aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--facebook/facebook-api.c122
-rw-r--r--facebook/facebook-api.h26
-rw-r--r--facebook/facebook.c42
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);