aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjgeboski <jgeboski@gmail.com>2015-01-13 12:14:31 -0500
committerjgeboski <jgeboski@gmail.com>2015-01-14 21:55:37 -0500
commitb29d66da918a912ce47551546a4cfa866325e56c (patch)
tree598449a681db97b7bb5fd5aee9b3c108722e5d1b
parent20cd31cc5e1320e7dde8a30380d67185c5b289c8 (diff)
downloadbitlbee-facebook-b29d66da918a912ce47551546a4cfa866325e56c.tar.gz
bitlbee-facebook-b29d66da918a912ce47551546a4cfa866325e56c.tar.bz2
bitlbee-facebook-b29d66da918a912ce47551546a4cfa866325e56c.tar.xz
Implemented one-on-one messaging
-rw-r--r--facebook/facebook-api.c550
-rw-r--r--facebook/facebook-api.h47
-rw-r--r--facebook/facebook.c41
3 files changed, 496 insertions, 142 deletions
diff --git a/facebook/facebook-api.c b/facebook/facebook-api.c
index 144304a..8cbde7f 100644
--- a/facebook/facebook-api.c
+++ b/facebook/facebook-api.c
@@ -37,6 +37,134 @@ GQuark fb_api_error_quark(void)
}
/**
+ * Creates a new #json_value for JSON contents of the #fb_api. This
+ * function is special in that it handles all errors, unlike the parent
+ * function #fb_json_new(). The returned #json_value should be freed
+ * with #json_value_free() when no longer needed.
+ *
+ * @param api The #fb_api.
+ * @param data The data.
+ * @param size The size of the data.
+ *
+ * @return TRUE if the data was parsed without error, otherwise FALSE.
+ **/
+static json_value *fb_api_json_new(fb_api_t *api, const gchar *data,
+ gsize size)
+{
+ json_value *json;
+ const gchar *msg;
+ gint64 code;
+
+ json = fb_json_new(data, size, &api->err);
+
+ if (api->err != NULL) {
+ fb_api_error(api, 0, NULL);
+ return NULL;
+ }
+
+ if (fb_json_int_chk(json, "error_code", &code)) {
+ if (!fb_json_str_chk(json, "error_msg", &msg))
+ msg = "Generic Error";
+
+ fb_api_error(api, FB_API_ERROR_GENERAL, "%s", msg);
+ json_value_free(json);
+ return NULL;
+ }
+
+ return json;
+}
+
+/**
+ * Creates a new #fb_http_req for a #fb_api request.
+ *
+ * @param api The #fb_api.
+ * @param host The host.
+ * @param path The path.
+ * @param func The #fb_http_func.
+ * @param class The class.
+ * @param name The friendly name.
+ * @param method The method.
+ **/
+static fb_http_req_t *fb_api_req_new(fb_api_t *api, const gchar *host,
+ const gchar *path, fb_http_func_t func,
+ const gchar *class, const gchar *name,
+ const gchar *method)
+{
+ fb_http_req_t *req;
+
+ req = fb_http_req_new(api->http, host, 443, path, func, api);
+ req->flags = FB_HTTP_REQ_FLAG_POST | FB_HTTP_REQ_FLAG_SSL;
+
+ fb_http_req_params_set(req,
+ FB_HTTP_PAIR("api_key", FB_API_KEY),
+ FB_HTTP_PAIR("fb_api_caller_class", class),
+ FB_HTTP_PAIR("fb_api_req_friendly_name", name),
+ FB_HTTP_PAIR("method", method),
+ FB_HTTP_PAIR("client_country_code", "US"),
+ FB_HTTP_PAIR("format", "json"),
+ FB_HTTP_PAIR("locale", "en_US"),
+ NULL
+ );
+
+ return req;
+}
+
+/**
+ * Sends a #fb_http_req for a #fb_api. This computes the signature for
+ * the request and sets the "sig" parameter. This sets the OAuth header
+ * for authorization.
+ *
+ * @param api The #fb_api.
+ * @param req The #fb_http_req.
+ **/
+static void fb_api_req_send(fb_api_t *api, fb_http_req_t *req)
+{
+ GString *gstr;
+ GList *keys;
+ GList *l;
+ const gchar *key;
+ const gchar *val;
+ gchar *hash;
+ gchar *auth;
+
+ /* Ensure an old signature is not computed */
+ g_hash_table_remove(req->params, "sig");
+
+ gstr = g_string_sized_new(128);
+ keys = g_hash_table_get_keys(req->params);
+ keys = g_list_sort(keys, (GCompareFunc) g_ascii_strcasecmp);
+
+ for (l = keys; l != NULL; l = l->next) {
+ key = l->data;
+ val = g_hash_table_lookup(req->params, key);
+ g_string_append_printf(gstr, "%s=%s", key, val);
+ }
+
+ g_string_append(gstr, FB_API_SECRET);
+ hash = g_compute_checksum_for_string(G_CHECKSUM_MD5, gstr->str, gstr->len);
+
+ fb_http_req_params_set(req,
+ FB_HTTP_PAIR("sig", hash),
+ NULL
+ );
+
+ g_free(hash);
+ g_list_free(keys);
+ g_string_free(gstr, TRUE);
+
+ if (api->token != NULL) {
+ auth = g_strdup_printf("OAuth %s", api->token);
+ fb_http_req_headers_set(req,
+ FB_HTTP_PAIR("Authorization", auth),
+ NULL
+ );
+ g_free(auth);
+ }
+
+ fb_http_req_send(req);
+}
+
+/**
* Implements #fb_mqtt_funcs->error().
*
* @param mqtt The #fb_mqtt.
@@ -74,7 +202,12 @@ static void fb_api_cb_mqtt_open(fb_mqtt_t *mqtt, gpointer data)
"\"a\":\"" FB_API_AGENT "\","
"\"mqtt_sid\":%s,"
"\"d\":\"%s\","
- "\"chat_on\":true"
+ "\"chat_on\":true,"
+ "\"no_auto_fg\":true,"
+ "\"fg\":false,"
+ "\"pf\":\"jz\","
+ "\"nwt\":1,"
+ "\"nwst\":0"
"}", api->uid, api->mid, api->cuid);
fb_mqtt_connect(mqtt,
@@ -88,6 +221,73 @@ static void fb_api_cb_mqtt_open(fb_mqtt_t *mqtt, gpointer data)
}
/**
+ * Implemented #fb_http_func for the sequence identifier.
+ *
+ * @param req The #fb_http_req.
+ * @param data The user-defined data, which is #fb_api.
+ **/
+static void fb_api_cb_seqid(fb_http_req_t *req, gpointer data)
+{
+ fb_api_t *api = data;
+ json_value *json;
+ json_value *jv;
+ const gchar *str;
+
+ json = fb_api_json_new(api, req->body, req->body_size);
+
+ if (json == NULL)
+ return;
+
+ /* Scattered values lead to a gnarly conditional... */
+ if (!fb_json_val_chk(json, "data", json_array, &jv) ||
+
+ /* Obtain the first array element */
+ (jv->u.array.length != 1) ||
+ ((jv = jv->u.array.values[0]) == NULL) ||
+
+ /* Check the name */
+ !fb_json_str_chk(jv, "name", &str) ||
+ (g_ascii_strcasecmp(str, "thread_list_ids") != 0) ||
+
+ /* Obtain the sequence identifier */
+ !fb_json_val_chk(jv, "fql_result_set", json_array, &jv) ||
+ (jv->u.array.length != 1) ||
+ !fb_json_str_chk(jv->u.array.values[0], "sync_sequence_id", &str))
+ {
+ fb_api_error(api, FB_API_ERROR, "Failed to obtain SequenceID");
+ goto finish;
+ }
+
+ if (G_UNLIKELY(api->stoken == NULL)) {
+ fb_api_publish(api, "/messenger_sync_create_queue", "{"
+ "\"device_params\":{},"
+ "\"encoding\":\"JSON\","
+ "\"max_deltas_able_to_process\":1250,"
+ "\"initial_titan_sequence_id\":%s,"
+ "\"sync_api_version\":2,"
+ "\"delta_batch_size\":125,"
+ "\"device_id\":\"%s\""
+ "}", str, api->cuid);
+
+ goto finish;
+ }
+
+ fb_api_publish(api, "/messenger_sync_get_diffs", "{"
+ "\"encoding\":\"JSON\","
+ "\"last_seq_id\":%s,"
+ "\"max_deltas_able_to_process\":1250,"
+ "\"sync_api_version\":2,"
+ "\"sync_token\":\"%s\","
+ "\"delta_batch_size\":125"
+ "}", str, api->stoken);
+
+ FB_API_FUNC(api, connect);
+
+finish:
+ json_value_free(json);
+}
+
+/**
* Implements #fb_mqtt_funcs->connack().
*
* @param mqtt The #fb_mqtt.
@@ -95,9 +295,122 @@ static void fb_api_cb_mqtt_open(fb_mqtt_t *mqtt, gpointer data)
**/
static void fb_api_cb_mqtt_connack(fb_mqtt_t *mqtt, gpointer data)
{
- fb_api_t *api = data;
+ fb_api_t *api = data;
+ fb_http_req_t *req;
- FB_API_FUNC(api, connect);
+ fb_api_publish(api, "/foreground_state", "{"
+ "\"foreground\": true,"
+ "\"keepalive_timeout\": %d"
+ "}", FB_MQTT_KA);
+
+ fb_mqtt_subscribe(mqtt,
+ "/quick_promotion_refresh", 0,
+ "/webrtc", 0,
+ "/delete_messages_notification", 0,
+ "/orca_message_notifications", 0,
+ "/messaging_events", 0,
+ "/mercury", 0,
+ "/t_rtc", 0,
+ "/inbox", 0,
+ "/orca_presence", 0,
+ "/webrtc_response", 0,
+ "/push_notification", 0,
+ "/pp", 0,
+ "/orca_typing_notifications", 0,
+ "/t_ms", 0,
+ "/t_p", 0,
+ NULL
+ );
+
+ req = fb_api_req_new(api, FB_API_GHOST, FB_API_PATH_FQL,
+ fb_api_cb_seqid,
+ "com.facebook.orca.protocol.methods.u",
+ "fetchThreadList",
+ "GET");
+
+ static const gchar *query = "{"
+ "\"thread_list_ids\":\""
+ "SELECT sync_sequence_id "
+ "FROM unified_thread "
+ "WHERE folder='inbox' "
+ "ORDER BY sync_sequence_id "
+ "DESC LIMIT 1\""
+ "}";
+
+ fb_http_req_params_set(req, FB_HTTP_PAIR("q", query), NULL);
+ fb_api_req_send(api, req);
+}
+
+/**
+ * Handles messages which are to be published to the user.
+ *
+ * @param api The #fb_api.
+ * @param pload The message payload.
+ **/
+static void fb_api_cb_publish_ms(fb_api_t *api, const GByteArray *pload)
+{
+ GSList *msgs;
+ fb_api_msg_t *msg;
+ json_value *json;
+ json_value *jv;
+ json_value *jx;
+ json_value *jy;
+ json_value *jz;
+ const gchar *str;
+ gint64 in;
+ gint64 auid;
+ guint i;
+
+ /* Start at 1 to skip the NULL byte */
+ json = fb_api_json_new(api, (gchar*) pload->data + 1, pload->len - 1);
+ auid = g_ascii_strtoll(api->uid, NULL, 10);
+ msgs = NULL;
+
+ if (json == NULL)
+ return;
+
+ if (fb_json_str_chk(json, "syncToken", &str)) {
+ g_free(api->stoken);
+ api->stoken = g_strdup(str);
+ FB_API_FUNC(api, connect);
+ goto finish;
+ }
+
+ if (!fb_json_val_chk(json, "deltas", json_array, &jv))
+ goto finish;
+
+ for (i = 0; i < jv->u.array.length; i++) {
+ jx = jv->u.array.values[i];
+
+ if (!fb_json_val_chk(jx, "deltaNewMessage", json_object, &jy) ||
+ !fb_json_val_chk(jy, "messageMetadata", json_object, &jz) ||
+ !fb_json_int_chk(jz, "actorFbId", &in) ||
+ (in == auid))
+ {
+ continue;
+ }
+
+ if (fb_json_str_chk(jy, "body", &str)) {
+ msg = fb_api_msg_new(NULL, str);
+ msg->uid = g_strdup_printf("%" G_GINT64_FORMAT, in);
+ msgs = g_slist_prepend(msgs, msg);
+ }
+
+ if (fb_json_val_chk(jy, "attachments", json_array, &jy) &&
+ (jy->u.array.length > 0))
+ {
+ msg = fb_api_msg_new(NULL, "* Non-Displayable Attachments *");
+ msg->uid = g_strdup_printf("%" G_GINT64_FORMAT, in);
+ msgs = g_slist_prepend(msgs, msg);
+ }
+ }
+
+ msgs = g_slist_reverse(msgs);
+ FB_API_FUNC(api, message, msgs);
+
+finish:
+ g_slist_free_full(msgs, (GDestroyNotify) fb_api_msg_free);
+ json_value_free(json);
}
/**
@@ -128,7 +441,10 @@ static void fb_api_cb_mqtt_publish(fb_mqtt_t *mqtt, const gchar *topic,
bytes = (GByteArray*) pload;
}
- fb_util_hexdump(bytes, 2, "Publishing:");
+ fb_util_hexdump(bytes, 2, "Reading message:");
+
+ if (g_ascii_strcasecmp(topic, "/t_ms") == 0)
+ fb_api_cb_publish_ms(api, bytes);
if (G_LIKELY(comp))
g_byte_array_free(bytes, TRUE);
@@ -183,7 +499,7 @@ void fb_api_rehash(fb_api_t *api)
api->cid = g_compute_checksum_for_data(G_CHECKSUM_MD5, rb, sizeof rb);
}
- if (api->mid == NULL)
+ if (api->mid == 0)
api->mid = g_strdup_printf("%" G_GUINT32_FORMAT, g_random_int());
if (api->cuid == NULL) {
@@ -215,10 +531,10 @@ void fb_api_free(fb_api_t *api)
fb_mqtt_free(api->mqtt);
fb_http_free(api->http);
- g_free(api->sid);
g_free(api->cuid);
g_free(api->mid);
g_free(api->cid);
+ g_free(api->stoken);
g_free(api->token);
g_free(api->uid);
g_free(api);
@@ -256,134 +572,6 @@ void fb_api_error(fb_api_t *api, fb_api_error_t err, const gchar *fmt, ...)
}
/**
- * Creates a new #json_value for JSON contents of the #fb_api. This
- * function is special in that it handles all errors, unlike the parent
- * function #fb_json_new(). The returned #json_value should be freed
- * with #json_value_free() when no longer needed.
- *
- * @param api The #fb_api.
- * @param data The data.
- * @param size The size of the data.
- *
- * @return TRUE if the data was parsed without error, otherwise FALSE.
- **/
-static json_value *fb_api_json_new(fb_api_t *api, const gchar *data,
- gsize size)
-{
- json_value *json;
- const gchar *msg;
- gint64 code;
-
- json = fb_json_new(data, size, &api->err);
-
- if (api->err != NULL) {
- fb_api_error(api, 0, NULL);
- return NULL;
- }
-
- if (fb_json_int_chk(json, "error_code", &code)) {
- if (!fb_json_str_chk(json, "error_msg", &msg))
- msg = "Generic Error";
-
- fb_api_error(api, FB_API_ERROR_GENERAL, "%s", msg);
- json_value_free(json);
- return NULL;
- }
-
- return json;
-}
-
-/**
- * Creates a new #fb_http_req for a #fb_api request.
- *
- * @param api The #fb_api.
- * @param host The host.
- * @param path The path.
- * @param func The #fb_http_func.
- * @param class The class.
- * @param name The friendly name.
- * @param method The method.
- **/
-static fb_http_req_t *fb_api_req_new(fb_api_t *api, const gchar *host,
- const gchar *path, fb_http_func_t func,
- const gchar *class, const gchar *name,
- const gchar *method)
-{
- fb_http_req_t *req;
-
- req = fb_http_req_new(api->http, host, 443, path, func, api);
- req->flags = FB_HTTP_REQ_FLAG_POST | FB_HTTP_REQ_FLAG_SSL;
-
- fb_http_req_params_set(req,
- FB_HTTP_PAIR("api_key", FB_API_KEY),
- FB_HTTP_PAIR("fb_api_caller_class", class),
- FB_HTTP_PAIR("fb_api_req_friendly_name", name),
- FB_HTTP_PAIR("method", method),
- FB_HTTP_PAIR("client_country_code", "US"),
- FB_HTTP_PAIR("format", "json"),
- FB_HTTP_PAIR("locale", "en_US"),
- NULL
- );
-
- return req;
-}
-
-/**
- * Sends a #fb_http_req for a #fb_api. This computes the signature for
- * the request and sets the "sig" parameter. This sets the OAuth header
- * for authorization.
- *
- * @param api The #fb_api.
- * @param req The #fb_http_req.
- **/
-static void fb_api_req_send(fb_api_t *api, fb_http_req_t *req)
-{
- GString *gstr;
- GList *keys;
- GList *l;
- const gchar *key;
- const gchar *val;
- gchar *hash;
- gchar *auth;
-
- /* Ensure an old signature is not computed */
- g_hash_table_remove(req->params, "sig");
-
- gstr = g_string_sized_new(128);
- keys = g_hash_table_get_keys(req->params);
- keys = g_list_sort(keys, (GCompareFunc) g_ascii_strcasecmp);
-
- for (l = keys; l != NULL; l = l->next) {
- key = l->data;
- val = g_hash_table_lookup(req->params, key);
- g_string_append_printf(gstr, "%s=%s", key, val);
- }
-
- g_string_append(gstr, FB_API_SECRET);
- hash = g_compute_checksum_for_string(G_CHECKSUM_MD5, gstr->str, gstr->len);
-
- fb_http_req_params_set(req,
- FB_HTTP_PAIR("sig", hash),
- NULL
- );
-
- g_free(hash);
- g_list_free(keys);
- g_string_free(gstr, TRUE);
-
- if (api->token != NULL) {
- auth = g_strdup_printf("OAuth %s", api->token);
- fb_http_req_headers_set(req,
- FB_HTTP_PAIR("Authorization", auth),
- NULL
- );
- g_free(auth);
- }
-
- fb_http_req_send(req);
-}
-
-/**
* Implemented #fb_http_func for #fb_api_auth().
*
* @param req The #fb_http_req.
@@ -571,6 +759,100 @@ void fb_api_disconnect(fb_api_t *api)
}
/**
+ * Sends a message to a user.
+ *
+ * @param api The #fb_api.
+ * @param uid The target user identifier.
+ * @param msg The message.
+ **/
+void fb_api_message(fb_api_t *api, const gchar *uid, const gchar *msg)
+{
+ guint64 msgid;
+
+ g_return_if_fail(api != NULL);
+ g_return_if_fail(uid != NULL);
+ g_return_if_fail(msg != NULL);
+
+ msgid = FB_API_MSGID(g_get_real_time() / 1000, g_random_int());
+
+ fb_api_publish(api, "/send_message2", "{"
+ "\"body\":\"%s\","
+ "\"to\":\"%s\","
+ "\"sender_fbid\":\"%s\","
+ "\"msgid\":%" G_GUINT64_FORMAT
+ "}", msg, uid, api->uid, msgid);
+}
+
+/**
+ * Publishes a string based message to the MQTT service. This enables
+ * compression of the message via zlib.
+ *
+ * @param api The #fb_api.
+ * @param topic The message topic.
+ * @param fmt The format string.
+ * @param ... The format arguments.
+ **/
+void fb_api_publish(fb_api_t *api, const gchar *topic, const gchar *fmt, ...)
+{
+ GByteArray *bytes;
+ GByteArray *cytes;
+ gchar *msg;
+ va_list ap;
+
+ g_return_if_fail(api != NULL);
+ g_return_if_fail(topic != NULL);
+ g_return_if_fail(fmt != NULL);
+
+ va_start(ap, fmt);
+ msg = g_strdup_vprintf(fmt, ap);
+ va_end(ap);
+
+ bytes = g_byte_array_new_take((guint8*) msg, strlen(msg));
+ cytes = fb_util_zcompress(bytes);
+
+ fb_util_hexdump(bytes, 2, "Writing message:");
+ fb_mqtt_publish(api->mqtt, topic, cytes);
+
+ g_byte_array_free(cytes, TRUE);
+ g_byte_array_free(bytes, TRUE);
+}
+
+/**
+ * Creates a new #fb_api_msg. The returned #fb_api_msg should be freed
+ * with #fb_api_msg_free() when no longer needed.
+ *
+ * @param uid The user identifier.
+ * @param text The message text.
+ *
+ * @return The #fb_api_msg or NULL on error.
+ **/
+fb_api_msg_t *fb_api_msg_new(const gchar *uid, const gchar *text)
+{
+ fb_api_msg_t *msg;
+
+ msg = g_new0(fb_api_msg_t, 1);
+ msg->uid = g_strdup(uid);
+ msg->text = g_strdup(text);
+
+ return msg;
+}
+
+/**
+ * Frees all memory used by a #fb_api_msg.
+ *
+ * @param msg The #fb_api_msg.
+ **/
+void fb_api_msg_free(fb_api_msg_t *msg)
+{
+ if (G_UNLIKELY(msg == NULL))
+ return;
+
+ g_free(msg->text);
+ g_free(msg->uid);
+ g_free(msg);
+}
+
+/**
* 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 b6bd8bd..5c84967 100644
--- a/facebook/facebook-api.h
+++ b/facebook/facebook-api.h
@@ -34,11 +34,11 @@
#define FB_API_SECRET "374e60f8b9bb6b8cbb30f78030438895"
#define FB_API_PATH_AUTH "/method/auth.login"
+#define FB_API_PATH_FQL "/fql"
#define FB_API_PATH_GQL "/graphql"
#define FB_API_QRYID_CONTACTS "10153122424521729"
-
/**
* Executes one of the #fb_api_funcs.
*
@@ -53,6 +53,19 @@
} \
} G_STMT_END
+/**
+ * Creates a message identifier.
+ *
+ * @param m The time in miliseconds (UTC).
+ * @param i The random integer.
+ *
+ * @return The 64-bit message identifier.
+ **/
+#define FB_API_MSGID(m, i) ((guint64) ( \
+ (((guint32) i) & 0x3FFFFF) | \
+ (((guint64) m) << 22) \
+ ))
+
/** The #GError codes of #fb_api. **/
typedef enum fb_api_error fb_api_error_t;
@@ -63,6 +76,9 @@ typedef struct fb_api fb_api_t;
/** The main structure for #fb_api callback functions. **/
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 user. **/
typedef struct fb_api_user fb_api_user_t;
@@ -120,6 +136,16 @@ struct fb_api_funcs
* @param data The user-defined data or NULL.
**/
void (*contacts) (fb_api_t *api, const GSList *users, gpointer data);
+
+ /**
+ * The message function. This is called whenever the #fb_api has
+ * retrieved a message.
+ *
+ * @param api The #fb_api.
+ * @param msgs The #GSList of #fb_api_msg.
+ * @param data The user-defined data or NULL.
+ **/
+ void (*message) (fb_api_t *api, const GSList *msgs, gpointer data);
};
/**
@@ -136,10 +162,19 @@ struct fb_api
gchar *uid; /** The user identifier. **/
gchar *token; /** The session token. **/
+ gchar *stoken; /** The sync token. **/
gchar *cid; /** The client identifier. **/
gchar *mid; /** The MQTT identifier. **/
gchar *cuid; /** The client unique identifier. **/
- gchar *sid; /** The sync identifier. **/
+};
+
+/**
+ * The structure for representing an #fb_api message.
+ **/
+struct fb_api_msg
+{
+ gchar *uid; /** The user identifier. **/
+ gchar *text; /** The message text. **/
};
/**
@@ -172,6 +207,14 @@ void fb_api_connect(fb_api_t *api);
void fb_api_disconnect(fb_api_t *api);
+void fb_api_message(fb_api_t *api, const gchar *uid, const gchar *msg);
+
+void fb_api_publish(fb_api_t *api, const gchar *topic, const gchar *fmt, ...);
+
+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_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 aed3893..a35a837 100644
--- a/facebook/facebook.c
+++ b/facebook/facebook.c
@@ -62,10 +62,12 @@ 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;
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;
@@ -101,6 +103,25 @@ static void fb_cb_api_contacts(fb_api_t *api, const GSList *users,
}
/**
+ * Implemented #fb_api_funcs->message().
+ *
+ * @param api The #fb_api.
+ * @param msgs The #GSList of #fb_api_msg.
+ * @param data The user defined data, which is #fb_data.
+ **/
+static void fb_cb_api_message(fb_api_t *api, const GSList *msgs, gpointer data)
+{
+ fb_data_t *fata = data;
+ fb_api_msg_t *msg;
+ const GSList *l;
+
+ for (l = msgs; l != NULL; l = l->next) {
+ msg = l->data;
+ imcb_buddy_msg(fata->ic, msg->uid, (gchar*) msg->text, 0, 0);
+ }
+}
+
+/**
* Creates a new #fb_data with an #account. The returned #fb_data
* should be freed with #fb_data_free() when no longer needed.
*
@@ -116,7 +137,8 @@ fb_data_t *fb_data_new(account_t *acc)
.error = fb_cb_api_error,
.auth = fb_cb_api_auth,
.connect = fb_cb_api_connect,
- .contacts = fb_cb_api_contacts
+ .contacts = fb_cb_api_contacts,
+ .message = fb_cb_api_message
};
g_return_val_if_fail(acc != NULL, NULL);
@@ -127,11 +149,12 @@ fb_data_t *fb_data_new(account_t *acc)
fata->ic = imcb_new(acc);
fata->ic->proto_data = fata;
- fata->api->uid = g_strdup(set_getstr(&acc->set, "uid"));
- fata->api->token = g_strdup(set_getstr(&acc->set, "token"));
- fata->api->cid = g_strdup(set_getstr(&acc->set, "cid"));
- fata->api->mid = g_strdup(set_getstr(&acc->set, "mid"));
- fata->api->cuid = g_strdup(set_getstr(&acc->set, "cuid"));
+ fata->api->uid = g_strdup(set_getstr(&acc->set, "uid"));
+ fata->api->token = g_strdup(set_getstr(&acc->set, "token"));
+ fata->api->stoken = g_strdup(set_getstr(&acc->set, "stoken"));
+ fata->api->cid = g_strdup(set_getstr(&acc->set, "cid"));
+ fata->api->mid = g_strdup(set_getstr(&acc->set, "mid"));
+ fata->api->cuid = g_strdup(set_getstr(&acc->set, "cuid"));
fb_api_rehash(fata->api);
@@ -177,6 +200,9 @@ static void fb_init(account_t *acc)
s = set_add(&acc->set, "token", NULL, NULL, acc);
s->flags = SET_NULL_OK | SET_HIDDEN | SET_PASSWORD;
+ s = set_add(&acc->set, "stoken", NULL, NULL, acc);
+ s->flags = SET_NULL_OK | SET_HIDDEN;
+
s = set_add(&acc->set, "uid", NULL, NULL, acc);
s->flags = SET_NULL_OK | SET_HIDDEN;
}
@@ -229,6 +255,9 @@ static void fb_logout(struct im_connection *ic)
static int fb_buddy_msg(struct im_connection *ic, char *to, char *message,
int flags)
{
+ fb_data_t *fata = ic->proto_data;
+
+ fb_api_message(fata->api, to, message);
return 0;
}