/soc/2015/jgeboski/facebook: aecff282de76: facebook: handle grou...

James Geboski jgeboski at gmail.com
Mon Aug 10 23:24:04 EDT 2015


Changeset: aecff282de76da325dc736f5facedaa20b3a2218
Author:	 James Geboski <jgeboski at gmail.com>
Date:	 2015-08-10 16:57 -0400
Branch:	 facebook
URL: https://hg.pidgin.im/soc/2015/jgeboski/facebook/rev/aecff282de76

Description:

facebook: handle group chat events

diffstat:

 libpurple/protocols/facebook/api.c      |  123 ++++++++++++++++++++++++++++++++
 libpurple/protocols/facebook/api.h      |   24 ++++++
 libpurple/protocols/facebook/facebook.c |   46 +++++++++++-
 3 files changed, 191 insertions(+), 2 deletions(-)

diffs (289 lines):

diff --git a/libpurple/protocols/facebook/api.c b/libpurple/protocols/facebook/api.c
--- a/libpurple/protocols/facebook/api.c
+++ b/libpurple/protocols/facebook/api.c
@@ -240,6 +240,14 @@ fb_api_class_init(FbApiClass *klass)
 	             fb_marshal_VOID__OBJECT,
 	             G_TYPE_NONE,
 	             1, G_TYPE_ERROR);
+	g_signal_new("events",
+	             G_TYPE_FROM_CLASS(klass),
+	             G_SIGNAL_ACTION,
+	             0,
+	             NULL, NULL,
+	             fb_marshal_VOID__POINTER,
+	             G_TYPE_NONE,
+	             1, G_TYPE_POINTER);
 	g_signal_new("messages",
 	             G_TYPE_FROM_CLASS(klass),
 	             G_SIGNAL_ACTION,
@@ -865,6 +873,98 @@ fb_api_cb_publish_mark(FbApi *api, GByte
 	json_node_free(root);
 }
 
+static GSList *
+fb_api_event_parse(FbApi *api, FbApiEvent *event, GSList *events,
+                   JsonNode *root, GError **error)
+{
+	const gchar *str;
+	FbJsonValues *values;
+	GError *err = NULL;
+	gpointer mptr;
+	guint i;
+
+	static const struct {
+		FbApiEventType type;
+		const gchar *expr;
+	} evtypes[] = {
+		{
+			FB_API_EVENT_TYPE_THREAD_USER_ADDED,
+		 	"$.log_message_data.added_participants"
+		}, {
+			FB_API_EVENT_TYPE_THREAD_USER_REMOVED,
+			"$.log_message_data.removed_participants"
+		}
+	};
+
+	for (i = 0; i < G_N_ELEMENTS(evtypes); i++) {
+		event->type = evtypes[i].type;
+		values = fb_json_values_new(root);
+		fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$");
+		fb_json_values_set_array(values, FALSE, evtypes[i].expr);
+
+		while (fb_json_values_update(values, &err)) {
+			str = fb_json_values_next_str(values, "");
+			str = strrchr(str, ':');
+
+			if (str != NULL) {
+				event->uid = FB_ID_FROM_STR(str + 1);
+				mptr = fb_api_event_dup(event);
+				events = g_slist_prepend(events, mptr);
+			}
+		}
+
+		fb_json_values_free(values);
+
+		if (G_UNLIKELY(err != NULL)) {
+			g_propagate_error(error, err);
+			break;
+		}
+	}
+
+	return events;
+}
+
+static void
+fb_api_cb_mercury(FbApi *api, GByteArray *pload)
+{
+	const gchar *str;
+	FbApiEvent event;
+	FbJsonValues *values;
+	GError *err = NULL;
+	GSList *events = NULL;
+	JsonNode *root;
+	JsonNode *node;
+
+	if (!fb_api_json_chk(api, pload->data, pload->len, &root)) {
+		return;
+	}
+
+	values = fb_json_values_new(root);
+	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.thread_fbid");
+	fb_json_values_set_array(values, FALSE, "$.actions");
+
+	while (fb_json_values_update(values, &err)) {
+		fb_api_event_reset(&event);
+		str = fb_json_values_next_str(values, "0");
+		event.tid = FB_ID_FROM_STR(str);
+
+		node = fb_json_values_get_root(values);
+		events = fb_api_event_parse(api, &event, events, node, &err);
+	}
+
+	if (G_LIKELY(err == NULL)) {
+		events = g_slist_reverse(events);
+		g_signal_emit_by_name(api, "events", events);
+	} else {
+		fb_api_error_emit(api, err);
+	}
+
+	g_slist_free_full(events, (GDestroyNotify) fb_api_event_free);
+	fb_json_values_free(values);
+	json_node_free(root);
+
+}
+
 static void
 fb_api_cb_publish_typing(FbApi *api, GByteArray *pload)
 {
@@ -1273,6 +1373,7 @@ fb_api_cb_mqtt_publish(FbMqtt *mqtt, con
 		void (*func) (FbApi *api, GByteArray *pload);
 	} parsers[] = {
 		{"/mark_thread_response", fb_api_cb_publish_mark},
+		{"/mercury", fb_api_cb_mercury},
 		{"/orca_typing_notifications", fb_api_cb_publish_typing},
 		{"/t_ms", fb_api_cb_publish_ms},
 		{"/t_p", fb_api_cb_publish_p}
@@ -2333,6 +2434,28 @@ fb_api_typing(FbApi *api, FbId uid, gboo
 	g_free(json);
 }
 
+FbApiEvent *
+fb_api_event_dup(FbApiEvent *event)
+{
+	g_return_val_if_fail(event != NULL, NULL);
+	return g_memdup(event, sizeof *event);
+}
+
+void
+fb_api_event_reset(FbApiEvent *event)
+{
+	g_return_if_fail(event != NULL);
+	memset(event, 0, sizeof *event);
+}
+
+void
+fb_api_event_free(FbApiEvent *event)
+{
+	if (G_LIKELY(event != NULL)) {
+		g_free(event);
+	}
+}
+
 FbApiMessage *
 fb_api_message_dup(FbApiMessage *msg, gboolean deep)
 {
diff --git a/libpurple/protocols/facebook/api.h b/libpurple/protocols/facebook/api.h
--- a/libpurple/protocols/facebook/api.h
+++ b/libpurple/protocols/facebook/api.h
@@ -79,9 +79,11 @@
 #define FB_API_ERROR fb_api_error_quark()
 
 typedef enum _FbApiError FbApiError;
+typedef enum _FbApiEventType FbApiEventType;
 typedef struct _FbApi FbApi;
 typedef struct _FbApiClass FbApiClass;
 typedef struct _FbApiPrivate FbApiPrivate;
+typedef struct _FbApiEvent FbApiEvent;
 typedef struct _FbApiMessage FbApiMessage;
 typedef struct _FbApiPresence FbApiPresence;
 typedef struct _FbApiThread FbApiThread;
@@ -95,6 +97,12 @@ enum _FbApiError
 	FB_API_ERROR_AUTH
 };
 
+enum _FbApiEventType
+{
+	FB_API_EVENT_TYPE_THREAD_USER_ADDED,
+	FB_API_EVENT_TYPE_THREAD_USER_REMOVED
+};
+
 struct _FbApi
 {
 	GObject parent;
@@ -106,6 +114,13 @@ struct _FbApiClass
 	GObjectClass parent_class;
 };
 
+struct _FbApiEvent
+{
+	FbApiEventType type;
+	FbId uid;
+	FbId tid;
+};
+
 struct _FbApiMessage
 {
 	FbId uid;
@@ -210,6 +225,15 @@ fb_api_threads(FbApi *api);
 void
 fb_api_typing(FbApi *api, FbId uid, gboolean state);
 
+FbApiEvent *
+fb_api_event_dup(FbApiEvent *event);
+
+void
+fb_api_event_reset(FbApiEvent *event);
+
+void
+fb_api_event_free(FbApiEvent *event);
+
 FbApiMessage *
 fb_api_message_dup(FbApiMessage *msg, gboolean deep);
 
diff --git a/libpurple/protocols/facebook/facebook.c b/libpurple/protocols/facebook/facebook.c
--- a/libpurple/protocols/facebook/facebook.c
+++ b/libpurple/protocols/facebook/facebook.c
@@ -224,6 +224,46 @@ fb_cb_api_error(FbApi *api, GError *erro
 }
 
 static void
+fb_cb_api_events(FbApi *api, GSList *events, gpointer data)
+{
+	FbData *fata = data;
+	FbApiEvent *event;
+	gchar uid[FB_ID_STRMAX];
+	gchar tid[FB_ID_STRMAX];
+	GSList *l;
+	PurpleAccount *acct;
+	PurpleChatConversation *chat;
+	PurpleConnection *gc;
+
+	gc = fb_data_get_connection(fata);
+	acct = purple_connection_get_account(gc);
+
+	for (l = events; l != NULL; l = l->next) {
+		event = l->data;
+
+		FB_ID_TO_STR(event->tid, tid);
+		chat = purple_conversations_find_chat_with_account(tid, acct);
+
+		if (chat == NULL) {
+			continue;
+		}
+
+		FB_ID_TO_STR(event->uid, uid);
+
+		switch (event->type) {
+		case FB_API_EVENT_TYPE_THREAD_USER_ADDED:
+			purple_chat_conversation_add_user(chat, uid, NULL, 0,
+			                                  TRUE);
+			break;
+
+		case FB_API_EVENT_TYPE_THREAD_USER_REMOVED:
+			purple_chat_conversation_remove_user(chat, uid, NULL);
+			break;
+		}
+	}
+}
+
+static void
 fb_cb_api_messages(FbApi *api, GSList *msgs, gpointer data)
 {
 	FbApiMessage *msg;
@@ -535,6 +575,10 @@ fb_login(PurpleAccount *acct)
 	                 G_CALLBACK(fb_cb_api_error),
 	                 fata);
 	g_signal_connect(api,
+	                 "events",
+	                 G_CALLBACK(fb_cb_api_events),
+	                 fata);
+	g_signal_connect(api,
 	                 "messages",
 	                 G_CALLBACK(fb_cb_api_messages),
 	                 fata);
@@ -829,7 +873,6 @@ fb_chat_invite(PurpleConnection *gc, gin
 	tid = FB_ID_FROM_STR(name);
 	uid = FB_ID_FROM_STR(who);
 
-	purple_chat_conversation_add_user(chat, who, NULL, 0, TRUE);
 	fb_api_thread_invite(api, tid, uid);
 }
 
@@ -983,7 +1026,6 @@ fb_cmd_kick(PurpleConversation *conv, co
 	name = purple_buddy_get_name(bdy);
 	uid = FB_ID_FROM_STR(name);
 
-	purple_chat_conversation_remove_user(chat, name, NULL);
 	fb_api_thread_remove(api, tid, uid);
 	return PURPLE_CMD_RET_OK;
 }



More information about the Commits mailing list