aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarius Halden <marius.h@lden.org>2017-03-29 14:44:52 +0200
committerMarius Halden <marius.h@lden.org>2017-03-29 14:44:52 +0200
commitb6ed8a8791605d882a8e389ea0b9db2b05713dd1 (patch)
treebcf1deab0e1a8d72ff5173276dcb03fb70fdff7b
parent690567817968396a5a97a7a7c53b25d80a9366dd (diff)
parentaf132a8990f0928b12f68172b21403df08207f4a (diff)
downloadbitlbee-facebook-b6ed8a8791605d882a8e389ea0b9db2b05713dd1.tar.gz
bitlbee-facebook-b6ed8a8791605d882a8e389ea0b9db2b05713dd1.tar.bz2
bitlbee-facebook-b6ed8a8791605d882a8e389ea0b9db2b05713dd1.tar.xz
Merge branch 'master' into track-messages
-rw-r--r--facebook/facebook-api.c230
-rw-r--r--facebook/facebook-api.h28
-rw-r--r--facebook/facebook.c12
3 files changed, 228 insertions, 42 deletions
diff --git a/facebook/facebook-api.c b/facebook/facebook-api.c
index d9d4486..b318c62 100644
--- a/facebook/facebook-api.c
+++ b/facebook/facebook-api.c
@@ -370,9 +370,9 @@ fb_api_class_init(FbApiClass *klass)
G_SIGNAL_ACTION,
0,
NULL, NULL,
- fb_marshal_VOID__OBJECT,
+ fb_marshal_VOID__POINTER,
G_TYPE_NONE,
- 1, G_TYPE_ERROR);
+ 1, G_TYPE_POINTER);
/**
* FbApi::events:
@@ -793,6 +793,7 @@ fb_api_http_query(FbApi *api, gint64 query, JsonBuilder *builder,
case FB_API_QUERY_THREAD:
name = "ThreadQuery";
break;
+ case FB_API_QUERY_SEQ_ID:
case FB_API_QUERY_THREADS:
name = "ThreadListQuery";
break;
@@ -877,7 +878,7 @@ fb_api_cb_mqtt_open(FbMqtt *mqtt, gpointer data)
/* Write the information string */
fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 2, 1);
- fb_thrift_write_str(thft, "");
+ fb_thrift_write_str(thft, FB_API_MQTT_AGENT);
/* Write the UNKNOWN ("cp"?) */
fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 3, 2);
@@ -1078,7 +1079,7 @@ fb_api_cb_mqtt_connect(FbMqtt *mqtt, gpointer data)
if (priv->sid == 0) {
bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
fb_json_bldr_add_str(bldr, "1", "0");
- fb_api_http_query(api, FB_API_QUERY_THREADS, bldr, fb_api_cb_seqid);
+ fb_api_http_query(api, FB_API_QUERY_SEQ_ID, bldr, fb_api_cb_seqid);
} else {
fb_api_connect_queue(api);
}
@@ -1390,7 +1391,7 @@ fb_api_message_parse_attach(FbApi *api, const gchar *mid, FbApiMessage *msg,
values = fb_json_values_new(root);
fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.xmaGraphQL");
fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE, "$.fbid");
- fb_json_values_set_array(values, FALSE, "$.deltaNewMessage.attachments");
+ fb_json_values_set_array(values, FALSE, "$.attachments");
while (fb_json_values_update(values, &err)) {
str = fb_json_values_next_str(values, NULL);
@@ -1432,25 +1433,39 @@ fb_api_message_parse_attach(FbApi *api, const gchar *mid, FbApiMessage *msg,
return msgs;
}
+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)
{
- const gchar *body;
const gchar *data;
- const gchar *str;
- FbApiMessage *dmsg;
- FbApiMessage msg;
FbApiPrivate *priv = api->priv;
- FbId id;
- FbId oid;
FbJsonValues *values;
FbThrift *thft;
gchar *stoken;
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);
@@ -1489,39 +1504,101 @@ fb_api_cb_publish_ms(FbApi *api, GByteArray *pload)
return;
}
+ arr = fb_json_node_get_arr(root, "$.deltas", NULL);
+ 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);
+
+ 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;
+ }
+ }
+
+ g_list_free(elms);
+ json_array_unref(arr);
+
+ if (G_LIKELY(err == NULL)) {
+ 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);
+}
+
+
+static GSList *
+fb_api_cb_publish_ms_new_message(FbApi *api, JsonNode *root, GSList *msgs, GError **error)
+{
+ const gchar *body;
+ const gchar *str;
+ GError *err = NULL;
+ FbApiPrivate *priv = api->priv;
+ FbApiMessage *dmsg;
+ FbApiMessage msg;
+ FbId id;
+ FbId oid;
+ FbJsonValues *values;
+ JsonNode *node;
+
values = fb_json_values_new(root);
fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.deltaNewMessage.messageMetadata.offlineThreadingId");
+ "$.messageMetadata.offlineThreadingId");
fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.deltaNewMessage.messageMetadata.actorFbId");
+ "$.messageMetadata.actorFbId");
fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.deltaNewMessage.messageMetadata"
+ "$.messageMetadata"
".threadKey.otherUserFbId");
fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.deltaNewMessage.messageMetadata"
+ "$.messageMetadata"
".threadKey.threadFbId");
fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.deltaNewMessage.messageMetadata.timestamp");
+ "$.messageMetadata.timestamp");
fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.deltaNewMessage.body");
+ "$.body");
fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
- "$.deltaNewMessage.stickerId");
+ "$.stickerId");
fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
- "$.deltaNewMessage.messageMetadata.messageId");
- fb_json_values_set_array(values, TRUE, "$.deltas");
+ "$.messageMetadata.messageId");
- while (fb_json_values_update(values, &err)) {
+ if (fb_json_values_update(values, &err)) {
id = fb_json_values_next_int(values, 0);
/* Ignore everything but new messages */
if (id == 0) {
- continue;
+ goto beach;
}
/* Ignore sequential duplicates */
if (id == priv->lastmid) {
fb_util_debug_info("Ignoring duplicate %" FB_ID_FORMAT, id);
- continue;
+ goto beach;
}
priv->lastmid = id;
@@ -1557,7 +1634,7 @@ fb_api_cb_publish_ms(FbApi *api, GByteArray *pload)
str = fb_json_values_next_str(values, NULL);
if (str == NULL) {
- continue;
+ goto beach;
}
node = fb_json_values_get_root(values);
@@ -1565,20 +1642,97 @@ fb_api_cb_publish_ms(FbApi *api, GByteArray *pload)
&err);
if (G_UNLIKELY(err != NULL)) {
- break;
+ g_propagate_error(error, err);
+ goto beach;
}
}
- if (G_LIKELY(err == NULL)) {
- msgs = g_slist_reverse(msgs);
- g_signal_emit_by_name(api, "messages", msgs);
- } else {
- fb_api_error_emit(api, err);
+beach:
+ g_object_unref(values);
+ 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_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
g_object_unref(values);
- json_node_free(root);
+
+ if (G_UNLIKELY(err != NULL)) {
+ g_propagate_error(error, err);
+ } else if (event) {
+ events = g_slist_prepend(events, event);
+ }
+
+ return events;
}
static void
@@ -2850,7 +3004,7 @@ fb_api_cb_thread_create(FbHttpRequest *req, gpointer data)
}
values = fb_json_values_new(root);
- fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.thread_fbid");
+ fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.id");
fb_json_values_update(values, &err);
FB_API_ERROR_EMIT(api, err,
@@ -2897,8 +3051,8 @@ fb_api_thread_create(FbApi *api, GSList *uids)
json = fb_json_bldr_close(bldr, JSON_NODE_ARRAY, NULL);
prms = fb_http_values_new();
- fb_http_values_set_str(prms, "to", json);
- fb_api_http_req(api, FB_API_URL_THREADS, "createThread", "POST", prms,
+ fb_http_values_set_str(prms, "recipients", json);
+ fb_api_http_req(api, FB_API_URL_THREADS, "createGroup", "POST", prms,
fb_api_cb_thread_create);
g_free(json);
}
@@ -2919,7 +3073,7 @@ fb_api_thread_invite(FbApi *api, FbId tid, FbId uid)
prms = fb_http_values_new();
fb_http_values_set_str(prms, "to", json);
- fb_http_values_set_strf(prms, "id", "t_id.%" FB_ID_FORMAT, tid);
+ fb_http_values_set_strf(prms, "id", "t_%" FB_ID_FORMAT, tid);
fb_api_http_req(api, FB_API_URL_PARTS, "addMembers", "POST", prms,
fb_api_cb_http_bool);
g_free(json);
@@ -2937,7 +3091,7 @@ fb_api_thread_remove(FbApi *api, FbId tid, FbId uid)
priv = api->priv;
prms = fb_http_values_new();
- fb_http_values_set_strf(prms, "id", "t_id.%" FB_ID_FORMAT, tid);
+ fb_http_values_set_strf(prms, "id", "t_%" FB_ID_FORMAT, tid);
if (uid == 0) {
uid = priv->uid;
@@ -2962,7 +3116,7 @@ fb_api_thread_topic(FbApi *api, FbId tid, const gchar *topic)
prms = fb_http_values_new();
fb_http_values_set_str(prms, "name", topic);
- fb_http_values_set_strf(prms, "tid", "t_id.%" FB_ID_FORMAT, tid);
+ fb_http_values_set_int(prms, "tid", tid);
fb_api_http_req(api, FB_API_URL_TOPIC, "setThreadName",
"messaging.setthreadname", prms,
fb_api_cb_http_bool);
diff --git a/facebook/facebook-api.h b/facebook/facebook-api.h
index b6a2812..fa38d3d 100644
--- a/facebook/facebook-api.h
+++ b/facebook/facebook-api.h
@@ -96,6 +96,22 @@
#define FB_API_AGENT "Facebook plugin / BitlBee / " PACKAGE_VERSION
/**
+ * FB_API_MQTT_AGENT
+ *
+ * The client information string sent in the MQTT CONNECT message
+ *
+ * We announce ourselves as compatible with Orca-Android 38.0 since that's the
+ * closest version to the last major protocol update. Some parts use older
+ * features, some parts use newer ones.
+ *
+ * Fun fact: this version sends old-style MQIsdp CONNECT messages for the first
+ * connection, with JSON payloads instead of compressed thrift.
+ */
+
+#define FB_API_MQTT_AGENT FB_API_AGENT " [FBAN/Orca-Android;FBAV/38.0.0.22.155;FBBV/14477681]"
+
+
+/**
* FB_API_URL_ATTACH:
*
* The URL for attachment URL requests.
@@ -136,7 +152,7 @@
*
* The URL for thread management requests.
*/
-#define FB_API_URL_THREADS FB_API_GHOST "/me/threads"
+#define FB_API_URL_THREADS FB_API_GHOST "/me/group_threads"
/**
* FB_API_URL_TOPIC:
@@ -273,6 +289,16 @@
#define FB_API_QUERY_THREADS 10153919752026729
/**
+ * FB_API_QUERY_SEQ_ID:
+ *
+ * A variant of ThreadListQuery with sequence ID
+ *
+ * TODO: parameters.
+ */
+
+#define FB_API_QUERY_SEQ_ID 10155268192741729
+
+/**
* FB_API_QUERY_XMA:
*
* The query hash for the `XMAQuery`.
diff --git a/facebook/facebook.c b/facebook/facebook.c
index 7102a29..3079d0c 100644
--- a/facebook/facebook.c
+++ b/facebook/facebook.c
@@ -357,15 +357,21 @@ fb_cb_api_events(FbApi *api, GSList *events, gpointer data)
case FB_API_EVENT_TYPE_THREAD_USER_ADDED:
if (bee_user_by_handle(ic->bee, ic, uid) == NULL) {
- g_hash_table_insert(fetch, &event->tid, event);
- break;
+ if (event->text) {
+ bee_user_new(ic->bee, ic, uid, BEE_USER_LOCAL);
+ imcb_buddy_nick_hint(ic, uid, event->text);
+ imcb_rename_buddy(ic, uid, event->text);
+ } else {
+ g_hash_table_insert(fetch, &event->tid, event);
+ break;
+ }
}
imcb_chat_add_buddy(gc, uid);
break;
case FB_API_EVENT_TYPE_THREAD_USER_REMOVED:
- imcb_chat_remove_buddy(gc, uid, NULL);
+ imcb_chat_remove_buddy(gc, uid, event->text);
break;
}
}