libpurple/protocols/facebook/facebook.c

changeset 42187
fc241db9162d
parent 42186
637ba5491231
child 42188
04c0398f1046
--- a/libpurple/protocols/facebook/facebook.c	Wed Mar 29 23:21:45 2023 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1740 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#include <glib/gi18n-lib.h>
-
-#include <gplugin.h>
-#include <gplugin-native.h>
-
-#include <purple.h>
-
-#include "libpurple/glibcompat.h"
-
-#include "api.h"
-#include "data.h"
-#include "facebook.h"
-#include "http.h"
-#include "util.h"
-
-struct _FacebookProtocol {
-	PurpleProtocol parent;
-};
-
-static GSList *fb_cmds = NULL;
-static PurpleProtocol *fb_protocol = NULL;
-
-static void
-fb_cb_api_messages(FbApi *api, GSList *msgs, gpointer data);
-
-static PurpleGroup *
-fb_get_group(gboolean friend)
-{
-	PurpleBlistNode *n;
-	PurpleBlistNode *node;
-	PurpleGroup *grp;
-	const gchar *title;
-
-	if (friend) {
-		title = _("Facebook Friends");
-	} else {
-		title = _("Facebook Non-Friends");
-	}
-
-	grp = purple_blist_find_group(title);
-
-	if (G_UNLIKELY(grp == NULL)) {
-		grp = purple_group_new(title);
-		node = NULL;
-
-		for (n = purple_blist_get_default_root(); n != NULL;
-		     n = n->next) {
-			node = n;
-		}
-
-		/* Append to the end of the buddy list */
-		purple_blist_add_group(grp, node);
-
-		if (!friend) {
-			node = PURPLE_BLIST_NODE(grp);
-			purple_blist_node_set_bool(node, "collapsed", TRUE);
-		}
-	}
-
-	return grp;
-}
-
-static void
-fb_buddy_add_nonfriend(PurpleAccount *acct, FbApiUser *user)
-{
-	gchar uid[FB_ID_STRMAX];
-	PurpleBuddy *bdy;
-	PurpleGroup *grp;
-
-	FB_ID_TO_STR(user->uid, uid);
-	bdy = purple_buddy_new(acct, uid, user->name);
-	grp = fb_get_group(FALSE);
-
-	purple_buddy_set_server_alias(bdy, user->name);
-	purple_blist_add_buddy(bdy, NULL, grp, NULL);
-}
-
-static void
-fb_cb_api_auth(FbApi *api, gpointer data)
-{
-	FbData *fata = data;
-
-	fb_data_save(fata);
-	fb_api_contacts(api);
-}
-
-static void
-fb_cb_api_connect(FbApi *api, gpointer data)
-{
-	FbData *fata = data;
-	PurpleAccount *acct;
-	PurpleConnection *gc;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-
-	fb_data_save(fata);
-	purple_connection_set_state(gc, PURPLE_CONNECTION_STATE_CONNECTED);
-
-	if (purple_account_get_bool(acct, "show-unread", TRUE)) {
-		fb_api_unread(api);
-	}
-}
-
-static void
-fb_cb_api_contact(FbApi *api, FbApiUser *user, gpointer data)
-{
-	FbData *fata = data;
-	gchar uid[FB_ID_STRMAX];
-	GSList *msgs;
-	PurpleAccount *acct;
-	PurpleConnection *gc;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-	FB_ID_TO_STR(user->uid, uid);
-
-	if (purple_blist_find_buddy(acct, uid) == NULL) {
-		fb_buddy_add_nonfriend(acct, user);
-	}
-
-	msgs = fb_data_take_messages(fata, user->uid);
-
-	if (msgs != NULL) {
-		fb_cb_api_messages(api, msgs, fata);
-		g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
-	}
-}
-
-static gboolean
-fb_cb_sync_contacts(gpointer data)
-{
-	FbApi *api;
-	FbData *fata = data;
-
-	api = fb_data_get_api(fata);
-	fb_data_clear_timeout(fata, "sync-contacts", FALSE);
-	fb_api_contacts(api);
-	return FALSE;
-}
-
-static void
-fb_cb_icon(FbDataImage *img, GError *error)
-{
-	const gchar *csum;
-	const gchar *name;
-	const gchar *str;
-	FbHttpParams *params;
-	gsize size;
-	guint8 *image;
-	PurpleAccount *acct;
-	PurpleBuddy *bdy;
-
-	bdy = fb_data_image_get_data(img);
-	acct = purple_buddy_get_account(bdy);
-	name = purple_buddy_get_name(bdy);
-
-	if (G_UNLIKELY(error != NULL)) {
-		fb_util_debug_warning("Failed to retrieve icon for %s: %s",
-		                      name, error->message);
-		return;
-	}
-
-	str = fb_data_image_get_url(img);
-	params = fb_http_params_new_parse(str, TRUE);
-	csum = fb_http_params_get_str(params, "oh", NULL);
-
-	image = fb_data_image_dup_image(img, &size);
-	purple_buddy_icons_set_for_user(acct, name, image, size, csum);
-	fb_http_params_free(params);
-}
-
-static void
-fb_sync_contacts_add_timeout(FbData *fata)
-{
-	gint sync;
-	PurpleConnection *gc;
-	PurpleAccount *acct;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-
-	sync = purple_account_get_int(acct, "sync-interval", 5);
-
-	if (sync < 1) {
-		purple_account_set_int(acct, "sync-interval", 1);
-		sync = 1;
-	}
-
-	sync *= 60;
-	fb_data_save_timeout(fata, "sync-contacts",
-	                     g_timeout_add_seconds(sync, fb_cb_sync_contacts, fata));
-}
-
-static void
-fb_cb_api_contacts(FbApi *api, GSList *users, gboolean complete, gpointer data)
-{
-	const gchar *alias;
-	const gchar *csum;
-	FbApiUser *user;
-	FbData *fata = data;
-	FbId muid;
-	gchar uid[FB_ID_STRMAX];
-	GSList *l;
-	GValue val = G_VALUE_INIT;
-	PurpleAccount *acct;
-	PurpleBuddy *bdy;
-	PurpleConnection *gc;
-	PurpleConnectionState state;
-	PurpleGroup *grp;
-	PurpleGroup *grpn;
-	PurpleStatus *status;
-	PurpleStatusPrimitive pstat;
-	PurpleStatusType *type;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-	grp = fb_get_group(TRUE);
-	grpn = fb_get_group(FALSE);
-	alias = purple_contact_info_get_alias(PURPLE_CONTACT_INFO(acct));
-	state = purple_connection_get_state(gc);
-
-	g_value_init(&val, FB_TYPE_ID);
-	g_object_get_property(G_OBJECT(api), "uid", &val);
-	muid = g_value_get_int64(&val);
-	g_value_unset(&val);
-
-	for (l = users; l != NULL; l = l->next) {
-		user = l->data;
-		FB_ID_TO_STR(user->uid, uid);
-
-		if (G_UNLIKELY(user->uid == muid)) {
-			PurpleContactInfo *info = NULL;
-
-			if (G_UNLIKELY(alias != NULL)) {
-				continue;
-			}
-
-			info = PURPLE_CONTACT_INFO(acct);
-			purple_contact_info_set_alias(info, user->name);
-
-			continue;
-		}
-
-		bdy = purple_blist_find_buddy(acct, uid);
-
-		if ((bdy != NULL) && (purple_buddy_get_group(bdy) == grpn)) {
-			purple_blist_remove_buddy(bdy);
-			bdy = NULL;
-		}
-
-		if (bdy == NULL) {
-			bdy = purple_buddy_new(acct, uid, NULL);
-			purple_blist_add_buddy(bdy, NULL, grp, NULL);
-		}
-
-		purple_buddy_set_server_alias(bdy, user->name);
-		csum = purple_buddy_icons_get_checksum_for_user(bdy);
-
-		if (!purple_strequal(csum, user->csum)) {
-			fb_data_image_add(fata, user->icon, fb_cb_icon,
-			                  bdy, NULL);
-		}
-	}
-
-	fb_data_image_queue(fata);
-
-	if (!complete) {
-		return;
-	}
-
-	if (state != PURPLE_CONNECTION_STATE_CONNECTED) {
-		status = purple_account_get_active_status(acct);
-		type = purple_status_get_status_type(status);
-		pstat = purple_status_type_get_primitive(type);
-
-		fb_api_connect(api, pstat == PURPLE_STATUS_INVISIBLE);
-	}
-
-	fb_sync_contacts_add_timeout(fata);
-}
-
-static void
-fb_cb_api_contacts_delta(G_GNUC_UNUSED FbApi *api, GSList *added,
-                         GSList *removed, gpointer data)
-{
-	FbApiUser *user;
-	FbData *fata = data;
-	gchar uid[FB_ID_STRMAX];
-	GSList *l;
-	PurpleAccount *acct;
-	PurpleBuddy *bdy;
-	PurpleConnection *gc;
-	PurpleGroup *grp;
-	PurpleGroup *grpn;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-	grp = fb_get_group(TRUE);
-	grpn = fb_get_group(FALSE);
-
-	for (l = added; l != NULL; l = l->next) {
-		user = l->data;
-		FB_ID_TO_STR(user->uid, uid);
-
-		bdy = purple_blist_find_buddy(acct, uid);
-
-		if ((bdy != NULL) && (purple_buddy_get_group(bdy) == grpn)) {
-			purple_blist_remove_buddy(bdy);
-		}
-
-		bdy = purple_buddy_new(acct, uid, NULL);
-		purple_blist_add_buddy(bdy, NULL, grp, NULL);
-
-		purple_buddy_set_server_alias(bdy, user->name);
-	}
-
-	for (l = removed; l != NULL; l = l->next) {
-		bdy = purple_blist_find_buddy(acct, l->data);
-
-		if (bdy != NULL) {
-			purple_blist_remove_buddy(bdy);
-		}
-	}
-
-	fb_sync_contacts_add_timeout(fata);
-}
-
-static void
-fb_cb_api_error(G_GNUC_UNUSED FbApi *api, GError *error, gpointer data)
-{
-	FbData *fata = data;
-	PurpleConnection *gc;
-	PurpleConnectionError errc;
-
-	gc = fb_data_get_connection(fata);
-
-	if (error->domain == G_IO_ERROR) {
-		purple_connection_g_error(gc, error);
-		return;
-	}
-
-	if (g_error_matches(error, FB_API_ERROR, FB_API_ERROR_QUEUE)) {
-		/* Save the reset data */
-		fb_data_save(fata);
-	}
-
-	if ((error->domain == FB_HTTP_ERROR) &&
-	    (error->code >= 400) &&
-	    (error->code <= 500))
-	{
-		errc = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-	} else if (g_error_matches(error, FB_API_ERROR, FB_API_ERROR_AUTH)) {
-		errc = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
-	} else {
-		errc = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
-	}
-
-
-	if (!g_error_matches(error, FB_API_ERROR, FB_API_ERROR_NONFATAL)) {
-		purple_connection_error(gc, errc, error->message);
-	}
-}
-
-static void
-fb_cb_api_events(FbApi *api, GSList *events, gpointer data)
-{
-	FbData *fata = data;
-	FbApiEvent *event;
-	gchar uid[FB_ID_STRMAX];
-	gchar tid[FB_ID_STRMAX];
-	GHashTable *fetch;
-	GHashTableIter iter;
-	GSList *l;
-	PurpleAccount *acct;
-	PurpleConversation *chat;
-	PurpleConversationManager *manager;
-	PurpleConnection *gc;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-	fetch = g_hash_table_new(fb_id_hash, fb_id_equal);
-
-	manager = purple_conversation_manager_get_default();
-
-	for (l = events; l != NULL; l = l->next) {
-		event = l->data;
-
-		FB_ID_TO_STR(event->tid, tid);
-		chat = purple_conversation_manager_find_chat(manager, acct, tid);
-
-		if (chat == NULL) {
-			continue;
-		}
-
-		FB_ID_TO_STR(event->uid, uid);
-
-		switch (event->type) {
-		case FB_API_EVENT_TYPE_THREAD_TOPIC:
-			purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION(chat), uid,
-			                                   event->text);
-			break;
-
-		case FB_API_EVENT_TYPE_THREAD_USER_ADDED:
-			if (purple_blist_find_buddy(acct, uid) == NULL) {
-				if (event->text) {
-					FbApiUser *user = g_new0(FbApiUser, 1);
-					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(PURPLE_CHAT_CONVERSATION(chat), uid, NULL, 0,
-			                                  TRUE);
-			break;
-
-		case FB_API_EVENT_TYPE_THREAD_USER_REMOVED:
-			purple_chat_conversation_remove_user(PURPLE_CHAT_CONVERSATION(chat), uid, event->text);
-			break;
-		}
-	}
-
-	g_hash_table_iter_init(&iter, fetch);
-
-	while (g_hash_table_iter_next(&iter, NULL, (gpointer) &event)) {
-		fb_api_thread(api, event->tid);
-	}
-
-	g_hash_table_destroy(fetch);
-}
-
-static void
-fb_cb_image(FbDataImage *img, GError *error)
-{
-	const gchar *url;
-	FbApi *api;
-	FbApiMessage *msg;
-	FbData *fata;
-	gsize size;
-	GSList *msgs = NULL;
-	guint id;
-	guint8 *image;
-	PurpleImage *pimg;
-
-	fata = fb_data_image_get_fata(img);
-	msg = fb_data_image_get_data(img);
-
-	if (G_UNLIKELY(error != NULL)) {
-		url = fb_data_image_get_url(img);
-		fb_util_debug_warning("Failed to retrieve image %s: %s",
-		                      url, error->message);
-		return;
-	}
-
-	api = fb_data_get_api(fata);
-	image = fb_data_image_dup_image(img, &size);
-	pimg = purple_image_new_from_data(image, size);
-	id = purple_image_store_add_weak(pimg);
-
-	g_free(msg->text);
-	msg->text = g_strdup_printf("<img src=\""
-	                            PURPLE_IMAGE_STORE_PROTOCOL
-	                            "%u\">", id);
-	msg->flags |= FB_API_MESSAGE_FLAG_DONE;
-
-	msgs = g_slist_prepend(msgs, msg);
-	fb_cb_api_messages(api, msgs, fata);
-	g_slist_free(msgs);
-}
-
-static void
-fb_cb_api_messages(FbApi *api, GSList *msgs, gpointer data)
-{
-	const gchar *text;
-	FbApiMessage *msg;
-	FbData *fata = data;
-	gboolean isself;
-	gboolean mark;
-	gboolean open;
-	gboolean self;
-	gchar *html;
-	gchar tid[FB_ID_STRMAX];
-	gchar uid[FB_ID_STRMAX];
-	gint id;
-	gint64 tstamp;
-	GSList *l;
-	PurpleAccount *acct;
-	PurpleConversation *chat;
-	PurpleConversationManager *manager;
-	PurpleConnection *gc;
-	PurpleMessageFlags flags;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-	mark = purple_account_get_bool(acct, "mark-read", TRUE);
-	open = purple_account_get_bool(acct, "group-chat-open", TRUE);
-	self = purple_account_get_bool(acct, "show-self", TRUE);
-
-	manager = purple_conversation_manager_get_default();
-
-	for (l = msgs; l != NULL; l = l->next) {
-		msg = l->data;
-		FB_ID_TO_STR(msg->uid, uid);
-
-		if (purple_blist_find_buddy(acct, uid) == NULL) {
-			msg = fb_api_message_dup(msg);
-			fb_data_add_message(fata, msg);
-			fb_api_contact(api, msg->uid);
-			continue;
-		}
-
-		isself = (msg->flags & FB_API_MESSAGE_FLAG_SELF) != 0;
-
-		if (isself && !self) {
-			continue;
-		}
-
-		flags = isself ? PURPLE_MESSAGE_SEND : PURPLE_MESSAGE_RECV;
-		tstamp = msg->tstamp / 1000;
-
-		if (msg->flags & FB_API_MESSAGE_FLAG_IMAGE) {
-			if (!(msg->flags & FB_API_MESSAGE_FLAG_DONE)) {
-				msg = fb_api_message_dup(msg);
-				fb_data_image_add(fata, msg->text, fb_cb_image,
-				                  msg, (GDestroyNotify)
-				                       fb_api_message_free);
-				fb_data_image_queue(fata);
-				continue;
-			}
-
-			flags |= PURPLE_MESSAGE_IMAGES;
-			text = msg->text;
-			html = NULL;
-		} else {
-			html = g_markup_escape_text(msg->text, -1);
-			text = html;
-		}
-
-		if (msg->tid == 0) {
-			if (mark && !isself) {
-				fb_data_set_unread(fata, msg->uid, TRUE);
-			}
-
-			fb_util_serv_got_im(gc, uid, text, flags, tstamp);
-			g_free(html);
-			continue;
-		}
-
-		FB_ID_TO_STR(msg->tid, tid);
-		chat = purple_conversation_manager_find_chat(manager, acct, tid);
-
-		if (chat == NULL) {
-			if (!open) {
-				g_free(html);
-				continue;
-			}
-
-			id = fb_id_hash(&msg->tid);
-			purple_serv_got_joined_chat(gc, id, tid);
-			fb_api_thread(api, msg->tid);
-		} else {
-			id = purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat));
-		}
-
-		if (mark && !isself) {
-			fb_data_set_unread(fata, msg->tid, TRUE);
-		}
-
-		fb_util_serv_got_chat_in(gc, id, uid, text, flags, tstamp);
-		g_free(html);
-	}
-}
-
-static void
-fb_cb_api_presences(G_GNUC_UNUSED FbApi *api, GSList *presences, gpointer data)
-{
-	const gchar *statid;
-	FbData *fata = data;
-	gchar uid[FB_ID_STRMAX];
-	GSList *l;
-	PurpleAccount *acct;
-	PurpleConnection *gc;
-	PurpleStatusPrimitive pstat;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-
-	for (l = presences; l != NULL; l = l->next) {
-		FbApiPresence *api_presence = l->data;
-
-		if (api_presence->active) {
-			pstat = PURPLE_STATUS_AVAILABLE;
-		} else {
-			pstat = PURPLE_STATUS_OFFLINE;
-		}
-
-		FB_ID_TO_STR(api_presence->uid, uid);
-		statid = purple_primitive_get_id_from_type(pstat);
-		purple_protocol_got_user_status(acct, uid, statid, NULL);
-	}
-}
-
-static void
-fb_cb_api_thread(G_GNUC_UNUSED FbApi *api, FbApiThread *thrd, gpointer data)
-{
-	const gchar *name;
-	FbApiUser *user;
-	FbData *fata = data;
-	gboolean active;
-	gchar tid[FB_ID_STRMAX];
-	gchar uid[FB_ID_STRMAX];
-	gint id;
-	GSList *l;
-	PurpleAccount *acct;
-	PurpleConversation *conv;
-	PurpleConversationManager *manager;
-	PurpleChatConversation *chat;
-	PurpleConnection *gc;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-	id = fb_id_hash(&thrd->tid);
-	FB_ID_TO_STR(thrd->tid, tid);
-
-	manager = purple_conversation_manager_get_default();
-	conv = purple_conversation_manager_find_chat(manager, acct, tid);
-	if((conv == NULL) || purple_chat_conversation_has_left(PURPLE_CHAT_CONVERSATION(conv))) {
-		conv = purple_serv_got_joined_chat(gc, id, tid);
-		chat = PURPLE_CHAT_CONVERSATION(conv);
-		active = FALSE;
-	} else {
-		/* If there are no users in the group chat, including
-		 * the local user, then the group chat has yet to be
-		 * setup by this function. As a result, any group chat
-		 * without users is inactive.
-		 */
-		chat = PURPLE_CHAT_CONVERSATION(conv);
-		active = purple_chat_conversation_get_users_count(chat) > 0;
-	}
-
-	if (!active) {
-		name = purple_contact_info_get_username(PURPLE_CONTACT_INFO(acct));
-		purple_chat_conversation_add_user(chat, name, NULL, 0, FALSE);
-	}
-
-	purple_chat_conversation_set_topic(chat, NULL, thrd->topic);
-
-	for (l = thrd->users; l != NULL; l = l->next) {
-		user = l->data;
-		FB_ID_TO_STR(user->uid, uid);
-
-		if (purple_chat_conversation_has_user(chat, uid)) {
-			continue;
-		}
-
-		if (purple_blist_find_buddy(acct, uid) == NULL) {
-			fb_buddy_add_nonfriend(acct, user);
-		}
-
-		purple_chat_conversation_add_user(chat, uid, NULL, 0, active);
-	}
-}
-
-static void
-fb_cb_api_thread_create(G_GNUC_UNUSED FbApi *api, FbId tid, gpointer data)
-{
-	FbData *fata = data;
-	gchar sid[FB_ID_STRMAX];
-	GHashTable *table;
-	PurpleConnection *gc;
-
-	gc = fb_data_get_connection(fata);
-	FB_ID_TO_STR(tid, sid);
-
-	table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
-	g_hash_table_insert(table, "name", g_strdup(sid));
-	purple_serv_join_chat(gc, table);
-	g_hash_table_destroy(table);
-}
-
-static void
-fb_cb_api_thread_kicked(G_GNUC_UNUSED FbApi *api, FbApiThread *thrd,
-                        gpointer data)
-{
-	FbData *fata = data;
-	gchar tid[FB_ID_STRMAX];
-	PurpleAccount *acct;
-	PurpleConnection *gc;
-	PurpleConversation *chat;
-	PurpleConversationManager *manager;
-
-	FB_ID_TO_STR(thrd->tid, tid);
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-
-	manager = purple_conversation_manager_get_default();
-	chat = purple_conversation_manager_find_chat(manager, acct, tid);
-
-	if (chat == NULL) {
-		PurpleRequestCommonParameters *cpar;
-
-		cpar = purple_request_cpar_from_connection(gc);
-		purple_notify_error(gc,
-				    _("Join a Chat"),
-				    _("Failed to Join Chat"),
-				    _("You have been removed from this chat"),
-				    cpar);
-		return;
-	}
-
-	purple_conversation_write_system_message(chat,
-		_("You have been removed from this chat"), 0);
-
-	purple_serv_got_chat_left(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat)));
-}
-
-static void
-fb_cb_api_threads(G_GNUC_UNUSED FbApi *api, GSList *thrds, gpointer data)
-{
-	const gchar *alias;
-	FbApiUser *user;
-	FbData *fata = data;
-	gchar tid[FB_ID_STRMAX];
-	gchar uid[FB_ID_STRMAX];
-	GSList *l;
-	GSList *m;
-	GString *gstr;
-	FbApiThread *thrd;
-	PurpleAccount *acct;
-	PurpleBuddy *bdy;
-	PurpleConnection *gc;
-	PurpleRoomlist *list;
-	PurpleRoomlistRoom *room;
-
-	list = fb_data_get_roomlist(fata);
-
-	if (G_UNLIKELY(list == NULL)) {
-		return;
-	}
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-	gstr = g_string_new(NULL);
-
-	for (l = thrds; l != NULL; l = l->next) {
-		thrd = l->data;
-		FB_ID_TO_STR(thrd->tid, tid);
-		g_string_truncate(gstr, 0);
-
-		for (m = thrd->users; m != NULL; m = m->next) {
-			user = m->data;
-			FB_ID_TO_STR(user->uid, uid);
-			bdy = purple_blist_find_buddy(acct, uid);
-
-			if (bdy != NULL) {
-				alias = purple_buddy_get_alias(bdy);
-			} else {
-				alias = user->name;
-			}
-
-			if (gstr->len > 0) {
-				g_string_append(gstr, ", ");
-			}
-
-			g_string_append(gstr, alias);
-		}
-
-		room = purple_roomlist_room_new(tid, thrd->topic);
-		purple_roomlist_room_add_field(room, "topic", g_strdup(thrd->topic));
-		purple_roomlist_room_add_field(room, "users", g_strdup(gstr->str));
-		purple_roomlist_room_add(list, room);
-		g_object_unref(room);
-	}
-
-	purple_roomlist_set_in_progress(list, FALSE);
-	fb_data_set_roomlist(fata, NULL);
-	g_string_free(gstr, TRUE);
-}
-
-static void
-fb_cb_api_typing(G_GNUC_UNUSED FbApi *api, FbApiTyping *typg, gpointer data)
-{
-	FbData *fata = data;
-	gchar uid[FB_ID_STRMAX];
-	PurpleConnection *gc;
-
-	gc = fb_data_get_connection(fata);
-	FB_ID_TO_STR(typg->uid, uid);
-
-	if (typg->state) {
-		purple_serv_got_typing(gc, uid, 0, PURPLE_IM_TYPING);
-	} else {
-		purple_serv_got_typing_stopped(gc, uid);
-	}
-}
-
-static void
-fb_mark_read(FbData *fata, FbId id, gboolean thread)
-{
-	FbApi *api;
-	PurpleAccount *acct;
-	PurpleConnection *gc;
-
-	gc = fb_data_get_connection(fata);
-	acct = purple_connection_get_account(gc);
-	api = fb_data_get_api(fata);
-
-	if (!fb_data_get_unread(fata, id) ||
-	    (purple_account_get_bool(acct, "mark-read-available", FALSE) &&
-	     fb_api_is_invisible(api)))
-	{
-		return;
-	}
-
-	fb_data_set_unread(fata, id, FALSE);
-	fb_api_read(api, id, thread);
-}
-
-static gboolean
-fb_cb_conv_read(gpointer data)
-{
-	const gchar *name;
-	FbData *fata;
-	FbId id;
-	gchar *tname;
-	PurpleConnection *gc;
-	PurpleConversation *conv = data;
-
-	gc = purple_conversation_get_connection(conv);
-	fata = purple_connection_get_protocol_data(gc);
-	name = purple_conversation_get_name(conv);
-	id = FB_ID_FROM_STR(name);
-
-	tname = g_strconcat("conv-read-", name, NULL);
-	fb_data_clear_timeout(fata, tname, FALSE);
-	g_free(tname);
-
-	if (purple_conversation_has_focus(conv)) {
-		fb_mark_read(fata, id, PURPLE_IS_CHAT_CONVERSATION(conv));
-	}
-	return FALSE;
-}
-
-static void
-fb_cb_conv_updated(PurpleConversation *conv, PurpleConversationUpdateType type,
-                   gpointer data)
-{
-	const gchar *name;
-	const gchar *pid;
-	FbData *fata = data;
-	gchar *tname;
-	PurpleAccount *acct;
-
-	acct = purple_conversation_get_account(conv);
-	pid = purple_account_get_protocol_id(acct);
-
-	if ((type == PURPLE_CONVERSATION_UPDATE_UNSEEN) &&
-	    purple_strequal(pid, FB_PROTOCOL_ID) &&
-	    purple_account_get_bool(acct, "mark-read", TRUE))
-	{
-		/* Use event loop for purple_conversation_has_focus() */
-		name = purple_conversation_get_name(conv);
-		tname = g_strconcat("conv-read-", name, NULL);
-		fb_data_save_timeout(fata, tname,
-		                     g_timeout_add_seconds(0, fb_cb_conv_read, conv));
-		g_free(tname);
-	}
-}
-
-static void
-fb_cb_conv_deleting(PurpleConversation *conv, gpointer data)
-{
-	const gchar *name;
-	const gchar *pid;
-	FbData *fata = data;
-	gchar *tname;
-	PurpleAccount *acct;
-
-	acct = purple_conversation_get_account(conv);
-	pid = purple_account_get_protocol_id(acct);
-
-	if (!purple_strequal(pid, FB_PROTOCOL_ID)) {
-		return;
-	}
-
-	name = purple_conversation_get_name(conv);
-	tname = g_strconcat("conv-read-", name, NULL);
-	fb_data_clear_timeout(fata, tname, TRUE);
-	g_free(tname);
-}
-
-static void
-fb_blist_chat_create(GSList *buddies, gpointer data)
-{
-	const gchar *name;
-	FbApi *api;
-	FbData *fata = data;
-	FbId *did;
-	FbId uid;
-	GSList *l;
-	GSList *uids = NULL;
-	PurpleConnection *gc;
-	PurpleRequestCommonParameters *cpar;
-
-	gc = fb_data_get_connection(fata);
-	api = fb_data_get_api(fata);
-
-	if (g_slist_length(buddies) < 2) {
-		cpar = purple_request_cpar_from_connection(gc);
-		purple_notify_error(gc,
-		                    _("Initiate Chat"),
-		                    _("Failed to Initiate Chat"),
-		                    _("At least two initial chat participants"
-		                      " are required."),
-				    cpar);
-		return;
-	}
-
-	for (l = buddies; l != NULL; l = l->next) {
-		name = purple_buddy_get_name(l->data);
-		uid = FB_ID_FROM_STR(name);
-		did = g_memdup2(&uid, sizeof uid);
-		uids = g_slist_prepend(uids, did);
-	}
-
-	fb_api_thread_create(api, uids);
-	g_slist_free_full(uids, g_free);
-}
-
-static void
-fb_blist_chat_init(PurpleBlistNode *node, gpointer data)
-{
-	FbData *fata = data;
-	GSList *select = NULL;
-	PurpleConnection *gc;
-
-	if (!PURPLE_IS_BUDDY(node)) {
-		return;
-	}
-
-	gc = fb_data_get_connection(fata);
-	select = g_slist_prepend(select, PURPLE_BUDDY(node));
-
-	fb_util_request_buddy(gc,
-	                      _("Initiate Chat"),
-	                      _("Initial Chat Participants"),
-	                      _("Select at least two initial participants."),
-	                      select, TRUE,
-			      G_CALLBACK(fb_blist_chat_create), NULL,
-			      fata);
-	g_slist_free(select);
-}
-
-static GList *
-fb_get_account_options(G_GNUC_UNUSED PurpleProtocol *protocol) {
-	GList *opts = NULL;
-	PurpleAccountOption *opt;
-
-	opt = purple_account_option_int_new(_("Buddy list sync interval"),
-	                                    "sync-interval", 5);
-	opts = g_list_prepend(opts, opt);
-
-	opt = purple_account_option_bool_new(_("Mark messages as read on focus"),
-	                                     "mark-read", TRUE);
-	opts = g_list_prepend(opts, opt);
-
-	opt = purple_account_option_bool_new(_("Mark messages as read only when available"),
-	                                     "mark-read-available", FALSE);
-	opts = g_list_prepend(opts, opt);
-
-	opt = purple_account_option_bool_new(_("Show self messages"),
-	                                     "show-self", TRUE);
-	opts = g_list_prepend(opts, opt);
-
-	opt = purple_account_option_bool_new(_("Show unread messages"),
-	                                     "show-unread", TRUE);
-	opts = g_list_prepend(opts, opt);
-
-	opt = purple_account_option_bool_new(_("Open new group chats with "
-	                                       "incoming messages"),
-	                                     "group-chat-open", TRUE);
-	opts = g_list_prepend(opts, opt);
-
-	return g_list_reverse(opts);
-}
-
-static void
-fb_login(G_GNUC_UNUSED PurpleProtocol *protocol, PurpleAccount *acct) {
-	const gchar *pass;
-	const gchar *user;
-	FbApi *api;
-	FbData *fata;
-	gpointer convh;
-	PurpleConnection *gc;
-	GProxyResolver *resolver;
-	GError *error = NULL;
-
-	gc = purple_account_get_connection(acct);
-
-	resolver = purple_proxy_get_proxy_resolver(acct, &error);
-	if (resolver == NULL) {
-		fb_util_debug_error("Unable to get account proxy resolver: %s",
-		                    error->message);
-		purple_connection_take_error(gc, error);
-		return;
-	}
-
-	fata = fb_data_new(gc, resolver);
-	api = fb_data_get_api(fata);
-	convh = purple_conversations_get_handle();
-	purple_connection_set_protocol_data(gc, fata);
-
-	g_signal_connect(api,
-	                 "auth",
-	                 G_CALLBACK(fb_cb_api_auth),
-	                 fata);
-	g_signal_connect(api,
-	                 "connect",
-	                 G_CALLBACK(fb_cb_api_connect),
-	                 fata);
-	g_signal_connect(api,
-	                 "contact",
-	                 G_CALLBACK(fb_cb_api_contact),
-	                 fata);
-	g_signal_connect(api,
-	                 "contacts",
-	                 G_CALLBACK(fb_cb_api_contacts),
-	                 fata);
-	g_signal_connect(api,
-	                 "contacts-delta",
-	                 G_CALLBACK(fb_cb_api_contacts_delta),
-	                 fata);
-	g_signal_connect(api,
-	                 "error",
-	                 G_CALLBACK(fb_cb_api_error),
-	                 fata);
-	g_signal_connect(api,
-	                 "events",
-	                 G_CALLBACK(fb_cb_api_events),
-	                 fata);
-	g_signal_connect(api,
-	                 "messages",
-	                 G_CALLBACK(fb_cb_api_messages),
-	                 fata);
-	g_signal_connect(api,
-	                 "presences",
-	                 G_CALLBACK(fb_cb_api_presences),
-	                 fata);
-	g_signal_connect(api,
-	                 "thread",
-	                 G_CALLBACK(fb_cb_api_thread),
-	                 fata);
-	g_signal_connect(api,
-	                 "thread-create",
-	                 G_CALLBACK(fb_cb_api_thread_create),
-	                 fata);
-	g_signal_connect(api,
-	                 "thread-kicked",
-	                 G_CALLBACK(fb_cb_api_thread_kicked),
-	                 fata);
-	g_signal_connect(api,
-	                 "threads",
-	                 G_CALLBACK(fb_cb_api_threads),
-	                 fata);
-	g_signal_connect(api,
-	                 "typing",
-	                 G_CALLBACK(fb_cb_api_typing),
-	                 fata);
-
-	purple_signal_connect(convh,
-	                      "conversation-updated",
-	                      gc,
-	                      G_CALLBACK(fb_cb_conv_updated),
-	                      fata);
-	purple_signal_connect(convh,
-	                      "deleting-conversation",
-	                      gc,
-	                      G_CALLBACK(fb_cb_conv_deleting),
-	                      fata);
-
-	if (!fb_data_load(fata) || !purple_account_get_remember_password(acct)) {
-		user = purple_contact_info_get_username(PURPLE_CONTACT_INFO(acct));
-		pass = purple_connection_get_password(gc);
-		fb_api_auth(api, user, pass);
-		return;
-	}
-
-	fb_api_contacts(api);
-}
-
-static void
-fb_close(G_GNUC_UNUSED PurpleProtocol *protocol, PurpleConnection *gc) {
-	FbApi *api;
-	FbData *fata;
-
-	fata = purple_connection_get_protocol_data(gc);
-	api = fb_data_get_api(fata);
-
-	fb_data_save(fata);
-	fb_api_disconnect(api);
-	g_object_unref(fata);
-
-	purple_connection_set_protocol_data(gc, NULL);
-	purple_signals_disconnect_by_handle(gc);
-}
-
-static GList *
-fb_status_types(G_GNUC_UNUSED PurpleProtocol *protocol,
-                G_GNUC_UNUSED PurpleAccount *acct)
-{
-	PurpleStatusType *type;
-	GList *types = NULL;
-
-	type = purple_status_type_new(PURPLE_STATUS_AVAILABLE,
-	                              NULL, NULL, TRUE);
-	types = g_list_prepend(types, type);
-
-	/* Just a NULL state (as of now) for compatibility */
-	type = purple_status_type_new(PURPLE_STATUS_AWAY,
-	                              NULL, NULL, TRUE);
-	types = g_list_prepend(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_INVISIBLE,
-	                              NULL, NULL, TRUE);
-	types = g_list_prepend(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_OFFLINE,
-	                              NULL, NULL, TRUE);
-	types = g_list_prepend(types, type);
-
-	return g_list_reverse(types);
-}
-
-static GList *
-fb_client_blist_node_menu(G_GNUC_UNUSED PurpleProtocolClient *client,
-                          PurpleBlistNode *node)
-{
-	FbData *fata;
-	GList *acts = NULL;
-	PurpleAccount *acct;
-	PurpleConnection *gc;
-	PurpleActionMenu *act;
-
-	if (!PURPLE_IS_BUDDY(node)) {
-		return NULL;
-	}
-
-	acct = purple_buddy_get_account(PURPLE_BUDDY(node));
-	gc = purple_account_get_connection(acct);
-	fata = purple_connection_get_protocol_data(gc);
-
-	act = purple_action_menu_new(_("Initiate _Chat"),
-	                             G_CALLBACK(fb_blist_chat_init),
-	                             fata, NULL);
-	acts = g_list_prepend(acts, act);
-
-	return g_list_reverse(acts);
-}
-
-static gboolean
-fb_client_offline_message(G_GNUC_UNUSED PurpleProtocolClient *client,
-                          G_GNUC_UNUSED PurpleBuddy *buddy)
-{
-	return TRUE;
-}
-
-static void
-fb_server_set_status(G_GNUC_UNUSED PurpleProtocolServer *protocol_server,
-                     PurpleAccount *acct, PurpleStatus *status)
-{
-	FbApi *api;
-	FbData *fata;
-	gboolean invis;
-	PurpleConnection *gc;
-	PurpleStatusPrimitive pstat;
-	PurpleStatusType *type;
-
-	gc = purple_account_get_connection(acct);
-	fata = purple_connection_get_protocol_data(gc);
-	api = fb_data_get_api(fata);
-
-	type = purple_status_get_status_type(status);
-	pstat = purple_status_type_get_primitive(type);
-	invis = fb_api_is_invisible(api);
-
-	if ((pstat == PURPLE_STATUS_INVISIBLE) && !invis) {
-		fb_api_connect(api, TRUE);
-	} else if ((pstat != PURPLE_STATUS_OFFLINE) && invis) {
-		fb_api_connect(api, FALSE);
-	}
-}
-
-static gint
-fb_im_send(G_GNUC_UNUSED PurpleProtocolIM *im, PurpleConnection *gc,
-           PurpleMessage *msg)
-{
-	const gchar *name;
-	const gchar *text;
-	FbApi *api;
-	FbData *fata;
-	FbId uid;
-	gchar *sext;
-
-	fata = purple_connection_get_protocol_data(gc);
-	api = fb_data_get_api(fata);
-
-	name = purple_message_get_recipient(msg);
-	uid = FB_ID_FROM_STR(name);
-
-	text = purple_message_get_contents(msg);
-	sext = purple_markup_strip_html(text);
-	fb_api_message(api, uid, FALSE, sext);
-	g_free(sext);
-	return 1;
-}
-
-static guint
-fb_im_send_typing(G_GNUC_UNUSED PurpleProtocolIM *im, PurpleConnection *gc,
-                  const gchar *name, PurpleIMTypingState state)
-{
-	FbApi *api;
-	FbData *fata;
-	FbId uid;
-
-	fata = purple_connection_get_protocol_data(gc);
-	api = fb_data_get_api(fata);
-	uid = FB_ID_FROM_STR(name);
-
-	fb_api_typing(api, uid, state != PURPLE_IM_NOT_TYPING);
-	return 0;
-}
-
-static GList *
-fb_chat_info(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
-             G_GNUC_UNUSED PurpleConnection *connection)
-{
-	GList *pces = NULL;
-	PurpleProtocolChatEntry *pce;
-
-	pce = g_new0(PurpleProtocolChatEntry, 1);
-	pce->label = _("Chat _Name");
-	pce->identifier = "name";
-	pce->required = TRUE;
-	pces = g_list_prepend(pces, pce);
-
-	return g_list_reverse(pces);
-}
-
-static GHashTable *
-fb_chat_info_defaults(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
-                      G_GNUC_UNUSED PurpleConnection *connection,
-                      const gchar *name)
-{
-	GHashTable *data;
-
-	data = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
-	g_hash_table_insert(data, "name", g_strdup(name));
-
-	return data;
-}
-
-static void
-fb_chat_join(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
-             PurpleConnection *gc, GHashTable *data)
-{
-	const gchar *name;
-	FbApi *api;
-	FbData *fata;
-	FbId tid;
-	gint id;
-	PurpleConversation *chat;
-	PurpleConversationManager *manager;
-	PurpleRequestCommonParameters *cpar;
-
-	name = g_hash_table_lookup(data, "name");
-	g_return_if_fail(name != NULL);
-
-	if (!FB_ID_IS_STR(name)) {
-		cpar = purple_request_cpar_from_connection(gc);
-		purple_notify_error(gc,
-		                    _("Join a Chat"),
-		                    _("Failed to Join Chat"),
-		                    _("Invalid Facebook identifier."),
-				    cpar);
-		return;
-	}
-
-	tid = FB_ID_FROM_STR(name);
-	id = fb_id_hash(&tid);
-
-	manager = purple_conversation_manager_get_default();
-	chat = purple_conversation_manager_find_chat_by_id(manager,
-	                                                   purple_connection_get_account(gc),
-	                                                   id);
-
-	if ((chat != NULL) && !purple_chat_conversation_has_left(PURPLE_CHAT_CONVERSATION(chat))) {
-		purple_conversation_present(chat);
-		return;
-	}
-
-	fata = purple_connection_get_protocol_data(gc);
-	api = fb_data_get_api(fata);
-	fb_api_thread(api, tid);
-}
-
-static gchar *
-fb_chat_get_name(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
-                 GHashTable *data)
-{
-	const gchar *name;
-
-	name = g_hash_table_lookup(data, "name");
-	g_return_val_if_fail(name != NULL, NULL);
-
-	return g_strdup(name);
-}
-
-static void
-fb_chat_invite(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
-               PurpleConnection *gc, gint id, G_GNUC_UNUSED const char *msg,
-               const char *who)
-{
-	const gchar *name;
-	FbApi *api;
-	FbData *fata;
-	FbId tid;
-	FbId uid;
-	PurpleConversation *chat;
-	PurpleConversationManager *manager;
-	PurpleRequestCommonParameters *cpar;
-
-	if (!FB_ID_IS_STR(who)) {
-		cpar = purple_request_cpar_from_connection(gc);
-		purple_notify_error(gc,
-		                    _("Invite Buddy Into Chat Room"),
-		                    _("Failed to Invite User"),
-		                    _("Invalid Facebook identifier."),
-				    cpar);
-		return;
-	}
-
-	fata = purple_connection_get_protocol_data(gc);
-	api = fb_data_get_api(fata);
-
-	manager = purple_conversation_manager_get_default();
-	chat = purple_conversation_manager_find_chat_by_id(manager,
-	                                                   purple_connection_get_account(gc),
-	                                                   id);
-
-	name = purple_conversation_get_name(chat);
-	tid = FB_ID_FROM_STR(name);
-	uid = FB_ID_FROM_STR(who);
-
-	fb_api_thread_invite(api, tid, uid);
-}
-
-static gint
-fb_chat_send(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
-             PurpleConnection *gc, gint id, PurpleMessage *msg)
-{
-	const gchar *name;
-	const gchar *text;
-	FbApi *api;
-	FbData *fata;
-	FbId tid;
-	gchar *sext;
-	PurpleAccount *acct;
-	PurpleConversation *chat;
-	PurpleConversationManager *manager;
-
-	acct = purple_connection_get_account(gc);
-	fata = purple_connection_get_protocol_data(gc);
-	api = fb_data_get_api(fata);
-
-	manager = purple_conversation_manager_get_default();
-	chat = purple_conversation_manager_find_chat_by_id(manager, acct, id);
-
-	name = purple_conversation_get_name(chat);
-	tid = FB_ID_FROM_STR(name);
-
-	text = purple_message_get_contents(msg);
-	sext = purple_markup_strip_html(text);
-	fb_api_message(api, tid, TRUE, sext);
-	g_free(sext);
-
-	name = purple_contact_info_get_username(PURPLE_CONTACT_INFO(acct));
-	purple_serv_got_chat_in(gc, id, name,
-				purple_message_get_flags(msg),
-	                        purple_message_get_contents(msg),
-	                        time(NULL));
-	return 0;
-}
-
-static void
-fb_chat_set_topic(G_GNUC_UNUSED PurpleProtocolChat *protocol_chat,
-                  PurpleConnection *gc, gint id, const char *topic)
-{
-	const gchar *name;
-	FbApi *api;
-	FbData *fata;
-	FbId tid;
-	PurpleConversation *chat;
-	PurpleConversationManager *manager;
-
-	fata = purple_connection_get_protocol_data(gc);
-	api = fb_data_get_api(fata);
-
-	manager = purple_conversation_manager_get_default();
-	chat = purple_conversation_manager_find_chat_by_id(manager,
-	                                                   purple_connection_get_account(gc),
-	                                                   id);
-
-	name = purple_conversation_get_name(chat);
-	tid = FB_ID_FROM_STR(name);
-	fb_api_thread_topic(api, tid, topic);
-}
-
-static PurpleRoomlist *
-fb_roomlist_get_list(G_GNUC_UNUSED PurpleProtocolRoomlist *protocol_roomlist,
-                     PurpleConnection *gc)
-{
-	FbApi *api;
-	FbData *fata;
-	PurpleAccount *acct;
-	PurpleRoomlist *list;
-
-	fata = purple_connection_get_protocol_data(gc);
-	list = fb_data_get_roomlist(fata);
-	g_return_val_if_fail(list == NULL, NULL);
-
-	api = fb_data_get_api(fata);
-	acct = purple_connection_get_account(gc);
-	list = purple_roomlist_new(acct);
-	fb_data_set_roomlist(fata, list);
-
-	purple_roomlist_set_in_progress(list, TRUE);
-	fb_api_threads(api);
-	return list;
-}
-
-static void
-fb_roomlist_cancel(G_GNUC_UNUSED PurpleProtocolRoomlist *protocol_roomlist,
-                   PurpleRoomlist *list)
-{
-	FbData *fata;
-	PurpleAccount *acct;
-	PurpleConnection *gc;
-	PurpleRoomlist *cist;
-
-	acct = purple_roomlist_get_account(list);
-	gc = purple_account_get_connection(acct);
-	fata = purple_connection_get_protocol_data(gc);
-	cist = fb_data_get_roomlist(fata);
-
-	if (G_LIKELY(cist == list)) {
-		fb_data_set_roomlist(fata, NULL);
-	}
-
-	purple_roomlist_set_in_progress(list, FALSE);
-	g_object_unref(list);
-}
-
-static PurpleCmdRet
-fb_cmd_kick(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
-            char **args, char **error, G_GNUC_UNUSED 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);
-
-	fb_api_thread_remove(api, tid, uid);
-	return PURPLE_CMD_RET_OK;
-}
-
-static PurpleCmdRet
-fb_cmd_leave(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
-             G_GNUC_UNUSED char **args, G_GNUC_UNUSED char **error,
-             G_GNUC_UNUSED 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(G_GNUC_UNUSED FacebookProtocol *self) {
-}
-
-static void
-facebook_protocol_class_init(FacebookProtocolClass *klass)
-{
-	PurpleProtocolClass *protocol_class = PURPLE_PROTOCOL_CLASS(klass);
-
-	protocol_class->get_account_options  = fb_get_account_options;
-
-	protocol_class->login = fb_login;
-	protocol_class->close = fb_close;
-	protocol_class->status_types = fb_status_types;
-}
-
-static void
-facebook_protocol_class_finalize(G_GNUC_UNUSED FacebookProtocolClass *klass)
-{
-}
-
-static void
-facebook_protocol_client_iface_init(PurpleProtocolClientInterface *iface)
-{
-	iface->blist_node_menu = fb_client_blist_node_menu;
-	iface->offline_message = fb_client_offline_message;
-}
-
-static void
-facebook_protocol_server_init(PurpleProtocolServerInterface *iface)
-{
-	iface->set_status = fb_server_set_status;
-}
-
-static void
-facebook_protocol_im_iface_init(PurpleProtocolIMInterface *iface)
-{
-	iface->send        = fb_im_send;
-	iface->send_typing = fb_im_send_typing;
-}
-
-static void
-facebook_protocol_chat_iface_init(PurpleProtocolChatInterface *iface)
-{
-	iface->info          = fb_chat_info;
-	iface->info_defaults = fb_chat_info_defaults;
-	iface->join          = fb_chat_join;
-	iface->get_name      = fb_chat_get_name;
-	iface->invite        = fb_chat_invite;
-	iface->send          = fb_chat_send;
-	iface->set_topic     = fb_chat_set_topic;
-}
-
-static void
-facebook_protocol_roomlist_iface_init(PurpleProtocolRoomlistInterface *iface)
-{
-	iface->get_list = fb_roomlist_get_list;
-	iface->cancel   = fb_roomlist_cancel;
-}
-
-G_DEFINE_DYNAMIC_TYPE_EXTENDED(
-	FacebookProtocol,
-	facebook_protocol,
-	PURPLE_TYPE_PROTOCOL,
-	G_TYPE_FLAG_FINAL,
-	G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT,
-	                              facebook_protocol_client_iface_init)
-	G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_SERVER,
-	                              facebook_protocol_server_init)
-	G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_IM,
-	                              facebook_protocol_im_iface_init)
-	G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CHAT,
-	                              facebook_protocol_chat_iface_init)
-	G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_ROOMLIST,
-	                              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_clear_slist(&fb_cmds, fb_cmds_unregister_free);
-}
-
-static GPluginPluginInfo *
-facebook_query(G_GNUC_UNUSED GError **error)
-{
-	return purple_plugin_info_new(
-		"id",          FB_PROTOCOL_ID,
-		"name",        "Facebook Protocol",
-		"version",     DISPLAY_VERSION,
-		"category",    N_("Protocol"),
-		"summary",     N_("Facebook Protocol Plugin"),
-		"description", N_("Facebook Protocol Plugin"),
-		"website",     PURPLE_WEBSITE,
-		"abi-version", PURPLE_ABI_VERSION,
-		"flags",       PURPLE_PLUGIN_INFO_FLAGS_INTERNAL |
-		               PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD,
-		NULL
-	);
-}
-
-static gboolean
-facebook_load(GPluginPlugin *plugin, GError **error)
-{
-	PurpleProtocolManager *manager = purple_protocol_manager_get_default();
-
-	facebook_protocol_register_type(G_TYPE_MODULE(plugin));
-	fb_protocol = g_object_new(FACEBOOK_TYPE_PROTOCOL,
-	                           "id", FB_PROTOCOL_ID,
-	                           "name", "Facebook",
-	                           "description", _("Facebook Messenger allows "
-	                                            "you to talk with your "
-	                                            "friends on Facebook."),
-	                           "icon-name", "im-facebook",
-	                           "icon-resource-path", "/im/pidgin/libpurple/facebook/icons",
-	                           "options", OPT_PROTO_CHAT_TOPIC,
-	                           NULL);
-
-	if(!purple_protocol_manager_register(manager, fb_protocol, error)) {
-		g_clear_object(&fb_protocol);
-
-		return FALSE;
-	}
-
-	fb_cmds_register();
-	return TRUE;
-}
-
-static gboolean
-facebook_unload(G_GNUC_UNUSED GPluginPlugin *plugin,
-                G_GNUC_UNUSED gboolean shutdown, GError **error)
-{
-	PurpleProtocolManager *manager = purple_protocol_manager_get_default();
-
-	if(!purple_protocol_manager_unregister(manager, fb_protocol, error)) {
-		return FALSE;
-	}
-
-	fb_cmds_unregister();
-
-	g_clear_object(&fb_protocol);
-
-	return TRUE;
-}
-
-GPLUGIN_NATIVE_PLUGIN_DECLARE(facebook)

mercurial