aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjgeboski <jgeboski@gmail.com>2015-01-15 19:19:28 -0500
committerjgeboski <jgeboski@gmail.com>2015-01-15 21:23:44 -0500
commita2cdeab81cb287063f8ed4be01263c284d4d94d6 (patch)
tree2832b457b54b0230fc5b66f7ea7edc81872b160d
parent68c46dd797ad24642b69d7dd8914a521cd20e87f (diff)
downloadbitlbee-facebook-a2cdeab81cb287063f8ed4be01263c284d4d94d6.tar.gz
bitlbee-facebook-a2cdeab81cb287063f8ed4be01263c284d4d94d6.tar.bz2
bitlbee-facebook-a2cdeab81cb287063f8ed4be01263c284d4d94d6.tar.xz
Implemented typing notifications
-rw-r--r--facebook/facebook-api.c98
-rw-r--r--facebook/facebook-api.h28
-rw-r--r--facebook/facebook.c25
3 files changed, 149 insertions, 2 deletions
diff --git a/facebook/facebook-api.c b/facebook/facebook-api.c
index 5187c81..39db434 100644
--- a/facebook/facebook-api.c
+++ b/facebook/facebook-api.c
@@ -343,6 +343,47 @@ static void fb_api_cb_mqtt_connack(fb_mqtt_t *mqtt, gpointer data)
}
/**
+ * Handles typing notifications which are to be published to the user.
+ *
+ * @param api The #fb_api.
+ * @param pload The message payload.
+ **/
+static void fb_api_cb_publish_tn(fb_api_t *api, const GByteArray *pload)
+{
+ json_value *json;
+ fb_api_typing_t *typg;
+ const gchar *str;
+ gint64 uid;
+ gint64 state;
+
+ json = fb_api_json_new(api, (gchar*) pload->data, pload->len);
+
+ if (json == NULL)
+ return;
+
+ if (!fb_json_str_chk(json, "type", &str) ||
+ (g_ascii_strcasecmp(str, "typ") != 0))
+ {
+ goto finish;
+ }
+
+ if (!fb_json_int_chk(json, "sender_fbid", &uid) ||
+ !fb_json_int_chk(json, "state", &state))
+ {
+ fb_api_error(api, FB_API_ERROR, "Failed to obtain typing state");
+ goto finish;
+ }
+
+ typg = fb_api_typing_new(NULL, state != 0);
+ typg->uid = g_strdup_printf("%" G_GINT64_FORMAT, uid);
+ FB_API_FUNC(api, typing, typg);
+ fb_api_typing_free(typg);
+
+finish:
+ json_value_free(json);
+}
+
+/**
* Handles message responses which publish the next message queued.
*
* @param api The #fb_api.
@@ -563,7 +604,10 @@ static void fb_api_cb_mqtt_publish(fb_mqtt_t *mqtt, const gchar *topic,
fb_util_hexdump(bytes, 2, "Reading message:");
- if (g_ascii_strcasecmp(topic, "/send_message_response") == 0)
+
+ if (g_ascii_strcasecmp(topic, "/orca_typing_notifications") == 0)
+ fb_api_cb_publish_tn(api, bytes);
+ else if (g_ascii_strcasecmp(topic, "/send_message_response") == 0)
fb_api_cb_publish_mr(api, bytes);
else if (g_ascii_strcasecmp(topic, "/t_ms") == 0)
fb_api_cb_publish_ms(api, bytes);
@@ -950,6 +994,24 @@ void fb_api_publish(fb_api_t *api, const gchar *topic, const gchar *fmt, ...)
}
/**
+ * Sends a typing state to a user.
+ *
+ * @param api The #fb_api.
+ * @param uid The target user identifier.
+ * @param state TRUE if the user is typing, otherwise FALSE.
+ **/
+void fb_api_typing(fb_api_t *api, const gchar *uid, gboolean state)
+{
+ g_return_if_fail(api != NULL);
+ g_return_if_fail(uid != NULL);
+
+ fb_api_publish(api, "/typing", "{"
+ "\"to\":\"%s\","
+ "\"state\":%d"
+ "}", uid, state != 0);
+}
+
+/**
* Creates a new #fb_api_msg. The returned #fb_api_msg should be freed
* with #fb_api_msg_free() when no longer needed.
*
@@ -1019,6 +1081,40 @@ void fb_api_pres_free(fb_api_pres_t *pres)
}
/**
+ * Creates a new #fb_api_typing. The returned #fb_api_typing should be
+ * freed with #fb_api_typing_free() when no longer needed.
+ *
+ * @param uid The user identifier.
+ * @param state TRUE if the user is typing, otherwise FALSE.
+ *
+ * @return The #fb_api_typing or NULL on error.
+ **/
+fb_api_typing_t *fb_api_typing_new(const gchar *uid, gboolean state)
+{
+ fb_api_typing_t *typg;
+
+ typg = g_new0(fb_api_typing_t, 1);
+ typg->uid = g_strdup(uid);
+ typg->state = state;
+
+ return typg;
+}
+
+/**
+ * Frees all memory used by a #fb_api_typing.
+ *
+ * @param typg The #fb_api_typing.
+ **/
+void fb_api_typing_free(fb_api_typing_t *typg)
+{
+ if (G_UNLIKELY(typg == NULL))
+ return;
+
+ g_free(typg->uid);
+ g_free(typg);
+}
+
+/**
* 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 0ea0be0..2caace2 100644
--- a/facebook/facebook-api.h
+++ b/facebook/facebook-api.h
@@ -82,6 +82,9 @@ 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 typing state. **/
+typedef struct fb_api_typing fb_api_typing_t;
+
/** The structure for representing an #fb_api user. **/
typedef struct fb_api_user fb_api_user_t;
@@ -159,6 +162,16 @@ struct fb_api_funcs
* @param data The user-defined data or NULL.
**/
void (*presence) (fb_api_t *api, const GSList *press, gpointer data);
+
+ /**
+ * The typing function. This is called whenever the #fb_api has
+ * retrieved a typing state update.
+ *
+ * @param api The #fb_api.
+ * @param typg The #fb_api_typing.
+ * @param data The user-defined data or NULL.
+ **/
+ void (*typing) (fb_api_t *api, fb_api_typing_t *typg, gpointer data);
};
/**
@@ -201,6 +214,15 @@ struct fb_api_pres
};
/**
+ * The structure for representing an #fb_api user typing state.
+ **/
+struct fb_api_typing
+{
+ gchar *uid; /** The user identifier. **/
+ gboolean state; /** TRUE if the user is typing. **/
+};
+
+/**
* The structure for representing an #fb_api user.
**/
struct fb_api_user
@@ -234,6 +256,8 @@ 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, ...);
+void fb_api_typing(fb_api_t *api, const gchar *uid, gboolean state);
+
fb_api_msg_t *fb_api_msg_new(const gchar *uid, const gchar *text);
void fb_api_msg_free(fb_api_msg_t *msg);
@@ -242,6 +266,10 @@ 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_typing_t *fb_api_typing_new(const gchar *uid, gboolean state);
+
+void fb_api_typing_free(fb_api_typing_t *typg);
+
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 4622ff3..6ab46a3 100644
--- a/facebook/facebook.c
+++ b/facebook/facebook.c
@@ -139,6 +139,23 @@ static void fb_cb_api_presence(fb_api_t *api, const GSList *press,
}
/**
+ * Implemented #fb_api_funcs->typing().
+ *
+ * @param api The #fb_api.
+ * @param typg The #fb_api_typing.
+ * @param data The user defined data, which is #fb_data.
+ **/
+static void fb_cb_api_typing(fb_api_t *api, fb_api_typing_t *typg,
+ gpointer data)
+{
+ fb_data_t *fata = data;
+ guint32 flags;
+
+ flags = typg->state ? OPT_TYPING : 0;
+ imcb_buddy_typing(fata->ic, typg->uid, flags);
+}
+
+/**
* Creates a new #fb_data with an #account. The returned #fb_data
* should be freed with #fb_data_free() when no longer needed.
*
@@ -156,7 +173,8 @@ fb_data_t *fb_data_new(account_t *acc)
.connect = fb_cb_api_connect,
.contacts = fb_cb_api_contacts,
.message = fb_cb_api_message,
- .presence = fb_cb_api_presence
+ .presence = fb_cb_api_presence,
+ .typing = fb_cb_api_typing
};
g_return_val_if_fail(acc != NULL, NULL);
@@ -290,6 +308,11 @@ static int fb_buddy_msg(struct im_connection *ic, char *to, char *message,
**/
static int fb_send_typing(struct im_connection *ic, char *who, int flags)
{
+ fb_data_t *fata = ic->proto_data;
+ gboolean state;
+
+ state = (flags & OPT_TYPING) != 0;
+ fb_api_typing(fata->api, who, state);
return 0;
}