diff options
author | jgeboski <jgeboski@gmail.com> | 2015-01-03 18:51:42 -0500 |
---|---|---|
committer | jgeboski <jgeboski@gmail.com> | 2015-01-14 16:06:05 -0500 |
commit | 20cd31cc5e1320e7dde8a30380d67185c5b289c8 (patch) | |
tree | 4e428a88daa25093bf156766405e8d932ab8844d | |
parent | cefcc09b3a91f882a4511f675750d1798494969b (diff) | |
download | bitlbee-facebook-20cd31cc5e1320e7dde8a30380d67185c5b289c8.tar.gz bitlbee-facebook-20cd31cc5e1320e7dde8a30380d67185c5b289c8.tar.bz2 bitlbee-facebook-20cd31cc5e1320e7dde8a30380d67185c5b289c8.tar.xz |
Implemented contacts list lookup
-rw-r--r-- | facebook/facebook-api.c | 131 | ||||
-rw-r--r-- | facebook/facebook-api.h | 33 | ||||
-rw-r--r-- | facebook/facebook.c | 47 |
3 files changed, 206 insertions, 5 deletions
diff --git a/facebook/facebook-api.c b/facebook/facebook-api.c index a5b601c..144304a 100644 --- a/facebook/facebook-api.c +++ b/facebook/facebook-api.c @@ -448,6 +448,102 @@ void fb_api_auth(fb_api_t *api, const gchar *user, const gchar *pass) } /** + * Implemented #fb_http_func for #fb_api_contacts(). + * + * @param req The #fb_http_req. + * @param data The user-defined data, which is #fb_api. + **/ +static void fb_api_cb_contacts(fb_http_req_t *req, gpointer data) +{ + fb_api_t *api = data; + GSList *users; + fb_api_user_t *user; + json_value *json; + json_value *jv; + json_value *jx; + json_value *jy; + json_value *jz; + const gchar *str; + const gchar *uid; + const gchar *name; + guint i; + + json = fb_api_json_new(api, req->body, req->body_size); + users = NULL; + + if (json == NULL) + return; + + if (!fb_json_val_chk(json, "viewer", json_object, &jv) || + !fb_json_val_chk(jv, "messenger_contacts", json_object, &jv) || + !fb_json_val_chk(jv, "nodes", json_array, &jv)) + { + fb_api_error(api, FB_API_ERROR_GENERAL, "Failed to parse contacts"); + goto finish; + } + + for (i = 0; i < jv->u.array.length; i++) { + jx = jv->u.array.values[i]; + + /* Scattered values lead to a gnarly conditional... */ + if (fb_json_val_chk(jx, "represented_profile", json_object, &jy) && + + /* Check the contact type is "user" */ + fb_json_val_chk(jy, "__type__", json_object, &jz) && + fb_json_str_chk(jz, "name", &str) && + (g_ascii_strcasecmp(str, "user") == 0) && + + /* Check the contact is a friend */ + fb_json_str_chk(jy, "friendship_status", &str) && + (g_ascii_strcasecmp(str, "ARE_FRIENDS") == 0) && + + /* Obtain the contact user identifier */ + fb_json_str_chk(jy, "id", &uid) && + (g_strcmp0(uid, api->uid) != 0) && + + /* Obtain the name of the user */ + fb_json_val_chk(jx, "structured_name", json_object, &jy) && + fb_json_str_chk(jy, "text", &name)) + { + user = fb_api_user_new(uid, name); + users = g_slist_prepend(users, user); + } + } + + FB_API_FUNC(api, contacts, users); + +finish: + g_slist_free_full(users, (GDestroyNotify) fb_api_user_free); + json_value_free(json); +} + +/** + * Sends a contacts request. + * + * @param api The #fb_api. + **/ +void fb_api_contacts(fb_api_t *api) +{ + fb_http_req_t *req; + + g_return_if_fail(api != NULL); + + req = fb_api_req_new(api, FB_API_GHOST, FB_API_PATH_GQL, + fb_api_cb_contacts, + "com.facebook.contacts.service.d", + "FetchContactsFullQuery", + "get"); + + fb_http_req_params_set(req, + FB_HTTP_PAIR("query_id", FB_API_QRYID_CONTACTS), + FB_HTTP_PAIR("query_params", "{}"), + NULL + ); + + fb_api_req_send(api, req); +} + +/** * Connects the #fb_api to the remote services. This is mainly for * connecting and setting up the internal #fb_mqtt. * @@ -473,3 +569,38 @@ void fb_api_disconnect(fb_api_t *api) fb_mqtt_disconnect(api->mqtt); } + +/** + * Creates a new #fb_api_user. The returned #fb_api_user should be + * freed with #fb_api_user_free() when no longer needed. + * + * @param uid The user identifier. + * @param name The name of the user. + * + * @return The #fb_api_user or NULL on error. + **/ +fb_api_user_t *fb_api_user_new(const gchar *uid, const gchar *name) +{ + fb_api_user_t *user; + + user = g_new0(fb_api_user_t, 1); + user->uid = g_strdup(uid); + user->name = g_strdup(name); + + return user; +} + +/** + * Frees all memory used by a #fb_api_user. + * + * @param user The #fb_api_user. + **/ +void fb_api_user_free(fb_api_user_t *user) +{ + if (G_UNLIKELY(user == NULL)) + return; + + g_free(user->name); + g_free(user->uid); + g_free(user); +} diff --git a/facebook/facebook-api.h b/facebook/facebook-api.h index 7d61c8e..b6bd8bd 100644 --- a/facebook/facebook-api.h +++ b/facebook/facebook-api.h @@ -28,11 +28,15 @@ #define FB_API_HOST "api.facebook.com" #define FB_API_BHOST "b-api.facebook.com" +#define FB_API_GHOST "graph.facebook.com" #define FB_API_AGENT "Facebook App / " PACKAGE " / " PACKAGE_VERSION #define FB_API_KEY "256002347743983" #define FB_API_SECRET "374e60f8b9bb6b8cbb30f78030438895" #define FB_API_PATH_AUTH "/method/auth.login" +#define FB_API_PATH_GQL "/graphql" + +#define FB_API_QRYID_CONTACTS "10153122424521729" /** @@ -59,6 +63,9 @@ typedef struct fb_api fb_api_t; /** The main structure for #fb_api callback functions. **/ typedef struct fb_api_funcs fb_api_funcs_t; +/** The structure for representing an #fb_api user. **/ +typedef struct fb_api_user fb_api_user_t; + /** * The #GError codes of #fb_api. @@ -102,6 +109,17 @@ struct fb_api_funcs * @param data The user-defined data or NULL. **/ void (*connect) (fb_api_t *api, gpointer data); + + /** + * The contacts function. This is called whenever the #fb_api has + * retrieved a set contacts. This is called as a result of + * #fb_api_contacts(). + * + * @param api The #fb_api. + * @param users The #GSList of #fb_api_user. + * @param data The user-defined data or NULL. + **/ + void (*contacts) (fb_api_t *api, const GSList *users, gpointer data); }; /** @@ -124,6 +142,15 @@ struct fb_api gchar *sid; /** The sync identifier. **/ }; +/** + * The structure for representing an #fb_api user. + **/ +struct fb_api_user +{ + gchar *uid; /** The user identifier. **/ + gchar *name; /** The name of the user. **/ +}; + #define FB_API_ERROR fb_api_error_quark() @@ -139,8 +166,14 @@ void fb_api_error(fb_api_t *api, fb_api_error_t err, const gchar *fmt, ...); void fb_api_auth(fb_api_t *api, const gchar *user, const gchar *pass); +void fb_api_contacts(fb_api_t *api); + void fb_api_connect(fb_api_t *api); void fb_api_disconnect(fb_api_t *api); +fb_api_user_t *fb_api_user_new(const gchar *uid, const gchar *name); + +void fb_api_user_free(fb_api_user_t *user); + #endif /* _FACEBOOK_API_H */ diff --git a/facebook/facebook.c b/facebook/facebook.c index ca2d687..aed3893 100644 --- a/facebook/facebook.c +++ b/facebook/facebook.c @@ -61,8 +61,43 @@ static void fb_cb_api_auth(fb_api_t *api, gpointer data) **/ static void fb_cb_api_connect(fb_api_t *api, gpointer data) { - fb_data_t *fata = data; + fb_data_t *fata = data; + GSList *l; + bee_user_t *bu; + imcb_connected(fata->ic); + + for (l = fata->ic->bee->users; l != NULL; l = l->next) { + bu = l->data; + + /* For now, all users are online */ + imcb_buddy_status(fata->ic, bu->handle, OPT_LOGGED_IN, NULL, NULL); + } +} + +/** + * Implemented #fb_api_funcs->contacts(). + * + * @param api The #fb_api. + * @param users The #GSList of #fb_api_user. + * @param data The user defined data, which is #fb_data. + **/ +static void fb_cb_api_contacts(fb_api_t *api, const GSList *users, + gpointer data) +{ + fb_data_t *fata = data; + fb_api_user_t *user; + const GSList *l; + + for (l = users; l != NULL; l = l->next) { + user = l->data; + imcb_add_buddy(fata->ic, user->uid, NULL); + imcb_buddy_nick_hint(fata->ic, user->uid, user->name); + imcb_rename_buddy(fata->ic, user->uid, user->name); + } + + imcb_log(fata->ic, "Establishing connection"); + fb_api_connect(fata->api); } /** @@ -78,9 +113,10 @@ fb_data_t *fb_data_new(account_t *acc) fb_data_t *fata; static const fb_api_funcs_t funcs = { - .error = fb_cb_api_error, - .auth = fb_cb_api_auth, - .connect = fb_cb_api_connect + .error = fb_cb_api_error, + .auth = fb_cb_api_auth, + .connect = fb_cb_api_connect, + .contacts = fb_cb_api_contacts }; g_return_val_if_fail(acc != NULL, NULL); @@ -163,7 +199,8 @@ static void fb_login(account_t *acc) return; } - fb_api_connect(fata->api); + imcb_log(fata->ic, "Fetching contacts"); + fb_api_contacts(fata->api); } /** |