# HG changeset patch
# Node ID 20b54e135fde
# Parent  2794bb8587d3
diff --git a/ChangeLog.API b/ChangeLog.API
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -249,6 +249,14 @@
 		* account-setting-info, account-set-info signals
 		* account-status-changing signal.
 		* blocked-img-msg signal.
+		* buddy-caps-changed signal.
+		* buddy-got-login-time signal.
+		* buddy-icon-changed signal.
+		* buddy-idle-changed signal.
+		* buddy-privacy-changed signal.
+		* buddy-removed-from-group signal.
+		* buddy-signed-off signal.
+		* buddy-signed-on signal.
 		* buddy-status-changed signal.
 		* buddy-typed signal.
 		* buddy-typing signal.
@@ -287,6 +295,8 @@
 		* PURPLE_ACCOUNT_RESPONSE_IGNORE
 		* PURPLE_ACCOUNT_RESPONSE_PASS
 		* PurpleAccountUiOps
+		* purple_account_add_buddy
+		* purple_account_add_buddies
 		* purple_account_add_buddies_with_invite
 		* purple_account_add_buddy_with_invite
 		* purple_account_destroy_log
@@ -322,6 +332,8 @@
 		* purple_account_privacy_get_permitted
 		* purple_account_privacy_permit_add
 		* purple_account_privacy_permit_remove
+		* purple_account_remove_buddy
+		* purple_account_remove_buddies
 		* purple_account_remove_setting
 		* purple_account_request_add. Use purple_add_contact_request_new
 		  instead.
@@ -344,6 +356,7 @@
 		* purple_account_set_ui_bool
 		* purple_account_set_username. Use purple_contact_info_set_username
 		  instead.
+		* purple_account_supports_offline_message
 		* account-status-changed signal
 		* purple_accounts_add
 		* purple_accounts_find
@@ -367,6 +380,8 @@
 		* purple_attention_type_get_unlocalized_name
 		* purple_base16_*
 		* purple_base64_*. Use g_base64_* instead
+		* purple_blist_add_account
+		* purple_blist_add_buddy
 		* purple_blist_add_chat
 		* purple_blist_find_chat
 		* purple_blist_get_ui_data
@@ -374,6 +389,8 @@
 		* purple_blist_new
 		* purple_blist_node_get_ui_data
 		* purple_blist_node_set_ui_data
+		* purple_blist_remove_account
+		* purple_blist_remove_buddy
 		* purple_blist_remove_chat
 		* purple_blist_request_add_chat
 		* purple_blist_set_ui_data
diff --git a/doc/reference/libpurple/signals_blist.md b/doc/reference/libpurple/signals_blist.md
--- a/doc/reference/libpurple/signals_blist.md
+++ b/doc/reference/libpurple/signals_blist.md
@@ -5,81 +5,13 @@
 
 ### Signal List
 
-* [buddy-idle-changed](#buddy-idle-changed)
-* [buddy-signed-on](#buddy-signed-on)
-* [buddy-signed-off](#buddy-signed-off)
 * [update-idle](#update-idle)
 * [blist-node-extended-menu](#blist-node-extended-menu)
-* [buddy-icon-changed](#buddy-icon-changed)
 * [blist-node-aliased](#blist-node-aliased)
-* [buddy-caps-changed](#buddy-caps-changed)
 * [ui-caps-changed](#ui-caps-changed)
 
 ### Signal Details
 
-#### buddy-idle-changed
-
-```c
-void user_function(PurpleBuddy *buddy,
-                   gboolean old_idle,
-                   gboolean idle,
-                   gpointer user_data);
-```
-
-Emitted when a buddy on your buddy list becomes idle.
-
-**Parameters:**
-
-**buddy**
-: The buddy whose idle status changed.
-
-**old_idle**
-: Whether the buddy was idle.
-
-**idle**
-: Whether the buddy is currently idle.
-
-**user_data**
-: user data set when the signal handler was connected.
-
-----
-
-#### buddy-signed-on
-
-```c
-void user_function(PurpleBuddy *buddy, gpointer user_data);
-```
-
-Emitted when a buddy on your buddy list signs on.
-
-**Parameters:**
-
-**buddy**
-: The buddy that signed on.
-
-**user_data**
-: user data set when the signal handler was connected.
-
-----
-
-#### buddy-signed-off
-
-```c
-void user_function(PurpleBuddy *buddy, gpointer user_data);
-```
-
-Emitted when a buddy on your buddy list signs off.
-
-**Parameters:**
-
-**buddy**
-: The buddy that signed off.
-
-**user_data**
-: user data set when the signal handler was connected.
-
-----
-
 #### update-idle
 
 ```c
@@ -126,16 +58,6 @@
 
 ----
 
-#### buddy-icon-changed
-
-```c
-void user_function(PurpleBuddy *buddy, gpointer user_data);
-```
-
-Emitted when a buddy's icon is set.
-
-----
-
 #### blist-node-aliased
 
 ```c
@@ -148,33 +70,6 @@
 
 ----
 
-#### buddy-caps-changed
-
-```c
-void user_function(PurpleBuddy *buddy,
-                   PurpleMediaCaps newcaps,
-                   PurpleMediaCaps oldcaps,
-                   gpointer user_data);
-```
-
-Emitted when updating a buddy's media capabilities.
-
-**Parameters:**
-
-**buddy**
-: The buddy.
-
-**newcaps**
-: .
-
-**oldcaps**
-: .
-
-**user_data**
-: user data set when the signal handler was connected.
-
-----
-
 #### ui-caps-changed
 
 ```c
diff --git a/libpurple/accounts.c b/libpurple/accounts.c
--- a/libpurple/accounts.c
+++ b/libpurple/accounts.c
@@ -33,6 +33,8 @@
 #include "purplecredentialmanager.h"
 #include "purpleenums.h"
 #include "purpleprivate.h"
+#include "signals.h"
+#include "util.h"
 
 static guint    save_timer = 0;
 static gboolean accounts_loaded = FALSE;
@@ -395,24 +397,6 @@
 		g_free(data);
 	}
 
-	/* Read an old buddyicon */
-	child = purple_xmlnode_get_child(node, "buddyicon");
-	if ((child != NULL) && ((data = purple_xmlnode_get_data(child)) != NULL))
-	{
-		const char *dirname = purple_buddy_icons_get_cache_dir();
-		char *filename = g_build_filename(dirname, data, NULL);
-		gchar *contents;
-		gsize len;
-
-		if (g_file_get_contents(filename, &contents, &len, NULL))
-		{
-			purple_buddy_icons_set_account_icon(ret, (guchar *)contents, len);
-		}
-
-		g_free(filename);
-		g_free(data);
-	}
-
 	/* Read settings (both core and UI) */
 	for (child = purple_xmlnode_get_child(node, "settings"); child != NULL;
 			child = purple_xmlnode_get_next_twin(child))
@@ -463,8 +447,6 @@
 	}
 
 	purple_xmlnode_free(node);
-
-	_purple_buddy_icons_account_loaded_cb();
 }
 
 static void
@@ -493,7 +475,6 @@
 purple_accounts_delete(PurpleAccount *account)
 {
 	PurpleAccountManager *manager = NULL;
-	PurpleBlistNode *gnode = NULL, *cnode = NULL, *bnode = NULL;
 	PurpleConversationManager *conv_manager = NULL;
 	PurpleCredentialManager *cred_manager = NULL;
 	GList *iter = NULL;
@@ -514,37 +495,6 @@
 	manager = purple_account_manager_get_default();
 	purple_account_manager_remove(manager, account);
 
-	/* Remove this account's buddies */
-	for(gnode = purple_blist_get_default_root(); gnode != NULL;
-	    gnode = purple_blist_node_get_sibling_next(gnode))
-	{
-		if(!PURPLE_IS_GROUP(gnode)) {
-			continue;
-		}
-
-		cnode = purple_blist_node_get_first_child(gnode);
-		while(cnode) {
-			PurpleBlistNode *cnode_next = purple_blist_node_get_sibling_next(cnode);
-
-			if(PURPLE_IS_META_CONTACT(cnode)) {
-				bnode = purple_blist_node_get_first_child(cnode);
-				while(bnode) {
-					PurpleBlistNode *bnode_next = purple_blist_node_get_sibling_next(bnode);
-
-					if (PURPLE_IS_BUDDY(bnode)) {
-						PurpleBuddy *b = (PurpleBuddy *)bnode;
-
-						if(purple_buddy_get_account(b) == account) {
-							purple_blist_remove_buddy(b);
-						}
-					}
-					bnode = bnode_next;
-				}
-			}
-			cnode = cnode_next;
-		}
-	}
-
 	/* Remove any open conversation for this account */
 	conv_manager = purple_conversation_manager_get_default();
 	iter = purple_conversation_manager_get_all(conv_manager);
@@ -558,9 +508,6 @@
 		iter = g_list_delete_link(iter, iter);
 	}
 
-	/* This will cause the deletion of an old buddy icon. */
-	purple_buddy_icons_set_account_icon(account, NULL, 0);
-
 	/* This is async because we do not want the
 	 * account being overwritten before we are done.
 	 */
diff --git a/libpurple/blistnode.c b/libpurple/blistnode.c
--- a/libpurple/blistnode.c
+++ b/libpurple/blistnode.c
@@ -21,7 +21,10 @@
  */
 
 #include "blistnode.h"
-#include "buddy.h"
+
+#include "buddylist.h"
+#include "signals.h"
+#include "util.h"
 
 typedef struct _PurpleBlistNodePrivate  PurpleBlistNodePrivate;
 
@@ -48,33 +51,11 @@
 /* Buddy list node API                                                    */
 /**************************************************************************/
 
-static PurpleBlistNode *get_next_node(PurpleBlistNode *node, gboolean godeep)
+PurpleBlistNode *
+purple_blist_node_next(G_GNUC_UNUSED PurpleBlistNode *node,
+                       G_GNUC_UNUSED gboolean offline)
 {
-	if (node == NULL)
-		return NULL;
-
-	if (godeep && node->child)
-		return node->child;
-
-	if (node->next)
-		return node->next;
-
-	return get_next_node(node->parent, FALSE);
-}
-
-PurpleBlistNode *purple_blist_node_next(PurpleBlistNode *node, gboolean offline)
-{
-	PurpleBlistNode *ret = node;
-
-	if (offline)
-		return get_next_node(ret, TRUE);
-	do
-	{
-		ret = get_next_node(ret, TRUE);
-	} while (ret && PURPLE_IS_BUDDY(ret) &&
-			!purple_account_is_connected(purple_buddy_get_account((PurpleBuddy *)ret)));
-
-	return ret;
+	return NULL;
 }
 
 PurpleBlistNode *purple_blist_node_get_parent(PurpleBlistNode *node)
diff --git a/libpurple/buddy.h b/libpurple/buddy.h
deleted file mode 100644
--- a/libpurple/buddy.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * 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 library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_BUDDY_H
-#define PURPLE_BUDDY_H
-
-#define PURPLE_TYPE_BUDDY             (purple_buddy_get_type())
-#define PURPLE_BUDDY(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_BUDDY, PurpleBuddy))
-#define PURPLE_BUDDY_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_BUDDY, PurpleBuddyClass))
-#define PURPLE_IS_BUDDY(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_BUDDY))
-#define PURPLE_IS_BUDDY_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_BUDDY))
-#define PURPLE_BUDDY_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_BUDDY, PurpleBuddyClass))
-
-typedef struct _PurpleBuddy PurpleBuddy;
-typedef struct _PurpleBuddyClass PurpleBuddyClass;
-
-#include "blistnode.h"
-#include "buddyicon.h"
-#include "contact.h"
-#include "group.h"
-#include "media.h"
-#include "purpleaccount.h"
-#include "purplepresence.h"
-#include "purpleversion.h"
-
-/**
- * PURPLE_BUDDY_IS_ONLINE:
- * @b: The #PurpleBuddy instance.
- *
- * Checks whether @b is online or not.
- */
-#define PURPLE_BUDDY_IS_ONLINE(b) \
-	(PURPLE_IS_BUDDY(b) \
-	&& purple_account_is_connected(purple_buddy_get_account(PURPLE_BUDDY(b))) \
-	&& purple_presence_is_online(purple_buddy_get_presence(PURPLE_BUDDY(b))))
-
-/**
- * PURPLE_BLIST_NODE_NAME:
- * @n: The #PurpleBlistNode instance.
- *
- * Gets the name of @n.
- */
-#define PURPLE_BLIST_NODE_NAME(n) \
-	(PURPLE_IS_BUDDY(n) ? purple_buddy_get_name(PURPLE_BUDDY(n)) : NULL)
-
-/**************************************************************************/
-/* Data Structures                                                        */
-/**************************************************************************/
-/**
- * PurpleBuddy:
- *
- * A buddy on the buddy list.
- *
- * Since: 2.0
- */
-struct _PurpleBuddy {
-	PurpleBlistNode node;
-};
-
-struct _PurpleBuddyClass {
-	PurpleBlistNodeClass node_class;
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* Buddy API                                                              */
-/**************************************************************************/
-
-/**
- * purple_buddy_get_type:
- *
- * Returns: The #GType for the #PurpleBuddy object.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GType purple_buddy_get_type(void);
-
-/**
- * purple_buddy_new:
- * @account:    The account this buddy will get added to
- * @name:       The name of the new buddy
- * @alias:      The alias of the new buddy (or NULL if unaliased)
- *
- * Creates a new buddy.
- *
- * This function only creates the #PurpleBuddy. Use purple_blist_add_buddy()
- * to add the buddy to the list and purple_account_add_buddy() to sync up
- * with the server.
- *
- * See purple_account_add_buddy(), purple_blist_add_buddy().
- *
- * Returns: A newly allocated buddy
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleBuddy *purple_buddy_new(PurpleAccount *account, const char *name, const char *alias);
-
-/**
- * purple_buddy_get_id:
- * @buddy: The buddy.
- *
- * Gets the globally unique identifier of the buddy.
- *
- * Returns: The id of @buddy.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-const gchar *purple_buddy_get_id(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_set_icon:
- * @buddy: The buddy.
- * @icon:  The buddy icon.
- *
- * Sets a buddy's icon.
- *
- * This should only be called from within Purple. You probably want to
- * call purple_buddy_icon_set_data().
- *
- * See purple_buddy_icon_set_data().
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_buddy_set_icon(PurpleBuddy *buddy, PurpleBuddyIcon *icon);
-
-/**
- * purple_buddy_get_icon:
- * @buddy: The buddy.
- *
- * Returns a buddy's icon.
- *
- * Returns: The buddy icon.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleBuddyIcon *purple_buddy_get_icon(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_get_account:
- * @buddy: The buddy.
- *
- * Returns a buddy's account.
- *
- * Returns: (transfer none): The account.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleAccount *purple_buddy_get_account(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_set_name:
- * @buddy: The buddy.
- * @name:  The name.
- *
- * Sets a buddy's name
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_buddy_set_name(PurpleBuddy *buddy, const char *name);
-
-/**
- * purple_buddy_get_name:
- * @buddy: The buddy.
- *
- * Returns a buddy's name
- *
- * Returns: The name.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_get_name(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_get_protocol_data:
- * @buddy: The buddy.
- *
- * Returns a buddy's protocol-specific data.
- *
- * This should only be called from the associated protocol.
- *
- * See purple_buddy_set_protocol_data().
- *
- * Returns:      The protocol data.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-gpointer purple_buddy_get_protocol_data(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_set_protocol_data:
- * @buddy: The buddy.
- * @data:  The data.
- *
- * Sets a buddy's protocol-specific data.
- *
- * This should only be called from the associated protocol.
- *
- * See purple_buddy_get_protocol_data().
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_buddy_set_protocol_data(PurpleBuddy *buddy, gpointer data);
-
-/**
- * purple_buddy_get_contact:
- * @buddy: The buddy.
- *
- * Returns a buddy's contact.
- *
- * Returns: (transfer none): The buddy's contact.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleMetaContact *purple_buddy_get_contact(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_get_presence:
- * @buddy: The buddy.
- *
- * Returns a buddy's presence.
- *
- * Returns: (transfer none): The buddy's presence.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurplePresence *purple_buddy_get_presence(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_get_media_caps:
- * @buddy: The buddy.
- *
- * Gets the media caps from a buddy.
- *
- * Returns:      The media caps.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-PurpleMediaCaps purple_buddy_get_media_caps(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_set_media_caps:
- * @buddy:      The PurpleBuddy.
- * @media_caps: The PurpleMediaCaps.
- *
- * Sets the media caps for a buddy.
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-void purple_buddy_set_media_caps(PurpleBuddy *buddy, PurpleMediaCaps media_caps);
-
-/**
- * purple_buddy_get_alias_only:
- * @buddy:   The buddy whose alias will be returned.
- *
- * Returns the alias of a buddy.
- *
- * Returns:        The alias (if set), server alias (if set),
- *                or NULL.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_get_alias_only(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_set_server_alias:
- * @buddy:  The buddy.
- * @alias:  The server alias to be set.
- *
- * Sets the server alias for a buddy.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_buddy_set_server_alias(PurpleBuddy *buddy, const char *alias);
-
-/**
- * purple_buddy_get_server_alias:
- * @buddy:  The buddy whose server alias will be returned
- *
- * Gets the server alias for a buddy.
- *
- * Returns:  The server alias, or NULL if it is not set.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_get_server_alias(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_get_contact_alias:
- * @buddy:  The buddy whose alias will be returned
- *
- * Returns the correct name to display for a buddy, taking the contact alias
- * into account. In order of precedence: the buddy's alias; the buddy's
- * contact alias; the buddy's server alias; the buddy's user name.
- *
- * Returns:       The appropriate name or alias, or NULL.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_get_contact_alias(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_get_alias:
- * @buddy:   The buddy whose alias will be returned.
- *
- * Returns the correct name to display for a buddy. In order of precedence:
- * the buddy's local alias; the buddy's server alias; the buddy's contact alias;
- * the buddy's user name.
- *
- * Returns:        The appropriate name or alias, or NULL
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_get_alias(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_set_local_alias:
- * @buddy:  The buddy
- * @alias:  The local alias for the buddy
- *
- * Sets the local alias for the buddy.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_buddy_set_local_alias(PurpleBuddy *buddy, const char *alias);
-
-/**
- * purple_buddy_get_local_alias:
- * @buddy:  The buddy
- *
- * Returns the local alias for the buddy, or %NULL if none exists.
- *
- * Returns:       The local alias for the buddy
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_get_local_alias(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_get_group:
- * @buddy:   The buddy
- *
- * Returns the group of which the buddy is a member.
- *
- * Returns: (transfer none): The group or %NULL if the buddy is not in a group.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleGroup *purple_buddy_get_group(PurpleBuddy *buddy);
-
-G_END_DECLS
-
-#endif /* PURPLE_BUDDY_H */
diff --git a/libpurple/buddy.c b/libpurple/buddy.c
deleted file mode 100644
--- a/libpurple/buddy.c
+++ /dev/null
@@ -1,730 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * 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 library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "buddy.h"
-
-#include "debug.h"
-#include "purplecontactmanager.h"
-#include "purpleconversationmanager.h"
-#include "purpleprotocolclient.h"
-#include "util.h"
-
-typedef struct {
-	gchar *id;
-	gchar *name;
-	gchar *local_alias;
-	gchar *server_alias;
-
-	gpointer proto_data;
-
-	PurpleBuddyIcon *icon;
-	PurpleAccount *account;
-	PurplePresence *presence;
-
-	PurpleMediaCaps media_caps;
-} PurpleBuddyPrivate;
-
-enum {
-	PROP_0,
-	PROP_ID,
-	PROP_NAME,
-	PROP_LOCAL_ALIAS,
-	PROP_SERVER_ALIAS,
-	PROP_ICON,
-	PROP_ACCOUNT,
-	PROP_PRESENCE,
-	PROP_MEDIA_CAPS,
-	N_PROPERTIES,
-};
-
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleBuddy, purple_buddy, PURPLE_TYPE_BLIST_NODE)
-
-/******************************************************************************
- * Helpers
- *****************************************************************************/
-static void
-purple_buddy_set_id(PurpleBuddy *buddy, const gchar *id) {
-	PurpleBuddyPrivate *priv = purple_buddy_get_instance_private(buddy);
-
-	g_free(priv->id);
-	priv->id = g_strdup(id);
-
-	g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_ID]);
-}
-
-static void
-purple_buddy_set_account(PurpleBuddy *buddy, PurpleAccount *account) {
-	PurpleBuddyPrivate *priv = purple_buddy_get_instance_private(buddy);
-
-	if(g_set_object(&priv->account, account)) {
-		g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_ACCOUNT]);
-	}
-}
-
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-static void
-purple_buddy_set_property(GObject *obj, guint param_id, const GValue *value,
-                          GParamSpec *pspec)
-{
-	PurpleBuddy *buddy = PURPLE_BUDDY(obj);
-
-	switch (param_id) {
-		case PROP_ID:
-			purple_buddy_set_id(buddy, g_value_get_string(value));
-			break;
-		case PROP_NAME:
-			purple_buddy_set_name(buddy, g_value_get_string(value));
-			break;
-		case PROP_LOCAL_ALIAS:
-			purple_buddy_set_local_alias(buddy, g_value_get_string(value));
-			break;
-		case PROP_SERVER_ALIAS:
-			purple_buddy_set_server_alias(buddy, g_value_get_string(value));
-			break;
-		case PROP_ICON:
-			purple_buddy_set_icon(buddy, g_value_get_pointer(value));
-			break;
-		case PROP_ACCOUNT:
-			purple_buddy_set_account(buddy,
-			                         PURPLE_ACCOUNT(g_value_get_object(value)));
-			break;
-		case PROP_MEDIA_CAPS:
-			purple_buddy_set_media_caps(buddy, g_value_get_enum(value));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_buddy_get_property(GObject *obj, guint param_id, GValue *value,
-                          GParamSpec *pspec)
-{
-	PurpleBuddy *buddy = PURPLE_BUDDY(obj);
-
-	switch (param_id) {
-		case PROP_ID:
-			g_value_set_string(value, purple_buddy_get_id(buddy));
-			break;
-		case PROP_NAME:
-			g_value_set_string(value, purple_buddy_get_name(buddy));
-			break;
-		case PROP_LOCAL_ALIAS:
-			g_value_set_string(value, purple_buddy_get_local_alias(buddy));
-			break;
-		case PROP_SERVER_ALIAS:
-			g_value_set_string(value, purple_buddy_get_server_alias(buddy));
-			break;
-		case PROP_ICON:
-			g_value_set_pointer(value, purple_buddy_get_icon(buddy));
-			break;
-		case PROP_ACCOUNT:
-			g_value_set_object(value, purple_buddy_get_account(buddy));
-			break;
-		case PROP_PRESENCE:
-			g_value_set_object(value, purple_buddy_get_presence(buddy));
-			break;
-		case PROP_MEDIA_CAPS:
-			g_value_set_enum(value, purple_buddy_get_media_caps(buddy));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_buddy_init(G_GNUC_UNUSED PurpleBuddy *buddy) {
-}
-
-static void
-purple_buddy_constructed(GObject *object) {
-	PurpleBuddy *buddy = PURPLE_BUDDY(object);
-	PurpleBuddyPrivate *priv = purple_buddy_get_instance_private(buddy);
-
-	G_OBJECT_CLASS(purple_buddy_parent_class)->constructed(object);
-
-	if(priv->id == NULL) {
-		/* If there is no id for the user, generate a SHA256 based on the
-		 * account_id and the username.
-		 */
-		PurpleContactInfo *info = PURPLE_CONTACT_INFO(priv->account);
-		GChecksum *sum = g_checksum_new(G_CHECKSUM_SHA256);
-		const guchar *data = NULL;
-
-		data = (const guchar *)purple_account_get_protocol_id(priv->account);
-		g_checksum_update(sum, data, -1);
-
-		data = (const guchar *)purple_contact_info_get_username(info);
-		g_checksum_update(sum, data, -1);
-
-		data = (const guchar *)priv->name;
-		g_checksum_update(sum, data, -1);
-
-		purple_buddy_set_id(buddy, g_checksum_get_string(sum));
-
-		g_checksum_free(sum);
-	}
-
-	priv->presence = purple_presence_new();
-	purple_presence_set_primitive(priv->presence,
-	                              PURPLE_PRESENCE_PRIMITIVE_OFFLINE);
-
-	purple_blist_new_node(purple_blist_get_default(),
-	                      PURPLE_BLIST_NODE(buddy));
-}
-
-static void
-purple_buddy_dispose(GObject *object) {
-	PurpleBuddyPrivate *priv = purple_buddy_get_instance_private(PURPLE_BUDDY(object));
-
-	g_clear_pointer(&priv->icon, purple_buddy_icon_unref);
-	g_clear_object(&priv->presence);
-
-	G_OBJECT_CLASS(purple_buddy_parent_class)->dispose(object);
-}
-
-static void
-purple_buddy_finalize(GObject *object) {
-	PurpleBuddy *buddy = PURPLE_BUDDY(object);
-	PurpleBuddyPrivate *priv = purple_buddy_get_instance_private(buddy);
-	PurpleProtocol *protocol;
-
-	/*
-	 * Tell the owner protocol that we're about to free the buddy so it
-	 * can free proto_data
-	 */
-	protocol = purple_account_get_protocol(priv->account);
-	if(protocol) {
-		purple_protocol_client_buddy_free(PURPLE_PROTOCOL_CLIENT(protocol),
-		                                  buddy);
-	}
-
-	g_free(priv->id);
-	g_free(priv->name);
-	g_free(priv->local_alias);
-	g_free(priv->server_alias);
-
-	G_OBJECT_CLASS(purple_buddy_parent_class)->finalize(object);
-}
-
-static void purple_buddy_class_init(PurpleBuddyClass *klass) {
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
-	obj_class->constructed = purple_buddy_constructed;
-	obj_class->dispose = purple_buddy_dispose;
-	obj_class->finalize = purple_buddy_finalize;
-	obj_class->get_property = purple_buddy_get_property;
-	obj_class->set_property = purple_buddy_set_property;
-
-	/**
-	 * PurpleBuddy:id:
-	 *
-	 * A globally unique identifier for this specific buddy.
-	 *
-	 * If an id is not passed during instantiation a uuid4 string is set as the
-	 * id.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_ID] = g_param_spec_string(
-		"id", "id",
-		"The globally unique identifier of the buddy.",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleBuddy:name:
-	 *
-	 * The name of the buddy.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_NAME] = g_param_spec_string(
-		"name", "Name",
-		"The name of the buddy.",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleBuddy:local-alias:
-	 *
-	 * An alias for the buddy created by the libpurple user.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_LOCAL_ALIAS] = g_param_spec_string(
-		"local-alias", "Local alias",
-		"Local alias of thee buddy.",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleBuddy:server-alias:
-	 *
-	 * An alias that is created by the remote user.
-	 *
-	 * This is typically called a display name now.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_SERVER_ALIAS] = g_param_spec_string(
-		"server-alias", "Server alias",
-		"Server-side alias of the buddy.",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleBuddy:icon:
-	 *
-	 * An avatar for the buddy.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_ICON] = g_param_spec_pointer(
-		"icon", "Buddy icon",
-		"The icon for the buddy.",
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleBuddy:account:
-	 *
-	 * The [class@Account] that this buddy belongs to.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_ACCOUNT] = g_param_spec_object(
-		"account", "Account",
-		"The account for the buddy.",
-		PURPLE_TYPE_ACCOUNT,
-		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleBuddy:presence:
-	 *
-	 * The [class@Presence] for this buddy.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_PRESENCE] = g_param_spec_object(
-		"presence", "Presence",
-		"The status information for the buddy.",
-		PURPLE_TYPE_PRESENCE,
-		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleBuddy:media-caps:
-	 *
-	 * The media caps for this buddy.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_MEDIA_CAPS] = g_param_spec_enum(
-		"media-caps", "Media capabilities",
-		"The media capabilities of the buddy.",
-		PURPLE_MEDIA_TYPE_CAPS, PURPLE_MEDIA_CAPS_NONE,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
-}
-
-/******************************************************************************
- * Public API
- *****************************************************************************/
-PurpleBuddy *
-purple_buddy_new(PurpleAccount *account, const gchar *name, const gchar *alias)
-{
-	PurpleBuddy *buddy = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
-	g_return_val_if_fail(name != NULL, NULL);
-
-	buddy = g_object_new(
-		PURPLE_TYPE_BUDDY,
-		"account", account,
-		"name", name,
-		"local-alias", alias,
-		NULL);
-
-	return buddy;
-}
-
-const gchar *
-purple_buddy_get_id(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	return priv->id;
-}
-
-void
-purple_buddy_set_icon(PurpleBuddy *buddy, PurpleBuddyIcon *icon) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	priv = purple_buddy_get_instance_private(buddy);
-	if(priv->icon == icon) {
-		return;
-	}
-
-	g_clear_pointer(&priv->icon, purple_buddy_icon_unref);
-	if(icon != NULL) {
-		priv->icon = purple_buddy_icon_ref(icon);
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_ICON]);
-
-	purple_signal_emit(purple_blist_get_handle(), "buddy-icon-changed", buddy);
-
-	purple_blist_update_node(purple_blist_get_default(),
-	                         PURPLE_BLIST_NODE(buddy));
-}
-
-PurpleBuddyIcon *
-purple_buddy_get_icon(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	return priv->icon;
-}
-
-PurpleAccount *
-purple_buddy_get_account(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	return priv->account;
-}
-
-void
-purple_buddy_set_name(PurpleBuddy *buddy, const gchar *name) {
-	PurpleBuddyList *blist = NULL;
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	if(priv->name != NULL) {
-		purple_blist_update_buddies_cache(buddy, name);
-	}
-
-	g_free(priv->name);
-	priv->name = purple_utf8_strip_unprintables(name);
-
-	g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_NAME]);
-
-	blist = purple_blist_get_default();
-	purple_blist_save_node(blist, PURPLE_BLIST_NODE(buddy));
-	purple_blist_update_node(blist, PURPLE_BLIST_NODE(buddy));
-}
-
-const gchar *
-purple_buddy_get_name(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	return priv->name;
-}
-
-gpointer
-purple_buddy_get_protocol_data(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	return priv->proto_data;
-}
-
-void
-purple_buddy_set_protocol_data(PurpleBuddy *buddy, gpointer data) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	priv->proto_data = data;
-}
-
-const gchar *
-purple_buddy_get_alias_only(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	if((priv->local_alias != NULL) && (*priv->local_alias != '\0')) {
-		return priv->local_alias;
-	} else if((priv->server_alias != NULL) && (*priv->server_alias != '\0')) {
-		return priv->server_alias;
-	}
-
-	return NULL;
-}
-
-const gchar *
-purple_buddy_get_contact_alias(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-	PurpleMetaContact *c = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	/* Search for an alias for the buddy. In order of precedence: */
-	/* The local buddy alias */
-	if(priv->local_alias != NULL) {
-		return priv->local_alias;
-	}
-
-	/* The contact alias */
-	c = purple_buddy_get_contact(buddy);
-	if((c != NULL) && (purple_meta_contact_get_alias(c) != NULL)) {
-		return purple_meta_contact_get_alias(c);
-	}
-
-	/* The server alias */
-	if((priv->server_alias) && (*priv->server_alias != '\0')) {
-		return priv->server_alias;
-	}
-
-	/* The buddy's user name (i.e. no alias) */
-	return priv->name;
-}
-
-const gchar *
-purple_buddy_get_alias(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	/* Search for an alias for the buddy. In order of precedence: */
-	/* The buddy alias */
-	if(priv->local_alias != NULL) {
-		return priv->local_alias;
-	}
-
-	/* The server alias */
-	if((priv->server_alias) && (*priv->server_alias != '\0')) {
-		return priv->server_alias;
-	}
-
-	/* The buddy's user name (i.e. no alias) */
-	return priv->name;
-}
-
-void
-purple_buddy_set_local_alias(PurpleBuddy *buddy, const gchar *alias) {
-	PurpleBuddyList *blist = NULL;
-	PurpleBuddyPrivate *priv = NULL;
-	gchar *old_alias = NULL, *new_alias = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	if((alias != NULL) && (*alias != '\0')) {
-		new_alias = purple_utf8_strip_unprintables(alias);
-	}
-
-	if(purple_strequal(priv->local_alias, new_alias)) {
-		g_free(new_alias);
-		return;
-	}
-
-	old_alias = priv->local_alias;
-
-	if((new_alias != NULL) && (*new_alias != '\0')) {
-		priv->local_alias = new_alias;
-	} else {
-		priv->local_alias = NULL;
-		g_free(new_alias);
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_LOCAL_ALIAS]);
-
-	blist = purple_blist_get_default();
-	purple_blist_save_node(blist, PURPLE_BLIST_NODE(buddy));
-	purple_blist_update_node(blist, PURPLE_BLIST_NODE(buddy));
-
-	purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased", buddy,
-	                   old_alias);
-	g_free(old_alias);
-}
-
-const gchar *
-purple_buddy_get_local_alias(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	return priv->local_alias;
-}
-
-void
-purple_buddy_set_server_alias(PurpleBuddy *buddy, const gchar *alias) {
-	PurpleBuddyList *blist = NULL;
-	PurpleBuddyPrivate *priv = NULL;
-	gchar *old_alias = NULL, *new_alias = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	if((alias != NULL) && (*alias != '\0') && g_utf8_validate(alias, -1, NULL))
-	{
-		new_alias = purple_utf8_strip_unprintables(alias);
-	}
-
-	if(purple_strequal(priv->server_alias, new_alias)) {
-		g_free(new_alias);
-
-		return;
-	}
-
-	old_alias = priv->server_alias;
-
-	if((new_alias != NULL) && (*new_alias != '\0')) {
-		priv->server_alias = new_alias;
-	} else {
-		priv->server_alias = NULL;
-		g_free(new_alias);
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_SERVER_ALIAS]);
-
-	blist = purple_blist_get_default();
-	purple_blist_save_node(blist, PURPLE_BLIST_NODE(buddy));
-	purple_blist_update_node(blist, PURPLE_BLIST_NODE(buddy));
-
-	purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased", buddy,
-	                   old_alias);
-	g_free(old_alias);
-}
-
-const gchar *
-purple_buddy_get_server_alias(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	if((priv->server_alias) && (*priv->server_alias != '\0')) {
-	    return priv->server_alias;
-	}
-
-	return NULL;
-}
-
-PurpleMetaContact *
-purple_buddy_get_contact(PurpleBuddy *buddy) {
-	PurpleBlistNode *parent = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	parent = purple_blist_node_get_parent(PURPLE_BLIST_NODE(buddy));
-	if(PURPLE_IS_META_CONTACT(parent)) {
-		return PURPLE_META_CONTACT(parent);
-	}
-
-	return NULL;
-}
-
-PurplePresence *
-purple_buddy_get_presence(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	return priv->presence;
-}
-
-PurpleMediaCaps
-purple_buddy_get_media_caps(PurpleBuddy *buddy) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), 0);
-
-	priv = purple_buddy_get_instance_private(buddy);
-
-	return priv->media_caps;
-}
-
-void
-purple_buddy_set_media_caps(PurpleBuddy *buddy, PurpleMediaCaps media_caps) {
-	PurpleBuddyPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	priv = purple_buddy_get_instance_private(buddy);
-	priv->media_caps = media_caps;
-
-	g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_MEDIA_CAPS]);
-}
-
-PurpleGroup *
-purple_buddy_get_group(PurpleBuddy *buddy) {
-	PurpleBlistNode *contact = NULL, *group = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
-
-	contact = purple_blist_node_get_parent(PURPLE_BLIST_NODE(buddy));
-	if(!PURPLE_IS_META_CONTACT(contact)) {
-		return purple_blist_get_default_group();
-	}
-
-	group = purple_blist_node_get_parent(contact);
-	if(PURPLE_IS_GROUP(group)) {
-		return PURPLE_GROUP(group);
-	}
-
-	return NULL;
-}
diff --git a/libpurple/buddyicon.h b/libpurple/buddyicon.h
deleted file mode 100644
--- a/libpurple/buddyicon.h
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * 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 library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_BUDDYICON_H
-#define PURPLE_BUDDYICON_H
-
-#include <glib.h>
-#include <gio/gio.h>
-
-#define PURPLE_TYPE_BUDDY_ICON (purple_buddy_icon_get_type())
-
-/**
- * PurpleBuddyIcon:
- *
- * An opaque structure representing a buddy icon for a particular user on a
- * particular #PurpleAccount.  Instances are reference-counted; use
- * purple_buddy_icon_ref() and purple_buddy_icon_unref() to take and release
- * references.
- *
- * Since: 2.0
- */
-typedef struct _PurpleBuddyIcon PurpleBuddyIcon;
-
-#define PURPLE_TYPE_BUDDY_ICON_SPEC  (purple_buddy_icon_spec_get_type())
-
-typedef struct _PurpleBuddyIconSpec PurpleBuddyIconSpec;
-
-#include "buddylist.h"
-#include "image.h"
-#include "purpleaccount.h"
-#include "purpleversion.h"
-#include "util.h"
-
-/**
- * PurpleBuddyIconScaleFlags:
- * @PURPLE_ICON_SCALE_DISPLAY: We scale the icon when we display it
- * @PURPLE_ICON_SCALE_SEND:    We scale the icon before we send it to the server
- *
- * Flags for when an icon should be scaled.
- *
- * Since: 2.0
- */
-typedef enum  /*< flags >*/
-{
-	PURPLE_ICON_SCALE_DISPLAY = 0x01,
-	PURPLE_ICON_SCALE_SEND    = 0x02
-
-} PurpleBuddyIconScaleFlags;
-
-/**
- * PurpleBuddyIconSpec:
- * @format: This is a comma-delimited list of image formats or %NULL if icons
- *          are not supported.  Neither the core nor the protocol will actually
- *          check to see if the data it's given matches this; it's entirely up
- *          to the UI to do what it wants
- * @min_width:    Minimum width of this icon
- * @min_height:   Minimum height of this icon
- * @max_width:    Maximum width of this icon
- * @max_height:   Maximum height of this icon
- * @max_filesize: Maximum size in bytes
- * @scale_rules:  How to stretch this icon
- *
- * A description of a Buddy Icon specification.  This tells Purple what kind of
- * image file it should give a protocol, and what kind of image file it should
- * expect back. Dimensions less than 1 should be ignored and the image not
- * scaled.
- *
- * Since: 2.0
- */
-struct _PurpleBuddyIconSpec {
-	char *format;
-	int min_width;
-	int min_height;
-	int max_width;
-	int max_height;
-	size_t max_filesize;
-	PurpleBuddyIconScaleFlags scale_rules;
-};
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* Buddy Icon API                                                         */
-/**************************************************************************/
-
-/**
- * purple_buddy_icon_get_type:
- *
- * Returns: The #GType for the #PurpleBuddyIcon boxed structure.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GType purple_buddy_icon_get_type(void);
-
-/**
- * purple_buddy_icon_new:
- * @account:   The account the user is on.
- * @username:  The username the icon belongs to.
- * @icon_data: The buddy icon data.
- * @icon_len:  The buddy icon length.
- * @checksum:  A protocol checksum from the protocol or %NULL.
- *
- * Creates a new buddy icon structure and populates it.
- *
- * If an icon for this account+username already exists, you'll get a reference
- * to that structure, which will have been updated with the data supplied.
- *
- * Returns: The buddy icon structure, with a reference for the caller.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleBuddyIcon *purple_buddy_icon_new(PurpleAccount *account, const char *username,
-                                       void *icon_data, size_t icon_len,
-                                       const char *checksum);
-
-/**
- * purple_buddy_icon_ref:
- * @icon: The buddy icon.
- *
- * Increments the reference count on a buddy icon.
- *
- * Returns: @icon.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleBuddyIcon *purple_buddy_icon_ref(PurpleBuddyIcon *icon);
-
-/**
- * purple_buddy_icon_unref:
- * @icon: The buddy icon.
- *
- * Decrements the reference count on a buddy icon.
- *
- * If the reference count reaches 0, the icon will be destroyed.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_buddy_icon_unref(PurpleBuddyIcon *icon);
-
-/**
- * purple_buddy_icon_update:
- * @icon: The buddy icon.
- *
- * Updates every instance of this icon.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_buddy_icon_update(PurpleBuddyIcon *icon);
-
-/**
- * purple_buddy_icon_set_data:
- * @icon: The buddy icon.
- * @data: (transfer full): The buddy icon data.
- * @len: The length of the data in @data.
- * @checksum: A protocol checksum from the protocol or %NULL.
- *
- * Sets the buddy icon's data.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void
-purple_buddy_icon_set_data(PurpleBuddyIcon *icon, guchar *data,
-                           size_t len, const char *checksum);
-
-/**
- * purple_buddy_icon_save_to_filename:
- * @icon: The #PurpleBuddyIcon instance.
- * @filename: The filename to write.
- * @error: Return address for a #GError, or %NULL.
- *
- * Writes the contents of @icon to @filename.
- *
- * Returns: %TRUE on success, or %FALSE on error possibly with @error set.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gboolean purple_buddy_icon_save_to_filename(PurpleBuddyIcon *icon, const gchar *filename, GError **error);
-
-/**
- * purple_buddy_icon_get_account:
- * @icon: The buddy icon.
- *
- * Returns the buddy icon's account.
- *
- * Returns: (transfer none): The account.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleAccount *purple_buddy_icon_get_account(const PurpleBuddyIcon *icon);
-
-/**
- * purple_buddy_icon_get_username:
- * @icon: The buddy icon.
- *
- * Returns the buddy icon's username.
- *
- * Returns: The username.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_icon_get_username(const PurpleBuddyIcon *icon);
-
-/**
- * purple_buddy_icon_get_checksum:
- * @icon: The buddy icon.
- *
- * Returns the buddy icon's checksum.
- *
- * This function is really only for protocol use.
- *
- * Returns: The checksum.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_icon_get_checksum(const PurpleBuddyIcon *icon);
-
-/**
- * purple_buddy_icon_get_data:
- * @icon: The buddy icon.
- * @len:  If not %NULL, the length of the icon data returned will be
- *             set in the location pointed to by this.
- *
- * Returns the buddy icon's data.
- *
- * Returns: A pointer to the icon data.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-gconstpointer purple_buddy_icon_get_data(const PurpleBuddyIcon *icon, size_t *len);
-
-/**
- * purple_buddy_icon_get_stream:
- * @icon: The #PurpleBuddyIcon instance.
- *
- * Gets the data of @icon as a #GInputStream.
- *
- * Returns: (transfer full): A new #GInputStream.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GInputStream *purple_buddy_icon_get_stream(PurpleBuddyIcon *icon);
-
-/**
- * purple_buddy_icon_get_extension:
- * @icon: The buddy icon.
- *
- * Returns an extension corresponding to the buddy icon's file type.
- *
- * Returns: The icon's extension, "icon" if unknown, or %NULL if
- *         the image data has disappeared.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_icon_get_extension(const PurpleBuddyIcon *icon);
-
-/**
- * purple_buddy_icon_get_full_path:
- * @icon: The buddy icon
- *
- * Returns a full path to an icon.
- *
- * If the icon has data and the file exists in the cache, this will return
- * a full path to the cache file.
- *
- * In general, it is not appropriate to be poking in the icon cache
- * directly.  If you find yourself wanting to use this function, think
- * very long and hard about it, and then don't.
- *
- * Returns: (transfer none): A full path to the file, or %NULL under various conditions.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const gchar *purple_buddy_icon_get_full_path(PurpleBuddyIcon *icon);
-
-/**************************************************************************/
-/* Buddy Icon Subsystem API                                               */
-/**************************************************************************/
-
-/**
- * purple_buddy_icons_set_for_user:
- * @account: The account the user is on.
- * @username: The username of the user.
- * @icon_data: (transfer full): The buddy icon data.
- * @icon_len: The length of the icon data.
- * @checksum: A protocol checksum from the protocol or %NULL.
- *
- * Sets a buddy icon for a user.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_buddy_icons_set_for_user(PurpleAccount *account, const char *username, void *icon_data, size_t icon_len, const char *checksum);
-
-/**
- * purple_buddy_icons_get_checksum_for_user:
- * @buddy: The buddy
- *
- * Returns the checksum for the buddy icon of a specified buddy.
- *
- * This avoids loading the icon image data from the cache if it's
- * not already loaded for some other reason.
- *
- * Returns: The checksum.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_icons_get_checksum_for_user(PurpleBuddy *buddy);
-
-/**
- * purple_buddy_icons_find:
- * @account:  The account the user is on.
- * @username: The username of the user.
- *
- * Returns the buddy icon information for a user.
- *
- * Returns: The icon (with a reference for the caller) if found, or %NULL if
- *         not found.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleBuddyIcon *purple_buddy_icons_find(PurpleAccount *account, const char *username);
-
-/**
- * purple_buddy_icons_find_account_icon:
- * @account: The account
- *
- * Returns the buddy icon image for an account.
- *
- * This function deals with loading the icon from the cache, if
- * needed, so it should be called in any case where you want the
- * appropriate icon.
- *
- * Returns: (transfer full): The account's buddy icon image.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleImage *purple_buddy_icons_find_account_icon(PurpleAccount *account);
-
-/**
- * purple_buddy_icons_set_account_icon:
- * @account:   The account for which to set a custom icon.
- * @icon_data: The image data of the icon, which the
- *                  buddy icon code will free.
- * @icon_len:  The length of the data in @icon_data.
- *
- * Sets a buddy icon for an account.
- *
- * This function will deal with saving a record of the icon,
- * caching the data, etc.
- *
- * Returns: (transfer none): The icon that was set.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleImage *purple_buddy_icons_set_account_icon(PurpleAccount *account, guchar *icon_data, size_t icon_len);
-
-/**
- * purple_buddy_icons_get_account_icon_timestamp:
- * @account: The account
- *
- * Returns the timestamp of when the icon was set.
- *
- * This is intended for use in protocols that require a timestamp for
- * buddy icon update reasons.
- *
- * Returns: The time the icon was set, or 0 if an error occurred.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-time_t purple_buddy_icons_get_account_icon_timestamp(PurpleAccount *account);
-
-/**
- * purple_buddy_icons_node_has_custom_icon:
- * @node: The blist node.
- *
- * Returns a boolean indicating if a given blist node has a custom buddy icon.
- *
- * Returns: A boolean indicating if @node has a custom buddy icon.
- *
- * Since: 2.5
- */
-PURPLE_AVAILABLE_IN_2_5
-gboolean purple_buddy_icons_node_has_custom_icon(PurpleBlistNode *node);
-
-/**
- * purple_buddy_icons_node_find_custom_icon:
- * @node: The node.
- *
- * Returns the custom buddy icon image for a blist node.
- *
- * This function deals with loading the icon from the cache, if
- * needed, so it should be called in any case where you want the
- * appropriate icon.
- *
- * Returns: (transfer full): The custom buddy icon.
- *
- * Since: 2.5
- */
-PURPLE_AVAILABLE_IN_2_5
-PurpleImage *purple_buddy_icons_node_find_custom_icon(PurpleBlistNode *node);
-
-/**
- * purple_buddy_icons_node_set_custom_icon:
- * @node:      The blist node for which to set a custom icon.
- * @icon_data: The image data of the icon, which the buddy icon code will
- *                  free. Use NULL to unset the icon.
- * @icon_len:  The length of the data in @icon_data.
- *
- * Sets a custom buddy icon for a blist node.
- *
- * This function will deal with saving a record of the icon, caching the data,
- * etc.
- *
- * Returns: (transfer none): The icon that was set.
- *
- * Since: 2.5
- */
-PURPLE_AVAILABLE_IN_2_5
-PurpleImage *purple_buddy_icons_node_set_custom_icon(PurpleBlistNode *node, guchar *icon_data, size_t icon_len);
-
-/**
- * purple_buddy_icons_node_set_custom_icon_from_file:
- * @node:      The blist node for which to set a custom icon.
- * @filename:  The path to the icon to set for the blist node. Use NULL
- *                  to unset the custom icon.
- *
- * Sets a custom buddy icon for a blist node.
- *
- * Convenience wrapper around purple_buddy_icons_node_set_custom_icon.
- * See purple_buddy_icons_node_set_custom_icon().
- *
- * Returns: (transfer none): The icon that was set.
- *
- * Since: 2.5
- */
-PURPLE_AVAILABLE_IN_2_5
-PurpleImage *purple_buddy_icons_node_set_custom_icon_from_file(PurpleBlistNode *node, const gchar *filename);
-
-/**
- * purple_buddy_icons_set_caching:
- * @caching: TRUE if buddy icon caching should be enabled, or FALSE otherwise.
- *
- * Sets whether or not buddy icon caching is enabled.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_buddy_icons_set_caching(gboolean caching);
-
-/**
- * purple_buddy_icons_is_caching:
- *
- * Returns whether or not buddy icon caching should be enabled.
- *
- * The default is TRUE, unless otherwise specified by
- * purple_buddy_icons_set_caching().
- *
- * Returns: TRUE if buddy icon caching is enabled, or FALSE otherwise.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-gboolean purple_buddy_icons_is_caching(void);
-
-/**
- * purple_buddy_icons_set_cache_dir:
- * @cache_dir: The directory to store buddy icon cache files to.
- *
- * Sets the directory used to store buddy icon cache files.
- */
-void purple_buddy_icons_set_cache_dir(const char *cache_dir);
-
-/**
- * purple_buddy_icons_get_cache_dir:
- *
- * Returns the directory used to store buddy icon cache files.
- *
- * The default directory is PURPLEDIR/icons, unless otherwise specified
- * by purple_buddy_icons_set_cache_dir().
- *
- * Returns: The directory to store buddy icon cache files to.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_buddy_icons_get_cache_dir(void);
-
-/**
- * purple_buddy_icons_get_handle:
- *
- * Returns the buddy icon subsystem handle.
- *
- * Returns: The subsystem handle.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void *purple_buddy_icons_get_handle(void);
-
-/**
- * purple_buddy_icons_init:
- *
- * Initializes the buddy icon subsystem.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_buddy_icons_init(void);
-
-/**
- * purple_buddy_icons_uninit:
- *
- * Uninitializes the buddy icon subsystem.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_buddy_icons_uninit(void);
-
-/**************************************************************************/
-/* Buddy Icon Spec API                                                    */
-/**************************************************************************/
-
-/**
- * purple_buddy_icon_spec_get_type:
- *
- * Returns: The #GType for the #PurpleBuddyIconSpec boxed structure.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GType purple_buddy_icon_spec_get_type(void);
-
-/**
- * purple_buddy_icon_spec_new:
- * @format:        A comma-delimited list of image formats or %NULL if
- *                 icons are not supported
- * @min_width:     Minimum width of an icon
- * @min_height:    Minimum height of an icon
- * @max_width:     Maximum width of an icon
- * @max_height:    Maximum height of an icon
- * @max_filesize:  Maximum file size in bytes
- * @scale_rules:   How to stretch this icon
- *
- * Creates a new #PurpleBuddyIconSpec instance.
- *
- * Returns:  A new buddy icon spec.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleBuddyIconSpec *purple_buddy_icon_spec_new(char *format, int min_width, int min_height, int max_width, int max_height, size_t max_filesize, PurpleBuddyIconScaleFlags scale_rules);
-
-/**
- * purple_buddy_icon_spec_free:
- * @spec: The #PurpleBuddyIconSpec instance.
- *
- * Frees @spec.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_buddy_icon_spec_free(PurpleBuddyIconSpec *spec);
-
-/**
- * purple_buddy_icon_spec_get_scaled_size:
- * @spec: The buddy icon spec.
- * @width: (inout): On input, the suggested width. On output, the width
- *                  constrained by the spec.
- * @height: (inout): On input, the suggested height. On output, the height
- *                   constrained by the spec.
- *
- * Gets display size for a buddy icon
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_buddy_icon_spec_get_scaled_size(PurpleBuddyIconSpec *spec, int *width, int *height);
-
-G_END_DECLS
-
-#endif /* PURPLE_BUDDYICON_H */
diff --git a/libpurple/buddyicon.c b/libpurple/buddyicon.c
deleted file mode 100644
--- a/libpurple/buddyicon.c
+++ /dev/null
@@ -1,1216 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * 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 library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "buddyicon.h"
-#include "debug.h"
-#include "image.h"
-#include "purpleaccountmanager.h"
-#include "purpleconversation.h"
-#include "purpleconversationmanager.h"
-#include "purplepath.h"
-#include "purpleprivate.h"
-#include "purpleprotocolserver.h"
-
-#ifdef _WIN32
-# include "win32/libc_interface.h"
-#endif
-
-/* NOTE: Instances of this struct are allocated without zeroing the memory, so
- * NOTE: be sure to update purple_buddy_icon_new() if you add members. */
-struct _PurpleBuddyIcon
-{
-	PurpleAccount *account;    /* The account the user is on.          */
-	PurpleImage *img;          /* The image containing
-	                              the icon data.                       */
-	char *username;            /* The username the icon belongs to.    */
-	char *checksum;            /* The protocol checksum.               */
-	unsigned int ref_count;    /* The buddy icon reference count.      */
-};
-
-/*
- * This is the big grand daddy hash table that contains references to
- * everybody's buddy icons.
- *
- * Key is a PurpleAccount.
- * Value is another hash table, usually referred to as "icon_cache."
- * For this inner hash table:
- *    Key is the username of the buddy whose icon is being stored.
- *    Value is the PurpleBuddyIcon for this buddy.
- */
-static GHashTable *account_cache = NULL;
-
-/*
- * This hash table contains a bunch of PurpleImages that are
- * shared across all accounts.
- *
- * Key is the filename for this image as constructed by
- * purple_image_generate_filename().  So it is the base16 encoded
- * sha-1 hash plus an appropriate file extension.  For example:
- *   "0f4972d17d1e70e751c43c90c948e72efbff9796.gif"
- *
- * The value is a PurpleImage containing the icon data.  These images are
- * reference counted, and when the count reaches 0 we remove the image from
- * the hash table (but it might still be saved on disk, if the icon is being
- * used by offline accounts or some such).
- */
-static GHashTable *icon_data_cache = NULL;
-
-/*
- * This hash table contains reference counts for how many times each
- * icon in the ~/.purple/icons/ directory is being used.  It's pretty
- * crazy.  It maintains the reference count across sessions, too, so
- * if you exit Pidgin then this hash table is reconstructed the next
- * time Pidgin starts.
- *
- * Key is the filename for this image as constructed by
- * purple_image_generate_filename().  So it is the base16 encoded
- * sha-1 hash plus an appropriate file extension.  For example:
- *   "0f4972d17d1e70e751c43c90c948e72efbff9796.gif"
- *
- * The value is a GINT_TO_POINTER count of the number of times this
- * icon is used.  So if four of your buddies are using an icon, and
- * you have the icon set for two of your accounts, then this number
- * will be six.  When this reference count reaches 0 the icon will
- * be deleted from disk.
- */
-static GHashTable *icon_file_cache = NULL;
-
-/*
- * This hash table is used for both custom buddy icons on PurpleBlistNodes and
- * account icons.
- */
-static GHashTable *pointer_icon_cache = NULL;
-
-static char       *cache_dir     = NULL;
-
-/* "Should icons be cached to disk?" */
-static gboolean    icon_caching  = TRUE;
-
-static void delete_buddy_icon_settings(PurpleBlistNode *node, const char *setting_name);
-
-/*
- * Begin functions for dealing with the on-disk icon cache
- */
-
-static void
-ref_filename(const char *filename)
-{
-	int refs;
-
-	g_return_if_fail(filename != NULL);
-
-	refs = GPOINTER_TO_INT(g_hash_table_lookup(icon_file_cache, filename));
-
-	g_hash_table_insert(icon_file_cache, g_strdup(filename),
-	                    GINT_TO_POINTER(refs + 1));
-}
-
-static void
-unref_filename(const char *filename)
-{
-	int refs;
-
-	if (filename == NULL)
-		return;
-
-	refs = GPOINTER_TO_INT(g_hash_table_lookup(icon_file_cache, filename));
-
-	if (refs == 1)
-	{
-		g_hash_table_remove(icon_file_cache, filename);
-	}
-	else
-	{
-		g_hash_table_insert(icon_file_cache, g_strdup(filename),
-		                    GINT_TO_POINTER(refs - 1));
-	}
-}
-
-static const gchar *
-image_get_filename(PurpleImage *img)
-{
-	return g_object_get_data(G_OBJECT(img), "purple-buddyicon-filename");
-}
-
-static void
-purple_buddy_icon_data_cache(PurpleImage *img)
-{
-	const gchar *dirname, *filename;
-	gchar *path;
-
-	g_return_if_fail(PURPLE_IS_IMAGE(img));
-
-	if (!purple_buddy_icons_is_caching())
-		return;
-
-	dirname = purple_buddy_icons_get_cache_dir();
-	filename = image_get_filename(img);
-	g_return_if_fail(filename != NULL);
-
-	if (!g_file_test(dirname, G_FILE_TEST_IS_DIR))
-	{
-		purple_debug_info("buddyicon", "creating icon cache directory");
-
-		if (g_mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) < 0)
-		{
-			purple_debug_error("buddyicon",
-				"unable to create directory %s: %s",
-				dirname, g_strerror(errno));
-			return;
-		}
-	}
-
-	path = g_build_filename(dirname, filename, NULL);
-	if (!purple_image_save(img, path))
-		purple_debug_error("buddyicon", "failed to save icon %s", path);
-
-	g_free(path);
-}
-
-static void
-purple_buddy_icon_data_uncache_file(const char *filename)
-{
-	const char *dirname;
-	char *path;
-
-	g_return_if_fail(filename != NULL);
-
-	/* It's possible that there are other references to this icon
-	 * cache file that are not currently loaded into memory. */
-	if (GPOINTER_TO_INT(g_hash_table_lookup(icon_file_cache, filename)))
-		return;
-
-	dirname = purple_buddy_icons_get_cache_dir();
-	path = g_build_filename(dirname, filename, NULL);
-
-	if (g_file_test(path, G_FILE_TEST_EXISTS))
-	{
-		if (g_unlink(path))
-		{
-			purple_debug_error("buddyicon", "Failed to delete %s: %s\n",
-			                   path, g_strerror(errno));
-		}
-		else
-		{
-			purple_debug_info("buddyicon", "Deleted cache file: %s\n", path);
-		}
-	}
-
-	g_free(path);
-}
-
-/*
- * End functions for dealing with the on-disk icon cache
- */
-
-/*
- * Begin functions for dealing with the in-memory icon cache
- */
-
-static gboolean
-value_equals(G_GNUC_UNUSED gpointer key, gpointer value, gpointer user_data)
-{
-	return (value == user_data);
-}
-
-static void
-image_deleting_cb(gpointer _filename)
-{
-	PurpleImage *img;
-	gchar *filename = _filename;
-
-	img = g_hash_table_lookup(icon_data_cache, filename);
-	purple_buddy_icon_data_uncache_file(filename);
-	g_hash_table_remove(icon_data_cache, filename);
-
-	/* We could make this O(1) by using another hash table, but
-	 * this is probably good enough. */
-	g_hash_table_foreach_remove(pointer_icon_cache, value_equals, (gpointer)img);
-
-	g_free(filename);
-}
-
-static PurpleImage *
-purple_buddy_icon_data_new(guchar *icon_data, size_t icon_len)
-{
-	PurpleImage *newimg, *oldimg;
-	const gchar *filename;
-
-	g_return_val_if_fail(icon_data != NULL, NULL);
-	g_return_val_if_fail(icon_len > 0, NULL);
-
-	newimg = purple_image_new_take_data(icon_data, icon_len);
-	filename = purple_image_generate_filename(newimg);
-
-	/* TODO: Why is this function called for buddies without icons? If this is
-	 * intended, should the filename be null?
-	 */
-	if (filename != NULL) {
-		oldimg = g_hash_table_lookup(icon_data_cache, filename);
-		if (oldimg) {
-			g_warn_if_fail(PURPLE_IS_IMAGE(oldimg));
-			g_object_unref(newimg);
-			g_object_ref(oldimg);
-			return oldimg;
-		}
-
-		/* This will take ownership of file and free it as needed */
-		g_hash_table_insert(icon_data_cache, g_strdup(filename), newimg);
-	}
-
-	g_object_set_data_full(G_OBJECT(newimg), "purple-buddyicon-filename",
-		g_strdup(filename), image_deleting_cb);
-
-	purple_buddy_icon_data_cache(newimg);
-
-	return newimg;
-}
-
-/*
- * End functions for dealing with the in-memory icon cache
- */
-
-static PurpleBuddyIcon *
-purple_buddy_icon_create(PurpleAccount *account, const char *username)
-{
-	PurpleBuddyIcon *icon;
-	GHashTable *icon_cache;
-
-	/* This does not zero.  See purple_buddy_icon_new() for
-	 * information on which function allocates which member. */
-	icon = g_slice_new(PurpleBuddyIcon);
-
-	icon->account = account;
-	icon->username = g_strdup(username);
-	icon->checksum = NULL;
-	icon->ref_count = 1;
-
-	icon_cache = g_hash_table_lookup(account_cache, account);
-
-	if (icon_cache == NULL)
-	{
-		icon_cache = g_hash_table_new(g_str_hash, g_str_equal);
-
-		g_hash_table_insert(account_cache, account, icon_cache);
-	}
-
-	g_hash_table_insert(icon_cache,
-	                    (char *)purple_buddy_icon_get_username(icon), icon);
-	return icon;
-}
-
-PurpleBuddyIcon *
-purple_buddy_icon_new(PurpleAccount *account, const char *username,
-                      void *icon_data, size_t icon_len,
-                      const char *checksum)
-{
-	PurpleBuddyIcon *icon;
-
-	g_return_val_if_fail(account   != NULL, NULL);
-	g_return_val_if_fail(username  != NULL, NULL);
-	g_return_val_if_fail(icon_data != NULL, NULL);
-	g_return_val_if_fail(icon_len  > 0,    NULL);
-
-	/* purple_buddy_icons_find() does allocation, so be
-	 * sure to update it as well when members are added. */
-	icon = purple_buddy_icons_find(account, username);
-
-	/* purple_buddy_icon_create() sets account & username */
-	if (icon == NULL)
-		icon = purple_buddy_icon_create(account, username);
-
-	/* purple_buddy_icon_set_data() sets img, but it
-	 * references img first, so we need to initialize it */
-	icon->img = NULL;
-	purple_buddy_icon_set_data(icon, icon_data, icon_len, checksum);
-
-	return icon;
-}
-
-PurpleBuddyIcon *
-purple_buddy_icon_ref(PurpleBuddyIcon *icon)
-{
-	g_return_val_if_fail(icon != NULL, NULL);
-
-	icon->ref_count++;
-
-	return icon;
-}
-
-void
-purple_buddy_icon_unref(PurpleBuddyIcon *icon)
-{
-	if (icon == NULL)
-		return;
-
-	g_return_if_fail(icon->ref_count > 0);
-
-	icon->ref_count--;
-
-	if (icon->ref_count == 0)
-	{
-		GHashTable *icon_cache = g_hash_table_lookup(account_cache, purple_buddy_icon_get_account(icon));
-
-		if (icon_cache != NULL)
-			g_hash_table_remove(icon_cache, purple_buddy_icon_get_username(icon));
-
-		g_free(icon->username);
-		g_free(icon->checksum);
-		g_object_unref(icon->img);
-
-		g_slice_free(PurpleBuddyIcon, icon);
-	}
-}
-
-void
-purple_buddy_icon_update(PurpleBuddyIcon *icon)
-{
-	PurpleAccount *account;
-	const char *username;
-	PurpleBuddyIcon *icon_to_set;
-	GSList *buddies;
-
-	g_return_if_fail(icon != NULL);
-
-	account  = purple_buddy_icon_get_account(icon);
-	username = purple_buddy_icon_get_username(icon);
-
-	/* If no data exists (icon->img == NULL), then call the functions below
-	 * with NULL to unset the icon.  They will then unref the icon and it should
-	 * be destroyed.  The only way it wouldn't be destroyed is if someone
-	 * else is holding a reference to it, in which case they can kill
-	 * the icon when they realize it has no data. */
-	icon_to_set = icon->img ? icon : NULL;
-
-	/* Ensure that icon remains valid throughout */
-	purple_buddy_icon_ref(icon);
-
-	buddies = purple_blist_find_buddies(account, username);
-	while (buddies != NULL)
-	{
-		PurpleBuddy *buddy = (PurpleBuddy *)buddies->data;
-		char *old_icon;
-
-		purple_buddy_set_icon(buddy, icon_to_set);
-		old_icon = g_strdup(purple_blist_node_get_string((PurpleBlistNode *)buddy,
-		                                                 "buddy_icon"));
-		if (icon->img && purple_buddy_icons_is_caching())
-		{
-			const char *filename = image_get_filename(icon->img);
-			g_warn_if_fail(filename != NULL);
-			purple_blist_node_set_string((PurpleBlistNode *)buddy,
-			                             "buddy_icon",
-			                             filename);
-
-			if (icon->checksum && *icon->checksum)
-			{
-				purple_blist_node_set_string((PurpleBlistNode *)buddy,
-				                             "icon_checksum",
-				                             icon->checksum);
-			}
-			else
-			{
-				purple_blist_node_remove_setting((PurpleBlistNode *)buddy,
-				                                 "icon_checksum");
-			}
-			ref_filename(filename);
-		}
-		else if (!icon->img)
-		{
-			purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon");
-			purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "icon_checksum");
-		}
-		unref_filename(old_icon);
-		g_free(old_icon);
-
-		buddies = g_slist_delete_link(buddies, buddies);
-	}
-
-	/* icon's refcount was incremented above */
-	purple_buddy_icon_unref(icon);
-}
-
-void
-purple_buddy_icon_set_data(PurpleBuddyIcon *icon, guchar *data,
-                           size_t len, const char *checksum)
-{
-	PurpleImage *old_img;
-
-	g_return_if_fail(icon != NULL);
-
-	old_img = icon->img;
-	icon->img = NULL;
-
-	if (data != NULL)
-	{
-		if (len > 0)
-			icon->img = purple_buddy_icon_data_new(data, len);
-		else
-			g_free(data);
-	}
-
-	g_free(icon->checksum);
-	icon->checksum = g_strdup(checksum);
-
-	purple_buddy_icon_update(icon);
-
-	if (old_img)
-		g_object_unref(old_img);
-}
-
-gboolean
-purple_buddy_icon_save_to_filename(PurpleBuddyIcon *icon,
-                                   const gchar *filename, GError **error)
-{
-	gconstpointer data;
-	size_t len = 0;
-
-	data = purple_buddy_icon_get_data(icon, &len);
-
-	return g_file_set_contents(filename, data, len, error);
-}
-
-
-PurpleAccount *
-purple_buddy_icon_get_account(const PurpleBuddyIcon *icon)
-{
-	g_return_val_if_fail(icon != NULL, NULL);
-
-	return icon->account;
-}
-
-const char *
-purple_buddy_icon_get_username(const PurpleBuddyIcon *icon)
-{
-	g_return_val_if_fail(icon != NULL, NULL);
-
-	return icon->username;
-}
-
-const char *
-purple_buddy_icon_get_checksum(const PurpleBuddyIcon *icon)
-{
-	g_return_val_if_fail(icon != NULL, NULL);
-
-	return icon->checksum;
-}
-
-gconstpointer
-purple_buddy_icon_get_data(const PurpleBuddyIcon *icon, size_t *len)
-{
-	g_return_val_if_fail(icon != NULL, NULL);
-
-	if (icon->img)
-	{
-		if (len != NULL)
-			*len = purple_image_get_data_size(icon->img);
-
-		return purple_image_get_data(icon->img);
-	}
-
-	return NULL;
-}
-
-GInputStream *
-purple_buddy_icon_get_stream(PurpleBuddyIcon *icon) {
-	gconstpointer data = NULL;
-	size_t len = 0;
-
-	g_return_val_if_fail(icon != NULL, NULL);
-
-	data = purple_buddy_icon_get_data(icon, &len);
-
-	return g_memory_input_stream_new_from_data(data, (gssize)len, NULL);
-}
-
-const char *
-purple_buddy_icon_get_extension(const PurpleBuddyIcon *icon)
-{
-	if (icon->img != NULL)
-		return purple_image_get_extension(icon->img);
-
-	return NULL;
-}
-
-void
-purple_buddy_icons_set_for_user(PurpleAccount *account, const char *username,
-                                void *icon_data, size_t icon_len,
-                                const char *checksum)
-{
-	GHashTable *icon_cache;
-	PurpleBuddyIcon *icon = NULL;
-
-	g_return_if_fail(account  != NULL);
-	g_return_if_fail(username != NULL);
-
-	icon_cache = g_hash_table_lookup(account_cache, account);
-
-	if (icon_cache != NULL)
-		icon = g_hash_table_lookup(icon_cache, username);
-
-	if (icon != NULL)
-		purple_buddy_icon_set_data(icon, icon_data, icon_len, checksum);
-	else if (icon_data && icon_len > 0)
-	{
-		PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len, checksum);
-
-		/* purple_buddy_icon_new() calls
-		 * purple_buddy_icon_set_data(), which calls
-		 * purple_buddy_icon_update(), which has the buddy list
-		 * and conversations take references as appropriate.
-		 * This function doesn't return icon, so we can't
-		 * leave a reference dangling. */
-		purple_buddy_icon_unref(icon);
-	}
-	else
-	{
-		/* If the buddy list or a conversation was holding a
-		 * reference, we'd have found the icon in the cache.
-		 * Since we know we're deleting the icon, we only
-		 * need a subset of purple_buddy_icon_update(). */
-
-		GSList *buddies = purple_blist_find_buddies(account, username);
-		while (buddies != NULL)
-		{
-			PurpleBuddy *buddy = (PurpleBuddy *)buddies->data;
-
-			unref_filename(purple_blist_node_get_string((PurpleBlistNode *)buddy, "buddy_icon"));
-			purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon");
-			purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "icon_checksum");
-
-			buddies = g_slist_delete_link(buddies, buddies);
-		}
-	}
-}
-
-const gchar *
-purple_buddy_icon_get_full_path(PurpleBuddyIcon *icon)
-{
-	const gchar *path;
-
-	g_return_val_if_fail(icon != NULL, NULL);
-
-	if (icon->img == NULL)
-		return NULL;
-
-	path = purple_image_get_path(icon->img);
-	if (!g_file_test(path, G_FILE_TEST_EXISTS))
-	{
-		return NULL;
-	}
-	return path;
-}
-
-const char *
-purple_buddy_icons_get_checksum_for_user(PurpleBuddy *buddy)
-{
-	return purple_blist_node_get_string((PurpleBlistNode*)buddy,
-	                                    "icon_checksum");
-}
-
-static gboolean
-read_icon_file(const char *path, guchar **data, size_t *len)
-{
-	GError *err = NULL;
-
-	if (!g_file_get_contents(path, (gchar **)data, len, &err))
-	{
-		purple_debug_error("buddyicon", "Error reading %s: %s\n",
-		                   path, err->message);
-		g_error_free(err);
-
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-PurpleBuddyIcon *
-purple_buddy_icons_find(PurpleAccount *account, const char *username)
-{
-	GHashTable *icon_cache;
-	PurpleBuddyIcon *icon = NULL;
-
-	g_return_val_if_fail(account  != NULL, NULL);
-	g_return_val_if_fail(username != NULL, NULL);
-
-	icon_cache = g_hash_table_lookup(account_cache, account);
-
-	if ((icon_cache == NULL) || ((icon = g_hash_table_lookup(icon_cache, username)) == NULL))
-	{
-		/* The icon is not currently cached in memory--try reading from disk */
-		PurpleBuddy *b = purple_blist_find_buddy(account, username);
-		const char *protocol_icon_file;
-		const char *dirname;
-		gboolean caching;
-		gchar *path;
-		guchar *data;
-		size_t len;
-
-		if (!b)
-			return NULL;
-
-		protocol_icon_file = purple_blist_node_get_string((PurpleBlistNode*)b, "buddy_icon");
-
-		if (protocol_icon_file == NULL)
-			return NULL;
-
-		dirname = purple_buddy_icons_get_cache_dir();
-
-		caching = purple_buddy_icons_is_caching();
-		/* By disabling caching temporarily, we avoid a loop
-		 * and don't have to add special code through several
-		 * functions. */
-		purple_buddy_icons_set_caching(FALSE);
-
-		path = g_build_filename(dirname, protocol_icon_file, NULL);
-		if (read_icon_file(path, &data, &len)) {
-			const char *checksum;
-
-			icon = purple_buddy_icon_create(account, username);
-			icon->img = NULL;
-			checksum = purple_blist_node_get_string((PurpleBlistNode *)b,
-			                                        "icon_checksum");
-			purple_buddy_icon_set_data(icon, data, len, checksum);
-		} else {
-			delete_buddy_icon_settings((PurpleBlistNode *)b, "buddy_icon");
-		}
-
-		g_free(path);
-
-		purple_buddy_icons_set_caching(caching);
-	}
-
-	return (icon ? purple_buddy_icon_ref(icon) : NULL);
-}
-
-PurpleImage *
-purple_buddy_icons_find_account_icon(PurpleAccount *account)
-{
-	PurpleImage *img;
-	const char *account_icon_file;
-	const char *dirname;
-	char *path;
-	guchar *data;
-	size_t len;
-
-	g_return_val_if_fail(account != NULL, NULL);
-
-	img = g_hash_table_lookup(pointer_icon_cache, account);
-	if (img) {
-		g_object_ref(img);
-		return img;
-	}
-
-	account_icon_file = purple_account_get_string(account, "buddy_icon", NULL);
-
-	if (account_icon_file == NULL)
-		return NULL;
-
-	dirname = purple_buddy_icons_get_cache_dir();
-	path = g_build_filename(dirname, account_icon_file, NULL);
-
-	if (read_icon_file(path, &data, &len)) {
-		g_free(path);
-		img = purple_buddy_icons_set_account_icon(account, data, len);
-		g_object_ref(img);
-		return img;
-	}
-	g_free(path);
-
-	return NULL;
-}
-
-PurpleImage *
-purple_buddy_icons_set_account_icon(PurpleAccount *account,
-                                    guchar *icon_data, size_t icon_len)
-{
-	PurpleImage *old_img;
-	PurpleImage *img = NULL;
-	char *old_icon;
-
-	if (icon_data != NULL && icon_len > 0) {
-		img = purple_buddy_icon_data_new(icon_data, icon_len);
-	}
-
-	old_icon = g_strdup(purple_account_get_string(account, "buddy_icon", NULL));
-	if (img && purple_buddy_icons_is_caching())
-	{
-		const char *filename = image_get_filename(img);
-		g_warn_if_fail(filename != NULL);
-		purple_account_set_string(account, "buddy_icon", filename);
-		purple_account_set_int(account, "buddy_icon_timestamp", time(NULL));
-		ref_filename(filename);
-	}
-	else
-	{
-		purple_account_set_string(account, "buddy_icon", NULL);
-		purple_account_set_int(account, "buddy_icon_timestamp", 0);
-	}
-	unref_filename(old_icon);
-
-	old_img = g_hash_table_lookup(pointer_icon_cache, account);
-
-	if (img)
-		g_hash_table_insert(pointer_icon_cache, account, img);
-	else
-		g_hash_table_remove(pointer_icon_cache, account);
-
-	if (!purple_account_is_disconnected(account))
-	{
-		PurpleConnection *gc;
-		PurpleProtocol *protocol;
-
-		gc = purple_account_get_connection(account);
-		protocol = purple_connection_get_protocol(gc);
-
-		if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
-			purple_protocol_server_set_buddy_icon(PURPLE_PROTOCOL_SERVER(protocol),
-			                                      gc, img);
-		}
-	}
-
-	if (old_img)
-		g_object_unref(old_img);
-	else if (old_icon)
-	{
-		/* The old icon may not have been loaded into memory.  In that
-		 * case, we'll need to uncache the filename.  The filenames
-		 * are ref-counted, so this is safe. */
-		purple_buddy_icon_data_uncache_file(old_icon);
-	}
-	g_free(old_icon);
-
-	return img;
-}
-
-time_t
-purple_buddy_icons_get_account_icon_timestamp(PurpleAccount *account)
-{
-	time_t ret;
-
-	g_return_val_if_fail(account != NULL, 0);
-
-	ret = purple_account_get_int(account, "buddy_icon_timestamp", 0);
-
-	/* This deals with migration cases. */
-	if (ret == 0 && purple_account_get_string(account, "buddy_icon", NULL) != NULL)
-	{
-		ret = time(NULL);
-		purple_account_set_int(account, "buddy_icon_timestamp", ret);
-	}
-
-	return ret;
-}
-
-gboolean
-purple_buddy_icons_node_has_custom_icon(PurpleBlistNode *node)
-{
-	g_return_val_if_fail(node != NULL, FALSE);
-
-	return (purple_blist_node_get_string(node, "custom_buddy_icon") != NULL);
-}
-
-PurpleImage *
-purple_buddy_icons_node_find_custom_icon(PurpleBlistNode *node)
-{
-	char *path;
-	size_t len;
-	guchar *data;
-	PurpleImage *img;
-	const char *custom_icon_file, *dirname;
-
-	g_return_val_if_fail(node != NULL, NULL);
-
-	img = g_hash_table_lookup(pointer_icon_cache, node);
-	if (img) {
-		g_object_ref(img);
-		return img;
-	}
-
-	custom_icon_file = purple_blist_node_get_string(node,
-	                                                "custom_buddy_icon");
-
-	if (custom_icon_file == NULL)
-		return NULL;
-
-	dirname = purple_buddy_icons_get_cache_dir();
-	path = g_build_filename(dirname, custom_icon_file, NULL);
-
-	if (read_icon_file(path, &data, &len)) {
-		g_free(path);
-		img = purple_buddy_icons_node_set_custom_icon(node, data, len);
-		g_object_ref(img);
-		return img;
-	}
-	g_free(path);
-
-	return NULL;
-}
-
-PurpleImage *
-purple_buddy_icons_node_set_custom_icon(PurpleBlistNode *node,
-                                        guchar *icon_data, size_t icon_len)
-{
-	char *old_icon;
-	PurpleImage *old_img;
-	PurpleImage *img = NULL;
-
-	g_return_val_if_fail(node != NULL, NULL);
-
-	if (!PURPLE_IS_META_CONTACT(node) &&
-	    !PURPLE_IS_GROUP(node)) {
-		return NULL;
-	}
-
-	old_img = g_hash_table_lookup(pointer_icon_cache, node);
-
-	if (icon_data != NULL && icon_len > 0) {
-		img = purple_buddy_icon_data_new(icon_data, icon_len);
-	}
-
-	old_icon = g_strdup(purple_blist_node_get_string(node,
-	                                                 "custom_buddy_icon"));
-	if (img && purple_buddy_icons_is_caching()) {
-		const char *filename = image_get_filename(img);
-		g_warn_if_fail(filename);
-		purple_blist_node_set_string(node, "custom_buddy_icon",
-		                             filename);
-		ref_filename(filename);
-	} else {
-		purple_blist_node_remove_setting(node, "custom_buddy_icon");
-	}
-	unref_filename(old_icon);
-
-	if (img)
-		g_hash_table_insert(pointer_icon_cache, node, img);
-	else
-		g_hash_table_remove(pointer_icon_cache, node);
-
-	if (PURPLE_IS_META_CONTACT(node)) {
-		PurpleBlistNode *child;
-		for (child = purple_blist_node_get_first_child(node);
-		     child;
-			 child = purple_blist_node_get_sibling_next(child))
-		{
-			/* Is this call necessary anymore? Can the buddies
-			 * themselves need updating when the custom buddy
-			 * icon changes? */
-			purple_blist_update_node(purple_blist_get_default(), child);
-		}
-	}
-
-	purple_blist_update_node(purple_blist_get_default(), node);
-
-	if (old_img) {
-		g_object_unref(old_img);
-	} else if (old_icon) {
-		/* The old icon may not have been loaded into memory.  In that
-		 * case, we'll need to uncache the filename.  The filenames
-		 * are ref-counted, so this is safe. */
-		purple_buddy_icon_data_uncache_file(old_icon);
-	}
-	g_free(old_icon);
-
-	return img;
-}
-
-PurpleImage *
-purple_buddy_icons_node_set_custom_icon_from_file(PurpleBlistNode *node,
-                                                  const gchar *filename)
-{
-	size_t len = 0;
-	guchar *data = NULL;
-
-	g_return_val_if_fail(node != NULL, NULL);
-
-	if (!PURPLE_IS_META_CONTACT(node) &&
-	    !PURPLE_IS_GROUP(node)) {
-		return NULL;
-	}
-
-	if (filename != NULL) {
-		if (!read_icon_file(filename, &data, &len)) {
-			return NULL;
-		}
-	}
-
-	return purple_buddy_icons_node_set_custom_icon(node, data, len);
-}
-
-static void
-delete_buddy_icon_settings(PurpleBlistNode *node, const char *setting_name)
-{
-	purple_blist_node_remove_setting(node, setting_name);
-
-	if (purple_strequal(setting_name, "buddy_icon"))
-	{
-		purple_blist_node_remove_setting(node, "avatar_hash");
-		purple_blist_node_remove_setting(node, "icon_checksum");
-	}
-}
-
-static void
-_purple_buddy_icons_account_loaded_cb_helper(PurpleAccount *account,
-                                             gpointer data)
-{
-	const gchar *dirname = (const gchar *)data;
-	const gchar *filename = NULL;
-
-	filename = purple_account_get_string(account, "buddy_icon", NULL);
-	if(filename != NULL) {
-		gchar *path = g_build_filename(dirname, filename, NULL);
-
-		if(!g_file_test(path, G_FILE_TEST_EXISTS)) {
-			purple_account_set_string(account, "buddy_icon", NULL);
-		} else {
-			ref_filename(filename);
-		}
-		g_free(path);
-	}
-}
-
-void
-_purple_buddy_icons_account_loaded_cb(void)
-{
-	PurpleAccountManager *manager = purple_account_manager_get_default();
-	const char *dirname = purple_buddy_icons_get_cache_dir();
-
-	purple_account_manager_foreach(manager,
-	                               _purple_buddy_icons_account_loaded_cb_helper,
-	                               (gpointer)dirname);
-}
-
-void
-_purple_buddy_icons_blist_loaded_cb(void)
-{
-	PurpleBlistNode *node = purple_blist_get_default_root();
-	const char *dirname = purple_buddy_icons_get_cache_dir();
-
-	while (node != NULL)
-	{
-		if (PURPLE_IS_BUDDY(node))
-		{
-			const char *filename;
-
-			filename = purple_blist_node_get_string(node, "buddy_icon");
-			if (filename != NULL)
-			{
-				char *path = g_build_filename(dirname, filename, NULL);
-				if (!g_file_test(path, G_FILE_TEST_EXISTS))
-				{
-					purple_blist_node_remove_setting(node,
-					                                 "buddy_icon");
-					purple_blist_node_remove_setting(node,
-					                                 "icon_checksum");
-				}
-				else
-					ref_filename(filename);
-				g_free(path);
-			}
-		}
-		else if (PURPLE_IS_META_CONTACT(node) ||
-		         PURPLE_IS_GROUP(node))
-		{
-			const char *filename;
-
-			filename = purple_blist_node_get_string(node, "custom_buddy_icon");
-			if (filename != NULL)
-			{
-				char *path = g_build_filename(dirname, filename, NULL);
-				if (!g_file_test(path, G_FILE_TEST_EXISTS))
-				{
-					purple_blist_node_remove_setting(node,
-					                                 "custom_buddy_icon");
-				}
-				else
-					ref_filename(filename);
-				g_free(path);
-			}
-		}
-		node = purple_blist_node_next(node, TRUE);
-	}
-}
-
-void
-purple_buddy_icons_set_caching(gboolean caching)
-{
-	icon_caching = caching;
-}
-
-gboolean
-purple_buddy_icons_is_caching(void)
-{
-	return icon_caching;
-}
-
-void
-purple_buddy_icons_set_cache_dir(const char *dir)
-{
-	g_return_if_fail(dir != NULL);
-
-	g_free(cache_dir);
-	cache_dir = g_strdup(dir);
-}
-
-const char *
-purple_buddy_icons_get_cache_dir(void)
-{
-	return cache_dir;
-}
-
-void *
-purple_buddy_icons_get_handle(void)
-{
-	static int handle;
-
-	return &handle;
-}
-
-void
-purple_buddy_icons_init(void)
-{
-	account_cache = g_hash_table_new_full(
-		g_direct_hash, g_direct_equal,
-		NULL, (GFreeFunc)g_hash_table_destroy);
-
-	icon_data_cache = g_hash_table_new_full(g_str_hash, g_str_equal,
-	                                        g_free, NULL);
-	icon_file_cache = g_hash_table_new_full(g_str_hash, g_str_equal,
-	                                        g_free, NULL);
-	pointer_icon_cache = g_hash_table_new(g_direct_hash, g_direct_equal);
-
-	if (!cache_dir)
-		cache_dir = g_build_filename(purple_cache_dir(), "icons", NULL);
-}
-
-void
-purple_buddy_icons_uninit(void)
-{
-	purple_signals_disconnect_by_handle(purple_buddy_icons_get_handle());
-
-	g_hash_table_destroy(account_cache);
-	g_hash_table_destroy(icon_data_cache);
-	g_hash_table_destroy(icon_file_cache);
-	g_hash_table_destroy(pointer_icon_cache);
-	g_clear_pointer(&cache_dir, g_free);
-}
-
-GType
-purple_buddy_icon_get_type(void)
-{
-	static GType type = 0;
-
-	if (type == 0) {
-		type = g_boxed_type_register_static("PurpleBuddyIcon",
-				(GBoxedCopyFunc)purple_buddy_icon_ref,
-				(GBoxedFreeFunc)purple_buddy_icon_unref);
-	}
-
-	return type;
-}
-
-PurpleBuddyIconSpec *
-purple_buddy_icon_spec_new(char *format, int min_width, int min_height,
-		int max_width, int max_height, size_t max_filesize,
-		PurpleBuddyIconScaleFlags scale_rules)
-{
-	PurpleBuddyIconSpec *icon_spec;
-
-	icon_spec = g_new0(PurpleBuddyIconSpec, 1);
-
-	icon_spec->format       = format;
-	icon_spec->min_width    = min_width;
-	icon_spec->min_height   = min_height;
-	icon_spec->max_width    = max_width;
-	icon_spec->max_height   = max_height;
-	icon_spec->max_filesize = max_filesize;
-	icon_spec->scale_rules  = scale_rules;
-
-	return icon_spec;
-}
-
-void
-purple_buddy_icon_spec_free(PurpleBuddyIconSpec *spec) {
-	if(spec == NULL) {
-		return;
-	}
-
-	g_free(spec);
-}
-
-static PurpleBuddyIconSpec *
-purple_buddy_icon_spec_copy(PurpleBuddyIconSpec *icon_spec)
-{
-	PurpleBuddyIconSpec *icon_spec_copy;
-
-	g_return_val_if_fail(icon_spec != NULL, NULL);
-
-	icon_spec_copy  = g_new0(PurpleBuddyIconSpec, 1);
-	*icon_spec_copy = *icon_spec;
-
-	return icon_spec_copy;
-}
-
-void purple_buddy_icon_spec_get_scaled_size(PurpleBuddyIconSpec *spec,
-		int *width, int *height)
-{
-	int new_width, new_height;
-
-	new_width = *width;
-	new_height = *height;
-
-	if (*width < spec->min_width)
-		new_width = spec->min_width;
-	else if (*width > spec->max_width)
-		new_width = spec->max_width;
-
-	if (*height < spec->min_height)
-		new_height = spec->min_height;
-	else if (*height > spec->max_height)
-		new_height = spec->max_height;
-
-	/* preserve aspect ratio */
-	if ((double)*height * (double)new_width >
-		(double)*width * (double)new_height) {
-			new_width = 0.5 + (double)*width * (double)new_height / (double)*height;
-	} else {
-			new_height = 0.5 + (double)*height * (double)new_width / (double)*width;
-	}
-
-	*width = new_width;
-	*height = new_height;
-}
-
-GType
-purple_buddy_icon_spec_get_type(void)
-{
-	static GType type = 0;
-
-	if (type == 0) {
-		type = g_boxed_type_register_static("PurpleBuddyIconSpec",
-				(GBoxedCopyFunc)purple_buddy_icon_spec_copy,
-				(GBoxedFreeFunc)purple_buddy_icon_spec_free);
-	}
-
-	return type;
-}
diff --git a/libpurple/buddylist.h b/libpurple/buddylist.h
--- a/libpurple/buddylist.h
+++ b/libpurple/buddylist.h
@@ -29,7 +29,6 @@
 
 /* I can't believe I let ChipX86 inspire me to write good code. -Sean */
 
-#include "buddy.h"
 #include "purpleaccount.h"
 #include "purpleversion.h"
 
@@ -251,20 +250,6 @@
 void purple_blist_set_visible(gboolean show);
 
 /**
- * purple_blist_update_buddies_cache:
- * @buddy:    The buddy whose name will be changed.
- * @new_name: The new name of the buddy.
- *
- * Updates the buddies hash table when a buddy has been renamed. This only
- * updates the cache, the caller is responsible for the actual renaming of
- * the buddy after updating the cache.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_update_buddies_cache(PurpleBuddy *buddy, const char *new_name);
-
-/**
  * purple_blist_update_groups_cache:
  * @group:    The group whose name will be changed.
  * @new_name: The new name of the group.
@@ -279,25 +264,6 @@
 void purple_blist_update_groups_cache(PurpleGroup *group, const char *new_name);
 
 /**
- * purple_blist_add_buddy:
- * @buddy:   The new buddy who gets added
- * @contact: The optional contact to place the buddy in.
- * @group:   The group to add the new buddy to.
- * @node:    The insertion point.  Pass in NULL to add the node as
- *                the first child in the given group.
- *
- * Adds a new buddy to the buddy list.
- *
- * The buddy will be inserted right after node or prepended to the
- * group if node is NULL.  If both are NULL, the buddy will be added to
- * the default group.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleMetaContact *contact, PurpleGroup *group, PurpleBlistNode *node);
-
-/**
  * purple_blist_add_group:
  * @group:  The group
  * @node:   The insertion point
@@ -329,20 +295,6 @@
 void purple_blist_add_contact(PurpleMetaContact *contact, PurpleGroup *group, PurpleBlistNode *node);
 
 /**
- * purple_blist_remove_buddy:
- * @buddy:   The buddy to be removed
- *
- * Removes a buddy from the buddy list and frees the memory allocated to it.
- * This doesn't actually try to remove the buddy from the server list.
- *
- * See purple_account_remove_buddy().
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_remove_buddy(PurpleBuddy *buddy);
-
-/**
  * purple_blist_remove_contact:
  * @contact: The contact to be removed
  *
@@ -370,52 +322,6 @@
 void purple_blist_remove_group(PurpleGroup *group);
 
 /**
- * purple_blist_find_buddy:
- * @account: The account this buddy belongs to
- * @name:    The buddy's name
- *
- * Finds the buddy struct given a name and an account
- *
- * Returns: (transfer none): The buddy or %NULL if the buddy does not exist.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleBuddy *purple_blist_find_buddy(PurpleAccount *account, const char *name);
-
-/**
- * purple_blist_find_buddy_in_group:
- * @account: The account this buddy belongs to
- * @name:    The buddy's name
- * @group:   The group to look in
- *
- * Finds the buddy struct given a name, an account, and a group
- *
- * Returns: (transfer none): The buddy or %NULL if the buddy does not exist in
- *          the group.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleBuddy *purple_blist_find_buddy_in_group(PurpleAccount *account, const char *name,
-		PurpleGroup *group);
-
-/**
- * purple_blist_find_buddies:
- * @account: The account this buddy belongs to
- * @name:    The buddy's name (or NULL to return all buddies for the account)
- *
- * Finds all PurpleBuddy structs given a name and an account
- *
- * Returns: (element-type PurpleBuddy) (transfer container): %NULL if the buddy
- *          doesn't exist, or a GSList of PurpleBuddy structs.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GSList *purple_blist_find_buddies(PurpleAccount *account, const char *name);
-
-/**
  * purple_blist_find_group:
  * @name:    The group's name
  *
@@ -441,30 +347,6 @@
 PurpleGroup *purple_blist_get_default_group(void);
 
 /**
- * purple_blist_add_account:
- * @account:   The account
- *
- * Called when an account connects.  Tells the UI to update all the
- * buddies.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_add_account(PurpleAccount *account);
-
-/**
- * purple_blist_remove_account:
- * @account:   The account
- *
- * Called when an account disconnects.  Sets the presence of all the buddies to 0
- * and tells the UI to update them.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_remove_account(PurpleAccount *account);
-
-/**
  * purple_blist_walk:
  * @group_func: (scope call): The callback for groups
  * @meta_contact_func: (scope call): The callback for meta-contacts
diff --git a/libpurple/buddylist.c b/libpurple/buddylist.c
--- a/libpurple/buddylist.c
+++ b/libpurple/buddylist.c
@@ -200,39 +200,9 @@
 }
 
 static PurpleXmlNode *
-buddy_to_xmlnode(PurpleBuddy *buddy)
-{
-	PurpleXmlNode *node, *child;
-	PurpleAccount *account = purple_buddy_get_account(buddy);
-	PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
-	const char *alias = purple_buddy_get_local_alias(buddy);
-
-	node = purple_xmlnode_new("buddy");
-	purple_xmlnode_set_attrib(node, "account",
-	                          purple_contact_info_get_username(info));
-	purple_xmlnode_set_attrib(node, "proto", purple_account_get_protocol_id(account));
-
-	child = purple_xmlnode_new_child(node, "name");
-	purple_xmlnode_insert_data(child, purple_buddy_get_name(buddy), -1);
-
-	if (alias != NULL)
-	{
-		child = purple_xmlnode_new_child(node, "alias");
-		purple_xmlnode_insert_data(child, alias, -1);
-	}
-
-	/* Write buddy settings */
-	g_hash_table_foreach(purple_blist_node_get_settings(PURPLE_BLIST_NODE(buddy)),
-			value_to_xmlnode, node);
-
-	return node;
-}
-
-static PurpleXmlNode *
 contact_to_xmlnode(PurpleMetaContact *contact)
 {
-	PurpleXmlNode *node, *child;
-	PurpleBlistNode *bnode;
+	PurpleXmlNode *node;
 	gchar *alias;
 
 	node = purple_xmlnode_new("contact");
@@ -243,18 +213,6 @@
 		purple_xmlnode_set_attrib(node, "alias", alias);
 	}
 
-	/* Write buddies */
-	for (bnode = PURPLE_BLIST_NODE(contact)->child; bnode != NULL; bnode = bnode->next)
-	{
-		if (purple_blist_node_is_transient(bnode))
-			continue;
-		if (PURPLE_IS_BUDDY(bnode))
-		{
-			child = buddy_to_xmlnode(PURPLE_BUDDY(bnode));
-			purple_xmlnode_insert_child(node, child);
-		}
-	}
-
 	/* Write contact settings */
 	g_hash_table_foreach(purple_blist_node_get_settings(PURPLE_BLIST_NODE(contact)),
 			value_to_xmlnode, node);
@@ -423,54 +381,6 @@
 }
 
 static void
-parse_buddy(PurpleGroup *group, PurpleMetaContact *contact, PurpleXmlNode *bnode) {
-	PurpleAccount *account;
-	PurpleAccountManager *manager = purple_account_manager_get_default();
-	PurpleBuddy *buddy;
-	char *name = NULL, *alias = NULL;
-	const char *acct_name, *proto;
-	PurpleXmlNode *x;
-
-	acct_name = purple_xmlnode_get_attrib(bnode, "account");
-	proto = purple_xmlnode_get_attrib(bnode, "proto");
-
-	if(!acct_name || !proto) {
-		return;
-	}
-
-	account = purple_account_manager_find(manager, acct_name, proto);
-
-	if(!account) {
-		return;
-	}
-
-	if((x = purple_xmlnode_get_child(bnode, "name"))) {
-		name = purple_xmlnode_get_data(x);
-	}
-
-	if(!name) {
-		g_clear_object(&account);
-		return;
-	}
-
-	if((x = purple_xmlnode_get_child(bnode, "alias"))) {
-		alias = purple_xmlnode_get_data(x);
-	}
-
-	buddy = purple_buddy_new(account, name, alias);
-	purple_blist_add_buddy(buddy, contact, group,
-			_purple_blist_get_last_child((PurpleBlistNode*)contact));
-
-	for(x = purple_xmlnode_get_child(bnode, "setting"); x; x = purple_xmlnode_get_next_twin(x)) {
-		parse_setting((PurpleBlistNode*)buddy, x);
-	}
-
-	g_clear_object(&account);
-	g_free(name);
-	g_free(alias);
-}
-
-static void
 parse_contact(PurpleGroup *group, PurpleXmlNode *cnode)
 {
 	PurpleMetaContact *contact = purple_meta_contact_new();
@@ -487,9 +397,7 @@
 	for (x = cnode->child; x; x = x->next) {
 		if (x->type != PURPLE_XMLNODE_TYPE_TAG)
 			continue;
-		if (purple_strequal(x->name, "buddy"))
-			parse_buddy(group, contact, x);
-		else if (purple_strequal(x->name, "setting"))
+		if (purple_strequal(x->name, "setting"))
 			parse_setting(PURPLE_BLIST_NODE(contact), x);
 	}
 
@@ -551,9 +459,6 @@
 	}
 
 	purple_xmlnode_free(purple);
-
-	/* This tells the buddy icon code to do its thing. */
-	_purple_buddy_icons_blist_loaded_cb();
 }
 
 /*****************************************************************************
@@ -667,40 +572,6 @@
 	}
 }
 
-void purple_blist_update_buddies_cache(PurpleBuddy *buddy, const char *new_name)
-{
-	struct _purple_hbuddy *hb, *hb2;
-	GHashTable *account_buddies;
-	PurpleAccount *account;
-	gchar *name;
-	PurpleBuddyListPrivate *priv =
-			purple_buddy_list_get_instance_private(purplebuddylist);
-
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	account = purple_buddy_get_account(buddy);
-	name = (gchar *)purple_buddy_get_name(buddy);
-
-	hb = g_new(struct _purple_hbuddy, 1);
-	hb->name = (gchar *)purple_normalize(account, name);
-	hb->account = account;
-	hb->group = PURPLE_BLIST_NODE(buddy)->parent->parent;
-	g_hash_table_remove(priv->buddies, hb);
-
-	account_buddies = g_hash_table_lookup(buddies_cache, account);
-	g_hash_table_remove(account_buddies, hb);
-
-	hb->name = g_strdup(purple_normalize(account, new_name));
-	g_hash_table_replace(priv->buddies, hb, buddy);
-
-	hb2 = g_new(struct _purple_hbuddy, 1);
-	hb2->name = g_strdup(hb->name);
-	hb2->account = account;
-	hb2->group = PURPLE_BLIST_NODE(buddy)->parent->parent;
-
-	g_hash_table_replace(account_buddies, hb2, buddy);
-}
-
 void purple_blist_update_groups_cache(PurpleGroup *group, const char *new_name)
 {
 		gchar* key;
@@ -713,178 +584,9 @@
 			purple_blist_fold_name(new_name), group);
 }
 
-void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleMetaContact *contact, PurpleGroup *group, PurpleBlistNode *node)
-{
-	PurpleBuddyListClass *klass = NULL;
-	PurpleBuddyListPrivate *priv = NULL;
-	PurpleBlistNode *cnode, *bnode;
-	PurpleCountingNode *contact_counter, *group_counter;
-	PurpleGroup *g;
-	PurpleMetaContact *c;
-	PurpleAccount *account;
-	struct _purple_hbuddy *hb, *hb2;
-	GHashTable *account_buddies;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-	priv = purple_buddy_list_get_instance_private(purplebuddylist);
-	bnode = PURPLE_BLIST_NODE(buddy);
-	account = purple_buddy_get_account(buddy);
-
-	/* if we're moving to overtop of ourselves, do nothing */
-	if (bnode == node || (!node && bnode->parent &&
-				contact && bnode->parent == (PurpleBlistNode*)contact
-				&& bnode == bnode->parent->child))
-		return;
-
-	if (node && PURPLE_IS_BUDDY(node)) {
-		c = (PurpleMetaContact*)node->parent;
-		g = (PurpleGroup*)node->parent->parent;
-	} else if (contact) {
-		c = contact;
-		g = PURPLE_GROUP(PURPLE_BLIST_NODE(c)->parent);
-	} else {
-		g = group;
-		if (g == NULL)
-			g = purple_blist_get_default_group();
-		/* Add group to blist if isn't already on it. Fixes #2752. */
-		if (!purple_blist_find_group(purple_group_get_name(g))) {
-			purple_blist_add_group(
-			        g, purple_blist_get_last_sibling(priv->root));
-		}
-		c = purple_meta_contact_new();
-		purple_blist_add_contact(c, g,
-				_purple_blist_get_last_child((PurpleBlistNode*)g));
-	}
-
-	cnode = PURPLE_BLIST_NODE(c);
-
-	if (bnode->parent) {
-		contact_counter = PURPLE_COUNTING_NODE(bnode->parent);
-		group_counter = PURPLE_COUNTING_NODE(bnode->parent->parent);
-
-		if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
-			purple_counting_node_change_online_count(contact_counter, -1);
-			if (purple_counting_node_get_online_count(contact_counter) == 0)
-				purple_counting_node_change_online_count(group_counter, -1);
-		}
-		if (purple_account_is_connected(account)) {
-			purple_counting_node_change_current_size(contact_counter, -1);
-			if (purple_counting_node_get_current_size(contact_counter) == 0)
-				purple_counting_node_change_current_size(group_counter, -1);
-		}
-		purple_counting_node_change_total_size(contact_counter, -1);
-		/* the group totalsize will be taken care of by remove_contact below */
-
-		if (bnode->parent->parent != (PurpleBlistNode*)g) {
-			purple_signal_emit(purple_blist_get_handle(), "buddy-removed-from-group", buddy);
-		}
-
-		if (bnode->next)
-			bnode->next->prev = bnode->prev;
-		if (bnode->prev)
-			bnode->prev->next = bnode->next;
-		if (bnode->parent->child == bnode)
-			bnode->parent->child = bnode->next;
-
-		if (klass && klass->remove) {
-			klass->remove(purplebuddylist, bnode);
-		}
-
-		if (bnode->parent->parent != (PurpleBlistNode*)g) {
-			struct _purple_hbuddy hb;
-			hb.name = (gchar *)purple_normalize(account,
-					purple_buddy_get_name(buddy));
-			hb.account = account;
-			hb.group = bnode->parent->parent;
-			g_hash_table_remove(priv->buddies, &hb);
-
-			account_buddies = g_hash_table_lookup(buddies_cache, account);
-			g_hash_table_remove(account_buddies, &hb);
-		}
-
-		if (!bnode->parent->child) {
-			purple_blist_remove_contact((PurpleMetaContact*)bnode->parent);
-		} else {
-			purple_meta_contact_invalidate_priority_buddy((PurpleMetaContact*)bnode->parent);
-
-			if (klass && klass->update) {
-				klass->update(purplebuddylist, bnode->parent);
-			}
-		}
-	}
-
-	if (node && PURPLE_IS_BUDDY(node)) {
-		if (node->next)
-			node->next->prev = bnode;
-		bnode->next = node->next;
-		bnode->prev = node;
-		bnode->parent = node->parent;
-		node->next = bnode;
-	} else {
-		if (cnode->child)
-			cnode->child->prev = bnode;
-		bnode->prev = NULL;
-		bnode->next = cnode->child;
-		cnode->child = bnode;
-		bnode->parent = cnode;
-	}
-
-	contact_counter = PURPLE_COUNTING_NODE(bnode->parent);
-	group_counter = PURPLE_COUNTING_NODE(bnode->parent->parent);
-
-	if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
-		purple_counting_node_change_online_count(contact_counter, +1);
-		if (purple_counting_node_get_online_count(contact_counter) == 1)
-			purple_counting_node_change_online_count(group_counter, +1);
-	}
-	if (purple_account_is_connected(account)) {
-		purple_counting_node_change_current_size(contact_counter, +1);
-		if (purple_counting_node_get_current_size(contact_counter) == 1)
-			purple_counting_node_change_current_size(group_counter, +1);
-	}
-	purple_counting_node_change_total_size(contact_counter, +1);
-
-	hb = g_new(struct _purple_hbuddy, 1);
-	hb->name = g_strdup(purple_normalize(account, purple_buddy_get_name(buddy)));
-	hb->account = account;
-	hb->group = PURPLE_BLIST_NODE(buddy)->parent->parent;
-
-	g_hash_table_replace(priv->buddies, hb, buddy);
-
-	account_buddies = g_hash_table_lookup(buddies_cache, account);
-
-	hb2 = g_new(struct _purple_hbuddy, 1);
-	hb2->name = g_strdup(hb->name);
-	hb2->account = account;
-	hb2->group = ((PurpleBlistNode*)buddy)->parent->parent;
-
-	g_hash_table_replace(account_buddies, hb2, buddy);
-
-	purple_meta_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
-
-	if (klass) {
-		if (klass->save_node) {
-			klass->save_node(purplebuddylist,
-			                 (PurpleBlistNode *)buddy);
-		}
-		if (klass->update) {
-			klass->update(purplebuddylist,
-			              PURPLE_BLIST_NODE(buddy));
-		}
-	}
-
-	/* Signal that the buddy has been added */
-	purple_signal_emit(purple_blist_get_handle(), "blist-node-added",
-			PURPLE_BLIST_NODE(buddy));
-}
-
 void purple_blist_add_contact(PurpleMetaContact *contact, PurpleGroup *group, PurpleBlistNode *node)
 {
 	PurpleBuddyListClass *klass = NULL;
-	PurpleBuddyListPrivate *priv = NULL;
 	PurpleGroup *g;
 	PurpleBlistNode *gnode, *cnode, *bnode;
 	PurpleCountingNode *contact_counter, *group_counter;
@@ -896,7 +598,6 @@
 		return;
 
 	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-	priv = purple_buddy_list_get_instance_private(purplebuddylist);
 
 	if (node && (PURPLE_IS_META_CONTACT(node)))
 		g = PURPLE_GROUP(node->parent);
@@ -916,60 +617,6 @@
 		if (cnode->next)
 			cnode->next->prev = cnode->prev;
 
-		if (cnode->parent != gnode) {
-			bnode = cnode->child;
-			while (bnode) {
-				PurpleBlistNode *next_bnode = bnode->next;
-				PurpleBuddy *b = PURPLE_BUDDY(bnode);
-				PurpleAccount *account = purple_buddy_get_account(b);
-				GHashTable *account_buddies;
-
-				struct _purple_hbuddy *hb, *hb2;
-
-				hb = g_new(struct _purple_hbuddy, 1);
-				hb->name = g_strdup(purple_normalize(account, purple_buddy_get_name(b)));
-				hb->account = account;
-				hb->group = cnode->parent;
-
-				g_hash_table_remove(priv->buddies, hb);
-
-				account_buddies = g_hash_table_lookup(buddies_cache, account);
-				g_hash_table_remove(account_buddies, hb);
-
-				if (!purple_blist_find_buddy_in_group(account, purple_buddy_get_name(b), g)) {
-					hb->group = gnode;
-					g_hash_table_replace(priv->buddies, hb, b);
-
-					hb2 = g_new(struct _purple_hbuddy, 1);
-					hb2->name = g_strdup(hb->name);
-					hb2->account = account;
-					hb2->group = gnode;
-
-					g_hash_table_replace(account_buddies, hb2, b);
-				} else {
-					gboolean empty_contact = FALSE;
-
-					/* this buddy already exists in the group, so we're
-					 * gonna delete it instead */
-					g_free(hb->name);
-					g_free(hb);
-					if (purple_account_get_connection(account))
-						purple_account_remove_buddy(account, b, PURPLE_GROUP(cnode->parent));
-
-					if (!cnode->child->next)
-						empty_contact = TRUE;
-					purple_blist_remove_buddy(b);
-
-					/* in purple_blist_remove_buddy(), if the last buddy in a
-					 * contact is removed, the contact is cleaned up and
-					 * g_free'd, so we mustn't try to reference bnode->next */
-					if (empty_contact)
-						return;
-				}
-				bnode = next_bnode;
-			}
-		}
-
 		contact_counter = PURPLE_COUNTING_NODE(contact);
 		group_counter = PURPLE_COUNTING_NODE(cnode->parent);
 
@@ -1122,115 +769,14 @@
 	gnode = node->parent;
 	group = PURPLE_GROUP(gnode);
 
-	if (node->child) {
-		/*
-		 * If this contact has children then remove them.  When the last
-		 * buddy is removed from the contact, the contact is automatically
-		 * deleted.
-		 */
-		while (node->child->next) {
-			purple_blist_remove_buddy((PurpleBuddy*)node->child);
-		}
-		/*
-		 * Remove the last buddy and trigger the deletion of the contact.
-		 * It would probably be cleaner if contact-deletion was done after
-		 * a timeout?  Or if it had to be done manually, like below?
-		 */
-		purple_blist_remove_buddy((PurpleBuddy*)node->child);
-	} else {
-		/* Remove the node from its parent */
-		if (gnode->child == node)
-			gnode->child = node->next;
-		if (node->prev)
-			node->prev->next = node->next;
-		if (node->next)
-			node->next->prev = node->prev;
-		purple_counting_node_change_total_size(PURPLE_COUNTING_NODE(group), -1);
-
-		/* Update the UI */
-		if (klass && klass->remove) {
-			klass->remove(purplebuddylist, node);
-		}
-
-		if (klass && klass->remove_node) {
-			klass->remove_node(purplebuddylist, node);
-		}
-
-		purple_signal_emit(purple_blist_get_handle(), "blist-node-removed",
-				PURPLE_BLIST_NODE(contact));
-
-		/* Delete the node */
-		g_object_unref(contact);
-	}
-}
-
-void purple_blist_remove_buddy(PurpleBuddy *buddy)
-{
-	PurpleBuddyListClass *klass = NULL;
-	PurpleBuddyListPrivate *priv = NULL;
-	PurpleBlistNode *node, *cnode, *gnode;
-	PurpleCountingNode *contact_counter, *group_counter;
-	PurpleMetaContact *contact;
-	PurpleGroup *group;
-	struct _purple_hbuddy hb;
-	GHashTable *account_buddies;
-	PurpleAccount *account;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-	priv = purple_buddy_list_get_instance_private(purplebuddylist);
-	account = purple_buddy_get_account(buddy);
-	node = PURPLE_BLIST_NODE(buddy);
-	cnode = node->parent;
-	gnode = (cnode != NULL) ? cnode->parent : NULL;
-	contact = (PurpleMetaContact *)cnode;
-	group = (PurpleGroup *)gnode;
-
 	/* Remove the node from its parent */
+	if (gnode->child == node)
+		gnode->child = node->next;
 	if (node->prev)
 		node->prev->next = node->next;
 	if (node->next)
 		node->next->prev = node->prev;
-	if ((cnode != NULL) && (cnode->child == node))
-		cnode->child = node->next;
-
-	/* Adjust size counts */
-	if (contact != NULL) {
-		contact_counter = PURPLE_COUNTING_NODE(contact);
-		group_counter = PURPLE_COUNTING_NODE(group);
-
-		if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
-			purple_counting_node_change_online_count(contact_counter, -1);
-			if (purple_counting_node_get_online_count(contact_counter) == 0)
-				purple_counting_node_change_online_count(group_counter, -1);
-		}
-		if (purple_account_is_connected(account)) {
-			purple_counting_node_change_current_size(contact_counter, -1);
-			if (purple_counting_node_get_current_size(contact_counter) == 0)
-				purple_counting_node_change_current_size(group_counter, -1);
-		}
-		purple_counting_node_change_total_size(contact_counter, -1);
-
-		/* Re-sort the contact */
-		if (cnode->child && purple_meta_contact_get_priority_buddy(contact) == buddy) {
-			purple_meta_contact_invalidate_priority_buddy(contact);
-
-			if (klass && klass->update) {
-				klass->update(purplebuddylist, cnode);
-			}
-		}
-	}
-
-	/* Remove this buddy from the buddies hash table */
-	hb.name = (gchar *)purple_normalize(account, purple_buddy_get_name(buddy));
-	hb.account = account;
-	hb.group = gnode;
-	g_hash_table_remove(priv->buddies, &hb);
-
-	account_buddies = g_hash_table_lookup(buddies_cache, account);
-	g_hash_table_remove(account_buddies, &hb);
+	purple_counting_node_change_total_size(PURPLE_COUNTING_NODE(group), -1);
 
 	/* Update the UI */
 	if (klass && klass->remove) {
@@ -1241,15 +787,11 @@
 		klass->remove_node(purplebuddylist, node);
 	}
 
-	/* Signal that the buddy has been removed before freeing the memory for it */
 	purple_signal_emit(purple_blist_get_handle(), "blist-node-removed",
-			PURPLE_BLIST_NODE(buddy));
+			PURPLE_BLIST_NODE(contact));
 
-	g_object_unref(buddy);
-
-	/* If the contact is empty then remove it */
-	if ((contact != NULL) && !cnode->child)
-		purple_blist_remove_contact(contact);
+	/* Delete the node */
+	g_object_unref(contact);
 }
 
 void purple_blist_remove_group(PurpleGroup *group)
@@ -1313,97 +855,6 @@
 	g_object_unref(group);
 }
 
-PurpleBuddy *purple_blist_find_buddy(PurpleAccount *account, const char *name)
-{
-	PurpleBuddyListPrivate *priv =
-			purple_buddy_list_get_instance_private(purplebuddylist);
-	PurpleBuddy *buddy;
-	struct _purple_hbuddy hb;
-	PurpleBlistNode *group;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist), NULL);
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
-	g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
-
-	hb.account = account;
-	hb.name = (gchar *)purple_normalize(account, name);
-
-	for (group = priv->root; group; group = group->next) {
-		if (!group->child)
-			continue;
-
-		hb.group = group;
-		if ((buddy = g_hash_table_lookup(priv->buddies, &hb))) {
-			return buddy;
-		}
-	}
-
-	return NULL;
-}
-
-PurpleBuddy *purple_blist_find_buddy_in_group(PurpleAccount *account, const char *name,
-		PurpleGroup *group)
-{
-	PurpleBuddyListPrivate *priv =
-			purple_buddy_list_get_instance_private(purplebuddylist);
-	struct _purple_hbuddy hb;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist), NULL);
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
-	g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
-
-	hb.name = (gchar *)purple_normalize(account, name);
-	hb.account = account;
-	hb.group = (PurpleBlistNode*)group;
-
-	return g_hash_table_lookup(priv->buddies, &hb);
-}
-
-static void
-find_acct_buddies(G_GNUC_UNUSED gpointer key, gpointer value, gpointer data)
-{
-	PurpleBuddy *buddy = value;
-	GSList **list = data;
-
-	*list = g_slist_prepend(*list, buddy);
-}
-
-GSList *purple_blist_find_buddies(PurpleAccount *account, const char *name)
-{
-	PurpleBuddyListPrivate *priv =
-			purple_buddy_list_get_instance_private(purplebuddylist);
-	PurpleBuddy *buddy;
-	PurpleBlistNode *node;
-	GSList *ret = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist), NULL);
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
-
-	if ((name != NULL) && (*name != '\0')) {
-		struct _purple_hbuddy hb;
-
-		hb.name = (gchar *)purple_normalize(account, name);
-		hb.account = account;
-
-		for (node = priv->root; node != NULL; node = node->next) {
-			if (!node->child)
-				continue;
-
-			hb.group = node;
-			if ((buddy = g_hash_table_lookup(priv->buddies,
-					&hb)) != NULL)
-				ret = g_slist_prepend(ret, buddy);
-		}
-	} else {
-		GSList *list = NULL;
-		GHashTable *buddies = g_hash_table_lookup(buddies_cache, account);
-		g_hash_table_foreach(buddies, find_acct_buddies, &list);
-		ret = list;
-	}
-
-	return ret;
-}
-
 PurpleGroup *purple_blist_find_group(const char *name)
 {
 	gchar* key;
@@ -1439,139 +890,6 @@
 	return group;
 }
 
-void purple_blist_add_account(PurpleAccount *account)
-{
-	PurpleBuddyListClass *klass = NULL;
-	PurpleBlistNode *gnode, *cnode, *bnode;
-	PurpleCountingNode *contact_counter, *group_counter;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-	if (!klass || !klass->update) {
-		return;
-	}
-
-	for (gnode = purple_blist_get_default_root(); gnode;
-	     gnode = gnode->next) {
-		if (!PURPLE_IS_GROUP(gnode))
-			continue;
-		for (cnode = gnode->child; cnode; cnode = cnode->next) {
-			if (PURPLE_IS_META_CONTACT(cnode)) {
-				gboolean recompute = FALSE;
-					for (bnode = cnode->child; bnode; bnode = bnode->next) {
-						if (PURPLE_IS_BUDDY(bnode) &&
-								purple_buddy_get_account(PURPLE_BUDDY(bnode)) == account) {
-							recompute = TRUE;
-							contact_counter = PURPLE_COUNTING_NODE(cnode);
-							group_counter = PURPLE_COUNTING_NODE(gnode);
-							purple_counting_node_change_current_size(contact_counter, +1);
-							if (purple_counting_node_get_current_size(contact_counter) == 1)
-								purple_counting_node_change_current_size(group_counter, +1);
-						        klass->update(
-						                purplebuddylist,
-						                bnode);
-					        }
-				        }
-				        if (recompute ||
-				            purple_blist_node_get_bool(
-				                    cnode, "show_offline")) {
-					        purple_meta_contact_invalidate_priority_buddy(
-					                (PurpleMetaContact *)cnode);
-					        klass->update(purplebuddylist,
-					                      cnode);
-				        }
-			}
-		}
-		klass->update(purplebuddylist, gnode);
-	}
-}
-
-void purple_blist_remove_account(PurpleAccount *account)
-{
-	PurpleBuddyListClass *klass = NULL;
-	PurpleBlistNode *gnode, *cnode, *bnode;
-	PurpleCountingNode *contact_counter, *group_counter;
-	PurpleBuddy *buddy;
-	PurpleMetaContact *contact;
-	PurpleGroup *group;
-	GList *list = NULL, *iter = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-
-	for (gnode = purple_blist_get_default_root(); gnode;
-	     gnode = gnode->next) {
-		if (!PURPLE_IS_GROUP(gnode))
-			continue;
-
-		group = (PurpleGroup *)gnode;
-
-		for (cnode = gnode->child; cnode; cnode = cnode->next) {
-			if (PURPLE_IS_META_CONTACT(cnode)) {
-				gboolean recompute = FALSE;
-				contact = (PurpleMetaContact *)cnode;
-
-				for (bnode = cnode->child; bnode; bnode = bnode->next) {
-					if (!PURPLE_IS_BUDDY(bnode))
-						continue;
-
-					buddy = (PurpleBuddy *)bnode;
-					if (account == purple_buddy_get_account(buddy)) {
-						PurplePresence *presence;
-
-						presence = purple_buddy_get_presence(buddy);
-						contact_counter = PURPLE_COUNTING_NODE(contact);
-						group_counter = PURPLE_COUNTING_NODE(group);
-
-						if(purple_presence_is_online(presence)) {
-							purple_counting_node_change_online_count(contact_counter, -1);
-							if (purple_counting_node_get_online_count(contact_counter) == 0)
-								purple_counting_node_change_online_count(group_counter, -1);
-
-							purple_blist_node_set_int(PURPLE_BLIST_NODE(buddy),
-													"last_seen", time(NULL));
-						}
-
-						purple_counting_node_change_current_size(contact_counter, -1);
-						if (purple_counting_node_get_current_size(contact_counter) == 0)
-							purple_counting_node_change_current_size(group_counter, -1);
-
-						if (!g_list_find(list, presence))
-							list = g_list_prepend(list, presence);
-
-						if (purple_meta_contact_get_priority_buddy(contact) == buddy)
-							purple_meta_contact_invalidate_priority_buddy(contact);
-						else
-							recompute = TRUE;
-
-						if (klass && klass->remove) {
-							klass->remove(
-							        purplebuddylist,
-							        bnode);
-						}
-					}
-				}
-				if (recompute) {
-					purple_meta_contact_invalidate_priority_buddy(contact);
-
-					if (klass && klass->update) {
-						klass->update(purplebuddylist,
-						              cnode);
-					}
-				}
-			}
-		}
-	}
-
-	for (iter = list; iter; iter = iter->next)
-	{
-		purple_presence_set_primitive(iter->data,
-		                              PURPLE_PRESENCE_PRIMITIVE_OFFLINE);
-	}
-	g_list_free(list);
-}
-
 void
 purple_blist_walk(PurpleBlistWalkFunc group_func,
                   PurpleBlistWalkFunc meta_contact_func,
@@ -1719,26 +1037,6 @@
 	/* Set a default, which can't be done as a static initializer. */
 	buddy_list_type = PURPLE_TYPE_BUDDY_LIST;
 
-	purple_signal_register(handle, "buddy-privacy-changed",
-	                     purple_marshal_VOID__POINTER, G_TYPE_NONE,
-	                     1, PURPLE_TYPE_BUDDY);
-
-	purple_signal_register(handle, "buddy-idle-changed",
-	                     purple_marshal_VOID__POINTER_INT_INT, G_TYPE_NONE,
-	                     3, PURPLE_TYPE_BUDDY, G_TYPE_INT, G_TYPE_INT);
-
-	purple_signal_register(handle, "buddy-signed-on",
-						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-						 PURPLE_TYPE_BUDDY);
-
-	purple_signal_register(handle, "buddy-signed-off",
-						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-						 PURPLE_TYPE_BUDDY);
-
-	purple_signal_register(handle, "buddy-got-login-time",
-						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-						 PURPLE_TYPE_BUDDY);
-
 	purple_signal_register(handle, "blist-node-added",
 						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
 						 PURPLE_TYPE_BLIST_NODE);
@@ -1747,14 +1045,6 @@
 						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
 						 PURPLE_TYPE_BLIST_NODE);
 
-	purple_signal_register(handle, "buddy-removed-from-group",
-						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-						 PURPLE_TYPE_BUDDY);
-
-	purple_signal_register(handle, "buddy-icon-changed",
-						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-						 PURPLE_TYPE_BUDDY);
-
 	purple_signal_register(handle, "update-idle", purple_marshal_VOID,
 						 G_TYPE_NONE, 0);
 
@@ -1766,10 +1056,6 @@
 	purple_signal_register(handle, "blist-node-aliased",
 						 purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2,
 						 PURPLE_TYPE_BLIST_NODE, G_TYPE_STRING);
-
-	purple_signal_register(handle, "buddy-caps-changed",
-			purple_marshal_VOID__POINTER_INT_INT, G_TYPE_NONE,
-			3, PURPLE_TYPE_BUDDY, G_TYPE_INT, G_TYPE_INT);
 }
 
 static void
diff --git a/libpurple/cmds.c b/libpurple/cmds.c
--- a/libpurple/cmds.c
+++ b/libpurple/cmds.c
@@ -23,6 +23,8 @@
 #include "cmds.h"
 #include "purpleaccount.h"
 #include "purplemarkup.h"
+#include "signals.h"
+#include "util.h"
 
 static GList *cmds = NULL;
 static guint next_id = 1;
diff --git a/libpurple/connection.c b/libpurple/connection.c
--- a/libpurple/connection.c
+++ b/libpurple/connection.c
@@ -138,8 +138,6 @@
 		purple_presence_set_login_time(presence, timestamp);
 		g_date_time_unref(timestamp);
 
-		purple_blist_add_account(priv->account);
-
 		handle = purple_connections_get_handle();
 		purple_signal_emit(handle, "signed-on", connection);
 		purple_signal_emit_return_1(handle, "autojoin", connection);
@@ -824,8 +822,6 @@
 purple_connection_disconnect(PurpleConnection *connection, GError **error) {
 	PurpleConnectionClass *klass = NULL;
 	PurpleConnectionPrivate *priv = NULL;
-	GSList *buddies = NULL;
-	gboolean remove = FALSE;
 	gboolean ret = TRUE;
 	gpointer handle = NULL;
 
@@ -837,13 +833,6 @@
 
 	priv = purple_connection_get_instance_private(connection);
 
-	/* If we're not connecting, we'll need to remove stuff from our contacts
-	 * from the buddy list.
-	 */
-	if(priv->state != PURPLE_CONNECTION_STATE_CONNECTING) {
-		remove = TRUE;
-	}
-
 	handle = purple_connections_get_handle();
 
 	purple_debug_info("connection", "Disconnecting connection %p", connection);
@@ -857,24 +846,12 @@
 		ret = klass->disconnect(connection, error);
 	}
 
-	/* Clear out the proto data that was freed in the protocol's close method */
-	buddies = purple_blist_find_buddies(priv->account, NULL);
-	while (buddies != NULL) {
-		PurpleBuddy *buddy = buddies->data;
-		purple_buddy_set_protocol_data(buddy, NULL);
-		buddies = g_slist_delete_link(buddies, buddies);
-	}
-
 	/* Do the rest of our cleanup. */
 	connections = g_list_remove(connections, connection);
 
 	purple_connection_set_state(connection,
 	                            PURPLE_CONNECTION_STATE_DISCONNECTED);
 
-	if(remove) {
-		purple_blist_remove_account(priv->account);
-	}
-
 	purple_signal_emit(handle, "signed-off", connection);
 
 	purple_account_request_close_with_account(priv->account);
diff --git a/libpurple/contact.h b/libpurple/contact.h
--- a/libpurple/contact.h
+++ b/libpurple/contact.h
@@ -93,19 +93,6 @@
 PurpleMetaContact *purple_meta_contact_new(void);
 
 /**
- * purple_meta_contact_get_priority_buddy:
- * @contact:  The contact
- *
- * Returns the highest priority buddy for a given contact.
- *
- * Returns: (transfer none): The highest priority buddy.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleBuddy *purple_meta_contact_get_priority_buddy(PurpleMetaContact *contact);
-
-/**
  * purple_meta_contact_set_alias:
  * @contact:  The contact
  * @alias:    The alias
@@ -130,32 +117,6 @@
 PURPLE_AVAILABLE_IN_3_0
 const char *purple_meta_contact_get_alias(PurpleMetaContact *contact);
 
-/**
- * purple_meta_contact_on_account:
- * @contact:  The contact to search through.
- * @account:  The account.
- *
- * Determines whether an account owns any buddies in a given contact
- *
- * Returns: TRUE if there are any buddies from account in the contact, or FALSE otherwise.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gboolean purple_meta_contact_on_account(PurpleMetaContact *contact, PurpleAccount *account);
-
-/**
- * purple_meta_contact_invalidate_priority_buddy:
- * @contact:  The contact
- *
- * Invalidates the priority buddy so that the next call to
- * purple_meta_contact_get_priority_buddy recomputes it.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_meta_contact_invalidate_priority_buddy(PurpleMetaContact *contact);
-
 G_END_DECLS
 
 #endif /* PURPLE_META_CONTACT_H */
diff --git a/libpurple/contact.c b/libpurple/contact.c
--- a/libpurple/contact.c
+++ b/libpurple/contact.c
@@ -21,24 +21,24 @@
  */
 
 #include "contact.h"
+
+#include "buddylist.h"
 #include "prefs.h"
 #include "purpleconversationmanager.h"
 #include "purpleprivate.h"
+#include "signals.h"
 #include "util.h"
 
 typedef struct _PurpleMetaContactPrivate    PurpleMetaContactPrivate;
 
 struct _PurpleMetaContactPrivate {
 	char *alias;                  /* The user-set alias of the contact  */
-	PurpleBuddy *priority_buddy;  /* The "top" buddy for this contact   */
-	gboolean priority_valid;      /* Is priority valid?                 */
 };
 
 enum
 {
 	PROP_0,
 	PROP_ALIAS,
-	PROP_PRIORITY_BUDDY,
 	N_PROPERTIES,
 };
 
@@ -53,53 +53,6 @@
 /******************************************************************************
  * API
  *****************************************************************************/
-static void
-purple_meta_contact_compute_priority_buddy(PurpleMetaContact *contact) {
-	PurpleBlistNode *bnode;
-	PurpleBuddy *new_priority = NULL;
-	PurpleMetaContactPrivate *priv =
-			purple_meta_contact_get_instance_private(contact);
-
-	priv->priority_buddy = NULL;
-	for (bnode = PURPLE_BLIST_NODE(contact)->child;
-			bnode != NULL;
-			bnode = bnode->next)
-	{
-		PurpleBuddy *buddy;
-
-		if (!PURPLE_IS_BUDDY(bnode))
-			continue;
-
-		buddy = PURPLE_BUDDY(bnode);
-		if (new_priority == NULL)
-		{
-			new_priority = buddy;
-			continue;
-		}
-
-		if (purple_account_is_connected(purple_buddy_get_account(buddy)))
-		{
-			int cmp = 1;
-			if (purple_account_is_connected(purple_buddy_get_account(new_priority)))
-				cmp = purple_presence_compare(
-						purple_buddy_get_presence(new_priority),
-						purple_buddy_get_presence(buddy));
-
-			if (cmp > 0 || (cmp == 0 &&
-			                purple_prefs_get_bool("/purple/contact/last_match")))
-			{
-				new_priority = buddy;
-			}
-		}
-	}
-
-	priv->priority_buddy = new_priority;
-	priv->priority_valid = TRUE;
-
-	g_object_notify_by_pspec(G_OBJECT(contact),
-			properties[PROP_PRIORITY_BUDDY]);
-}
-
 void
 purple_meta_contact_set_alias(PurpleMetaContact *contact, const char *alias)
 {
@@ -149,50 +102,7 @@
 	if (priv->alias)
 		return priv->alias;
 
-	return purple_buddy_get_alias(purple_meta_contact_get_priority_buddy(contact));
-}
-
-gboolean purple_meta_contact_on_account(PurpleMetaContact *c, PurpleAccount *account)
-{
-	PurpleBlistNode *bnode, *cnode = (PurpleBlistNode *) c;
-
-	g_return_val_if_fail(PURPLE_IS_META_CONTACT(c), FALSE);
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
-
-	for (bnode = cnode->child; bnode; bnode = bnode->next) {
-		PurpleBuddy *buddy;
-
-		if (! PURPLE_IS_BUDDY(bnode))
-			continue;
-
-		buddy = (PurpleBuddy *)bnode;
-		if (purple_buddy_get_account(buddy) == account)
-			return TRUE;
-	}
-	return FALSE;
-}
-
-void purple_meta_contact_invalidate_priority_buddy(PurpleMetaContact *contact)
-{
-	PurpleMetaContactPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_META_CONTACT(contact));
-
-	priv = purple_meta_contact_get_instance_private(contact);
-	priv->priority_valid = FALSE;
-}
-
-PurpleBuddy *purple_meta_contact_get_priority_buddy(PurpleMetaContact *contact)
-{
-	PurpleMetaContactPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_META_CONTACT(contact), NULL);
-
-	priv = purple_meta_contact_get_instance_private(contact);
-	if (!priv->priority_valid)
-		purple_meta_contact_compute_priority_buddy(contact);
-
-	return priv->priority_buddy;
+	return NULL;
 }
 
 /**************************************************************************
@@ -228,9 +138,6 @@
 		case PROP_ALIAS:
 			g_value_set_string(value, priv->alias);
 			break;
-		case PROP_PRIORITY_BUDDY:
-			g_value_set_object(value, purple_meta_contact_get_priority_buddy(contact));
-			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
 			break;
@@ -283,21 +190,6 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
 	);
 
-	/**
-	 * PurpleMetaContact:priority-buddy:
-	 *
-	 * The priority buddy of the contact.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_PRIORITY_BUDDY] = g_param_spec_object(
-		"priority-buddy",
-		"Priority buddy",
-		"The priority buddy of the contact.",
-		PURPLE_TYPE_BUDDY,
-		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS
-	);
-
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
 }
 
diff --git a/libpurple/conversations.c b/libpurple/conversations.c
--- a/libpurple/conversations.c
+++ b/libpurple/conversations.c
@@ -25,6 +25,7 @@
 #include "prefs.h"
 #include "purpleprivate.h"
 #include "purpleconversationmanager.h"
+#include "signals.h"
 
 void *
 purple_conversations_get_handle(void)
diff --git a/libpurple/core.c b/libpurple/core.c
--- a/libpurple/core.c
+++ b/libpurple/core.c
@@ -26,6 +26,7 @@
 #define G_SETTINGS_ENABLE_BACKEND
 #include <gio/gsettingsbackend.h>
 
+#include "buddylist.h"
 #include "cmds.h"
 #include "connection.h"
 #include "conversations.h"
@@ -147,10 +148,6 @@
 	 */
 	purple_plugins_init();
 
-	/* Accounts buddy icons and connection signals, so initialize these before
-	 * accounts.
-	 */
-	purple_buddy_icons_init();
 	purple_connections_init();
 
 	purple_account_manager_startup();
@@ -235,7 +232,6 @@
 	purple_blist_uninit();
 	purple_notify_uninit();
 	purple_connections_uninit();
-	purple_buddy_icons_uninit();
 	purple_presence_manager_shutdown();
 	purple_accounts_uninit();
 	purple_proxy_uninit();
diff --git a/libpurple/group.c b/libpurple/group.c
--- a/libpurple/group.c
+++ b/libpurple/group.c
@@ -22,9 +22,12 @@
 
 #include "group.h"
 
+#include "buddylist.h"
+#include "contact.h"
 #include "debug.h"
 #include "purpleprivate.h"
 #include "purpleprotocolserver.h"
+#include "util.h"
 
 typedef struct _PurpleGroupPrivate      PurpleGroupPrivate;
 
@@ -56,34 +59,15 @@
 /******************************************************************************
  * Group API
  *****************************************************************************/
-GSList *purple_group_get_accounts(PurpleGroup *group) {
-	GSList *l = NULL;
-	PurpleBlistNode *gnode, *cnode, *bnode;
-
-	gnode = (PurpleBlistNode *)group;
-
-	for (cnode = gnode->child;  cnode; cnode = cnode->next) {
-		if (PURPLE_IS_META_CONTACT(cnode)) {
-			for (bnode = cnode->child; bnode; bnode = bnode->next) {
-				if (PURPLE_IS_BUDDY(bnode)) {
-					if (!g_slist_find(l, purple_buddy_get_account(PURPLE_BUDDY(bnode))))
-						l = g_slist_append(l, purple_buddy_get_account(PURPLE_BUDDY(bnode)));
-				}
-			}
-		}
-	}
-
-	return l;
+GSList *
+purple_group_get_accounts(G_GNUC_UNUSED PurpleGroup *group) {
+	return NULL;
 }
 
-gboolean purple_group_on_account(PurpleGroup *g, PurpleAccount *account) {
-	PurpleBlistNode *cnode;
-	for (cnode = ((PurpleBlistNode *)g)->child; cnode; cnode = cnode->next) {
-		if (PURPLE_IS_META_CONTACT(cnode)) {
-			if(purple_meta_contact_on_account((PurpleMetaContact *) cnode, account))
-				return TRUE;
-		}
-	}
+gboolean
+purple_group_on_account(G_GNUC_UNUSED PurpleGroup *g,
+                        G_GNUC_UNUSED PurpleAccount *account)
+{
 	return FALSE;
 }
 
@@ -129,13 +113,7 @@
 		{
 			next = child->next;
 			if (PURPLE_IS_META_CONTACT(child)) {
-				PurpleBlistNode *bnode;
 				purple_blist_add_contact((PurpleMetaContact *)child, dest, prev);
-				for (bnode = child->child; bnode != NULL; bnode = bnode->next) {
-					purple_blist_add_buddy((PurpleBuddy *)bnode, (PurpleMetaContact *)child,
-							NULL, bnode->prev);
-					moved_buddies = g_list_append(moved_buddies, bnode);
-				}
 				prev = child;
 			} else {
 				purple_debug_error("blistnodetypes", "Unknown child type in group %s", priv->name);
@@ -183,7 +161,7 @@
 			PurpleAccount *account = accts->data;
 			PurpleConnection *gc = NULL;
 			PurpleProtocol *protocol = NULL;
-			GList *l = NULL, *buddies = NULL;
+			GList *buddies = NULL;
 
 			gc = purple_account_get_connection(account);
 
@@ -193,13 +171,6 @@
 			if(!protocol)
 				continue;
 
-			for(l = moved_buddies; l; l = l->next) {
-				PurpleBuddy *buddy = PURPLE_BUDDY(l->data);
-
-				if(buddy && purple_buddy_get_account(buddy) == account)
-					buddies = g_list_append(buddies, (PurpleBlistNode *)buddy);
-			}
-
 			if(PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, rename_group)) {
 				purple_protocol_server_rename_group(PURPLE_PROTOCOL_SERVER(protocol),
 				                                    gc, old_name, source,
@@ -213,9 +184,7 @@
 					groups = g_list_prepend(groups, node->parent->parent);
 				}
 
-				purple_account_remove_buddies(account, buddies, groups);
 				g_list_free(groups);
-				purple_account_add_buddies(account, buddies, NULL);
 			}
 
 			g_list_free(buddies);
@@ -346,8 +315,6 @@
 		name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
 	if (g_strcmp0(name, "Buddies") == 0)
 		name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
-	if (g_strcmp0(name, _purple_blist_get_localized_default_group_name()) == 0)
-		name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
 
 	group = purple_blist_find_group(name);
 	if (group != NULL)
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -2,9 +2,7 @@
 	'accounts.c',
 	'action.c',
 	'blistnode.c',
-	'buddy.c',
 	'buddylist.c',
-	'buddyicon.c',
 	'circularbuffer.c',
 	'cmds.c',
 	'connection.c',
@@ -111,9 +109,7 @@
 	'accounts.h',
 	'action.h',
 	'blistnode.h',
-	'buddy.h',
 	'buddylist.h',
-	'buddyicon.h',
 	'circularbuffer.h',
 	'cmds.h',
 	'connection.h',
@@ -266,7 +262,6 @@
 ]
 
 purple_enumheaders = [
-	'buddyicon.h',
 	'connection.h',
 	'debug.h',
 	'notify.h',
diff --git a/libpurple/purpleaccount.h b/libpurple/purpleaccount.h
--- a/libpurple/purpleaccount.h
+++ b/libpurple/purpleaccount.h
@@ -506,62 +506,6 @@
 gboolean purple_account_get_bool(PurpleAccount *account, const char *name, gboolean default_value);
 
 /**
- * purple_account_add_buddy:
- * @account: The account.
- * @buddy: The buddy to add.
- * @message: The invite message.  This may be ignored by a protocol.
- *
- * Adds a buddy to the server-side buddy list for the specified account.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_account_add_buddy(PurpleAccount *account, PurpleBuddy *buddy, const char *message);
-
-/**
- * purple_account_add_buddies:
- * @account: The account.
- * @buddies: (element-type PurpleBuddy): The list of PurpleBlistNodes representing the buddies to add.
- * @message: The invite message.  This may be ignored by a protocol.
- *
- * Adds a list of buddies to the server-side buddy list.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_account_add_buddies(PurpleAccount *account, GList *buddies, const char *message);
-
-/**
- * purple_account_remove_buddy:
- * @account: The account.
- * @buddy: The buddy to remove.
- * @group: The group to remove the buddy from.
- *
- * Removes a buddy from the server-side buddy list.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_account_remove_buddy(PurpleAccount *account, PurpleBuddy *buddy, PurpleGroup *group);
-
-/**
- * purple_account_remove_buddies:
- * @account: The account.
- * @buddies: (element-type PurpleBuddy): The list of buddies to remove.
- * @groups: (element-type PurpleGroup): The list of groups to remove buddies from.  Each node of this
- *               list should match the corresponding node of buddies.
- *
- * Removes a list of buddies from the server-side buddy list.
- *
- * Note: The lists buddies and groups are parallel lists.  Be sure that node n of
- *       groups matches node n of buddies.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_account_remove_buddies(PurpleAccount *account, GList *buddies, GList *groups);
-
-/**
  * purple_account_remove_group:
  * @account: The account.
  * @group: The group to remove.
@@ -587,20 +531,6 @@
 void purple_account_change_password(PurpleAccount *account, const char *orig_pw, const char *new_pw);
 
 /**
- * purple_account_supports_offline_message:
- * @account: The account
- * @buddy: The buddy
- *
- * Whether the account supports sending offline messages to buddy.
- *
- * Returns: %TRUE if offline messages are supported, otherwise %FALSE.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-gboolean purple_account_supports_offline_message(PurpleAccount *account, PurpleBuddy *buddy);
-
-/**
  * purple_account_get_error:
  * @account: The account whose error should be retrieved.
  *
diff --git a/libpurple/purpleaccount.c b/libpurple/purpleaccount.c
--- a/libpurple/purpleaccount.c
+++ b/libpurple/purpleaccount.c
@@ -391,24 +391,6 @@
 }
 
 static void
-purple_account_changed_cb(GObject *obj, GParamSpec *pspec,
-                          G_GNUC_UNUSED gpointer data)
-{
-	const char *name = NULL;
-
-	purple_accounts_schedule_save();
-
-	name = g_param_spec_get_name(pspec);
-	if(purple_strequal(name, "username")) {
-		/* if the username changes, we should re-write the buddy list to disk
-		 * with the new name.
-		  */
-		purple_blist_save_account(purple_blist_get_default(),
-		                          PURPLE_ACCOUNT(obj));
-	}
-}
-
-static void
 purple_account_connection_state_cb(GObject *obj,
                                    G_GNUC_UNUSED GParamSpec *pspec,
                                    gpointer data)
@@ -776,10 +758,6 @@
 	}
 
 	account->presence = purple_presence_new();
-
-	/* Connect to our own notify signal so we can update accounts.xml. */
-	g_signal_connect(object, "notify",
-	                 G_CALLBACK(purple_account_changed_cb), NULL);
 }
 
 static void
@@ -1635,87 +1613,6 @@
 }
 
 void
-purple_account_add_buddy(PurpleAccount *account, PurpleBuddy *buddy,
-                         const char *message)
-{
-	PurpleProtocol *protocol = NULL;
-	PurpleConnection *gc;
-
-	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	gc = purple_account_get_connection(account);
-	if(gc != NULL) {
-		protocol = purple_connection_get_protocol(gc);
-	}
-
-	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
-		PurpleGroup *group = purple_buddy_get_group(buddy);
-
-		purple_protocol_server_add_buddy(PURPLE_PROTOCOL_SERVER(protocol), gc,
-		                                 buddy, group, message);
-	}
-}
-
-void
-purple_account_add_buddies(PurpleAccount *account, GList *buddies,
-                           const char *message)
-{
-	PurpleProtocol *protocol = NULL;
-	PurpleConnection *gc = purple_account_get_connection(account);
-
-	if(gc != NULL) {
-		protocol = purple_connection_get_protocol(gc);
-	}
-
-	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
-		PurpleProtocolServer *server = PURPLE_PROTOCOL_SERVER(protocol);
-
-		for(GList *b = buddies; b != NULL; b = b->next) {
-			PurpleBuddy *buddy = b->data;
-
-			purple_protocol_server_add_buddy(server, gc, buddy,
-			                                 purple_buddy_get_group(buddy),
-			                                 message);
-		}
-	}
-}
-
-void
-purple_account_remove_buddy(PurpleAccount *account, PurpleBuddy *buddy,
-                            PurpleGroup *group)
-{
-	PurpleProtocol *protocol = NULL;
-	PurpleConnection *gc = purple_account_get_connection(account);
-
-	if(gc != NULL) {
-		protocol = purple_connection_get_protocol(gc);
-	}
-
-	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
-		purple_protocol_server_remove_buddy(PURPLE_PROTOCOL_SERVER(protocol),
-		                                    gc, buddy, group);
-	}
-}
-
-void
-purple_account_remove_buddies(PurpleAccount *account, GList *buddies,
-                              GList *groups)
-{
-	PurpleProtocol *protocol = NULL;
-	PurpleConnection *gc = purple_account_get_connection(account);
-
-	if(gc != NULL) {
-		protocol = purple_connection_get_protocol(gc);
-	}
-
-	if(PURPLE_IS_PROTOCOL_SERVER(protocol)) {
-		purple_protocol_server_remove_buddies(PURPLE_PROTOCOL_SERVER(protocol),
-		                                      gc, buddies, groups);
-	}
-}
-
-void
 purple_account_remove_group(PurpleAccount *account, PurpleGroup *group) {
 	PurpleProtocol *protocol = NULL;
 	PurpleConnection *gc = purple_account_get_connection(account);
@@ -1755,30 +1652,6 @@
 	}
 }
 
-gboolean
-purple_account_supports_offline_message(PurpleAccount *account,
-                                        PurpleBuddy *buddy)
-{
-	PurpleConnection *gc;
-	PurpleProtocol *protocol = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), FALSE);
-
-	gc = purple_account_get_connection(account);
-	if(gc == NULL) {
-		return FALSE;
-	}
-
-	protocol = purple_connection_get_protocol(gc);
-	if(!protocol) {
-		return FALSE;
-	}
-
-	return purple_protocol_client_offline_message(PURPLE_PROTOCOL_CLIENT(protocol),
-	                                              buddy);
-}
-
 const PurpleConnectionErrorInfo *
 purple_account_get_error(PurpleAccount *account) {
 	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
diff --git a/libpurple/purpleaccountmanager.c b/libpurple/purpleaccountmanager.c
--- a/libpurple/purpleaccountmanager.c
+++ b/libpurple/purpleaccountmanager.c
@@ -26,6 +26,7 @@
 #include "accounts.h"
 #include "core.h"
 #include "purpleaccount.h"
+#include "util.h"
 
 enum {
 	PROP_0,
diff --git a/libpurple/purpleauthorizationrequestnotification.c b/libpurple/purpleauthorizationrequestnotification.c
--- a/libpurple/purpleauthorizationrequestnotification.c
+++ b/libpurple/purpleauthorizationrequestnotification.c
@@ -24,6 +24,8 @@
 
 #include "purpleauthorizationrequestnotification.h"
 
+#include "util.h"
+
 enum {
 	PROP_0,
 	PROP_AUTHORIZATION_REQUEST,
diff --git a/libpurple/purpleconversation.h b/libpurple/purpleconversation.h
--- a/libpurple/purpleconversation.h
+++ b/libpurple/purpleconversation.h
@@ -155,7 +155,6 @@
 	gpointer reserved[4];
 };
 
-#include "buddyicon.h"
 #include "purpleaccount.h"
 
 G_BEGIN_DECLS
diff --git a/libpurple/purpleconversation.c b/libpurple/purpleconversation.c
--- a/libpurple/purpleconversation.c
+++ b/libpurple/purpleconversation.c
@@ -35,6 +35,8 @@
 #include "purpleprivate.h"
 #include "purpleprotocolconversation.h"
 #include "purpletags.h"
+#include "signals.h"
+#include "util.h"
 
 typedef struct {
 	char *id;
diff --git a/libpurple/purpleconversationmanager.c b/libpurple/purpleconversationmanager.c
--- a/libpurple/purpleconversationmanager.c
+++ b/libpurple/purpleconversationmanager.c
@@ -24,6 +24,7 @@
 
 #include "purplecontact.h"
 #include "purpleprivate.h"
+#include "util.h"
 
 enum {
 	SIG_REGISTERED,
diff --git a/libpurple/purplecredentialmanager.c b/libpurple/purplecredentialmanager.c
--- a/libpurple/purplecredentialmanager.c
+++ b/libpurple/purplecredentialmanager.c
@@ -30,6 +30,7 @@
 #include "prefs.h"
 #include "purplenoopcredentialprovider.h"
 #include "purpleprivate.h"
+#include "signals.h"
 #include "util.h"
 
 enum {
diff --git a/libpurple/purplenotification.c b/libpurple/purplenotification.c
--- a/libpurple/purplenotification.c
+++ b/libpurple/purplenotification.c
@@ -25,6 +25,7 @@
 #include "purplenotification.h"
 
 #include "purpleenums.h"
+#include "util.h"
 
 typedef struct {
 	char *id;
diff --git a/libpurple/purplepresence.c b/libpurple/purplepresence.c
--- a/libpurple/purplepresence.c
+++ b/libpurple/purplepresence.c
@@ -27,6 +27,7 @@
 #include "debug.h"
 #include "purpleenums.h"
 #include "purpleprivate.h"
+#include "util.h"
 
 typedef struct {
 	gboolean idle;
diff --git a/libpurple/purpleprivate.h b/libpurple/purpleprivate.h
--- a/libpurple/purpleprivate.h
+++ b/libpurple/purpleprivate.h
@@ -35,6 +35,7 @@
 #include "purplecredentialprovider.h"
 #include "purplehistoryadapter.h"
 #include "purpleversion.h"
+#include "xmlnode.h"
 
 G_BEGIN_DECLS
 
@@ -60,16 +61,6 @@
 G_GNUC_INTERNAL
 PurpleBlistNode *_purple_blist_get_last_child(PurpleBlistNode *node);
 
-/* This is for the accounts code to notify the buddy icon code that
- * it's done loading.  We may want to replace this with a signal. */
-G_GNUC_INTERNAL
-void _purple_buddy_icons_account_loaded_cb(void);
-
-/* This is for the buddy list to notify the buddy icon code that
- * it's done loading.  We may want to replace this with a signal. */
-G_GNUC_INTERNAL
-void _purple_buddy_icons_blist_loaded_cb(void);
-
 /**
  * _purple_connection_wants_to_die:
  * @gc:  The connection to check
diff --git a/libpurple/purpleprotocol.h b/libpurple/purpleprotocol.h
--- a/libpurple/purpleprotocol.h
+++ b/libpurple/purpleprotocol.h
@@ -30,6 +30,8 @@
 #include <glib.h>
 #include <glib-object.h>
 
+#include <gio/gio.h>
+
 #include "purpleversion.h"
 
 #define PURPLE_TYPE_PROTOCOL (purple_protocol_get_type())
@@ -46,7 +48,6 @@
 G_DECLARE_DERIVABLE_TYPE(PurpleProtocol, purple_protocol, PURPLE, PROTOCOL,
                          GObject)
 
-#include "buddyicon.h"
 #include "connection.h"
 #include "purpleaccount.h"
 #include "purplewhiteboardops.h"
@@ -117,7 +118,6 @@
  *                   procotol provides.
  * @get_account_options: Returns a list of all #PurpleAccountOption's for the
  *                       protocol.
- * @get_buddy_icon_spec: Returns a #PurpleBuddyIconSpec that should be used.
  * @get_whiteboard_ops: Return the #PurpleWhiteboardOps that should be used.
  * @login: Logs into the server.
  * @close: Close sconnection with the server.
@@ -139,7 +139,6 @@
 
 	GList *(*get_user_splits)(PurpleProtocol *protocol);
 	GList *(*get_account_options)(PurpleProtocol *protocol);
-	PurpleBuddyIconSpec *(*get_buddy_icon_spec)(PurpleProtocol *protocol);
 	PurpleWhiteboardOps *(*get_whiteboard_ops)(PurpleProtocol *protocol);
 
 	void (*can_connect_async)(PurpleProtocol *protocol, PurpleAccount *account, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data);
@@ -252,19 +251,6 @@
 GList *purple_protocol_get_account_options(PurpleProtocol *protocol);
 
 /**
- * purple_protocol_get_icon_spec:
- * @protocol: The #PurpleProtocol instance.
- *
- * Gets the icon spec of a protocol.
- *
- * Returns: (transfer full): The icon spec of the protocol.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleBuddyIconSpec *purple_protocol_get_icon_spec(PurpleProtocol *protocol);
-
-/**
  * purple_protocol_get_whiteboard_ops:
  * @protocol: The #PurpleProtocol instance.
  *
diff --git a/libpurple/purpleprotocol.c b/libpurple/purpleprotocol.c
--- a/libpurple/purpleprotocol.c
+++ b/libpurple/purpleprotocol.c
@@ -26,6 +26,7 @@
 #include "prefs.h"
 #include "purpleaccountmanager.h"
 #include "purpleenums.h"
+#include "signals.h"
 
 enum {
 	PROP_0,
@@ -491,20 +492,6 @@
 	return NULL;
 }
 
-PurpleBuddyIconSpec *
-purple_protocol_get_icon_spec(PurpleProtocol *protocol) {
-	PurpleProtocolClass *klass = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol), NULL);
-
-	klass = PURPLE_PROTOCOL_GET_CLASS(protocol);
-	if(klass != NULL && klass->get_buddy_icon_spec != NULL) {
-		return klass->get_buddy_icon_spec(protocol);
-	}
-
-	return NULL;
-}
-
 PurpleWhiteboardOps *
 purple_protocol_get_whiteboard_ops(PurpleProtocol *protocol) {
 	PurpleProtocolClass *klass = NULL;
diff --git a/libpurple/purpleprotocolclient.h b/libpurple/purpleprotocolclient.h
--- a/libpurple/purpleprotocolclient.h
+++ b/libpurple/purpleprotocolclient.h
@@ -56,14 +56,10 @@
 	GTypeInterface parent;
 
 	/*< public >*/
-	void (*buddy_free)(PurpleProtocolClient *client, PurpleBuddy *buddy);
-
 	void (*convo_closed)(PurpleProtocolClient *client, PurpleConnection *connection, const gchar *who);
 
 	const gchar *(*normalize)(PurpleProtocolClient *client, PurpleAccount *account, const gchar *who);
 
-	gboolean (*offline_message)(PurpleProtocolClient *client, PurpleBuddy *buddy);
-
 	/*< private >*/
 	gpointer reserved[4];
 };
@@ -71,18 +67,6 @@
 G_BEGIN_DECLS
 
 /**
- * purple_protocol_client_buddy_free:
- * @client: The #PurpleProtocolClient instance.
- * @buddy: A #PurpleBuddy instance.
- *
- * Cleans up any protocol specific data for @buddy.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_protocol_client_buddy_free(PurpleProtocolClient *client, PurpleBuddy *buddy);
-
-/**
  * purple_protocol_client_convo_closed:
  * @client: The #PurpleProtocolClient instance.
  * @connection: A #PurpleConnection instance.
@@ -115,20 +99,6 @@
 PURPLE_DEPRECATED
 const gchar *purple_protocol_client_normalize(PurpleProtocolClient *client, PurpleAccount *account, const gchar *who);
 
-/**
- * purple_protocol_client_offline_message:
- * @client: The #PurpleProtocolClient instance.
- * @buddy: A #PurpleBuddy instance.
- *
- * Checks whether offline messages to @buddy are supported.
- *
- * Returns: %TRUE if @buddy supports offline messages, otherwise %FALSE.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gboolean purple_protocol_client_offline_message(PurpleProtocolClient *client, PurpleBuddy *buddy);
-
 G_END_DECLS
 
 #endif /* PURPLE_PROTOCOL_CLIENT_H */
diff --git a/libpurple/purpleprotocolclient.c b/libpurple/purpleprotocolclient.c
--- a/libpurple/purpleprotocolclient.c
+++ b/libpurple/purpleprotocolclient.c
@@ -39,21 +39,6 @@
  * Public API
  *****************************************************************************/
 void
-purple_protocol_client_buddy_free(PurpleProtocolClient *client,
-                                  PurpleBuddy *buddy)
-{
-	PurpleProtocolClientInterface *iface = NULL;
-
-	g_return_if_fail(PURPLE_IS_PROTOCOL_CLIENT(client));
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	iface = PURPLE_PROTOCOL_CLIENT_GET_IFACE(client);
-	if(iface != NULL && iface->buddy_free != NULL) {
-		iface->buddy_free(client, buddy);
-	}
-}
-
-void
 purple_protocol_client_convo_closed(PurpleProtocolClient *client,
                                     PurpleConnection *connection,
                                     const gchar *who)
@@ -86,20 +71,3 @@
 
 	return NULL;
 }
-
-gboolean
-purple_protocol_client_offline_message(PurpleProtocolClient *client,
-                                       PurpleBuddy *buddy)
-{
-	PurpleProtocolClientInterface *iface = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_PROTOCOL_CLIENT(client), FALSE);
-	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), FALSE);
-
-	iface = PURPLE_PROTOCOL_CLIENT_GET_IFACE(client);
-	if(iface != NULL && iface->offline_message != NULL) {
-		return iface->offline_message(client, buddy);
-	}
-
-	return FALSE;
-}
diff --git a/libpurple/purpleprotocolcontacts.c b/libpurple/purpleprotocolcontacts.c
--- a/libpurple/purpleprotocolcontacts.c
+++ b/libpurple/purpleprotocolcontacts.c
@@ -22,6 +22,8 @@
 
 #include "purpleprotocolcontacts.h"
 
+#include "util.h"
+
 /******************************************************************************
  * GInterface Implementation
  *****************************************************************************/
diff --git a/libpurple/purpleprotocolserver.h b/libpurple/purpleprotocolserver.h
--- a/libpurple/purpleprotocolserver.h
+++ b/libpurple/purpleprotocolserver.h
@@ -30,7 +30,6 @@
 #include <glib.h>
 #include <glib-object.h>
 
-#include "buddy.h"
 #include "connection.h"
 #include "group.h"
 #include "purpleaccount.h"
@@ -67,18 +66,8 @@
 
 	void (*change_passwd)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_pass, const gchar *new_pass);
 
-	void (*add_buddy)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleBuddy *buddy, PurpleGroup *group, const gchar *message);
-	void (*remove_buddy)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleBuddy *buddy, PurpleGroup *group);
-	void (*remove_buddies)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, GList *buddies, GList *groups);
-
-	void (*alias_buddy)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *who, const gchar *alias);
-
-	void (*group_buddy)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *who, const gchar *old_group, const gchar *new_group);
-
 	void (*rename_group)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_name, PurpleGroup *group, GList *moved_buddies);
 
-	void (*set_buddy_icon)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleImage *img);
-
 	void (*remove_group)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleGroup *group);
 
 	gint (*send_raw)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *buf, gint len);
@@ -142,80 +131,12 @@
 void purple_protocol_server_change_passwd(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_pass, const gchar *new_pass);
 
 /**
- * purple_protocol_server_add_buddy:
- * @protocol_server: The #PurpleProtocolServer instance.
- * @connection: The #PurpleConnection instance.
- * @buddy: The #PurpleBuddy to add.
- * @group: The #PurpleGroup for @buddy.
- * @message: An optional invite message.
- *
- * This protocol function may be called in situations in which the buddy is
- * already in the specified group. If the protocol supports authorization and
- * the user is not already authorized to see the status of @buddy, this
- * function will request authorization. If authorization is required, then
- * @message will be used as an invite message.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_protocol_server_add_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleBuddy *buddy, PurpleGroup *group, const gchar *message);
-
-/**
- * purple_protocol_server_remove_buddy:
- * @protocol_server: The #PurpleProtocolServer instance.
- * @connection: The #PurpleConnection instance.
- * @buddy: The #PurpleBuddy instance.
- * @group: (nullable): The #PurpleGroup instance.
- *
- * Removes @buddy and potentially @group from the server side list of contacts.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_protocol_server_remove_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleBuddy *buddy, PurpleGroup *group);
-
-/**
- * purple_protocol_server_remove_buddies:
- * @protocol_server: The #PurpleProtocolServer instance.
- * @connection: The #PurpleConnection instance.
- * @buddies: (element-type PurpleBuddy): A #GList of #PurpleBuddy's to remove.
- * @groups: (element-type PurpleGroup): A #GList of #PurpleGroup's
- *          corresponding to @buddies.
- *
- * Similar to purple_protocol_server_remove_buddy() but allows you to remove
- * multiple at a time.
- *
- * If @protocol_server doesn't implement this function directly,
- * purple_protocol_server_remove_buddy() will be called for each buddy/group
- * pair in @buddies/@groups.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_protocol_server_remove_buddies(PurpleProtocolServer *protocol_server, PurpleConnection *connection, GList *buddies, GList *groups);
-
-/**
- * purple_protocol_server_group_buddy:
- * @protocol_server: The #PurpleProtocolServer instance.
- * @connection: The #PurpleConnection instance.
- * @who: The name of the user whose group to switch.
- * @old_group: The name of @who's old group.
- * @new_group: The name of the new group to add @who to.
- *
- * Moves @who from group @old_group to a new group of @new_group.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_protocol_server_group_buddy(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *who, const gchar *old_group, const gchar *new_group);
-
-/**
  * purple_protocol_server_rename_group:
  * @protocol_server: The #PurpleProtocolServer instance.
  * @connection:  The #PurpleConnection instance.
  * @old_name: The old name of the group.
  * @group: The new #PurpleGroup instance.
- * @moved_buddies: (element-type PurpleBuddy): A list of #PurpleBuddy's being
+ * @moved_buddies: (element-type GObject): A list of #PurpleBuddy's being
  *                 moved as part of this rename.
  *
  * Renames the group named @old_name to the new @group.
@@ -226,19 +147,6 @@
 void purple_protocol_server_rename_group(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_name, PurpleGroup *group, GList *moved_buddies);
 
 /**
- * purple_protocol_server_set_buddy_icon:
- * @protocol_server: The #PurpleProtocolServer instance.
- * @connection: The #PurpleConnection instance.
- * @img: (nullable): The #PurpleImage instance, or %NULL to unset the icon.
- *
- * Sets the user's buddy icon to @img.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_protocol_server_set_buddy_icon(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleImage *img);
-
-/**
  * purple_protocol_server_remove_group:
  * @protocol_server: The #PurpleProtocolServer instance.
  * @connection: The #PurpleConnection instance.
diff --git a/libpurple/purpleprotocolserver.c b/libpurple/purpleprotocolserver.c
--- a/libpurple/purpleprotocolserver.c
+++ b/libpurple/purpleprotocolserver.c
@@ -103,86 +103,6 @@
 }
 
 void
-purple_protocol_server_add_buddy(PurpleProtocolServer *protocol_server,
-                                 PurpleConnection *connection,
-                                 PurpleBuddy *buddy, PurpleGroup *group,
-                                 const gchar *message)
-{
-	PurpleProtocolServerInterface *iface = NULL;
-
-	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
-	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-	g_return_if_fail(PURPLE_IS_GROUP(group));
-
-	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
-	if(iface != NULL && iface->add_buddy != NULL) {
-		iface->add_buddy(protocol_server, connection, buddy, group, message);
-	}
-}
-
-void
-purple_protocol_server_remove_buddy(PurpleProtocolServer *protocol_server,
-                                    PurpleConnection *connection,
-                                    PurpleBuddy *buddy, PurpleGroup *group)
-{
-	PurpleProtocolServerInterface *iface = NULL;
-
-	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
-	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
-	g_return_if_fail(PURPLE_IS_BUDDY(buddy));
-
-	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
-	if(iface != NULL && iface->remove_buddy != NULL) {
-		iface->remove_buddy(protocol_server, connection, buddy, group);
-	}
-}
-
-void
-purple_protocol_server_remove_buddies(PurpleProtocolServer *protocol_server,
-                                      PurpleConnection *connection,
-                                      GList *buddies, GList *groups)
-{
-	PurpleProtocolServerInterface *iface = NULL;
-
-	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
-	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
-
-	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
-	if(iface != NULL && iface->remove_buddies != NULL) {
-		iface->remove_buddies(protocol_server, connection, buddies, groups);
-	} else {
-		while(buddies != NULL && groups != NULL) {
-			purple_protocol_server_remove_buddy(protocol_server, connection,
-			                                    PURPLE_BUDDY(buddies->data),
-			                                    PURPLE_GROUP(groups->data));
-
-			buddies = g_list_next(buddies);
-			groups = g_list_next(groups);
-		}
-	}
-}
-
-void
-purple_protocol_server_group_buddy(PurpleProtocolServer *protocol_server,
-                                   PurpleConnection *connection,
-                                   const gchar *who, const gchar *old_group,
-                                   const gchar *new_group)
-{
-	PurpleProtocolServerInterface *iface = NULL;
-
-	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
-	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
-	g_return_if_fail(who != NULL);
-
-	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
-	if(iface != NULL && iface->group_buddy != NULL) {
-		iface->group_buddy(protocol_server, connection, who, old_group,
-		                   new_group);
-	}
-}
-
-void
 purple_protocol_server_rename_group(PurpleProtocolServer *protocol_server,
                                     PurpleConnection *connection,
                                     const gchar *old_name, PurpleGroup *group,
@@ -202,22 +122,6 @@
 }
 
 void
-purple_protocol_server_set_buddy_icon(PurpleProtocolServer *protocol_server,
-                                      PurpleConnection *connection,
-                                      PurpleImage *img)
-{
-	PurpleProtocolServerInterface *iface = NULL;
-
-	g_return_if_fail(PURPLE_IS_PROTOCOL_SERVER(protocol_server));
-	g_return_if_fail(PURPLE_IS_CONNECTION(connection));
-
-	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
-	if(iface != NULL && iface->set_buddy_icon != NULL) {
-		iface->set_buddy_icon(protocol_server, connection, img);
-	}
-}
-
-void
 purple_protocol_server_remove_group(PurpleProtocolServer *protocol_server,
                                     PurpleConnection *connection,
                                     PurpleGroup *group)
diff --git a/libpurple/request.c b/libpurple/request.c
--- a/libpurple/request.c
+++ b/libpurple/request.c
@@ -29,6 +29,7 @@
 #include "debug.h"
 #include "purplekeyvaluepair.h"
 #include "purpleprivate.h"
+#include "util.h"
 
 static PurpleRequestUiOps *request_ui_ops = NULL;
 static GList *handles = NULL;
diff --git a/libpurple/request/purplerequestfieldstring.c b/libpurple/request/purplerequestfieldstring.c
--- a/libpurple/request/purplerequestfieldstring.c
+++ b/libpurple/request/purplerequestfieldstring.c
@@ -24,6 +24,7 @@
 
 #include "purplerequestfield.h"
 #include "purplerequestfieldstring.h"
+#include "util.h"
 
 struct _PurpleRequestFieldString {
 	PurpleRequestField parent;
diff --git a/libpurple/util.c b/libpurple/util.c
--- a/libpurple/util.c
+++ b/libpurple/util.c
@@ -37,6 +37,7 @@
 #include "purplepath.h"
 #include "purpleprotocol.h"
 #include "purpleprotocolclient.h"
+#include "signals.h"
 #include "util.h"
 
 #ifdef _WIN32
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,8 +1,6 @@
 libpurple/accounts.c
 libpurple/action.c
 libpurple/blistnode.c
-libpurple/buddy.c
-libpurple/buddyicon.c
 libpurple/buddylist.c
 libpurple/circularbuffer.c
 libpurple/cmds.c
