Sun, 05 Jul 2015 14:44:14 -0400
facebook: implemented kicking/leaving group chats
--- a/libpurple/protocols/facebook/api.c Sat Jul 04 13:26:42 2015 -0400 +++ b/libpurple/protocols/facebook/api.c Sun Jul 05 14:44:14 2015 -0400 @@ -1219,6 +1219,7 @@ FbApiPrivate *priv = api->priv; FbApiThread thrd; FbApiUser user; + gboolean haself; gchar *str; GError *err = NULL; GList *elms = NULL; @@ -1258,7 +1259,7 @@ FB_API_ERROR_CHK(api, err, goto finish); elms2 = json_array_get_elements(arr2); - for (m = elms2; m != NULL; m = m->next) { + for (haself = FALSE, m = elms2; m != NULL; m = m->next) { node2 = m->data; fb_api_user_reset(&user, FALSE); @@ -1268,6 +1269,7 @@ g_free(str); if (user.uid == priv->uid) { + haself = TRUE; continue; } @@ -1289,8 +1291,12 @@ continue; } - mptr = fb_api_thread_dup(&thrd, FALSE); - thrds = g_slist_prepend(thrds, mptr); + if (haself) { + mptr = fb_api_thread_dup(&thrd, FALSE); + thrds = g_slist_prepend(thrds, mptr); + } else { + fb_api_thread_reset(&thrd, TRUE); + } } ret = g_slist_reverse(thrds); @@ -1428,6 +1434,42 @@ } void +fb_api_thread_remove(FbApi *api, FbId tid, FbId uid) +{ + FbApiPrivate *priv; + FbHttpParams *prms; + gchar *json; + JsonBuilder *bldr; + + static const FbApiHttpInfo info = { + fb_api_cb_http_bool, + "com.facebook.orca.protocol.a", + "removeMembers", + "DELETE" + }; + + g_return_if_fail(api != NULL); + priv = api->priv; + + prms = fb_http_params_new(); + fb_http_params_set_strf(prms, "id", "t_id.%" FB_ID_FORMAT, tid); + + if (uid == 0) { + uid = priv->uid; + } + + if (uid != priv->uid) { + bldr = fb_json_bldr_new(JSON_NODE_ARRAY); + fb_json_bldr_add_strf(bldr, NULL, "%" FB_ID_FORMAT, uid); + json = fb_json_bldr_close(bldr, JSON_NODE_ARRAY, NULL); + fb_http_params_set_str(prms, "to", json); + g_free(json); + } + + fb_api_http_req(api, &info, prms, FB_API_URL_PARTS); +} + +void fb_api_thread_topic(FbApi *api, FbId tid, const gchar *topic) { FbHttpParams *prms;
--- a/libpurple/protocols/facebook/api.h Sat Jul 04 13:26:42 2015 -0400 +++ b/libpurple/protocols/facebook/api.h Sun Jul 05 14:44:14 2015 -0400 @@ -191,6 +191,9 @@ fb_api_thread_list(FbApi *api); void +fb_api_thread_remove(FbApi *api, FbId tid, FbId uid); + +void fb_api_thread_topic(FbApi *api, FbId tid, const gchar *topic); void
--- a/libpurple/protocols/facebook/facebook.c Sat Jul 04 13:26:42 2015 -0400 +++ b/libpurple/protocols/facebook/facebook.c Sun Jul 05 14:44:14 2015 -0400 @@ -30,11 +30,13 @@ #include "version.h" #include "api.h" +#include "cmds.h" #include "data.h" #include "facebook.h" #include "util.h" -static PurpleProtocol *my_protocol = NULL; +static GSList *fb_cmds = NULL; +static PurpleProtocol *fb_protocol = NULL; static void fb_cb_api_error(FbApi *api, GError *error, gpointer data); @@ -739,6 +741,79 @@ g_object_unref(list); } +static PurpleCmdRet +fb_cmd_kick(PurpleConversation *conv, const gchar *cmd, gchar **args, + gchar **error, gpointer data) +{ + const gchar *name; + FbApi *api; + FbData *fata; + FbId tid; + FbId uid; + GError *err = NULL; + PurpleAccount *acct; + PurpleBuddy *bdy; + PurpleConnection *gc; + PurpleChatConversation *chat; + + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(conv), + PURPLE_CMD_RET_FAILED); + + gc = purple_conversation_get_connection(conv); + acct = purple_connection_get_account(gc); + chat = PURPLE_CHAT_CONVERSATION(conv); + bdy = fb_util_account_find_buddy(acct, chat, args[0], &err); + + if (err != NULL) { + *error = g_strdup_printf(_("%s."), err->message); + g_error_free(err); + return PURPLE_CMD_RET_FAILED; + } + + fata = purple_connection_get_protocol_data(gc); + api = fb_data_get_api(fata); + + name = purple_conversation_get_name(conv); + tid = FB_ID_FROM_STR(name); + + 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; +} + +static PurpleCmdRet +fb_cmd_leave(PurpleConversation *conv, const gchar *cmd, gchar **args, + gchar **error, gpointer data) +{ + const gchar *name; + FbApi *api; + FbData *fata; + FbId tid; + gint id; + PurpleConnection *gc; + PurpleChatConversation *chat; + + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(conv), + PURPLE_CMD_RET_FAILED); + + gc = purple_conversation_get_connection(conv); + fata = purple_connection_get_protocol_data(gc); + api = fb_data_get_api(fata); + + chat = PURPLE_CHAT_CONVERSATION(conv); + id = purple_chat_conversation_get_id(chat); + + name = purple_conversation_get_name(conv); + tid = FB_ID_FROM_STR(name); + + purple_serv_got_chat_left(gc, id); + fb_api_thread_remove(api, tid, 0); + return PURPLE_CMD_RET_OK; +} + static void facebook_protocol_init(PurpleProtocol *protocol) { @@ -814,6 +889,43 @@ facebook_protocol_roomlist_iface_init) ); +static void +fb_cmds_register(void) +{ + PurpleCmdId id; + + static PurpleCmdFlag cflags = + PURPLE_CMD_FLAG_CHAT | + PURPLE_CMD_FLAG_PROTOCOL_ONLY; + + g_return_if_fail(fb_cmds == NULL); + + id = purple_cmd_register("kick", "s", PURPLE_CMD_P_PROTOCOL, cflags, + fb_protocol->id, fb_cmd_kick, + _("kick: Kick someone from the chat"), + NULL); + fb_cmds = g_slist_prepend(fb_cmds, GUINT_TO_POINTER(id)); + + id = purple_cmd_register("leave", "", PURPLE_CMD_P_PROTOCOL, cflags, + fb_protocol->id, fb_cmd_leave, + _("leave: Leave the chat"), + NULL); + fb_cmds = g_slist_prepend(fb_cmds, GUINT_TO_POINTER(id)); +} + +static void +fb_cmds_unregister_free(gpointer data) +{ + PurpleCmdId id = GPOINTER_TO_UINT(data); + purple_cmd_unregister(id); +} + +static void +fb_cmds_unregister(void) +{ + g_slist_free_full(fb_cmds, fb_cmds_unregister_free); +} + static PurplePluginInfo * plugin_query(GError **error) { @@ -836,14 +948,21 @@ plugin_load(PurplePlugin *plugin, GError **error) { facebook_protocol_register_type(plugin); - my_protocol = purple_protocols_add(FACEBOOK_TYPE_PROTOCOL, error); - return my_protocol != NULL; + fb_protocol = purple_protocols_add(FACEBOOK_TYPE_PROTOCOL, error); + + if (fb_protocol == NULL) { + return FALSE; + } + + fb_cmds_register(); + return TRUE; } static gboolean plugin_unload(PurplePlugin *plugin, GError **error) { - return purple_protocols_remove(my_protocol, error); + fb_cmds_unregister(); + return purple_protocols_remove(fb_protocol, error); } PURPLE_PLUGIN_INIT(facebook, plugin_query, plugin_load, plugin_unload);
--- a/libpurple/protocols/facebook/json.c Sat Jul 04 13:26:42 2015 -0400 +++ b/libpurple/protocols/facebook/json.c Sun Jul 05 14:44:14 2015 -0400 @@ -128,28 +128,40 @@ void fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value) { - json_builder_set_member_name(bldr, name); + if (name != NULL) { + json_builder_set_member_name(bldr, name); + } + json_builder_add_boolean_value(bldr, value); } void fb_json_bldr_add_dbl(JsonBuilder *bldr, const gchar *name, gdouble value) { - json_builder_set_member_name(bldr, name); + if (name != NULL) { + json_builder_set_member_name(bldr, name); + } + json_builder_add_double_value(bldr, value); } void fb_json_bldr_add_int(JsonBuilder *bldr, const gchar *name, gint64 value) { - json_builder_set_member_name(bldr, name); + if (name != NULL) { + json_builder_set_member_name(bldr, name); + } + json_builder_add_int_value(bldr, value); } void fb_json_bldr_add_str(JsonBuilder *bldr, const gchar *name, const gchar *value) { - json_builder_set_member_name(bldr, name); + if (name != NULL) { + json_builder_set_member_name(bldr, name); + } + json_builder_add_string_value(bldr, value); } @@ -164,9 +176,7 @@ value = g_strdup_vprintf(format, ap); va_end(ap); - json_builder_set_member_name(bldr, name); - json_builder_add_string_value(bldr, value); - + fb_json_bldr_add_str(bldr, name, value); g_free(value); }
--- a/libpurple/protocols/facebook/util.c Sat Jul 04 13:26:42 2015 -0400 +++ b/libpurple/protocols/facebook/util.c Sun Jul 05 14:44:14 2015 -0400 @@ -27,6 +27,68 @@ #include "util.h" +GQuark +fb_util_error_quark(void) +{ + static GQuark q = 0; + + if (G_UNLIKELY(q == 0)) { + q = g_quark_from_static_string("fb-util-error-quark"); + } + + return q; +} + +PurpleBuddy * +fb_util_account_find_buddy(PurpleAccount *acct, PurpleChatConversation *chat, + const gchar *search, GError **error) +{ + const gchar *alias; + const gchar *name; + GSList *buddies; + GSList *l; + guint retc; + PurpleBuddy *ret = NULL; + + g_return_val_if_fail(acct != NULL, NULL); + g_return_val_if_fail(search != NULL, NULL); + + buddies = purple_blist_find_buddies(acct, NULL); + + for (retc = 0, l = buddies; l != NULL; l = l->next) { + name = purple_buddy_get_name(l->data); + alias = purple_buddy_get_alias(l->data); + + if ((chat != NULL) && + !purple_chat_conversation_has_user(chat, name)) + { + continue; + } + + if (g_ascii_strcasecmp(name, search) == 0) { + ret = l->data; + retc++; + } + + if (g_ascii_strcasecmp(alias, search) == 0) { + ret = l->data; + retc++; + } + } + + if (retc == 0) { + g_set_error(error, FB_UTIL_ERROR, FB_UTIL_ERROR_GENERAL, + _("Buddy %s not found"), search); + } else if (retc > 1) { + g_set_error(error, FB_UTIL_ERROR, FB_UTIL_ERROR_GENERAL, + _("Buddy name %s is ambiguous"), search); + ret = NULL; + } + + g_slist_free(buddies); + return ret; +} + void fb_util_debug(PurpleDebugLevel level, const gchar *format, ...) {
--- a/libpurple/protocols/facebook/util.h Sat Jul 04 13:26:42 2015 -0400 +++ b/libpurple/protocols/facebook/util.h Sun Jul 05 14:44:14 2015 -0400 @@ -31,7 +31,10 @@ FB_UTIL_DEBUG_FLAG_VERBOSE \ ) +#define FB_UTIL_ERROR fb_util_error_quark() + typedef enum _FbUtilDebugFlags FbUtilDebugFlags; +typedef enum _FbUtilError FbUtilError; typedef void (*FbUtilRequestBuddyFunc) (GSList *buddies, gpointer data); @@ -41,6 +44,19 @@ FB_UTIL_DEBUG_FLAG_VERBOSE = 1 << 26 }; +enum _FbUtilError +{ + FB_UTIL_ERROR_GENERAL +}; + + +GQuark +fb_util_error_quark(void); + +PurpleBuddy * +fb_util_account_find_buddy(PurpleAccount *acct, PurpleChatConversation *chat, + const gchar *name, GError **error); + void fb_util_debug(PurpleDebugLevel level, const gchar *format, ...) G_GNUC_PRINTF(2, 3);