diff options
-rw-r--r-- | facebook/facebook-api.c | 122 | ||||
-rw-r--r-- | facebook/facebook-api.h | 26 | ||||
-rw-r--r-- | facebook/facebook.c | 42 |
3 files changed, 178 insertions, 12 deletions
diff --git a/facebook/facebook-api.c b/facebook/facebook-api.c index 8cbde7f..ed94853 100644 --- a/facebook/facebook-api.c +++ b/facebook/facebook-api.c @@ -20,6 +20,7 @@ #include <sha1.h> #include "facebook-api.h" +#include "facebook-thrift.h" /** * Gets the error domain for #fb_api. @@ -414,6 +415,91 @@ finish: } /** + * Handles a presence states which are to be published to the user. + * + * @param api The #fb_api. + * @param pload The message payload. + **/ +static void fb_api_cb_publish_p(fb_api_t *api, const GByteArray *pload) +{ + fb_thrift_t *thft; + fb_thrift_type_t type; + fb_api_pres_t *pres; + GSList *press; + gint64 i64; + gint32 i32; + guint size; + guint i; + + /* Start at 1 to skip the NULL byte */ + thft = fb_thrift_new((GByteArray*) pload, 1, TRUE); + press = NULL; + + /* Skip the full list boolean field */ + fb_thrift_read_field(thft, &type, NULL); + g_warn_if_fail(type == FB_THRIFT_TYPE_BOOL); + fb_thrift_read_bool(thft, NULL); + + /* Read the list field */ + fb_thrift_read_field(thft, &type, NULL); + g_warn_if_fail(type == FB_THRIFT_TYPE_LIST); + + /* Read the list */ + fb_thrift_read_list(thft, &type, &size); + g_warn_if_fail(type == FB_THRIFT_TYPE_STRUCT); + + for (i = 0; i < size; i++) { + /* Read the user identifier field */ + fb_thrift_read_field(thft, &type, NULL); + g_warn_if_fail(type == FB_THRIFT_TYPE_I64); + fb_thrift_read_i64(thft, &i64); + + /* Read the active field */ + fb_thrift_read_field(thft, &type, NULL); + g_warn_if_fail(type == FB_THRIFT_TYPE_I32); + fb_thrift_read_i32(thft, &i32); + + pres = fb_api_pres_new(NULL, i32 != 0); + pres->uid = g_strdup_printf("%" G_GINT64_FORMAT, i64); + press = g_slist_prepend(press, pres); + + FB_UTIL_DEBUGLN("Presence: %s (%d)", pres->uid, pres->active); + + /* Skip the last active timestamp field */ + if (!fb_thrift_read_field(thft, &type, NULL)) + continue; + + g_warn_if_fail(type == FB_THRIFT_TYPE_I64); + fb_thrift_read_i64(thft, NULL); + + /* Skip the active client bits field */ + if (!fb_thrift_read_field(thft, &type, NULL)) + continue; + + g_warn_if_fail(type == FB_THRIFT_TYPE_I16); + fb_thrift_read_i16(thft, NULL); + + /* Skip the VoIP compatibility bits field */ + if (!fb_thrift_read_field(thft, &type, NULL)) + continue; + + g_warn_if_fail(type == FB_THRIFT_TYPE_I64); + fb_thrift_read_i64(thft, NULL); + + /* Read the field stop */ + fb_thrift_read_stop(thft); + } + + /* Read the field stop */ + fb_thrift_read_stop(thft); + fb_thrift_free(thft); + + press = g_slist_reverse(press); + FB_API_FUNC(api, presence, press); + g_slist_free_full(press, (GDestroyNotify) fb_api_pres_free); +} + +/** * Implements #fb_mqtt_funcs->publish((). * * @param mqtt The #fb_mqtt. @@ -445,6 +531,8 @@ static void fb_api_cb_mqtt_publish(fb_mqtt_t *mqtt, const gchar *topic, if (g_ascii_strcasecmp(topic, "/t_ms") == 0) fb_api_cb_publish_ms(api, bytes); + else if (g_ascii_strcasecmp(topic, "/t_p") == 0) + fb_api_cb_publish_p(api, bytes); if (G_LIKELY(comp)) g_byte_array_free(bytes, TRUE); @@ -853,6 +941,40 @@ void fb_api_msg_free(fb_api_msg_t *msg) } /** + * Creates a new #fb_api_pres. The returned #fb_api_pres should be + * freed with #fb_api_pres_free() when no longer needed. + * + * @param uid The user identifier. + * @param active TRUE if the user is active, otherwise FALSE. + * + * @return The #fb_api_pres or NULL on error. + **/ +fb_api_pres_t *fb_api_pres_new(const gchar *uid, gboolean active) +{ + fb_api_pres_t *pres; + + pres = g_new0(fb_api_pres_t, 1); + pres->uid = g_strdup(uid); + pres->active = active; + + return pres; +} + +/** + * Frees all memory used by a #fb_api_pres. + * + * @param pres The #fb_api_pres. + **/ +void fb_api_pres_free(fb_api_pres_t *pres) +{ + if (G_UNLIKELY(pres == NULL)) + return; + + g_free(pres->uid); + g_free(pres); +} + +/** * Creates a new #fb_api_user. The returned #fb_api_user should be * freed with #fb_api_user_free() when no longer needed. * diff --git a/facebook/facebook-api.h b/facebook/facebook-api.h index 5c84967..bbdd860 100644 --- a/facebook/facebook-api.h +++ b/facebook/facebook-api.h @@ -79,6 +79,9 @@ typedef struct fb_api_funcs fb_api_funcs_t; /** The structure for representing an #fb_api message. **/ typedef struct fb_api_msg fb_api_msg_t; +/** The structure for representing an #fb_api presence. **/ +typedef struct fb_api_pres fb_api_pres_t; + /** The structure for representing an #fb_api user. **/ typedef struct fb_api_user fb_api_user_t; @@ -146,6 +149,16 @@ struct fb_api_funcs * @param data The user-defined data or NULL. **/ void (*message) (fb_api_t *api, const GSList *msgs, gpointer data); + + /** + * The presence function. This is called whenever the #fb_api has + * retrieved a presence update. + * + * @param api The #fb_api. + * @param press The #GSList of #fb_api_pres. + * @param data The user-defined data or NULL. + **/ + void (*presence) (fb_api_t *api, const GSList *press, gpointer data); }; /** @@ -178,6 +191,15 @@ struct fb_api_msg }; /** + * The structure for representing an #fb_api presence. + **/ +struct fb_api_pres +{ + gchar *uid; /** The user identifier. **/ + gboolean active; /** TRUE if the user is active. **/ +}; + +/** * The structure for representing an #fb_api user. **/ struct fb_api_user @@ -215,6 +237,10 @@ fb_api_msg_t *fb_api_msg_new(const gchar *uid, const gchar *text); void fb_api_msg_free(fb_api_msg_t *msg); +fb_api_pres_t *fb_api_pres_new(const gchar *uid, gboolean online); + +void fb_api_pres_free(fb_api_pres_t *pres); + fb_api_user_t *fb_api_user_new(const gchar *uid, const gchar *name); void fb_api_user_free(fb_api_user_t *user); diff --git a/facebook/facebook.c b/facebook/facebook.c index a35a837..4622ff3 100644 --- a/facebook/facebook.c +++ b/facebook/facebook.c @@ -61,20 +61,11 @@ 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; - account_t *acc = fata->ic->acc; - GSList *l; - bee_user_t *bu; + fb_data_t *fata = data; + account_t *acc = fata->ic->acc; imcb_connected(fata->ic); set_setstr(&acc->set, "stoken", api->stoken); - - 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); - } } /** @@ -122,6 +113,32 @@ static void fb_cb_api_message(fb_api_t *api, const GSList *msgs, gpointer data) } /** + * Implemented #fb_api_funcs->presence(). + * + * @param api The #fb_api. + * @param press The #GSList of #fb_api_msg. + * @param data The user defined data, which is #fb_data. + **/ +static void fb_cb_api_presence(fb_api_t *api, const GSList *press, + gpointer data) +{ + fb_data_t *fata = data; + fb_api_pres_t *pres; + const GSList *l; + guint flags; + + for (l = press; l != NULL; l = l->next) { + pres = l->data; + flags = 0; + + if (pres->active) + flags |= OPT_LOGGED_IN; + + imcb_buddy_status(fata->ic, pres->uid, flags, NULL, NULL); + } +} + +/** * Creates a new #fb_data with an #account. The returned #fb_data * should be freed with #fb_data_free() when no longer needed. * @@ -138,7 +155,8 @@ fb_data_t *fb_data_new(account_t *acc) .auth = fb_cb_api_auth, .connect = fb_cb_api_connect, .contacts = fb_cb_api_contacts, - .message = fb_cb_api_message + .message = fb_cb_api_message, + .presence = fb_cb_api_presence }; g_return_val_if_fail(acc != NULL, NULL); |