facebook: Handle new style topic/groupchat membership events

Sun, 25 Jun 2017 04:44:19 -0300

author
dx <dx@dxzone.com.ar>
date
Sun, 25 Jun 2017 04:44:19 -0300
changeset 38397
046138091ee2
parent 38396
a7a919217259
child 38398
a2fe2e8fe876

facebook: Handle new style topic/groupchat membership events

Looks like the mercury topics were deprecated and instead we get these:

* deltaThreadName
* deltaParticipantsAddedToGroupThread
* deltaParticipantLeftGroupThread

Also slightly modified the handlers on the UI side to add users
directly without requiring a thread fetch, and to show a kick message

libpurple/protocols/facebook/api.c file | annotate | diff | comparison | revisions
libpurple/protocols/facebook/facebook.c file | annotate | diff | comparison | revisions
--- a/libpurple/protocols/facebook/api.c	Sun Jun 25 04:16:48 2017 -0300
+++ b/libpurple/protocols/facebook/api.c	Sun Jun 25 04:44:19 2017 -0300
@@ -1484,6 +1484,9 @@
 static GSList *
 fb_api_cb_publish_ms_new_message(FbApi *api, JsonNode *root, GSList *msgs, GError **error);
 
+static GSList *
+fb_api_cb_publish_ms_event(FbApi *api, JsonNode *root, GSList *events, FbApiEventType type, GError **error);
+
 static void
 fb_api_cb_publish_ms(FbApi *api, GByteArray *pload)
 {
@@ -1495,11 +1498,23 @@
 	GError *err = NULL;
 	GList *elms, *l;
 	GSList *msgs = NULL;
+	GSList *events = NULL;
 	guint size;
 	JsonNode *root;
 	JsonNode *node;
 	JsonArray *arr;
 
+	static const struct {
+		const gchar *member;
+		FbApiEventType type;
+		gboolean is_message;
+	} event_types[] = {
+		{"deltaNewMessage", 0, 1},
+		{"deltaThreadName", FB_API_EVENT_TYPE_THREAD_TOPIC, 0},
+		{"deltaParticipantsAddedToGroupThread", FB_API_EVENT_TYPE_THREAD_USER_ADDED, 0},
+		{"deltaParticipantLeftGroupThread", FB_API_EVENT_TYPE_THREAD_USER_REMOVED, 0},
+	};
+
 	/* Read identifier string (for Facebook employees) */
 	thft = fb_thrift_new(pload, 0);
 	fb_thrift_read_str(thft, NULL);
@@ -1542,10 +1557,23 @@
 	elms = json_array_get_elements(arr);
 
 	for (l = elms; l != NULL; l = l->next) {
+		guint i = 0;
 		JsonObject *o = json_node_get_object(l->data);
-		if ((node = json_object_get_member(o, "deltaNewMessage"))) {
-			msgs = fb_api_cb_publish_ms_new_message(api, node, msgs, &err);
+
+		for (i = 0; i < G_N_ELEMENTS(event_types); i++) {
+			if ((node = json_object_get_member(o, event_types[i].member))) {
+				if (event_types[i].is_message) {
+					msgs = fb_api_cb_publish_ms_new_message(
+						api, node, msgs, &err
+					);
+				} else {
+					events = fb_api_cb_publish_ms_event(
+						api, node, events, event_types[i].type, &err
+					);
+				}
+			}
 		}
+
 		if (G_UNLIKELY(err != NULL)) {
 			break;
 		}
@@ -1555,13 +1583,21 @@
 	json_array_unref(arr);
 
 	if (G_LIKELY(err == NULL)) {
-		msgs = g_slist_reverse(msgs);
-		g_signal_emit_by_name(api, "messages", msgs);
+		if (msgs) {
+			msgs = g_slist_reverse(msgs);
+			g_signal_emit_by_name(api, "messages", msgs);
+		}
+
+		if (events) {
+			events = g_slist_reverse(events);
+			g_signal_emit_by_name(api, "events", events);
+		}
 	} else {
 		fb_api_error_emit(api, err);
 	}
 
 	g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
+	g_slist_free_full(events, (GDestroyNotify) fb_api_event_free);
 	json_node_free(root);
 }
 
@@ -1664,6 +1700,89 @@
 	return msgs;
 }
 
+static GSList *
+fb_api_cb_publish_ms_event(FbApi *api, JsonNode *root, GSList *events, FbApiEventType type, GError **error)
+{
+	FbApiEvent *event;
+	FbJsonValues *values = NULL;
+	FbJsonValues *values_inner = NULL;
+	GError *err = NULL;
+
+	values = fb_json_values_new(root);
+	fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
+	                   "$.messageMetadata.threadKey.threadFbId");
+	fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
+	                   "$.messageMetadata.actorFbId");
+
+	switch (type) {
+	case FB_API_EVENT_TYPE_THREAD_TOPIC:
+		fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
+		                   "$.name");
+		break;
+
+	case FB_API_EVENT_TYPE_THREAD_USER_ADDED:
+		values_inner = fb_json_values_new(root);
+
+		fb_json_values_add(values_inner, FB_JSON_TYPE_INT, FALSE,
+		                   "$.userFbId");
+
+		/* use the text field for the full name */
+		fb_json_values_add(values_inner, FB_JSON_TYPE_STR, FALSE,
+		                   "$.fullName");
+
+		fb_json_values_set_array(values_inner, FALSE,
+		                         "$.addedParticipants");
+		break;
+
+	case FB_API_EVENT_TYPE_THREAD_USER_REMOVED:
+		fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
+		                   "$.leftParticipantFbId");
+
+		/* use the text field for the kick message */
+		fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
+		                   "$.messageMetadata.adminText");
+		break;
+	}
+
+	fb_json_values_update(values, &err);
+
+	event = fb_api_event_dup(NULL, FALSE);
+	event->type = type;
+	event->tid = fb_json_values_next_int(values, 0);
+	event->uid = fb_json_values_next_int(values, 0);
+
+	if (type == FB_API_EVENT_TYPE_THREAD_TOPIC) {
+		event->text = fb_json_values_next_str_dup(values, NULL);
+	} else if (type == FB_API_EVENT_TYPE_THREAD_USER_REMOVED) {
+		/* overwrite actor with subject */
+		event->uid = fb_json_values_next_int(values, 0);
+		event->text = fb_json_values_next_str_dup(values, NULL);
+	} else if (type == FB_API_EVENT_TYPE_THREAD_USER_ADDED) {
+
+		while (fb_json_values_update(values_inner, &err)) {
+			FbApiEvent *devent = fb_api_event_dup(event, FALSE);
+
+			devent->uid = fb_json_values_next_int(values_inner, 0);
+			devent->text = fb_json_values_next_str_dup(values_inner, NULL);
+
+			events = g_slist_prepend(events, devent);
+		}
+		fb_api_event_free(event);
+		event = NULL;
+		g_object_unref(values_inner);
+	}
+
+	g_object_unref(values);
+
+	if (G_UNLIKELY(err != NULL)) {
+		g_propagate_error(error, err);
+	} else if (event) {
+		events = g_slist_prepend(events, event);
+	}
+
+	return events;
+}
+
 static void
 fb_api_cb_publish_pt(FbThrift *thft, GSList **press, GError **error)
 {
--- a/libpurple/protocols/facebook/facebook.c	Sun Jun 25 04:16:48 2017 -0300
+++ b/libpurple/protocols/facebook/facebook.c	Sun Jun 25 04:44:19 2017 -0300
@@ -437,8 +437,18 @@
 
 		case FB_API_EVENT_TYPE_THREAD_USER_ADDED:
 			if (purple_blist_find_buddy(acct, uid) == NULL) {
-				g_hash_table_insert(fetch, &event->tid, event);
-				break;
+				if (event->text) {
+					FbApiUser *user = fb_api_user_dup(NULL, FALSE);
+					user->uid = event->uid;
+					user->name = g_strdup(event->text);
+
+					fb_buddy_add_nonfriend(acct, user);
+
+					fb_api_user_free(user);
+				} else {
+					g_hash_table_insert(fetch, &event->tid, event);
+					break;
+				}
 			}
 
 			purple_chat_conversation_add_user(chat, uid, NULL, 0,
@@ -446,7 +456,7 @@
 			break;
 
 		case FB_API_EVENT_TYPE_THREAD_USER_REMOVED:
-			purple_chat_conversation_remove_user(chat, uid, NULL);
+			purple_chat_conversation_remove_user(chat, uid, event->text);
 			break;
 		}
 	}

mercurial