# HG changeset patch
# Node ID 71d9a605550a
# Parent  226a7ec46dde
diff --git a/ChangeLog.API b/ChangeLog.API
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -248,6 +248,8 @@
 		  instead.
 		* account-setting-info, account-set-info signals
 		* account-status-changing signal.
+		* blist-node-aliased signal.
+		* blist-node-extended-menu signal.
 		* blocked-img-msg signal.
 		* buddy-caps-changed signal.
 		* buddy-got-login-time signal.
@@ -334,6 +336,7 @@
 		* purple_account_privacy_permit_remove
 		* purple_account_remove_buddy
 		* purple_account_remove_buddies
+		* purple_account_remove_group
 		* purple_account_remove_setting
 		* purple_account_request_add. Use purple_add_contact_request_new
 		  instead.
@@ -380,20 +383,50 @@
 		* purple_attention_type_get_unlocalized_name
 		* purple_base16_*
 		* purple_base64_*. Use g_base64_* instead
+		* PurpleBuddyList
 		* purple_blist_add_account
 		* purple_blist_add_buddy
 		* purple_blist_add_chat
+		* purple_blist_add_contact
+		* purple_blist_add_group
 		* purple_blist_find_chat
+		* purple_blist_get_buddies
+		* purple_blist_get_handle
+		* purple_blist_get_root
 		* purple_blist_get_ui_data
+		* purple_blist_init
 		* purple_blist_load
 		* purple_blist_new
+		* PurpleBlistNode
+		* purple_blist_node_get_bool
+		* purple_blist_node_get_extended_menu
+		* purple_blist_node_get_first_child
+		* purple_blist_node_get_int
+		* purple_blist_node_get_parent
+		* purple_blist_node_get_sibling_next
+		* purple_blist_node_get_sibling_prev
+		* purple_blist_node_get_string
+		* purple_blist_node_get_type
 		* purple_blist_node_get_ui_data
+		* purple_blist_node_next
+		* purple_blist_node_remove_setting
+		* purple_blist_node_set_bool
+		* purple_blist_node_set_int
+		* purple_blist_node_set_string
 		* purple_blist_node_set_ui_data
 		* purple_blist_remove_account
 		* purple_blist_remove_buddy
 		* purple_blist_remove_chat
+		* purple_blist_remove_contact
+		* purple_blist_remove_group
+		* purple_blist_request_add_buddy
 		* purple_blist_request_add_chat
+		* purple_blist_request_add_group
+		* purple_blist_schedule_save
 		* purple_blist_set_ui_data
+		* purple_blist_set_visible
+		* purple_blist_show
+		* purple_blist_uninit
 		* purple_set_blist
 		* purple_blist_update_buddy_icon
 		* purple_buddy_get_local_alias
@@ -492,6 +525,11 @@
 		* purple_get_attention_type_from_code
 		* purple_get_host_name. Use g_get_host_name, instead.
 		* purple_get_tzoff_str(). Use g_date_time_format, instead.
+		* PurpleGroup
+		* purple_group_get_accounts
+		* purple_group_get_name
+		* purple_group_new
+		* purple_group_on_account
 		* purple_home_dir
 		* PurpleIdleUiOps
 		* purple_idle_get_ui_ops
@@ -960,6 +998,8 @@
 		* struct PurpleAccountOption
 		* struct PurpleAccountUserSplit
 		* struct PurpleNotifySearchColumn
+		* ui-caps-changed signal
+		* update-idle signal
 		* wpurple_g_access
 		* writing-chat-msg signal
 		* writing-im-msg signal
diff --git a/doc/reference/libpurple/libpurple.toml.in b/doc/reference/libpurple/libpurple.toml.in
--- a/doc/reference/libpurple/libpurple.toml.in
+++ b/doc/reference/libpurple/libpurple.toml.in
@@ -41,7 +41,6 @@
 	"plugin_i18n.md",
 	"plugin_ids.md",
 	"signals_account.md",
-	"signals_blist.md",
 	"signals_cmd.md",
 	"signals_connection.md",
 	"signals_conversation.md",
diff --git a/doc/reference/libpurple/meson.build b/doc/reference/libpurple/meson.build
--- a/doc/reference/libpurple/meson.build
+++ b/doc/reference/libpurple/meson.build
@@ -3,7 +3,6 @@
 	'plugin_i18n.md',
 	'plugin_ids.md',
 	'signals_account.md',
-	'signals_blist.md',
 	'signals_cmd.md',
 	'signals_connection.md',
 	'signals_conversation.md',
diff --git a/doc/reference/libpurple/signals_blist.md b/doc/reference/libpurple/signals_blist.md
deleted file mode 100644
--- a/doc/reference/libpurple/signals_blist.md
+++ /dev/null
@@ -1,92 +0,0 @@
-Title: Buddy List Signals
-Slug: buddy-list-signals
-
-## Buddy List Signals
-
-### Signal List
-
-* [update-idle](#update-idle)
-* [blist-node-extended-menu](#blist-node-extended-menu)
-* [blist-node-aliased](#blist-node-aliased)
-* [ui-caps-changed](#ui-caps-changed)
-
-### Signal Details
-
-#### update-idle
-
-```c
-void user_function(gpointer user_data);
-```
-
-Emitted when the buddy list is refreshed and the idle times are updated.
-
-**Parameters:**
-
-**user_data**
-: user data set when the signal handler was connected.
-
-----
-
-#### blist-node-extended-menu
-
-```c
-void user_function(PurpleBlistNode *node, GList **menu, gpointer user_data);
-```
-
-Emitted when a buddylist menu is being constructed `menu` is a pointer to a
-GList of PurpleMenuAction's allowing a plugin to add menu items.
-
-----
-
-#### blist-node-added
-
-```c
-void user_function(PurpleBlistNode *node, gpointer user_data);
-```
-
-Emitted when a new blist node is added to the buddy list.
-
-----
-
-#### blist-node-removed
-
-```c
-void user_function(PurpleBlistNode *node, gpointer user_data);
-```
-
-Emitted when a blist node is removed from the buddy list.
-
-----
-
-#### blist-node-aliased
-
-```c
-void user_function(PurpleBlistNode *node,
-                   const gchar *old_alias,
-                   gpointer user_data);
-```
-
-Emitted when a blist node (buddy, chat, or contact) is aliased.
-
-----
-
-#### ui-caps-changed
-
-```c
-void user_function(PurpleMediaCaps newcaps,
-                   PurpleMediaCaps oldcaps,
-                   gpointer user_data);
-```
-
-Emitted when updating the media capabilities of the UI.
-
-**Parameters:**
-
-**newcaps**
-: .
-
-**oldcaps**
-: .
-
-**user_data**
-: user data set when the signal handler was connected.
diff --git a/libpurple/blistnode.h b/libpurple/blistnode.h
deleted file mode 100644
--- a/libpurple/blistnode.h
+++ /dev/null
@@ -1,336 +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_BLIST_NODE_H
-#define PURPLE_BLIST_NODE_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "purpleversion.h"
-
-#define PURPLE_TYPE_BLIST_NODE             (purple_blist_node_get_type())
-#define PURPLE_BLIST_NODE(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_BLIST_NODE, PurpleBlistNode))
-#define PURPLE_BLIST_NODE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_BLIST_NODE, PurpleBlistNodeClass))
-#define PURPLE_IS_BLIST_NODE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_BLIST_NODE))
-#define PURPLE_IS_BLIST_NODE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_BLIST_NODE))
-#define PURPLE_BLIST_NODE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_BLIST_NODE, PurpleBlistNodeClass))
-
-typedef struct _PurpleBlistNode PurpleBlistNode;
-typedef struct _PurpleBlistNodeClass PurpleBlistNodeClass;
-
-/**
- * PurpleBlistNode:
- * @prev:    The sibling before this buddy.
- * @next:    The sibling after this buddy.
- * @parent:  The parent of this node.
- * @child:   The child of this node.
- *
- * A Buddy list node.  This can represent a group, a buddy, or anything else.
- * This is a base class for PurpleBuddy, PurpleContact, PurpleGroup, and for
- * anything else that wants to put itself in the buddy list.
- *
- * Since: 2.0
- */
-struct _PurpleBlistNode {
-	GObject gparent;
-
-	/*< public >*/
-	PurpleBlistNode *prev;
-	PurpleBlistNode *next;
-	PurpleBlistNode *parent;
-	PurpleBlistNode *child;
-};
-
-struct _PurpleBlistNodeClass {
-	GObjectClass gparent_class;
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-/**
- * purple_blist_node_get_type:
- *
- * Returns: The #GType for the #PurpleBlistNode object.
- *
- * Since: 2.1
- */
-PURPLE_AVAILABLE_IN_2_1
-GType purple_blist_node_get_type(void);
-
-/**
- * purple_blist_node_next:
- * @node:		A node.
- * @offline:	Whether to include nodes for offline accounts
- *
- * Returns the next node of a given node. This function is to be used to iterate
- * over the tree returned by purple_blist_get_default.
- *
- * See purple_blist_node_get_parent(), purple_blist_node_get_first_child(),
- *   purple_blist_node_get_sibling_next(), purple_blist_node_get_sibling_prev().
- *
- * Returns: (transfer none): The next node
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleBlistNode *purple_blist_node_next(PurpleBlistNode *node, gboolean offline);
-
-/**
- * purple_blist_node_get_parent:
- * @node: A node.
- *
- * Returns the parent node of a given node.
- *
- * See purple_blist_node_get_first_child(), purple_blist_node_get_sibling_next(),
- *     purple_blist_node_get_sibling_prev(), purple_blist_node_next().
- *
- * Returns: (transfer none): The parent node.
- *
- * Since: 2.4
- */
-PURPLE_AVAILABLE_IN_2_4
-PurpleBlistNode *purple_blist_node_get_parent(PurpleBlistNode *node);
-
-/**
- * purple_blist_node_get_first_child:
- * @node: A node.
- *
- * Returns the the first child node of a given node.
- *
- * See purple_blist_node_get_parent(), purple_blist_node_get_sibling_next(),
- *     purple_blist_node_get_sibling_prev(), purple_blist_node_next().
- *
- * Returns: (transfer none): The child node.
- *
- * Since: 2.4
- */
-PURPLE_AVAILABLE_IN_2_4
-PurpleBlistNode *purple_blist_node_get_first_child(PurpleBlistNode *node);
-
-/**
- * purple_blist_node_get_sibling_next:
- * @node: A node.
- *
- * Returns the sibling node of a given node.
- *
- * See purple_blist_node_get_parent(), purple_blist_node_get_first_child(),
- *     purple_blist_node_get_sibling_prev(), purple_blist_node_next().
- *
- * Returns: (transfer none): The sibling node.
- *
- * Since: 2.4
- */
-PURPLE_AVAILABLE_IN_2_4
-PurpleBlistNode *purple_blist_node_get_sibling_next(PurpleBlistNode *node);
-
-/**
- * purple_blist_node_get_sibling_prev:
- * @node: A node.
- *
- * Returns the previous sibling node of a given node.
- *
- * See purple_blist_node_get_parent(), purple_blist_node_get_first_child(),
- *     purple_blist_node_get_sibling_next(), purple_blist_node_next().
- *
- * Returns: (transfer none): The sibling node.
- *
- * Since: 2.4
- */
-PURPLE_AVAILABLE_IN_2_4
-PurpleBlistNode *purple_blist_node_get_sibling_prev(PurpleBlistNode *node);
-
-/**
- * purple_blist_node_get_settings:
- * @node:  The node to from which to get settings
- *
- * Returns a node's settings
- *
- * Returns: (transfer none): The hash table with the node's settings.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GHashTable *purple_blist_node_get_settings(PurpleBlistNode *node);
-
-/**
- * purple_blist_node_has_setting:
- * @node:  The node to check from which to check settings
- * @key:   The identifier of the data
- *
- * Checks whether a named setting exists for a node in the buddy list
- *
- * Returns: TRUE if a value exists, or FALSE if there is no setting
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gboolean purple_blist_node_has_setting(PurpleBlistNode *node, const char *key);
-
-/**
- * purple_blist_node_set_bool:
- * @node:  The node to associate the data with
- * @key:   The identifier for the data
- * @value: The value to set
- *
- * Associates a boolean with a node in the buddy list
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_node_set_bool(PurpleBlistNode *node, const char *key, gboolean value);
-
-/**
- * purple_blist_node_get_bool:
- * @node:  The node to retrieve the data from
- * @key:   The identifier of the data
- *
- * Retrieves a named boolean setting from a node in the buddy list
- *
- * Returns: The value, or FALSE if there is no setting
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-gboolean purple_blist_node_get_bool(PurpleBlistNode *node, const char *key);
-
-/**
- * purple_blist_node_set_int:
- * @node:  The node to associate the data with
- * @key:   The identifier for the data
- * @value: The value to set
- *
- * Associates an integer with a node in the buddy list
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_node_set_int(PurpleBlistNode *node, const char *key, int value);
-
-/**
- * purple_blist_node_get_int:
- * @node:  The node to retrieve the data from
- * @key:   The identifier of the data
- *
- * Retrieves a named integer setting from a node in the buddy list
- *
- * Returns: The value, or 0 if there is no setting
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-int purple_blist_node_get_int(PurpleBlistNode *node, const char *key);
-
-/**
- * purple_blist_node_set_string:
- * @node:  The node to associate the data with
- * @key:   The identifier for the data
- * @value: The value to set
- *
- * Associates a string with a node in the buddy list
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_node_set_string(PurpleBlistNode *node, const char *key, const char *value);
-
-/**
- * purple_blist_node_get_string:
- * @node:  The node to retrieve the data from
- * @key:   The identifier of the data
- *
- * Retrieves a named string setting from a node in the buddy list
- *
- * Returns: The value, or NULL if there is no setting
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_blist_node_get_string(PurpleBlistNode *node, const char *key);
-
-/**
- * purple_blist_node_remove_setting:
- * @node:  The node from which to remove the setting
- * @key:   The name of the setting
- *
- * Removes a named setting from a blist node
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_node_remove_setting(PurpleBlistNode *node, const char *key);
-
-/**
- * purple_blist_node_set_transient:
- * @node:  The node
- * @transient: TRUE if the node should NOT be saved, FALSE if node should
- *                  be saved
- *
- * Sets whether the node should be saved with the buddy list or not
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_node_set_transient(PurpleBlistNode *node, gboolean transient);
-
-/**
- * purple_blist_node_is_transient:
- * @node:  The node
- *
- * Gets whether the node should be saved with the buddy list or not
- *
- * Returns: TRUE if the node should NOT be saved, FALSE if node should be saved
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gboolean purple_blist_node_is_transient(PurpleBlistNode *node);
-
-/**
- * purple_blist_node_get_extended_menu:
- * @n: The blist node for which to obtain the extended menu items.
- *
- * Emits the blist-node-extended-menu signal and returns the results.
- *
- * Returns: (element-type PurpleActionMenu) (transfer full): The extended menu
- *          items for a buddy list node, as harvested by the
- *          blist-node-extended-menu signal.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-GList *purple_blist_node_get_extended_menu(PurpleBlistNode *n);
-
-G_END_DECLS
-
-#endif /* PURPLE_BLIST_NODE_H */
-
diff --git a/libpurple/blistnode.c b/libpurple/blistnode.c
deleted file mode 100644
--- a/libpurple/blistnode.c
+++ /dev/null
@@ -1,370 +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 "blistnode.h"
-
-#include "buddylist.h"
-#include "signals.h"
-#include "util.h"
-
-typedef struct _PurpleBlistNodePrivate  PurpleBlistNodePrivate;
-
-/* Private data of a buddy list node */
-struct _PurpleBlistNodePrivate {
-	GHashTable *settings;  /* per-node settings                            */
-	gboolean transient;    /* node should not be saved with the buddy list */
-};
-
-/* Blist node property enums */
-enum
-{
-	PROP_0,
-	PROP_TRANSIENT,
-	N_PROPERTIES,
-};
-
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
-G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(PurpleBlistNode, purple_blist_node,
-		G_TYPE_OBJECT);
-
-/**************************************************************************/
-/* Buddy list node API                                                    */
-/**************************************************************************/
-
-PurpleBlistNode *
-purple_blist_node_next(G_GNUC_UNUSED PurpleBlistNode *node,
-                       G_GNUC_UNUSED gboolean offline)
-{
-	return NULL;
-}
-
-PurpleBlistNode *purple_blist_node_get_parent(PurpleBlistNode *node)
-{
-	return node ? node->parent : NULL;
-}
-
-PurpleBlistNode *purple_blist_node_get_first_child(PurpleBlistNode *node)
-{
-	return node ? node->child : NULL;
-}
-
-PurpleBlistNode *purple_blist_node_get_sibling_next(PurpleBlistNode *node)
-{
-	return node? node->next : NULL;
-}
-
-PurpleBlistNode *purple_blist_node_get_sibling_prev(PurpleBlistNode *node)
-{
-	return node? node->prev : NULL;
-}
-
-void purple_blist_node_remove_setting(PurpleBlistNode *node, const char *key)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_BLIST_NODE(node));
-	g_return_if_fail(key != NULL);
-
-	priv = purple_blist_node_get_instance_private(node);
-	g_return_if_fail(priv->settings != NULL);
-
-	g_hash_table_remove(priv->settings, key);
-
-	purple_blist_save_node(purple_blist_get_default(), node);
-}
-
-void
-purple_blist_node_set_transient(PurpleBlistNode *node, gboolean transient)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_BLIST_NODE(node));
-
-	priv = purple_blist_node_get_instance_private(node);
-	priv->transient = transient;
-
-	g_object_notify_by_pspec(G_OBJECT(node), properties[PROP_TRANSIENT]);
-}
-
-gboolean
-purple_blist_node_is_transient(PurpleBlistNode *node)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BLIST_NODE(node), 0);
-
-	priv = purple_blist_node_get_instance_private(node);
-	return priv->transient;
-}
-
-GHashTable *
-purple_blist_node_get_settings(PurpleBlistNode *node)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BLIST_NODE(node), NULL);
-
-	priv = purple_blist_node_get_instance_private(node);
-	return priv->settings;
-}
-
-gboolean
-purple_blist_node_has_setting(PurpleBlistNode* node, const char *key)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BLIST_NODE(node), FALSE);
-	g_return_val_if_fail(key != NULL, FALSE);
-
-	priv = purple_blist_node_get_instance_private(node);
-	g_return_val_if_fail(priv->settings != NULL, FALSE);
-
-	/* Boxed type, so it won't ever be NULL, so no need for _extended */
-	return (g_hash_table_lookup(priv->settings, key) != NULL);
-}
-
-void
-purple_blist_node_set_bool(PurpleBlistNode* node, const char *key, gboolean data)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-	GValue *value;
-
-	g_return_if_fail(PURPLE_IS_BLIST_NODE(node));
-	g_return_if_fail(key != NULL);
-
-	priv = purple_blist_node_get_instance_private(node);
-	g_return_if_fail(priv->settings != NULL);
-
-	value = purple_value_new(G_TYPE_BOOLEAN);
-	g_value_set_boolean(value, data);
-
-	g_hash_table_replace(priv->settings, g_strdup(key), value);
-
-	purple_blist_save_node(purple_blist_get_default(), node);
-}
-
-gboolean
-purple_blist_node_get_bool(PurpleBlistNode* node, const char *key)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-	GValue *value;
-
-	g_return_val_if_fail(PURPLE_IS_BLIST_NODE(node), FALSE);
-	g_return_val_if_fail(key != NULL, FALSE);
-
-	priv = purple_blist_node_get_instance_private(node);
-	g_return_val_if_fail(priv->settings != NULL, FALSE);
-
-	value = g_hash_table_lookup(priv->settings, key);
-
-	if (value == NULL)
-		return FALSE;
-
-	g_return_val_if_fail(G_VALUE_HOLDS_BOOLEAN(value), FALSE);
-
-	return g_value_get_boolean(value);
-}
-
-void
-purple_blist_node_set_int(PurpleBlistNode* node, const char *key, int data)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-	GValue *value;
-
-	g_return_if_fail(PURPLE_IS_BLIST_NODE(node));
-	g_return_if_fail(key != NULL);
-
-	priv = purple_blist_node_get_instance_private(node);
-	g_return_if_fail(priv->settings != NULL);
-
-	value = purple_value_new(G_TYPE_INT);
-	g_value_set_int(value, data);
-
-	g_hash_table_replace(priv->settings, g_strdup(key), value);
-
-	purple_blist_save_node(purple_blist_get_default(), node);
-}
-
-int
-purple_blist_node_get_int(PurpleBlistNode* node, const char *key)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-	GValue *value;
-
-	g_return_val_if_fail(PURPLE_IS_BLIST_NODE(node), 0);
-	g_return_val_if_fail(key != NULL, 0);
-
-	priv = purple_blist_node_get_instance_private(node);
-	g_return_val_if_fail(priv->settings != NULL, 0);
-
-	value = g_hash_table_lookup(priv->settings, key);
-
-	if (value == NULL)
-		return 0;
-
-	g_return_val_if_fail(G_VALUE_HOLDS_INT(value), 0);
-
-	return g_value_get_int(value);
-}
-
-void
-purple_blist_node_set_string(PurpleBlistNode* node, const char *key, const char *data)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-	GValue *value;
-
-	g_return_if_fail(PURPLE_IS_BLIST_NODE(node));
-	g_return_if_fail(key != NULL);
-
-	priv = purple_blist_node_get_instance_private(node);
-	g_return_if_fail(priv->settings != NULL);
-
-	value = purple_value_new(G_TYPE_STRING);
-	g_value_set_string(value, data);
-
-	g_hash_table_replace(priv->settings, g_strdup(key), value);
-
-	purple_blist_save_node(purple_blist_get_default(), node);
-}
-
-const char *
-purple_blist_node_get_string(PurpleBlistNode* node, const char *key)
-{
-	PurpleBlistNodePrivate *priv = NULL;
-	GValue *value;
-
-	g_return_val_if_fail(PURPLE_IS_BLIST_NODE(node), NULL);
-	g_return_val_if_fail(key != NULL, NULL);
-
-	priv = purple_blist_node_get_instance_private(node);
-	g_return_val_if_fail(priv->settings != NULL, NULL);
-
-	value = g_hash_table_lookup(priv->settings, key);
-
-	if (value == NULL)
-		return NULL;
-
-	g_return_val_if_fail(G_VALUE_HOLDS_STRING(value), NULL);
-
-	return g_value_get_string(value);
-}
-
-GList *
-purple_blist_node_get_extended_menu(PurpleBlistNode *n)
-{
-	GList *menu = NULL;
-
-	g_return_val_if_fail(n != NULL, NULL);
-
-	purple_signal_emit(purple_blist_get_handle(), "blist-node-extended-menu",
-			n, &menu);
-	return menu;
-}
-
-/**************************************************************************
- * GObject code for PurpleBlistNode
- **************************************************************************/
-
-/* Set method for GObject properties */
-static void
-purple_blist_node_set_property(GObject *obj, guint param_id, const GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleBlistNode *node = PURPLE_BLIST_NODE(obj);
-
-	switch (param_id) {
-		case PROP_TRANSIENT:
-			purple_blist_node_set_transient(node, g_value_get_boolean(value));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-/* Get method for GObject properties */
-static void
-purple_blist_node_get_property(GObject *obj, guint param_id, GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleBlistNode *node = PURPLE_BLIST_NODE(obj);
-
-	switch (param_id) {
-		case PROP_TRANSIENT:
-			g_value_set_boolean(value, purple_blist_node_is_transient(node));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-/* GObject initialization function */
-static void
-purple_blist_node_init(PurpleBlistNode *node)
-{
-	PurpleBlistNodePrivate *priv =
-			purple_blist_node_get_instance_private(node);
-
-	priv->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
-			(GDestroyNotify)purple_value_free);
-}
-
-/* GObject finalize function */
-static void
-purple_blist_node_finalize(GObject *object)
-{
-	PurpleBlistNodePrivate *priv = purple_blist_node_get_instance_private(
-			PURPLE_BLIST_NODE(object));
-
-	g_hash_table_destroy(priv->settings);
-
-	G_OBJECT_CLASS(purple_blist_node_parent_class)->finalize(object);
-}
-
-/* Class initializer function */
-static void
-purple_blist_node_class_init(PurpleBlistNodeClass *klass)
-{
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
-	obj_class->finalize = purple_blist_node_finalize;
-
-	/* Setup properties */
-	obj_class->get_property = purple_blist_node_get_property;
-	obj_class->set_property = purple_blist_node_set_property;
-
-	/**
-	 * PurpleBlistNode:transient:
-	 *
-	 * If %TRUE the node will not be saved to the contact list.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_TRANSIENT] = g_param_spec_boolean("transient",
-				"Transient",
-				"Whether node should not be saved with the buddy list.",
-				FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
-}
diff --git a/libpurple/buddylist.h b/libpurple/buddylist.h
deleted file mode 100644
--- a/libpurple/buddylist.h
+++ /dev/null
@@ -1,543 +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_LIST_H
-#define PURPLE_BUDDY_LIST_H
-
-/* I can't believe I let ChipX86 inspire me to write good code. -Sean */
-
-#include "purpleaccount.h"
-#include "purpleversion.h"
-
-#define PURPLE_TYPE_BUDDY_LIST (purple_buddy_list_get_type())
-typedef struct _PurpleBuddyList PurpleBuddyList;
-
-/**
- * PURPLE_BLIST_DEFAULT_GROUP_NAME:
- *
- * A helper to get the default group name for the buddy list.
- */
-#define PURPLE_BLIST_DEFAULT_GROUP_NAME (purple_blist_get_default_group_name())
-
-#include "contact.h"
-
-/**
- * _purple_blist_get_localized_default_group_name:
- *
- * Returns the name of default group for previously used non-English
- * localization. It's used for merging default group, in cases when roster
- * contains localized name.
- *
- * Please note, prpls shouldn't save default group name depending on current
- * locale. So, this function is mostly for libpurple2 compatibility. And for
- * improperly written prpls.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-const gchar *
-_purple_blist_get_localized_default_group_name(void);
-
-/**
- * PurpleBlistWalkFunc:
- * @node: The node that's being iterated
- * @data: User supplied data.
- *
- * A callback function for purple_blist_walk.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_TYPE_IN_3_0
-typedef void (*PurpleBlistWalkFunc)(PurpleBlistNode *node, gpointer data);
-
-/**************************************************************************/
-/* Data Structures                                                        */
-/**************************************************************************/
-/**
- * PurpleBuddyList:
- *
- * The Buddy List
- *
- * Since: 2.0
- */
-/**
- * PurpleBuddyListClass:
- * @new_node:     Sets UI-specific data on a node.
- * @show:         The core will call this when it's finished doing its core
- *                stuff.
- * @update:       This will update a node in the buddy list.
- * @remove:       This removes a node from the list
- * @set_visible:  Hides or unhides the buddy list.
- * @request_add_buddy: Called when information is needed to add a buddy to the
- *                     buddy list. See purple_blist_request_add_buddy().
- * @request_add_group: Called when information is needed to add a group to the
- *                     buddy list. See purple_blist_request_add_group().
- * @save_node:    This is called when a node has been modified and should be
- *                saved.
- *                <sbr/>Implementation of this method is
- *                <emphasis>OPTIONAL</emphasis>. If not implemented, it will be
- *                set to a fallback function that saves data to
- *                <filename>blist.xml</filename> like in previous libpurple
- *                versions.
- *                <sbr/>@node: The node which has been modified.
- * @remove_node:  Called when a node is about to be removed from the buddy list.
- *                The method should update the relevant data structures to
- *                remove this node (for example, removing a buddy from the
- *                group this node is in).
- *                <sbr/>Implementation of this method is
- *                <emphasis>OPTIONAL</emphasis>. If not implemented, it will be
- *                set to a fallback function that saves data to
- *                <filename>blist.xml</filename> like in previous libpurple
- *                versions.
- *                <sbr/>@node: The node which has been modified.
- * @save_account: Called to save all the data for an account. If the UI sets
- *                this, the callback must save the privacy and buddy list data
- *                for an account. If the account is %NULL, save the data for all
- *                accounts.
- *                <sbr/>Implementation of this method is
- *                <emphasis>OPTIONAL</emphasis>. If not implemented, it will be
- *                set to a fallback function that saves data to
- *                <filename>blist.xml</filename> like in previous
- *                libpurple versions.
- *                <sbr/>@account: The account whose data to save. If %NULL,
- *                                save all data for all accounts.
- *
- * Buddy list operations.
- *
- * Any UI representing a buddy list must derive a filled-out
- * @PurpleBuddyListClass and set the GType using purple_blist_set_ui() before a
- * buddy list is created.
- */
-struct _PurpleBuddyListClass {
-	/*< private >*/
-	GObjectClass gparent_class;
-
-	/*< public >*/
-	void (*new_node)(PurpleBuddyList *list, PurpleBlistNode *node);
-	void (*show)(PurpleBuddyList *list);
-	void (*update)(PurpleBuddyList *list, PurpleBlistNode *node);
-	void (*remove)(PurpleBuddyList *list, PurpleBlistNode *node);
-	void (*set_visible)(PurpleBuddyList *list, gboolean show);
-
-	void (*request_add_buddy)(PurpleBuddyList *list, PurpleAccount *account,
-	                          const char *username, const char *group,
-	                          const char *alias);
-
-	void (*request_add_group)(PurpleBuddyList *list);
-
-	void (*save_node)(PurpleBuddyList *list, PurpleBlistNode *node);
-	void (*remove_node)(PurpleBuddyList *list, PurpleBlistNode *node);
-
-	void (*save_account)(PurpleBuddyList *list, PurpleAccount *account);
-
-	/*< private >*/
-	gpointer reserved[4];
-};
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* Buddy List API                                                         */
-/**************************************************************************/
-
-/**
- * purple_buddy_list_get_type:
- *
- * Returns: The #GType for the #PurpleBuddyList object.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-G_DECLARE_DERIVABLE_TYPE(PurpleBuddyList, purple_buddy_list, PURPLE, BUDDY_LIST,
-                         GObject)
-
-/**
- * purple_blist_get_default:
- *
- * Returns the default buddy list.
- *
- * Returns: (transfer none): The default buddy list.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleBuddyList *purple_blist_get_default(void);
-
-/**
- * purple_blist_get_default_root:
- *
- * Returns the root node of the default buddy list.
- *
- * Returns: (transfer none): The root node.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleBlistNode *purple_blist_get_default_root(void);
-
-/**
- * purple_blist_get_root:
- * @list: The buddy list to query.
- *
- * Returns the root node of the specified buddy list.
- *
- * Returns: (transfer none): The root node.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleBlistNode *purple_blist_get_root(PurpleBuddyList *list);
-
-/**
- * purple_blist_get_buddies:
- *
- * Returns a list of every buddy in the list.  Use of this function is
- * discouraged if you do not actually need every buddy in the list.  Use
- * purple_blist_find_buddies instead.
- *
- * See purple_blist_find_buddies().
- *
- * Returns: (element-type PurpleBlistNode) (transfer container): A list of every
- *          buddy in the list.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-GSList *purple_blist_get_buddies(void);
-
-/**
- * purple_blist_show:
- *
- * Shows the buddy list, creating a new one if necessary.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_show(void);
-
-/**
- * purple_blist_set_visible:
- * @show:   Whether or not to show the buddy list
- *
- * Hides or unhides the buddy list.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_set_visible(gboolean show);
-
-/**
- * purple_blist_update_groups_cache:
- * @group:    The group whose name will be changed.
- * @new_name: The new name of the group.
- *
- * Updates the groups hash table when a group has been renamed. This only
- * updates the cache, the caller is responsible for the actual renaming of
- * the group after updating the cache.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_update_groups_cache(PurpleGroup *group, const char *new_name);
-
-/**
- * purple_blist_add_group:
- * @group:  The group
- * @node:   The insertion point
- *
- * Adds a new group to the buddy list.
- *
- * The new group will be inserted after insert or prepended to the list if
- * node is NULL.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_add_group(PurpleGroup *group, PurpleBlistNode *node);
-
-/**
- * purple_blist_add_contact:
- * @contact: The contact
- * @group:   The group to add the contact to
- * @node:    The insertion point
- *
- * Adds a new contact to the buddy list.
- *
- * The new contact will be inserted after insert or prepended to the list if
- * node is NULL.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_add_contact(PurpleMetaContact *contact, PurpleGroup *group, PurpleBlistNode *node);
-
-/**
- * purple_blist_remove_contact:
- * @contact: The contact to be removed
- *
- * Removes a contact, and any buddies it contains, and frees the memory
- * allocated to it. This calls purple_blist_remove_buddy and therefore
- * doesn't remove the buddies from the server list.
- *
- * See purple_blist_remove_buddy().
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_remove_contact(PurpleMetaContact *contact);
-
-/**
- * purple_blist_remove_group:
- * @group:   The group to be removed
- *
- * Removes a group from the buddy list and frees the memory allocated to it and to
- * its children
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_remove_group(PurpleGroup *group);
-
-/**
- * purple_blist_find_group:
- * @name:    The group's name
- *
- * Finds a group by name
- *
- * Returns: (transfer none): The group or %NULL if the group does not exist.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleGroup *purple_blist_find_group(const char *name);
-
-/**
- * purple_blist_get_default_group:
- *
- * Finds or creates default group.
- *
- * Returns: (transfer none): The default group.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleGroup *purple_blist_get_default_group(void);
-
-/**
- * purple_blist_walk:
- * @group_func: (scope call): The callback for groups
- * @meta_contact_func: (scope call): The callback for meta-contacts
- * @contact_func: (scope call): The callback for contacts
- * @data: User supplied data.
- *
- * Walks the buddy list and calls the appropriate function for each node.  If
- * a callback function is omitted iteration will continue without it.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_walk(PurpleBlistWalkFunc group_func, PurpleBlistWalkFunc meta_contact_func, PurpleBlistWalkFunc contact_func, gpointer data);
-
-/**
- * purple_blist_get_default_group_name:
- *
- * Gets the default group name for the buddy list.
- *
- * Returns: The name of the default group.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-const gchar *purple_blist_get_default_group_name(void);
-
-/****************************************************************************************/
-/* Buddy list file management API                                                       */
-/****************************************************************************************/
-
-/**
- * purple_blist_schedule_save:
- *
- * Schedule a save of the <filename>blist.xml</filename> file.  This is used by
- * the account API whenever the privacy settings are changed.  If you make a
- * change to <filename>blist.xml</filename> using one of the functions in the
- * buddy list API, then the buddy list is saved automatically, so you should not
- * need to call this.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_schedule_save(void);
-
-/**
- * purple_blist_request_add_buddy:
- * @account:  The account the buddy is added to.
- * @username: The username of the buddy.
- * @group:    The name of the group to place the buddy in.
- * @alias:    The optional alias for the buddy.
- *
- * Requests from the user information needed to add a buddy to the
- * buddy list.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_request_add_buddy(PurpleAccount *account, const char *username,
-								  const char *group, const char *alias);
-
-/**
- * purple_blist_request_add_group:
- *
- * Requests from the user information needed to add a group to the
- * buddy list.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_request_add_group(void);
-
-/**
- * purple_blist_new_node:
- * @list: The list that contains the node.
- * @node: The node to initialize.
- *
- * Sets UI-specific data on a node.
- *
- * This should usually only be run when initializing a @PurpleBlistNode
- * instance.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_new_node(PurpleBuddyList *list, PurpleBlistNode *node);
-
-/**
- * purple_blist_update_node:
- * @list: The buddy list to modify.
- * @node: The node to update.
- *
- * Update a node in the buddy list in the UI.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_update_node(PurpleBuddyList *list, PurpleBlistNode *node);
-
-/**
- * purple_blist_save_node:
- * @list: The list that contains the node.
- * @node: The node which has been modified.
- *
- * This is called when a node has been modified and should be saved by the UI.
- *
- * If the UI does not implement a more specific method, it will be set to save
- * data to <filename>blist.xml</filename> like in previous libpurple versions.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_save_node(PurpleBuddyList *list, PurpleBlistNode *node);
-
-/**
- * purple_blist_save_account:
- * @list: The list that contains the account.
- * @account: The account whose data to save. If %NULL, save all data for all
- *           accounts.
- *
- * Save all the data for an account.
- *
- * If the UI does not set a more specific method, it will be set to save data
- * to <filename>blist.xml</filename> like in previous libpurple versions.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_save_account(PurpleBuddyList *list, PurpleAccount *account);
-
-/**************************************************************************/
-/* Buddy List Subsystem                                                   */
-/**************************************************************************/
-
-/**
- * purple_blist_set_ui:
- * @type: The @GType of a derived UI implementation of @PurpleBuddyList.
- *
- * Set the UI implementation of the buddy list.
- *
- * This must be called before the buddy list is created or you will get the
- * default libpurple implementation.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_set_ui(GType type);
-
-/**
- * purple_blist_get_handle:
- *
- * Returns the handle for the buddy list subsystem.
- *
- * Returns: The buddy list subsystem handle.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void *purple_blist_get_handle(void);
-
-/**
- * purple_blist_init:
- *
- * Initializes the buddy list subsystem.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_init(void);
-
-/**
- * purple_blist_boot:
- *
- * Loads the buddy list.
- *
- * You shouldn't call this. purple_core_init() will do it for you.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_blist_boot(void);
-
-/**
- * purple_blist_uninit:
- *
- * Uninitializes the buddy list subsystem.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_blist_uninit(void);
-
-G_END_DECLS
-
-#endif /* PURPLE_BUDDY_LIST_H */
diff --git a/libpurple/buddylist.c b/libpurple/buddylist.c
deleted file mode 100644
--- a/libpurple/buddylist.c
+++ /dev/null
@@ -1,1171 +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 <glib/gi18n-lib.h>
-
-#include "buddylist.h"
-#include "debug.h"
-#include "notify.h"
-#include "prefs.h"
-#include "purpleaccount.h"
-#include "purpleaccountmanager.h"
-#include "purpleprivate.h"
-#include "purpleprotocol.h"
-#include "purpleprotocolclient.h"
-#include "purpleconversation.h"
-#include "signals.h"
-#include "util.h"
-#include "xmlnode.h"
-
-/* Private data for a buddy list. */
-typedef struct  {
-	PurpleBlistNode *root;
-	GHashTable *buddies;  /* Every buddy in this list */
-} PurpleBuddyListPrivate;
-
-static GType buddy_list_type = G_TYPE_INVALID;
-static PurpleBuddyList *purplebuddylist = NULL;
-
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleBuddyList, purple_buddy_list, G_TYPE_OBJECT);
-
-/*
- * A hash table used for efficient lookups of buddies by name.
- * PurpleAccount* => GHashTable*, with the inner hash table being
- * struct _purple_hbuddy => PurpleBuddy*
- */
-static GHashTable *buddies_cache = NULL;
-
-/*
- * A hash table used for efficient lookups of groups by name.
- * UTF-8 collate-key => PurpleGroup*.
- */
-static GHashTable *groups_cache = NULL;
-
-static guint          save_timer = 0;
-static gboolean       blist_loaded = FALSE;
-static gchar *localized_default_group_name = NULL;
-
-/*********************************************************************
- * Private utility functions                                         *
- *********************************************************************/
-
-static gchar *
-purple_blist_fold_name(const gchar *name)
-{
-	gchar *res, *tmp;
-
-	if (name == NULL)
-		return NULL;
-
-	tmp = g_utf8_casefold(name, -1);
-	res = g_utf8_collate_key(tmp, -1);
-	g_free(tmp);
-
-	return res;
-}
-
-static PurpleBlistNode *purple_blist_get_last_sibling(PurpleBlistNode *node)
-{
-	PurpleBlistNode *n = node;
-	if (!n)
-		return NULL;
-	while (n->next)
-		n = n->next;
-	return n;
-}
-
-PurpleBlistNode *_purple_blist_get_last_child(PurpleBlistNode *node)
-{
-	if (!node)
-		return NULL;
-	return purple_blist_get_last_sibling(node->child);
-}
-
-struct _list_account_buddies {
-	GSList *list;
-	PurpleAccount *account;
-};
-
-struct _purple_hbuddy {
-	char *name;
-	PurpleAccount *account;
-	PurpleBlistNode *group;
-};
-
-/* This function must not use purple_normalize */
-static guint _purple_blist_hbuddy_hash(struct _purple_hbuddy *hb)
-{
-	return g_str_hash(hb->name) ^ g_direct_hash(hb->group) ^ g_direct_hash(hb->account);
-}
-
-/* This function must not use purple_normalize */
-static guint _purple_blist_hbuddy_equal(struct _purple_hbuddy *hb1, struct _purple_hbuddy *hb2)
-{
-	return (hb1->group == hb2->group &&
-	        hb1->account == hb2->account &&
-	        purple_strequal(hb1->name, hb2->name));
-}
-
-static void _purple_blist_hbuddy_free_key(struct _purple_hbuddy *hb)
-{
-	g_free(hb->name);
-	g_free(hb);
-}
-
-static void
-purple_blist_buddies_cache_add_account(PurpleAccount *account)
-{
-	GHashTable *account_buddies = g_hash_table_new_full((GHashFunc)_purple_blist_hbuddy_hash,
-						(GEqualFunc)_purple_blist_hbuddy_equal,
-						(GDestroyNotify)_purple_blist_hbuddy_free_key, NULL);
-	g_hash_table_insert(buddies_cache, account, account_buddies);
-}
-
-static void
-purple_buddy_list_account_added_cb(G_GNUC_UNUSED PurpleAccountManager *manager,
-                                   PurpleAccount *account,
-                                   G_GNUC_UNUSED gpointer data)
-{
-	purple_blist_buddies_cache_add_account(account);
-}
-
-static void
-purple_blist_buddies_cache_remove_account(const PurpleAccount *account)
-{
-	g_hash_table_remove(buddies_cache, account);
-}
-
-static void
-purple_buddy_list_account_removed_cb(G_GNUC_UNUSED PurpleAccountManager *manager,
-                                     PurpleAccount *account,
-                                     G_GNUC_UNUSED gpointer data)
-{
-	purple_blist_buddies_cache_remove_account(account);
-}
-
-/*********************************************************************
- * Writing to disk                                                   *
- *********************************************************************/
-
-static void
-value_to_xmlnode(gpointer key, gpointer hvalue, gpointer user_data)
-{
-	const char *name;
-	GValue *value;
-	PurpleXmlNode *node, *child;
-	char buf[21];
-
-	name    = (const char *)key;
-	value   = (GValue *)hvalue;
-	node    = (PurpleXmlNode *)user_data;
-
-	g_return_if_fail(value != NULL);
-
-	child = purple_xmlnode_new_child(node, "setting");
-	purple_xmlnode_set_attrib(child, "name", name);
-
-	if (G_VALUE_HOLDS_INT(value)) {
-		purple_xmlnode_set_attrib(child, "type", "int");
-		g_snprintf(buf, sizeof(buf), "%d", g_value_get_int(value));
-		purple_xmlnode_insert_data(child, buf, -1);
-	}
-	else if (G_VALUE_HOLDS_STRING(value)) {
-		purple_xmlnode_set_attrib(child, "type", "string");
-		purple_xmlnode_insert_data(child, g_value_get_string(value), -1);
-	}
-	else if (G_VALUE_HOLDS_BOOLEAN(value)) {
-		purple_xmlnode_set_attrib(child, "type", "bool");
-		g_snprintf(buf, sizeof(buf), "%d", g_value_get_boolean(value));
-		purple_xmlnode_insert_data(child, buf, -1);
-	}
-}
-
-static PurpleXmlNode *
-contact_to_xmlnode(PurpleMetaContact *contact)
-{
-	PurpleXmlNode *node;
-	gchar *alias;
-
-	node = purple_xmlnode_new("contact");
-	g_object_get(contact, "alias", &alias, NULL);
-
-	if (alias != NULL)
-	{
-		purple_xmlnode_set_attrib(node, "alias", alias);
-	}
-
-	/* Write contact settings */
-	g_hash_table_foreach(purple_blist_node_get_settings(PURPLE_BLIST_NODE(contact)),
-			value_to_xmlnode, node);
-
-	g_free(alias);
-	return node;
-}
-
-static PurpleXmlNode *
-group_to_xmlnode(PurpleGroup *group)
-{
-	PurpleXmlNode *node, *child;
-	PurpleBlistNode *cnode;
-
-	node = purple_xmlnode_new("group");
-	if (group != purple_blist_get_default_group())
-		purple_xmlnode_set_attrib(node, "name", purple_group_get_name(group));
-
-	/* Write settings */
-	g_hash_table_foreach(purple_blist_node_get_settings(PURPLE_BLIST_NODE(group)),
-			value_to_xmlnode, node);
-
-	/* Write contacts and chats */
-	for (cnode = PURPLE_BLIST_NODE(group)->child; cnode != NULL; cnode = cnode->next)
-	{
-		if (purple_blist_node_is_transient(cnode))
-			continue;
-		if (PURPLE_IS_META_CONTACT(cnode))
-		{
-			child = contact_to_xmlnode(PURPLE_META_CONTACT(cnode));
-			purple_xmlnode_insert_child(node, child);
-		}
-	}
-
-	return node;
-}
-
-static PurpleXmlNode *
-blist_to_xmlnode(void) {
-	PurpleXmlNode *node, *child, *grandchild;
-	PurpleBlistNode *gnode;
-	const gchar *localized_default;
-
-	node = purple_xmlnode_new("purple");
-	purple_xmlnode_set_attrib(node, "version", "1.0");
-
-	/* Write groups */
-	child = purple_xmlnode_new_child(node, "blist");
-
-	localized_default = localized_default_group_name;
-	if (!purple_strequal(_("Buddies"), "Buddies"))
-		localized_default = _("Buddies");
-	if (localized_default != NULL) {
-		purple_xmlnode_set_attrib(child,
-			"localized-default-group", localized_default);
-	}
-
-	for (gnode = purple_blist_get_default_root(); gnode != NULL;
-	     gnode = gnode->next) {
-		if (purple_blist_node_is_transient(gnode))
-			continue;
-		if (PURPLE_IS_GROUP(gnode))
-		{
-			grandchild = group_to_xmlnode(PURPLE_GROUP(gnode));
-			purple_xmlnode_insert_child(child, grandchild);
-		}
-	}
-
-	return node;
-}
-
-static void
-purple_blist_sync(void)
-{
-	PurpleXmlNode *node;
-	char *data;
-
-	if (!blist_loaded)
-	{
-		purple_debug_error("buddylist", "Attempted to save buddy list before it "
-						 "was read!\n");
-		return;
-	}
-
-	node = blist_to_xmlnode();
-	data = purple_xmlnode_to_formatted_str(node, NULL);
-	purple_util_write_data_to_config_file("blist.xml", data, -1);
-	g_free(data);
-	purple_xmlnode_free(node);
-}
-
-static gboolean
-save_cb(G_GNUC_UNUSED gpointer data)
-{
-	purple_blist_sync();
-	save_timer = 0;
-	return FALSE;
-}
-
-static void
-purple_blist_real_schedule_save(void)
-{
-	if (save_timer == 0)
-		save_timer = g_timeout_add_seconds(5, save_cb, NULL);
-}
-
-static void
-purple_blist_real_save_account(G_GNUC_UNUSED PurpleBuddyList *list,
-                               G_GNUC_UNUSED PurpleAccount *account)
-{
-#if 1
-	purple_blist_real_schedule_save();
-#else
-	if (account != NULL) {
-		/* Save the buddies and privacy data for this account */
-	} else {
-		/* Save all buddies and privacy data */
-	}
-#endif
-}
-
-static void
-purple_blist_real_save_node(G_GNUC_UNUSED PurpleBuddyList *list,
-                            G_GNUC_UNUSED PurpleBlistNode *node)
-{
-	purple_blist_real_schedule_save();
-}
-
-void
-purple_blist_schedule_save(void)
-{
-	PurpleBuddyListClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-
-	/* Save everything */
-	if (klass && klass->save_account) {
-		klass->save_account(purplebuddylist, NULL);
-	}
-}
-
-/*********************************************************************
- * Reading from disk                                                 *
- *********************************************************************/
-
-static void
-parse_setting(PurpleBlistNode *node, PurpleXmlNode *setting)
-{
-	const char *name = purple_xmlnode_get_attrib(setting, "name");
-	const char *type = purple_xmlnode_get_attrib(setting, "type");
-	char *value = purple_xmlnode_get_data(setting);
-
-	if (!value)
-		return;
-
-	if (!type || purple_strequal(type, "string"))
-		purple_blist_node_set_string(node, name, value);
-	else if (purple_strequal(type, "bool"))
-		purple_blist_node_set_bool(node, name, atoi(value));
-	else if (purple_strequal(type, "int"))
-		purple_blist_node_set_int(node, name, atoi(value));
-
-	g_free(value);
-}
-
-static void
-parse_contact(PurpleGroup *group, PurpleXmlNode *cnode)
-{
-	PurpleMetaContact *contact = purple_meta_contact_new();
-	PurpleXmlNode *x;
-	const char *alias;
-
-	purple_blist_add_contact(contact, group,
-			_purple_blist_get_last_child((PurpleBlistNode*)group));
-
-	if ((alias = purple_xmlnode_get_attrib(cnode, "alias"))) {
-		purple_meta_contact_set_alias(contact, alias);
-	}
-
-	for (x = cnode->child; x; x = x->next) {
-		if (x->type != PURPLE_XMLNODE_TYPE_TAG)
-			continue;
-		if (purple_strequal(x->name, "setting"))
-			parse_setting(PURPLE_BLIST_NODE(contact), x);
-	}
-
-	/* if the contact is empty, don't keep it around.  it causes problems */
-	if (!PURPLE_BLIST_NODE(contact)->child)
-		purple_blist_remove_contact(contact);
-}
-
-static void
-parse_group(PurpleXmlNode *groupnode)
-{
-	const char *name = purple_xmlnode_get_attrib(groupnode, "name");
-	PurpleGroup *group;
-	PurpleXmlNode *cnode;
-
-	group = purple_group_new(name);
-	purple_blist_add_group(group, purple_blist_get_last_sibling(
-	                                      purple_blist_get_default_root()));
-
-	for (cnode = groupnode->child; cnode; cnode = cnode->next) {
-		if (cnode->type != PURPLE_XMLNODE_TYPE_TAG)
-			continue;
-		if (purple_strequal(cnode->name, "setting"))
-			parse_setting((PurpleBlistNode*)group, cnode);
-		else if (purple_strequal(cnode->name, "contact") ||
-				purple_strequal(cnode->name, "person"))
-			parse_contact(group, cnode);
-	}
-}
-
-static void
-load_blist(void)
-{
-	PurpleXmlNode *purple, *blist;
-
-	blist_loaded = TRUE;
-
-	purple = purple_util_read_xml_from_config_file("blist.xml", _("buddy list"));
-
-	if(purple == NULL) {
-		return;
-	}
-
-	blist = purple_xmlnode_get_child(purple, "blist");
-	if(blist) {
-		PurpleXmlNode *groupnode;
-
-		localized_default_group_name = g_strdup(
-			purple_xmlnode_get_attrib(blist,
-				"localized-default-group"));
-
-		for(groupnode = purple_xmlnode_get_child(blist, "group"); groupnode != NULL;
-				groupnode = purple_xmlnode_get_next_twin(groupnode)) {
-			parse_group(groupnode);
-		}
-	} else {
-		g_free(localized_default_group_name);
-		localized_default_group_name = NULL;
-	}
-
-	purple_xmlnode_free(purple);
-}
-
-/*****************************************************************************
- * Public API functions                                                      *
- *****************************************************************************/
-
-void
-purple_blist_set_ui(GType type)
-{
-	g_return_if_fail(g_type_is_a(type, PURPLE_TYPE_BUDDY_LIST) ||
-	                 type == G_TYPE_INVALID);
-	buddy_list_type = type;
-}
-
-void
-purple_blist_boot(void)
-{
-	GListModel *manager_model = NULL;
-	PurpleBuddyList *gbl = g_object_new(buddy_list_type, NULL);
-	guint n_items = 0;
-
-	buddies_cache = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-					 NULL, (GDestroyNotify)g_hash_table_destroy);
-
-	groups_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-
-	manager_model = purple_account_manager_get_default_as_model();
-	n_items = g_list_model_get_n_items(manager_model);
-	for(guint index = 0; index < n_items; index++) {
-		PurpleAccount *account = g_list_model_get_item(manager_model, index);
-		purple_blist_buddies_cache_add_account(account);
-		g_object_unref(account);
-	}
-
-	purplebuddylist = gbl;
-
-	load_blist();
-}
-
-PurpleBuddyList *
-purple_blist_get_default(void)
-{
-	return purplebuddylist;
-}
-
-PurpleBlistNode *
-purple_blist_get_default_root(void)
-{
-	if (purplebuddylist) {
-		PurpleBuddyListPrivate *priv =
-		        purple_buddy_list_get_instance_private(purplebuddylist);
-		return priv->root;
-	}
-	return NULL;
-}
-
-PurpleBlistNode *
-purple_blist_get_root(PurpleBuddyList *list)
-{
-	PurpleBuddyListPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY_LIST(list), NULL);
-	priv = purple_buddy_list_get_instance_private(list);
-
-	return priv->root;
-}
-
-static void
-append_buddy(G_GNUC_UNUSED gpointer key, gpointer value, gpointer user_data)
-{
-	GSList **list = user_data;
-	*list = g_slist_prepend(*list, value);
-}
-
-GSList *
-purple_blist_get_buddies(void)
-{
-	PurpleBuddyListPrivate *priv;
-	GSList *buddies = NULL;
-
-	if (!purplebuddylist)
-		return NULL;
-
-	priv = purple_buddy_list_get_instance_private(purplebuddylist);
-	g_hash_table_foreach(priv->buddies, append_buddy, &buddies);
-	return buddies;
-}
-
-void
-purple_blist_show(void)
-{
-	PurpleBuddyListClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-
-	if (klass && klass->show) {
-		klass->show(purplebuddylist);
-	}
-}
-
-void purple_blist_set_visible(gboolean show)
-{
-	PurpleBuddyListClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-
-	if (klass && klass->set_visible) {
-		klass->set_visible(purplebuddylist, show);
-	}
-}
-
-void purple_blist_update_groups_cache(PurpleGroup *group, const char *new_name)
-{
-		gchar* key;
-
-		key = purple_blist_fold_name(purple_group_get_name(group));
-		g_hash_table_remove(groups_cache, key);
-		g_free(key);
-
-		g_hash_table_insert(groups_cache,
-			purple_blist_fold_name(new_name), group);
-}
-
-void purple_blist_add_contact(PurpleMetaContact *contact, PurpleGroup *group, PurpleBlistNode *node)
-{
-	PurpleBuddyListClass *klass = NULL;
-	PurpleGroup *g;
-	PurpleBlistNode *gnode, *cnode, *bnode;
-	PurpleCountingNode *contact_counter, *group_counter;
-
-	g_return_if_fail(PURPLE_IS_META_CONTACT(contact));
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-
-	if (PURPLE_BLIST_NODE(contact) == node)
-		return;
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-
-	if (node && (PURPLE_IS_META_CONTACT(node)))
-		g = PURPLE_GROUP(node->parent);
-	else if (group)
-		g = group;
-	else
-		g = purple_blist_get_default_group();
-
-	gnode = (PurpleBlistNode*)g;
-	cnode = (PurpleBlistNode*)contact;
-
-	if (cnode->parent) {
-		if (cnode->parent->child == cnode)
-			cnode->parent->child = cnode->next;
-		if (cnode->prev)
-			cnode->prev->next = cnode->next;
-		if (cnode->next)
-			cnode->next->prev = cnode->prev;
-
-		contact_counter = PURPLE_COUNTING_NODE(contact);
-		group_counter = PURPLE_COUNTING_NODE(cnode->parent);
-
-		if (purple_counting_node_get_online_count(contact_counter) > 0)
-			purple_counting_node_change_online_count(group_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(group_counter, -1);
-
-		if (klass && klass->remove) {
-			klass->remove(purplebuddylist, cnode);
-		}
-
-		if (klass && klass->remove_node) {
-			klass->remove_node(purplebuddylist, cnode);
-		}
-	}
-
-	if (node && (PURPLE_IS_META_CONTACT(node))) {
-		if (node->next)
-			node->next->prev = cnode;
-		cnode->next = node->next;
-		cnode->prev = node;
-		cnode->parent = node->parent;
-		node->next = cnode;
-	} else {
-		if (gnode->child)
-			gnode->child->prev = cnode;
-		cnode->prev = NULL;
-		cnode->next = gnode->child;
-		gnode->child = cnode;
-		cnode->parent = gnode;
-	}
-
-	contact_counter = PURPLE_COUNTING_NODE(contact);
-	group_counter = PURPLE_COUNTING_NODE(g);
-
-	if (purple_counting_node_get_online_count(contact_counter) > 0)
-		purple_counting_node_change_online_count(group_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(group_counter, +1);
-
-	if (klass && klass->save_node) {
-		if (cnode->child) {
-			klass->save_node(purplebuddylist, cnode);
-		}
-		for (bnode = cnode->child; bnode; bnode = bnode->next) {
-			klass->save_node(purplebuddylist, bnode);
-		}
-	}
-
-	if (klass && klass->update) {
-		if (cnode->child) {
-			klass->update(purplebuddylist, cnode);
-		}
-
-		for (bnode = cnode->child; bnode; bnode = bnode->next) {
-			klass->update(purplebuddylist, bnode);
-		}
-	}
-}
-
-void purple_blist_add_group(PurpleGroup *group, PurpleBlistNode *node)
-{
-	PurpleBuddyListClass *klass = NULL;
-	PurpleBuddyListPrivate *priv = NULL;
-	PurpleBlistNode *gnode = (PurpleBlistNode*)group;
-	gchar* key;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-	g_return_if_fail(PURPLE_IS_GROUP(group));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-	priv = purple_buddy_list_get_instance_private(purplebuddylist);
-
-	/* if we're moving to overtop of ourselves, do nothing */
-	if (gnode == node) {
-		if (!priv->root) {
-			node = NULL;
-		} else {
-			return;
-		}
-	}
-
-	if (purple_blist_find_group(purple_group_get_name(group))) {
-		/* This is just being moved */
-
-		if (klass && klass->remove) {
-			klass->remove(purplebuddylist,
-			              (PurpleBlistNode *)group);
-		}
-
-		if (gnode == priv->root) {
-			priv->root = gnode->next;
-		}
-		if (gnode->prev)
-			gnode->prev->next = gnode->next;
-		if (gnode->next)
-			gnode->next->prev = gnode->prev;
-	} else {
-		key = purple_blist_fold_name(purple_group_get_name(group));
-		g_hash_table_insert(groups_cache, key, group);
-	}
-
-	if (node && PURPLE_IS_GROUP(node)) {
-		gnode->next = node->next;
-		gnode->prev = node;
-		if (node->next)
-			node->next->prev = gnode;
-		node->next = gnode;
-	} else {
-		if (priv->root) {
-			priv->root->prev = gnode;
-		}
-		gnode->next = priv->root;
-		gnode->prev = NULL;
-		priv->root = gnode;
-	}
-
-	if (klass && klass->save_node) {
-		klass->save_node(purplebuddylist, gnode);
-		for (node = gnode->child; node; node = node->next) {
-			klass->save_node(purplebuddylist, node);
-		}
-	}
-
-	if (klass && klass->update) {
-		klass->update(purplebuddylist, gnode);
-		for (node = gnode->child; node; node = node->next) {
-			klass->update(purplebuddylist, node);
-		}
-	}
-
-	purple_signal_emit(purple_blist_get_handle(), "blist-node-added",
-			gnode);
-}
-
-void purple_blist_remove_contact(PurpleMetaContact *contact)
-{
-	PurpleBuddyListClass *klass = NULL;
-	PurpleBlistNode *node, *gnode;
-	PurpleGroup *group;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-	g_return_if_fail(PURPLE_IS_META_CONTACT(contact));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-	node = (PurpleBlistNode *)contact;
-	gnode = node->parent;
-	group = PURPLE_GROUP(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;
-	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_group(PurpleGroup *group)
-{
-	PurpleAccountManager *manager = NULL;
-	PurpleBuddyListClass *klass = NULL;
-	PurpleBuddyListPrivate *priv = NULL;
-	PurpleBlistNode *node;
-	GList *accounts = NULL;
-	gchar* key;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-	g_return_if_fail(PURPLE_IS_GROUP(group));
-
-	if (group == purple_blist_get_default_group())
-		purple_debug_warning("buddylist", "cannot remove default group");
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-	priv = purple_buddy_list_get_instance_private(purplebuddylist);
-	node = (PurpleBlistNode *)group;
-
-	/* Make sure the group is empty */
-	if (node->child)
-		return;
-
-	/* Remove the node from its parent */
-	if (priv->root == node) {
-		priv->root = node->next;
-	}
-	if (node->prev)
-		node->prev->next = node->next;
-	if (node->next)
-		node->next->prev = node->prev;
-
-	key = purple_blist_fold_name(purple_group_get_name(group));
-	g_hash_table_remove(groups_cache, key);
-	g_free(key);
-
-	/* 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(group));
-
-	/* Remove the group from all accounts that are online */
-	manager = purple_account_manager_get_default();
-	accounts = purple_account_manager_get_connected(manager);
-	while(accounts != NULL) {
-		purple_account_remove_group(accounts->data, group);
-
-		accounts = g_list_delete_link(accounts, accounts);
-	}
-
-	/* Delete the node */
-	g_object_unref(group);
-}
-
-PurpleGroup *purple_blist_find_group(const char *name)
-{
-	gchar* key;
-	PurpleGroup *group;
-
-	g_return_val_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist), NULL);
-
-	if (name == NULL || name[0] == '\0')
-		name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
-	if (purple_strequal(name, "Buddies"))
-		name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
-	if (purple_strequal(name, localized_default_group_name))
-		name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
-
-	key = purple_blist_fold_name(name);
-	group = g_hash_table_lookup(groups_cache, key);
-	g_free(key);
-
-	return group;
-}
-
-PurpleGroup *
-purple_blist_get_default_group(void)
-{
-	PurpleGroup *group;
-
-	group = purple_blist_find_group(PURPLE_BLIST_DEFAULT_GROUP_NAME);
-	if (!group) {
-		group = purple_group_new(PURPLE_BLIST_DEFAULT_GROUP_NAME);
-		purple_blist_add_group(group, NULL);
-	}
-
-	return group;
-}
-
-void
-purple_blist_walk(PurpleBlistWalkFunc group_func,
-                  PurpleBlistWalkFunc meta_contact_func,
-                  PurpleBlistWalkFunc contact_func,
-                  gpointer data)
-{
-	PurpleBlistNode *group = NULL, *meta_contact = NULL, *contact = NULL;
-
-	for (group = purple_blist_get_default_root(); group != NULL;
-	     group = group->next) {
-		if(group_func != NULL) {
-			group_func(group, data);
-		}
-
-		for(meta_contact = group->child; meta_contact != NULL; meta_contact = meta_contact->next) {
-			if(PURPLE_IS_META_CONTACT(meta_contact)) {
-				if(meta_contact_func != NULL) {
-					meta_contact_func(meta_contact, data);
-				}
-
-				if(contact_func != NULL) {
-					for(contact = meta_contact->child; contact != NULL; contact = contact->next) {
-						contact_func(contact, data);
-					}
-				}
-			}
-		}
-	}
-}
-
-const gchar *
-purple_blist_get_default_group_name(void) {
-	return _("Buddies");
-}
-
-
-void
-purple_blist_request_add_buddy(PurpleAccount *account, const char *username,
-							 const char *group, const char *alias)
-{
-	PurpleBuddyListClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-	if (klass != NULL && klass->request_add_buddy != NULL) {
-		klass->request_add_buddy(purplebuddylist, account, username,
-		                         group, alias);
-	}
-}
-
-void
-purple_blist_request_add_group(void)
-{
-	PurpleBuddyListClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
-	if (klass != NULL && klass->request_add_group != NULL) {
-		klass->request_add_group(purplebuddylist);
-	}
-}
-
-void
-purple_blist_new_node(PurpleBuddyList *list, PurpleBlistNode *node)
-{
-	PurpleBuddyListClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(list));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(list);
-	if (klass && klass->new_node) {
-		klass->new_node(list, node);
-	}
-}
-
-void
-purple_blist_update_node(PurpleBuddyList *list, PurpleBlistNode *node)
-{
-	PurpleBuddyListClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(list));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(list);
-	if (klass && klass->update) {
-		klass->update(list, node);
-	}
-}
-
-void
-purple_blist_save_node(PurpleBuddyList *list, PurpleBlistNode *node)
-{
-	PurpleBuddyListClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(list));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(list);
-	if (klass && klass->save_node) {
-		klass->save_node(list, node);
-	}
-}
-
-void
-purple_blist_save_account(PurpleBuddyList *list, PurpleAccount *account)
-{
-	PurpleBuddyListClass *klass = NULL;
-
-	/* XXX: There's a chicken and egg problem with the accounts api, where
-	 * it'll call this function before purple_blist_init is called, this will
-	 * cause the following g_return_if_fail to fail, and muck up the logs.  We
-	 * need to find a better fix for this, but this gets rid of it for now.
-	 */
-	if(G_UNLIKELY(list == NULL && purplebuddylist == NULL)) {
-		return;
-	}
-
-	g_return_if_fail(PURPLE_IS_BUDDY_LIST(list));
-
-	klass = PURPLE_BUDDY_LIST_GET_CLASS(list);
-	if (klass && klass->save_account) {
-		klass->save_account(list, account);
-	}
-}
-
-const gchar *
-_purple_blist_get_localized_default_group_name(void)
-{
-	return localized_default_group_name;
-}
-
-void *
-purple_blist_get_handle(void)
-{
-	static int handle;
-
-	return &handle;
-}
-
-void
-purple_blist_init(void)
-{
-	void *handle = purple_blist_get_handle();
-
-	/* Set a default, which can't be done as a static initializer. */
-	buddy_list_type = PURPLE_TYPE_BUDDY_LIST;
-
-	purple_signal_register(handle, "blist-node-added",
-						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-						 PURPLE_TYPE_BLIST_NODE);
-
-	purple_signal_register(handle, "blist-node-removed",
-						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-						 PURPLE_TYPE_BLIST_NODE);
-
-	purple_signal_register(handle, "update-idle", purple_marshal_VOID,
-						 G_TYPE_NONE, 0);
-
-	purple_signal_register(handle, "blist-node-extended-menu",
-			     purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2,
-			     PURPLE_TYPE_BLIST_NODE,
-			     G_TYPE_POINTER); /* (GList **) */
-
-	purple_signal_register(handle, "blist-node-aliased",
-						 purple_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2,
-						 PURPLE_TYPE_BLIST_NODE, G_TYPE_STRING);
-}
-
-static void
-blist_node_destroy(PurpleBuddyListClass *klass, PurpleBuddyList *list,
-                   PurpleBlistNode *node)
-{
-	PurpleBlistNode *child, *next_child;
-
-	child = node->child;
-	while (child) {
-		next_child = child->next;
-		blist_node_destroy(klass, list, child);
-		child = next_child;
-	}
-
-	/* Allow the UI to free data */
-	node->parent = NULL;
-	node->child  = NULL;
-	node->next   = NULL;
-	node->prev   = NULL;
-	if (klass && klass->remove) {
-		klass->remove(list, node);
-	}
-
-	g_object_unref(node);
-}
-
-void
-purple_blist_uninit(void)
-{
-	/* This happens if we quit before purple_set_blist is called. */
-	if (purplebuddylist == NULL)
-		return;
-
-	if(save_timer != 0) {
-		g_clear_handle_id(&save_timer, g_source_remove);
-		purple_blist_sync();
-	}
-
-	purple_debug_info("buddylist", "Destroying");
-
-	g_clear_pointer(&buddies_cache, g_hash_table_destroy);
-	g_clear_pointer(&groups_cache, g_hash_table_destroy);
-
-	g_clear_object(&purplebuddylist);
-
-	g_clear_pointer(&localized_default_group_name, g_free);
-
-	purple_signals_disconnect_by_handle(purple_blist_get_handle());
-	purple_signals_unregister_by_instance(purple_blist_get_handle());
-}
-
-/**************************************************************************
- * GObject code
- **************************************************************************/
-
-/* GObject initialization function */
-static void
-purple_buddy_list_init(PurpleBuddyList *blist)
-{
-	PurpleBuddyListPrivate *priv = NULL;
-	PurpleAccountManager *manager = NULL;
-
-	priv = purple_buddy_list_get_instance_private(blist);
-
-	priv->buddies = g_hash_table_new_full(
-					 (GHashFunc)_purple_blist_hbuddy_hash,
-					 (GEqualFunc)_purple_blist_hbuddy_equal,
-					 (GDestroyNotify)_purple_blist_hbuddy_free_key, NULL);
-
-	manager = purple_account_manager_get_default();
-	g_signal_connect_object(manager, "added",
-	                        G_CALLBACK(purple_buddy_list_account_added_cb),
-	                        blist, 0);
-	g_signal_connect_object(manager, "removed",
-	                        G_CALLBACK(purple_buddy_list_account_removed_cb),
-	                        blist, 0);
-}
-
-/* GObject finalize function */
-static void
-purple_buddy_list_finalize(GObject *object)
-{
-	PurpleBuddyList *list = PURPLE_BUDDY_LIST(object);
-	PurpleBuddyListClass *klass = PURPLE_BUDDY_LIST_GET_CLASS(list);
-	PurpleBuddyListPrivate *priv =
-	        purple_buddy_list_get_instance_private(list);
-	PurpleBlistNode *node, *next_node;
-
-	g_hash_table_destroy(priv->buddies);
-
-	node = priv->root;
-	while (node) {
-		next_node = node->next;
-		blist_node_destroy(klass, list, node);
-		node = next_node;
-	}
-	priv->root = NULL;
-
-	G_OBJECT_CLASS(purple_buddy_list_parent_class)->finalize(object);
-}
-
-/* Class initializer function */
-static void purple_buddy_list_class_init(PurpleBuddyListClass *klass)
-{
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
-	obj_class->finalize = purple_buddy_list_finalize;
-
-	klass->save_node = purple_blist_real_save_node;
-	klass->remove_node = purple_blist_real_save_node;
-	klass->save_account = purple_blist_real_save_account;
-}
diff --git a/libpurple/connection.c b/libpurple/connection.c
--- a/libpurple/connection.c
+++ b/libpurple/connection.c
@@ -22,7 +22,6 @@
 
 #include <glib/gi18n-lib.h>
 
-#include "buddylist.h"
 #include "connection.h"
 #include "debug.h"
 #include "notify.h"
diff --git a/libpurple/contact.h b/libpurple/contact.h
deleted file mode 100644
--- a/libpurple/contact.h
+++ /dev/null
@@ -1,123 +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_META_CONTACT_H
-#define PURPLE_META_CONTACT_H
-
-#define PURPLE_TYPE_META_CONTACT             (purple_meta_contact_get_type())
-#define PURPLE_META_CONTACT(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_META_CONTACT, PurpleMetaContact))
-#define PURPLE_META_CONTACT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_META_CONTACT, PurpleMetaContactClass))
-#define PURPLE_IS_META_CONTACT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_META_CONTACT))
-#define PURPLE_IS_META_CONTACT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_META_CONTACT))
-#define PURPLE_META_CONTACT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_META_CONTACT, PurpleMetaContactClass))
-
-typedef struct _PurpleMetaContact PurpleMetaContact;
-typedef struct _PurpleMetaContactClass PurpleMetaContactClass;
-
-#include "countingnode.h"
-#include "group.h"
-#include "purpleaccount.h"
-#include "purpleversion.h"
-
-/**
- * PurpleMetaContact:
- *
- * A contact on the buddy list.
- *
- * A contact is a counting node, which means it keeps track of the counts of
- * the buddies under this contact.
- */
-struct _PurpleMetaContact {
-	PurpleCountingNode counting;
-};
-
-struct _PurpleMetaContactClass {
-	PurpleCountingNodeClass counting_class;
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* Contact API                                                            */
-/**************************************************************************/
-
-/**
- * purple_meta_contact_get_type:
- *
- * Returns: The #GType for the #PurpleMetaContact object.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GType purple_meta_contact_get_type(void);
-
-/**
- * purple_meta_contact_new:
- *
- * Creates a new contact
- *
- * Returns:       A new contact struct
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleMetaContact *purple_meta_contact_new(void);
-
-/**
- * purple_meta_contact_set_alias:
- * @contact:  The contact
- * @alias:    The alias
- *
- * Sets the alias for a contact.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_meta_contact_set_alias(PurpleMetaContact *contact, const char *alias);
-
-/**
- * purple_meta_contact_get_alias:
- * @contact:  The contact
- *
- * Gets the alias for a contact.
- *
- * Returns:  The alias, or NULL if it is not set.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-const char *purple_meta_contact_get_alias(PurpleMetaContact *contact);
-
-G_END_DECLS
-
-#endif /* PURPLE_META_CONTACT_H */
-
diff --git a/libpurple/contact.c b/libpurple/contact.c
deleted file mode 100644
--- a/libpurple/contact.c
+++ /dev/null
@@ -1,201 +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 "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  */
-};
-
-enum
-{
-	PROP_0,
-	PROP_ALIAS,
-	N_PROPERTIES,
-};
-
-/******************************************************************************
- * Globals
- *****************************************************************************/
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleMetaContact, purple_meta_contact,
-		PURPLE_TYPE_COUNTING_NODE);
-
-/******************************************************************************
- * API
- *****************************************************************************/
-void
-purple_meta_contact_set_alias(PurpleMetaContact *contact, const char *alias)
-{
-	PurpleMetaContactPrivate *priv = NULL;
-	char *old_alias;
-	char *new_alias = NULL;
-
-	g_return_if_fail(PURPLE_IS_META_CONTACT(contact));
-	priv = purple_meta_contact_get_instance_private(contact);
-
-	if ((alias != NULL) && (*alias != '\0'))
-		new_alias = purple_utf8_strip_unprintables(alias);
-
-	if (!purple_strequal(priv->alias, new_alias)) {
-		g_free(new_alias);
-		return;
-	}
-
-	old_alias = priv->alias;
-
-	if ((new_alias != NULL) && (*new_alias != '\0')) {
-		priv->alias = new_alias;
-	} else {
-		priv->alias = NULL;
-		g_free(new_alias); /* could be "\0" */
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ALIAS]);
-
-	purple_blist_save_node(purple_blist_get_default(),
-	                       PURPLE_BLIST_NODE(contact));
-	purple_blist_update_node(purple_blist_get_default(),
-	                         PURPLE_BLIST_NODE(contact));
-
-	purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
-	                   contact, old_alias);
-	g_free(old_alias);
-}
-
-const char *purple_meta_contact_get_alias(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->alias)
-		return priv->alias;
-
-	return NULL;
-}
-
-/**************************************************************************
- * GObject Stuff
- **************************************************************************/
-/* Set method for GObject properties */
-static void
-purple_meta_contact_set_property(GObject *obj, guint param_id, const GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleMetaContact *contact = PURPLE_META_CONTACT(obj);
-
-	switch (param_id) {
-		case PROP_ALIAS:
-			purple_meta_contact_set_alias(contact, g_value_get_string(value));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-/* Get method for GObject properties */
-static void
-purple_meta_contact_get_property(GObject *obj, guint param_id, GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleMetaContact *contact = PURPLE_META_CONTACT(obj);
-	PurpleMetaContactPrivate *priv =
-			purple_meta_contact_get_instance_private(contact);
-
-	switch (param_id) {
-		case PROP_ALIAS:
-			g_value_set_string(value, priv->alias);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-/* GObject initialization function */
-static void
-purple_meta_contact_init(PurpleMetaContact *contact)
-{
-	purple_blist_new_node(purple_blist_get_default(),
-	                      PURPLE_BLIST_NODE(contact));
-}
-
-/* GObject finalize function */
-static void
-purple_meta_contact_finalize(GObject *object)
-{
-	PurpleMetaContactPrivate *priv = purple_meta_contact_get_instance_private(
-			PURPLE_META_CONTACT(object));
-
-	g_free(priv->alias);
-
-	G_OBJECT_CLASS(purple_meta_contact_parent_class)->finalize(object);
-}
-
-/* Class initializer function */
-static void purple_meta_contact_class_init(PurpleMetaContactClass *klass)
-{
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
-	obj_class->finalize = purple_meta_contact_finalize;
-
-	/* Setup properties */
-	obj_class->get_property = purple_meta_contact_get_property;
-	obj_class->set_property = purple_meta_contact_set_property;
-
-	/**
-	 * PurpleMetaContact:alias:
-	 *
-	 * The alias for the contact.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_ALIAS] = g_param_spec_string(
-		"alias",
-		"Alias",
-		"The alias for the contact.",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
-	);
-
-	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
-}
-
-PurpleMetaContact *
-purple_meta_contact_new(void)
-{
-	return g_object_new(PURPLE_TYPE_META_CONTACT, NULL);
-}
-
diff --git a/libpurple/core.c b/libpurple/core.c
--- a/libpurple/core.c
+++ b/libpurple/core.c
@@ -26,7 +26,6 @@
 #define G_SETTINGS_ENABLE_BACKEND
 #include <gio/gsettingsbackend.h>
 
-#include "buddylist.h"
 #include "cmds.h"
 #include "connection.h"
 #include "conversations.h"
@@ -158,7 +157,6 @@
 	purple_conversations_init();
 	purple_conversation_manager_startup();
 	purple_whiteboard_manager_startup();
-	purple_blist_init();
 
 	/* Setup the history adapter. */
 	adapter = purple_ui_get_history_adapter(ui);
@@ -196,9 +194,6 @@
 		return FALSE;
 	}
 
-	/* Load the buddy list after UI init */
-	purple_blist_boot();
-
 	purple_signal_emit(purple_get_core(), "core-initialized");
 
 	return TRUE;
@@ -229,7 +224,6 @@
 	purple_whiteboard_manager_shutdown();
 	purple_conversation_manager_shutdown();
 	purple_conversations_uninit();
-	purple_blist_uninit();
 	purple_notify_uninit();
 	purple_connections_uninit();
 	purple_presence_manager_shutdown();
diff --git a/libpurple/countingnode.h b/libpurple/countingnode.h
deleted file mode 100644
--- a/libpurple/countingnode.h
+++ /dev/null
@@ -1,212 +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_COUNTING_NODE_H
-#define PURPLE_COUNTING_NODE_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "blistnode.h"
-#include "purpleversion.h"
-
-#define PURPLE_TYPE_COUNTING_NODE             (purple_counting_node_get_type())
-#define PURPLE_COUNTING_NODE(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_COUNTING_NODE, PurpleCountingNode))
-#define PURPLE_COUNTING_NODE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_COUNTING_NODE, PurpleCountingNodeClass))
-#define PURPLE_IS_COUNTING_NODE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_COUNTING_NODE))
-#define PURPLE_IS_COUNTING_NODE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_COUNTING_NODE))
-#define PURPLE_COUNTING_NODE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_COUNTING_NODE, PurpleCountingNodeClass))
-
-PURPLE_AVAILABLE_TYPE_IN_3_0
-typedef struct _PurpleCountingNode PurpleCountingNode;
-typedef struct _PurpleCountingNodeClass PurpleCountingNodeClass;
-
-/**
- * PurpleCountingNode:
- *
- * A node that keeps count of the number of children that it has. It tracks the
- * total number of children, the number of children corresponding to online
- * accounts, and the number of online children.
- *
- * The two types of counting nodes are:
- * <orderedlist>
- *  <listitem>Contact: Keeps track of the number of buddies under it.</listitem>
- *  <listitem>Group: Keeps track of the number of chats and contacts under it.
- *                                                                   </listitem>
- * </orderedlist>
- *
- * See #PurpleContact, #PurpleGroup
- *
- * Since: 3.0
- */
-struct _PurpleCountingNode {
-	PurpleBlistNode node;
-};
-
-struct _PurpleCountingNodeClass {
-	PurpleBlistNodeClass node_class;
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-/**
- * purple_counting_node_get_type:
- *
- * Returns: The #GType for the #PurpleCountingNode object.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GType purple_counting_node_get_type(void);
-
-/**
- * purple_counting_node_get_total_size:
- * @counter:  The node
- *
- * Returns the total number of children of the counting node.
- *
- * Returns:  The total number of children of the node
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-int purple_counting_node_get_total_size(PurpleCountingNode *counter);
-
-/**
- * purple_counting_node_get_current_size:
- * @counter:  The node
- *
- * Returns the number of children of the counting node corresponding to online
- * accounts.
- *
- * Returns:  The number of children with online accounts
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-int purple_counting_node_get_current_size(PurpleCountingNode *counter);
-
-/**
- * purple_counting_node_get_online_count:
- * @counter:  The node
- *
- * Returns the number of children of the counting node that are online.
- *
- * Returns:  The total number of online children
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-int purple_counting_node_get_online_count(PurpleCountingNode *counter);
-
-/**
- * purple_counting_node_change_total_size:
- * @counter:  The node
- * @delta:    The value to change the total size by
- *
- * Changes the total number of children of the counting node. The provided
- * delta value is added to the count, or if it's negative, the count is
- * decreased.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_counting_node_change_total_size(PurpleCountingNode *counter, int delta);
-
-/**
- * purple_counting_node_change_current_size:
- * @counter:  The node
- * @delta:    The value to change the current size by
- *
- * Changes the number of children of the counting node corresponding to online
- * accounts. The provided delta value is added to the count, or if it's
- * negative, the count is decreased.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_counting_node_change_current_size(PurpleCountingNode *counter, int delta);
-
-/**
- * purple_counting_node_change_online_count:
- * @counter:  The node
- * @delta:    The value to change the online count by
- *
- * Changes the number of children of the counting node that are online. The
- * provided delta value is added to the count, or if it's negative, the count is
- * decreased.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_counting_node_change_online_count(PurpleCountingNode *counter, int delta);
-
-/**
- * purple_counting_node_set_total_size:
- * @counter:    The node
- * @totalsize:  The total number of children of the node
- *
- * Sets the total number of children of the counting node.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_counting_node_set_total_size(PurpleCountingNode *counter, int totalsize);
-
-/**
- * purple_counting_node_set_current_size:
- * @counter:      The node
- * @currentsize:  The number of children with online accounts
- *
- * Sets the number of children of the counting node corresponding to online
- * accounts.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_counting_node_set_current_size(PurpleCountingNode *counter, int currentsize);
-
-/**
- * purple_counting_node_set_online_count:
- * @counter:      The node
- * @onlinecount:  The total number of online children
- *
- * Sets the number of children of the counting node that are online.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_counting_node_set_online_count(PurpleCountingNode *counter, int onlinecount);
-
-G_END_DECLS
-
-#endif /* PURPLE_COUNTING_NODE_H */
diff --git a/libpurple/countingnode.c b/libpurple/countingnode.c
deleted file mode 100644
--- a/libpurple/countingnode.c
+++ /dev/null
@@ -1,270 +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 "countingnode.h"
-
-typedef struct _PurpleCountingNodePrivate  PurpleCountingNodePrivate;
-
-/* Private data of a counting node */
-struct _PurpleCountingNodePrivate {
-	int totalsize;    /* The number of children under this node            */
-	int currentsize;  /* The number of children under this node
-	                     corresponding to online accounts                  */
-	int onlinecount;  /* The number of children under this contact who are
-	                     currently online                                  */
-};
-
-/* Counting node property enums */
-enum
-{
-	PROP_0,
-	PROP_TOTAL_SIZE,
-	PROP_CURRENT_SIZE,
-	PROP_ONLINE_COUNT,
-	N_PROPERTIES,
-};
-
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
-G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(PurpleCountingNode, purple_counting_node,
-		PURPLE_TYPE_BLIST_NODE);
-
-/******************************************************************************
- * API
- *****************************************************************************/
-int
-purple_counting_node_get_total_size(PurpleCountingNode *counter)
-{
-	PurpleCountingNodePrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_COUNTING_NODE(counter), -1);
-
-	priv = purple_counting_node_get_instance_private(counter);
-	return priv->totalsize;
-}
-
-int
-purple_counting_node_get_current_size(PurpleCountingNode *counter)
-{
-	PurpleCountingNodePrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_COUNTING_NODE(counter), -1);
-
-	priv = purple_counting_node_get_instance_private(counter);
-	return priv->currentsize;
-}
-
-int
-purple_counting_node_get_online_count(PurpleCountingNode *counter)
-{
-	PurpleCountingNodePrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_COUNTING_NODE(counter), -1);
-
-	priv = purple_counting_node_get_instance_private(counter);
-	return priv->onlinecount;
-}
-
-void
-purple_counting_node_change_total_size(PurpleCountingNode *counter, int delta)
-{
-	PurpleCountingNodePrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_COUNTING_NODE(counter));
-
-	priv = purple_counting_node_get_instance_private(counter);
-	purple_counting_node_set_total_size(counter, priv->totalsize + delta);
-}
-
-void
-purple_counting_node_change_current_size(PurpleCountingNode *counter, int delta)
-{
-	PurpleCountingNodePrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_COUNTING_NODE(counter));
-
-	priv = purple_counting_node_get_instance_private(counter);
-	purple_counting_node_set_current_size(counter, priv->currentsize + delta);
-}
-
-void
-purple_counting_node_change_online_count(PurpleCountingNode *counter, int delta)
-{
-	PurpleCountingNodePrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_COUNTING_NODE(counter));
-
-	priv = purple_counting_node_get_instance_private(counter);
-	purple_counting_node_set_online_count(counter, priv->onlinecount + delta);
-}
-
-void
-purple_counting_node_set_total_size(PurpleCountingNode *counter, int totalsize)
-{
-	PurpleCountingNodePrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_COUNTING_NODE(counter));
-
-	priv = purple_counting_node_get_instance_private(counter);
-	priv->totalsize = totalsize;
-
-	g_object_notify_by_pspec(G_OBJECT(counter), properties[PROP_TOTAL_SIZE]);
-}
-
-void
-purple_counting_node_set_current_size(PurpleCountingNode *counter, int currentsize)
-{
-	PurpleCountingNodePrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_COUNTING_NODE(counter));
-
-	priv = purple_counting_node_get_instance_private(counter);
-	priv->currentsize = currentsize;
-
-	g_object_notify_by_pspec(G_OBJECT(counter), properties[PROP_CURRENT_SIZE]);
-}
-
-void
-purple_counting_node_set_online_count(PurpleCountingNode *counter, int onlinecount)
-{
-	PurpleCountingNodePrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_COUNTING_NODE(counter));
-
-	priv = purple_counting_node_get_instance_private(counter);
-	priv->onlinecount = onlinecount;
-
-	g_object_notify_by_pspec(G_OBJECT(counter), properties[PROP_ONLINE_COUNT]);
-}
-
-/**************************************************************************
- * GObject Stuff
- **************************************************************************/
-/* Set method for GObject properties */
-static void
-purple_counting_node_set_property(GObject *obj, guint param_id, const GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleCountingNode *node = PURPLE_COUNTING_NODE(obj);
-
-	switch (param_id) {
-		case PROP_TOTAL_SIZE:
-			purple_counting_node_set_total_size(node, g_value_get_int(value));
-			break;
-		case PROP_CURRENT_SIZE:
-			purple_counting_node_set_current_size(node, g_value_get_int(value));
-			break;
-		case PROP_ONLINE_COUNT:
-			purple_counting_node_set_online_count(node, g_value_get_int(value));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-/* Get method for GObject properties */
-static void
-purple_counting_node_get_property(GObject *obj, guint param_id, GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleCountingNode *node = PURPLE_COUNTING_NODE(obj);
-
-	switch (param_id) {
-		case PROP_TOTAL_SIZE:
-			g_value_set_int(value, purple_counting_node_get_total_size(node));
-			break;
-		case PROP_CURRENT_SIZE:
-			g_value_set_int(value, purple_counting_node_get_current_size(node));
-			break;
-		case PROP_ONLINE_COUNT:
-			g_value_set_int(value, purple_counting_node_get_online_count(node));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_counting_node_init(G_GNUC_UNUSED PurpleCountingNode *counter)
-{
-}
-
-/* Class initializer function */
-static void
-purple_counting_node_class_init(PurpleCountingNodeClass *klass)
-{
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
-	/* Setup properties */
-	obj_class->get_property = purple_counting_node_get_property;
-	obj_class->set_property = purple_counting_node_set_property;
-
-	/**
-	 * PurpleCountingNode:total-size:
-	 *
-	 * The number of children under this node.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_TOTAL_SIZE] = g_param_spec_int(
-		"total-size",
-		"Total size",
-		"The number of children under this node.",
-		G_MININT, G_MAXINT, 0,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
-	);
-
-	/**
-	 * PurpleCountingNode:current-size:
-	 *
-	 * The number of children with online accounts.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_CURRENT_SIZE] = g_param_spec_int(
-		"current-size",
-		"Current size",
-		"The number of children with online accounts.",
-		G_MININT, G_MAXINT, 0,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
-	);
-
-	/**
-	 * PurpleCountingNode:online-count:
-	 *
-	 * The number of children that are online.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_ONLINE_COUNT] = g_param_spec_int(
-		"online-count",
-		"Online count",
-		"The number of children that are online.",
-		G_MININT, G_MAXINT, 0,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
-	);
-
-	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
-}
-
diff --git a/libpurple/group.h b/libpurple/group.h
deleted file mode 100644
--- a/libpurple/group.h
+++ /dev/null
@@ -1,161 +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_GROUP_H
-#define PURPLE_GROUP_H
-
-#include "countingnode.h"
-
-#define PURPLE_TYPE_GROUP             (purple_group_get_type())
-#define PURPLE_GROUP(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_GROUP, PurpleGroup))
-#define PURPLE_GROUP_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_GROUP, PurpleGroupClass))
-#define PURPLE_IS_GROUP(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_GROUP))
-#define PURPLE_IS_GROUP_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_GROUP))
-#define PURPLE_GROUP_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_GROUP, PurpleGroupClass))
-
-typedef struct _PurpleGroup PurpleGroup;
-typedef struct _PurpleGroupClass PurpleGroupClass;
-
-#include "purpleaccount.h"
-#include "purpleversion.h"
-
-/**************************************************************************/
-/* Data Structures                                                        */
-/**************************************************************************/
-
-/**
- * PurpleGroup:
- *
- * A group on the buddy list.
- *
- * A group is a counting node, which means it keeps track of the counts of the
- * chats and contacts under this group.
- *
- * Since: 2.0
- */
-struct _PurpleGroup {
-	PurpleCountingNode counting;
-};
-
-struct _PurpleGroupClass {
-	PurpleCountingNodeClass counting_class;
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* Group API                                                              */
-/**************************************************************************/
-
-/**
- * purple_group_get_type:
- *
- * Returns: The #GType for the #PurpleGroup object.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GType purple_group_get_type(void);
-
-/**
- * purple_group_new:
- * @name: The name of the new group
- *
- * Creates a new group
- *
- * You can't have more than one group with the same name.  Sorry.  If you pass
- * this the name of a group that already exists, it will return that group.
- *
- * Returns: A new group struct
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleGroup *purple_group_new(const char *name);
-
-/**
- * purple_group_get_accounts:
- * @g: The group
- *
- * Returns a list of accounts that have buddies in this group
- *
- * Returns: (element-type PurpleAccount) (transfer container): A list of
- *          accounts, or %NULL if the group has no accounts.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-GSList *purple_group_get_accounts(PurpleGroup *g);
-
-/**
- * purple_group_on_account:
- * @g:       The group to search through.
- * @account: The account.
- *
- * Determines whether an account owns any buddies in a given group
- *
- * Returns: TRUE if there are any buddies in the group, or FALSE otherwise.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-gboolean purple_group_on_account(PurpleGroup *g, PurpleAccount *account);
-
-/**
- * purple_group_set_name:
- * @group: The group.
- * @name:  The name of the group.
- *
- * Sets the name of a group.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_group_set_name(PurpleGroup *group, const char *name);
-
-/**
- * purple_group_get_name:
- * @group: The group.
- *
- * Returns the name of a group.
- *
- * Returns: The name of the group.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_group_get_name(PurpleGroup *group);
-
-G_END_DECLS
-
-#endif /* PURPLE_GROUP_H */
-
diff --git a/libpurple/group.c b/libpurple/group.c
deleted file mode 100644
--- a/libpurple/group.c
+++ /dev/null
@@ -1,325 +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 "group.h"
-
-#include "buddylist.h"
-#include "contact.h"
-#include "debug.h"
-#include "purpleprivate.h"
-#include "purpleprotocolserver.h"
-#include "util.h"
-
-typedef struct _PurpleGroupPrivate      PurpleGroupPrivate;
-
-/******************************************************************************
- * Private Data
- *****************************************************************************/
-struct _PurpleGroupPrivate {
-	char *name;               /* The name of this group.                    */
-	gboolean is_constructed;  /* Indicates if the group has finished being
-	                             constructed.                               */
-};
-
-/* Group property enums */
-enum
-{
-	PROP_0,
-	PROP_NAME,
-	N_PROPERTIES,
-};
-
-/******************************************************************************
- * Globals
- *****************************************************************************/
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleGroup, purple_group,
-		PURPLE_TYPE_COUNTING_NODE);
-
-/******************************************************************************
- * Group API
- *****************************************************************************/
-GSList *
-purple_group_get_accounts(G_GNUC_UNUSED PurpleGroup *group) {
-	return NULL;
-}
-
-gboolean
-purple_group_on_account(G_GNUC_UNUSED PurpleGroup *g,
-                        G_GNUC_UNUSED PurpleAccount *account)
-{
-	return FALSE;
-}
-
-/*
- * TODO: If merging, prompt the user if they want to merge.
- */
-void purple_group_set_name(PurpleGroup *source, const char *name) {
-	PurpleGroupPrivate *priv = NULL;
-	PurpleGroup *dest;
-	gchar *old_name;
-	gchar *new_name;
-	GList *moved_buddies = NULL;
-	GSList *accts;
-
-	g_return_if_fail(PURPLE_IS_GROUP(source));
-	g_return_if_fail(name != NULL);
-
-	priv = purple_group_get_instance_private(source);
-
-	new_name = purple_utf8_strip_unprintables(name);
-
-	if (*new_name == '\0' || purple_strequal(new_name, priv->name)) {
-		g_free(new_name);
-		return;
-	}
-
-	dest = purple_blist_find_group(new_name);
-	if (dest != NULL && purple_utf8_strcasecmp(priv->name,
-			purple_group_get_name(dest)) != 0) {
-		/* We're merging two groups */
-		PurpleBlistNode *prev, *child, *next;
-
-		prev = _purple_blist_get_last_child((PurpleBlistNode*)dest);
-		child = PURPLE_BLIST_NODE(source)->child;
-
-		/*
-		 * TODO: This seems like a dumb way to do this... why not just
-		 * append all children from the old group to the end of the new
-		 * one?  Protocols might be expecting to receive an add_buddy() for
-		 * each moved buddy...
-		 */
-		while (child)
-		{
-			next = child->next;
-			if (PURPLE_IS_META_CONTACT(child)) {
-				purple_blist_add_contact((PurpleMetaContact *)child, dest, prev);
-				prev = child;
-			} else {
-				purple_debug_error("blistnodetypes", "Unknown child type in group %s", priv->name);
-			}
-			child = next;
-		}
-
-		/* Make a copy of the old group name and then delete the old group */
-		old_name = g_strdup(priv->name);
-		purple_blist_remove_group(source);
-		source = dest;
-		g_free(new_name);
-	} else {
-		/* A simple rename */
-		PurpleBlistNode *cnode, *bnode;
-
-		/* Build a GList of all buddies in this group */
-		for (cnode = PURPLE_BLIST_NODE(source)->child; cnode != NULL; cnode = cnode->next) {
-			if (PURPLE_IS_META_CONTACT(cnode))
-				for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
-					moved_buddies = g_list_append(moved_buddies, bnode);
-		}
-
-		purple_blist_update_groups_cache(source, new_name);
-
-		old_name = priv->name;
-		priv->name = new_name;
-
-		g_object_notify_by_pspec(G_OBJECT(source), properties[PROP_NAME]);
-	}
-
-	/* Save our changes */
-	purple_blist_save_node(purple_blist_get_default(),
-	                       PURPLE_BLIST_NODE(source));
-
-	/* Update the UI */
-	purple_blist_update_node(purple_blist_get_default(),
-	                         PURPLE_BLIST_NODE(source));
-
-	/* Notify all protocols */
-	/* TODO: Is this condition needed?  Seems like it would always be TRUE */
-	if(old_name && !purple_strequal(priv->name, old_name)) {
-		for (accts = purple_group_get_accounts(source); accts;
-		     accts = g_slist_delete_link(accts, accts)) {
-			PurpleAccount *account = accts->data;
-			PurpleConnection *gc = NULL;
-			PurpleProtocol *protocol = NULL;
-			GList *buddies = NULL;
-
-			gc = purple_account_get_connection(account);
-
-			if(gc)
-				protocol = purple_connection_get_protocol(gc);
-
-			if(!protocol)
-				continue;
-
-			if(PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, rename_group)) {
-				purple_protocol_server_rename_group(PURPLE_PROTOCOL_SERVER(protocol),
-				                                    gc, old_name, source,
-				                                    buddies);
-			} else {
-				GList *cur, *groups = NULL;
-
-				/* Make a list of what the groups each buddy is in */
-				for(cur = buddies; cur; cur = cur->next) {
-					PurpleBlistNode *node = (PurpleBlistNode *)cur->data;
-					groups = g_list_prepend(groups, node->parent->parent);
-				}
-
-				g_list_free(groups);
-			}
-
-			g_list_free(buddies);
-		}
-	}
-	g_list_free(moved_buddies);
-	g_free(old_name);
-
-	g_object_notify_by_pspec(G_OBJECT(source), properties[PROP_NAME]);
-}
-
-const char *purple_group_get_name(PurpleGroup *group) {
-	PurpleGroupPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_GROUP(group), NULL);
-
-	priv = purple_group_get_instance_private(group);
-	return priv->name;
-}
-
-/******************************************************************************
- * GObject Stuff
- *****************************************************************************/
-/* Set method for GObject properties */
-static void
-purple_group_set_property(GObject *obj, guint param_id, const GValue *value,
-                          GParamSpec *pspec)
-{
-	PurpleGroup *group = PURPLE_GROUP(obj);
-	PurpleGroupPrivate *priv = purple_group_get_instance_private(group);
-
-	switch (param_id) {
-		case PROP_NAME:
-			if (priv->is_constructed)
-				purple_group_set_name(group, g_value_get_string(value));
-			else
-				priv->name =
-					purple_utf8_strip_unprintables(g_value_get_string(value));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-/* Get method for GObject properties */
-static void
-purple_group_get_property(GObject *obj, guint param_id, GValue *value,
-                          GParamSpec *pspec)
-{
-	PurpleGroup *group = PURPLE_GROUP(obj);
-
-	switch (param_id) {
-		case PROP_NAME:
-			g_value_set_string(value, purple_group_get_name(group));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-/* GObject initialization function */
-static void
-purple_group_init(G_GNUC_UNUSED PurpleGroup *group) {
-}
-
-/* Called when done constructing */
-static void
-purple_group_constructed(GObject *object) {
-	PurpleGroup *group = PURPLE_GROUP(object);
-	PurpleGroupPrivate *priv = purple_group_get_instance_private(group);
-
-	G_OBJECT_CLASS(purple_group_parent_class)->constructed(object);
-
-	purple_blist_new_node(purple_blist_get_default(),
-	                      PURPLE_BLIST_NODE(group));
-
-	priv->is_constructed = TRUE;
-}
-
-/* GObject finalize function */
-static void
-purple_group_finalize(GObject *object) {
-	PurpleGroupPrivate *priv = purple_group_get_instance_private(
-			PURPLE_GROUP(object));
-
-	g_free(priv->name);
-
-	G_OBJECT_CLASS(purple_group_parent_class)->finalize(object);
-}
-
-/* Class initializer function */
-static void
-purple_group_class_init(PurpleGroupClass *klass) {
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
-	obj_class->finalize = purple_group_finalize;
-	obj_class->constructed = purple_group_constructed;
-
-	/* Setup properties */
-	obj_class->get_property = purple_group_get_property;
-	obj_class->set_property = purple_group_set_property;
-
-	/**
-	 * PurpleGroup:name:
-	 *
-	 * The name of the group.
-	 *
-	 * Since: 3.0
-	 */
-	properties[PROP_NAME] = g_param_spec_string(
-		"name",
-		"Name",
-		"Name of the group.",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS
-	);
-
-	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
-}
-
-PurpleGroup *
-purple_group_new(const char *name) {
-	PurpleGroup *group;
-
-	if (name == NULL || name[0] == '\0')
-		name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
-	if (g_strcmp0(name, "Buddies") == 0)
-		name = PURPLE_BLIST_DEFAULT_GROUP_NAME;
-
-	group = purple_blist_find_group(name);
-	if (group != NULL)
-		return group;
-
-	return g_object_new(PURPLE_TYPE_GROUP, "name", name, NULL);
-}
-
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -1,17 +1,12 @@
 purple_coresources = [
 	'accounts.c',
 	'action.c',
-	'blistnode.c',
-	'buddylist.c',
 	'circularbuffer.c',
 	'cmds.c',
 	'connection.c',
-	'contact.c',
 	'conversations.c',
 	'core.c',
-	'countingnode.c',
 	'debug.c',
-	'group.c',
 	'image.c',
 	'media/backend-iface.c',
 	'media/candidate.c',
@@ -108,17 +103,12 @@
 purple_coreheaders = [
 	'accounts.h',
 	'action.h',
-	'blistnode.h',
-	'buddylist.h',
 	'circularbuffer.h',
 	'cmds.h',
 	'connection.h',
-	'contact.h',
 	'conversations.h',
 	'core.h',
-	'countingnode.h',
 	'debug.h',
-	'group.h',
 	'image.h',
 	'media.h',
 	'media-gst.h',
diff --git a/libpurple/purpleaccount.h b/libpurple/purpleaccount.h
--- a/libpurple/purpleaccount.h
+++ b/libpurple/purpleaccount.h
@@ -35,7 +35,6 @@
 typedef struct _PurpleAccount PurpleAccount;
 
 #include "connection.h"
-#include "group.h"
 #include "purpleconnectionerrorinfo.h"
 #include "purplecontactinfo.h"
 #include "purpleprotocol.h"
@@ -506,18 +505,6 @@
 gboolean purple_account_get_bool(PurpleAccount *account, const char *name, gboolean default_value);
 
 /**
- * purple_account_remove_group:
- * @account: The account.
- * @group: The group to remove.
- *
- * Removes a group from the server-side buddy list.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_account_remove_group(PurpleAccount *account, PurpleGroup *group);
-
-/**
  * purple_account_change_password:
  * @account: The account.
  * @orig_pw: The old password.
diff --git a/libpurple/purpleaccount.c b/libpurple/purpleaccount.c
--- a/libpurple/purpleaccount.c
+++ b/libpurple/purpleaccount.c
@@ -1613,21 +1613,6 @@
 }
 
 void
-purple_account_remove_group(PurpleAccount *account, 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_group(PURPLE_PROTOCOL_SERVER(protocol),
-		                                    gc, group);
-	}
-}
-
-void
 purple_account_change_password(PurpleAccount *account, const char *orig_pw,
                                const char *new_pw)
 {
diff --git a/libpurple/purpleprivate.h b/libpurple/purpleprivate.h
--- a/libpurple/purpleprivate.h
+++ b/libpurple/purpleprivate.h
@@ -51,17 +51,6 @@
 PurpleXmlNode *_purple_account_to_xmlnode(PurpleAccount *account);
 
 /**
- * _purple_blist_get_last_child:
- * @node:  The node whose last child is to be retrieved.
- *
- * Returns the last child of a particular node.
- *
- * Returns: The last child of the node.
- */
-G_GNUC_INTERNAL
-PurpleBlistNode *_purple_blist_get_last_child(PurpleBlistNode *node);
-
-/**
  * _purple_connection_wants_to_die:
  * @gc:  The connection to check
  *
diff --git a/libpurple/purpleprotocolserver.h b/libpurple/purpleprotocolserver.h
--- a/libpurple/purpleprotocolserver.h
+++ b/libpurple/purpleprotocolserver.h
@@ -31,7 +31,6 @@
 #include <glib-object.h>
 
 #include "connection.h"
-#include "group.h"
 #include "purpleaccount.h"
 #include "purplemessage.h"
 #include "purpleprotocol.h"
@@ -66,10 +65,6 @@
 
 	void (*change_passwd)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_pass, const gchar *new_pass);
 
-	void (*rename_group)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_name, PurpleGroup *group, GList *moved_buddies);
-
-	void (*remove_group)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleGroup *group);
-
 	gint (*send_raw)(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *buf, gint len);
 
 	/*< private >*/
@@ -131,35 +126,6 @@
 void purple_protocol_server_change_passwd(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_pass, const gchar *new_pass);
 
 /**
- * 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 GObject): A list of #PurpleBuddy's being
- *                 moved as part of this rename.
- *
- * Renames the group named @old_name to the new @group.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_protocol_server_rename_group(PurpleProtocolServer *protocol_server, PurpleConnection *connection, const gchar *old_name, PurpleGroup *group, GList *moved_buddies);
-
-/**
- * purple_protocol_server_remove_group:
- * @protocol_server: The #PurpleProtocolServer instance.
- * @connection: The #PurpleConnection instance.
- * @group: The #PurpleGroup instance.
- *
- * Removes @group from the server side contact list.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_protocol_server_remove_group(PurpleProtocolServer *protocol_server, PurpleConnection *connection, PurpleGroup *group);
-
-/**
  * purple_protocol_server_send_raw:
  * @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
@@ -102,42 +102,6 @@
 	}
 }
 
-void
-purple_protocol_server_rename_group(PurpleProtocolServer *protocol_server,
-                                    PurpleConnection *connection,
-                                    const gchar *old_name, PurpleGroup *group,
-                                    GList *moved_buddies)
-{
-	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_GROUP(group));
-
-	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
-	if(iface != NULL && iface->rename_group != NULL) {
-		iface->rename_group(protocol_server, connection, old_name, group,
-		                    moved_buddies);
-	}
-}
-
-void
-purple_protocol_server_remove_group(PurpleProtocolServer *protocol_server,
-                                    PurpleConnection *connection,
-                                    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_GROUP(group));
-
-	iface = PURPLE_PROTOCOL_SERVER_GET_IFACE(protocol_server);
-	if(iface != NULL && iface->remove_group != NULL) {
-		iface->remove_group(protocol_server, connection, group);
-	}
-}
-
 gint
 purple_protocol_server_send_raw(PurpleProtocolServer *protocol_server,
                                 PurpleConnection *connection,
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,16 +1,11 @@
 libpurple/accounts.c
 libpurple/action.c
-libpurple/blistnode.c
-libpurple/buddylist.c
 libpurple/circularbuffer.c
 libpurple/cmds.c
 libpurple/connection.c
-libpurple/contact.c
 libpurple/conversations.c
 libpurple/core.c
-libpurple/countingnode.c
 libpurple/debug.c
-libpurple/group.c
 libpurple/image.c
 libpurple/media/backend-iface.c
 libpurple/media.c
