# HG changeset patch
# Node ID 5aff053ab591
# Parent  9519814ad7e0
diff --git a/doc/reference/protocols/facebook/facebook.toml.in b/doc/reference/protocols/facebook/facebook.toml.in
deleted file mode 100644
--- a/doc/reference/protocols/facebook/facebook.toml.in
+++ /dev/null
@@ -1,43 +0,0 @@
-[library]
-version = "@PURPLE_VERSION@"
-browse_url = "https://keep.imfreedom.org/pidgin/pidgin/"
-repository_url = "https://keep.imfreedom.org/pidgin/pidgin/"
-website_url = "https://keep.imfreedom.org/pidgin/pidgin/"
-authors = "Pidgin Developers"
-logo_url = ""
-license = "GPL-2.0-or-later"
-description = "Purple Facebook Protocol Plugin"
-dependencies = [ "GLib-2.0", "GObject-2.0", "Purple-3.0" ]
-devhelp = true
-search_index = true
-
-  [dependencies."GLib-2.0"]
-  name = "GLib"
-  description = "General-purpose, portable utility library."
-  docs_url = "https://docs.gtk.org/glib/"
-
-  [dependencies."GObject-2.0"]
-  name = "GObject"
-  description = "The base type system library"
-  docs_url = "https://docs.gtk.org/gobject/"
-
-  [dependencies."Purple-3.0"]
-  name = "Purple"
-  description = "Purple Universal Chat Library"
-  docs_url = "https://docs.imfreedom.org/purple3/"
-
-[theme]
-name = "basic"
-show_index_summary = true
-show_class_hierarchy = true
-
-[source-location]
-base_url = "https://keep.imfreedom.org/pidgin/pidgin/file/default/"
-
-[extra]
-# The same order will be used when generating the index
-content_files = [
-]
-content_images = [
-]
-urlmap_file = "urlmap.js"
diff --git a/doc/reference/protocols/facebook/meson.build b/doc/reference/protocols/facebook/meson.build
deleted file mode 100644
--- a/doc/reference/protocols/facebook/meson.build
+++ /dev/null
@@ -1,35 +0,0 @@
-facebook_doc_content_files = []
-
-if get_option('doc')
-	facebook_toml = configure_file(
-		input : 'facebook.toml.in',
-		output : 'facebook.toml',
-		configuration : version_conf,
-		install : true,
-		install_dir : docs_dir / 'facebook',
-	)
-
-	facebook_doc = custom_target('facebook-doc',
-		input : [ facebook_toml, facebook_gir[0] ],
-		output : 'facebook',
-		command : [
-			gidocgen,
-			'generate',
-			'--quiet',
-			'--fatal-warnings',
-			'--config=@INPUT0@',
-			'--output-dir=@OUTPUT@',
-			'--no-namespace-dir',
-			'--content-dir=@0@'.format(meson.current_source_dir()),
-			'--add-include-path=@0@'.format(meson.global_build_root() / 'subprojects/gplugin/gplugin'),
-			'--add-include-path=@0@'.format(meson.global_build_root() / 'libpurple'),
-			'@INPUT1@'
-		],
-		depends: [ libpurple_gir[0] ],
-		depend_files : [ facebook_doc_content_files ],
-		build_by_default : true,
-		install : true,
-		install_dir : docs_dir,
-	)
-endif
-
diff --git a/doc/reference/protocols/facebook/urlmap.js b/doc/reference/protocols/facebook/urlmap.js
deleted file mode 100644
--- a/doc/reference/protocols/facebook/urlmap.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// SPDX-FileCopyrightText: 2021 GNOME Foundation
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-// A map between namespaces and base URLs for their online documentation
-baseURLs = [
-    [ 'GLib', 'https://docs.gtk.org/glib/' ],
-    [ 'GObject', 'https://docs.gtk.org/gobject/' ],
-    [ 'Purple3', 'https://docs.imfreedom.org/purple3/' ],
-]
diff --git a/doc/reference/protocols/meson.build b/doc/reference/protocols/meson.build
--- a/doc/reference/protocols/meson.build
+++ b/doc/reference/protocols/meson.build
@@ -1,6 +1,2 @@
 protocols_doc = []
 
-if DYNAMIC_FACEBOOK
-	subdir('facebook')
-	protocols_doc += facebook_doc
-endif
diff --git a/libpurple/protocols/facebook/api.h b/libpurple/protocols/facebook/api.h
deleted file mode 100644
--- a/libpurple/protocols/facebook/api.h
+++ /dev/null
@@ -1,1002 +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
- */
-
-#ifndef PURPLE_FACEBOOK_API_H
-#define PURPLE_FACEBOOK_API_H
-
-#include <glib.h>
-
-#include <purple.h>
-
-#include "http.h"
-#include "id.h"
-#include "mqtt.h"
-
-#define FB_TYPE_API  fb_api_get_type()
-
-/**
- * FB_API_AHOST:
- *
- * The HTTP host for the Facebook API.
- */
-#define FB_API_AHOST  "https://api.facebook.com"
-
-/**
- * FB_API_BHOST:
- *
- * The HTTP host for the Facebook BAPI.
- */
-#define FB_API_BHOST  "https://b-api.facebook.com"
-
-/**
- * FB_API_GHOST:
- *
- * The HTTP host for the Facebook Graph API.
- */
-#define FB_API_GHOST  "https://graph.facebook.com"
-
-/**
- * FB_API_WHOST:
- *
- * The HTTP host for the Facebook website.
- */
-#define FB_API_WHOST  "https://www.facebook.com"
-
-/**
- * FB_API_FBRPC_PREFIX
- *
- * The fbrpc URL prefix used in links shared from the mobile app.
- */
-#define FB_API_FBRPC_PREFIX "fbrpc://facebook/nativethirdparty"
-
-/**
- * FB_API_KEY:
- *
- * The Facebook API key.
- */
-#define FB_API_KEY  "256002347743983"
-
-/**
- * FB_API_SECRET:
- *
- * The Facebook API secret.
- */
-#define FB_API_SECRET  "374e60f8b9bb6b8cbb30f78030438895"
-
-/**
- * FB_ORCA_AGENT
- *
- * The part of the user agent that looks like the official client, since the
- * server started checking this.
- */
-
-#define FB_ORCA_AGENT "[FBAN/Orca-Android;FBAV/537.0.0.31.101;FBPN/com.facebook.orca;FBLC/en_US;FBBV/52182662]"
-
-/**
- * FB_API_AGENT:
- *
- * The HTTP User-Agent header.
- */
-#define FB_API_AGENT  "Facebook plugin / Purple / 0.9.5 " FB_ORCA_AGENT
-
-/**
- * FB_API_MQTT_AGENT
- *
- * The client information string sent in the MQTT CONNECT message
- */
-
-#define FB_API_MQTT_AGENT FB_API_AGENT
-
-/**
- * FB_API_URL_ATTACH:
- *
- * The URL for attachment URL requests.
- */
-#define FB_API_URL_ATTACH  FB_API_AHOST "/method/messaging.getAttachment"
-//#define FB_API_URL_ATTACH  FB_API_AHOST "/method/messaging.attachmentRedirect"
-
-/**
- * FB_API_URL_AUTH:
- *
- * The URL for authentication requests.
- */
-#define FB_API_URL_AUTH  FB_API_BHOST "/method/auth.login"
-
-/**
- * FB_API_URL_GQL:
- *
- * The URL for GraphQL requests.
- */
-#define FB_API_URL_GQL  FB_API_GHOST "/graphql"
-
-/**
- * FB_API_URL_MESSAGES:
- *
- * The URL for linking message threads.
- */
-#define FB_API_URL_MESSAGES  FB_API_WHOST "/messages"
-
-/**
- * FB_API_URL_PARTS:
- *
- * The URL for participant management requests.
- */
-#define FB_API_URL_PARTS  FB_API_GHOST "/participants"
-
-/**
- * FB_API_URL_THREADS:
- *
- * The URL for thread management requests.
- */
-#define FB_API_URL_THREADS  FB_API_GHOST "/me/group_threads"
-
-/**
- * FB_API_URL_TOPIC:
- *
- * The URL for thread topic requests.
- */
-#define FB_API_URL_TOPIC  FB_API_AHOST "/method/messaging.setthreadname"
-
-/**
- * FB_API_QUERY_CONTACT:
- *
- * The query hash for the `UsersQuery`.
- *
- * Key mapping:
- *   0: user_fbids
- *   1: include_full_user_info
- *   2: profile_pic_large_size
- *   3: profile_pic_medium_size
- *   4: profile_pic_small_size
- */
-#define FB_API_QUERY_CONTACT  10153915107411729
-
-/**
- * FB_API_QUERY_CONTACTS:
- *
- * The query hash for the `FetchContactsFullQuery`.
- *
- * Key mapping:
- *   0: profile_types
- *   1: limit
- *   2: big_img_size
- *   3: huge_img_size
- *   4: small_img_size
- */
-#define FB_API_QUERY_CONTACTS  10154444360806729
-
-/**
- * FB_API_QUERY_CONTACTS_AFTER:
- *
- * The query hash for the `FetchContactsFullWithAfterQuery`.
- *
- * Key mapping:
- *   0: profile_types
- *   1: after
- *   2: limit
- *   3: big_img_size
- *   4: huge_img_size
- *   5: small_img_size
- */
-#define FB_API_QUERY_CONTACTS_AFTER  10154444360816729
-
-
-/**
- * FB_API_QUERY_CONTACTS_DELTA:
- *
- * The query hash for the `FetchContactsDeltaQuery`.
- *
- * Key mapping:
- *   0: after
- *   1: profile_types
- *   2: limit
- *   3: big_img_size
- *   4: huge_img_size
- *   5: small_img_size
- */
-#define FB_API_QUERY_CONTACTS_DELTA  10154444360801729
-
-/**
- * FB_API_QUERY_STICKER:
- *
- * The query hash for the `FetchStickersWithPreviewsQuery`.
- *
- * Key mapping:
- *   0: sticker_ids
- *   1: media_type
- *   2: preview_size
- *   3: scaling_factor
- *   4: animated_media_type
- */
-#define FB_API_QUERY_STICKER  10152877994321729
-
-/**
- * FB_API_QUERY_THREAD:
- *
- * The query hash for the `ThreadQuery`.
- *
- * Key mapping:
- *   0: thread_ids
- *   1: verification_type
- *   2: hash_key
- *   3: small_preview_size
- *   4: large_preview_size
- *   5: item_count
- *   6: event_count
- *   7: full_screen_height
- *   8: full_screen_width
- *   9: medium_preview_size
- *   10: fetch_users_separately
- *   11: include_message_info
- *   12: msg_count
- *   13: include_full_user_info
- *   14: profile_pic_large_size
- *   15: profile_pic_medium_size
- *   16: profile_pic_small_size
- */
-#define FB_API_QUERY_THREAD  10153919752036729
-
-/**
- * FB_API_QUERY_THREADS:
- *
- * The query hash for the `ThreadListQuery`.
- *
- * Key mapping:
- *   0: folder_tag
- *   1: thread_count
- *   2: include_thread_info
- *   3: verification_type
- *   4: hash_key
- *   5: small_preview_size
- *   6: large_preview_size
- *   7: item_count
- *   8: event_count
- *   9: full_screen_height
- *   10: full_screen_width
- *   11: medium_preview_size
- *   12: fetch_users_separately
- *   13: include_message_info
- *   14: msg_count
- *   15: UNKNOWN
- *   16: profile_pic_large_size
- *   17: profile_pic_medium_size
- *   18: profile_pic_small_size
- */
-#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`.
- *
- * Key mapping:
- *   0: xma_id
- */
-#define FB_API_QUERY_XMA  10153919431161729
-
-/**
- * FB_API_CONTACTS_COUNT:
- *
- * The maximum amount of contacts to fetch in a single request. If this
- * value is set too high, HTTP request will fail. This is due to the
- * request data being too large.
- */
-#define FB_API_CONTACTS_COUNT  500
-
-/**
- * FB_API_TCHK:
- * @e: The expression.
- *
- * Checks the Thrift related expression to ensure that it evaluates to
- * #TRUE. If the expression evaluates to #FALSE, a #GError is assigned
- * to the local `error` variable, then returns with no value.
- *
- * This macro is meant to only be used for Thrift related expressions,
- * where the calling function has a `void` return type. This macro also
- * requires the existence of a predefined `error` variable, which is a
- * pointer of a pointer to a #GError.
- */
-#define FB_API_TCHK(e) \
-	G_STMT_START { \
-		if (G_UNLIKELY(!(e))) { \
-			g_set_error(error, FB_API_ERROR, FB_API_ERROR_GENERAL, \
-						"Failed to read thrift: %s:%d " \
-						"%s: assertion '%s' failed", \
-						__FILE__, __LINE__, G_STRFUNC, #e); \
-			return; \
-		} \
-	} G_STMT_END
-
-/**
- * FB_API_MSGID:
- * @m: The time in milliseconds.
- * @i: The random integer.
- *
- * Creates a 64-bit message identifier in the Facebook format.
- *
- * Returns: The message identifier.
- */
-#define FB_API_MSGID(m, i) ((guint64) ( \
-		(((guint32) i) & 0x3FFFFF) | \
-		(((guint64) m) << 22) \
-	))
-
-/**
- * FB_API_ERROR_EMIT:
- * @a: The #FbApi.
- * @e: The #FbApiError.
- * @c: The code to execute.
- *
- * Emits a #GError on behalf of the #FbApi.
- */
-#define FB_API_ERROR_EMIT(a, e, c) \
-	G_STMT_START { \
-		if (G_UNLIKELY((e) != NULL)) { \
-			fb_api_error_emit(a, e); \
-			{c;} \
-		} \
-	} G_STMT_END
-
-/**
- * FB_API_ERROR:
- *
- * The #GQuark of the domain of API errors.
- */
-#define FB_API_ERROR  fb_api_error_quark()
-
-typedef struct _FbApiEvent FbApiEvent;
-typedef struct _FbApiMessage FbApiMessage;
-typedef struct _FbApiPresence FbApiPresence;
-typedef struct _FbApiThread FbApiThread;
-typedef struct _FbApiTyping FbApiTyping;
-typedef struct _FbApiUser FbApiUser;
-
-/**
- * FbApiError:
- * @FB_API_ERROR_GENERAL: General failure.
- * @FB_API_ERROR_AUTH: Authentication failure.
- * @FB_API_ERROR_QUEUE: Queue failure.
- * @FB_API_ERROR_NONFATAL: Other non-fatal errors.
- *
- * The error codes for the #FB_API_ERROR domain.
- */
-typedef enum
-{
-	FB_API_ERROR_GENERAL,
-	FB_API_ERROR_AUTH,
-	FB_API_ERROR_QUEUE,
-	FB_API_ERROR_NONFATAL
-} FbApiError;
-
-/**
- * FbApiEventType:
- * @FB_API_EVENT_TYPE_THREAD_TOPIC: The thread topic was changed.
- * @FB_API_EVENT_TYPE_THREAD_USER_ADDED: A thread user was added.
- * @FB_API_EVENT_TYPE_THREAD_USER_REMOVED: A thread user was removed.
- *
- * The #FbApiEvent types.
- */
-typedef enum
-{
-	FB_API_EVENT_TYPE_THREAD_TOPIC,
-	FB_API_EVENT_TYPE_THREAD_USER_ADDED,
-	FB_API_EVENT_TYPE_THREAD_USER_REMOVED
-} FbApiEventType;
-
-/**
- * FbApiMessageFlags:
- * @FB_API_MESSAGE_FLAG_DONE: The text has been processed.
- * @FB_API_MESSAGE_FLAG_IMAGE: The text is a URL to an image.
- * @FB_API_MESSAGE_FLAG_SELF: The text is from the #FbApi user.
- *
- * The #FbApiMessage flags.
- */
-typedef enum
-{
-	FB_API_MESSAGE_FLAG_DONE = 1 << 0,
-	FB_API_MESSAGE_FLAG_IMAGE = 1 << 1,
-	FB_API_MESSAGE_FLAG_SELF = 1 << 2
-} FbApiMessageFlags;
-
-#define FB_TYPE_API_EVENT (fb_api_event_get_type())
-
-/**
- * FbApiEvent:
- * @type: The #FbApiEventType.
- * @uid: The user #FbId.
- * @tid: The thread #FbId.
- * @text: The event text.
- *
- * Represents a Facebook update event.
- */
-struct _FbApiEvent
-{
-	FbApiEventType type;
-	FbId uid;
-	FbId tid;
-	gchar *text;
-};
-
-#define FB_TYPE_API_MESSAGE (fb_api_message_get_type())
-
-/**
- * FbApiMessage:
- * @flags: The #FbApiMessageFlags.
- * @uid: The user #FbId.
- * @tid: The thread #FbId.
- * @tstamp: The timestamp in milliseconds (UTC).
- * @text: The message text.
- *
- * Represents a Facebook user message.
- */
-struct _FbApiMessage
-{
-	FbApiMessageFlags flags;
-	FbId uid;
-	FbId tid;
-	gint64 tstamp;
-	gchar *text;
-};
-
-#define FB_TYPE_API_PRESENCE (fb_api_presence_get_type())
-
-/**
- * FbApiPresence:
- * @uid: The user #FbId.
- * @active: #TRUE if the user is active, otherwise #FALSE.
- *
- * Represents a Facebook presence message.
- */
-struct _FbApiPresence
-{
-	FbId uid;
-	gboolean active;
-};
-
-#define FB_TYPE_API_THREAD (fb_api_thread_get_type())
-
-/**
- * FbApiThread:
- * @tid: The thread #FbId.
- * @topic: The topic.
- * @users: The #GSList of #FbApiUser's.
- *
- * Represents a Facebook message thread.
- */
-struct _FbApiThread
-{
-	FbId tid;
-	gchar *topic;
-	GSList *users;
-};
-
-#define FB_TYPE_API_TYPING (fb_api_typing_get_type())
-
-/**
- * FbApiTyping:
- * @uid: The user #FbId.
- * @state: #TRUE if the user is typing, otherwise #FALSE.
- *
- * Represents a Facebook typing message.
- */
-struct _FbApiTyping
-{
-	FbId uid;
-	gboolean state;
-};
-
-#define FB_TYPE_API_USER (fb_api_user_get_type())
-
-/**
- * FbApiUser:
- * @uid: The user #FbId.
- * @name: The name of the user.
- * @icon: The icon URL.
- * @csum: The checksum of @icon.
- *
- * Represents a Facebook user.
- */
-struct _FbApiUser
-{
-	FbId uid;
-	gchar *name;
-	gchar *icon;
-	gchar *csum;
-};
-
-G_DECLARE_FINAL_TYPE(FbApi, fb_api, FB, API, GObject)
-
-/**
- * fb_api_error_quark:
- *
- * Gets the #GQuark of the domain of API errors.
- *
- * Returns: The #GQuark of the domain.
- */
-GQuark
-fb_api_error_quark(void);
-
-/**
- * fb_api_new:
- * @gc: The #PurpleConnection.
- * @resolver: The proxy resolver to use from the account.
- *
- * Creates a new #FbApi. The returned #FbApi should be freed with
- * #g_object_unref() when no longer needed.
- *
- * Returns: The new #FbApi.
- */
-FbApi *fb_api_new(PurpleConnection *gc, GProxyResolver *resolver);
-
-/**
- * fb_api_rehash:
- * @api: The #FbApi.
- *
- * Rehashes and updates internal data of the #FbApi. This should be
- * called whenever properties are modified.
- */
-void
-fb_api_rehash(FbApi *api);
-
-/**
- * fb_api_is_invisible:
- * @api: The #FbApi.
- *
- * Determines if the user of the #FbApi is invisible.
- *
- * Returns: #TRUE if the #FbApi user is invisible, otherwise #FALSE.
- */
-gboolean
-fb_api_is_invisible(FbApi *api);
-
-/**
- * fb_api_error:
- * @api: The #FbApi.
- * @error: The #FbApiError.
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Emits an #FbApiError.
- */
-void
-fb_api_error(FbApi *api, FbApiError error, const gchar *format, ...)
-             G_GNUC_PRINTF(3, 4);
-
-/**
- * fb_api_error_emit:
- * @api: The #FbApi.
- * @error: The #GError.
- *
- * Emits a #GError on an #FbApiError.
- */
-void
-fb_api_error_emit(FbApi *api, GError *error);
-
-/**
- * fb_api_auth:
- * @api: The #FbApi.
- * @user: The Facebook user name, email, or phone number.
- * @pass: The Facebook password.
- *
- * Sends an authentication request to Facebook. This will obtain
- * session information, which is required for all other requests.
- */
-void
-fb_api_auth(FbApi *api, const gchar *user, const gchar *pass);
-
-/**
- * fb_api_contact:
- * @api: The #FbApi.
- * @uid: The user #FbId.
- *
- * Sends a contact request. This will obtain the general information of
- * a single contact.
- */
-void
-fb_api_contact(FbApi *api, FbId uid);
-
-/**
- * fb_api_contacts:
- * @api: The #FbApi.
- *
- * Sends a contacts request. This will obtain a full list of detailed
- * contact information about the friends of the #FbApi user.
- */
-void
-fb_api_contacts(FbApi *api);
-
-/**
- * fb_api_connect:
- * @api: The #FbApi.
- * @invisible: #TRUE to make the user invisible, otherwise #FALSE.
- *
- * Initializes and establishes the underlying MQTT connection.
- */
-void
-fb_api_connect(FbApi *api, gboolean invisible);
-
-/**
- * fb_api_disconnect:
- * @api: The #FbApi.
- *
- * Closes the underlying MQTT connection.
- */
-void
-fb_api_disconnect(FbApi *api);
-
-/**
- * fb_api_message:
- * @api: The #FbApi.
- * @id: The user or thread #FbId.
- * @thread: #TRUE if @id is a thread, otherwise #FALSE.
- * @text: The message text.
- *
- * Sends a message as the user of the #FbApi to a user or a thread.
- */
-void
-fb_api_message(FbApi *api, FbId id, gboolean thread, const gchar *text);
-
-/**
- * fb_api_publish:
- * @api: The #FbApi.
- * @topic: The topic.
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Publishes an MQTT message.
- */
-void
-fb_api_publish(FbApi *api, const gchar *topic, const gchar *format, ...)
-               G_GNUC_PRINTF(3, 4);
-
-/**
- * fb_api_read:
- * @api: The #FbApi.
- * @id: The user or thread #FbId.
- * @thread: #TRUE if @id is a thread, otherwise #FALSE.
- *
- * Marks a message thread as read.
- */
-void
-fb_api_read(FbApi *api, FbId id, gboolean thread);
-
-/**
- * fb_api_unread:
- * @api: The #FbApi.
- *
- * Sends an unread message request.
- */
-void
-fb_api_unread(FbApi *api);
-
-/**
- * fb_api_thread:
- * @api: The #FbApi.
- * @tid: The thread #FbId.
- *
- * Sends a thread request. This will obtain the general information of
- * a single thread.
- */
-void
-fb_api_thread(FbApi *api, FbId tid);
-
-/**
- * fb_api_thread_create:
- * @api: The #FbApi.
- * @uids: (element-type FbId): The #GSList of #FbId's.
- *
- * Sends a thread creation request. In order to create a thread, there
- * must be at least two other users in @uids.
- */
-void
-fb_api_thread_create(FbApi *api, GSList *uids);
-
-/**
- * fb_api_thread_invite:
- * @api: The #FbApi.
- * @tid: The thread #FbId.
- * @uid: The user #FbId.
- *
- * Sends a thread user invitation request.
- */
-void
-fb_api_thread_invite(FbApi *api, FbId tid, FbId uid);
-
-/**
- * fb_api_thread_remove:
- * @api: The #FbApi.
- * @tid: The thread #FbId.
- * @uid: The user #FbId.
- *
- * Sends a thread user removal request.
- */
-void
-fb_api_thread_remove(FbApi *api, FbId tid, FbId uid);
-
-/**
- * fb_api_thread_topic:
- * @api: The #FbApi.
- * @tid: The thread #FbId.
- * @topic: The topic.
- *
- * Sends a thread topic change request.
- */
-void
-fb_api_thread_topic(FbApi *api, FbId tid, const gchar *topic);
-
-/**
- * fb_api_threads:
- * @api: The #FbApi.
- *
- * Sends a threads request. This will obtain a full list of detailed
- * thread information about the threads of the #FbApi user.
- */
-void
-fb_api_threads(FbApi *api);
-
-/**
- * fb_api_typing:
- * @api: The #FbApi.
- * @uid: The user #FbId.
- * @state: #TRUE if the #FbApi user is typing, otherwise #FALSE.
- *
- * Sends a typing state message for the user of the #FbApi.
- */
-void
-fb_api_typing(FbApi *api, FbId uid, gboolean state);
-
-/**
- * fb_api_event_get_type:
- *
- * Returns: The #GType for the #FbApiEvent boxed structure.
- */
-GType fb_api_event_get_type(void);
-
-/**
- * fb_api_event_dup:
- * @event: The #FbApiEvent or #NULL.
- *
- * Duplicates an #FbApiEvent. The returned #FbApiEvent should be freed with
- * #fb_api_event_free() when no longer needed.
- *
- * Returns: The new #FbApiEvent.
- */
-FbApiEvent *
-fb_api_event_dup(const FbApiEvent *event);
-
-/**
- * fb_api_event_reset:
- * @event: The #FbApiEvent.
- * @deep: #TRUE to free allocated data, otherwise #FALSE.
- *
- * Resets an #FbApiEvent.
- */
-void
-fb_api_event_reset(FbApiEvent *event, gboolean deep);
-
-/**
- * fb_api_event_free:
- * @event: The #FbApiEvent.
- *
- * Frees all memory used by the #FbApiEvent.
- */
-void
-fb_api_event_free(FbApiEvent *event);
-
-/**
- * fb_api_message_get_type:
- *
- * Returns: The #GType for the #FbApiMessage boxed structure.
- */
-GType fb_api_message_get_type(void);
-
-/**
- * fb_api_message_dup:
- * @msg: The #FbApiMessage or #NULL.
- *
- * Duplicates an #FbApiMessage. The returned #FbApiMessage should be freed with
- * #fb_api_message_free() when no longer needed.
- *
- * Returns: The new #FbApiMessage.
- */
-FbApiMessage *
-fb_api_message_dup(const FbApiMessage *msg);
-
-/**
- * fb_api_message_reset:
- * @msg: The #FbApiMessage.
- * @deep: #TRUE to free allocated data, otherwise #FALSE.
- *
- * Resets an #FbApiMessage.
- */
-void
-fb_api_message_reset(FbApiMessage *msg, gboolean deep);
-
-/**
- * fb_api_message_free:
- * @msg: The #FbApiMessage.
- *
- * Frees all memory used by the #FbApiMessage.
- */
-void
-fb_api_message_free(FbApiMessage *msg);
-
-/**
- * fb_api_presence_get_type:
- *
- * Returns: The #GType for the #FbApiPresence boxed structure.
- */
-GType fb_api_presence_get_type(void);
-
-/**
- * fb_api_presence_dup:
- * @presence: The #FbApiPresence or %NULL.
- *
- * Duplicates an #FbApiPresence. The returned #FbApiPresence should be freed
- * with #fb_api_presence_free() when no longer needed.
- *
- * Returns: The new #FbApiPresence.
- */
-FbApiPresence *
-fb_api_presence_dup(const FbApiPresence *presence);
-
-/**
- * fb_api_presence_reset:
- * @presence: The #FbApiPresence.
- *
- * Resets an #FbApiPresence.
- */
-void
-fb_api_presence_reset(FbApiPresence *presence);
-
-/**
- * fb_api_presence_free:
- * @presence: The #FbApiPresence.
- *
- * Frees all memory used by the #FbApiPresence.
- */
-void
-fb_api_presence_free(FbApiPresence *presence);
-
-/**
- * fb_api_thread_get_type:
- *
- * Returns: The #GType for the #FbApiThread boxed structure.
- */
-GType fb_api_thread_get_type(void);
-
-/**
- * fb_api_thread_dup:
- * @thrd: The #FbApiThread or #NULL.
- *
- * Duplicates an #FbApiThread. The returned #FbApiThread should be freed with
- * #fb_api_thread_free() when no longer needed.
- *
- * Returns: The new #FbApiThread.
- */
-FbApiThread *
-fb_api_thread_dup(const FbApiThread *thrd);
-
-/**
- * fb_api_thread_reset:
- * @thrd: The #FbApiThread.
- * @deep: #TRUE to free allocated data, otherwise #FALSE.
- *
- * Resets an #FbApiThread.
- */
-void
-fb_api_thread_reset(FbApiThread *thrd, gboolean deep);
-
-/**
- * fb_api_thread_free:
- * @thrd: The #FbApiThread.
- *
- * Frees all memory used by the #FbApiThread.
- */
-void
-fb_api_thread_free(FbApiThread *thrd);
-
-/**
- * fb_api_typing_get_type:
- *
- * Returns: The #GType for the #FbApiTyping boxed structure.
- */
-GType fb_api_typing_get_type(void);
-
-/**
- * fb_api_typing_dup:
- * @typg: The #FbApiTyping or #NULL.
- *
- * Duplicates an #FbApiTyping. The returned #FbApiTyping should be freed with
- * #fb_api_typing_free() when no longer needed.
- *
- * Returns: The new #FbApiTyping.
- */
-FbApiTyping *
-fb_api_typing_dup(const FbApiTyping *typg);
-
-/**
- * fb_api_typing_reset:
- * @typg: The #FbApiTyping.
- *
- * Resets an #FbApiTyping.
- */
-void
-fb_api_typing_reset(FbApiTyping *typg);
-
-/**
- * fb_api_typing_free:
- * @typg: The #FbApiTyping.
- *
- * Frees all memory used by the #FbApiTyping.
- */
-void
-fb_api_typing_free(FbApiTyping *typg);
-
-/**
- * fb_api_user_get_type:
- *
- * Returns: The #GType for the #FbApiUser boxed structure.
- */
-GType fb_api_user_get_type(void);
-
-/**
- * fb_api_user_dup:
- * @user: The #FbApiUser or #NULL.
- *
- * Duplicates an #FbApiUser. The returned #FbApiUser should be freed with
- * #fb_api_user_free() when no longer needed.
- *
- * Returns: The new #FbApiUser.
- */
-FbApiUser *
-fb_api_user_dup(const FbApiUser *user);
-
-/**
- * fb_api_user_reset:
- * @user: The #FbApiUser.
- * @deep: #TRUE to free allocated data, otherwise #FALSE.
- *
- * Resets an #FbApiUser.
- */
-void
-fb_api_user_reset(FbApiUser *user, gboolean deep);
-
-/**
- * fb_api_user_free:
- * @user: The #FbApiUser.
- *
- * Frees all memory used by the #FbApiUser.
- */
-void
-fb_api_user_free(FbApiUser *user);
-
-#endif /* PURPLE_FACEBOOK_API_H */
diff --git a/libpurple/protocols/facebook/api.c b/libpurple/protocols/facebook/api.c
deleted file mode 100644
--- a/libpurple/protocols/facebook/api.c
+++ /dev/null
@@ -1,3468 +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 <json-glib/json-glib.h>
-#include <libsoup/soup.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include "libpurple/glibcompat.h"
-
-#include "api.h"
-#include "http.h"
-#include "json.h"
-#include "thrift.h"
-#include "util.h"
-
-enum
-{
-	PROP_0,
-
-	PROP_CID,
-	PROP_DID,
-	PROP_MID,
-	PROP_STOKEN,
-	PROP_TOKEN,
-	PROP_UID,
-
-	PROP_N
-};
-
-/**
- * FbApi:
- *
- * Represents a Facebook Messenger connection.
- */
-struct _FbApi {
-	GObject parent;
-
-	FbMqtt *mqtt;
-	SoupSession *cons;
-	PurpleConnection *gc;
-	gboolean retrying;
-
-	FbId uid;
-	gint64 sid;
-	guint64 mid;
-	gchar *cid;
-	gchar *did;
-	gchar *stoken;
-	gchar *token;
-
-	GQueue *msgs;
-	gboolean invisible;
-	guint unread;
-	FbId lastmid;
-	gchar *contacts_delta;
-};
-
-static void fb_api_error_literal(FbApi *api, FbApiError error,
-                                 const gchar *msg);
-
-static void
-fb_api_attach(FbApi *api, FbId aid, const gchar *msgid, FbApiMessage *msg);
-
-static void
-fb_api_contacts_after(FbApi *api, const gchar *cursor);
-
-static void
-fb_api_message_send(FbApi *api, FbApiMessage *msg);
-
-static void
-fb_api_sticker(FbApi *api, FbId sid, FbApiMessage *msg);
-
-void
-fb_api_contacts_delta(FbApi *api, const gchar *delta_cursor);
-
-G_DEFINE_TYPE(FbApi, fb_api, G_TYPE_OBJECT);
-
-static void
-fb_api_set_property(GObject *obj, guint prop, const GValue *val,
-                    GParamSpec *pspec)
-{
-	FbApi *api = FB_API(obj);
-
-	switch (prop) {
-	case PROP_CID:
-		g_free(api->cid);
-		api->cid = g_value_dup_string(val);
-		break;
-	case PROP_DID:
-		g_free(api->did);
-		api->did = g_value_dup_string(val);
-		break;
-	case PROP_MID:
-		api->mid = g_value_get_uint64(val);
-		break;
-	case PROP_STOKEN:
-		g_free(api->stoken);
-		api->stoken = g_value_dup_string(val);
-		break;
-	case PROP_TOKEN:
-		g_free(api->token);
-		api->token = g_value_dup_string(val);
-		break;
-	case PROP_UID:
-		api->uid = g_value_get_int64(val);
-		break;
-
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop, pspec);
-		break;
-	}
-}
-
-static void
-fb_api_get_property(GObject *obj, guint prop, GValue *val, GParamSpec *pspec)
-{
-	FbApi *api = FB_API(obj);
-
-	switch (prop) {
-	case PROP_CID:
-		g_value_set_string(val, api->cid);
-		break;
-	case PROP_DID:
-		g_value_set_string(val, api->did);
-		break;
-	case PROP_MID:
-		g_value_set_uint64(val, api->mid);
-		break;
-	case PROP_STOKEN:
-		g_value_set_string(val, api->stoken);
-		break;
-	case PROP_TOKEN:
-		g_value_set_string(val, api->token);
-		break;
-	case PROP_UID:
-		g_value_set_int64(val, api->uid);
-		break;
-
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop, pspec);
-		break;
-	}
-}
-
-
-static void
-fb_api_dispose(GObject *obj)
-{
-	FbApi *api = FB_API(obj);
-
-	if(api->cons != NULL) {
-		soup_session_abort(api->cons);
-	}
-
-	g_clear_object(&api->mqtt);
-
-	g_clear_object(&api->cons);
-	if(api->msgs != NULL) {
-		g_queue_free_full(api->msgs, (GDestroyNotify)fb_api_message_free);
-		api->msgs = NULL;
-	}
-
-	g_clear_pointer(&api->cid, g_free);
-	g_clear_pointer(&api->did, g_free);
-	g_clear_pointer(&api->stoken, g_free);
-	g_clear_pointer(&api->token, g_free);
-	g_clear_pointer(&api->contacts_delta, g_free);
-}
-
-static void
-fb_api_class_init(FbApiClass *klass)
-{
-	GObjectClass *gklass = G_OBJECT_CLASS(klass);
-	GParamSpec *props[PROP_N] = {NULL};
-
-	gklass->set_property = fb_api_set_property;
-	gklass->get_property = fb_api_get_property;
-	gklass->dispose = fb_api_dispose;
-
-	/**
-	 * FbApi:cid:
-	 *
-	 * The client identifier for MQTT. This value should be saved
-	 * and loaded for persistence.
-	 */
-	props[PROP_CID] = g_param_spec_string(
-		"cid",
-		"Client ID",
-		"Client identifier for MQTT",
-		NULL,
-		G_PARAM_READWRITE);
-
-	/**
-	 * FbApi:did:
-	 *
-	 * The device identifier for the MQTT message queue. This value
-	 * should be saved and loaded for persistence.
-	 */
-	props[PROP_DID] = g_param_spec_string(
-		"did",
-		"Device ID",
-		"Device identifier for the MQTT message queue",
-		NULL,
-		G_PARAM_READWRITE);
-
-	/**
-	 * FbApi:mid:
-	 *
-	 * The MQTT identifier. This value should be saved and loaded
-	 * for persistence.
-	 */
-	props[PROP_MID] = g_param_spec_uint64(
-		"mid",
-		"MQTT ID",
-		"MQTT identifier",
-		0, G_MAXUINT64, 0,
-		G_PARAM_READWRITE);
-
-	/**
-	 * FbApi:stoken:
-	 *
-	 * The synchronization token for the MQTT message queue. This
-	 * value should be saved and loaded for persistence.
-	 */
-	props[PROP_STOKEN] = g_param_spec_string(
-		"stoken",
-		"Sync Token",
-		"Synchronization token for the MQTT message queue",
-		NULL,
-		G_PARAM_READWRITE);
-
-	/**
-	 * FbApi:token:
-	 *
-	 * The access token for authentication. This value should be
-	 * saved and loaded for persistence.
-	 */
-	props[PROP_TOKEN] = g_param_spec_string(
-		"token",
-		"Access Token",
-		"Access token for authentication",
-		NULL,
-		G_PARAM_READWRITE);
-
-	/**
-	 * FbApi:uid:
-	 *
-	 * The #FbId of the user of the #FbApi.
-	 */
-	props[PROP_UID] = g_param_spec_int64(
-		"uid",
-		"User ID",
-		"User identifier",
-		0, G_MAXINT64, 0,
-		G_PARAM_READWRITE);
-	g_object_class_install_properties(gklass, PROP_N, props);
-
-	/**
-	 * FbApi::auth:
-	 * @api: The #FbApi.
-	 *
-	 * Emitted upon the successful completion of the authentication
-	 * process. This is emitted as a result of #fb_api_auth().
-	 */
-	g_signal_new("auth",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             0);
-
-	/**
-	 * FbApi::connect:
-	 * @api: The #FbApi.
-	 *
-	 * Emitted upon the successful completion of the connection
-	 * process. This is emitted as a result of #fb_api_connect().
-	 */
-	g_signal_new("connect",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             0);
-
-	/**
-	 * FbApi::contact:
-	 * @api: The #FbApi.
-	 * @user: The #FbApiUser.
-	 *
-	 * Emitted upon the successful reply of a contact request. This
-	 * is emitted as a result of #fb_api_contact().
-	 */
-	g_signal_new("contact",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_POINTER);
-
-	/**
-	 * FbApi::contacts:
-	 * @api: The #FbApi.
-	 * @users: The #GSList of #FbApiUser's.
-	 * @complete: #TRUE if the list is fetched, otherwise #FALSE.
-	 *
-	 * Emitted upon the successful reply of a contacts request.
-	 * This is emitted as a result of #fb_api_contacts(). This can
-	 * be emitted multiple times before the entire contacts list
-	 * has been fetched. Use @complete for detecting the completion
-	 * status of the list fetch.
-	 */
-	g_signal_new("contacts",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
-
-	/**
-	 * FbApi::contacts-delta:
-	 * @api: The #FbApi.
-	 * @added: The #GSList of added #FbApiUser's.
-	 * @removed: The #GSList of strings with removed user ids.
-	 *
-	 * Like 'contacts', but only the deltas.
-	 */
-	g_signal_new("contacts-delta",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             2, G_TYPE_POINTER, G_TYPE_POINTER);
-
-	/**
-	 * FbApi::error:
-	 * @api: The #FbApi.
-	 * @error: The #GError.
-	 *
-	 * Emitted whenever an error is hit within the #FbApi. This
-	 * should disconnect the #FbApi with #fb_api_disconnect().
-	 */
-	g_signal_new("error",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_POINTER);
-
-	/**
-	 * FbApi::events:
-	 * @api: The #FbApi.
-	 * @events: The #GSList of #FbApiEvent's.
-	 *
-	 * Emitted upon incoming events from the stream.
-	 */
-	g_signal_new("events",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_POINTER);
-
-	/**
-	 * FbApi::messages:
-	 * @api: The #FbApi.
-	 * @msgs: The #GSList of #FbApiMessage's.
-	 *
-	 * Emitted upon incoming messages from the stream.
-	 */
-	g_signal_new("messages",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_POINTER);
-
-	/**
-	 * FbApi::presences:
-	 * @api: The #FbApi.
-	 * @press: The #GSList of #FbApiPresence's.
-	 *
-	 * Emitted upon incoming presences from the stream.
-	 */
-	g_signal_new("presences",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_POINTER);
-
-	/**
-	 * FbApi::thread:
-	 * @api: The #FbApi.
-	 * @thrd: The #FbApiThread.
-	 *
-	 * Emitted upon the successful reply of a thread request. This
-	 * is emitted as a result of #fb_api_thread().
-	 */
-	g_signal_new("thread",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_POINTER);
-
-	/**
-	 * FbApi::thread-create:
-	 * @api: The #FbApi.
-	 * @tid: The thread #FbId.
-	 *
-	 * Emitted upon the successful reply of a thread creation
-	 * request. This is emitted as a result of
-	 * #fb_api_thread_create().
-	 */
-	g_signal_new("thread-create",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, FB_TYPE_ID);
-
-	/**
-	 * FbApi::thread-kicked:
-	 * @api: The #FbApi.
-	 * @thrd: The #FbApiThread.
-	 *
-	 * Emitted upon the reply of a thread request when the user is no longer
-	 * part of that thread. This is emitted as a result of #fb_api_thread().
-	 */
-	g_signal_new("thread-kicked",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_POINTER);
-
-	/**
-	 * FbApi::threads:
-	 * @api: The #FbApi.
-	 * @thrds: The #GSList of #FbApiThread's.
-	 *
-	 * Emitted upon the successful reply of a threads request. This
-	 * is emitted as a result of #fb_api_threads().
-	 */
-	g_signal_new("threads",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_POINTER);
-
-	/**
-	 * FbApi::typing:
-	 * @api: The #FbApi.
-	 * @typg: The #FbApiTyping.
-	 *
-	 * Emitted upon an incoming typing state from the stream.
-	 */
-	g_signal_new("typing",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_POINTER);
-}
-
-static void
-fb_api_init(FbApi *api)
-{
-	api->msgs = g_queue_new();
-}
-
-GQuark
-fb_api_error_quark(void)
-{
-	static GQuark q = 0;
-
-	if (G_UNLIKELY(q == 0)) {
-		q = g_quark_from_static_string("fb-api-error-quark");
-	}
-
-	return q;
-}
-
-static gboolean
-fb_api_json_chk(FbApi *api, gconstpointer data, gssize size, JsonNode **node)
-{
-	const gchar *str;
-	FbApiError errc = FB_API_ERROR_GENERAL;
-	FbJsonValues *values;
-	gboolean success = TRUE;
-	gchar *msg;
-	GError *err = NULL;
-	gint64 code;
-	guint i;
-	JsonNode *root;
-
-	static const gchar *exprs[] = {
-		"$.error.message",
-		"$.error.summary",
-		"$.error_msg",
-		"$.errorCode",
-		"$.failedSend.errorMessage",
-	};
-
-	g_return_val_if_fail(FB_IS_API(api), FALSE);
-
-	if (G_UNLIKELY(size == 0)) {
-		fb_api_error_literal(api, FB_API_ERROR_GENERAL, _("Empty JSON data"));
-		return FALSE;
-	}
-
-	fb_util_debug(FB_UTIL_DEBUG_INFO, "Parsing JSON: %.*s\n",
-	              (gint) size, (const gchar *) data);
-
-	root = fb_json_node_new(data, size, &err);
-	FB_API_ERROR_EMIT(api, err, return FALSE);
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE, "$.error_code");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.error.type");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.errorCode");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		return FALSE
-	);
-
-	code = fb_json_values_next_int(values, 0);
-	str = fb_json_values_next_str(values, NULL);
-
-	if (purple_strequal(str, "OAuthException") || (code == 401)) {
-		errc = FB_API_ERROR_AUTH;
-		success = FALSE;
-
-		g_clear_pointer(&api->stoken, g_free);
-		g_clear_pointer(&api->token, g_free);
-	}
-
-	/* 509 is used for "invalid attachment id" */
-	if (code == 509) {
-		errc = FB_API_ERROR_NONFATAL;
-		success = FALSE;
-	}
-
-	str = fb_json_values_next_str(values, NULL);
-
-	if (purple_strequal(str, "ERROR_QUEUE_NOT_FOUND") ||
-	    purple_strequal(str, "ERROR_QUEUE_LOST"))
-	{
-		errc = FB_API_ERROR_QUEUE;
-		success = FALSE;
-
-		g_clear_pointer(&api->stoken, g_free);
-	}
-
-	g_object_unref(values);
-
-	for (msg = NULL, i = 0; i < G_N_ELEMENTS(exprs); i++) {
-		msg = fb_json_node_get_str(root, exprs[i], NULL);
-
-		if (msg != NULL) {
-			success = FALSE;
-			break;
-		}
-	}
-
-	if (!success && (msg == NULL)) {
-		msg = g_strdup(_("Unknown error"));
-	}
-
-	if (msg != NULL) {
-		fb_api_error_literal(api, errc, msg);
-		json_node_free(root);
-		g_free(msg);
-		return FALSE;
-	}
-
-	if (node != NULL) {
-		*node = root;
-	} else {
-		json_node_free(root);
-	}
-
-	return TRUE;
-}
-
-static gboolean
-fb_api_http_chk(FbApi *api, SoupSession *session, GAsyncResult *result,
-                SoupMessage *msg, JsonNode **root)
-{
-	GBytes *response_body = NULL;
-	const gchar *reason = NULL;
-	const gchar *data = NULL;
-	GError *err = NULL;
-	gint code;
-	gsize size = 0;
-
-	reason = soup_message_get_reason_phrase(msg);
-	code = soup_message_get_status(msg);
-
-	fb_util_debug(FB_UTIL_DEBUG_INFO, "HTTP Response (%p):", msg);
-	if (reason != NULL) {
-		fb_util_debug(FB_UTIL_DEBUG_INFO, "  Response Error: %s (%d)", reason,
-		              code);
-	} else {
-		fb_util_debug(FB_UTIL_DEBUG_INFO, "  Response Error: %d", code);
-	}
-
-	if (fb_http_error_chk(msg, &err) && (root == NULL)) {
-		return TRUE;
-	}
-
-	response_body = soup_session_send_and_read_finish(session, result, &err);
-	if(response_body != NULL) {
-		data = g_bytes_get_data(response_body, &size);
-	}
-
-	if (G_LIKELY(size > 0)) {
-		fb_util_debug(FB_UTIL_DEBUG_INFO, "  Response Data: %.*s",
-		              (gint) size, data);
-	}
-
-	/* Rudimentary check to prevent wrongful error parsing */
-	if ((size < 2) || (data[0] != '{') || (data[size - 1] != '}')) {
-		FB_API_ERROR_EMIT(api, err, return FALSE);
-	}
-
-	if (!fb_api_json_chk(api, data, size, root)) {
-		if (G_UNLIKELY(err != NULL)) {
-			g_error_free(err);
-		}
-
-		return FALSE;
-	}
-
-	FB_API_ERROR_EMIT(api, err, return FALSE);
-	return TRUE;
-}
-
-static SoupMessage *
-fb_api_http_req(FbApi *api, const gchar *url, const gchar *name,
-                const gchar *method, FbHttpParams *params,
-                GAsyncReadyCallback callback)
-{
-	gchar *data;
-	gchar *key;
-	gchar *val;
-	GList *keys;
-	GList *l;
-	GString *gstr;
-	SoupMessage *msg;
-
-	fb_http_params_set_str(params, "api_key", FB_API_KEY);
-	fb_http_params_set_str(params, "device_id", api->did);
-	fb_http_params_set_str(params, "fb_api_req_friendly_name", name);
-	fb_http_params_set_str(params, "format", "json");
-	fb_http_params_set_str(params, "method", method);
-
-	val = fb_util_get_locale();
-	fb_http_params_set_str(params, "locale", val);
-	g_free(val);
-
-	/* Ensure an old signature is not computed */
-	g_hash_table_remove(params, "sig");
-
-	gstr = g_string_new(NULL);
-	keys = g_hash_table_get_keys(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(params, key);
-		g_string_append_printf(gstr, "%s=%s", key, val);
-	}
-
-	g_string_append(gstr, FB_API_SECRET);
-	data = g_compute_checksum_for_string(G_CHECKSUM_MD5, gstr->str,
-	                                     gstr->len);
-	fb_http_params_set_str(params, "sig", data);
-	g_string_free(gstr, TRUE);
-	g_list_free(keys);
-	g_free(data);
-
-	msg = soup_message_new_from_encoded_form("POST", url, soup_form_encode_hash(params));
-	fb_http_params_free(params);
-
-	if (api->token != NULL) {
-		data = g_strdup_printf("OAuth %s", api->token);
-		soup_message_headers_replace(soup_message_get_request_headers(msg),
-		                             "Authorization", data);
-		g_free(data);
-	}
-
-	g_object_set_data(G_OBJECT(msg), "facebook-api", api);
-	soup_session_send_and_read_async(api->cons, msg, G_PRIORITY_DEFAULT, NULL,
-	                                 callback, msg);
-
-	fb_util_debug(FB_UTIL_DEBUG_INFO, "HTTP Request (%p):", msg);
-	fb_util_debug(FB_UTIL_DEBUG_INFO, "  Request URL: %s", url);
-
-	return msg;
-}
-
-static SoupMessage *
-fb_api_http_query(FbApi *api, gint64 query, JsonBuilder *builder,
-                  GAsyncReadyCallback hcb)
-{
-	const gchar *name;
-	FbHttpParams *prms;
-	gchar *json;
-
-	switch (query) {
-	case FB_API_QUERY_CONTACT:
-		name = "UsersQuery";
-		break;
-	case FB_API_QUERY_CONTACTS:
-		name = "FetchContactsFullQuery";
-		break;
-	case FB_API_QUERY_CONTACTS_AFTER:
-		name = "FetchContactsFullWithAfterQuery";
-		break;
-	case FB_API_QUERY_CONTACTS_DELTA:
-		name = "FetchContactsDeltaQuery";
-		break;
-	case FB_API_QUERY_STICKER:
-		name = "FetchStickersWithPreviewsQuery";
-		break;
-	case FB_API_QUERY_THREAD:
-		name = "ThreadQuery";
-		break;
-	case FB_API_QUERY_SEQ_ID:
-	case FB_API_QUERY_THREADS:
-		name = "ThreadListQuery";
-		break;
-	case FB_API_QUERY_XMA:
-		name = "XMAQuery";
-		break;
-	default:
-		g_return_val_if_reached(NULL);
-		return NULL;
-	}
-
-	prms = fb_http_params_new();
-	json = fb_json_bldr_close(builder, JSON_NODE_OBJECT, NULL);
-
-	fb_http_params_set_strf(prms, "query_id", "%" G_GINT64_FORMAT, query);
-	fb_http_params_set_str(prms, "query_params", json);
-	g_free(json);
-
-	return fb_api_http_req(api, FB_API_URL_GQL, name, "get", prms, hcb);
-}
-
-static void
-fb_api_cb_http_bool(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	JsonNode *root;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	if (!json_node_get_boolean(root)) {
-		fb_api_error_literal(api, FB_API_ERROR,
-		                     _("Failed generic API operation"));
-	}
-
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-static void
-fb_api_cb_mqtt_error(G_GNUC_UNUSED FbMqtt *mqtt, GError *error, gpointer data)
-{
-	FbApi *api = data;
-
-	if (!api->retrying) {
-		api->retrying = TRUE;
-		fb_util_debug_info("Attempting to reconnect the MQTT stream...");
-		fb_api_connect(api, api->invisible);
-	} else {
-		g_signal_emit_by_name(api, "error", error);
-	}
-}
-
-static void
-fb_api_cb_mqtt_open(FbMqtt *mqtt, gpointer data)
-{
-	const GByteArray *bytes;
-	FbApi *api = data;
-	FbThrift *thft;
-	GByteArray *cytes;
-	GError *err = NULL;
-
-	static guint8 flags = FB_MQTT_CONNECT_FLAG_USER |
-	                      FB_MQTT_CONNECT_FLAG_PASS |
-	                      FB_MQTT_CONNECT_FLAG_CLR;
-
-	thft = fb_thrift_new(NULL, 0);
-
-	/* Write the client identifier */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 1, 0);
-	fb_thrift_write_str(thft, api->cid);
-
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRUCT, 4, 1);
-
-	/* Write the user identifier */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 1, 0);
-	fb_thrift_write_i64(thft, api->uid);
-
-	/* Write the information string */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 2, 1);
-	fb_thrift_write_str(thft, FB_API_MQTT_AGENT);
-
-	/* Write the UNKNOWN ("cp"?) */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 3, 2);
-	fb_thrift_write_i64(thft, 23);
-
-	/* Write the UNKNOWN ("ecp"?) */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 4, 3);
-	fb_thrift_write_i64(thft, 26);
-
-	/* Write the UNKNOWN */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_I32, 5, 4);
-	fb_thrift_write_i32(thft, 1);
-
-	/* Write the UNKNOWN ("no_auto_fg"?) */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_BOOL, 6, 5);
-	fb_thrift_write_bool(thft, TRUE);
-
-	/* Write the visibility state */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_BOOL, 7, 6);
-	fb_thrift_write_bool(thft, !api->invisible);
-
-	/* Write the device identifier */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 8, 7);
-	fb_thrift_write_str(thft, api->did);
-
-	/* Write the UNKNOWN ("fg"?) */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_BOOL, 9, 8);
-	fb_thrift_write_bool(thft, TRUE);
-
-	/* Write the UNKNOWN ("nwt"?) */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_I32, 10, 9);
-	fb_thrift_write_i32(thft, 1);
-
-	/* Write the UNKNOWN ("nwst"?) */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_I32, 11, 10);
-	fb_thrift_write_i32(thft, 0);
-
-	/* Write the MQTT identifier */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 12, 11);
-	fb_thrift_write_i64(thft, api->mid);
-
-	/* Write the UNKNOWN */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_LIST, 14, 12);
-	fb_thrift_write_list(thft, FB_THRIFT_TYPE_I32, 0);
-	fb_thrift_write_stop(thft);
-
-	/* Write the token */
-	fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 15, 14);
-	fb_thrift_write_str(thft, api->token);
-
-	/* Write the STOP for the struct */
-	fb_thrift_write_stop(thft);
-
-	bytes = fb_thrift_get_bytes(thft);
-	cytes = fb_util_zlib_deflate(bytes, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(thft);
-		return;
-	);
-
-	fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, bytes, "Writing connect");
-	fb_mqtt_connect(mqtt, flags, cytes);
-
-	g_byte_array_free(cytes, TRUE);
-	g_object_unref(thft);
-}
-
-static void
-fb_api_connect_queue(FbApi *api)
-{
-	FbApiMessage *msg;
-	gchar *json;
-	JsonBuilder *bldr;
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_add_int(bldr, "delta_batch_size", 125);
-	fb_json_bldr_add_int(bldr, "max_deltas_able_to_process", 1250);
-	fb_json_bldr_add_int(bldr, "sync_api_version", 3);
-	fb_json_bldr_add_str(bldr, "encoding", "JSON");
-
-	if (api->stoken == NULL) {
-		fb_json_bldr_add_int(bldr, "initial_titan_sequence_id", api->sid);
-		fb_json_bldr_add_str(bldr, "device_id", api->did);
-		fb_json_bldr_add_int(bldr, "entity_fbid", api->uid);
-
-		fb_json_bldr_obj_begin(bldr, "queue_params");
-		fb_json_bldr_add_str(bldr, "buzz_on_deltas_enabled", "false");
-
-		fb_json_bldr_obj_begin(bldr, "graphql_query_hashes");
-		fb_json_bldr_add_str(bldr, "xma_query_id",
-		                     G_STRINGIFY(FB_API_QUERY_XMA));
-		fb_json_bldr_obj_end(bldr);
-
-		fb_json_bldr_obj_begin(bldr, "graphql_query_params");
-		fb_json_bldr_obj_begin(bldr, G_STRINGIFY(FB_API_QUERY_XMA));
-		fb_json_bldr_add_str(bldr, "xma_id", "<ID>");
-		fb_json_bldr_obj_end(bldr);
-		fb_json_bldr_obj_end(bldr);
-		fb_json_bldr_obj_end(bldr);
-
-		json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
-		fb_api_publish(api, "/messenger_sync_create_queue", "%s",
-		               json);
-		g_free(json);
-		return;
-	}
-
-	fb_json_bldr_add_int(bldr, "last_seq_id", api->sid);
-	fb_json_bldr_add_str(bldr, "sync_token", api->stoken);
-
-	json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
-	fb_api_publish(api, "/messenger_sync_get_diffs", "%s", json);
-	g_signal_emit_by_name(api, "connect");
-	g_free(json);
-
-	if (!g_queue_is_empty(api->msgs)) {
-		msg = g_queue_peek_head(api->msgs);
-		fb_api_message_send(api, msg);
-	}
-
-	if (api->retrying) {
-		api->retrying = FALSE;
-		fb_util_debug_info("Reconnected the MQTT stream");
-	}
-}
-
-static void
-fb_api_cb_seqid(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	const gchar *str;
-	FbJsonValues *values;
-	GError *err = NULL;
-	JsonNode *root;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.viewer.message_threads.sync_sequence_id");
-	fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE,
-	                   "$.viewer.message_threads.unread_count");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	);
-
-	str = fb_json_values_next_str(values, "0");
-	api->sid = g_ascii_strtoll(str, NULL, 10);
-	api->unread = fb_json_values_next_int(values, 0);
-
-	if (api->sid == 0) {
-		fb_api_error_literal(api, FB_API_ERROR_GENERAL,
-		                     _("Failed to get sync_sequence_id"));
-	} else {
-		fb_api_connect_queue(api);
-	}
-
-	g_object_unref(values);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-static void
-fb_api_cb_mqtt_connect(FbMqtt *mqtt, gpointer data)
-{
-	FbApi *api = data;
-	gchar *json;
-	JsonBuilder *bldr;
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_add_bool(bldr, "foreground", TRUE);
-	fb_json_bldr_add_int(bldr, "keepalive_timeout", FB_MQTT_KA);
-
-	json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
-	fb_api_publish(api, "/foreground_state", "%s", json);
-	g_free(json);
-
-	fb_mqtt_subscribe(mqtt,
-		"/inbox", 0,
-		"/mercury", 0,
-		"/messaging_events", 0,
-		"/orca_presence", 0,
-		"/orca_typing_notifications", 0,
-		"/pp", 0,
-		"/t_ms", 0,
-		"/t_p", 0,
-		"/t_rtc", 0,
-		"/webrtc", 0,
-		"/webrtc_response", 0,
-		NULL
-	);
-
-	/* Notifications seem to lead to some sort of sending rate limit */
-	fb_mqtt_unsubscribe(mqtt, "/orca_message_notifications", NULL);
-
-	if (api->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_SEQ_ID, bldr,
-		                  fb_api_cb_seqid);
-	} else {
-		fb_api_connect_queue(api);
-	}
-}
-
-static void
-fb_api_cb_publish_mark(FbApi *api, GByteArray *pload)
-{
-	FbJsonValues *values;
-	GError *err = NULL;
-	JsonNode *root;
-
-	if (!fb_api_json_chk(api, pload->data, pload->len, &root)) {
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_BOOL, FALSE, "$.succeeded");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		return;
-	);
-
-	if (!fb_json_values_next_bool(values, TRUE)) {
-		fb_api_error_literal(api, FB_API_ERROR_GENERAL,
-		                     _("Failed to mark thread as read"));
-	}
-
-	g_object_unref(values);
-	json_node_free(root);
-}
-
-static GSList *
-fb_api_event_parse(G_GNUC_UNUSED FbApi *api, FbApiEvent *event, GSList *events,
-                   JsonNode *root, GError **error)
-{
-	const gchar *str;
-	FbApiEvent *devent;
-	FbJsonValues *values;
-	GError *err = NULL;
-	guint i;
-
-	static const struct {
-		FbApiEventType type;
-		const gchar *expr;
-	} evtypes[] = {
-		{
-			FB_API_EVENT_TYPE_THREAD_USER_ADDED,
-			"$.log_message_data.added_participants"
-		}, {
-			FB_API_EVENT_TYPE_THREAD_USER_REMOVED,
-			"$.log_message_data.removed_participants"
-		}
-	};
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.log_message_type");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.author");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.log_message_data.name");
-	fb_json_values_update(values, &err);
-
-	if (G_UNLIKELY(err != NULL)) {
-		g_propagate_error(error, err);
-		g_object_unref(values);
-		return events;
-	}
-
-	str = fb_json_values_next_str(values, NULL);
-
-	if (g_strcmp0(str, "log:thread-name") == 0) {
-		str = fb_json_values_next_str(values, "");
-		str = strrchr(str, ':');
-
-		if (str != NULL) {
-			devent = g_new(FbApiEvent, 1);
-			devent->type = FB_API_EVENT_TYPE_THREAD_TOPIC;
-			devent->uid = FB_ID_FROM_STR(str + 1);
-			devent->tid = event->tid;
-			devent->text = fb_json_values_next_str_dup(values, NULL);
-			events = g_slist_prepend(events, devent);
-		}
-	}
-
-	g_object_unref(values);
-
-	for (i = 0; i < G_N_ELEMENTS(evtypes); i++) {
-		values = fb_json_values_new(root);
-		fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$");
-		fb_json_values_set_array(values, FALSE, evtypes[i].expr);
-
-		while (fb_json_values_update(values, &err)) {
-			str = fb_json_values_next_str(values, "");
-			str = strrchr(str, ':');
-
-			if (str != NULL) {
-				devent = g_new0(FbApiEvent, 1);
-				devent->type = evtypes[i].type;
-				devent->uid = FB_ID_FROM_STR(str + 1);
-				devent->tid = event->tid;
-				events = g_slist_prepend(events, devent);
-			}
-		}
-
-		g_object_unref(values);
-
-		if (G_UNLIKELY(err != NULL)) {
-			g_propagate_error(error, err);
-			break;
-		}
-	}
-
-	return events;
-}
-
-static void
-fb_api_cb_publish_mercury(FbApi *api, GByteArray *pload)
-{
-	const gchar *str;
-	FbApiEvent event;
-	FbJsonValues *values;
-	GError *err = NULL;
-	GSList *events = NULL;
-	JsonNode *root;
-	JsonNode *node;
-
-	if (!fb_api_json_chk(api, pload->data, pload->len, &root)) {
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.thread_fbid");
-	fb_json_values_set_array(values, FALSE, "$.actions");
-
-	while (fb_json_values_update(values, &err)) {
-		fb_api_event_reset(&event, FALSE);
-		str = fb_json_values_next_str(values, "0");
-		event.tid = FB_ID_FROM_STR(str);
-
-		node = fb_json_values_get_root(values);
-		events = fb_api_event_parse(api, &event, events, node, &err);
-	}
-
-	if (G_LIKELY(err == NULL)) {
-		events = g_slist_reverse(events);
-		g_signal_emit_by_name(api, "events", events);
-	} else {
-		fb_api_error_emit(api, err);
-	}
-
-	g_slist_free_full(events, (GDestroyNotify) fb_api_event_free);
-	g_object_unref(values);
-	json_node_free(root);
-
-}
-
-static void
-fb_api_cb_publish_typing(FbApi *api, GByteArray *pload)
-{
-	const gchar *str;
-	FbApiTyping typg;
-	FbJsonValues *values;
-	GError *err = NULL;
-	JsonNode *root;
-
-	if (!fb_api_json_chk(api, pload->data, pload->len, &root)) {
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.type");
-	fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE, "$.sender_fbid");
-	fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE, "$.state");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		return;
-	);
-
-	str = fb_json_values_next_str(values, NULL);
-
-	if (g_ascii_strcasecmp(str, "typ") == 0) {
-		typg.uid = fb_json_values_next_int(values, 0);
-
-		if (typg.uid != api->uid) {
-			typg.state = fb_json_values_next_int(values, 0);
-			g_signal_emit_by_name(api, "typing", &typg);
-		}
-	}
-
-	g_object_unref(values);
-	json_node_free(root);
-}
-
-static void
-fb_api_cb_publish_ms_r(FbApi *api, GByteArray *pload)
-{
-	FbApiMessage *msg;
-	FbJsonValues *values;
-	GError *err = NULL;
-	JsonNode *root;
-
-	if (!fb_api_json_chk(api, pload->data, pload->len, &root)) {
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_BOOL, TRUE, "$.succeeded");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		return;
-	);
-
-	if (fb_json_values_next_bool(values, TRUE)) {
-		/* Pop and free the successful message */
-		msg = g_queue_pop_head(api->msgs);
-		fb_api_message_free(msg);
-
-		if (!g_queue_is_empty(api->msgs)) {
-			msg = g_queue_peek_head(api->msgs);
-			fb_api_message_send(api, msg);
-		}
-	} else {
-		fb_api_error_literal(api, FB_API_ERROR_GENERAL,
-		                     "Failed to send message");
-	}
-
-	g_object_unref(values);
-	json_node_free(root);
-}
-
-static gchar *
-fb_api_xma_parse(G_GNUC_UNUSED FbApi *api, const char *body, JsonNode *root,
-                 GError **error)
-{
-	const gchar *str;
-	const gchar *url;
-	FbHttpParams *params;
-	FbJsonValues *values;
-	gchar *text;
-	GError *err = NULL;
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.story_attachment.target.__type__.name");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.story_attachment.url");
-	fb_json_values_update(values, &err);
-
-	if (G_UNLIKELY(err != NULL)) {
-		g_propagate_error(error, err);
-		g_object_unref(values);
-		return NULL;
-	}
-
-	str = fb_json_values_next_str(values, NULL);
-	url = fb_json_values_next_str(values, NULL);
-
-	if ((str == NULL) || (url == NULL)) {
-		text = g_strdup(_("<Unsupported Attachment>"));
-		g_object_unref(values);
-		return text;
-	}
-
-	if (purple_strequal(str, "ExternalUrl")) {
-		params = fb_http_params_new_parse(url, TRUE);
-		if (g_str_has_prefix(url, FB_API_FBRPC_PREFIX)) {
-			text = fb_http_params_dup_str(params, "target_url", NULL);
-		} else {
-			text = fb_http_params_dup_str(params, "u", NULL);
-		}
-		fb_http_params_free(params);
-	} else {
-		text = g_strdup(url);
-	}
-
-	if (fb_http_urlcmp(body, text, FALSE)) {
-		g_free(text);
-		g_object_unref(values);
-		return NULL;
-	}
-
-	g_object_unref(values);
-	return text;
-}
-
-static GSList *
-fb_api_message_parse_attach(FbApi *api, const gchar *mid, FbApiMessage *msg,
-                            GSList *msgs, const gchar *body, JsonNode *root,
-                            GError **error)
-{
-	const gchar *str;
-	FbApiMessage *dmsg;
-	FbId id;
-	FbJsonValues *values;
-	gchar *xma;
-	GError *err = NULL;
-	JsonNode *node;
-	JsonNode *xode;
-
-	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, "$.attachments");
-
-	while (fb_json_values_update(values, &err)) {
-		str = fb_json_values_next_str(values, NULL);
-
-		if (str == NULL) {
-			id = fb_json_values_next_int(values, 0);
-			dmsg = g_memdup2(msg, sizeof(*msg));
-			fb_api_attach(api, id, mid, dmsg);
-			continue;
-		}
-
-		node = fb_json_node_new(str, -1, &err);
-
-		if (G_UNLIKELY(err != NULL)) {
-			break;
-		}
-
-		xode = fb_json_node_get_nth(node, 0);
-		xma = fb_api_xma_parse(api, body, xode, &err);
-
-		if (xma != NULL) {
-			dmsg = g_memdup2(msg, sizeof(*msg));
-			dmsg->text = xma;
-			msgs = g_slist_prepend(msgs, dmsg);
-		}
-
-		json_node_free(node);
-
-		if (G_UNLIKELY(err != NULL)) {
-			break;
-		}
-	}
-
-	if (G_UNLIKELY(err != NULL)) {
-		g_propagate_error(error, err);
-	}
-
-	g_object_unref(values);
-	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_mst(FbThrift *thft, GError **error)
-{
-	if (fb_thrift_read_isstop(thft)) {
-		FB_API_TCHK(fb_thrift_read_stop(thft));
-	} else {
-		FbThriftType type;
-		gint16 id;
-
-		FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, 0));
-		FB_API_TCHK(type == FB_THRIFT_TYPE_STRING);
-		// FB_API_TCHK(id == 2);
-		FB_API_TCHK(fb_thrift_read_str(thft, NULL));
-		FB_API_TCHK(fb_thrift_read_stop(thft));
-	}
-}
-
-static void
-fb_api_cb_publish_ms(FbApi *api, GByteArray *pload)
-{
-	const gchar *data;
-	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);
-	fb_api_cb_publish_mst(thft, &err);
-	size = fb_thrift_get_pos(thft);
-	g_object_unref(thft);
-
-	FB_API_ERROR_EMIT(api, err,
-		return;
-	);
-
-	g_return_if_fail(size < pload->len);
-	data = (gchar *) pload->data + size;
-	size = pload->len - size;
-
-	if (!fb_api_json_chk(api, data, size, &root)) {
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
-	                   "$.lastIssuedSeqId");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.syncToken");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		return;
-	);
-
-	api->sid = fb_json_values_next_int(values, 0);
-	stoken = fb_json_values_next_str_dup(values, NULL);
-	g_object_unref(values);
-
-	if (G_UNLIKELY(stoken != NULL)) {
-		g_free(api->stoken);
-		api->stoken = stoken;
-		g_signal_emit_by_name(api, "connect");
-		json_node_free(root);
-		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;
-	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,
-	                   "$.messageMetadata.offlineThreadingId");
-	fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
-	                   "$.messageMetadata.actorFbId");
-	fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
-	                   "$.messageMetadata"
-	                    ".threadKey.otherUserFbId");
-	fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
-	                   "$.messageMetadata"
-	                    ".threadKey.threadFbId");
-	fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
-	                   "$.messageMetadata.timestamp");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.body");
-	fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
-	                   "$.stickerId");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.messageMetadata.messageId");
-
-	if (fb_json_values_update(values, &err)) {
-		id = fb_json_values_next_int(values, 0);
-
-		/* Ignore everything but new messages */
-		if (id == 0) {
-			goto beach;
-		}
-
-		/* Ignore sequential duplicates */
-		if (id == api->lastmid) {
-			fb_util_debug_info("Ignoring duplicate %" FB_ID_FORMAT, id);
-			goto beach;
-		}
-
-		api->lastmid = id;
-		fb_api_message_reset(&msg, FALSE);
-		msg.uid = fb_json_values_next_int(values, 0);
-		oid = fb_json_values_next_int(values, 0);
-		msg.tid = fb_json_values_next_int(values, 0);
-		msg.tstamp = fb_json_values_next_int(values, 0);
-
-		if (msg.uid == api->uid) {
-			msg.flags |= FB_API_MESSAGE_FLAG_SELF;
-
-			if (msg.tid == 0) {
-				msg.uid = oid;
-			}
-		}
-
-		body = fb_json_values_next_str(values, NULL);
-
-		if (body != NULL) {
-			dmsg = g_memdup2(&msg, sizeof(msg));
-			dmsg->text = g_strdup(body);
-			msgs = g_slist_prepend(msgs, dmsg);
-		}
-
-		id = fb_json_values_next_int(values, 0);
-
-		if (id != 0) {
-			dmsg = g_memdup2(&msg, sizeof(msg));
-			fb_api_sticker(api, id, dmsg);
-		}
-
-		str = fb_json_values_next_str(values, NULL);
-
-		if (str == NULL) {
-			goto beach;
-		}
-
-		node = fb_json_values_get_root(values);
-		msgs = fb_api_message_parse_attach(api, str, &msg, msgs, body,
-		                                   node, &err);
-
-		if (G_UNLIKELY(err != NULL)) {
-			g_propagate_error(error, err);
-			goto beach;
-		}
-	}
-
-beach:
-	g_object_unref(values);
-	return msgs;
-}
-
-static GSList *
-fb_api_cb_publish_ms_event(G_GNUC_UNUSED 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 = g_new0(FbApiEvent, 1);
-	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 = g_new0(FbApiEvent, 1);
-
-			devent->type = event->type;
-			devent->uid = fb_json_values_next_int(values_inner, 0);
-			devent->tid = event->tid;
-			devent->text = fb_json_values_next_str_dup(values_inner, NULL);
-
-			events = g_slist_prepend(events, devent);
-		}
-		g_clear_pointer(&event, fb_api_event_free);
-		g_object_unref(values_inner);
-	}
-
-	g_object_unref(values);
-
-	if (G_UNLIKELY(err != NULL)) {
-		g_propagate_error(error, err);
-	} else if (event) {
-		events = g_slist_prepend(events, event);
-	}
-
-	return events;
-}
-
-static void
-fb_api_cb_publish_pt(FbThrift *thft, GSList **presences, GError **error)
-{
-	FbApiPresence *api_presence;
-	FbThriftType type;
-	gint16 id;
-	gint32 i32;
-	gint64 i64;
-	guint i;
-	guint size = 0;
-
-	/* Read identifier string (for Facebook employees) */
-	FB_API_TCHK(fb_thrift_read_str(thft, NULL));
-
-	/* Read the full list boolean field */
-	FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, 0));
-	FB_API_TCHK(type == FB_THRIFT_TYPE_BOOL);
-	FB_API_TCHK(id == 1);
-	FB_API_TCHK(fb_thrift_read_bool(thft, NULL));
-
-	/* Read the list field */
-	FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, id));
-	FB_API_TCHK(type == FB_THRIFT_TYPE_LIST);
-	FB_API_TCHK(id == 2);
-
-	/* Read the list */
-	FB_API_TCHK(fb_thrift_read_list(thft, &type, &size));
-	FB_API_TCHK(type == FB_THRIFT_TYPE_STRUCT);
-
-	for (i = 0; i < size; i++) {
-		/* Read the user identifier field */
-		FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, 0));
-		FB_API_TCHK(type == FB_THRIFT_TYPE_I64);
-		FB_API_TCHK(id == 1);
-		FB_API_TCHK(fb_thrift_read_i64(thft, &i64));
-
-		/* Read the active field */
-		FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, id));
-		FB_API_TCHK(type == FB_THRIFT_TYPE_I32);
-		FB_API_TCHK(id == 2);
-		FB_API_TCHK(fb_thrift_read_i32(thft, &i32));
-
-		api_presence = g_new0(FbApiPresence, 1);
-		api_presence->uid = i64;
-		api_presence->active = i32 != 0;
-		*presences = g_slist_prepend(*presences, api_presence);
-
-		fb_util_debug_info("Presence: %" FB_ID_FORMAT " (%d) id: %d",
-		                   i64, i32 != 0, id);
-
-		while (id <= 6) {
-			if (fb_thrift_read_isstop(thft)) {
-				break;
-			}
-
-			FB_API_TCHK(fb_thrift_read_field(thft, &type, &id, id));
-
-			switch (id) {
-			case 3:
-				/* Read the last active timestamp field */
-				FB_API_TCHK(type == FB_THRIFT_TYPE_I64);
-				FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
-				break;
-
-			case 4:
-				/* Read the active client bits field */
-				FB_API_TCHK(type == FB_THRIFT_TYPE_I16);
-				FB_API_TCHK(fb_thrift_read_i16(thft, NULL));
-				break;
-
-			case 5:
-				/* Read the VoIP compatibility bits field */
-				FB_API_TCHK(type == FB_THRIFT_TYPE_I64);
-				FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
-				break;
-
-			case 6:
-				/* Unknown new field */
-				FB_API_TCHK(type == FB_THRIFT_TYPE_I64);
-				FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
-				break;
-
-			default:
-				/* Try to read unknown fields as varint */
-				FB_API_TCHK(type == FB_THRIFT_TYPE_I16 ||
-				            type == FB_THRIFT_TYPE_I32 ||
-				            type == FB_THRIFT_TYPE_I64);
-				FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
-				break;
-			}
-		}
-
-		/* Read the field stop */
-		FB_API_TCHK(fb_thrift_read_stop(thft));
-	}
-
-	/* Read the field stop */
-	if (fb_thrift_read_isstop(thft)) {
-		FB_API_TCHK(fb_thrift_read_stop(thft));
-	}
-}
-
-static void
-fb_api_cb_publish_p(FbApi *api, GByteArray *pload)
-{
-	FbThrift *thft;
-	GError *err = NULL;
-	GSList *presences = NULL;
-
-	thft = fb_thrift_new(pload, 0);
-	fb_api_cb_publish_pt(thft, &presences, &err);
-	g_object_unref(thft);
-
-	if (G_LIKELY(err == NULL)) {
-		g_signal_emit_by_name(api, "presences", presences);
-	} else {
-		fb_api_error_emit(api, err);
-	}
-
-	g_slist_free_full(presences, (GDestroyNotify)fb_api_presence_free);
-}
-
-static void
-fb_api_cb_mqtt_publish(G_GNUC_UNUSED FbMqtt *mqtt, const char *topic,
-                       GByteArray *pload, gpointer data)
-{
-	FbApi *api = data;
-	gboolean comp;
-	GByteArray *bytes;
-	GError *err = NULL;
-	guint i;
-
-	static const struct {
-		const gchar *topic;
-		void (*func) (FbApi *api, GByteArray *pload);
-	} parsers[] = {
-		{"/mark_thread_response", fb_api_cb_publish_mark},
-		{"/mercury", fb_api_cb_publish_mercury},
-		{"/orca_typing_notifications", fb_api_cb_publish_typing},
-		{"/send_message_response", fb_api_cb_publish_ms_r},
-		{"/t_ms", fb_api_cb_publish_ms},
-		{"/t_p", fb_api_cb_publish_p}
-	};
-
-	comp = fb_util_zlib_test(pload);
-
-	if (G_LIKELY(comp)) {
-		bytes = fb_util_zlib_inflate(pload, &err);
-		FB_API_ERROR_EMIT(api, err, return);
-	} else {
-		bytes = (GByteArray *) pload;
-	}
-
-	fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, bytes,
-	                      "Reading message (topic: %s)",
-			      topic);
-
-	for (i = 0; i < G_N_ELEMENTS(parsers); i++) {
-		if (g_ascii_strcasecmp(topic, parsers[i].topic) == 0) {
-			parsers[i].func(api, bytes);
-			break;
-		}
-	}
-
-	if (G_LIKELY(comp)) {
-		g_byte_array_free(bytes, TRUE);
-	}
-}
-
-FbApi *
-fb_api_new(PurpleConnection *gc, GProxyResolver *resolver)
-{
-	FbApi *api;
-
-	api = g_object_new(FB_TYPE_API, NULL);
-
-	api->gc = gc;
-	api->cons = soup_session_new_with_options(
-	        "proxy-resolver", resolver,
-	        "user-agent", FB_API_AGENT,
-	        NULL);
-	api->mqtt = fb_mqtt_new(gc);
-
-	g_signal_connect(api->mqtt,
-	                 "connect",
-	                 G_CALLBACK(fb_api_cb_mqtt_connect),
-	                 api);
-	g_signal_connect(api->mqtt,
-	                 "error",
-	                 G_CALLBACK(fb_api_cb_mqtt_error),
-	                 api);
-	g_signal_connect(api->mqtt,
-	                 "open",
-	                 G_CALLBACK(fb_api_cb_mqtt_open),
-	                 api);
-	g_signal_connect(api->mqtt,
-	                 "publish",
-	                 G_CALLBACK(fb_api_cb_mqtt_publish),
-	                 api);
-
-	return api;
-}
-
-void
-fb_api_rehash(FbApi *api)
-{
-	g_return_if_fail(FB_IS_API(api));
-
-	if (api->cid == NULL) {
-		api->cid = fb_util_rand_alnum(32);
-	}
-
-	if (api->did == NULL) {
-		api->did = g_uuid_string_random();
-	}
-
-	if (api->mid == 0) {
-		api->mid = g_random_int();
-	}
-
-	if (strlen(api->cid) > 20) {
-		api->cid = g_realloc_n(api->cid , 21, sizeof *api->cid);
-		api->cid[20] = 0;
-	}
-}
-
-gboolean
-fb_api_is_invisible(FbApi *api)
-{
-	g_return_val_if_fail(FB_IS_API(api), FALSE);
-
-	return api->invisible;
-}
-
-static void
-fb_api_error_literal(FbApi *api, FbApiError error, const gchar *msg)
-{
-	GError *err;
-
-	g_return_if_fail(FB_IS_API(api));
-
-	err = g_error_new_literal(FB_API_ERROR, error, msg);
-
-	fb_api_error_emit(api, err);
-}
-
-void
-fb_api_error(FbApi *api, FbApiError error, const gchar *format, ...)
-{
-	GError *err;
-	va_list ap;
-
-	g_return_if_fail(FB_IS_API(api));
-
-	va_start(ap, format);
-	err = g_error_new_valist(FB_API_ERROR, error, format, ap);
-	va_end(ap);
-
-	fb_api_error_emit(api, err);
-}
-
-void
-fb_api_error_emit(FbApi *api, GError *error)
-{
-	g_return_if_fail(FB_IS_API(api));
-	g_return_if_fail(error != NULL);
-
-	g_signal_emit_by_name(api, "error", error);
-	g_error_free(error);
-}
-
-static void
-fb_api_cb_attach(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	const gchar *str;
-	FbApiMessage *msg;
-	FbJsonValues *values;
-	gchar *name;
-	GError *err = NULL;
-	GSList *msgs = NULL;
-	guint i;
-	JsonNode *root;
-
-	static const gchar *imgexts[] = {".jpg", ".png", ".gif"};
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.filename");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.redirect_uri");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	);
-
-	msg = g_object_steal_data(G_OBJECT(soupmsg), "fb-api-msg");
-	str = fb_json_values_next_str(values, NULL);
-	name = g_ascii_strdown(str, -1);
-
-	for (i = 0; i < G_N_ELEMENTS(imgexts); i++) {
-		if (g_str_has_suffix(name, imgexts[i])) {
-			msg->flags |= FB_API_MESSAGE_FLAG_IMAGE;
-			break;
-		}
-	}
-
-	g_free(name);
-	msg->text = fb_json_values_next_str_dup(values, NULL);
-	msgs = g_slist_prepend(msgs, msg);
-
-	g_signal_emit_by_name(api, "messages", msgs);
-	g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
-	g_object_unref(values);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-static void
-fb_api_attach(FbApi *api, FbId aid, const gchar *msgid, FbApiMessage *msg)
-{
-	FbHttpParams *prms;
-	SoupMessage *http;
-
-	prms = fb_http_params_new();
-	fb_http_params_set_str(prms, "mid", msgid);
-	fb_http_params_set_strf(prms, "aid", "%" FB_ID_FORMAT, aid);
-
-	http = fb_api_http_req(api, FB_API_URL_ATTACH, "getAttachment",
-	                       "messaging.getAttachment", prms,
-	                       fb_api_cb_attach);
-	g_object_set_data_full(G_OBJECT(http), "fb-api-msg", msg,
-	                       (GDestroyNotify)fb_api_message_free);
-}
-
-static void
-fb_api_cb_auth(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	FbJsonValues *values;
-	GError *err = NULL;
-	JsonNode *root;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.access_token");
-	fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE, "$.uid");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	);
-
-	g_free(api->token);
-	api->token = fb_json_values_next_str_dup(values, NULL);
-	api->uid = fb_json_values_next_int(values, 0);
-
-	g_signal_emit_by_name(api, "auth");
-	g_object_unref(values);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-void
-fb_api_auth(FbApi *api, const gchar *user, const gchar *pass)
-{
-	FbHttpParams *prms;
-
-	prms = fb_http_params_new();
-	fb_http_params_set_str(prms, "email", user);
-	fb_http_params_set_str(prms, "password", pass);
-	fb_api_http_req(api, FB_API_URL_AUTH, "authenticate", "auth.login",
-	                prms, fb_api_cb_auth);
-}
-
-static gchar *
-fb_api_user_icon_checksum(gchar *icon)
-{
-	gchar *csum;
-	FbHttpParams *prms;
-
-	if (G_UNLIKELY(icon == NULL)) {
-		return NULL;
-	}
-
-	prms = fb_http_params_new_parse(icon, TRUE);
-	csum = fb_http_params_dup_str(prms, "oh", NULL);
-	fb_http_params_free(prms);
-
-	if (G_UNLIKELY(csum == NULL)) {
-		/* Revert to the icon URL as the unique checksum */
-		csum = g_strdup(icon);
-	}
-
-	return csum;
-}
-
-static void
-fb_api_cb_contact(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	const gchar *str;
-	FbApiUser user;
-	FbJsonValues *values;
-	GError *err = NULL;
-	JsonNode *node;
-	JsonNode *root;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	node = fb_json_node_get_nth(root, 0);
-
-	if (node == NULL) {
-		fb_api_error_literal(api, FB_API_ERROR_GENERAL,
-		                     _("Failed to obtain contact information"));
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	values = fb_json_values_new(node);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.id");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.name");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.profile_pic_large.uri");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	);
-
-	fb_api_user_reset(&user, FALSE);
-	str = fb_json_values_next_str(values, "0");
-	user.uid = FB_ID_FROM_STR(str);
-	user.name = fb_json_values_next_str_dup(values, NULL);
-	user.icon = fb_json_values_next_str_dup(values, NULL);
-
-	user.csum = fb_api_user_icon_checksum(user.icon);
-
-	g_signal_emit_by_name(api, "contact", &user);
-	fb_api_user_reset(&user, TRUE);
-	g_object_unref(values);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-void
-fb_api_contact(FbApi *api, FbId uid)
-{
-	JsonBuilder *bldr;
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_arr_begin(bldr, "0");
-	fb_json_bldr_add_strf(bldr, NULL, "%" FB_ID_FORMAT, uid);
-	fb_json_bldr_arr_end(bldr);
-
-	fb_json_bldr_add_str(bldr, "1", "true");
-	fb_api_http_query(api, FB_API_QUERY_CONTACT, bldr, fb_api_cb_contact);
-}
-
-static GSList *
-fb_api_cb_contacts_nodes(FbApi *api, JsonNode *root, GSList *users)
-{
-	const gchar *str;
-	FbApiUser *user;
-	FbId uid;
-	FbJsonValues *values;
-	gboolean is_array;
-	GError *err = NULL;
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.represented_profile.id");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.represented_profile.friendship_status");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.structured_name.text");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.hugePictureUrl.uri");
-
-	is_array = (JSON_NODE_TYPE(root) == JSON_NODE_ARRAY);
-
-	if (is_array) {
-		fb_json_values_set_array(values, FALSE, "$");
-	}
-
-	while (fb_json_values_update(values, &err)) {
-		str = fb_json_values_next_str(values, "0");
-		uid = FB_ID_FROM_STR(str);
-		str = fb_json_values_next_str(values, NULL);
-
-		if ((!purple_strequal(str, "ARE_FRIENDS") &&
-		    (uid != api->uid)) || (uid == 0))
-		{
-			if (!is_array) {
-				break;
-			}
-			continue;
-		}
-
-		user = g_new0(FbApiUser, 1);
-		user->uid = uid;
-		user->name = fb_json_values_next_str_dup(values, NULL);
-		user->icon = fb_json_values_next_str_dup(values, NULL);
-
-		user->csum = fb_api_user_icon_checksum(user->icon);
-
-		users = g_slist_prepend(users, user);
-
-		if (!is_array) {
-			break;
-		}
-	}
-
-	g_object_unref(values);
-
-	return users;
-}
-
-/* base64(contact:<our id>:<their id>:<whatever>) */
-static GSList *
-fb_api_cb_contacts_parse_removed(G_GNUC_UNUSED FbApi *api, JsonNode *node,
-                                 GSList *users)
-{
-	gsize len;
-	char **split;
-	char *decoded = (char *) g_base64_decode(json_node_get_string(node), &len);
-
-	g_return_val_if_fail(decoded[len] == '\0', users);
-	g_return_val_if_fail(len == strlen(decoded), users);
-	g_return_val_if_fail(g_str_has_prefix(decoded, "contact:"), users);
-
-	split = g_strsplit_set(decoded, ":", 4);
-
-	if (g_strv_length(split) != 4) {
-		g_strfreev(split);
-		g_return_val_if_reached(users);
-	}
-
-	users = g_slist_prepend(users, g_strdup(split[2]));
-
-	g_strfreev(split);
-	g_free(decoded);
-
-	return users;
-}
-
-static void
-fb_api_cb_contacts(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	const gchar *cursor;
-	const gchar *delta_cursor;
-	FbJsonValues *values;
-	gboolean complete;
-	gboolean is_delta;
-	GError *err = NULL;
-	GList *l;
-	GSList *users = NULL;
-	JsonNode *root;
-	JsonNode *croot;
-	JsonNode *node;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	croot = fb_json_node_get(root, "$.viewer.messenger_contacts.deltas", NULL);
-	is_delta = (croot != NULL);
-
-	if (!is_delta) {
-		croot = fb_json_node_get(root, "$.viewer.messenger_contacts", NULL);
-		node = fb_json_node_get(croot, "$.nodes", NULL);
-		users = fb_api_cb_contacts_nodes(api, node, users);
-		json_node_free(node);
-
-	} else {
-		GSList *added = NULL;
-		GSList *removed = NULL;
-		JsonArray *arr = fb_json_node_get_arr(croot, "$.nodes", NULL);
-		GList *elms = json_array_get_elements(arr);
-
-		for (l = elms; l != NULL; l = l->next) {
-			if ((node = fb_json_node_get(l->data, "$.added", NULL))) {
-				added = fb_api_cb_contacts_nodes(api, node, added);
-				json_node_free(node);
-			}
-
-			if ((node = fb_json_node_get(l->data, "$.removed", NULL))) {
-				removed = fb_api_cb_contacts_parse_removed(api, node, removed);
-				json_node_free(node);
-			}
-		}
-
-		g_signal_emit_by_name(api, "contacts-delta", added, removed);
-
-		g_slist_free_full(added, (GDestroyNotify) fb_api_user_free);
-		g_slist_free_full(removed, g_free);
-
-		g_list_free(elms);
-		json_array_unref(arr);
-	}
-
-	values = fb_json_values_new(croot);
-	fb_json_values_add(values, FB_JSON_TYPE_BOOL, FALSE,
-	                   "$.page_info.has_next_page");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.page_info.delta_cursor");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.page_info.end_cursor");
-	fb_json_values_update(values, NULL);
-
-	complete = !fb_json_values_next_bool(values, FALSE);
-
-	delta_cursor = fb_json_values_next_str(values, NULL);
-
-	cursor = fb_json_values_next_str(values, NULL);
-
-	if (G_UNLIKELY(err == NULL)) {
-		if (is_delta || complete) {
-			g_free(api->contacts_delta);
-			api->contacts_delta = g_strdup(is_delta ? cursor : delta_cursor);
-		}
-
-		if (users) {
-			g_signal_emit_by_name(api, "contacts", users, complete);
-		}
-
-		if (!complete) {
-			fb_api_contacts_after(api, cursor);
-		}
-	} else {
-		fb_api_error_emit(api, err);
-	}
-
-	g_slist_free_full(users, (GDestroyNotify) fb_api_user_free);
-	g_object_unref(values);
-
-	json_node_free(croot);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-void
-fb_api_contacts(FbApi *api)
-{
-	JsonBuilder *bldr;
-
-	g_return_if_fail(FB_IS_API(api));
-
-	if (api->contacts_delta) {
-		fb_api_contacts_delta(api, api->contacts_delta);
-		return;
-	}
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_arr_begin(bldr, "0");
-	fb_json_bldr_add_str(bldr, NULL, "user");
-	fb_json_bldr_arr_end(bldr);
-
-	fb_json_bldr_add_str(bldr, "1", G_STRINGIFY(FB_API_CONTACTS_COUNT));
-	fb_api_http_query(api, FB_API_QUERY_CONTACTS, bldr,
-	                  fb_api_cb_contacts);
-}
-
-static void
-fb_api_contacts_after(FbApi *api, const gchar *cursor)
-{
-	JsonBuilder *bldr;
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_arr_begin(bldr, "0");
-	fb_json_bldr_add_str(bldr, NULL, "user");
-	fb_json_bldr_arr_end(bldr);
-
-	fb_json_bldr_add_str(bldr, "1", cursor);
-	fb_json_bldr_add_str(bldr, "2", G_STRINGIFY(FB_API_CONTACTS_COUNT));
-	fb_api_http_query(api, FB_API_QUERY_CONTACTS_AFTER, bldr,
-	                  fb_api_cb_contacts);
-}
-
-void
-fb_api_contacts_delta(FbApi *api, const gchar *delta_cursor)
-{
-	JsonBuilder *bldr;
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-
-	fb_json_bldr_add_str(bldr, "0", delta_cursor);
-
-	fb_json_bldr_arr_begin(bldr, "1");
-	fb_json_bldr_add_str(bldr, NULL, "user");
-	fb_json_bldr_arr_end(bldr);
-
-	fb_json_bldr_add_str(bldr, "2", G_STRINGIFY(FB_API_CONTACTS_COUNT));
-	fb_api_http_query(api, FB_API_QUERY_CONTACTS_DELTA, bldr,
-	                  fb_api_cb_contacts);
-}
-
-void
-fb_api_connect(FbApi *api, gboolean invisible)
-{
-	g_return_if_fail(FB_IS_API(api));
-
-	api->invisible = invisible;
-	fb_mqtt_open(api->mqtt, FB_MQTT_HOST, FB_MQTT_PORT);
-}
-
-void
-fb_api_disconnect(FbApi *api)
-{
-	g_return_if_fail(FB_IS_API(api));
-
-	fb_mqtt_disconnect(api->mqtt);
-}
-
-static void
-fb_api_message_send(FbApi *api, FbApiMessage *msg)
-{
-	const gchar *tpfx;
-	FbId id;
-	FbId mid;
-	gchar *json;
-	JsonBuilder *bldr;
-
-	mid = FB_API_MSGID(g_get_real_time() / 1000, g_random_int());
-	api->lastmid = mid;
-
-	if (msg->tid != 0) {
-		tpfx = "tfbid_";
-		id = msg->tid;
-	} else {
-		tpfx = "";
-		id = msg->uid;
-	}
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_add_str(bldr, "body", msg->text);
-	fb_json_bldr_add_strf(bldr, "msgid", "%" FB_ID_FORMAT, mid);
-	fb_json_bldr_add_strf(bldr, "sender_fbid", "%" FB_ID_FORMAT, api->uid);
-	fb_json_bldr_add_strf(bldr, "to", "%s%" FB_ID_FORMAT, tpfx, id);
-
-	json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
-	fb_api_publish(api, "/send_message2", "%s", json);
-	g_free(json);
-}
-
-void
-fb_api_message(FbApi *api, FbId id, gboolean thread, const gchar *text)
-{
-	FbApiMessage *msg;
-	gboolean empty;
-
-	g_return_if_fail(FB_IS_API(api));
-	g_return_if_fail(text != NULL);
-
-	msg = g_new0(FbApiMessage, 1);
-	msg->text = g_strdup(text);
-
-	if (thread) {
-		msg->tid = id;
-	} else {
-		msg->uid = id;
-	}
-
-	empty = g_queue_is_empty(api->msgs);
-	g_queue_push_tail(api->msgs, msg);
-
-	if (empty && fb_mqtt_connected(api->mqtt, FALSE)) {
-		fb_api_message_send(api, msg);
-	}
-}
-
-void
-fb_api_publish(FbApi *api, const gchar *topic, const gchar *format, ...)
-{
-	GByteArray *bytes;
-	GByteArray *cytes;
-	gchar *msg;
-	GError *err = NULL;
-	va_list ap;
-
-	g_return_if_fail(FB_IS_API(api));
-	g_return_if_fail(topic != NULL);
-	g_return_if_fail(format != NULL);
-
-	va_start(ap, format);
-	msg = g_strdup_vprintf(format, ap);
-	va_end(ap);
-
-	bytes = g_byte_array_new_take((guint8 *) msg, strlen(msg));
-	cytes = fb_util_zlib_deflate(bytes, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_byte_array_free(bytes, TRUE);
-		return;
-	);
-
-	fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, bytes,
-	                      "Writing message (topic: %s)",
-			      topic);
-
-	fb_mqtt_publish(api->mqtt, topic, cytes);
-	g_byte_array_free(cytes, TRUE);
-	g_byte_array_free(bytes, TRUE);
-}
-
-void
-fb_api_read(FbApi *api, FbId id, gboolean thread)
-{
-	const gchar *key;
-	gchar *json;
-	JsonBuilder *bldr;
-
-	g_return_if_fail(FB_IS_API(api));
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_add_bool(bldr, "state", TRUE);
-	fb_json_bldr_add_int(bldr, "syncSeqId", api->sid);
-	fb_json_bldr_add_str(bldr, "mark", "read");
-
-	key = thread ? "threadFbId" : "otherUserFbId";
-	fb_json_bldr_add_strf(bldr, key, "%" FB_ID_FORMAT, id);
-
-	json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
-	fb_api_publish(api, "/mark_thread", "%s", json);
-	g_free(json);
-}
-
-static GSList *
-fb_api_cb_unread_parse_attach(FbApi *api, const gchar *mid, FbApiMessage *msg,
-                              GSList *msgs, JsonNode *root, GError **error)
-{
-	const gchar *str;
-	FbApiMessage *dmsg;
-	FbId id;
-	FbJsonValues *values;
-	GError *err = NULL;
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
-	                   "$.attachment_fbid");
-	fb_json_values_set_array(values, FALSE, "$.blob_attachments");
-
-	while (fb_json_values_update(values, &err)) {
-		str = fb_json_values_next_str(values, NULL);
-		id = FB_ID_FROM_STR(str);
-		dmsg = g_memdup2(msg, sizeof(*msg));
-		fb_api_attach(api, id, mid, dmsg);
-	}
-
-	if (G_UNLIKELY(err != NULL)) {
-		g_propagate_error(error, err);
-	}
-
-	g_object_unref(values);
-	return msgs;
-}
-
-static void
-fb_api_cb_unread_msgs(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	const gchar *body;
-	const gchar *str;
-	FbApiMessage *dmsg;
-	FbApiMessage msg;
-	FbId id;
-	FbId tid;
-	FbJsonValues *values;
-	gchar *xma;
-	GError *err = NULL;
-	GSList *msgs = NULL;
-	JsonNode *node;
-	JsonNode *root;
-	JsonNode *xode;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	node = fb_json_node_get_nth(root, 0);
-
-	if (node == NULL) {
-		fb_api_error_literal(api, FB_API_ERROR_GENERAL,
-		                     _("Failed to obtain unread messages"));
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	values = fb_json_values_new(node);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.thread_key.thread_fbid");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		g_object_unref(soupmsg);
-		return;
-	);
-
-	fb_api_message_reset(&msg, FALSE);
-	str = fb_json_values_next_str(values, "0");
-	tid = FB_ID_FROM_STR(str);
-	g_object_unref(values);
-
-	values = fb_json_values_new(node);
-	fb_json_values_add(values, FB_JSON_TYPE_BOOL, TRUE, "$.unread");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
-	                   "$.message_sender.messaging_actor.id");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.message.text");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
-	                   "$.timestamp_precise");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.sticker.id");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.message_id");
-	fb_json_values_set_array(values, FALSE, "$.messages.nodes");
-
-	while (fb_json_values_update(values, &err)) {
-		if (!fb_json_values_next_bool(values, FALSE)) {
-			continue;
-		}
-
-		str = fb_json_values_next_str(values, "0");
-		body = fb_json_values_next_str(values, NULL);
-
-		fb_api_message_reset(&msg, FALSE);
-		msg.uid = FB_ID_FROM_STR(str);
-		msg.tid = tid;
-
-		str = fb_json_values_next_str(values, "0");
-		msg.tstamp = g_ascii_strtoll(str, NULL, 10);
-
-		if (body != NULL) {
-			dmsg = g_memdup2(&msg, sizeof(msg));
-			dmsg->text = g_strdup(body);
-			msgs = g_slist_prepend(msgs, dmsg);
-		}
-
-		str = fb_json_values_next_str(values, NULL);
-
-		if (str != NULL) {
-			dmsg = g_memdup2(&msg, sizeof(msg));
-			id = FB_ID_FROM_STR(str);
-			fb_api_sticker(api, id, dmsg);
-		}
-
-		node = fb_json_values_get_root(values);
-		xode = fb_json_node_get(node, "$.extensible_attachment", NULL);
-
-		if (xode != NULL) {
-			xma = fb_api_xma_parse(api, body, xode, &err);
-
-			if (xma != NULL) {
-				dmsg = g_memdup2(&msg, sizeof(msg));
-				dmsg->text = xma;
-				msgs = g_slist_prepend(msgs, dmsg);
-			}
-
-			json_node_free(xode);
-
-			if (G_UNLIKELY(err != NULL)) {
-				break;
-			}
-		}
-
-		str = fb_json_values_next_str(values, NULL);
-
-		if (str == NULL) {
-			continue;
-		}
-
-		msgs = fb_api_cb_unread_parse_attach(api, str, &msg, msgs,
-		                                     node, &err);
-
-		if (G_UNLIKELY(err != NULL)) {
-			break;
-		}
-	}
-
-	if (G_UNLIKELY(err == NULL)) {
-		msgs = g_slist_reverse(msgs);
-		g_signal_emit_by_name(api, "messages", msgs);
-	} else {
-		fb_api_error_emit(api, err);
-	}
-
-	g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
-	g_object_unref(values);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-static void
-fb_api_cb_unread(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	const gchar *id;
-	FbJsonValues *values;
-	GError *err = NULL;
-	gint64 count;
-	JsonBuilder *bldr;
-	JsonNode *root;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE, "$.unread_count");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.thread_key.other_user_id");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.thread_key.thread_fbid");
-	fb_json_values_set_array(values, FALSE, "$.viewer.message_threads"
-	                                         ".nodes");
-
-	while (fb_json_values_update(values, &err)) {
-		count = fb_json_values_next_int(values, -5);
-
-		if (count < 1) {
-			continue;
-		}
-
-		id = fb_json_values_next_str(values, NULL);
-
-		if (id == NULL) {
-			id = fb_json_values_next_str(values, "0");
-		}
-
-		bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-		fb_json_bldr_arr_begin(bldr, "0");
-		fb_json_bldr_add_str(bldr, NULL, id);
-		fb_json_bldr_arr_end(bldr);
-
-		fb_json_bldr_add_str(bldr, "10", "true");
-		fb_json_bldr_add_str(bldr, "11", "true");
-		fb_json_bldr_add_int(bldr, "12", count);
-		fb_json_bldr_add_str(bldr, "13", "false");
-		fb_api_http_query(api, FB_API_QUERY_THREAD, bldr,
-		                  fb_api_cb_unread_msgs);
-	}
-
-	if (G_UNLIKELY(err != NULL)) {
-		fb_api_error_emit(api, err);
-	}
-
-	g_object_unref(values);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-void
-fb_api_unread(FbApi *api)
-{
-	JsonBuilder *bldr;
-
-	g_return_if_fail(FB_IS_API(api));
-
-	if (api->unread < 1) {
-		return;
-	}
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_add_str(bldr, "2", "true");
-	fb_json_bldr_add_int(bldr, "1", api->unread);
-	fb_json_bldr_add_str(bldr, "12", "true");
-	fb_json_bldr_add_str(bldr, "13", "false");
-	fb_api_http_query(api, FB_API_QUERY_THREADS, bldr,
-	                  fb_api_cb_unread);
-}
-
-static void
-fb_api_cb_sticker(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	FbApiMessage *msg;
-	FbJsonValues *values;
-	GError *err = NULL;
-	GSList *msgs = NULL;
-	JsonNode *node;
-	JsonNode *root;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	node = fb_json_node_get_nth(root, 0);
-	values = fb_json_values_new(node);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
-	                   "$.thread_image.uri");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	);
-
-	msg = g_object_steal_data(G_OBJECT(soupmsg), "fb-api-msg");
-	msg->flags |= FB_API_MESSAGE_FLAG_IMAGE;
-	msg->text = fb_json_values_next_str_dup(values, NULL);
-	msgs = g_slist_prepend(msgs, msg);
-
-	g_signal_emit_by_name(api, "messages", msgs);
-	g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
-	g_object_unref(values);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-static void
-fb_api_sticker(FbApi *api, FbId sid, FbApiMessage *msg)
-{
-	JsonBuilder *bldr;
-	SoupMessage *http;
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_arr_begin(bldr, "0");
-	fb_json_bldr_add_strf(bldr, NULL, "%" FB_ID_FORMAT, sid);
-	fb_json_bldr_arr_end(bldr);
-
-	http = fb_api_http_query(api, FB_API_QUERY_STICKER, bldr,
-	                         fb_api_cb_sticker);
-	g_object_set_data_full(G_OBJECT(http), "fb-api-msg", msg,
-	                       (GDestroyNotify)fb_api_message_free);
-}
-
-static gboolean
-fb_api_thread_parse(FbApi *api, FbApiThread *thrd, JsonNode *root,
-                    GError **error)
-{
-	const gchar *str;
-	FbApiUser *user;
-	FbId uid;
-	FbJsonValues *values;
-	gboolean haself = FALSE;
-	guint num_users = 0;
-	GError *err = NULL;
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
-	                   "$.thread_key.thread_fbid");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.name");
-	fb_json_values_update(values, &err);
-
-	if (G_UNLIKELY(err != NULL)) {
-		g_propagate_error(error, err);
-		g_object_unref(values);
-		return FALSE;
-	}
-
-	str = fb_json_values_next_str(values, NULL);
-
-	if (str == NULL) {
-		g_object_unref(values);
-		return FALSE;
-	}
-
-	thrd->tid = FB_ID_FROM_STR(str);
-	thrd->topic = fb_json_values_next_str_dup(values, NULL);
-	g_object_unref(values);
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
-	                   "$.messaging_actor.id");
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
-	                   "$.messaging_actor.name");
-	fb_json_values_set_array(values, TRUE, "$.all_participants.nodes");
-
-	while (fb_json_values_update(values, &err)) {
-		str = fb_json_values_next_str(values, "0");
-		uid = FB_ID_FROM_STR(str);
-		num_users++;
-
-		if (uid != api->uid) {
-			user = g_new0(FbApiUser, 1);
-			user->uid = uid;
-			user->name = fb_json_values_next_str_dup(values, NULL);
-			thrd->users = g_slist_prepend(thrd->users, user);
-		} else {
-			haself = TRUE;
-		}
-	}
-
-	if (G_UNLIKELY(err != NULL)) {
-		g_propagate_error(error, err);
-		fb_api_thread_reset(thrd, TRUE);
-		g_object_unref(values);
-		return FALSE;
-	}
-
-	if (num_users < 2 || !haself) {
-		g_object_unref(values);
-		return FALSE;
-	}
-
-	g_object_unref(values);
-	return TRUE;
-}
-
-static void
-fb_api_cb_thread(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	FbApiThread thrd;
-	GError *err = NULL;
-	JsonNode *node;
-	JsonNode *root;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	node = fb_json_node_get_nth(root, 0);
-
-	if (node == NULL) {
-		fb_api_error_literal(api, FB_API_ERROR_GENERAL,
-		                     _("Failed to obtain thread information"));
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	fb_api_thread_reset(&thrd, FALSE);
-
-	if (!fb_api_thread_parse(api, &thrd, node, &err)) {
-		if (G_LIKELY(err == NULL)) {
-			if (thrd.tid) {
-				g_signal_emit_by_name(api, "thread-kicked", &thrd);
-			} else {
-				fb_api_error_literal(api, FB_API_ERROR_GENERAL,
-				                     _("Failed to parse thread information"));
-			}
-		} else {
-			fb_api_error_emit(api, err);
-		}
-	} else {
-		g_signal_emit_by_name(api, "thread", &thrd);
-	}
-
-	fb_api_thread_reset(&thrd, TRUE);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-void
-fb_api_thread(FbApi *api, FbId tid)
-{
-	JsonBuilder *bldr;
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_arr_begin(bldr, "0");
-	fb_json_bldr_add_strf(bldr, NULL, "%" FB_ID_FORMAT, tid);
-	fb_json_bldr_arr_end(bldr);
-
-	fb_json_bldr_add_str(bldr, "10", "false");
-	fb_json_bldr_add_str(bldr, "11", "false");
-	fb_json_bldr_add_str(bldr, "13", "false");
-	fb_api_http_query(api, FB_API_QUERY_THREAD, bldr, fb_api_cb_thread);
-}
-
-static void
-fb_api_cb_thread_create(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	const gchar *str;
-	FbId tid;
-	FbJsonValues *values;
-	GError *err = NULL;
-	JsonNode *root;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	values = fb_json_values_new(root);
-	fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.id");
-	fb_json_values_update(values, &err);
-
-	FB_API_ERROR_EMIT(api, err,
-		g_object_unref(values);
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	);
-
-	str = fb_json_values_next_str(values, "0");
-	tid = FB_ID_FROM_STR(str);
-	g_signal_emit_by_name(api, "thread-create", tid);
-
-	g_object_unref(values);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-void
-fb_api_thread_create(FbApi *api, GSList *uids)
-{
-	FbHttpParams *prms;
-	FbId *uid;
-	gchar *json;
-	GSList *l;
-	JsonBuilder *bldr;
-
-	g_return_if_fail(FB_IS_API(api));
-	g_warn_if_fail(g_slist_length(uids) > 1);
-
-	bldr = fb_json_bldr_new(JSON_NODE_ARRAY);
-	fb_json_bldr_obj_begin(bldr, NULL);
-	fb_json_bldr_add_str(bldr, "type", "id");
-	fb_json_bldr_add_strf(bldr, "id", "%" FB_ID_FORMAT, api->uid);
-	fb_json_bldr_obj_end(bldr);
-
-	for (l = uids; l != NULL; l = l->next) {
-		uid = l->data;
-		fb_json_bldr_obj_begin(bldr, NULL);
-		fb_json_bldr_add_str(bldr, "type", "id");
-		fb_json_bldr_add_strf(bldr, "id", "%" FB_ID_FORMAT, *uid);
-		fb_json_bldr_obj_end(bldr);
-	}
-
-	json = fb_json_bldr_close(bldr, JSON_NODE_ARRAY, NULL);
-	prms = fb_http_params_new();
-	fb_http_params_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);
-}
-
-void
-fb_api_thread_invite(FbApi *api, FbId tid, FbId uid)
-{
-	FbHttpParams *prms;
-	gchar *json;
-	JsonBuilder *bldr;
-
-	bldr = fb_json_bldr_new(JSON_NODE_ARRAY);
-	fb_json_bldr_obj_begin(bldr, NULL);
-	fb_json_bldr_add_str(bldr, "type", "id");
-	fb_json_bldr_add_strf(bldr, "id", "%" FB_ID_FORMAT, uid);
-	fb_json_bldr_obj_end(bldr);
-	json = fb_json_bldr_close(bldr, JSON_NODE_ARRAY, NULL);
-
-	prms = fb_http_params_new();
-	fb_http_params_set_str(prms, "to", json);
-	fb_http_params_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);
-}
-
-void
-fb_api_thread_remove(FbApi *api, FbId tid, FbId uid)
-{
-	FbHttpParams *prms;
-	gchar *json;
-	JsonBuilder *bldr;
-
-	g_return_if_fail(FB_IS_API(api));
-
-	prms = fb_http_params_new();
-	fb_http_params_set_strf(prms, "id", "t_%" FB_ID_FORMAT, tid);
-
-	if (uid == 0) {
-		uid = api->uid;
-	}
-
-	if (uid != api->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, FB_API_URL_PARTS, "removeMembers", "DELETE",
-	                prms, fb_api_cb_http_bool);
-}
-
-void
-fb_api_thread_topic(FbApi *api, FbId tid, const gchar *topic)
-{
-	FbHttpParams *prms;
-
-	prms = fb_http_params_new();
-	fb_http_params_set_str(prms, "name", topic);
-	fb_http_params_set_int(prms, "tid", tid);
-	fb_api_http_req(api, FB_API_URL_TOPIC, "setThreadName",
-	                "messaging.setthreadname", prms, fb_api_cb_http_bool);
-}
-
-static void
-fb_api_cb_threads(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupSession *session = SOUP_SESSION(source);
-	SoupMessage *soupmsg = data;
-	FbApi *api = g_object_get_data(G_OBJECT(soupmsg), "facebook-api");
-	FbApiThread *dthrd;
-	FbApiThread thrd;
-	GError *err = NULL;
-	GList *elms;
-	GList *l;
-	GSList *thrds = NULL;
-	JsonArray *arr;
-	JsonNode *root;
-
-	if (!fb_api_http_chk(api, session, result, soupmsg, &root)) {
-		g_object_unref(soupmsg);
-		return;
-	}
-
-	arr = fb_json_node_get_arr(root, "$.viewer.message_threads.nodes",
-	                           &err);
-	FB_API_ERROR_EMIT(api, err,
-		json_node_free(root);
-		g_object_unref(soupmsg);
-		return;
-	);
-
-	elms = json_array_get_elements(arr);
-
-	for (l = elms; l != NULL; l = l->next) {
-		fb_api_thread_reset(&thrd, FALSE);
-
-		if (fb_api_thread_parse(api, &thrd, l->data, &err)) {
-			dthrd = g_memdup2(&thrd, sizeof(thrd));
-			thrds = g_slist_prepend(thrds, dthrd);
-		} else {
-			fb_api_thread_reset(&thrd, TRUE);
-		}
-
-		if (G_UNLIKELY(err != NULL)) {
-			break;
-		}
-	}
-
-	if (G_LIKELY(err == NULL)) {
-		thrds = g_slist_reverse(thrds);
-		g_signal_emit_by_name(api, "threads", thrds);
-	} else {
-		fb_api_error_emit(api, err);
-	}
-
-	g_slist_free_full(thrds, (GDestroyNotify) fb_api_thread_free);
-	g_list_free(elms);
-	json_array_unref(arr);
-	json_node_free(root);
-	g_object_unref(soupmsg);
-}
-
-void
-fb_api_threads(FbApi *api)
-{
-	JsonBuilder *bldr;
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_add_str(bldr, "2", "true");
-	fb_json_bldr_add_str(bldr, "12", "false");
-	fb_json_bldr_add_str(bldr, "13", "false");
-	fb_api_http_query(api, FB_API_QUERY_THREADS, bldr, fb_api_cb_threads);
-}
-
-void
-fb_api_typing(FbApi *api, FbId uid, gboolean state)
-{
-	gchar *json;
-	JsonBuilder *bldr;
-
-	bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
-	fb_json_bldr_add_int(bldr, "state", state != 0);
-	fb_json_bldr_add_strf(bldr, "to", "%" FB_ID_FORMAT, uid);
-
-	json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
-	fb_api_publish(api, "/typing", "%s", json);
-	g_free(json);
-}
-
-FbApiEvent *
-fb_api_event_dup(const FbApiEvent *event)
-{
-	FbApiEvent *ret;
-
-	if (event == NULL) {
-		return NULL;
-	}
-
-	ret = g_memdup2(event, sizeof *event);
-	ret->text = g_strdup(event->text);
-
-	return ret;
-}
-
-void
-fb_api_event_reset(FbApiEvent *event, gboolean deep)
-{
-	g_return_if_fail(event != NULL);
-
-	if (deep) {
-		g_free(event->text);
-	}
-
-	memset(event, 0, sizeof *event);
-}
-
-void
-fb_api_event_free(FbApiEvent *event)
-{
-	if (G_LIKELY(event != NULL)) {
-		g_free(event->text);
-		g_free(event);
-	}
-}
-
-G_DEFINE_BOXED_TYPE(FbApiEvent, fb_api_event, fb_api_event_dup,
-                    fb_api_event_free)
-
-FbApiMessage *
-fb_api_message_dup(const FbApiMessage *msg)
-{
-	FbApiMessage *ret;
-
-	if (msg == NULL) {
-		return NULL;
-	}
-
-	ret = g_memdup2(msg, sizeof *msg);
-	ret->text = g_strdup(msg->text);
-
-	return ret;
-}
-
-void
-fb_api_message_reset(FbApiMessage *msg, gboolean deep)
-{
-	g_return_if_fail(msg != NULL);
-
-	if (deep) {
-		g_free(msg->text);
-	}
-
-	memset(msg, 0, sizeof *msg);
-}
-
-void
-fb_api_message_free(FbApiMessage *msg)
-{
-	if (G_LIKELY(msg != NULL)) {
-		g_free(msg->text);
-		g_free(msg);
-	}
-}
-
-G_DEFINE_BOXED_TYPE(FbApiMessage, fb_api_message, fb_api_message_dup,
-                    fb_api_message_free)
-
-FbApiPresence *
-fb_api_presence_dup(const FbApiPresence *presence)
-{
-	return g_memdup2(presence, sizeof *presence);
-}
-
-void
-fb_api_presence_reset(FbApiPresence *presence)
-{
-	g_return_if_fail(presence != NULL);
-	memset(presence, 0, sizeof *presence);
-}
-
-void
-fb_api_presence_free(FbApiPresence *presence)
-{
-	if (G_LIKELY(presence != NULL)) {
-		g_free(presence);
-	}
-}
-
-G_DEFINE_BOXED_TYPE(FbApiPresence, fb_api_presence, fb_api_presence_dup,
-                    fb_api_presence_free)
-
-FbApiThread *
-fb_api_thread_dup(const FbApiThread *thrd)
-{
-	FbApiThread *ret;
-
-	if (thrd == NULL) {
-		return NULL;
-	}
-
-	ret = g_memdup2(thrd, sizeof *thrd);
-	ret->topic = g_strdup(thrd->topic);
-	ret->users = g_slist_copy_deep(thrd->users,
-	                               (GCopyFunc)(GCallback)fb_api_user_dup,
-	                               NULL);
-
-	return ret;
-}
-
-void
-fb_api_thread_reset(FbApiThread *thrd, gboolean deep)
-{
-	g_return_if_fail(thrd != NULL);
-
-	if (deep) {
-		g_slist_free_full(thrd->users, (GDestroyNotify) fb_api_user_free);
-		g_free(thrd->topic);
-	}
-
-	memset(thrd, 0, sizeof *thrd);
-}
-
-void
-fb_api_thread_free(FbApiThread *thrd)
-{
-	if (G_LIKELY(thrd != NULL)) {
-		g_slist_free_full(thrd->users, (GDestroyNotify) fb_api_user_free);
-		g_free(thrd->topic);
-		g_free(thrd);
-	}
-}
-
-G_DEFINE_BOXED_TYPE(FbApiThread, fb_api_thread, fb_api_thread_dup,
-                    fb_api_thread_free)
-
-FbApiTyping *
-fb_api_typing_dup(const FbApiTyping *typg)
-{
-	return g_memdup2(typg, sizeof *typg);
-}
-
-void
-fb_api_typing_reset(FbApiTyping *typg)
-{
-	g_return_if_fail(typg != NULL);
-	memset(typg, 0, sizeof *typg);
-}
-
-void
-fb_api_typing_free(FbApiTyping *typg)
-{
-	if (G_LIKELY(typg != NULL)) {
-		g_free(typg);
-	}
-}
-
-G_DEFINE_BOXED_TYPE(FbApiTyping, fb_api_typing, fb_api_typing_dup,
-                    fb_api_typing_free)
-
-FbApiUser *
-fb_api_user_dup(const FbApiUser *user)
-{
-	FbApiUser *ret;
-
-	if (user == NULL) {
-		return NULL;
-	}
-
-	ret = g_memdup2(user, sizeof *user);
-	ret->name = g_strdup(user->name);
-	ret->icon = g_strdup(user->icon);
-	ret->csum = g_strdup(user->csum);
-
-	return ret;
-}
-
-void
-fb_api_user_reset(FbApiUser *user, gboolean deep)
-{
-	g_return_if_fail(user != NULL);
-
-	if (deep) {
-		g_free(user->name);
-		g_free(user->icon);
-		g_free(user->csum);
-	}
-
-	memset(user, 0, sizeof *user);
-}
-
-void
-fb_api_user_free(FbApiUser *user)
-{
-	if (G_LIKELY(user != NULL)) {
-		g_free(user->name);
-		g_free(user->icon);
-		g_free(user->csum);
-		g_free(user);
-	}
-}
-
-G_DEFINE_BOXED_TYPE(FbApiUser, fb_api_user, fb_api_user_dup, fb_api_user_free)
diff --git a/libpurple/protocols/facebook/data.h b/libpurple/protocols/facebook/data.h
deleted file mode 100644
--- a/libpurple/protocols/facebook/data.h
+++ /dev/null
@@ -1,318 +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
- */
-
-#ifndef PURPLE_FACEBOOK_DATA_H
-#define PURPLE_FACEBOOK_DATA_H
-
-#include <glib.h>
-
-#include <purple.h>
-
-#include "api.h"
-#include "http.h"
-#include "id.h"
-
-#define FB_TYPE_DATA  fb_data_get_type()
-#define FB_TYPE_DATA_IMAGE  fb_data_image_get_type()
-
-/**
- * FB_DATA_ICON_MAX:
- *
- * The maximum of number of concurrent icon fetches.
- */
-#define FB_DATA_ICON_MAX  4
-
-/**
- * FB_DATA_ICON_SIZE_MAX:
- *
- * The maximum size of a fetched icon.
- */
-#define FB_DATA_ICON_SIZE_MAX  0xa00000 /* 10MiB */
-
-G_DECLARE_FINAL_TYPE(FbData, fb_data, FB, DATA, GObject)
-
-G_DECLARE_FINAL_TYPE(FbDataImage, fb_data_image, FB, DATA_IMAGE, GObject)
-
-/**
- * FbDataImageFunc:
- * @img: The #FbDataImage.
- * @error: The #GError or #NULL.
- *
- * The callback for a fetched #FbDataImage.
- */
-typedef void (*FbDataImageFunc) (FbDataImage *img, GError *error);
-
-/**
- * fb_data_new:
- * @gc: The #PurpleConnection.
- * @resolver: The proxy resolver to use from the account.
- *
- * Creates a new #FbData. The returned #FbData should be freed with
- * #g_object_unref() when no longer needed.
- *
- * Returns: The new #FbData.
- */
-FbData *fb_data_new(PurpleConnection *gc, GProxyResolver *resolver);
-
-/**
- * fb_data_load:
- * @fata: The #FbData.
- *
- * Loads the internal data from the underlying #PurpleAccount.
- *
- * Return: #TRUE if all of the data was loaded, otherwise #FALSE.
- */
-gboolean
-fb_data_load(FbData *fata);
-
-/**
- * fb_data_save:
- * @fata: The #FbData.
- *
- * Saves the internal data to the underlying #PurpleAccount.
- */
-void
-fb_data_save(FbData *fata);
-
-/**
- * fb_data_save_timeout:
- * @fata: The #FbData.
- * @name: The name of the timeout.
- * @id: The source id of the timeout.
- *
- * Saves a new callback timer. The callback should be added to the main loop
- * with `g_timeout_add` or similar, and the returned source identifier passed
- * to this function. The timeout should be cleared with
- * #fb_data_clear_timeout() when no longer needed.
- */
-void
-fb_data_save_timeout(FbData *fata, const gchar *name, guint id);
-
-/**
- * fb_data_clear_timeout:
- * @fata: The #FbData.
- * @name: The name of the timeout.
- * @remove: #TRUE to remove from the event loop, otherwise #FALSE.
- *
- * Clears and removes a callback timer. The only time @remove should be
- * #FALSE, is when being called from a #GSourceFunc, which is returning
- * #FALSE.
- */
-void
-fb_data_clear_timeout(FbData *fata, const gchar *name, gboolean remove);
-
-/**
- * fb_data_get_api:
- * @fata: The #FbData.
- *
- * Gets the #FbApi from the #FbData.
- *
- * Return: (transfer none): The #FbApi.
- */
-FbApi *
-fb_data_get_api(FbData *fata);
-
-/**
- * fb_data_get_connection:
- * @fata: The #FbData.
- *
- * Gets the #PurpleConnection from the #FbData.
- *
- * Return: (transfer none): The #PurpleConnection.
- */
-PurpleConnection *
-fb_data_get_connection(FbData *fata);
-
-/**
- * fb_data_get_roomlist:
- * @fata: The #FbData.
- *
- * Gets the #PurpleRoomlist from the #FbData.
- *
- * Return: (transfer none): The #PurpleRoomlist.
- */
-PurpleRoomlist *
-fb_data_get_roomlist(FbData *fata);
-
-/**
- * fb_data_get_unread:
- * @fata: The #FbData.
- * @id: The #FbId.
- *
- * Gets the unread state of an #FbId.
- *
- * Return: #TRUE if the #FbId is unread, otherwise #FALSE.
- */
-gboolean
-fb_data_get_unread(FbData *fata, FbId id);
-
-/**
- * fb_data_set_roomlist:
- * @fata: The #FbData.
- * @list: The #PurpleRoomlist.
- *
- * Sets the #PurpleRoomlist to the #FbData.
- */
-void
-fb_data_set_roomlist(FbData *fata, PurpleRoomlist *list);
-
-/**
- * fb_data_set_unread:
- * @fata: The #FbData.
- * @id: The #FbId.
- * @unread: #TRUE if the #FbId is unread, otherwise #FALSE.
- *
- * Sets the unread state of an #FbId to the #FbData.
- */
-void
-fb_data_set_unread(FbData *fata, FbId id, gboolean unread);
-
-/**
- * fb_data_add_message:
- * @fata: The #FbData.
- * @msg: The #FbApiMessage.
- *
- * Adds an #FbApiMessage to the #FbData.
- */
-void
-fb_data_add_message(FbData *fata, FbApiMessage *msg);
-
-/**
- * fb_data_remove_message:
- * @fata: The #FbData.
- * @msg: The #FbApiMessage.
- *
- * Removes an #FbApiMessage from the #FbData.
- */
-void
-fb_data_remove_message(FbData *fata, FbApiMessage *msg);
-
-/**
- * fb_data_take_messages:
- * @fata: The #FbData.
- * @uid: The user #FbId.
- *
- * Gets a #GSList of messages by the user #FbId from the #FbData. The
- * #FbApiMessage's are removed from the #FbData.
- *
- * Returns: (element-type FbApiMessage) (transfer full): The messages from the
- *          user.
- */
-GSList *
-fb_data_take_messages(FbData *fata, FbId uid);
-
-/**
- * fb_data_image_add:
- * @fata: The #FbData.
- * @url: The image URL.
- * @func: The #FbDataImageFunc.
- * @data: The user-defined data.
- * @dunc: The #GDestroyNotify for @data or #NULL.
- *
- * Adds a new #FbDataImage to the #FbData. This is used to fetch images
- * from HTTP sources. After calling this, #fb_data_image_queue() should
- * be called to queue the fetching process.
- *
- * Return: (transfer none): The #FbDataImage.
- */
-FbDataImage *
-fb_data_image_add(FbData *fata, const gchar *url, FbDataImageFunc func,
-                  gpointer data, GDestroyNotify dunc);
-
-/**
- * fb_data_image_get_active:
- * @img: The #FbDataImage.
- *
- * Gets the active fetching state from the #FbDataImage.
- *
- * Returns: #TRUE if the image is being fetched, otherwise #FALSE.
- */
-gboolean
-fb_data_image_get_active(FbDataImage *img);
-
-/**
- * fb_data_image_get_data:
- * @img: The #FbDataImage.
- *
- * Gets the user-defined data from the #FbDataImage.
- *
- * Returns: The user-defined data.
- */
-gpointer
-fb_data_image_get_data(FbDataImage *img);
-
-/**
- * fb_data_image_get_fata:
- * @img: The #FbDataImage.
- *
- * Gets the #FbData from the #FbDataImage.
- *
- * Returns: (transfer none): The #FbData.
- */
-FbData *
-fb_data_image_get_fata(FbDataImage *img);
-
-/**
- * fb_data_image_get_image:
- * @img: The #FbDataImage.
- * @size: The return location for the image size or #NULL.
- *
- * Gets the image data from the #FbDataImage.
- *
- * Returns: The image data.
- */
-const guint8 *
-fb_data_image_get_image(FbDataImage *img, gsize *size);
-
-/**
- * fb_data_image_dup_image:
- * @img: The #FbDataImage.
- * @size: The return location for the image size or #NULL.
- *
- * Gets the duplicated image data from the #FbDataImage. The returned
- * data should be freed with #g_free() when no longer needed.
- *
- * Returns: The duplicated image data.
- */
-guint8 *
-fb_data_image_dup_image(FbDataImage *img, gsize *size);
-
-/**
- * fb_data_image_get_url:
- * @img: The #FbDataImage.
- *
- * Gets the image URL from the #FbDataImage.
- *
- * Returns: The image URL.
- */
-const gchar *
-fb_data_image_get_url(FbDataImage *img);
-
-/**
- * fb_data_image_queue:
- * @fata: The #FbData.
- *
- * Queues the next #FbDataImage fetches.
- */
-void
-fb_data_image_queue(FbData *fata);
-
-#endif /* PURPLE_FACEBOOK_DATA_H */
diff --git a/libpurple/protocols/facebook/data.c b/libpurple/protocols/facebook/data.c
deleted file mode 100644
--- a/libpurple/protocols/facebook/data.c
+++ /dev/null
@@ -1,558 +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 <libsoup/soup.h>
-#include <string.h>
-
-#include <purple.h>
-#include "libpurple/glibcompat.h"
-
-#include "api.h"
-#include "data.h"
-
-/**
- * FbData:
- *
- * Represents the connection data used by #FacebookProtocol.
- */
-struct _FbData {
-	GObject parent;
-
-	FbApi *api;
-	SoupSession *cons;
-	PurpleConnection *gc;
-	PurpleRoomlist *roomlist;
-	GQueue *msgs;
-	GHashTable *imgs;
-	GHashTable *unread;
-	GHashTable *evs;
-};
-
-/**
- * FbDataImage:
- *
- * Represents the data used for fetching images.
- */
-struct _FbDataImage {
-	GObject parent;
-
-	FbData *fata;
-	gchar *url;
-	FbDataImageFunc func;
-	gpointer data;
-	GDestroyNotify dunc;
-
-	gboolean active;
-	const guint8 *image;
-	gsize size;
-};
-
-static const gchar *fb_props_strs[] = {
-	"cid",
-	"did",
-	"stoken",
-	"token"
-};
-
-G_DEFINE_TYPE(FbData, fb_data, G_TYPE_OBJECT);
-G_DEFINE_TYPE(FbDataImage, fb_data_image, G_TYPE_OBJECT);
-
-static void
-fb_data_dispose(GObject *obj)
-{
-	FbData *fata = FB_DATA(obj);
-
-	if(fata->cons != NULL) {
-		soup_session_abort(fata->cons);
-	}
-
-	if(fata->evs != NULL) {
-		GHashTableIter iter;
-		gpointer ptr = NULL;
-
-		g_hash_table_iter_init(&iter, fata->evs);
-		while (g_hash_table_iter_next(&iter, NULL, &ptr)) {
-			g_source_remove(GPOINTER_TO_UINT(ptr));
-		}
-	}
-
-	g_clear_object(&fata->api);
-
-	g_clear_object(&fata->cons);
-	if(fata->msgs != NULL) {
-		g_queue_free_full(fata->msgs, (GDestroyNotify)fb_api_message_free);
-		fata->msgs = NULL;
-	}
-
-	g_clear_pointer(&fata->imgs, g_hash_table_destroy);
-	g_clear_pointer(&fata->unread, g_hash_table_destroy);
-	g_clear_pointer(&fata->evs, g_hash_table_destroy);
-}
-
-static void
-fb_data_class_init(FbDataClass *klass)
-{
-	GObjectClass *gklass = G_OBJECT_CLASS(klass);
-
-	gklass->dispose = fb_data_dispose;
-}
-
-static void
-fb_data_init(FbData *fata)
-{
-	fata->msgs = g_queue_new();
-
-	fata->imgs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-	                                   g_object_unref, NULL);
-	fata->unread = g_hash_table_new_full(fb_id_hash, fb_id_equal,
-	                                     g_free, NULL);
-	fata->evs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-}
-
-static void
-fb_data_image_dispose(GObject *obj)
-{
-	FbDataImage *img = FB_DATA_IMAGE(obj);
-	FbData *fata = img->fata;
-
-	if (img->dunc != NULL && img->data != NULL) {
-		img->dunc(img->data);
-		img->dunc = NULL;
-	}
-
-	g_clear_pointer(&img->url, g_free);
-	g_hash_table_steal(fata->imgs, img);
-}
-
-static void
-fb_data_image_class_init(FbDataImageClass *klass)
-{
-	GObjectClass *gklass = G_OBJECT_CLASS(klass);
-
-	gklass->dispose = fb_data_image_dispose;
-}
-
-static void
-fb_data_image_init(G_GNUC_UNUSED FbDataImage *img)
-{
-}
-
-FbData *
-fb_data_new(PurpleConnection *gc, GProxyResolver *resolver)
-{
-	FbData *fata;
-
-	fata = g_object_new(FB_TYPE_DATA, NULL);
-
-	fata->cons = soup_session_new_with_options("proxy-resolver", resolver,
-	                                           NULL);
-	fata->api = fb_api_new(gc, resolver);
-	fata->gc = gc;
-
-	return fata;
-}
-
-gboolean
-fb_data_load(FbData *fata)
-{
-	const gchar *str;
-	FbId id;
-	gboolean ret = TRUE;
-	guint i;
-	guint64 uint;
-	GValue val = G_VALUE_INIT;
-	PurpleAccount *acct;
-
-	g_return_val_if_fail(FB_IS_DATA(fata), FALSE);
-	acct = purple_connection_get_account(fata->gc);
-
-	for (i = 0; i < G_N_ELEMENTS(fb_props_strs); i++) {
-		str = purple_account_get_string(acct, fb_props_strs[i], NULL);
-
-		if (str == NULL) {
-			ret = FALSE;
-		}
-
-		g_value_init(&val, G_TYPE_STRING);
-		g_value_set_string(&val, str);
-		g_object_set_property(G_OBJECT(fata->api), fb_props_strs[i],
-		                      &val);
-		g_value_unset(&val);
-	}
-
-	str = purple_account_get_string(acct, "mid", NULL);
-
-	if (str != NULL) {
-		uint = g_ascii_strtoull(str, NULL, 10);
-		g_value_init(&val, G_TYPE_UINT64);
-		g_value_set_uint64(&val, uint);
-		g_object_set_property(G_OBJECT(fata->api), "mid", &val);
-		g_value_unset(&val);
-	} else {
-		ret = FALSE;
-	}
-
-	str = purple_account_get_string(acct, "uid", NULL);
-
-	if (str != NULL) {
-		id = FB_ID_FROM_STR(str);
-		g_value_init(&val, FB_TYPE_ID);
-		g_value_set_int64(&val, id);
-		g_object_set_property(G_OBJECT(fata->api), "uid", &val);
-		g_value_unset(&val);
-	} else {
-		ret = FALSE;
-	}
-
-	fb_api_rehash(fata->api);
-	return ret;
-}
-
-void
-fb_data_save(FbData *fata)
-{
-	const gchar *str;
-	gchar *dup;
-	guint i;
-	guint64 uint;
-	GValue val = G_VALUE_INIT;
-	PurpleAccount *acct;
-
-	g_return_if_fail(FB_IS_DATA(fata));
-	acct = purple_connection_get_account(fata->gc);
-
-	for (i = 0; i < G_N_ELEMENTS(fb_props_strs); i++) {
-		g_value_init(&val, G_TYPE_STRING);
-		g_object_get_property(G_OBJECT(fata->api), fb_props_strs[i],
-		                      &val);
-		str = g_value_get_string(&val);
-
-		if (purple_strequal(fb_props_strs[i], "token") && !purple_account_get_remember_password(acct)) {
-			str = "";
-		}
-		purple_account_set_string(acct, fb_props_strs[i], str);
-		g_value_unset(&val);
-	}
-
-	g_value_init(&val, G_TYPE_UINT64);
-	g_object_get_property(G_OBJECT(fata->api), "mid", &val);
-	uint = g_value_get_uint64(&val);
-	g_value_unset(&val);
-
-	dup = g_strdup_printf("%" G_GINT64_FORMAT, uint);
-	purple_account_set_string(acct, "mid", dup);
-	g_free(dup);
-
-	g_value_init(&val, G_TYPE_INT64);
-	g_object_get_property(G_OBJECT(fata->api), "uid", &val);
-	uint = g_value_get_int64(&val);
-	g_value_unset(&val);
-
-	dup = g_strdup_printf("%" FB_ID_FORMAT, uint);
-	purple_account_set_string(acct, "uid", dup);
-	g_free(dup);
-}
-
-void
-fb_data_save_timeout(FbData *fata, const gchar *name, guint id)
-{
-	g_return_if_fail(FB_IS_DATA(fata));
-
-	fb_data_clear_timeout(fata, name, TRUE);
-
-	g_hash_table_replace(fata->evs, g_strdup(name), GUINT_TO_POINTER(id));
-}
-
-void
-fb_data_clear_timeout(FbData *fata, const gchar *name, gboolean remove)
-{
-	gpointer ptr;
-	guint id;
-
-	g_return_if_fail(FB_IS_DATA(fata));
-
-	ptr = g_hash_table_lookup(fata->evs, name);
-	id = GPOINTER_TO_UINT(ptr);
-
-	if(remove) {
-		g_clear_handle_id(&id, g_source_remove);
-	}
-
-	g_hash_table_remove(fata->evs, name);
-}
-
-FbApi *
-fb_data_get_api(FbData *fata)
-{
-
-	g_return_val_if_fail(FB_IS_DATA(fata), NULL);
-
-	return fata->api;
-}
-
-PurpleConnection *
-fb_data_get_connection(FbData *fata)
-{
-	g_return_val_if_fail(FB_IS_DATA(fata), NULL);
-
-	return fata->gc;
-}
-
-PurpleRoomlist *
-fb_data_get_roomlist(FbData *fata)
-{
-	g_return_val_if_fail(FB_IS_DATA(fata), NULL);
-
-	return fata->roomlist;
-}
-
-gboolean
-fb_data_get_unread(FbData *fata, FbId id)
-{
-	gpointer *ptr;
-
-	g_return_val_if_fail(FB_IS_DATA(fata), FALSE);
-	g_return_val_if_fail(id != 0, FALSE);
-
-	ptr = g_hash_table_lookup(fata->unread, &id);
-	return GPOINTER_TO_INT(ptr);
-}
-
-void
-fb_data_set_roomlist(FbData *fata, PurpleRoomlist *list)
-{
-	g_return_if_fail(FB_IS_DATA(fata));
-
-	fata->roomlist = list;
-}
-
-void
-fb_data_set_unread(FbData *fata, FbId id, gboolean unread)
-{
-	gpointer key;
-
-	g_return_if_fail(FB_IS_DATA(fata));
-	g_return_if_fail(id != 0);
-
-	if (!unread) {
-		g_hash_table_remove(fata->unread, &id);
-		return;
-	}
-
-	key = g_memdup2(&id, sizeof id);
-	g_hash_table_replace(fata->unread, key, GINT_TO_POINTER(unread));
-}
-
-void
-fb_data_add_message(FbData *fata, FbApiMessage *msg)
-{
-	g_return_if_fail(FB_IS_DATA(fata));
-
-	g_queue_push_tail(fata->msgs, msg);
-}
-
-void
-fb_data_remove_message(FbData *fata, FbApiMessage *msg)
-{
-	g_return_if_fail(FB_IS_DATA(fata));
-
-	g_queue_remove(fata->msgs, msg);
-}
-
-GSList *
-fb_data_take_messages(FbData *fata, FbId uid)
-{
-	FbApiMessage *msg;
-	GList *l;
-	GList *prev;
-	GSList *msgs = NULL;
-
-	g_return_val_if_fail(FB_IS_DATA(fata), NULL);
-	l = fata->msgs->tail;
-
-	while (l != NULL) {
-		msg = l->data;
-		prev = l->prev;
-
-		if (msg->uid == uid) {
-			msgs = g_slist_prepend(msgs, msg);
-			g_queue_delete_link(fata->msgs, l);
-		}
-
-		l = prev;
-	}
-
-	return msgs;
-}
-
-FbDataImage *
-fb_data_image_add(FbData *fata, const gchar *url, FbDataImageFunc func,
-                  gpointer data, GDestroyNotify dunc)
-{
-	FbDataImage *img;
-
-	g_return_val_if_fail(FB_IS_DATA(fata), NULL);
-	g_return_val_if_fail(url != NULL, NULL);
-	g_return_val_if_fail(func != NULL, NULL);
-
-	img = g_object_new(FB_TYPE_DATA_IMAGE, NULL);
-
-	img->fata = fata;
-	img->url = g_strdup(url);
-	img->func = func;
-	img->data = data;
-	img->dunc = dunc;
-
-	g_hash_table_add(fata->imgs, img);
-	return img;
-}
-
-gboolean
-fb_data_image_get_active(FbDataImage *img)
-{
-	g_return_val_if_fail(FB_IS_DATA_IMAGE(img), FALSE);
-
-	return img->active;
-}
-
-gpointer
-fb_data_image_get_data(FbDataImage *img)
-{
-	g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
-
-	return img->data;
-}
-
-FbData *
-fb_data_image_get_fata(FbDataImage *img)
-{
-	g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
-
-	return img->fata;
-}
-
-const guint8 *
-fb_data_image_get_image(FbDataImage *img, gsize *size)
-{
-	g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
-
-	if (size != NULL) {
-		*size = img->size;
-	}
-
-	return img->image;
-}
-
-guint8 *
-fb_data_image_dup_image(FbDataImage *img, gsize *size)
-{
-	g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
-
-	if (size != NULL) {
-		*size = img->size;
-	}
-
-	if (img->size < 1) {
-		return NULL;
-	}
-
-	return g_memdup2(img->image, img->size);
-}
-
-const gchar *
-fb_data_image_get_url(FbDataImage *img)
-{
-	g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
-
-	return img->url;
-}
-
-static void
-fb_data_image_cb(GObject *source, GAsyncResult *result, gpointer data) {
-	SoupMessage *msg = data;
-	FbDataImage *img = g_object_get_data(G_OBJECT(msg), "facebook-data-image");
-	GError *err = NULL;
-
-	if(fb_http_error_chk(msg, &err)) {
-		GBytes *bytes = NULL;
-
-		bytes = soup_session_send_and_read_finish(SOUP_SESSION(source),
-		                                          result, &err);
-		if(bytes != NULL) {
-			img->image = g_bytes_unref_to_data(bytes, &img->size);
-		}
-	}
-
-	img->func(img, err);
-
-	if (G_LIKELY(err == NULL)) {
-		fb_data_image_queue(img->fata);
-	} else {
-		g_error_free(err);
-	}
-
-	g_object_unref(img);
-	g_object_unref(msg);
-}
-
-void
-fb_data_image_queue(FbData *fata)
-{
-	const gchar *url;
-	FbDataImage *img;
-	GHashTableIter iter;
-	guint active = 0;
-
-	g_return_if_fail(FB_IS_DATA(fata));
-
-	g_hash_table_iter_init(&iter, fata->imgs);
-	while (g_hash_table_iter_next(&iter, (gpointer *) &img, NULL)) {
-		if (fb_data_image_get_active(img)) {
-			active++;
-		}
-	}
-
-	if (active >= FB_DATA_ICON_MAX) {
-		return;
-	}
-
-	g_hash_table_iter_init(&iter, fata->imgs);
-	while (g_hash_table_iter_next(&iter, (gpointer *) &img, NULL)) {
-		SoupMessage *msg;
-
-		if (fb_data_image_get_active(img)) {
-			continue;
-		}
-
-		img->active = TRUE;
-		url = fb_data_image_get_url(img);
-
-		msg = soup_message_new("GET", url);
-		g_object_set_data(G_OBJECT(msg), "facebook-data-image", img);
-		// purple_http_request_set_max_len(req, FB_DATA_ICON_SIZE_MAX);
-		soup_session_send_and_read_async(fata->cons, msg, G_PRIORITY_DEFAULT,
-		                                 NULL, fb_data_image_cb, msg);
-
-		if (++active >= FB_DATA_ICON_MAX) {
-			break;
-		}
-	}
-}
diff --git a/libpurple/protocols/facebook/facebook.h b/libpurple/protocols/facebook/facebook.h
deleted file mode 100644
--- a/libpurple/protocols/facebook/facebook.h
+++ /dev/null
@@ -1,51 +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
- */
-
-#ifndef PURPLE_FACEBOOK_FACEBOOK_H
-#define PURPLE_FACEBOOK_FACEBOOK_H
-
-#include <glib.h>
-#include <gmodule.h>
-
-#define FACEBOOK_TYPE_PROTOCOL (facebook_protocol_get_type())
-G_DECLARE_FINAL_TYPE(FacebookProtocol, facebook_protocol, FACEBOOK, PROTOCOL,
-                     PurpleProtocol)
-
-/**
- * FB_PROTOCOL_ID:
- *
- * The Facebook protocol identifier.
- */
-#define FB_PROTOCOL_ID  "prpl-facebook"
-
-/**
- * FacebookProtocol:
- *
- * Represents the Facebook #PurpleProtocol.
- */
-
-/**
- * FacebookProtocolClass:
- *
- * The base class for all #FacebookProtocol's.
- */
-
-#endif /* PURPLE_FACEBOOK_FACEBOOK_H */
diff --git a/libpurple/protocols/facebook/facebook.c b/libpurple/protocols/facebook/facebook.c
deleted file mode 100644
--- a/libpurple/protocols/facebook/facebook.c
+++ /dev/null
@@ -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)
diff --git a/libpurple/protocols/facebook/http.h b/libpurple/protocols/facebook/http.h
deleted file mode 100644
--- a/libpurple/protocols/facebook/http.h
+++ /dev/null
@@ -1,266 +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
- */
-
-#ifndef PURPLE_FACEBOOK_HTTP_H
-#define PURPLE_FACEBOOK_HTTP_H
-
-#include <glib.h>
-#include <libsoup/soup.h>
-
-/**
- * FB_HTTP_ERROR:
- *
- * The #GQuark of the domain of HTTP errors.
- */
-#define FB_HTTP_ERROR  fb_http_error_quark()
-
-/**
- * FbHttpParams:
- *
- * Represents a set of key/value HTTP parameters.
- */
-typedef GHashTable FbHttpParams;
-
-/**
- * FbHttpError:
- * @FB_HTTP_ERROR_SUCCESS: There is no error.
- * @FB_HTTP_ERROR_NOMATCH: The name does not match anything.
- *
- * The error codes for the #FB_HTTP_ERROR domain.
- */
-typedef enum
-{
-	FB_HTTP_ERROR_SUCCESS = 0,
-	FB_HTTP_ERROR_NOMATCH
-} FbHttpError;
-
-/**
- * fb_http_error_quark:
- *
- * Gets the #GQuark of the domain of HTTP errors.
- *
- * Returns: The #GQuark of the domain.
- */
-GQuark
-fb_http_error_quark(void);
-
-/**
- * fb_http_error_chk:
- * @res: The #SoupMessage.
- * @error: The return location for the #GError or #NULL.
- *
- * Checks a #SoupMessage for success. This optionally assigns an
- * appropriate #GError upon failure.
- *
- * Returns: #TRUE if the request was successful, otherwise #FALSE.
- */
-gboolean fb_http_error_chk(SoupMessage *res, GError **error);
-
-/**
- * fb_http_params_new:
- *
- * Creates a new #FbHttpParams. The returned #FbHttpParams should be
- * freed with #fb_http_params_free() when no longer needed. Optionally,
- * instead of freeing, the returned #FbHttpParams can be closed with
- * #fb_http_params_close().
- *
- * Returns: (transfer full): The new #FbHttpParams.
- */
-FbHttpParams *
-fb_http_params_new(void);
-
-/**
- * fb_http_params_new_parse:
- * @data: The string containing HTTP parameters.
- * @isurl: #TRUE if @data is a URL, otherwise #FALSE.
- *
- * Creates a new #FbHttpParams. This parses the #FbHttpParams from a
- * string, which can be a URL. The returned #FbHttpParams should be
- * freed with #fb_http_params_free() when no longer needed. Optionally,
- * instead of freeing, the returned #FbHttpParams can be closed with
- * #fb_http_params_close().
- *
- * Returns: (transfer full): The new #FbHttpParams.
- */
-FbHttpParams *
-fb_http_params_new_parse(const gchar *data, gboolean isurl);
-
-/**
- * fb_http_params_free:
- * @params: The #FbHttpParams.
- *
- * Frees all memory used by the #FbHttpParams.
- */
-void
-fb_http_params_free(FbHttpParams *params);
-
-/**
- * fb_http_params_get_bool:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets a boolean value from the #FbHttpParams. This optionally assigns
- * an appropriate #GError upon failure.
- *
- * Return: The boolean value.
- */
-gboolean
-fb_http_params_get_bool(FbHttpParams *params, const gchar *name,
-                        GError **error);
-
-/**
- * fb_http_params_get_dbl:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets a floating point value from the #FbHttpParams. This optionally
- * assigns an appropriate #GError upon failure.
- *
- * Return: The floating point value.
- */
-gdouble
-fb_http_params_get_dbl(FbHttpParams *params, const gchar *name,
-                       GError **error);
-
-/**
- * fb_http_params_get_int:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets an integer value from the #FbHttpParams. This optionally
- * assigns an appropriate #GError upon failure.
- *
- * Return: The integer value.
- */
-gint64
-fb_http_params_get_int(FbHttpParams *params, const gchar *name,
-                       GError **error);
-
-/**
- * fb_http_params_get_str:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets a string value from the #FbHttpParams. This optionally assigns
- * an appropriate #GError upon failure.
- *
- * Return: The string value.
- */
-const gchar *
-fb_http_params_get_str(FbHttpParams *params, const gchar *name,
-                       GError **error);
-
-/**
- * fb_http_params_dup_str:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets a duplicated string value from the #FbHttpParams. This
- * optionally assigns an appropriate #GError upon failure. The returned
- * string should be freed with #g_free() when no longer needed.
- *
- * Return: The duplicated string value.
- */
-gchar *
-fb_http_params_dup_str(FbHttpParams *params, const gchar *name,
-                       GError **error);
-
-/**
- * fb_http_params_set_bool:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @value: The value.
- *
- * Sets a boolean value to the #FbHttpParams.
- */
-void
-fb_http_params_set_bool(FbHttpParams *params, const gchar *name,
-		        gboolean value);
-
-/**
- * fb_http_params_set_dbl:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @value: The value.
- *
- * Sets a floating point value to the #FbHttpParams.
- */
-void
-fb_http_params_set_dbl(FbHttpParams *params, const gchar *name, gdouble value);
-
-/**
- * fb_http_params_set_int:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @value: The value.
- *
- * Sets an integer value to the #FbHttpParams.
- */
-void
-fb_http_params_set_int(FbHttpParams *params, const gchar *name, gint64 value);
-
-/**
- * fb_http_params_set_str:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @value: The value.
- *
- * Sets a string value to the #FbHttpParams.
- */
-void
-fb_http_params_set_str(FbHttpParams *params, const gchar *name,
-                       const gchar *value);
-
-/**
- * fb_http_params_set_strf:
- * @params: The #FbHttpParams.
- * @name: The parameter name.
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Sets a formatted string value to the #FbHttpParams.
- */
-void
-fb_http_params_set_strf(FbHttpParams *params, const gchar *name,
-                        const gchar *format, ...)
-                        G_GNUC_PRINTF(3, 4);
-
-/**
- * fb_http_urlcmp:
- * @url1: The first URL.
- * @url2: The second URL.
- * @protocol: #TRUE to match the protocols, otherwise #FALSE.
- *
- * Compares two URLs. This is more reliable than just comparing two URL
- * strings, as it avoids casing in some areas, while not in others. It
- * can also, optionally, ignore the matching of the URL protocol.
- *
- * Returns: #TRUE if the URLs match, otherwise #FALSE.
- */
-gboolean
-fb_http_urlcmp(const gchar *url1, const gchar *url2, gboolean protocol);
-
-#endif /* PURPLE_FACEBOOK_HTTP_H */
diff --git a/libpurple/protocols/facebook/http.c b/libpurple/protocols/facebook/http.c
deleted file mode 100644
--- a/libpurple/protocols/facebook/http.c
+++ /dev/null
@@ -1,282 +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 <string.h>
-
-#include "http.h"
-
-GQuark
-fb_http_error_quark(void)
-{
-	static GQuark q = 0;
-
-	if (G_UNLIKELY(q == 0)) {
-		q = g_quark_from_static_string("fb-http-error-quark");
-	}
-
-	return q;
-}
-
-gboolean
-fb_http_error_chk(SoupMessage *res, GError **error)
-{
-	SoupStatus status_code = soup_message_get_status(res);
-
-	if (SOUP_STATUS_IS_SUCCESSFUL(status_code)) {
-		return TRUE;
-	}
-
-	g_set_error(error, FB_HTTP_ERROR, status_code, "%s",
-	            soup_message_get_reason_phrase(res));
-	return FALSE;
-}
-
-FbHttpParams *
-fb_http_params_new(void)
-{
-        return g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-}
-
-FbHttpParams *
-fb_http_params_new_parse(const gchar *data, gboolean isurl)
-{
-	gchar *query = NULL;
-	FbHttpParams *params;
-
-	if (data == NULL) {
-		return fb_http_params_new();
-	}
-
-	if (isurl) {
-		if (!g_uri_split(data, G_URI_FLAGS_ENCODED_QUERY, NULL, NULL, NULL,
-		                 NULL, NULL, &query, NULL, NULL))
-		{
-			return fb_http_params_new();
-		}
-
-		data = query;
-	}
-
-	params = soup_form_decode(data);
-
-	g_free(query);
-
-	return params;
-}
-
-void
-fb_http_params_free(FbHttpParams *params)
-{
-	g_hash_table_destroy(params);
-}
-
-static const gchar *
-fb_http_params_get(FbHttpParams *params, const gchar *name, GError **error)
-{
-	const gchar *ret;
-
-	ret = g_hash_table_lookup(params, name);
-
-	if (ret == NULL) {
-		g_set_error(error, FB_HTTP_ERROR, FB_HTTP_ERROR_NOMATCH,
-		            _("No matches for %s"), name);
-		return NULL;
-	}
-
-	return ret;
-}
-
-gboolean
-fb_http_params_get_bool(FbHttpParams *params, const gchar *name,
-                        GError **error)
-{
-	const gchar *val;
-
-	val = fb_http_params_get(params, name, error);
-
-	if (val == NULL) {
-		return FALSE;
-	}
-
-	return g_ascii_strcasecmp(val, "TRUE") == 0;
-}
-
-gdouble
-fb_http_params_get_dbl(FbHttpParams *params, const gchar *name,
-                       GError **error)
-{
-	const gchar *val;
-
-	val = fb_http_params_get(params, name, error);
-
-	if (val == NULL) {
-		return 0.0;
-	}
-
-	return g_ascii_strtod(val, NULL);
-}
-
-gint64
-fb_http_params_get_int(FbHttpParams *params, const gchar *name,
-                       GError **error)
-{
-	const gchar *val;
-
-	val = fb_http_params_get(params, name, error);
-
-	if (val == NULL) {
-		return 0;
-	}
-
-	return g_ascii_strtoll(val, NULL, 10);
-}
-
-const gchar *
-fb_http_params_get_str(FbHttpParams *params, const gchar *name,
-                       GError **error)
-{
-	return fb_http_params_get(params, name, error);
-}
-
-gchar *
-fb_http_params_dup_str(FbHttpParams *params, const gchar *name,
-                       GError **error)
-{
-	const gchar *str;
-
-	str = fb_http_params_get(params, name, error);
-	return g_strdup(str);
-}
-
-static void
-fb_http_params_set(FbHttpParams *params, const gchar *name, gchar *value)
-{
-	gchar *key;
-
-	key = g_strdup(name);
-	g_hash_table_replace(params, key, value);
-}
-
-void
-fb_http_params_set_bool(FbHttpParams *params, const gchar *name,
-                        gboolean value)
-{
-	gchar *val;
-
-	val = g_strdup(value ? "true" : "false");
-	fb_http_params_set(params, name, val);
-}
-
-void
-fb_http_params_set_dbl(FbHttpParams *params, const gchar *name, gdouble value)
-{
-	gchar *val;
-
-	val = g_strdup_printf("%f", value);
-	fb_http_params_set(params, name, val);
-}
-
-void
-fb_http_params_set_int(FbHttpParams *params, const gchar *name, gint64 value)
-{
-	gchar *val;
-
-	val = g_strdup_printf("%" G_GINT64_FORMAT, value);
-	fb_http_params_set(params, name, val);
-}
-
-void
-fb_http_params_set_str(FbHttpParams *params, const gchar *name,
-                       const gchar *value)
-{
-	gchar *val;
-
-	val = g_strdup(value);
-	fb_http_params_set(params, name, val);
-}
-
-void
-fb_http_params_set_strf(FbHttpParams *params, const gchar *name,
-                        const gchar *format, ...)
-{
-	gchar *val;
-	va_list ap;
-
-	va_start(ap, format);
-	val = g_strdup_vprintf(format, ap);
-	va_end(ap);
-
-	fb_http_params_set(params, name, val);
-}
-
-gboolean
-fb_http_urlcmp(const gchar *url1, const gchar *url2, gboolean protocol)
-{
-	gboolean ret = TRUE;
-	GUri *uri1, *uri2;
-
-	if ((url1 == NULL) || (url2 == NULL)) {
-		return url1 == url2;
-	}
-
-	if (strstr(url1, url2) != NULL || strstr(url2, url1) != NULL) {
-		return TRUE;
-	}
-
-	uri1 = g_uri_parse(url1, SOUP_HTTP_URI_FLAGS, NULL);
-	if (uri1 == NULL) {
-		return g_ascii_strcasecmp(url1, url2) == 0;
-	}
-
-	uri2 = g_uri_parse(url2, SOUP_HTTP_URI_FLAGS, NULL);
-	if (uri2 == NULL) {
-		g_uri_unref(uri1);
-		return g_ascii_strcasecmp(url1, url2) == 0;
-	}
-
-	if (!protocol) {
-		/* Force the same scheme (and same port). */
-		GUri *tmp = NULL;
-
-		tmp = soup_uri_copy(uri1,
-		                    SOUP_URI_SCHEME, "https",
-		                    SOUP_URI_PORT, 443,
-		                    SOUP_URI_NONE);
-		g_uri_unref(uri1);
-		uri1 = tmp;
-
-		tmp = soup_uri_copy(uri2,
-		                    SOUP_URI_SCHEME, "https",
-		                    SOUP_URI_PORT, 443,
-		                    SOUP_URI_NONE);
-		g_uri_unref(uri2);
-		uri2 = tmp;
-	}
-
-	ret = soup_uri_equal(uri1, uri2);
-
-	g_uri_unref(uri1);
-	g_uri_unref(uri2);
-
-	return ret;
-}
diff --git a/libpurple/protocols/facebook/id.h b/libpurple/protocols/facebook/id.h
deleted file mode 100644
--- a/libpurple/protocols/facebook/id.h
+++ /dev/null
@@ -1,122 +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
- */
-
-#ifndef PURPLE_FACEBOOK_ID_H
-#define PURPLE_FACEBOOK_ID_H
-
-#include <glib.h>
-#include <glib/gprintf.h>
-
-#include "util.h"
-
-/**
- * FB_ID_FORMAT:
- *
- * The format specifier for printing and scanning an #FbId.
- */
-#define FB_ID_FORMAT  G_GINT64_FORMAT
-
-/**
- * FB_ID_MODIFIER:
- *
- * The length modifier for printing an #FbId.
- */
-#define FB_ID_MODIFIER  G_GINT64_MODIFIER
-
-/**
- * FB_ID_STRMAX:
- *
- * The maximum length, including a null-terminating character, of the
- * string representation of an #FbId.
- */
-#define FB_ID_STRMAX  21
-
-/**
- * FB_TYPE_ID:
- *
- * The #GType of an #FbId.
- */
-#define FB_TYPE_ID  G_TYPE_INT64
-
-/**
- * FB_ID_CONSTANT:
- * @v: The value.
- *
- * Inserts a literal #FbId into source code.
- *
- * Return: The literal #FbId value.
- */
-#define FB_ID_CONSTANT(v)  G_GINT64_CONSTANT(v)
-
-/**
- * FB_ID_FROM_STR:
- * @s: The string value.
- *
- * Converts a string to an #FbId.
- *
- * Return: The converted #FbId value.
- */
-#define FB_ID_FROM_STR(s)  g_ascii_strtoll(s, NULL, 10)
-
-/**
- * FB_ID_IS_STR:
- * @s: The string value.
- *
- * Determines if a string is an #FbId.
- *
- * Return: #TRUE if the string is an #FbId, otherwise #FALSE.
- */
-#define FB_ID_IS_STR(s)  fb_util_strtest(s, G_ASCII_DIGIT)
-
-/**
- * FB_ID_TO_STR:
- * @i: The #FbId.
- * @s: The string buffer.
- *
- * Converts an #FbId to a string. The buffer should be at least the
- * size of #FB_ID_STRMAX.
- *
- * Return: The converted string value.
- */
-#define FB_ID_TO_STR(i, s)  g_sprintf(s, "%" FB_ID_FORMAT, (FbId) i)
-
-/**
- * fb_id_equal:
- *
- * Compares the values of two #FbId's for equality. See #g_int64_equal.
- */
-#define fb_id_equal  g_int64_equal
-
-/**
- * fb_id_hash:
- *
- * Converts a pointer to a #FbId hash value. See #g_int64_hash.
- */
-#define fb_id_hash  g_int64_hash
-
-/**
- * FbId:
- *
- * Represents a numeric Facebook identifier.
- */
-typedef gint64 FbId;
-
-#endif /* PURPLE_FACEBOOK_ID_H */
diff --git a/libpurple/protocols/facebook/json.h b/libpurple/protocols/facebook/json.h
deleted file mode 100644
--- a/libpurple/protocols/facebook/json.h
+++ /dev/null
@@ -1,471 +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
- */
-
-#ifndef PURPLE_FACEBOOK_JSON_H
-#define PURPLE_FACEBOOK_JSON_H
-
-#include <glib.h>
-#include <json-glib/json-glib.h>
-
-#define FB_TYPE_JSON_VALUES  fb_json_values_get_type()
-
-/**
- * FB_JSON_ERROR:
- *
- * The #GQuark of the domain of JSON errors.
- */
-#define FB_JSON_ERROR  fb_json_error_quark()
-
-/**
- * FbJsonError:
- * @FB_JSON_ERROR_SUCCESS: There is no error.
- * @FB_JSON_ERROR_AMBIGUOUS: The node has ambiguous matches.
- * @FB_JSON_ERROR_GENERAL: General failure.
- * @FB_JSON_ERROR_NOMATCH: The node does not match anything.
- * @FB_JSON_ERROR_NULL: The node is of type NULL.
- * @FB_JSON_ERROR_TYPE: The node has an unexpected type.
- *
- * The error codes for the #FB_JSON_ERROR domain.
- */
-typedef enum
-{
-	FB_JSON_ERROR_SUCCESS = 0,
-	FB_JSON_ERROR_AMBIGUOUS,
-	FB_JSON_ERROR_GENERAL,
-	FB_JSON_ERROR_NOMATCH,
-	FB_JSON_ERROR_NULL,
-	FB_JSON_ERROR_TYPE
-} FbJsonError;
-
-/**
- * FbJsonType:
- * @FB_JSON_TYPE_NULL: An unknown value.
- * @FB_JSON_TYPE_BOOL: A boolean (#TRUE or #FALSE).
- * @FB_JSON_TYPE_DBL: A floating point number.
- * @FB_JSON_TYPE_INT: A signed integer.
- * @FB_JSON_TYPE_STR: A string.
- *
- * The JSON data types.
- */
-typedef enum
-{
-	FB_JSON_TYPE_NULL = 0,
-	FB_JSON_TYPE_BOOL = G_TYPE_BOOLEAN,
-	FB_JSON_TYPE_DBL = G_TYPE_DOUBLE,
-	FB_JSON_TYPE_INT = G_TYPE_INT64,
-	FB_JSON_TYPE_STR = G_TYPE_STRING
-} FbJsonType;
-
-G_DECLARE_FINAL_TYPE(FbJsonValues, fb_json_values, FB, JSON_VALUES,
-		GObject)
-
-/**
- * fb_json_error_quark:
- *
- * Gets the #GQuark of the domain of JSON errors.
- *
- * Returns: The #GQuark of the domain.
- */
-GQuark
-fb_json_error_quark(void);
-
-/**
- * fb_json_bldr_new:
- * @type: The starting #JsonNodeType.
- *
- * Creates a new #JsonBuilder. The starting #JsonNodeType is likely to
- * be #JSON_NODE_OBJECT. The returned #JsonBuilder should be freed with
- * #g_object_unref() when no longer needed. Optionally, instead of
- * freeing, the returned #JsonBuilder can be closed with
- * #fb_json_bldr_close().
- *
- * Returns: (transfer full): The new #JsonBuilder.
- */
-JsonBuilder *
-fb_json_bldr_new(JsonNodeType type);
-
-/**
- * fb_json_bldr_close:
- * @bldr: The #JsonBuilder.
- * @type: The ending #JsonNodeType.
- * @size: The return local for the size of the returned string.
- *
- * Closes the #JsonBuilder by returning a string representing the
- * #JsonBuilder. The ending #JsonNodeType is likely to be
- * #JSON_NODE_OBJECT. This calls #g_object_unref(). The returned
- * string should be freed with #g_free() when no longer needed.
- *
- * Returns: The string representation of the #JsonBuilder.
- */
-gchar *
-fb_json_bldr_close(JsonBuilder *bldr, JsonNodeType type, gsize *size);
-
-/**
- * fb_json_bldr_arr_begin:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- *
- * Begins an array member in the #JsonBuilder.
- */
-void
-fb_json_bldr_arr_begin(JsonBuilder *bldr, const gchar *name);
-
-/**
- * fb_json_bldr_arr_end:
- * @bldr: The #JsonBuilder.
- *
- * Ends an array member in the #JsonBuilder.
- */
-void
-fb_json_bldr_arr_end(JsonBuilder *bldr);
-
-/**
- * fb_json_bldr_obj_begin:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- *
- * Begins an object member in the #JsonBuilder.
- */
-void
-fb_json_bldr_obj_begin(JsonBuilder *bldr, const gchar *name);
-
-/**
- * fb_json_bldr_obj_end:
- * @bldr: The #JsonBuilder.
- *
- * Ends an array member in the #JsonBuilder.
- */
-void
-fb_json_bldr_obj_end(JsonBuilder *bldr);
-
-/**
- * fb_json_bldr_add_bool:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * @value: The value.
- *
- * Adds a boolean member to the #JsonBuilder.
- */
-void
-fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value);
-
-/**
- * fb_json_bldr_add_dbl:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * @value: The value.
- *
- * Adds a floating point member to the #JsonBuilder.
- */
-void
-fb_json_bldr_add_dbl(JsonBuilder *bldr, const gchar *name, gdouble value);
-
-/**
- * fb_json_bldr_add_int:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * @value: The value.
- *
- * Adds an integer member to the #JsonBuilder.
- */
-void
-fb_json_bldr_add_int(JsonBuilder *bldr, const gchar *name, gint64 value);
-
-/**
- * fb_json_bldr_add_str:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * @value: The value.
- *
- * Adds a string member to the #JsonBuilder.
- */
-void
-fb_json_bldr_add_str(JsonBuilder *bldr, const gchar *name, const gchar *value);
-
-/**
- * fb_json_bldr_add_strf:
- * @bldr: The #JsonBuilder.
- * @name: The member name or #NULL.
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Adds a formatted string member to the #JsonBuilder.
- */
-void
-fb_json_bldr_add_strf(JsonBuilder *bldr, const gchar *name,
-                      const gchar *format, ...)
-                      G_GNUC_PRINTF(3, 4);
-
-/**
- * fb_json_node_new:
- * @data: The string JSON.
- * @size: The size of @json or -1 if null-terminated.
- * @error: The return location for the #GError or #NULL.
- *
- * Creates a new #JsonNode. The returned #JsonBuilder should be freed
- * wuth #json_node_free() when no longer needed.
- *
- * Returns: The new #JsonNode.
- */
-JsonNode *
-fb_json_node_new(const gchar *data, gssize size, GError **error);
-
-/**
- * fb_json_node_get:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets a new #JsonNode value from a parent #JsonNode with a #JsonPath
- * expression. The returned #JsonNode should be freed with
- * #json_node_free() when no longer needed.
- *
- * Returns: The new #JsonNode.
- */
-JsonNode *
-fb_json_node_get(JsonNode *root, const gchar *expr, GError **error);
-
-/**
- * fb_json_node_get_nth:
- * @root: The root #JsonNode.
- * @n: The index number.
- *
- * Gets a #JsonNode value from a parent #JsonNode by index. The
- * returned #JsonNode should not be freed.
- *
- * Return: The #JsonNode.
- */
-JsonNode *
-fb_json_node_get_nth(JsonNode *root, guint n);
-
-/**
- * fb_json_node_get_arr:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets a new #JsonArray value from a parent #JsonNode with a #JsonPath
- * expression. The returned #JsonArray should be freed with
- * #json_array_unref() when no longer needed.
- *
- * Returns: The new #JsonArray.
- */
-JsonArray *
-fb_json_node_get_arr(JsonNode *root, const gchar *expr, GError **error);
-
-/**
- * fb_json_node_get_bool:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets a boolean value from a parent #JsonNode with a #JsonPath
- * expression.
- *
- * Returns: The boolean value.
- */
-gboolean
-fb_json_node_get_bool(JsonNode *root, const gchar *expr, GError **error);
-
-/**
- * fb_json_node_get_dbl:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets a floating point value from a parent #JsonNode with a #JsonPath
- * expression.
- *
- * Returns: The floating point value.
- */
-gdouble
-fb_json_node_get_dbl(JsonNode *root, const gchar *expr, GError **error);
-
-/**
- * fb_json_node_get_int:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets an integer value from a parent #JsonNode with a #JsonPath
- * expression.
- *
- * Returns: The integer value.
- */
-gint64
-fb_json_node_get_int(JsonNode *root, const gchar *expr, GError **error);
-
-/**
- * fb_json_node_get_str:
- * @root: The root #JsonNode.
- * @expr: The #JsonPath expression.
- * @error: The return location for the #GError or #NULL.
- *
- * Gets an string value from a parent #JsonNode with a #JsonPath
- * expression. The returned string should be freed with #g_free()
- * when no longer needed.
- *
- * Returns: The string value.
- */
-gchar *
-fb_json_node_get_str(JsonNode *root, const gchar *expr, GError **error);
-
-/**
- * fb_json_values_new:
- * @root: The root #JsonNode.
- *
- * Creates a new #FbJsonValues. The returned #FbJsonValues should be
- * freed with #g_object_unref when no longer needed.
- *
- * Returns: The new #FbJsonValues.
- */
-FbJsonValues *
-fb_json_values_new(JsonNode *root);
-
-/**
- * fb_json_values_add:
- * @values: The #FbJsonValues.
- * @type: The #FbJsonType.
- * @required: #TRUE if the node is required, otherwise #FALSE.
- * @expr: The #JsonPath expression.
- *
- * Adds a new #FbJsonValue to the #FbJsonValues.
- */
-void
-fb_json_values_add(FbJsonValues *values, FbJsonType type, gboolean required,
-                   const gchar *expr);
-
-/**
- * fb_json_values_get_root:
- * @values: The #FbJsonValues.
- *
- * Gets the current working root #JsonNode. This is either the current
- * array #JsonNode or the root #JsonNode. The returned #JsonNode should
- * not be freed.
- */
-JsonNode *
-fb_json_values_get_root(FbJsonValues *values);
-
-/**
- * fb_json_values_set_array:
- * @values: The #FbJsonValues.
- * @required: #TRUE if the node is required, otherwise #FALSE.
- * @expr: The #JsonPath expression.
- *
- * Sets the #JsonPath for an array to base all #FbJsonValue's off.
- */
-void
-fb_json_values_set_array(FbJsonValues *values, gboolean required,
-                         const gchar *expr);
-
-/**
- * fb_json_values_update:
- * @values: The #FbJsonValues.
- * @error: The return location for the #GError or #NULL.
- *
- * Updates the current working root. This should be called after all of
- * the #FbJsonValue's have been added with #fb_json_values_add(). If an
- * array was set with #fb_json_values_set_array(), then this should be
- * called in a while loop, until #FALSE is returned.
- *
- * Returns: #TRUE if the values were updated, otherwise #FALSE.
- */
-gboolean
-fb_json_values_update(FbJsonValues *values, GError **error);
-
-/**
- * fb_json_values_next:
- * @values: The #FbJsonValues.
- *
- * Gets the next #GValue from the #FbJsonValues. Before calling this
- * function, #fb_json_values_update() must be called.
- *
- * Returns: The #GValue.
- */
-const GValue *
-fb_json_values_next(FbJsonValues *values);
-
-/**
- * fb_json_values_next_bool:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- *
- * Gets the next boolean value from the #FbJsonValues. Before calling
- * this function, #fb_json_values_update() must be called.
- *
- * Returns: The boolean value.
- */
-gboolean
-fb_json_values_next_bool(FbJsonValues *values, gboolean defval);
-
-/**
- * fb_json_values_next_dbl:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- *
- * Gets the next floating point value from the #FbJsonValues. Before
- * calling this function, #fb_json_values_update() must be called.
- *
- * Returns: The floating point value.
- */
-gdouble
-fb_json_values_next_dbl(FbJsonValues *values, gdouble defval);
-
-/**
- * fb_json_values_next_int:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- *
- * Gets the next integer value from the #FbJsonValues. Before calling
- * this function, #fb_json_values_update() must be called.
- *
- * Returns: The integer value.
- */
-gint64
-fb_json_values_next_int(FbJsonValues *values, gint64 defval);
-
-/**
- * fb_json_values_next_str:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- *
- * Gets the next string value from the #FbJsonValues. Before calling
- * this function, #fb_json_values_update() must be called.
- *
- * Returns: The string value.
- */
-const gchar *
-fb_json_values_next_str(FbJsonValues *values, const gchar *defval);
-
-/**
- * fb_json_values_next_str_dup:
- * @values: The #FbJsonValues.
- * @defval: The default value.
- *
- * Gets the next duplicate string value from the #FbJsonValues. Before
- * calling this function, #fb_json_values_update() must be called.
- *
- * Returns: The duplicate string value.
- */
-gchar *
-fb_json_values_next_str_dup(FbJsonValues *values, const gchar *defval);
-
-#endif /* PURPLE_FACEBOOK_JSON_H */
diff --git a/libpurple/protocols/facebook/json.c b/libpurple/protocols/facebook/json.c
deleted file mode 100644
--- a/libpurple/protocols/facebook/json.c
+++ /dev/null
@@ -1,658 +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 <stdarg.h>
-#include <string.h>
-
-#include "json.h"
-#include "util.h"
-
-typedef struct _FbJsonValue FbJsonValue;
-
-struct _FbJsonValue
-{
-	const gchar *expr;
-	FbJsonType type;
-	gboolean required;
-	GValue value;
-};
-
-/**
- * FbJsonValues:
- *
- * Represents a JSON value handler.
- */
-struct _FbJsonValues
-{
-	GObject parent;
-
-	JsonNode *root;
-	GQueue *queue;
-	GList *next;
-
-	gboolean isarray;
-	JsonArray *array;
-	guint index;
-
-	GError *error;
-};
-
-G_DEFINE_TYPE(FbJsonValues, fb_json_values, G_TYPE_OBJECT);
-
-static void
-fb_json_values_dispose(GObject *obj)
-{
-	FbJsonValues *values = FB_JSON_VALUES(obj);
-
-	if(values->queue != NULL) {
-		while(!g_queue_is_empty(values->queue)) {
-			FbJsonValue *value = g_queue_pop_head(values->queue);
-
-			if(G_IS_VALUE(&value->value)) {
-				g_value_unset(&value->value);
-			}
-
-			g_free(value);
-		}
-	}
-
-	g_clear_pointer(&values->array, json_array_unref);
-	g_clear_error(&values->error);
-	g_clear_pointer(&values->queue, g_queue_free);
-}
-
-static void
-fb_json_values_class_init(FbJsonValuesClass *klass)
-{
-	GObjectClass *gklass = G_OBJECT_CLASS(klass);
-
-	gklass->dispose = fb_json_values_dispose;
-}
-
-static void
-fb_json_values_init(FbJsonValues *values)
-{
-	values->queue = g_queue_new();
-}
-
-GQuark
-fb_json_error_quark(void)
-{
-	static GQuark q = 0;
-
-	if (G_UNLIKELY(q == 0)) {
-		q = g_quark_from_static_string("fb-json-error-quark");
-	}
-
-	return q;
-}
-
-JsonBuilder *
-fb_json_bldr_new(JsonNodeType type)
-{
-	JsonBuilder *bldr;
-
-	bldr = json_builder_new();
-
-	switch (type) {
-	case JSON_NODE_ARRAY:
-		fb_json_bldr_arr_begin(bldr, NULL);
-		break;
-
-	case JSON_NODE_OBJECT:
-		fb_json_bldr_obj_begin(bldr, NULL);
-		break;
-
-	default:
-		break;
-	}
-
-	return bldr;
-}
-
-gchar *
-fb_json_bldr_close(JsonBuilder *bldr, JsonNodeType type, gsize *size)
-{
-	gchar *ret;
-	JsonGenerator *genr;
-	JsonNode *root;
-
-	switch (type) {
-	case JSON_NODE_ARRAY:
-		fb_json_bldr_arr_end(bldr);
-		break;
-
-	case JSON_NODE_OBJECT:
-		fb_json_bldr_obj_end(bldr);
-		break;
-
-	default:
-		break;
-	}
-
-	genr = json_generator_new();
-	root = json_builder_get_root(bldr);
-
-	json_generator_set_root(genr, root);
-	ret = json_generator_to_data(genr, size);
-
-	json_node_free(root);
-	g_object_unref(genr);
-	g_object_unref(bldr);
-
-	return ret;
-}
-
-void
-fb_json_bldr_arr_begin(JsonBuilder *bldr, const gchar *name)
-{
-	if (name != NULL) {
-		json_builder_set_member_name(bldr, name);
-	}
-
-	json_builder_begin_array(bldr);
-}
-
-void
-fb_json_bldr_arr_end(JsonBuilder *bldr)
-{
-	json_builder_end_array(bldr);
-}
-
-void
-fb_json_bldr_obj_begin(JsonBuilder *bldr, const gchar *name)
-{
-	if (name != NULL) {
-		json_builder_set_member_name(bldr, name);
-	}
-
-	json_builder_begin_object(bldr);
-}
-
-void
-fb_json_bldr_obj_end(JsonBuilder *bldr)
-{
-	json_builder_end_object(bldr);
-}
-
-void
-fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value)
-{
-	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)
-{
-	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)
-{
-	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)
-{
-	if (name != NULL) {
-		json_builder_set_member_name(bldr, name);
-	}
-
-	json_builder_add_string_value(bldr, value);
-}
-
-void
-fb_json_bldr_add_strf(JsonBuilder *bldr, const gchar *name,
-					  const gchar *format, ...)
-{
-	gchar *value;
-	va_list ap;
-
-	va_start(ap, format);
-	value = g_strdup_vprintf(format, ap);
-	va_end(ap);
-
-	fb_json_bldr_add_str(bldr, name, value);
-	g_free(value);
-}
-
-JsonNode *
-fb_json_node_new(const gchar *data, gssize size, GError **error)
-{
-	gchar *slice;
-	JsonNode *root;
-	JsonParser *prsr;
-
-	g_return_val_if_fail(data != NULL, NULL);
-
-	if (size < 0) {
-		size = strlen(data);
-	}
-
-	/* Ensure data is null terminated for json-glib < 1.0.2 */
-	slice = g_strndup(data, size);
-	prsr = json_parser_new();
-
-	if (!json_parser_load_from_data(prsr, slice, size, error)) {
-		g_object_unref(prsr);
-		g_free(slice);
-		return NULL;
-	}
-
-	root = json_parser_get_root(prsr);
-	root = json_node_copy(root);
-
-	g_object_unref(prsr);
-	g_free(slice);
-	return root;
-}
-
-JsonNode *
-fb_json_node_get(JsonNode *root, const gchar *expr, GError **error)
-{
-	GError *err = NULL;
-	guint size;
-	JsonArray *rslt;
-	JsonNode *node;
-	JsonNode *ret;
-
-	/* Special case for json-glib < 0.99.2 */
-	if (purple_strequal(expr, "$")) {
-		return json_node_copy(root);
-	}
-
-	node = json_path_query(expr, root, &err);
-
-	if (err != NULL) {
-		g_propagate_error(error, err);
-		json_node_free(node);
-		return NULL;
-	}
-
-	rslt = json_node_get_array(node);
-	size = json_array_get_length(rslt);
-
-	if (size < 1) {
-		g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NOMATCH,
-		            _("No matches for %s"), expr);
-		json_node_free(node);
-		return NULL;
-	}
-
-	if (size > 1) {
-		g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_AMBIGUOUS,
-		            _("Ambiguous matches for %s"), expr);
-		json_node_free(node);
-		return NULL;
-	}
-
-	if (json_array_get_null_element(rslt, 0)) {
-		g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NULL,
-		            _("Null value for %s"), expr);
-		json_node_free(node);
-		return NULL;
-	}
-
-	ret = json_array_dup_element(rslt, 0);
-	json_node_free(node);
-	return ret;
-}
-
-JsonNode *
-fb_json_node_get_nth(JsonNode *root, guint n)
-{
-	GList *vals;
-	JsonNode *ret;
-	JsonObject *obj;
-
-	obj = json_node_get_object(root);
-	vals = json_object_get_values(obj);
-	ret = g_list_nth_data(vals, n);
-
-	g_list_free(vals);
-	return ret;
-}
-
-JsonArray *
-fb_json_node_get_arr(JsonNode *root, const gchar *expr, GError **error)
-{
-	JsonArray *ret;
-	JsonNode *rslt;
-
-	rslt = fb_json_node_get(root, expr, error);
-
-	if (rslt == NULL) {
-		return NULL;
-	}
-
-	ret = json_node_dup_array(rslt);
-	json_node_free(rslt);
-	return ret;
-}
-
-gboolean
-fb_json_node_get_bool(JsonNode *root, const gchar *expr, GError **error)
-{
-	gboolean ret;
-	JsonNode *rslt;
-
-	rslt = fb_json_node_get(root, expr, error);
-
-	if (rslt == NULL) {
-		return FALSE;
-	}
-
-	ret = json_node_get_boolean(rslt);
-	json_node_free(rslt);
-	return ret;
-}
-
-gdouble
-fb_json_node_get_dbl(JsonNode *root, const gchar *expr, GError **error)
-{
-	gdouble ret;
-	JsonNode *rslt;
-
-	rslt = fb_json_node_get(root, expr, error);
-
-	if (rslt == NULL) {
-		return 0.0;
-	}
-
-	ret = json_node_get_double(rslt);
-	json_node_free(rslt);
-	return ret;
-}
-
-gint64
-fb_json_node_get_int(JsonNode *root, const gchar *expr, GError **error)
-{
-	gint64 ret;
-	JsonNode *rslt;
-
-	rslt = fb_json_node_get(root, expr, error);
-
-	if (rslt == NULL) {
-		return 0;
-	}
-
-	ret = json_node_get_int(rslt);
-	json_node_free(rslt);
-	return ret;
-}
-
-gchar *
-fb_json_node_get_str(JsonNode *root, const gchar *expr, GError **error)
-{
-	gchar *ret;
-	JsonNode *rslt;
-
-	rslt = fb_json_node_get(root, expr, error);
-
-	if (rslt == NULL) {
-		return NULL;
-	}
-
-	ret = json_node_dup_string(rslt);
-	json_node_free(rslt);
-	return ret;
-}
-
-FbJsonValues *
-fb_json_values_new(JsonNode *root)
-{
-	FbJsonValues *values;
-
-	g_return_val_if_fail(root != NULL, NULL);
-
-	values = g_object_new(FB_TYPE_JSON_VALUES, NULL);
-	values->root = root;
-
-	return values;
-}
-
-void
-fb_json_values_add(FbJsonValues *values, FbJsonType type, gboolean required,
-                   const gchar *expr)
-{
-	FbJsonValue *value;
-
-	g_return_if_fail(values != NULL);
-	g_return_if_fail(expr != NULL);
-
-	value = g_new0(FbJsonValue, 1);
-	value->expr = expr;
-	value->type = type;
-	value->required = required;
-
-	g_queue_push_tail(values->queue, value);
-}
-
-JsonNode *
-fb_json_values_get_root(FbJsonValues *values)
-{
-	guint index;
-
-	g_return_val_if_fail(values != NULL, NULL);
-
-	if(values->array == NULL) {
-		return values->root;
-	}
-
-	g_return_val_if_fail(values->index > 0, NULL);
-	index = values->index - 1;
-
-	if(json_array_get_length(values->array) <= index) {
-		return NULL;
-	}
-
-	return json_array_get_element(values->array, index);
-}
-
-void
-fb_json_values_set_array(FbJsonValues *values, gboolean required,
-                         const gchar *expr)
-{
-	g_return_if_fail(values != NULL);
-
-	values->array = fb_json_node_get_arr(values->root, expr, &values->error);
-	values->isarray = TRUE;
-
-	if(!required) {
-		g_clear_error(&values->error);
-	}
-}
-
-gboolean
-fb_json_values_update(FbJsonValues *values, GError **error)
-{
-	FbJsonValue *value;
-	GError *err = NULL;
-	GList *l;
-	GType type;
-	JsonNode *root;
-	JsonNode *node;
-
-	g_return_val_if_fail(values != NULL, FALSE);
-
-	if(G_UNLIKELY(values->error != NULL)) {
-		g_propagate_error(error, values->error);
-		values->error = NULL;
-		return FALSE;
-	}
-
-	if(values->isarray) {
-		if(values->array == NULL ||
-		   json_array_get_length(values->array) <= values->index)
-		{
-			return FALSE;
-		}
-
-		root = json_array_get_element(values->array, values->index++);
-	} else {
-		root = values->root;
-	}
-
-	g_return_val_if_fail(root != NULL, FALSE);
-
-	for(l = values->queue->head; l != NULL; l = l->next) {
-		value = l->data;
-		node = fb_json_node_get(root, value->expr, &err);
-
-		if (G_IS_VALUE(&value->value)) {
-			g_value_unset(&value->value);
-		}
-
-		if (err != NULL) {
-			json_node_free(node);
-
-			if (value->required) {
-				g_propagate_error(error, err);
-				return FALSE;
-			}
-
-			g_clear_error(&err);
-			continue;
-		}
-
-		type = json_node_get_value_type(node);
-
-		if (G_UNLIKELY(type != value->type)) {
-			g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_TYPE,
-			            _("Expected a %s but got a %s for %s"),
-			            g_type_name(value->type),
-			            g_type_name(type),
-				    value->expr);
-			json_node_free(node);
-			return FALSE;
-		}
-
-		json_node_get_value(node, &value->value);
-		json_node_free(node);
-	}
-
-	values->next = values->queue->head;
-	return TRUE;
-}
-
-const GValue *
-fb_json_values_next(FbJsonValues *values)
-{
-	FbJsonValue *value;
-
-	g_return_val_if_fail(values != NULL, NULL);
-
-	g_return_val_if_fail(values->next != NULL, NULL);
-	value = values->next->data;
-	values->next = values->next->next;
-
-	if (!G_IS_VALUE(&value->value)) {
-		return NULL;
-	}
-
-	return &value->value;
-}
-
-gboolean
-fb_json_values_next_bool(FbJsonValues *values, gboolean defval)
-{
-	const GValue *value;
-
-	value = fb_json_values_next(values);
-
-	if (G_UNLIKELY(value == NULL)) {
-		return defval;
-	}
-
-	return g_value_get_boolean(value);
-}
-
-gdouble
-fb_json_values_next_dbl(FbJsonValues *values, gdouble defval)
-{
-	const GValue *value;
-
-	value = fb_json_values_next(values);
-
-	if (G_UNLIKELY(value == NULL)) {
-		return defval;
-	}
-
-	return g_value_get_double(value);
-}
-
-gint64
-fb_json_values_next_int(FbJsonValues *values, gint64 defval)
-{
-	const GValue *value;
-
-	value = fb_json_values_next(values);
-
-	if (G_UNLIKELY(value == NULL)) {
-		return defval;
-	}
-
-	return g_value_get_int64(value);
-}
-
-const gchar *
-fb_json_values_next_str(FbJsonValues *values, const gchar *defval)
-{
-	const GValue *value;
-
-	value = fb_json_values_next(values);
-
-	if (G_UNLIKELY(value == NULL)) {
-		return defval;
-	}
-
-	return g_value_get_string(value);
-}
-
-gchar *
-fb_json_values_next_str_dup(FbJsonValues *values, const gchar *defval)
-{
-	const GValue *value;
-
-	value = fb_json_values_next(values);
-
-	if (G_UNLIKELY(value == NULL)) {
-		return g_strdup(defval);
-	}
-
-	return g_value_dup_string(value);
-}
diff --git a/libpurple/protocols/facebook/meson.build b/libpurple/protocols/facebook/meson.build
deleted file mode 100644
--- a/libpurple/protocols/facebook/meson.build
+++ /dev/null
@@ -1,63 +0,0 @@
-FACEBOOK_SOURCES = [
-	'api.c',
-	'api.h',
-	'data.c',
-	'data.h',
-	'facebook.h',
-	'facebook.c',
-	'http.c',
-	'http.h',
-	'id.h',
-	'json.c',
-	'json.h',
-	'mqtt.c',
-	'mqtt.h',
-	'thrift.c',
-	'thrift.h',
-	'util.c',
-	'util.h'
-]
-
-FACEBOOK_BUILT_SOURCES = []
-
-if DYNAMIC_FACEBOOK
-	facebook_resources = gnome.compile_resources('facebookresource',
-		'resources/facebook.gresource.xml',
-		source_dir : 'resources',
-		c_name : 'facebook')
-	FACEBOOK_BUILT_SOURCES += facebook_resources
-
-	facebook_prpl = shared_library('facebook',
-	    FACEBOOK_SOURCES + FACEBOOK_BUILT_SOURCES,
-	    c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Purple-Facebook"'],
-	    dependencies : [json, libpurple_dep, libsoup, glib],
-	    install : true,
-	    install_dir : PURPLE_PLUGINDIR)
-
-	# Used to produce docs.
-	facebook_inc = include_directories('.')
-	facebook_dep = declare_dependency(
-	    link_with : facebook_prpl,
-	    dependencies : [json, libpurple_dep, glib])
-
-	devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir())
-
-	if enable_introspection
-		introspection_sources = FACEBOOK_SOURCES
-
-		facebook_gir_includes = ['GObject-2.0', 'Gio-2.0', 'Gst-1.0',
-		                         'Json-1.0', 'Soup-3.0', libpurple_gir[0]]
-
-		facebook_gir = gnome.generate_gir(facebook_prpl,
-		    sources : introspection_sources,
-		    includes : facebook_gir_includes,
-		    namespace : 'Facebook',
-		    symbol_prefix : 'fb',
-		    identifier_prefix : 'Fb',
-		    nsversion : f'@purple_major_version@.@purple_minor_version@',
-		    dependencies: [gplugin_dep, libpurple_dep],
-		    install : false,
-		    extra_args : ['-DPURPLE_COMPILATION', '--quiet'])
-	endif
-
-endif
diff --git a/libpurple/protocols/facebook/mqtt.h b/libpurple/protocols/facebook/mqtt.h
deleted file mode 100644
--- a/libpurple/protocols/facebook/mqtt.h
+++ /dev/null
@@ -1,520 +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
- */
-
-#ifndef PURPLE_FACEBOOK_MQTT_H
-#define PURPLE_FACEBOOK_MQTT_H
-
-#include <glib.h>
-#include <string.h>
-
-#include <purple.h>
-
-#define FB_TYPE_MQTT  fb_mqtt_get_type()
-#define FB_TYPE_MQTT_MESSAGE  fb_mqtt_message_get_type()
-
-/**
- * FB_MQTT_NAME:
- *
- * The name of the MQTT version.
- */
-#define FB_MQTT_NAME  "MQTToT"
-
-/**
- * FB_MQTT_LEVEL:
- *
- * The level of the MQTT version.
- */
-#define FB_MQTT_LEVEL  3
-
-/**
- * FB_MQTT_KA:
- *
- * The keep-alive timeout, in seconds, of the MQTT connection.
- */
-#define FB_MQTT_KA  60
-
-/**
- * FB_MQTT_HOST:
- *
- * The MQTT host name for Facebook.
- */
-#define FB_MQTT_HOST  "mqtt.facebook.com"
-
-/**
- * FB_MQTT_PORT:
- *
- * The MQTT host port for Facebook.
- */
-#define FB_MQTT_PORT  443
-
-/**
- * FB_MQTT_TIMEOUT_CONN:
- *
- * The timeout, in seconds, to wait for a PING back from the server.
- */
-#define FB_MQTT_TIMEOUT_CONN ((guint)(FB_MQTT_KA * 1.5))
-
-/**
- * FB_MQTT_TIMEOUT_PING:
- *
- * The timeout, in seconds, to send a PING to the server.
- */
-#define FB_MQTT_TIMEOUT_PING (FB_MQTT_KA)
-
-/**
- * FB_MQTT_ERROR:
- *
- * The #GQuark of the domain of MQTT errors.
- */
-#define FB_MQTT_ERROR  fb_mqtt_error_quark()
-
-/**
- * FbMqttConnectFlags:
- * @FB_MQTT_CONNECT_FLAG_CLR: Clear the session.
- * @FB_MQTT_CONNECT_FLAG_WILL: A will message is in the payload.
- * @FB_MQTT_CONNECT_FLAG_RET: Retain the will message.
- * @FB_MQTT_CONNECT_FLAG_PASS: A password is in the payload.
- * @FB_MQTT_CONNECT_FLAG_USER: A user name is in the payload.
- * @FB_MQTT_CONNECT_FLAG_QOS0: Use no quality of service.
- * @FB_MQTT_CONNECT_FLAG_QOS1: Use level one quality of service.
- * @FB_MQTT_CONNECT_FLAG_QOS2: Use level two quality of service.
- *
- * The #FbMqttMessage flags for the CONNECT message.
- */
-typedef enum
-{
-	FB_MQTT_CONNECT_FLAG_CLR = 1 << 1,
-	FB_MQTT_CONNECT_FLAG_WILL = 1 << 2,
-	FB_MQTT_CONNECT_FLAG_RET = 1 << 5,
-	FB_MQTT_CONNECT_FLAG_PASS = 1 << 6,
-	FB_MQTT_CONNECT_FLAG_USER = 1 << 7,
-	FB_MQTT_CONNECT_FLAG_QOS0 = 0 << 3,
-	FB_MQTT_CONNECT_FLAG_QOS1 = 1 << 3,
-	FB_MQTT_CONNECT_FLAG_QOS2 = 2 << 3
-} FbMqttConnectFlags;
-
-/**
- * FbMqttError:
- * @FB_MQTT_ERROR_SUCCESS: There is no error.
- * @FB_MQTT_ERROR_PRTVERS: Unacceptable protocol version.
- * @FB_MQTT_ERROR_IDREJECT: Identifier rejected.
- * @FB_MQTT_ERROR_SRVGONE: Server unavailable.
- * @FB_MQTT_ERROR_USERPASS: Bad user name or password.
- * @FB_MQTT_ERROR_UNAUTHORIZED: Not authorized.
- * @FB_MQTT_ERROR_GENERAL: General failure.
- *
- * The error codes for the #FB_MQTT_ERROR domain.
- */
-typedef enum
-{
-	FB_MQTT_ERROR_SUCCESS = 0,
-	FB_MQTT_ERROR_PRTVERS = 1,
-	FB_MQTT_ERROR_IDREJECT = 2,
-	FB_MQTT_ERROR_SRVGONE = 3,
-	FB_MQTT_ERROR_USERPASS = 4,
-	FB_MQTT_ERROR_UNAUTHORIZED = 5,
-	FB_MQTT_ERROR_GENERAL
-} FbMqttError;
-
-/**
- * FbMqttMessageFlags:
- * @FB_MQTT_MESSAGE_FLAG_RET: Retain messages.
- * @FB_MQTT_MESSAGE_FLAG_DUP: Duplicate delivery of control packet.
- * @FB_MQTT_MESSAGE_FLAG_QOS0: Use no quality of service.
- * @FB_MQTT_MESSAGE_FLAG_QOS1: Use level one quality of service.
- * @FB_MQTT_MESSAGE_FLAG_QOS2: Use level two quality of service.
- *
- * The #FbMqttMessage flags.
- */
-typedef enum
-{
-	FB_MQTT_MESSAGE_FLAG_RET = 1 << 0,
-	FB_MQTT_MESSAGE_FLAG_DUP = 1 << 3,
-	FB_MQTT_MESSAGE_FLAG_QOS0 = 0 << 1,
-	FB_MQTT_MESSAGE_FLAG_QOS1 = 1 << 1,
-	FB_MQTT_MESSAGE_FLAG_QOS2 = 2 << 1
-} FbMqttMessageFlags;
-
-/**
- * FbMqttMessageType:
- * @FB_MQTT_MESSAGE_TYPE_CONNECT: Requests a connection.
- * @FB_MQTT_MESSAGE_TYPE_CONNACK: Connection acknowledgment.
- * @FB_MQTT_MESSAGE_TYPE_PUBLISH: Requests a message publication.
- * @FB_MQTT_MESSAGE_TYPE_PUBACK: Publication acknowledgment.
- * @FB_MQTT_MESSAGE_TYPE_PUBREC: Publication received.
- * @FB_MQTT_MESSAGE_TYPE_PUBREL: Publication released.
- * @FB_MQTT_MESSAGE_TYPE_PUBCOMP: Publication complete.
- * @FB_MQTT_MESSAGE_TYPE_SUBSCRIBE: Requests a subscription.
- * @FB_MQTT_MESSAGE_TYPE_SUBACK: Subscription acknowledgment.
- * @FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE: Requests an unsubscription.
- * @FB_MQTT_MESSAGE_TYPE_UNSUBACK: Unsubscription acknowledgment.
- * @FB_MQTT_MESSAGE_TYPE_PINGREQ: Requests a ping response.
- * @FB_MQTT_MESSAGE_TYPE_PINGRESP: Ping response.
- * @FB_MQTT_MESSAGE_TYPE_DISCONNECT: Requests a disconnection.
- *
- * The #FbMqttMessage types.
- */
-typedef enum
-{
-	FB_MQTT_MESSAGE_TYPE_CONNECT = 1,
-	FB_MQTT_MESSAGE_TYPE_CONNACK = 2,
-	FB_MQTT_MESSAGE_TYPE_PUBLISH = 3,
-	FB_MQTT_MESSAGE_TYPE_PUBACK = 4,
-	FB_MQTT_MESSAGE_TYPE_PUBREC = 5,
-	FB_MQTT_MESSAGE_TYPE_PUBREL = 6,
-	FB_MQTT_MESSAGE_TYPE_PUBCOMP = 7,
-	FB_MQTT_MESSAGE_TYPE_SUBSCRIBE = 8,
-	FB_MQTT_MESSAGE_TYPE_SUBACK = 9,
-	FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE = 10,
-	FB_MQTT_MESSAGE_TYPE_UNSUBACK = 11,
-	FB_MQTT_MESSAGE_TYPE_PINGREQ = 12,
-	FB_MQTT_MESSAGE_TYPE_PINGRESP = 13,
-	FB_MQTT_MESSAGE_TYPE_DISCONNECT = 14
-} FbMqttMessageType;
-
-G_DECLARE_FINAL_TYPE(FbMqtt, fb_mqtt, FB, MQTT, GObject)
-
-G_DECLARE_FINAL_TYPE(FbMqttMessage, fb_mqtt_message, FB, MQTT_MESSAGE,
-		GObject)
-
-/**
- * fb_mqtt_error_quark:
- *
- * Gets the #GQuark of the domain of MQTT errors.
- *
- * Returns: The #GQuark of the domain.
- */
-GQuark
-fb_mqtt_error_quark(void);
-
-/**
- * fb_mqtt_new:
- * @gc: The #PurpleConnection.
- *
- * Creates a new #FbMqtt. The returned #FbMqtt should be freed with
- * #g_object_unref() when no longer needed.
- *
- * Returns: The new #FbMqtt.
- */
-FbMqtt *
-fb_mqtt_new(PurpleConnection *gc);
-
-/**
- * fb_mqtt_close:
- * @mqtt: The #FbMqtt.
- *
- * Closes the MQTT without sending the `DISCONNECT` message. The #FbMqtt
- * may be reopened after calling this.
- */
-void
-fb_mqtt_close(FbMqtt *mqtt);
-
-/**
- * fb_mqtt_error:
- * @mqtt: The #FbMqtt.
- * @error: The #FbMqttError.
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Emits an #FbMqttError and closes the #FbMqtt.
- */
-void
-fb_mqtt_error(FbMqtt *mqtt, FbMqttError error, const gchar *format, ...)
-              G_GNUC_PRINTF(3, 4);
-
-/**
- * fb_mqtt_read:
- * @mqtt: The #FbMqtt.
- * @msg: The #FbMqttMessage.
- *
- * Reads an #FbMqttMessage into the #FbMqtt for processing.
- */
-void
-fb_mqtt_read(FbMqtt *mqtt, FbMqttMessage *msg);
-
-/**
- * fb_mqtt_write:
- * @mqtt: The #FbMqtt.
- * @msg: The #FbMqttMessage.
- *
- * Writes an #FbMqttMessage to the wire.
- */
-void
-fb_mqtt_write(FbMqtt *mqtt, FbMqttMessage *msg);
-
-/**
- * fb_mqtt_open:
- * @mqtt: The #FbMqtt.
- * @host: The host name.
- * @port: The port.
- *
- * Opens an SSL connection to the remote server.
- */
-void
-fb_mqtt_open(FbMqtt *mqtt, const gchar *host, gint port);
-
-/**
- * fb_mqtt_connect:
- * @mqtt: The #FbMqtt.
- * @flags: The #FbMqttConnectFlags.
- * @pload: The payload.
- *
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_CONNECT.
- */
-void
-fb_mqtt_connect(FbMqtt *mqtt, guint8 flags, const GByteArray *pload);
-
-/**
- * fb_mqtt_connected:
- * @mqtt: The #FbMqtt.
- * @error: #TRUE to error with no connection, otherwise #FALSE.
- *
- * Determines the connection state of the #FbMqtt, and optionally emits
- * an error.
- *
- * Returns: #TRUE if the #FbMqtt is connected, otherwise #FALSE.
- */
-gboolean
-fb_mqtt_connected(FbMqtt *mqtt, gboolean error);
-
-/**
- * fb_mqtt_disconnect:
- * @mqtt: The #FbMqtt.
- *
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_DISCONNECT, and closes
- * the connection.
- */
-void
-fb_mqtt_disconnect(FbMqtt *mqtt);
-
-/**
- * fb_mqtt_publish:
- * @mqtt: The #FbMqtt.
- * @topic: The topic.
- * @pload: The payload.
- *
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_PUBLISH.
- */
-void
-fb_mqtt_publish(FbMqtt *mqtt, const gchar *topic, const GByteArray *pload);
-
-/**
- * fb_mqtt_subscribe:
- * @mqtt: The #FbMqtt.
- * @...: The %NULL-terminated list of topic/QoS pairs.
- *
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_SUBSCRIBE.
- */
-void fb_mqtt_subscribe(FbMqtt *mqtt, ...) G_GNUC_NULL_TERMINATED;
-
-/**
- * fb_mqtt_unsubscribe:
- * @mqtt: The #FbMqtt.
- * @topic1: The first topic.
- * @...: The %NULL-terminated list of topics.
- *
- * Sends a message of type #FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE.
- */
-void
-fb_mqtt_unsubscribe(FbMqtt *mqtt, const gchar *topic1, ...)
-                    G_GNUC_NULL_TERMINATED;
-
-/**
- * fb_mqtt_message_new:
- * @type: The #FbMqttMessageType.
- * @flags: The #FbMqttMessageFlags.
- *
- * Creates a new #FbMqttMessage. The returned #FbMqttMessage should be
- * freed with #g_object_unref() when no longer needed.
- *
- * Returns: The new #FbMqttMessage.
- */
-FbMqttMessage *
-fb_mqtt_message_new(FbMqttMessageType type, FbMqttMessageFlags flags);
-
-/**
- * fb_mqtt_message_new_bytes:
- * @bytes: The #GByteArray.
- *
- * Creates a new #FbMqttMessage from a #GByteArray. The returned
- * #FbMqttMessage should be freed with #g_object_unref() when no
- * longer needed.
- *
- * Returns: The new #FbMqttMessage.
- */
-FbMqttMessage *
-fb_mqtt_message_new_bytes(GByteArray *bytes);
-
-/**
- * fb_mqtt_message_reset:
- * @msg: The #FbMqttMessage.
- *
- * Resets an #FbMqttMessage. This resets the cursor position, and
- * removes any sort of fixed header.
- */
-void
-fb_mqtt_message_reset(FbMqttMessage *msg);
-
-/**
- * fb_mqtt_message_bytes:
- * @msg: The #FbMqttMessage.
- *
- * Formats the internal #GByteArray of the #FbMqttMessage with the
- * required fixed header. This resets the cursor position.
- *
- * Returns: The internal #GByteArray.
- */
-const GByteArray *
-fb_mqtt_message_bytes(FbMqttMessage *msg);
-
-/**
- * fb_mqtt_message_read:
- * @msg: The #FbMqttMessage.
- * @data: The data buffer.
- * @size: The size of @buffer.
- *
- * Reads data from the #FbMqttMessage into a buffer. If @data is #NULL,
- * this will simply advance the cursor position.
- *
- * Returns: #TRUE if the data was read, otherwise #FALSE.
- */
-gboolean
-fb_mqtt_message_read(FbMqttMessage *msg, gpointer data, guint size);
-
-/**
- * fb_mqtt_message_read_r:
- * @msg: The #FbMqttMessage.
- * @bytes: The #GByteArray.
- *
- * Reads the remaining data from the #FbMqttMessage into a #GByteArray.
- * This is useful for obtaining the payload of a message.
- *
- * Returns: #TRUE if the data was read, otherwise #FALSE.
- */
-gboolean
-fb_mqtt_message_read_r(FbMqttMessage *msg, GByteArray *bytes);
-
-/**
- * fb_mqtt_message_read_byte:
- * @msg: The #FbMqttMessage.
- * @value: The return location for the value or #NULL.
- *
- * Reads an 8-bit integer value from the #FbMqttMessage. If @value is
- * #NULL, this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_mqtt_message_read_byte(FbMqttMessage *msg, guint8 *value);
-
-/**
- * fb_mqtt_message_read_mid:
- * @msg: The #FbMqttMessage.
- * @value: The return location for the value or #NULL.
- *
- * Reads a message identifier from the #FbMqttMessage. If @value is
- * #NULL, this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_mqtt_message_read_mid(FbMqttMessage *msg, guint16 *value);
-
-/**
- * fb_mqtt_message_read_u16:
- * @msg: The #FbMqttMessage.
- * @value: The return location for the value or #NULL.
- *
- * Reads a 16-bit integer value from the #FbMqttMessage. If @value is
- * #NULL, this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_mqtt_message_read_u16(FbMqttMessage *msg, guint16 *value);
-
-/**
- * fb_mqtt_message_read_str:
- * @msg: The #FbMqttMessage.
- * @value: The return location for the value or #NULL.
- *
- * Reads a string value from the #FbMqttMessage. The value returned to
- * @value should be freed with #g_free() when no longer needed. If
- * @value is #NULL, this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_mqtt_message_read_str(FbMqttMessage *msg, gchar **value);
-
-/**
- * fb_mqtt_message_write:
- * @msg: The #FbMqttMessage.
- * @data: The data buffer.
- * @size: The size of @buffer.
- *
- * Writes data to the #FbMqttMessage.
- */
-void
-fb_mqtt_message_write(FbMqttMessage *msg, gconstpointer data, guint size);
-
-/**
- * fb_mqtt_message_write_byte:
- * @msg: The #FbMqttMessage.
- * @value: The value.
- *
- * Writes an 8-bit integer value to the #FbMqttMessage.
- */
-void
-fb_mqtt_message_write_byte(FbMqttMessage *msg, guint8 value);
-
-/**
- * fb_mqtt_message_write_mid:
- * @msg: The #FbMqttMessage.
- * @value: The value.
- *
- * Writes a message identifier to the #FbMqttMessage. This increments
- * @value for the next message.
- */
-void
-fb_mqtt_message_write_mid(FbMqttMessage *msg, guint16 *value);
-
-/**
- * fb_mqtt_message_write_u16:
- * @msg: The #FbMqttMessage.
- * @value: The value.
- *
- * Writes a 16-bit integer value to the #FbMqttMessage.
- */
-void
-fb_mqtt_message_write_u16(FbMqttMessage *msg, guint16 value);
-
-/**
- * fb_mqtt_message_write_str:
- * @msg: The #FbMqttMessage.
- * @value: The value.
- *
- * Writes a string value to the #FbMqttMessage.
- */
-void
-fb_mqtt_message_write_str(FbMqttMessage *msg, const gchar *value);
-
-#endif /* PURPLE_FACEBOOK_MQTT_H */
diff --git a/libpurple/protocols/facebook/mqtt.c b/libpurple/protocols/facebook/mqtt.c
deleted file mode 100644
--- a/libpurple/protocols/facebook/mqtt.c
+++ /dev/null
@@ -1,1016 +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 <glib/gprintf.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include <purple.h>
-
-#include "mqtt.h"
-#include "util.h"
-
-/**
- * FbMqtt:
- *
- * Represents an MQTT connection.
- */
-struct _FbMqtt
-{
-	GObject parent;
-
-	PurpleConnection *gc;
-	GIOStream *conn;
-	GBufferedInputStream *input;
-	PurpleQueuedOutputStream *output;
-	GCancellable *cancellable;
-	gboolean connected;
-	guint16 mid;
-
-	GByteArray *rbuf;
-	gsize remz;
-
-	gint tev;
-};
-
-G_DEFINE_TYPE(FbMqtt, fb_mqtt, G_TYPE_OBJECT);
-
-/**
- * FbMqttMessage:
- *
- * Represents a reader/writer for an MQTT message.
- */
-struct _FbMqttMessage
-{
-	GObject parent;
-
-	FbMqttMessageType type;
-	FbMqttMessageFlags flags;
-
-	GByteArray *bytes;
-	guint offset;
-	guint pos;
-
-	gboolean local;
-};
-
-G_DEFINE_TYPE(FbMqttMessage, fb_mqtt_message, G_TYPE_OBJECT);
-
-static void fb_mqtt_read_packet(FbMqtt *mqtt);
-
-static void
-fb_mqtt_dispose(GObject *obj)
-{
-	FbMqtt *mqtt = FB_MQTT(obj);
-
-	fb_mqtt_close(mqtt);
-	g_byte_array_free(mqtt->rbuf, TRUE);
-}
-
-static void
-fb_mqtt_class_init(FbMqttClass *klass)
-{
-	GObjectClass *gklass = G_OBJECT_CLASS(klass);
-
-	gklass->dispose = fb_mqtt_dispose;
-	/**
-	 * FbMqtt::connect:
-	 * @mqtt: The #FbMqtt.
-	 *
-	 * Emitted upon the successful completion of the connection
-	 * process. This is emitted as a result of #fb_mqtt_connect().
-	 */
-	g_signal_new("connect",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             0);
-
-	/**
-	 * FbMqtt::error:
-	 * @mqtt: The #FbMqtt.
-	 * @error: The #GError.
-	 *
-	 * Emitted whenever an error is hit within the #FbMqtt. This
-	 * should close the #FbMqtt with #fb_mqtt_close().
-	 */
-	g_signal_new("error",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             1, G_TYPE_ERROR);
-
-	/**
-	 * FbMqtt::open:
-	 * @mqtt: The #FbMqtt.
-	 *
-	 * Emitted upon the successful opening of the remote socket.
-	 * This is emitted as a result of #fb_mqtt_open(). This should
-	 * call #fb_mqtt_connect().
-	 */
-	g_signal_new("open",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             0);
-
-	/**
-	 * FbMqtt::publish:
-	 * @mqtt: The #FbMqtt.
-	 * @topic: The topic.
-	 * @pload: The payload.
-	 *
-	 * Emitted upon an incoming message from the steam.
-	 */
-	g_signal_new("publish",
-	             G_TYPE_FROM_CLASS(klass),
-	             G_SIGNAL_ACTION,
-	             0,
-	             NULL, NULL, NULL,
-	             G_TYPE_NONE,
-	             2, G_TYPE_STRING, G_TYPE_BYTE_ARRAY);
-}
-
-static void
-fb_mqtt_init(FbMqtt *mqtt)
-{
-	mqtt->rbuf = g_byte_array_new();
-}
-
-static void
-fb_mqtt_message_dispose(GObject *obj)
-{
-	FbMqttMessage *msg = FB_MQTT_MESSAGE(obj);
-
-	if(msg->bytes != NULL && msg->local) {
-		g_byte_array_free(msg->bytes, TRUE);
-		msg->bytes = NULL;
-	}
-}
-
-static void
-fb_mqtt_message_class_init(FbMqttMessageClass *klass)
-{
-	GObjectClass *gklass = G_OBJECT_CLASS(klass);
-
-	gklass->dispose = fb_mqtt_message_dispose;
-}
-
-static void
-fb_mqtt_message_init(G_GNUC_UNUSED FbMqttMessage *msg)
-{
-}
-
-GQuark
-fb_mqtt_error_quark(void)
-{
-	static GQuark q = 0;
-
-	if (G_UNLIKELY(q == 0)) {
-		q = g_quark_from_static_string("fb-mqtt-error-quark");
-	}
-
-	return q;
-}
-
-FbMqtt *
-fb_mqtt_new(PurpleConnection *gc)
-{
-	FbMqtt *mqtt;
-
-	g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL);
-
-	mqtt = g_object_new(FB_TYPE_MQTT,  NULL);
-	mqtt->gc = gc;
-
-	return mqtt;
-};
-
-void
-fb_mqtt_close(FbMqtt *mqtt)
-{
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-
-	g_clear_handle_id(&mqtt->tev, g_source_remove);
-
-	if(mqtt->cancellable != NULL) {
-		g_cancellable_cancel(mqtt->cancellable);
-		g_clear_object(&mqtt->cancellable);
-	}
-
-	if(mqtt->conn != NULL) {
-		purple_gio_graceful_close(mqtt->conn,
-				G_INPUT_STREAM(mqtt->input),
-				G_OUTPUT_STREAM(mqtt->output));
-		g_clear_object(&mqtt->input);
-		g_clear_object(&mqtt->output);
-		g_clear_object(&mqtt->conn);
-	}
-
-	mqtt->connected = FALSE;
-	g_byte_array_set_size(mqtt->rbuf, 0);
-}
-
-static void
-fb_mqtt_take_error(FbMqtt *mqtt, GError *err, const gchar *prefix)
-{
-	if (g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-		/* Return as cancelled means the connection is closing */
-		g_error_free(err);
-		return;
-	}
-
-	/* Now we can check for programming errors */
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-
-	if (prefix != NULL) {
-		g_prefix_error(&err, "%s: ", prefix);
-	}
-
-	g_signal_emit_by_name(mqtt, "error", err);
-	g_error_free(err);
-}
-
-static void
-fb_mqtt_error_literal(FbMqtt *mqtt, FbMqttError error, const gchar *msg)
-{
-	GError *err;
-
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-
-	err = g_error_new_literal(FB_MQTT_ERROR, error, msg);
-
-	g_signal_emit_by_name(mqtt, "error", err);
-	g_error_free(err);
-}
-
-void
-fb_mqtt_error(FbMqtt *mqtt, FbMqttError error, const gchar *format, ...)
-{
-	GError *err;
-	va_list ap;
-
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-
-	va_start(ap, format);
-	err = g_error_new_valist(FB_MQTT_ERROR, error, format, ap);
-	va_end(ap);
-
-	g_signal_emit_by_name(mqtt, "error", err);
-	g_error_free(err);
-}
-
-static gboolean
-fb_mqtt_cb_timeout(gpointer data)
-{
-	FbMqtt *mqtt = data;
-
-	mqtt->tev = 0;
-	fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL,
-	                      _("Connection timed out"));
-	return FALSE;
-}
-
-static void
-fb_mqtt_timeout_clear(FbMqtt *mqtt)
-{
-	g_clear_handle_id(&mqtt->tev, g_source_remove);
-}
-
-static void
-fb_mqtt_timeout(FbMqtt *mqtt)
-{
-	fb_mqtt_timeout_clear(mqtt);
-	mqtt->tev = g_timeout_add_seconds(FB_MQTT_TIMEOUT_CONN, fb_mqtt_cb_timeout,
-	                                  mqtt);
-}
-
-static gboolean
-fb_mqtt_cb_ping(gpointer data)
-{
-	FbMqtt *mqtt = data;
-	FbMqttMessage *msg;
-
-	msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_PINGREQ, 0);
-	fb_mqtt_write(mqtt, msg);
-	g_object_unref(msg);
-
-	mqtt->tev = 0;
-	fb_mqtt_timeout(mqtt);
-	return FALSE;
-}
-
-static void
-fb_mqtt_ping(FbMqtt *mqtt)
-{
-	fb_mqtt_timeout_clear(mqtt);
-	mqtt->tev = g_timeout_add_seconds(FB_MQTT_TIMEOUT_PING, fb_mqtt_cb_ping,
-	                                  mqtt);
-}
-
-static void
-fb_mqtt_cb_fill(GObject *source, GAsyncResult *res, gpointer data)
-{
-	GBufferedInputStream *input = G_BUFFERED_INPUT_STREAM(source);
-	FbMqtt *mqtt = data;
-	gssize ret;
-	GError *err = NULL;
-
-	ret = g_buffered_input_stream_fill_finish(input, res, &err);
-
-	if (ret < 1) {
-		if (ret == 0) {
-			err = g_error_new_literal(G_IO_ERROR,
-					G_IO_ERROR_CONNECTION_CLOSED,
-					_("Connection closed"));
-		}
-
-		fb_mqtt_take_error(mqtt, err, _("Failed to read fixed header"));
-		return;
-	}
-
-	fb_mqtt_read_packet(mqtt);
-}
-
-static void
-fb_mqtt_cb_read_packet(GObject *source, GAsyncResult *res, gpointer data)
-{
-	FbMqtt *mqtt = data;
-	gssize ret;
-	FbMqttMessage *msg;
-	GError *err = NULL;
-
-	ret = g_input_stream_read_finish(G_INPUT_STREAM(source), res, &err);
-
-	if (ret < 1) {
-		if (ret == 0) {
-			err = g_error_new_literal(G_IO_ERROR,
-					G_IO_ERROR_CONNECTION_CLOSED,
-					_("Connection closed"));
-		}
-
-		fb_mqtt_take_error(mqtt, err, _("Failed to read packet data"));
-		return;
-	}
-
-	mqtt->remz -= ret;
-
-	if(mqtt->remz > 0) {
-		g_input_stream_read_async(G_INPUT_STREAM(source),
-		                          mqtt->rbuf->data + mqtt->rbuf->len - mqtt->remz,
-		                          mqtt->remz, G_PRIORITY_DEFAULT,
-		                          mqtt->cancellable, fb_mqtt_cb_read_packet,
-		                          mqtt);
-		return;
-	}
-
-	msg = fb_mqtt_message_new_bytes(mqtt->rbuf);
-
-	if (G_UNLIKELY(msg == NULL)) {
-		fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL,
-		                      _("Failed to parse message"));
-		return;
-	}
-
-	fb_mqtt_read(mqtt, msg);
-	g_object_unref(msg);
-
-	/* Read another packet if connection wasn't reset in fb_mqtt_read() */
-	if (fb_mqtt_connected(mqtt, FALSE)) {
-		fb_mqtt_read_packet(mqtt);
-	}
-}
-
-static void
-fb_mqtt_read_packet(FbMqtt *mqtt)
-{
-	const guint8 *buf;
-	gsize count = 0;
-	gsize pos;
-	guint mult = 1;
-	guint8 byte;
-	gsize size = 0;
-
-	buf = g_buffered_input_stream_peek_buffer(mqtt->input, &count);
-
-	/* Start at 1 to skip the first byte */
-	pos = 1;
-
-	do {
-		if (pos >= count) {
-			/* Not enough data yet, try again later */
-			g_buffered_input_stream_fill_async(mqtt->input, -1,
-			                                   G_PRIORITY_DEFAULT,
-			                                   mqtt->cancellable,
-			                                   fb_mqtt_cb_fill, mqtt);
-			return;
-		}
-
-		byte = *(buf + pos++);
-
-		size += (byte & 127) * mult;
-		mult *= 128;
-	} while ((byte & 128) != 0);
-
-	/* Add header to size */
-	size += pos;
-
-	g_byte_array_set_size(mqtt->rbuf, size);
-	mqtt->remz = size;
-
-	/* TODO: Use g_input_stream_read_all_async() when available. */
-	/* TODO: Alternately, it would be nice to let the
-	 * FbMqttMessage directly use the GBufferedInputStream
-	 * buffer instead of copying it, provided it's consumed
-	 * before the next read.
-	 */
-	g_input_stream_read_async(G_INPUT_STREAM(mqtt->input), mqtt->rbuf->data,
-	                          mqtt->rbuf->len, G_PRIORITY_DEFAULT,
-	                          mqtt->cancellable, fb_mqtt_cb_read_packet, mqtt);
-}
-
-void
-fb_mqtt_read(FbMqtt *mqtt, FbMqttMessage *msg)
-{
-	FbMqttMessage *nsg;
-	GByteArray *wytes;
-	gchar *str;
-	guint8 chr;
-	guint16 mid;
-
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-
-	fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, msg->bytes,
-	                      "Reading %d (flags: 0x%0X)",
-	                      msg->type, msg->flags);
-
-	switch (msg->type) {
-	case FB_MQTT_MESSAGE_TYPE_CONNACK:
-		if (!fb_mqtt_message_read_byte(msg, NULL) ||
-		    !fb_mqtt_message_read_byte(msg, &chr))
-		{
-			break;
-		}
-
-		if (chr != FB_MQTT_ERROR_SUCCESS) {
-			fb_mqtt_error(mqtt, chr, _("Connection failed (%u)"),
-			              chr);
-			return;
-		}
-
-		mqtt->connected = TRUE;
-		fb_mqtt_ping(mqtt);
-		g_signal_emit_by_name(mqtt, "connect");
-		return;
-
-	case FB_MQTT_MESSAGE_TYPE_PUBLISH:
-		if (!fb_mqtt_message_read_str(msg, &str)) {
-			break;
-		}
-
-		if((msg->flags & FB_MQTT_MESSAGE_FLAG_QOS1) ||
-		   (msg->flags & FB_MQTT_MESSAGE_FLAG_QOS2))
-		{
-			if(msg->flags & FB_MQTT_MESSAGE_FLAG_QOS1) {
-				chr = FB_MQTT_MESSAGE_TYPE_PUBACK;
-			} else {
-				chr = FB_MQTT_MESSAGE_TYPE_PUBREC;
-			}
-
-			if (!fb_mqtt_message_read_mid(msg, &mid)) {
-				g_free(str);
-				break;
-			}
-
-			nsg = fb_mqtt_message_new(chr, 0);
-			fb_mqtt_message_write_u16(nsg, mid);
-			fb_mqtt_write(mqtt, nsg);
-			g_object_unref(nsg);
-		}
-
-		wytes = g_byte_array_new();
-		fb_mqtt_message_read_r(msg, wytes);
-		g_signal_emit_by_name(mqtt, "publish", str, wytes);
-		g_byte_array_free(wytes, TRUE);
-		g_free(str);
-		return;
-
-	case FB_MQTT_MESSAGE_TYPE_PUBREL:
-		if (!fb_mqtt_message_read_mid(msg, &mid)) {
-			break;
-		}
-
-		nsg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_PUBCOMP, 0);
-		fb_mqtt_message_write_u16(nsg, mid); /* Message identifier */
-		fb_mqtt_write(mqtt, nsg);
-		g_object_unref(nsg);
-		return;
-
-	case FB_MQTT_MESSAGE_TYPE_PINGRESP:
-		fb_mqtt_ping(mqtt);
-		return;
-
-	case FB_MQTT_MESSAGE_TYPE_PUBACK:
-	case FB_MQTT_MESSAGE_TYPE_PUBCOMP:
-	case FB_MQTT_MESSAGE_TYPE_SUBACK:
-	case FB_MQTT_MESSAGE_TYPE_UNSUBACK:
-		return;
-
-	default:
-		fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
-		              _("Unknown packet (%u)"), msg->type);
-		return;
-	}
-
-	/* Since no case returned, there was a parse error. */
-	fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL,
-	                      _("Failed to parse message"));
-}
-
-static void
-fb_mqtt_cb_push_bytes(GObject *source, GAsyncResult *res, gpointer data)
-{
-	PurpleQueuedOutputStream *stream = PURPLE_QUEUED_OUTPUT_STREAM(source);
-	FbMqtt *mqtt = data;
-	GError *err = NULL;
-
-	if (!purple_queued_output_stream_push_bytes_finish(stream,
-			res, &err)) {
-		purple_queued_output_stream_clear_queue(stream);
-
-		fb_mqtt_take_error(mqtt, err, _("Failed to write data"));
-		return;
-	}
-}
-
-void
-fb_mqtt_write(FbMqtt *mqtt, FbMqttMessage *msg)
-{
-	const GByteArray *bytes;
-	GBytes *gbytes;
-
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-	g_return_if_fail(FB_IS_MQTT_MESSAGE(msg));
-
-	bytes = fb_mqtt_message_bytes(msg);
-
-	if (G_UNLIKELY(bytes == NULL)) {
-		fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL,
-		                      _("Failed to format data"));
-		return;
-	}
-
-	fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, msg->bytes,
-	                      "Writing %d (flags: 0x%0X)",
-	                      msg->type, msg->flags);
-
- 	/* TODO: Would be nice to refactor this to not require copying bytes */
-	gbytes = g_bytes_new(bytes->data, bytes->len);
-	purple_queued_output_stream_push_bytes_async(mqtt->output, gbytes,
-	                                             G_PRIORITY_DEFAULT,
-	                                             mqtt->cancellable,
-	                                             fb_mqtt_cb_push_bytes, mqtt);
-	g_bytes_unref(gbytes);
-}
-
-static void
-fb_mqtt_cb_open(GObject *source, GAsyncResult *res, gpointer data)
-{
-	FbMqtt *mqtt = data;
-	GSocketConnection *conn;
-	GError *err = NULL;
-
-	conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source),
-			res, &err);
-
-	if (conn == NULL) {
-		fb_mqtt_take_error(mqtt, err, NULL);
-		return;
-	}
-
-	fb_mqtt_timeout_clear(mqtt);
-
-	mqtt->conn = G_IO_STREAM(conn);
-	mqtt->input = G_BUFFERED_INPUT_STREAM(g_buffered_input_stream_new(
-			g_io_stream_get_input_stream(mqtt->conn)));
-	mqtt->output = purple_queued_output_stream_new(
-			g_io_stream_get_output_stream(mqtt->conn));
-
-	fb_mqtt_read_packet(mqtt);
-
-	g_signal_emit_by_name(mqtt, "open");
-}
-
-void
-fb_mqtt_open(FbMqtt *mqtt, const gchar *host, gint port)
-{
-	PurpleAccount *acc;
-	GSocketClient *client;
-	GError *err = NULL;
-
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-
-	acc = purple_connection_get_account(mqtt->gc);
-	fb_mqtt_close(mqtt);
-
-	client = purple_gio_socket_client_new(acc, &err);
-
-	if (client == NULL) {
-		fb_mqtt_take_error(mqtt, err, NULL);
-		return;
-	}
-
-	mqtt->cancellable = g_cancellable_new();
-
-	g_socket_client_set_tls(client, TRUE);
-	g_socket_client_connect_to_host_async(client, host, port,
-	                                      mqtt->cancellable, fb_mqtt_cb_open,
-	                                      mqtt);
-	g_object_unref(client);
-
-	fb_mqtt_timeout(mqtt);
-}
-
-void
-fb_mqtt_connect(FbMqtt *mqtt, guint8 flags, const GByteArray *pload)
-{
-	FbMqttMessage *msg;
-
-	g_return_if_fail(!fb_mqtt_connected(mqtt, FALSE));
-	g_return_if_fail(pload != NULL);
-
-	/* Facebook always sends a CONNACK, use QoS1 */
-	flags |= FB_MQTT_CONNECT_FLAG_QOS1;
-
-	msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_CONNECT, 0);
-	fb_mqtt_message_write_str(msg, FB_MQTT_NAME);   /* Protocol name */
-	fb_mqtt_message_write_byte(msg, FB_MQTT_LEVEL); /* Protocol level */
-	fb_mqtt_message_write_byte(msg, flags);         /* Flags */
-	fb_mqtt_message_write_u16(msg, FB_MQTT_KA);     /* Keep alive */
-
-	fb_mqtt_message_write(msg, pload->data, pload->len);
-	fb_mqtt_write(mqtt, msg);
-
-	fb_mqtt_timeout(mqtt);
-	g_object_unref(msg);
-}
-
-gboolean
-fb_mqtt_connected(FbMqtt *mqtt, gboolean error)
-{
-	gboolean connected;
-
-	g_return_val_if_fail(FB_IS_MQTT(mqtt), FALSE);
-	connected = (mqtt->conn != NULL) && mqtt->connected;
-
-	if (!connected && error) {
-		fb_mqtt_error_literal(mqtt, FB_MQTT_ERROR_GENERAL, _("Not connected"));
-	}
-
-	return connected;
-}
-
-void
-fb_mqtt_disconnect(FbMqtt *mqtt)
-{
-	FbMqttMessage *msg;
-
-	if (G_UNLIKELY(!fb_mqtt_connected(mqtt, FALSE))) {
-		return;
-	}
-
-	msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_DISCONNECT, 0);
-	fb_mqtt_write(mqtt, msg);
-	g_object_unref(msg);
-	fb_mqtt_close(mqtt);
-}
-
-void
-fb_mqtt_publish(FbMqtt *mqtt, const gchar *topic, const GByteArray *pload)
-{
-	FbMqttMessage *msg;
-
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-	g_return_if_fail(fb_mqtt_connected(mqtt, FALSE));
-
-	/* Message identifier not required, but for consistency use QoS1 */
-	msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_PUBLISH,
-	                          FB_MQTT_MESSAGE_FLAG_QOS1);
-
-	fb_mqtt_message_write_str(msg, topic);      /* Message topic */
-	fb_mqtt_message_write_mid(msg, &mqtt->mid); /* Message identifier */
-
-	if (pload != NULL) {
-		fb_mqtt_message_write(msg, pload->data, pload->len);
-	}
-
-	fb_mqtt_write(mqtt, msg);
-	g_object_unref(msg);
-}
-
-void
-fb_mqtt_subscribe(FbMqtt *mqtt, ...)
-{
-	const gchar *topic;
-	FbMqttMessage *msg;
-	guint16 qos;
-	va_list ap;
-
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-	g_return_if_fail(fb_mqtt_connected(mqtt, FALSE));
-
-	/* Facebook requires a message identifier, use QoS1 */
-	msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_SUBSCRIBE,
-	                          FB_MQTT_MESSAGE_FLAG_QOS1);
-
-	fb_mqtt_message_write_mid(msg, &mqtt->mid); /* Message identifier */
-
-	va_start(ap, mqtt);
-
-	while ((topic = va_arg(ap, const gchar*)) != NULL) {
-		qos = va_arg(ap, guint);
-		fb_mqtt_message_write_str(msg, topic);
-		fb_mqtt_message_write_byte(msg, qos);
-	}
-
-	va_end(ap);
-
-	fb_mqtt_write(mqtt, msg);
-	g_object_unref(msg);
-}
-
-void
-fb_mqtt_unsubscribe(FbMqtt *mqtt, const gchar *topic1, ...)
-{
-	const gchar *topic;
-	FbMqttMessage *msg;
-	va_list ap;
-
-	g_return_if_fail(FB_IS_MQTT(mqtt));
-	g_return_if_fail(fb_mqtt_connected(mqtt, FALSE));
-
-	/* Facebook requires a message identifier, use QoS1 */
-	msg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE,
-	                          FB_MQTT_MESSAGE_FLAG_QOS1);
-
-	fb_mqtt_message_write_mid(msg, &mqtt->mid); /* Message identifier */
-	fb_mqtt_message_write_str(msg, topic1);     /* First topic */
-
-	va_start(ap, topic1);
-
-	while ((topic = va_arg(ap, const gchar*)) != NULL) {
-		fb_mqtt_message_write_str(msg, topic); /* Remaining topics */
-	}
-
-	va_end(ap);
-
-	fb_mqtt_write(mqtt, msg);
-	g_object_unref(msg);
-}
-
-FbMqttMessage *
-fb_mqtt_message_new(FbMqttMessageType type, FbMqttMessageFlags flags)
-{
-	FbMqttMessage *msg;
-
-	msg = g_object_new(FB_TYPE_MQTT_MESSAGE, NULL);
-
-	msg->type = type;
-	msg->flags = flags;
-	msg->bytes = g_byte_array_new();
-	msg->local = TRUE;
-
-	return msg;
-}
-
-FbMqttMessage *
-fb_mqtt_message_new_bytes(GByteArray *bytes)
-{
-	FbMqttMessage *msg;
-	guint8 *byte;
-
-	g_return_val_if_fail(bytes != NULL, NULL);
-	g_return_val_if_fail(bytes->len >= 2, NULL);
-
-	msg = g_object_new(FB_TYPE_MQTT_MESSAGE, NULL);
-
-	msg->bytes = bytes;
-	msg->local = FALSE;
-	msg->type = (*bytes->data & 0xF0) >> 4;
-	msg->flags = *bytes->data & 0x0F;
-
-	/* Skip the fixed header */
-	byte = msg->bytes->data + 1;
-	while((*byte & 128) != 0) {
-		byte++;
-	}
-	byte++;
-	msg->offset = byte - bytes->data;
-	msg->pos = msg->offset;
-
-	return msg;
-}
-
-void
-fb_mqtt_message_reset(FbMqttMessage *msg)
-{
-	g_return_if_fail(FB_IS_MQTT_MESSAGE(msg));
-
-	if(msg->offset > 0) {
-		g_byte_array_remove_range(msg->bytes, 0, msg->offset);
-		msg->offset = 0;
-		msg->pos = 0;
-	}
-}
-
-const GByteArray *
-fb_mqtt_message_bytes(FbMqttMessage *msg)
-{
-	guint i;
-	guint8 byte;
-	guint8 sbuf[4];
-	guint32 size;
-
-	g_return_val_if_fail(FB_IS_MQTT_MESSAGE(msg), NULL);
-
-	i = 0;
-	size = msg->bytes->len - msg->offset;
-
-	do {
-		if (G_UNLIKELY(i >= G_N_ELEMENTS(sbuf))) {
-			return NULL;
-		}
-
-		byte = size % 128;
-		size /= 128;
-
-		if (size > 0) {
-			byte |= 128;
-		}
-
-		sbuf[i++] = byte;
-	} while (size > 0);
-
-	fb_mqtt_message_reset(msg);
-	g_byte_array_prepend(msg->bytes, sbuf, i);
-
-	byte = ((msg->type & 0x0F) << 4) | (msg->flags & 0x0F);
-	g_byte_array_prepend(msg->bytes, &byte, sizeof byte);
-
-	msg->pos = (i + 1) * (sizeof byte);
-	return msg->bytes;
-}
-
-gboolean
-fb_mqtt_message_read(FbMqttMessage *msg, gpointer data, guint size)
-{
-	g_return_val_if_fail(FB_IS_MQTT_MESSAGE(msg), FALSE);
-
-	if((msg->pos + size) > msg->bytes->len) {
-		return FALSE;
-	}
-
-	if ((data != NULL) && (size > 0)) {
-		memcpy(data, msg->bytes->data + msg->pos, size);
-	}
-
-	msg->pos += size;
-	return TRUE;
-}
-
-gboolean
-fb_mqtt_message_read_r(FbMqttMessage *msg, GByteArray *bytes)
-{
-	guint size;
-
-	g_return_val_if_fail(FB_IS_MQTT_MESSAGE(msg), FALSE);
-	size = msg->bytes->len - msg->pos;
-
-	if (G_LIKELY(size > 0)) {
-		g_byte_array_append(bytes, msg->bytes->data + msg->pos, size);
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_mqtt_message_read_byte(FbMqttMessage *msg, guint8 *value)
-{
-	return fb_mqtt_message_read(msg, value, sizeof *value);
-}
-
-gboolean
-fb_mqtt_message_read_mid(FbMqttMessage *msg, guint16 *value)
-{
-	return fb_mqtt_message_read_u16(msg, value);
-}
-
-gboolean
-fb_mqtt_message_read_u16(FbMqttMessage *msg, guint16 *value)
-{
-	if (!fb_mqtt_message_read(msg, value, sizeof *value)) {
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		*value = g_ntohs(*value);
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_mqtt_message_read_str(FbMqttMessage *msg, gchar **value)
-{
-	guint8 *data;
-	guint16 size;
-
-	if (!fb_mqtt_message_read_u16(msg, &size)) {
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		data = g_new(guint8, size + 1);
-		data[size] = 0;
-	} else {
-		data = NULL;
-	}
-
-	if (!fb_mqtt_message_read(msg, data, size)) {
-		g_free(data);
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		*value = (gchar *) data;
-	}
-
-	return TRUE;
-}
-
-void
-fb_mqtt_message_write(FbMqttMessage *msg, gconstpointer data, guint size)
-{
-	g_return_if_fail(FB_IS_MQTT_MESSAGE(msg));
-
-	g_byte_array_append(msg->bytes, data, size);
-	msg->pos += size;
-}
-
-void
-fb_mqtt_message_write_byte(FbMqttMessage *msg, guint8 value)
-{
-	fb_mqtt_message_write(msg, &value, sizeof value);
-}
-
-void
-fb_mqtt_message_write_mid(FbMqttMessage *msg, guint16 *value)
-{
-	g_return_if_fail(value != NULL);
-	fb_mqtt_message_write_u16(msg, ++(*value));
-}
-
-void
-fb_mqtt_message_write_u16(FbMqttMessage *msg, guint16 value)
-{
-	value = g_htons(value);
-	fb_mqtt_message_write(msg, &value, sizeof value);
-}
-
-void
-fb_mqtt_message_write_str(FbMqttMessage *msg, const gchar *value)
-{
-	gint16 size;
-
-	g_return_if_fail(value != NULL);
-
-	size = strlen(value);
-	fb_mqtt_message_write_u16(msg, size);
-	fb_mqtt_message_write(msg, value, size);
-}
diff --git a/libpurple/protocols/facebook/resources/facebook.gresource.xml b/libpurple/protocols/facebook/resources/facebook.gresource.xml
deleted file mode 100644
--- a/libpurple/protocols/facebook/resources/facebook.gresource.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<gresources>
-  <gresource prefix="/im/pidgin/libpurple/facebook">
-    <file>icons/16x16/apps/im-facebook.png</file>
-    <file>icons/22x22/apps/im-facebook.png</file>
-    <file>icons/48x48/apps/im-facebook.png</file>
-  </gresource>
-</gresources>
diff --git a/libpurple/protocols/facebook/resources/icons/16x16/apps/im-facebook.png b/libpurple/protocols/facebook/resources/icons/16x16/apps/im-facebook.png
deleted file mode 100644
index bc42cf9b0b3251a61786d99628207d2978969cb2..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/libpurple/protocols/facebook/resources/icons/22x22/apps/im-facebook.png b/libpurple/protocols/facebook/resources/icons/22x22/apps/im-facebook.png
deleted file mode 100644
index 8036b198b302e4bfb794edefab50031a6c31a243..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/libpurple/protocols/facebook/resources/icons/48x48/apps/im-facebook.png b/libpurple/protocols/facebook/resources/icons/48x48/apps/im-facebook.png
deleted file mode 100644
index 2501acaab51de52c513812f2d531f4695abe5c2e..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/libpurple/protocols/facebook/thrift.h b/libpurple/protocols/facebook/thrift.h
deleted file mode 100644
--- a/libpurple/protocols/facebook/thrift.h
+++ /dev/null
@@ -1,553 +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
- */
-
-#ifndef PURPLE_FACEBOOK_THRIFT_H
-#define PURPLE_FACEBOOK_THRIFT_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#define FB_TYPE_THRIFT  fb_thrift_get_type()
-
-/**
- * FbThriftType:
- * @FB_THRIFT_TYPE_STOP: A stopper for certain types.
- * @FB_THRIFT_TYPE_VOID: A void or empty value.
- * @FB_THRIFT_TYPE_BOOL: A boolean (#TRUE or #FALSE).
- * @FB_THRIFT_TYPE_BYTE: A signed 8-bit integer.
- * @FB_THRIFT_TYPE_DOUBLE: A 64-bit floating point number.
- * @FB_THRIFT_TYPE_I16: A signed 16-bit integer.
- * @FB_THRIFT_TYPE_I32: A signed 32-bit integer.
- * @FB_THRIFT_TYPE_I64: A signed 64-bit integer.
- * @FB_THRIFT_TYPE_STRING: A UTF-8 encoded string.
- * @FB_THRIFT_TYPE_STRUCT: A set of typed fields.
- * @FB_THRIFT_TYPE_MAP: A map of unique keys to values.
- * @FB_THRIFT_TYPE_SET: A unique set of values.
- * @FB_THRIFT_TYPE_LIST: A ordered list of values.
- * @FB_THRIFT_TYPE_ENUM: A 32-bit enumerated list.
- * @FB_THRIFT_TYPE_UNKNOWN: An unknown type.
- *
- * The Thrift data types.
- */
-typedef enum
-{
-	FB_THRIFT_TYPE_STOP = 0,
-	FB_THRIFT_TYPE_VOID = 1,
-	FB_THRIFT_TYPE_BOOL = 2,
-	FB_THRIFT_TYPE_BYTE = 3,
-	FB_THRIFT_TYPE_DOUBLE = 4,
-	FB_THRIFT_TYPE_I16 = 6,
-	FB_THRIFT_TYPE_I32 = 8,
-	FB_THRIFT_TYPE_I64 = 10,
-	FB_THRIFT_TYPE_STRING = 11,
-	FB_THRIFT_TYPE_STRUCT = 12,
-	FB_THRIFT_TYPE_MAP = 13,
-	FB_THRIFT_TYPE_SET = 14,
-	FB_THRIFT_TYPE_LIST = 15,
-	FB_THRIFT_TYPE_ENUM = 16,
-
-	FB_THRIFT_TYPE_UNKNOWN
-} FbThriftType;
-
-G_DECLARE_FINAL_TYPE(FbThrift, fb_thrift, FB, THRIFT, GObject)
-
-/**
- * fb_thrift_new:
- * @bytes: The #GByteArray to read or write.
- * @offset: The offset in bytes of the data in @bytes.
- *
- * Creates a new #FbThrift. The returned #FbThrift should be freed with
- * #g_object_unref() when no longer needed. This will optionally use a
- * #GByteArray at an offset, rather than a newly created and internal
- * #GByteArray.
- *
- * Returns: The new #FbThrift.
- */
-FbThrift *
-fb_thrift_new(GByteArray *bytes, guint offset);
-
-/**
- * fb_thrift_get_bytes:
- * @thft: The #FbThrift.
- *
- * Gets the underlying #GByteArray of an #FbThrift.
- *
- * Returns: The #GByteArray.
- */
-const GByteArray *
-fb_thrift_get_bytes(FbThrift *thft);
-
-/**
- * fb_thrift_get_pos:
- * @thft: The #FbThrift.
- *
- * Gets the cursor position of an #FbThrift.
- *
- * Returns: The cursor position.
- */
-guint
-fb_thrift_get_pos(FbThrift *thft);
-
-/**
- * fb_thrift_set_pos:
- * @thft: The #FbThrift.
- * @pos: The position.
- *
- * Sets the cursor position of an #FbThrift.
- */
-void
-fb_thrift_set_pos(FbThrift *thft, guint pos);
-
-/**
- * fb_thrift_reset:
- * @thft: The #FbThrift.
- *
- * Resets the cursor position of an #FbThrift.
- */
-void
-fb_thrift_reset(FbThrift *thft);
-
-/**
- * fb_thrift_read:
- * @thft: The #FbThrift.
- * @data: The data buffer.
- * @size: The size of @buffer.
- *
- * Reads data from the #FbThrift into a buffer. If @data is #NULL, this
- * will simply advance the cursor position.
- *
- * Returns: #TRUE if the data was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read(FbThrift *thft, gpointer data, guint size);
-
-/**
- * fb_thrift_read_bool:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads a boolean value from the #FbThrift. If @value is #NULL, this
- * will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_bool(FbThrift *thft, gboolean *value);
-
-/**
- * fb_thrift_read_byte:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads an 8-bit integer value from the #FbThrift. If @value is #NULL,
- * this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_byte(FbThrift *thft, guint8 *value);
-
-/**
- * fb_thrift_read_dbl:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads a 64-bit floating point value from the #FbThrift. If @value
- * is #NULL, this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_dbl(FbThrift *thft, gdouble *value);
-
-/**
- * fb_thrift_read_i16:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads a signed 16-bit integer value from the #FbThrift. This will
- * convert the integer from the zig-zag format. If @value is #NULL,
- * this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_i16(FbThrift *thft, gint16 *value);
-
-/**
- * fb_thrift_read_vi16:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads a 16-bit integer value from the #FbThrift. This reads the raw
- * integer value without converting it from the zig-zag format. If
- * @value is #NULL, this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_vi16(FbThrift *thft, guint16 *value);
-
-/**
- * fb_thrift_read_i32:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads a signed 32-bit integer value from the #FbThrift. This will
- * convert the integer from the zig-zag format. If @value is #NULL,
- * this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_i32(FbThrift *thft, gint32 *value);
-
-/**
- * fb_thrift_read_vi32:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads a 32-bit integer value from the #FbThrift. This reads the raw
- * integer value without converting it from the zig-zag format. If
- * @value is #NULL, this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_vi32(FbThrift *thft, guint32 *value);
-
-/**
- * fb_thrift_read_i64:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads a signed 64-bit integer value from the #FbThrift. This will
- * convert the integer from the zig-zag format. If @value is #NULL,
- * this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_i64(FbThrift *thft, gint64 *value);
-
-/**
- * fb_thrift_read_vi64:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads a 64-bit integer value from the #FbThrift. This reads the raw
- * integer value without converting it from the zig-zag format. If
- * @value is #NULL, this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_vi64(FbThrift *thft, guint64 *value);
-
-/**
- * fb_thrift_read_str:
- * @thft: The #FbThrift.
- * @value: The return location for the value or #NULL.
- *
- * Reads a string value from the #FbThrift. The value returned to
- * @value should be freed with #g_free() when no longer needed. If
- * @value is #NULL, this will simply advance the cursor position.
- *
- * Returns: #TRUE if the value was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_str(FbThrift *thft, gchar **value);
-
-/**
- * fb_thrift_read_field:
- * @thft: The #FbThrift.
- * @type: The return location for the #FbThriftType.
- * @id: The return location for the identifier.
- * @lastid: The identifier of the previous field.
- *
- * Reads a field header from the #FbThrift.
- *
- * Returns: #TRUE if the field header was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_field(FbThrift *thft, FbThriftType *type, gint16 *id,
-					 gint16 lastid);
-
-/**
- * fb_thrift_read_stop:
- * @thft: The #FbThrift.
- *
- * Reads a field stop from the #FbThrift.
- *
- * Returns: #TRUE if the field stop was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_stop(FbThrift *thft);
-
-/**
- * fb_thrift_read_isstop:
- * @thft: The #FbThrift.
- *
- * Determines if the next byte of the #FbThrift is a field stop.
- *
- * Returns: #TRUE if the next byte is a field stop, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_isstop(FbThrift *thft);
-
-/**
- * fb_thrift_read_list:
- * @thft: The #FbThrift.
- * @type: The return location for the #FbThriftType.
- * @size: The return location for the size.
- *
- * Reads a list header from the #FbThrift.
- *
- * Returns: #TRUE if the list header was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_list(FbThrift *thft, FbThriftType *type, guint *size);
-
-/**
- * fb_thrift_read_map:
- * @thft: The #FbThrift.
- * @ktype: The return location for the key #FbThriftType.
- * @vtype: The return location for the value #FbThriftType.
- * @size: The return location for the size.
- *
- * Reads a map header from the #FbThrift.
- *
- * Returns: #TRUE if the map header was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_map(FbThrift *thft, FbThriftType *ktype, FbThriftType *vtype,
-                   guint *size);
-
-/**
- * fb_thrift_read_set:
- * @thft: The #FbThrift.
- * @type: The return location for the #FbThriftType.
- * @size: The return location for the size.
- *
- * Reads a set header from the #FbThrift.
- *
- * Returns: #TRUE if the set header was read, otherwise #FALSE.
- */
-gboolean
-fb_thrift_read_set(FbThrift *thft, FbThriftType *type, guint *size);
-
-/**
- * fb_thrift_write:
- * @thft: The #FbThrift.
- * @data: The data buffer.
- * @size: The size of @buffer.
- *
- * Writes data to the #FbThrift.
- */
-void
-fb_thrift_write(FbThrift *thft, gconstpointer data, guint size);
-
-/**
- * fb_thrift_write_bool:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes a boolean value to the #FbThrift.
- */
-void
-fb_thrift_write_bool(FbThrift *thft, gboolean value);
-
-/**
- * fb_thrift_write_byte:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes an 8-bit integer value to the #FbThrift.
- */
-void
-fb_thrift_write_byte(FbThrift *thft, guint8 value);
-
-/**
- * fb_thrift_write_dbl:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes a 64-bit floating point value to the #FbThrift.
- */
-void
-fb_thrift_write_dbl(FbThrift *thft, gdouble value);
-
-/**
- * fb_thrift_write_i16:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes a signed 16-bit integer value to the #FbThrift. This will
- * convert the integer to the zig-zag format.
- */
-void
-fb_thrift_write_i16(FbThrift *thft, gint16 value);
-
-/**
- * fb_thrift_write_vi16:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes a 16-bit integer value to the #FbThrift. This writes the raw
- * integer value without converting it to the zig-zag format.
- */
-void
-fb_thrift_write_vi16(FbThrift *thft, guint16 value);
-
-/**
- * fb_thrift_write_i32:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes a signed 32-bit integer value to the #FbThrift. This will
- * convert the integer to the zig-zag format.
- */
-void
-fb_thrift_write_i32(FbThrift *thft, gint32 value);
-
-/**
- * fb_thrift_write_vi32:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes a 32-bit integer value to the #FbThrift. This writes the raw
- * integer value without converting it to the zig-zag format.
- */
-void
-fb_thrift_write_vi32(FbThrift *thft, guint32 value);
-
-/**
- * fb_thrift_write_i64:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes a signed 64-bit integer value to the #FbThrift. This will
- * convert the integer to the zig-zag format.
- */
-void
-fb_thrift_write_i64(FbThrift *thft, gint64 value);
-
-/**
- * fb_thrift_write_vi64:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes a 64-bit integer value to the #FbThrift. This writes the raw
- * integer value without converting it to the zig-zag format.
- */
-void
-fb_thrift_write_vi64(FbThrift *thft, guint64 value);
-
-/**
- * fb_thrift_write_str:
- * @thft: The #FbThrift.
- * @value: The value.
- *
- * Writes a string value to the #FbThrift.
- */
-void
-fb_thrift_write_str(FbThrift *thft, const gchar *value);
-
-/**
- * fb_thrift_write_field:
- * @thft: The #FbThrift.
- * @type: The #FbThriftType.
- * @id: The identifier.
- * @lastid: The identifier of the previous field.
- *
- * Writes a field header to the #FbThrift.
- */
-void
-fb_thrift_write_field(FbThrift *thft, FbThriftType type, gint16 id,
-					  gint16 lastid);
-
-/**
- * fb_thrift_write_stop:
- * @thft: The #FbThrift.
- *
- * Writes a field stop to the #FbThrift.
- */
-void
-fb_thrift_write_stop(FbThrift *thft);
-
-/**
- * fb_thrift_write_list:
- * @thft: The #FbThrift.
- * @type: The #FbThriftType.
- * @size: The size.
- *
- * Writes a list header to the #FbThrift.
- */
-void
-fb_thrift_write_list(FbThrift *thft, FbThriftType type, guint size);
-
-/**
- * fb_thrift_write_map:
- * @thft: The #FbThrift.
- * @ktype: The key #FbThriftType.
- * @vtype: The value #FbThriftType.
- * @size: The size.
- *
- * Writes a map header to the #FbThrift.
- */
-void
-fb_thrift_write_map(FbThrift *thft, FbThriftType ktype, FbThriftType vtype,
-                    guint size);
-
-/**
- * fb_thrift_write_set:
- * @thft: The #FbThrift.
- * @type: The #FbThriftType.
- * @size: The size.
- *
- * Writes a set header to the #FbThrift.
- */
-void
-fb_thrift_write_set(FbThrift *thft, FbThriftType type, guint size);
-
-/**
- * fb_thrift_t2ct:
- * @type: The #FbThriftType.
- *
- * Converts a #FbThriftType to a compact type.
- *
- * Return: The equivalent compact type.
- */
-guint8
-fb_thrift_t2ct(FbThriftType type);
-
-/**
- * fb_thrift_ct2t:
- * @type: The compact type.
- *
- * Converts a compact type to an #FbThriftType.
- *
- * Return: The equivalent #FbThriftType.
- */
-FbThriftType
-fb_thrift_ct2t(guint8 type);
-
-#endif /* PURPLE_FACEBOOK_THRIFT_H */
diff --git a/libpurple/protocols/facebook/thrift.c b/libpurple/protocols/facebook/thrift.c
deleted file mode 100644
--- a/libpurple/protocols/facebook/thrift.c
+++ /dev/null
@@ -1,675 +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 <string.h>
-
-#include "thrift.h"
-
-/**
- * FbThrift:
- *
- * Represents a reader/writer for compact Thrift data.
- */
-struct _FbThrift {
-	GObject parent;
-
-	GByteArray *bytes;
-	gboolean internal;
-	guint offset;
-	guint pos;
-	guint lastbool;
-};
-
-G_DEFINE_TYPE(FbThrift, fb_thrift, G_TYPE_OBJECT);
-
-static void
-fb_thrift_dispose(GObject *obj)
-{
-	FbThrift* thft = FB_THRIFT(obj);
-
-	if (thft->internal) {
-		g_byte_array_free(thft->bytes, TRUE);
-		thft->bytes = NULL;
-		thft->internal = FALSE;
-	}
-}
-
-static void
-fb_thrift_class_init(FbThriftClass *klass)
-{
-	GObjectClass *gklass = G_OBJECT_CLASS(klass);
-
-	gklass->dispose = fb_thrift_dispose;
-}
-
-static void
-fb_thrift_init(G_GNUC_UNUSED FbThrift *thft)
-{
-}
-
-FbThrift *
-fb_thrift_new(GByteArray *bytes, guint offset)
-{
-	FbThrift *thft;
-
-	thft = g_object_new(FB_TYPE_THRIFT, NULL);
-
-	if (bytes != NULL) {
-		thft->bytes = bytes;
-		thft->offset = offset;
-		thft->pos = offset;
-	} else {
-		thft->bytes = g_byte_array_new();
-		thft->internal = TRUE;
-	}
-
-	return thft;
-}
-
-const GByteArray *
-fb_thrift_get_bytes(FbThrift *thft)
-{
-	g_return_val_if_fail(FB_IS_THRIFT(thft), NULL);
-
-	return thft->bytes;
-}
-
-guint
-fb_thrift_get_pos(FbThrift *thft)
-{
-	g_return_val_if_fail(FB_IS_THRIFT(thft), 0);
-
-	return thft->pos;
-}
-
-void
-fb_thrift_set_pos(FbThrift *thft, guint pos)
-{
-	g_return_if_fail(FB_IS_THRIFT(thft));
-
-	thft->pos = pos;
-}
-
-void
-fb_thrift_reset(FbThrift *thft)
-{
-	g_return_if_fail(FB_IS_THRIFT(thft));
-
-	thft->pos = thft->offset;
-}
-
-gboolean
-fb_thrift_read(FbThrift *thft, gpointer data, guint size)
-{
-	g_return_val_if_fail(FB_IS_THRIFT(thft), FALSE);
-
-	if ((thft->pos + size) > thft->bytes->len) {
-		return FALSE;
-	}
-
-	if ((data != NULL) && (size > 0)) {
-		memcpy(data, thft->bytes->data + thft->pos, size);
-	}
-
-	thft->pos += size;
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_bool(FbThrift *thft, gboolean *value)
-{
-	guint8 byte;
-
-	g_return_val_if_fail(FB_IS_THRIFT(thft), FALSE);
-
-	if ((thft->lastbool & 0x03) != 0x01) {
-		if (!fb_thrift_read_byte(thft, &byte)) {
-			return FALSE;
-		}
-
-		if (value != NULL) {
-			*value = (byte & 0x0F) == 0x01;
-		}
-
-		thft->lastbool = 0;
-		return TRUE;
-	}
-
-	if (value != NULL) {
-		*value = ((thft->lastbool & 0x04) >> 2) != 0;
-	}
-
-	thft->lastbool = 0;
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_byte(FbThrift *thft, guint8 *value)
-{
-	return fb_thrift_read(thft, value, sizeof *value);
-}
-
-gboolean
-fb_thrift_read_dbl(FbThrift *thft, gdouble *value)
-{
-	gint64 i64;
-
-	/* Almost always 8, but check anyways */
-	static const gsize size = MIN(sizeof value, sizeof i64);
-
-	if (!fb_thrift_read_i64(thft, &i64)) {
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		memcpy(value, &i64, size);
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_i16(FbThrift *thft, gint16 *value)
-{
-	gint64 i64;
-
-	if (!fb_thrift_read_i64(thft, &i64)) {
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		*value = i64;
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_vi16(FbThrift *thft, guint16 *value)
-{
-	guint64 u64;
-
-	if (!fb_thrift_read_vi64(thft, &u64)) {
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		*value = u64;
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_i32(FbThrift *thft, gint32 *value)
-{
-	gint64 i64;
-
-	if (!fb_thrift_read_i64(thft, &i64)) {
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		*value = i64;
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_vi32(FbThrift *thft, guint32 *value)
-{
-	guint64 u64;
-
-	if (!fb_thrift_read_vi64(thft, &u64)) {
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		*value = u64;
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_i64(FbThrift *thft, gint64 *value)
-{
-	guint64 u64;
-
-	if (!fb_thrift_read_vi64(thft, &u64)) {
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		/* Convert from zigzag to integer */
-		*value = (u64 >> 0x01) ^ -(u64 & 0x01);
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_vi64(FbThrift *thft, guint64 *value)
-{
-	guint i = 0;
-	guint8 byte;
-	guint64 u64 = 0;
-
-	do {
-		if (!fb_thrift_read_byte(thft, &byte)) {
-			return FALSE;
-		}
-
-		u64 |= ((guint64) (byte & 0x7F)) << i;
-		i += 7;
-	} while ((byte & 0x80) == 0x80);
-
-	if (value != NULL) {
-		*value = u64;
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_str(FbThrift *thft, gchar **value)
-{
-	guint8 *data;
-	guint32 size;
-
-	if (!fb_thrift_read_vi32(thft, &size)) {
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		data = g_new(guint8, size + 1);
-		data[size] = 0;
-	} else {
-		data = NULL;
-	}
-
-	if (!fb_thrift_read(thft, data, size)) {
-		g_free(data);
-		return FALSE;
-	}
-
-	if (value != NULL) {
-		*value = (gchar *) data;
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_field(FbThrift *thft, FbThriftType *type, gint16 *id,
-					 gint16 lastid)
-{
-	gint16 i16;
-	guint8 byte;
-
-	g_return_val_if_fail(FB_IS_THRIFT(thft), FALSE);
-	g_return_val_if_fail(type != NULL, FALSE);
-	g_return_val_if_fail(id != NULL, FALSE);
-
-	if (!fb_thrift_read_byte(thft, &byte)) {
-		return FALSE;
-	}
-
-	if (byte == FB_THRIFT_TYPE_STOP) {
-		*type = FB_THRIFT_TYPE_STOP;
-		return FALSE;
-	}
-
-	*type = fb_thrift_ct2t(byte & 0x0F);
-	i16 = (byte & 0xF0) >> 4;
-
-	if (i16 == 0) {
-		if (!fb_thrift_read_i16(thft, id)) {
-			return FALSE;
-		}
-	} else {
-		*id = lastid + i16;
-	}
-
-	if (*type == FB_THRIFT_TYPE_BOOL) {
-		thft->lastbool = 0x01;
-
-		if ((byte & 0x0F) == 0x01) {
-			thft->lastbool |= 0x01 << 2;
-		}
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_stop(FbThrift *thft)
-{
-	guint8 byte;
-
-	return fb_thrift_read_byte(thft, &byte) &&
-	       (byte == FB_THRIFT_TYPE_STOP);
-}
-
-gboolean
-fb_thrift_read_isstop(FbThrift *thft)
-{
-	guint8 byte;
-
-	g_return_val_if_fail(FB_IS_THRIFT(thft), FALSE);
-
-	if (!fb_thrift_read_byte(thft, &byte)) {
-		return FALSE;
-	}
-
-	thft->pos--;
-	return byte == FB_THRIFT_TYPE_STOP;
-}
-
-gboolean
-fb_thrift_read_list(FbThrift *thft, FbThriftType *type, guint *size)
-{
-	guint8 byte;
-	guint32 u32;
-
-	g_return_val_if_fail(type != NULL, FALSE);
-	g_return_val_if_fail(size != NULL, FALSE);
-
-	if (!fb_thrift_read_byte(thft, &byte)) {
-		return FALSE;
-	}
-
-	*type = fb_thrift_ct2t(byte & 0x0F);
-	*size = (byte & 0xF0) >> 4;
-
-	if (*size == 0x0F) {
-		if (!fb_thrift_read_vi32(thft, &u32)) {
-			return FALSE;
-		}
-
-		*size = u32;
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_map(FbThrift *thft, FbThriftType *ktype, FbThriftType *vtype,
-                   guint *size)
-{
-	gint32 i32;
-	guint8 byte;
-
-	g_return_val_if_fail(ktype != NULL, FALSE);
-	g_return_val_if_fail(vtype != NULL, FALSE);
-	g_return_val_if_fail(size != NULL, FALSE);
-
-	if (!fb_thrift_read_i32(thft, &i32)) {
-		return FALSE;
-	}
-
-	if (i32 != 0) {
-		if (!fb_thrift_read_byte(thft, &byte)) {
-			return FALSE;
-		}
-
-		*ktype = fb_thrift_ct2t((byte & 0xF0) >> 4);
-		*vtype = fb_thrift_ct2t(byte & 0x0F);
-	} else {
-		*ktype = 0;
-		*vtype = 0;
-	}
-
-	*size = i32;
-	return TRUE;
-}
-
-gboolean
-fb_thrift_read_set(FbThrift *thft, FbThriftType *type, guint *size)
-{
-	return fb_thrift_read_list(thft, type, size);
-}
-
-void
-fb_thrift_write(FbThrift *thft, gconstpointer data, guint size)
-{
-	g_return_if_fail(FB_IS_THRIFT(thft));
-
-	g_byte_array_append(thft->bytes, data, size);
-	thft->pos += size;
-}
-
-void
-fb_thrift_write_bool(FbThrift *thft, gboolean value)
-{
-	guint pos;
-
-	g_return_if_fail(FB_IS_THRIFT(thft));
-
-	if ((thft->lastbool & 0x03) != 0x02) {
-		fb_thrift_write_byte(thft, value ? 0x01 : 0x02);
-		return;
-	}
-
-	pos = thft->lastbool >> 3;
-	thft->lastbool = 0;
-
-	if ((pos >= thft->offset) && (pos < thft->bytes->len)) {
-		thft->bytes->data[pos] &= ~0x0F;
-		thft->bytes->data[pos] |= value ? 0x01 : 0x02;
-	}
-}
-
-void
-fb_thrift_write_byte(FbThrift *thft, guint8 value)
-{
-	fb_thrift_write(thft, &value, sizeof value);
-}
-
-void
-fb_thrift_write_dbl(FbThrift *thft, gdouble value)
-{
-	gint64 i64;
-
-	/* Almost always 8, but check anyways */
-	static const gsize size = MIN(sizeof value, sizeof i64);
-
-	memcpy(&i64, &value, size);
-	fb_thrift_write_i64(thft, i64);
-}
-
-void
-fb_thrift_write_i16(FbThrift *thft, gint16 value)
-{
-	fb_thrift_write_i64(thft, value);
-}
-
-void
-fb_thrift_write_vi16(FbThrift *thft, guint16 value)
-{
-	fb_thrift_write_vi64(thft, value);
-}
-
-void
-fb_thrift_write_i32(FbThrift *thft, gint32 value)
-{
-	value = (value << 1) ^ (value >> 31);
-	fb_thrift_write_vi64(thft, value);
-}
-
-void
-fb_thrift_write_vi32(FbThrift *thft, guint32 value)
-{
-	fb_thrift_write_vi64(thft, value);
-}
-
-void
-fb_thrift_write_i64(FbThrift *thft, gint64 value)
-{
-	value = (value << 1) ^ (value >> 63);
-	fb_thrift_write_vi64(thft, value);
-}
-
-void
-fb_thrift_write_vi64(FbThrift *thft, guint64 value)
-{
-	gboolean last;
-	guint8 byte;
-
-	do {
-		last = (value & ~0x7F) == 0;
-		byte = value & 0x7F;
-
-		if (!last) {
-			byte |= 0x80;
-			value >>= 7;
-		}
-
-		fb_thrift_write_byte(thft, byte);
-	} while (!last);
-}
-
-void
-fb_thrift_write_str(FbThrift *thft, const gchar *value)
-{
-	guint32 size;
-
-	g_return_if_fail(value != NULL);
-
-	size = strlen(value);
-	fb_thrift_write_vi32(thft, size);
-	fb_thrift_write(thft, value, size);
-}
-
-void
-fb_thrift_write_field(FbThrift *thft, FbThriftType type, gint16 id,
-					  gint16 lastid)
-{
-	gint16 diff;
-
-	g_return_if_fail(FB_IS_THRIFT(thft));
-
-	if (type == FB_THRIFT_TYPE_BOOL) {
-		thft->lastbool = (thft->pos << 3) | 0x02;
-	}
-
-	type = fb_thrift_t2ct(type);
-	diff = id - lastid;
-
-	if ((id <= lastid) || (diff > 0x0F)) {
-		fb_thrift_write_byte(thft, type);
-		fb_thrift_write_i16(thft, id);
-	} else {
-		fb_thrift_write_byte(thft, (diff << 4) | type);
-	}
-}
-
-void
-fb_thrift_write_stop(FbThrift *thft)
-{
-	fb_thrift_write_byte(thft, FB_THRIFT_TYPE_STOP);
-}
-
-void
-fb_thrift_write_list(FbThrift *thft, FbThriftType type, guint size)
-{
-	type = fb_thrift_t2ct(type);
-
-	if (size <= 14) {
-		fb_thrift_write_byte(thft, (size << 4) | type);
-		return;
-	}
-
-	fb_thrift_write_vi32(thft, size);
-	fb_thrift_write_byte(thft, 0xF0 | type);
-}
-
-void
-fb_thrift_write_map(FbThrift *thft, FbThriftType ktype, FbThriftType vtype,
-                    guint size)
-{
-	if (size == 0) {
-		fb_thrift_write_byte(thft, 0);
-		return;
-	}
-
-	ktype = fb_thrift_t2ct(ktype);
-	vtype = fb_thrift_t2ct(vtype);
-
-	fb_thrift_write_vi32(thft, size);
-	fb_thrift_write_byte(thft, (ktype << 4) | vtype);
-}
-
-void
-fb_thrift_write_set(FbThrift *thft, FbThriftType type, guint size)
-{
-	fb_thrift_write_list(thft, type, size);
-}
-
-guint8
-fb_thrift_t2ct(FbThriftType type)
-{
-	static const guint8 types[] = {
-		[FB_THRIFT_TYPE_STOP]   = 0,
-		[FB_THRIFT_TYPE_VOID]   = 0,
-		[FB_THRIFT_TYPE_BOOL]   = 2,
-		[FB_THRIFT_TYPE_BYTE]   = 3,
-		[FB_THRIFT_TYPE_DOUBLE] = 7,
-		[5]                     = 0,
-		[FB_THRIFT_TYPE_I16]    = 4,
-		[7]                     = 0,
-		[FB_THRIFT_TYPE_I32]    = 5,
-		[9]                     = 0,
-		[FB_THRIFT_TYPE_I64]    = 6,
-		[FB_THRIFT_TYPE_STRING] = 8,
-		[FB_THRIFT_TYPE_STRUCT] = 12,
-		[FB_THRIFT_TYPE_MAP]    = 11,
-		[FB_THRIFT_TYPE_SET]    = 10,
-		[FB_THRIFT_TYPE_LIST]   = 9
-	};
-
-	g_return_val_if_fail(type < G_N_ELEMENTS(types), 0);
-	return types[type];
-}
-
-FbThriftType
-fb_thrift_ct2t(guint8 type)
-{
-	static const guint8 types[] = {
-		[0]  = FB_THRIFT_TYPE_STOP,
-		[1]  = FB_THRIFT_TYPE_BOOL,
-		[2]  = FB_THRIFT_TYPE_BOOL,
-		[3]  = FB_THRIFT_TYPE_BYTE,
-		[4]  = FB_THRIFT_TYPE_I16,
-		[5]  = FB_THRIFT_TYPE_I32,
-		[6]  = FB_THRIFT_TYPE_I64,
-		[7]  = FB_THRIFT_TYPE_DOUBLE,
-		[8]  = FB_THRIFT_TYPE_STRING,
-		[9]  = FB_THRIFT_TYPE_LIST,
-		[10] = FB_THRIFT_TYPE_SET,
-		[11] = FB_THRIFT_TYPE_MAP,
-		[12] = FB_THRIFT_TYPE_STRUCT
-	};
-
-	g_return_val_if_fail(type < G_N_ELEMENTS(types), 0);
-	return types[type];
-}
diff --git a/libpurple/protocols/facebook/util.h b/libpurple/protocols/facebook/util.h
deleted file mode 100644
--- a/libpurple/protocols/facebook/util.h
+++ /dev/null
@@ -1,335 +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
- */
-
-#ifndef PURPLE_FACEBOOK_UTIL_H
-#define PURPLE_FACEBOOK_UTIL_H
-
-#include <glib.h>
-
-#include <purple.h>
-
-/**
- * FB_UTIL_DEBUG_INFO:
- *
- * Shortcut #PurpleDebugLevel for unsafe and verbose info messages.
- */
-#define FB_UTIL_DEBUG_INFO ( \
-		PURPLE_DEBUG_INFO | \
-		FB_UTIL_DEBUG_FLAG_UNSAFE | \
-		FB_UTIL_DEBUG_FLAG_VERBOSE \
-	)
-
-/**
- * FB_UTIL_ERROR:
- *
- * The #GQuark of the domain of utility errors.
- */
-#define FB_UTIL_ERROR  fb_util_error_quark()
-
-/**
- * FbUtilRequestBuddyFunc:
- * @buddies: The list of #PurpleBuddy's.
- * @data: The user-defined data.
- *
- * The callback for requested buddies.
- */
-typedef void (*FbUtilRequestBuddyFunc) (GSList *buddies, gpointer data);
-
-/**
- * FbUtilDebugFlags:
- * @FB_UTIL_DEBUG_FLAG_UNSAFE: The message is unsafe.
- * @FB_UTIL_DEBUG_FLAG_VERBOSE: The message is verbose.
- * @FB_UTIL_DEBUG_FLAG_ALL: All of the flags.
- *
- * The debugging message flags. These flags are inserted on top of
- * a #PurpleDebugLevel.
- */
-typedef enum
-{
-	FB_UTIL_DEBUG_FLAG_UNSAFE = 1 << 25,
-	FB_UTIL_DEBUG_FLAG_VERBOSE = 1 << 26,
-	FB_UTIL_DEBUG_FLAG_ALL = 3 << 25
-} FbUtilDebugFlags;
-
-/**
- * FbUtilError:
- * @FB_UTIL_ERROR_GENERAL: General failure.
- *
- * The error codes for the #FB_UTIL_ERROR domain.
- */
-typedef enum
-{
-	FB_UTIL_ERROR_GENERAL
-} FbUtilError;
-
-/**
- * fb_util_error_quark:
- *
- * Gets the #GQuark of the domain of utility errors.
- *
- * Returns: The #GQuark of the domain.
- */
-GQuark
-fb_util_error_quark(void);
-
-/**
- * fb_util_account_find_buddy:
- * @acct: The #PurpleAccount.
- * @chat: The #PurpleChatConversation.
- * @name: The name of the buddy.
- * @error: The return location for the #GError or #NULL.
- *
- * Finds a buddy by their name or alias.
- *
- * Returns: (transfer none): The #PurpleBuddy if found, otherwise #NULL.
- */
-PurpleBuddy *
-fb_util_account_find_buddy(PurpleAccount *acct, PurpleChatConversation *chat,
-                           const gchar *name, GError **error);
-
-/**
- * fb_util_debug:
- * @level: The #PurpleDebugLevel.
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Logs a debugging message. If the messages is unsafe or verbose,
- * apply the appropriate #FbUtilDebugFlags.
- */
-void
-fb_util_debug(PurpleDebugLevel level, const gchar *format, ...)
-              G_GNUC_PRINTF(2, 3);
-
-/**
- * fb_util_vdebug:
- * @level: The #PurpleDebugLevel.
- * @format: The format string literal.
- * @ap: The #va_list.
- *
- * Logs a debugging message. If the messages is unsafe or verbose,
- * apply the appropriate #FbUtilDebugFlags.
- */
-void
-fb_util_vdebug(PurpleDebugLevel level, const gchar *format, va_list ap);
-
-/**
- * fb_util_debug_misc:
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Logs a debugging message with the level of #PURPLE_DEBUG_MISC.
- */
-void
-fb_util_debug_misc(const gchar *format, ...)
-                   G_GNUC_PRINTF(1, 2);
-
-/**
- * fb_util_debug_info:
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Logs a debugging message with the level of #PURPLE_DEBUG_INFO.
- */
-void
-fb_util_debug_info(const gchar *format, ...)
-                   G_GNUC_PRINTF(1, 2);
-
-/**
- * fb_util_debug_warning:
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Logs a debugging message with the level of #PURPLE_DEBUG_WARNING.
- */
-void
-fb_util_debug_warning(const gchar *format, ...)
-                      G_GNUC_PRINTF(1, 2);
-
-/**
- * fb_util_debug_error:
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Logs a debugging message with the level of #PURPLE_DEBUG_ERROR.
- */
-void
-fb_util_debug_error(const gchar *format, ...)
-                    G_GNUC_PRINTF(1, 2);
-
-/**
- * fb_util_debug_fatal:
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Logs a debugging message with the level of #PURPLE_DEBUG_FATAL.
- */
-void
-fb_util_debug_fatal(const gchar *format, ...)
-                    G_GNUC_PRINTF(1, 2);
-
-/**
- * fb_util_debug_hexdump:
- * @level: The #PurpleDebugLevel.
- * @bytes: The #GByteArray.
- * @format: The format string literal.
- * @...: The arguments for @format.
- *
- * Logs a hexdump of a #GByteArray. If the messages is unsafe or
- * verbose, apply the appropriate #FbUtilDebugFlags.
- */
-void
-fb_util_debug_hexdump(PurpleDebugLevel level, const GByteArray *bytes,
-                      const gchar *format, ...)
-                      G_GNUC_PRINTF(3, 4);
-
-/**
- * fb_util_get_locale:
- *
- * Gets the locale string (ex: en_US) from the system. The returned
- * string should be freed with #g_free() when no longer needed.
- *
- * Returns: The locale string.
- */
-gchar *
-fb_util_get_locale(void);
-
-/**
- * fb_util_rand_alnum:
- * @len: The length of the string.
- *
- * Gets a random alphanumeric (A-Za-z0-9) string. This function should
- * *not* be relied on for cryptographic operations. The returned string
- * should be freed with #g_free() when no longer needed.
- *
- * Returns: The alphanumeric string.
- */
-gchar *
-fb_util_rand_alnum(guint len);
-
-/**
- * fb_util_request_buddy:
- * @gc: The #PurpleConnection.
- * @title: The title of the message or #NULL.
- * @primary: The main point of the message or #NULL.
- * @secondary: The secondary information or #NULL.
- * @select: (element-type PurpleBuddy): A #GSList of selected buddies or #NULL.
- * @multi: #TRUE to for multiple buddy selections, otherwise #FALSE.
- * @ok_cb: (scope async): The callback for the `OK` button or #NULL.
- * @cancel_cb: (scope async): The callback for the `Cancel` button or #NULL.
- * @data: The user-defined data.
- *
- * Displays a buddy list selection form.
- *
- * Returns: The UI-specific handle.
- */
-gpointer
-fb_util_request_buddy(PurpleConnection *gc, const gchar *title,
-                      const gchar *primary, const gchar *secondary,
-                      GSList *select, gboolean multi, GCallback ok_cb,
-                      GCallback cancel_cb, gpointer data);
-
-/**
- * fb_util_serv_got_im:
- * @gc: The #PurpleConnection.
- * @who: The message sender or receiver.
- * @text: The message text.
- * @flags: The #PurpleMessageFlags.
- * @timestamp: The message timestamp.
- *
- * Handles an incoming IM message. This function is special in that it
- * handles self messages. This function determines the direction of the
- * message from the #PurpleMessageFlags.
- */
-void
-fb_util_serv_got_im(PurpleConnection *gc, const gchar *who, const gchar *text,
-                    PurpleMessageFlags flags, guint64 timestamp);
-
-/**
- * fb_util_serv_got_chat_in:
- * @gc: The #PurpleConnection.
- * @id: The id of the chat.
- * @who: The message sender or receiver.
- * @text: The message text.
- * @flags: The #PurpleMessageFlags.
- * @timestamp: The message timestamp.
- *
- * Handles an incoming chat message. This function is special in that
- * it handles self messages. This function determines the direction of
- * the message from the #PurpleMessageFlags.
- */
-void
-fb_util_serv_got_chat_in(PurpleConnection *gc, gint id, const gchar *who,
-                         const gchar *text, PurpleMessageFlags flags,
-                         guint64 timestamp);
-
-/**
- * fb_util_strtest:
- * @str: The string.
- * @type: The #GAsciiType.
- *
- * Tests if the string only contains characters allowed by the
- * #GAsciiType. More than one type can be specified by ORing the types
- * together.
- *
- * Returns: #TRUE if the string only contains characters allowed by the
- *          #GAsciiType, otherwise #FALSE.
- */
-gboolean
-fb_util_strtest(const gchar *str, GAsciiType type);
-
-/**
- * fb_util_zlib_test:
- * @bytes: The #GByteArray.
- *
- * Tests if the #GByteArray is zlib compressed.
- *
- * Returns: #TRUE if the #GByteArray is compressed, otherwise #FALSE.
- */
-gboolean
-fb_util_zlib_test(const GByteArray *bytes);
-
-/**
- * fb_util_zlib_deflate:
- * @bytes: The #GByteArray.
- * @error: The return location for the #GError or #NULL.
- *
- * Deflates a #GByteArray with zlib. The returned #GByteArray should be
- * freed with #g_byte_array_free() when no longer needed.
- *
- * Returns: (transfer full): The deflated #GByteArray or #NULL on error.
- */
-GByteArray *
-fb_util_zlib_deflate(const GByteArray *bytes, GError **error);
-
-/**
- * fb_util_zlib_inflate:
- * @bytes: The #GByteArray.
- * @error: The return location for the #GError or #NULL.
- *
- * Inflates a #GByteArray with zlib. The returned #GByteArray should be
- * freed with #g_byte_array_free() when no longer needed.
- *
- * Returns: (transfer full): The inflated #GByteArray or #NULL on error.
- */
-GByteArray *
-fb_util_zlib_inflate(const GByteArray *bytes, GError **error);
-
-#endif /* PURPLE_FACEBOOK_UTIL_H */
diff --git a/libpurple/protocols/facebook/util.c b/libpurple/protocols/facebook/util.c
deleted file mode 100644
--- a/libpurple/protocols/facebook/util.c
+++ /dev/null
@@ -1,619 +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.h>
-#include <glib/gi18n-lib.h>
-
-#include <gio/gio.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include <purple.h>
-
-#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(PURPLE_IS_ACCOUNT(acct), 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, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	fb_util_vdebug(level, format, ap);
-	va_end(ap);
-}
-
-void
-fb_util_vdebug(PurpleDebugLevel level, const gchar *format, va_list ap)
-{
-	gboolean unsafe;
-	gboolean verbose;
-	gchar *str;
-
-	g_return_if_fail(format != NULL);
-
-	unsafe = (level & FB_UTIL_DEBUG_FLAG_UNSAFE) != 0;
-	verbose = (level & FB_UTIL_DEBUG_FLAG_VERBOSE) != 0;
-
-	if ((unsafe && !purple_debug_is_unsafe()) ||
-	    (verbose && !purple_debug_is_verbose()))
-	{
-		return;
-	}
-
-	/* Ensure all local flags are removed */
-	level &= ~FB_UTIL_DEBUG_FLAG_ALL;
-
-	str = g_strdup_vprintf(format, ap);
-	purple_debug(level, "facebook", "%s", str);
-	g_free(str);
-}
-
-void
-fb_util_debug_misc(const gchar *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	fb_util_vdebug(PURPLE_DEBUG_MISC, format, ap);
-	va_end(ap);
-}
-
-void
-fb_util_debug_info(const gchar *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	fb_util_vdebug(PURPLE_DEBUG_INFO, format, ap);
-	va_end(ap);
-}
-
-void
-fb_util_debug_warning(const gchar *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	fb_util_vdebug(PURPLE_DEBUG_WARNING, format, ap);
-	va_end(ap);
-}
-
-void
-fb_util_debug_error(const gchar *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	fb_util_vdebug(PURPLE_DEBUG_ERROR, format, ap);
-	va_end(ap);
-}
-
-void
-fb_util_debug_fatal(const gchar *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-	fb_util_vdebug(PURPLE_DEBUG_FATAL, format, ap);
-	va_end(ap);
-}
-
-void
-fb_util_debug_hexdump(PurpleDebugLevel level, const GByteArray *bytes,
-                      const gchar *format, ...)
-{
-	gchar c;
-	guint i;
-	guint j;
-	GString *gstr;
-	va_list ap;
-
-	static const gchar *indent = "  ";
-
-	g_return_if_fail(bytes != NULL);
-
-	if (format != NULL) {
-		va_start(ap, format);
-		fb_util_vdebug(level, format, ap);
-		va_end(ap);
-	}
-
-	gstr = g_string_sized_new(80);
-
-	for (i = 0; i < bytes->len; i += 16) {
-		g_string_append_printf(gstr, "%s%08x  ", indent, i);
-
-		for (j = 0; j < 16; j++) {
-			if ((i + j) < bytes->len) {
-				g_string_append_printf(gstr, "%02x ",
-				                       bytes->data[i + j]);
-			} else {
-				g_string_append(gstr, "   ");
-			}
-
-			if (j == 7) {
-				g_string_append_c(gstr, ' ');
-			}
-		}
-
-		g_string_append(gstr, " |");
-
-		for (j = 0; (j < 16) && ((i + j) < bytes->len); j++) {
-			c = bytes->data[i + j];
-
-			if (!g_ascii_isprint(c) || g_ascii_isspace(c)) {
-				c = '.';
-			}
-
-			g_string_append_c(gstr, c);
-		}
-
-		g_string_append_c(gstr, '|');
-		fb_util_debug(level, "%s", gstr->str);
-		g_string_erase(gstr, 0, -1);
-	}
-
-	g_string_append_printf(gstr, "%s%08x", indent, i);
-	fb_util_debug(level, "%s", gstr->str);
-	g_string_free(gstr, TRUE);
-}
-
-gchar *
-fb_util_get_locale(void)
-{
-	const gchar * const *langs;
-	const gchar *lang;
-	gchar *chr;
-	guint i;
-
-	static const gchar chrs[] = {'.', '@'};
-
-	langs = g_get_language_names();
-	lang = langs[0];
-
-	if (purple_strequal(lang, "C")) {
-		return g_strdup("en_US");
-	}
-
-	for (i = 0; i < G_N_ELEMENTS(chrs); i++) {
-		chr = strchr(lang, chrs[i]);
-
-		if (chr != NULL) {
-			return g_strndup(lang, chr - lang);
-		}
-	}
-
-	return g_strdup(lang);
-}
-
-gchar *
-fb_util_rand_alnum(guint len)
-{
-	gchar *ret;
-	GRand *rand;
-	guint i;
-	guint j;
-
-	static const gchar chars[] =
-		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-		"abcdefghijklmnopqrstuvwxyz"
-		"0123456789";
-	static const gsize charc = G_N_ELEMENTS(chars) - 1;
-
-	g_return_val_if_fail(len > 0, NULL);
-	rand = g_rand_new();
-	ret = g_new(gchar, len + 1);
-
-	for (i = 0; i < len; i++) {
-		j = g_rand_int_range(rand, 0, charc);
-		ret[i] = chars[j];
-	}
-
-	ret[len] = 0;
-	g_rand_free(rand);
-	return ret;
-}
-
-static void
-fb_util_request_buddy_ok(gpointer *request_data, PurpleRequestPage *page) {
-	FbUtilRequestBuddyFunc func = request_data[0];
-	GList *l;
-	GList *select;
-	gpointer data = request_data[2];
-	GSList *ret = NULL;
-	PurpleBuddy *bdy;
-	PurpleRequestFieldList *field;
-
-	if (func == NULL) {
-		g_free(request_data);
-		return;
-	}
-
-	field = PURPLE_REQUEST_FIELD_LIST(purple_request_page_get_field(page,
-	                                                                "buddy"));
-	select = purple_request_field_list_get_selected(field);
-
-	for (l = select; l != NULL; l = l->next) {
-		bdy = purple_request_field_list_get_data(field, l->data);
-		ret = g_slist_prepend(ret, bdy);
-	}
-
-	ret = g_slist_reverse(ret);
-	func(ret, data);
-
-	g_slist_free(ret);
-	g_free(request_data);
-}
-
-static void
-fb_util_request_buddy_cancel(gpointer *request_data,
-                             G_GNUC_UNUSED PurpleRequestPage *page)
-{
-	FbUtilRequestBuddyFunc func = request_data[1];
-	gpointer data = request_data[2];
-
-	if (func != NULL) {
-		func(NULL, data);
-	}
-
-	g_free(request_data);
-}
-
-static gint
-fb_buddy_cmp(gconstpointer a, gconstpointer b)
-{
-	PurpleBuddy *pba, *pbb;
-	gint alias_verdict, name_verdict;
-	gchar *astr, *bstr;
-
-	pba = PURPLE_BUDDY(a);
-	pbb = PURPLE_BUDDY(b);
-
-	astr = g_utf8_casefold(purple_buddy_get_alias(pba), -1);
-	bstr = g_utf8_casefold(purple_buddy_get_alias(pbb), -1);
-	alias_verdict = g_utf8_collate(astr, bstr);
-	g_free(astr);
-	g_free(bstr);
-	if (alias_verdict != 0) {
-		return alias_verdict;
-	}
-	astr = g_utf8_casefold(purple_buddy_get_name(pba), -1);
-	bstr = g_utf8_casefold(purple_buddy_get_name(pbb), -1);
-	name_verdict = g_utf8_collate(astr, bstr);
-	g_free(astr);
-	g_free(bstr);
-	return name_verdict;
-}
-
-gpointer
-fb_util_request_buddy(PurpleConnection *gc, const gchar *title,
-                      const gchar *primary, const gchar *secondary,
-                      GSList *select, gboolean multi, GCallback ok_cb,
-		      GCallback cancel_cb, gpointer data)
-{
-	const gchar *alias;
-	const gchar *name;
-	gchar *str;
-	GList *items = NULL;
-	gpointer *request_data;
-	GSList *buddies;
-	GSList *l;
-	PurpleAccount *acct;
-	PurpleRequestCommonParameters *cpar;
-	PurpleRequestField *field;
-	PurpleRequestFieldList *list;
-	PurpleRequestGroup *group;
-	PurpleRequestPage *page;
-
-	request_data = g_new0(gpointer, 3);
-	request_data[0] = ok_cb;
-	request_data[1] = cancel_cb;
-	request_data[2] = data;
-
-	acct = purple_connection_get_account(gc);
-	buddies = purple_blist_find_buddies(acct, NULL);
-	buddies = g_slist_sort(buddies, fb_buddy_cmp);
-
-	page = purple_request_page_new();
-	group = purple_request_group_new(NULL);
-	purple_request_page_add_group(page, group);
-
-	field = purple_request_field_list_new("buddy", NULL);
-	list = PURPLE_REQUEST_FIELD_LIST(field);
-	purple_request_field_list_set_multi_select(list, multi);
-	purple_request_field_set_required(field, TRUE);
-	purple_request_group_add_field(group, field);
-
-	for (l = buddies; l != NULL; l = l->next) {
-		name = purple_buddy_get_name(l->data);
-		alias = purple_buddy_get_alias(l->data);
-		str = g_strdup_printf("%s (%s)", alias, name);
-		purple_request_field_list_add_icon(list, str, NULL, l->data);
-		g_free(str);
-	}
-
-	for (l = select; l != NULL; l = l->next) {
-		name = purple_buddy_get_name(l->data);
-		alias = purple_buddy_get_alias(l->data);
-		str = g_strdup_printf("%s (%s)", alias, name);
-		items = g_list_append(items, str);
-	}
-
-	purple_request_field_list_set_selected(list, items);
-	g_slist_free(buddies);
-	g_list_free_full(items, g_free);
-
-	cpar = purple_request_cpar_from_connection(gc);
-	return purple_request_fields(gc, title, primary, secondary, page,
-	                             _("Ok"),
-	                             G_CALLBACK(fb_util_request_buddy_ok),
-				     _("Cancel"),
-	                             G_CALLBACK(fb_util_request_buddy_cancel),
-				     cpar, request_data);
-}
-
-void
-fb_util_serv_got_im(PurpleConnection *gc, const gchar *who, const gchar *text,
-                    PurpleMessageFlags flags, guint64 timestamp)
-{
-	GDateTime *dt = NULL;
-	const gchar *name, *me;
-	PurpleAccount *acct;
-	PurpleContactInfo *info = NULL;
-	PurpleConversation *conv;
-	PurpleConversationManager *manager;
-	PurpleMessage *msg;
-
-	if (!(flags & PURPLE_MESSAGE_SEND)) {
-		purple_serv_got_im(gc, who, text, flags, timestamp);
-		return;
-	}
-
-	acct = purple_connection_get_account(gc);
-	info = PURPLE_CONTACT_INFO(acct);
-	manager = purple_conversation_manager_get_default();
-
-	conv = purple_conversation_manager_find_im(manager, acct, who);
-
-	if (conv == NULL) {
-		conv = purple_im_conversation_new(acct, who);
-	}
-
-	me = purple_contact_info_get_name_for_display(info);
-	name = purple_contact_info_get_username(info);
-	msg = purple_message_new_outgoing(acct, me, name, text, flags);
-
-	dt = g_date_time_new_from_unix_local((gint64)timestamp);
-	purple_message_set_timestamp(msg, dt);
-	g_date_time_unref(dt);
-
-	purple_conversation_write_message(conv, msg);
-
-	g_object_unref(G_OBJECT(msg));
-}
-
-void
-fb_util_serv_got_chat_in(PurpleConnection *gc, gint id, const gchar *who,
-                         const gchar *text, PurpleMessageFlags flags,
-                         guint64 timestamp)
-{
-	GDateTime *dt = NULL;
-	const gchar *name;
-	PurpleAccount *acct;
-	PurpleContactInfo *info = NULL;
-	PurpleConversation *conv;
-	PurpleConversationManager *manager;
-	PurpleMessage *msg;
-	const gchar *me;
-
-	if (!(flags & PURPLE_MESSAGE_SEND)) {
-		purple_serv_got_chat_in(gc, id, who, flags, text, timestamp);
-		return;
-	}
-
-	acct = purple_connection_get_account(gc);
-	info = PURPLE_CONTACT_INFO(acct);
-	manager = purple_conversation_manager_get_default();
-
-	conv = purple_conversation_manager_find_chat_by_id(manager, acct, id);
-
-	me = purple_contact_info_get_name_for_display(info);
-	name = purple_contact_info_get_username(info);
-
-	msg = purple_message_new_outgoing(acct, me, name, text, flags);
-
-	dt = g_date_time_new_from_unix_local((gint64)timestamp);
-	purple_message_set_timestamp(msg, dt);
-	g_date_time_unref(dt);
-
-	purple_conversation_write_message(conv, msg);
-
-	g_object_unref(G_OBJECT(msg));
-}
-
-gboolean
-fb_util_strtest(const gchar *str, GAsciiType type)
-{
-	gsize i;
-	gsize size;
-	guchar c;
-
-	g_return_val_if_fail(str != NULL, FALSE);
-	size = strlen(str);
-
-	for (i = 0; i < size; i++) {
-		c = (guchar) str[i];
-
-		if ((g_ascii_table[c] & type) == 0) {
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
-gboolean
-fb_util_zlib_test(const GByteArray *bytes)
-{
-	guint8 b0;
-	guint8 b1;
-
-	g_return_val_if_fail(bytes != NULL, FALSE);
-
-	if (bytes->len < 2) {
-		return FALSE;
-	}
-
-	b0 = *(bytes->data + 0);
-	b1 = *(bytes->data + 1);
-
-	return ((((b0 << 8) | b1) % 31) == 0) &&    /* Check the header */
-	       ((b0 & 0x0F) == 8 /* Z_DEFLATED */); /* Check the method */
-}
-
-static GByteArray *
-fb_util_zlib_conv(GConverter *conv, const GByteArray *bytes, GError **error)
-{
-	GByteArray *ret;
-	GConverterResult res;
-	gsize cize = 0;
-	gsize rize;
-	gsize wize;
-	guint8 data[1024];
-
-	ret = g_byte_array_new();
-
-	while (TRUE) {
-		rize = 0;
-		wize = 0;
-
-		res = g_converter_convert(conv,
-		                          bytes->data + cize,
-		                          bytes->len - cize,
-		                          data, sizeof data,
-		                          G_CONVERTER_INPUT_AT_END,
-		                          &rize, &wize, error);
-
-		switch (res) {
-		case G_CONVERTER_CONVERTED:
-			g_byte_array_append(ret, data, wize);
-			cize += rize;
-			break;
-
-		case G_CONVERTER_ERROR:
-			g_byte_array_free(ret, TRUE);
-			return NULL;
-
-		case G_CONVERTER_FINISHED:
-			g_byte_array_append(ret, data, wize);
-			return ret;
-
-		default:
-			break;
-		}
-	}
-}
-
-GByteArray *
-fb_util_zlib_deflate(const GByteArray *bytes, GError **error)
-{
-	GByteArray *ret;
-	GZlibCompressor *conv;
-
-	conv = g_zlib_compressor_new(G_ZLIB_COMPRESSOR_FORMAT_ZLIB, -1);
-	ret = fb_util_zlib_conv(G_CONVERTER(conv), bytes, error);
-	g_object_unref(conv);
-	return ret;
-}
-
-GByteArray *
-fb_util_zlib_inflate(const GByteArray *bytes, GError **error)
-{
-	GByteArray *ret;
-	GZlibDecompressor *conv;
-
-	conv = g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_ZLIB);
-	ret = fb_util_zlib_conv(G_CONVERTER(conv), bytes, error);
-	g_object_unref(conv);
-	return ret;
-}
diff --git a/libpurple/protocols/meson.build b/libpurple/protocols/meson.build
--- a/libpurple/protocols/meson.build
+++ b/libpurple/protocols/meson.build
@@ -1,6 +1,5 @@
 subdir('bonjour')
 subdir('demo')
-subdir('facebook')
 subdir('gg')
 subdir('ircv3')
 subdir('jabber')
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -79,14 +79,6 @@
 libpurple/protocols/demo/purpledemocontacts.c
 libpurple/protocols/demo/purpledemoplugin.c
 libpurple/protocols/demo/purpledemoprotocol.c
-libpurple/protocols/facebook/api.c
-libpurple/protocols/facebook/data.c
-libpurple/protocols/facebook/facebook.c
-libpurple/protocols/facebook/http.c
-libpurple/protocols/facebook/json.c
-libpurple/protocols/facebook/mqtt.c
-libpurple/protocols/facebook/thrift.c
-libpurple/protocols/facebook/util.c
 libpurple/protocols/gg/avatar.c
 libpurple/protocols/gg/blist.c
 libpurple/protocols/gg/chat.c
