Merged default branch soc.2013.gobjectification

Sun, 23 Jun 2013 13:35:53 +0530

author
Ankit Vani <a@nevitus.org>
date
Sun, 23 Jun 2013 13:35:53 +0530
branch
soc.2013.gobjectification
changeset 34619
b8d8c1516d74
parent 34618
949097b6b371 (diff)
parent 34223
d3738c010ece (current diff)
child 34620
e49aa67344e1

Merged default branch

.hgignore file | annotate | diff | comparison | revisions
libpurple/ciphers/descipher.c file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/bosh.c file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoochat.c file | annotate | diff | comparison | revisions
libpurple/proxy.c file | annotate | diff | comparison | revisions
libpurple/tests/test_cipher.c file | annotate | diff | comparison | revisions
--- a/.hgignore	Sun Jun 23 02:43:06 2013 -0500
+++ b/.hgignore	Sun Jun 23 13:35:53 2013 +0530
@@ -59,6 +59,7 @@
 libpurple/dbus-signals.c
 libpurple/dbus-types.c
 libpurple/dbus-types.h
+libpurple/enums.[ch]
 libpurple/example/nullclient
 libpurple/gconf/purple.schemas$
 libpurple/marshallers.[ch]
--- a/configure.ac	Sun Jun 23 02:43:06 2013 -0500
+++ b/configure.ac	Sun Jun 23 13:35:53 2013 +0530
@@ -353,6 +353,9 @@
 GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
 AC_SUBST(GLIB_GENMARSHAL)
 
+GLIB_MKENUMS=`pkg-config --variable=glib_mkenums glib-2.0`
+AC_SUBST(GLIB_MKENUMS)
+
 AC_ARG_WITH([extraversion],
 			AS_HELP_STRING([--with-extraversion=STRING],
 						   [extra version number to be displayed in Help->About and --help (for packagers)]),
--- a/finch/gntaccount.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/finch/gntaccount.c	Sun Jun 23 13:35:53 2013 +0530
@@ -188,7 +188,7 @@
 
 	/* Alias */
 	value = gnt_entry_get_text(GNT_ENTRY(dialog->alias));
-	purple_account_set_alias(account, value);
+	purple_account_set_private_alias(account, value);
 
 	/* Remember password and password */
 	purple_account_set_remember_password(account,
@@ -628,7 +628,7 @@
 	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Alias:")));
 	gnt_box_add_widget(GNT_BOX(hbox), entry);
 	if (account)
-		gnt_entry_set_text(GNT_ENTRY(entry), purple_account_get_alias(account));
+		gnt_entry_set_text(GNT_ENTRY(entry), purple_account_get_private_alias(account));
 
 	/* User options */
 	update_user_options(dialog);
@@ -1157,7 +1157,8 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL
+	NULL,
+	NULL, NULL, NULL, NULL
 };
 
 PurpleAccountUiOps *finch_accounts_get_ui_ops()
--- a/finch/gntblist.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/finch/gntblist.c	Sun Jun 23 13:35:53 2013 +0530
@@ -30,7 +30,6 @@
 #include <blist.h>
 #include <log.h>
 #include <notify.h>
-#include <privacy.h>
 #include <request.h>
 #include <savedstatuses.h>
 #include <server.h>
@@ -1267,8 +1266,8 @@
 	PurpleAccount *account = purple_buddy_get_account(buddy);
 	const char *name = purple_buddy_get_name(buddy);
 
-	block ? purple_privacy_deny(account, name, FALSE, FALSE) :
-		purple_privacy_allow(account, name, FALSE, FALSE);
+	block ? purple_account_privacy_deny(account, name) :
+		purple_account_privacy_allow(account, name);
 }
 
 static void
@@ -1310,7 +1309,7 @@
 	}
 
 	account = purple_buddy_get_account(buddy);
-	permitted = purple_privacy_check(account, purple_buddy_get_name(buddy));
+	permitted = purple_account_privacy_check(account, purple_buddy_get_name(buddy));
 
 	item = gnt_menuitem_check_new(_("Blocked"));
 	gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item), !permitted);
@@ -2673,9 +2672,9 @@
 	const char *name = purple_request_fields_get_string(fields,  "screenname");
 	if (account && name && *name != '\0') {
 		if (purple_request_fields_get_choice(fields, "block") == 1) {
-			purple_privacy_deny(account, name, FALSE, FALSE);
+			purple_account_privacy_deny(account, name);
 		} else {
-			purple_privacy_allow(account, name, FALSE, FALSE);
+			purple_account_privacy_allow(account, name);
 		}
 	}
 }
--- a/finch/gntconv.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/finch/gntconv.c	Sun Jun 23 13:35:53 2013 +0530
@@ -1063,7 +1063,7 @@
 	{
 		who = purple_connection_get_display_name(purple_account_get_connection(account));
 		if (!who)
-			who = purple_account_get_alias(account);
+			who = purple_account_get_private_alias(account);
 		if (!who)
 			who = purple_account_get_username(account);
 	}
--- a/finch/gntpounce.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/finch/gntpounce.c	Sun Jun 23 13:35:53 2013 +0530
@@ -849,7 +849,7 @@
 		 * NULL to the account alias if we have it or the account
 		 * name if that's all we have
 		 */
-		if ((name_shown = purple_account_get_alias(account)) == NULL)
+		if ((name_shown = purple_account_get_private_alias(account)) == NULL)
 			name_shown = purple_account_get_username(account);
 
 		if (reason == NULL)
--- a/libpurple/Makefile.am	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/Makefile.am	Sun Jun 23 13:35:53 2013 +0530
@@ -38,20 +38,24 @@
 
 purple_coresources = \
 	account.c \
+	accounts.c \
 	accountopt.c \
 	blist.c \
 	buddyicon.c \
 	certificate.c \
 	cipher.c \
-	circbuffer.c \
+	circularbuffer.c \
 	cmds.c \
 	connection.c \
 	conversation.c \
+	conversationtypes.c \
+	conversations.c \
 	core.c \
 	debug.c \
 	desktopitem.c \
 	eventloop.c \
 	ft.c \
+	hash.c \
 	http.c \
 	idle.c \
 	imgstore.c \
@@ -74,7 +78,6 @@
 	pluginpref.c \
 	pounce.c \
 	prefs.c \
-	privacy.c \
 	proxy.c \
 	prpl.c \
 	request.c \
@@ -103,25 +106,30 @@
 	whiteboard.c
 
 purple_builtsources = \
+	enums.c \
 	marshallers.c
 
 purple_coreheaders = \
 	account.h \
+	accounts.h \
 	accountopt.h \
 	blist.h \
 	buddyicon.h \
 	certificate.h \
 	cipher.h \
-	circbuffer.h \
+	circularbuffer.h \
 	cmds.h \
 	connection.h \
 	conversation.h \
+	conversationtypes.h \
+	conversations.h \
 	core.h \
 	dbus-maybe.h \
 	debug.h \
 	desktopitem.h \
 	eventloop.h \
 	ft.h \
+	hash.h \
 	http.h \
 	idle.h \
 	imgstore.h \
@@ -139,7 +147,6 @@
 	pluginpref.h \
 	pounce.h \
 	prefs.h \
-	privacy.h \
 	proxy.h \
 	prpl.h \
 	request.h \
@@ -172,7 +179,23 @@
 	codec.h \
 	enum-types.h
 
-purple_builtheaders = purple.h version.h marshallers.h
+purple_builtheaders = purple.h version.h enums.h marshallers.h
+
+purple_enumheaders = \
+	account.h \
+	accounts.h \
+	cipher.h \
+	circularbuffer.h \
+	conversation.h \
+	conversationtypes.h \
+	conversations.h \
+	hash.h \
+	smiley.h \
+	sound-theme.h \
+	sound-theme-loader.h \
+	theme.h \
+	theme-loader.h \
+	theme-manager.h
 
 marshallers.h: marshallers.list
 	$(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=purple_smarshal $(srcdir)/marshallers.list --header > marshallers.h
@@ -181,6 +204,12 @@
 	$(AM_V_GEN)echo "#include \"marshallers.h\"" > marshallers.c
 	$(AM_V_at)$(GLIB_GENMARSHAL) --prefix=purple_smarshal $(srcdir)/marshallers.list --body >> marshallers.c
 
+enums.h: enums.h.template $(purple_enumheaders)
+	$(AM_V_GEN)$(GLIB_MKENUMS) --template enums.h.template $(purple_enumheaders) > $@
+
+enums.c: enums.c.template $(purple_enumheaders)
+	$(AM_V_GEN)$(GLIB_MKENUMS) --template enums.c.template $(purple_enumheaders) > $@
+
 if ENABLE_DBUS
 
 CLEANFILES = \
@@ -190,6 +219,8 @@
 	dbus-signals.c \
 	dbus-types.c \
 	dbus-types.h \
+	enums.c \
+	enums.h \
 	marshallers.c \
 	marshallers.h \
 	purple-client-bindings.c \
@@ -201,8 +232,8 @@
 dbus_sources  = dbus-server.c dbus-useful.c
 dbus_headers  = dbus-bindings.h dbus-purple.h dbus-server.h dbus-useful.h dbus-define-api.h dbus-types.h
 
-dbus_exported = dbus-useful.h dbus-define-api.h account.h blist.h buddyicon.h \
-                connection.h conversation.h core.h ft.h log.h notify.h prefs.h roomlist.h \
+dbus_exported = dbus-useful.h dbus-define-api.h accounts.h blist.h buddyicon.h \
+                connection.h conversations.h core.h ft.h log.h notify.h prefs.h roomlist.h \
                 savedstatuses.h smiley.h status.h server.h util.h xmlnode.h prpl.h
 
 purple_build_coreheaders = $(addprefix $(srcdir)/, $(purple_coreheaders)) \
@@ -304,7 +335,10 @@
 mediainclude_HEADERS = \
 	$(addprefix $(srcdir)/media/, $(purple_mediaheaders))
 
-libpurple_la_DEPENDENCIES = $(STATIC_LINK_LIBS)
+libpurple_la_DEPENDENCIES = \
+	$(STATIC_LINK_LIBS) \
+	ciphers/libpurple-ciphers.la
+
 libpurple_la_LDFLAGS = -export-dynamic -version-info $(PURPLE_LT_VERSION_INFO) -no-undefined
 libpurple_la_LIBADD = \
 	$(STATIC_LINK_LIBS) \
--- a/libpurple/Makefile.mingw	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/Makefile.mingw	Sun Jun 23 13:35:53 2013 +0530
@@ -61,22 +61,27 @@
 
 C_SRC =	\
 			account.c \
+			accounts.c \
 			accountopt.c \
 			blist.c \
 			buddyicon.c \
 			certificate.c \
 			cipher.c \
-			ciphers/aes.c \
-			ciphers/des.c \
-			ciphers/gchecksum.c \
-			ciphers/hmac.c \
-			ciphers/md4.c \
-			ciphers/pbkdf2.c \
-			ciphers/rc4.c \
-			circbuffer.c \
+			ciphers/aescipher.c \
+			ciphers/des3cipher.c \
+			ciphers/descipher.c \
+			ciphers/hmaccipher.c \
+			ciphers/md4hash.c \
+			ciphers/md5hash.c \
+			ciphers/pbkdf2cipher.c \
+			ciphers/rc4cipher.c \
+			ciphers/sha1hash.c \
+			ciphers/sha256hash.c \
+			circularbuffer.c \
 			cmds.c \
 			connection.c \
 			conversation.c \
+			conversations.c \
 			core.c \
 			debug.c \
 			dnsquery.c \
--- a/libpurple/account.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/account.c	Sun Jun 23 13:35:53 2013 +0530
@@ -24,38 +24,77 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 #include "internal.h"
-#include "account.h"
+#include "accounts.h"
 #include "core.h"
 #include "dbus-maybe.h"
 #include "debug.h"
-#include "keyring.h"
 #include "network.h"
 #include "notify.h"
 #include "pounce.h"
 #include "prefs.h"
-#include "privacy.h"
-#include "prpl.h"
 #include "request.h"
 #include "server.h"
 #include "signals.h"
-#include "status.h"
 #include "util.h"
-#include "xmlnode.h"
-
-/* TODO: Should use PurpleValue instead of this?  What about "ui"? */
+
+#define PURPLE_ACCOUNT_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_ACCOUNT, PurpleAccountPrivate))
+
 typedef struct
 {
-	PurplePrefType type;
-
+	char *username;             /**< The username.                          */
+	char *alias;                /**< How you appear to yourself.            */
+	char *password;             /**< The account password.                  */
+	char *user_info;            /**< User information.                      */
+
+	char *buddy_icon_path;      /**< The buddy icon's non-cached path.      */
+
+	gboolean remember_pass;     /**< Remember the password.                 */
+
+	/*
+	 * TODO: After a GObject representing a protocol is ready, use it
+	 * here instead of the protocol ID.
+	 */
+	char *protocol_id;          /**< The ID of the protocol.                */
+
+	PurpleConnection *gc;         /**< The connection handle.               */
+	gboolean disconnecting;     /**< The account is currently disconnecting */
+
+	GHashTable *settings;       /**< Protocol-specific settings.            */
+	GHashTable *ui_settings;    /**< UI-specific settings.                  */
+
+	PurpleProxyInfo *proxy_info;  /**< Proxy information.  This will be set */
+								/*   to NULL when the account inherits      */
+								/*   proxy settings from global prefs.      */
+
+	/*
+	 * TODO: Supplementing the next two linked lists with hash tables
+	 * should help performance a lot when these lists are long.  This
+	 * matters quite a bit for protocols like MSN, where all your
+	 * buddies are added to your permit list.  Currently we have to
+	 * iterate through the entire list if we want to check if someone
+	 * is permitted or denied.  We should do this for 3.0.0.
+	 * Or maybe use a GTree.
+	 */
+	GSList *permit;             /**< Permit list.                           */
+	GSList *deny;               /**< Deny list.                             */
+	PurpleAccountPrivacyType privacy_type;  /**< The permit/deny setting.   */
+
+	GList *status_types;        /**< Status types.                          */
+
+	PurplePresence *presence;     /**< Presence.                            */
+	PurpleLog *system_log;        /**< The system log                       */
+
+	PurpleAccountRegistrationCb registration_cb;
+	void *registration_cb_user_data;
+
+	PurpleConnectionErrorInfo *current_error;	/**< Errors */
+} PurpleAccountPrivate;
+
+typedef struct
+{
 	char *ui;
-
-	union
-	{
-		int integer;
-		char *string;
-		gboolean boolean;
-
-	} value;
+	GValue value;
 
 } PurpleAccountSetting;
 
@@ -77,1073 +116,37 @@
 	gpointer data;
 } PurpleCallbackBundle;
 
-static PurpleAccountUiOps *account_ui_ops = NULL;
-
-static GList   *accounts = NULL;
-static guint    save_timer = 0;
-static gboolean accounts_loaded = FALSE;
-
-static GList *handles = NULL;
-
-static void set_current_error(PurpleAccount *account,
-	PurpleConnectionErrorInfo *new_err);
-
-/*********************************************************************
- * Writing to disk                                                   *
- *********************************************************************/
-
-static void
-setting_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
-{
-	const char *name;
-	PurpleAccountSetting *setting;
-	xmlnode *node, *child;
-	char buf[21];
-
-	name    = (const char *)key;
-	setting = (PurpleAccountSetting *)value;
-	node    = (xmlnode *)user_data;
-
-	child = xmlnode_new_child(node, "setting");
-	xmlnode_set_attrib(child, "name", name);
-
-	if (setting->type == PURPLE_PREF_INT) {
-		xmlnode_set_attrib(child, "type", "int");
-		g_snprintf(buf, sizeof(buf), "%d", setting->value.integer);
-		xmlnode_insert_data(child, buf, -1);
-	}
-	else if (setting->type == PURPLE_PREF_STRING && setting->value.string != NULL) {
-		xmlnode_set_attrib(child, "type", "string");
-		xmlnode_insert_data(child, setting->value.string, -1);
-	}
-	else if (setting->type == PURPLE_PREF_BOOLEAN) {
-		xmlnode_set_attrib(child, "type", "bool");
-		g_snprintf(buf, sizeof(buf), "%d", setting->value.boolean);
-		xmlnode_insert_data(child, buf, -1);
-	}
-}
-
-static void
-ui_setting_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
-{
-	const char *ui;
-	GHashTable *table;
-	xmlnode *node, *child;
-
-	ui    = (const char *)key;
-	table = (GHashTable *)value;
-	node  = (xmlnode *)user_data;
-
-	if (g_hash_table_size(table) > 0)
-	{
-		child = xmlnode_new_child(node, "settings");
-		xmlnode_set_attrib(child, "ui", ui);
-		g_hash_table_foreach(table, setting_to_xmlnode, child);
-	}
-}
-
-static xmlnode *
-status_attr_to_xmlnode(const PurpleStatus *status, const PurpleStatusType *type, const PurpleStatusAttr *attr)
-{
-	xmlnode *node;
-	const char *id;
-	char *value = NULL;
-	PurpleStatusAttr *default_attr;
-	PurpleValue *default_value;
-	PurpleType attr_type;
-	PurpleValue *attr_value;
-
-	id = purple_status_attr_get_id(attr);
-	g_return_val_if_fail(id, NULL);
-
-	attr_value = purple_status_get_attr_value(status, id);
-	g_return_val_if_fail(attr_value, NULL);
-	attr_type = purple_value_get_type(attr_value);
-
-	/*
-	 * If attr_value is a different type than it should be
-	 * then don't write it to the file.
-	 */
-	default_attr = purple_status_type_get_attr(type, id);
-	default_value = purple_status_attr_get_value(default_attr);
-	if (attr_type != purple_value_get_type(default_value))
-		return NULL;
-
-	/*
-	 * If attr_value is the same as the default for this status
-	 * then there is no need to write it to the file.
-	 */
-	if (attr_type == PURPLE_TYPE_STRING)
-	{
-		const char *string_value = purple_value_get_string(attr_value);
-		const char *default_string_value = purple_value_get_string(default_value);
-		if (purple_strequal(string_value, default_string_value))
-			return NULL;
-		value = g_strdup(purple_value_get_string(attr_value));
-	}
-	else if (attr_type == PURPLE_TYPE_INT)
-	{
-		int int_value = purple_value_get_int(attr_value);
-		if (int_value == purple_value_get_int(default_value))
-			return NULL;
-		value = g_strdup_printf("%d", int_value);
-	}
-	else if (attr_type == PURPLE_TYPE_BOOLEAN)
-	{
-		gboolean boolean_value = purple_value_get_boolean(attr_value);
-		if (boolean_value == purple_value_get_boolean(default_value))
-			return NULL;
-		value = g_strdup(boolean_value ?
-								"true" : "false");
-	}
-	else
-	{
-		return NULL;
-	}
-
-	g_return_val_if_fail(value, NULL);
-
-	node = xmlnode_new("attribute");
-
-	xmlnode_set_attrib(node, "id", id);
-	xmlnode_set_attrib(node, "value", value);
-
-	g_free(value);
-
-	return node;
-}
-
-static xmlnode *
-status_attrs_to_xmlnode(const PurpleStatus *status)
-{
-	PurpleStatusType *type = purple_status_get_type(status);
-	xmlnode *node, *child;
-	GList *attrs, *attr;
-
-	node = xmlnode_new("attributes");
-
-	attrs = purple_status_type_get_attrs(type);
-	for (attr = attrs; attr != NULL; attr = attr->next)
-	{
-		child = status_attr_to_xmlnode(status, type, (const PurpleStatusAttr *)attr->data);
-		if (child)
-			xmlnode_insert_child(node, child);
-	}
-
-	return node;
-}
-
-static xmlnode *
-status_to_xmlnode(const PurpleStatus *status)
-{
-	xmlnode *node, *child;
-
-	node = xmlnode_new("status");
-	xmlnode_set_attrib(node, "type", purple_status_get_id(status));
-	if (purple_status_get_name(status) != NULL)
-		xmlnode_set_attrib(node, "name", purple_status_get_name(status));
-	xmlnode_set_attrib(node, "active", purple_status_is_active(status) ? "true" : "false");
-
-	child = status_attrs_to_xmlnode(status);
-	xmlnode_insert_child(node, child);
-
-	return node;
-}
-
-static xmlnode *
-statuses_to_xmlnode(const PurplePresence *presence)
-{
-	xmlnode *node, *child;
-	GList *statuses;
-	PurpleStatus *status;
-
-	node = xmlnode_new("statuses");
-
-	statuses = purple_presence_get_statuses(presence);
-	for (; statuses != NULL; statuses = statuses->next)
-	{
-		status = statuses->data;
-		if (purple_status_type_is_saveable(purple_status_get_type(status)))
-		{
-			child = status_to_xmlnode(status);
-			xmlnode_insert_child(node, child);
-		}
-	}
-
-	return node;
-}
-
-static xmlnode *
-proxy_settings_to_xmlnode(PurpleProxyInfo *proxy_info)
-{
-	xmlnode *node, *child;
-	PurpleProxyType proxy_type;
-	const char *value;
-	int int_value;
-	char buf[21];
-
-	proxy_type = purple_proxy_info_get_type(proxy_info);
-
-	node = xmlnode_new("proxy");
-
-	child = xmlnode_new_child(node, "type");
-	xmlnode_insert_data(child,
-			(proxy_type == PURPLE_PROXY_USE_GLOBAL ? "global" :
-			 proxy_type == PURPLE_PROXY_NONE       ? "none"   :
-			 proxy_type == PURPLE_PROXY_HTTP       ? "http"   :
-			 proxy_type == PURPLE_PROXY_SOCKS4     ? "socks4" :
-			 proxy_type == PURPLE_PROXY_SOCKS5     ? "socks5" :
-			 proxy_type == PURPLE_PROXY_TOR        ? "tor" :
-			 proxy_type == PURPLE_PROXY_USE_ENVVAR ? "envvar" : "unknown"), -1);
-
-	if ((value = purple_proxy_info_get_host(proxy_info)) != NULL)
-	{
-		child = xmlnode_new_child(node, "host");
-		xmlnode_insert_data(child, value, -1);
-	}
-
-	if ((int_value = purple_proxy_info_get_port(proxy_info)) != 0)
-	{
-		g_snprintf(buf, sizeof(buf), "%d", int_value);
-		child = xmlnode_new_child(node, "port");
-		xmlnode_insert_data(child, buf, -1);
-	}
-
-	if ((value = purple_proxy_info_get_username(proxy_info)) != NULL)
-	{
-		child = xmlnode_new_child(node, "username");
-		xmlnode_insert_data(child, value, -1);
-	}
-
-	if ((value = purple_proxy_info_get_password(proxy_info)) != NULL)
-	{
-		child = xmlnode_new_child(node, "password");
-		xmlnode_insert_data(child, value, -1);
-	}
-
-	return node;
-}
-
-static xmlnode *
-current_error_to_xmlnode(PurpleConnectionErrorInfo *err)
-{
-	xmlnode *node, *child;
-	char type_str[3];
-
-	node = xmlnode_new("current_error");
-
-	if(err == NULL)
-		return node;
-
-	/* It doesn't make sense to have transient errors persist across a
-	 * restart.
-	 */
-	if(!purple_connection_error_is_fatal (err->type))
-		return node;
-
-	child = xmlnode_new_child(node, "type");
-	g_snprintf(type_str, sizeof(type_str), "%u", err->type);
-	xmlnode_insert_data(child, type_str, -1);
-
-	child = xmlnode_new_child(node, "description");
-	if(err->description) {
-		char *utf8ized = purple_utf8_try_convert(err->description);
-		if(utf8ized == NULL)
-			utf8ized = purple_utf8_salvage(err->description);
-		xmlnode_insert_data(child, utf8ized, -1);
-		g_free(utf8ized);
-	}
-
-	return node;
-}
-
-static xmlnode *
-account_to_xmlnode(PurpleAccount *account)
-{
-	xmlnode *node, *child;
-	const char *tmp;
-	PurplePresence *presence;
-	PurpleProxyInfo *proxy_info;
-
-	node = xmlnode_new("account");
-
-	child = xmlnode_new_child(node, "protocol");
-	xmlnode_insert_data(child, purple_account_get_protocol_id(account), -1);
-
-	child = xmlnode_new_child(node, "name");
-	xmlnode_insert_data(child, purple_account_get_username(account), -1);
-
-	if (purple_account_get_remember_password(account))
-	{
-		const char *keyring_id = NULL;
-		const char *mode = NULL;
-		char *data = NULL;
-		GError *error = NULL;
-		GDestroyNotify destroy = NULL;
-		gboolean exported = purple_keyring_export_password(account,
-			&keyring_id, &mode, &data, &error, &destroy);
-
-		if (error != NULL) {
-			purple_debug_error("account",
-				"Failed to export password for account %s: %s.\n",
-				purple_account_get_username(account),
-				error->message);
-		} else if (exported) {
-			child = xmlnode_new_child(node, "password");
-			if (keyring_id != NULL)
-				xmlnode_set_attrib(child, "keyring_id", keyring_id);
-			if (mode != NULL)
-				xmlnode_set_attrib(child, "mode", mode);
-			if (data != NULL)
-				xmlnode_insert_data(child, data, -1);
-
-			if (destroy != NULL)
-				destroy(data);
-		}
-	}
-
-	if ((tmp = purple_account_get_alias(account)) != NULL)
-	{
-		child = xmlnode_new_child(node, "alias");
-		xmlnode_insert_data(child, tmp, -1);
-	}
-
-	if ((presence = purple_account_get_presence(account)) != NULL)
-	{
-		child = statuses_to_xmlnode(presence);
-		xmlnode_insert_child(node, child);
-	}
-
-	if ((tmp = purple_account_get_user_info(account)) != NULL)
-	{
-		/* TODO: Do we need to call purple_str_strip_char(tmp, '\r') here? */
-		child = xmlnode_new_child(node, "userinfo");
-		xmlnode_insert_data(child, tmp, -1);
-	}
-
-	if (g_hash_table_size(account->settings) > 0)
-	{
-		child = xmlnode_new_child(node, "settings");
-		g_hash_table_foreach(account->settings, setting_to_xmlnode, child);
-	}
-
-	if (g_hash_table_size(account->ui_settings) > 0)
-	{
-		g_hash_table_foreach(account->ui_settings, ui_setting_to_xmlnode, node);
-	}
-
-	if ((proxy_info = purple_account_get_proxy_info(account)) != NULL)
-	{
-		child = proxy_settings_to_xmlnode(proxy_info);
-		xmlnode_insert_child(node, child);
-	}
-
-	child = current_error_to_xmlnode(account->current_error);
-	xmlnode_insert_child(node, child);
-
-	return node;
-}
-
-static xmlnode *
-accounts_to_xmlnode(void)
-{
-	xmlnode *node, *child;
-	GList *cur;
-
-	node = xmlnode_new("account");
-	xmlnode_set_attrib(node, "version", "1.0");
-
-	for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
-	{
-		child = account_to_xmlnode(cur->data);
-		xmlnode_insert_child(node, child);
-	}
-
-	return node;
-}
-
-static void
-sync_accounts(void)
-{
-	xmlnode *node;
-	char *data;
-
-	if (!accounts_loaded)
-	{
-		purple_debug_error("account", "Attempted to save accounts before "
-						 "they were read!\n");
-		return;
-	}
-
-	node = accounts_to_xmlnode();
-	data = xmlnode_to_formatted_str(node, NULL);
-	purple_util_write_data_to_file("accounts.xml", data, -1);
-	g_free(data);
-	xmlnode_free(node);
-}
-
-static gboolean
-save_cb(gpointer data)
-{
-	sync_accounts();
-	save_timer = 0;
-	return FALSE;
-}
-
-static void
-schedule_accounts_save(void)
-{
-	if (save_timer == 0)
-		save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
-}
-
-
-/*********************************************************************
- * Reading from disk                                                 *
- *********************************************************************/
-static void
-migrate_yahoo_japan(PurpleAccount *account)
-{
-	/* detect a Yahoo! JAPAN account that existed prior to 2.6.0 and convert it
-	 * to use the new prpl-yahoojp.  Also remove the account-specific settings
-	 * we no longer need */
-
-	if(purple_strequal(purple_account_get_protocol_id(account), "prpl-yahoo")) {
-		if(purple_account_get_bool(account, "yahoojp", FALSE)) {
-			const char *serverjp = purple_account_get_string(account, "serverjp", NULL);
-			const char *xferjp_host = purple_account_get_string(account, "xferjp_host", NULL);
-
-			g_return_if_fail(serverjp != NULL);
-			g_return_if_fail(xferjp_host != NULL);
-
-			purple_account_set_string(account, "server", serverjp);
-			purple_account_set_string(account, "xfer_host", xferjp_host);
-
-			purple_account_set_protocol_id(account, "prpl-yahoojp");
-		}
-
-		/* these should always be nuked */
-		purple_account_remove_setting(account, "yahoojp");
-		purple_account_remove_setting(account, "serverjp");
-		purple_account_remove_setting(account, "xferjp_host");
-
-	}
-}
-
-static void
-migrate_icq_server(PurpleAccount *account)
-{
-	/* Migrate the login server setting for ICQ accounts.  See
-	 * 'mtn log --last 1 --no-graph --from b6d7712e90b68610df3bd2d8cbaf46d94c8b3794'
-	 * for details on the change. */
-
-	if(purple_strequal(purple_account_get_protocol_id(account), "prpl-icq")) {
-		const char *tmp = purple_account_get_string(account, "server", NULL);
-
-		/* Non-secure server */
-		if(purple_strequal(tmp,	"login.messaging.aol.com") ||
-				purple_strequal(tmp, "login.oscar.aol.com"))
-			purple_account_set_string(account, "server", "login.icq.com");
-
-		/* Secure server */
-		if(purple_strequal(tmp, "slogin.oscar.aol.com"))
-			purple_account_set_string(account, "server", "slogin.icq.com");
-	}
-}
-
-static void
-migrate_xmpp_encryption(PurpleAccount *account)
-{
-	/* When this is removed, nuke the "old_ssl" and "require_tls" settings */
-	if (g_str_equal(purple_account_get_protocol_id(account), "prpl-jabber")) {
-		const char *sec = purple_account_get_string(account, "connection_security", "");
-
-		if (g_str_equal("", sec)) {
-			const char *val = "require_tls";
-			if (purple_account_get_bool(account, "old_ssl", FALSE))
-				val = "old_ssl";
-			else if (!purple_account_get_bool(account, "require_tls", TRUE))
-				val = "opportunistic_tls";
-
-			purple_account_set_string(account, "connection_security", val);
-		}
-	}
-}
-
-static void
-parse_settings(xmlnode *node, PurpleAccount *account)
+/* GObject Property enums */
+enum
 {
-	const char *ui;
-	xmlnode *child;
-
-	/* Get the UI string, if these are UI settings */
-	ui = xmlnode_get_attrib(node, "ui");
-
-	/* Read settings, one by one */
-	for (child = xmlnode_get_child(node, "setting"); child != NULL;
-			child = xmlnode_get_next_twin(child))
-	{
-		const char *name, *str_type;
-		PurplePrefType type;
-		char *data;
-
-		name = xmlnode_get_attrib(child, "name");
-		if (name == NULL)
-			/* Ignore this setting */
-			continue;
-
-		str_type = xmlnode_get_attrib(child, "type");
-		if (str_type == NULL)
-			/* Ignore this setting */
-			continue;
-
-		if (purple_strequal(str_type, "string"))
-			type = PURPLE_PREF_STRING;
-		else if (purple_strequal(str_type, "int"))
-			type = PURPLE_PREF_INT;
-		else if (purple_strequal(str_type, "bool"))
-			type = PURPLE_PREF_BOOLEAN;
-		else
-			/* Ignore this setting */
-			continue;
-
-		data = xmlnode_get_data(child);
-		if (data == NULL)
-			/* Ignore this setting */
-			continue;
-
-		if (ui == NULL)
-		{
-			if (type == PURPLE_PREF_STRING)
-				purple_account_set_string(account, name, data);
-			else if (type == PURPLE_PREF_INT)
-				purple_account_set_int(account, name, atoi(data));
-			else if (type == PURPLE_PREF_BOOLEAN)
-				purple_account_set_bool(account, name,
-									  (*data == '0' ? FALSE : TRUE));
-		} else {
-			if (type == PURPLE_PREF_STRING)
-				purple_account_set_ui_string(account, ui, name, data);
-			else if (type == PURPLE_PREF_INT)
-				purple_account_set_ui_int(account, ui, name, atoi(data));
-			else if (type == PURPLE_PREF_BOOLEAN)
-				purple_account_set_ui_bool(account, ui, name,
-										 (*data == '0' ? FALSE : TRUE));
-		}
-
-		g_free(data);
-	}
-
-	/* we do this here because we need access to account settings to determine
-	 * if we can/should migrate an old Yahoo! JAPAN account */
-	migrate_yahoo_japan(account);
-	/* we do this here because we need access to account settings to determine
-	 * if we can/should migrate an ICQ account's server setting */
-	migrate_icq_server(account);
-	/* we do this here because we need to do it before the user views the
-	 * Edit Account dialog. */
-	migrate_xmpp_encryption(account);
-}
-
-static GList *
-parse_status_attrs(xmlnode *node, PurpleStatus *status)
-{
-	GList *list = NULL;
-	xmlnode *child;
-	PurpleValue *attr_value;
-
-	for (child = xmlnode_get_child(node, "attribute"); child != NULL;
-			child = xmlnode_get_next_twin(child))
-	{
-		const char *id = xmlnode_get_attrib(child, "id");
-		const char *value = xmlnode_get_attrib(child, "value");
-
-		if (!id || !*id || !value || !*value)
-			continue;
-
-		attr_value = purple_status_get_attr_value(status, id);
-		if (!attr_value)
-			continue;
-
-		list = g_list_append(list, (char *)id);
-
-		switch (purple_value_get_type(attr_value))
-		{
-			case PURPLE_TYPE_STRING:
-				list = g_list_append(list, (char *)value);
-				break;
-			case PURPLE_TYPE_INT:
-			case PURPLE_TYPE_BOOLEAN:
-			{
-				int v;
-				if (sscanf(value, "%d", &v) == 1)
-					list = g_list_append(list, GINT_TO_POINTER(v));
-				else
-					list = g_list_remove(list, id);
-				break;
-			}
-			default:
-				break;
-		}
-	}
-
-	return list;
-}
-
-static void
-parse_status(xmlnode *node, PurpleAccount *account)
-{
-	gboolean active = FALSE;
-	const char *data;
-	const char *type;
-	xmlnode *child;
-	GList *attrs = NULL;
-
-	/* Get the active/inactive state */
-	data = xmlnode_get_attrib(node, "active");
-	if (data == NULL)
-		return;
-	if (g_ascii_strcasecmp(data, "true") == 0)
-		active = TRUE;
-	else if (g_ascii_strcasecmp(data, "false") == 0)
-		active = FALSE;
-	else
-		return;
-
-	/* Get the type of the status */
-	type = xmlnode_get_attrib(node, "type");
-	if (type == NULL)
-		return;
-
-	/* Read attributes into a GList */
-	child = xmlnode_get_child(node, "attributes");
-	if (child != NULL)
-	{
-		attrs = parse_status_attrs(child,
-						purple_account_get_status(account, type));
-	}
-
-	purple_account_set_status_list(account, type, active, attrs);
-
-	g_list_free(attrs);
-}
-
-static void
-parse_statuses(xmlnode *node, PurpleAccount *account)
-{
-	xmlnode *child;
-
-	for (child = xmlnode_get_child(node, "status"); child != NULL;
-			child = xmlnode_get_next_twin(child))
-	{
-		parse_status(child, account);
-	}
-}
-
-static void
-parse_proxy_info(xmlnode *node, PurpleAccount *account)
-{
-	PurpleProxyInfo *proxy_info;
-	xmlnode *child;
-	char *data;
-
-	proxy_info = purple_proxy_info_new();
-
-	/* Use the global proxy settings, by default */
-	purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_GLOBAL);
-
-	/* Read proxy type */
-	child = xmlnode_get_child(node, "type");
-	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
-	{
-		if (purple_strequal(data, "global"))
-			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_GLOBAL);
-		else if (purple_strequal(data, "none"))
-			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_NONE);
-		else if (purple_strequal(data, "http"))
-			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_HTTP);
-		else if (purple_strequal(data, "socks4"))
-			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS4);
-		else if (purple_strequal(data, "socks5"))
-			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS5);
-		else if (purple_strequal(data, "tor"))
-			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_TOR);
-		else if (purple_strequal(data, "envvar"))
-			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_ENVVAR);
-		else
-		{
-			purple_debug_error("account", "Invalid proxy type found when "
-							 "loading account information for %s\n",
-							 purple_account_get_username(account));
-		}
-		g_free(data);
-	}
-
-	/* Read proxy host */
-	child = xmlnode_get_child(node, "host");
-	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
-	{
-		purple_proxy_info_set_host(proxy_info, data);
-		g_free(data);
-	}
-
-	/* Read proxy port */
-	child = xmlnode_get_child(node, "port");
-	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
-	{
-		purple_proxy_info_set_port(proxy_info, atoi(data));
-		g_free(data);
-	}
-
-	/* Read proxy username */
-	child = xmlnode_get_child(node, "username");
-	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
-	{
-		purple_proxy_info_set_username(proxy_info, data);
-		g_free(data);
-	}
-
-	/* Read proxy password */
-	child = xmlnode_get_child(node, "password");
-	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
-	{
-		purple_proxy_info_set_password(proxy_info, data);
-		g_free(data);
-	}
-
-	/* If there are no values set then proxy_info NULL */
-	if ((purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_USE_GLOBAL) &&
-		(purple_proxy_info_get_host(proxy_info) == NULL) &&
-		(purple_proxy_info_get_port(proxy_info) == 0) &&
-		(purple_proxy_info_get_username(proxy_info) == NULL) &&
-		(purple_proxy_info_get_password(proxy_info) == NULL))
-	{
-		purple_proxy_info_destroy(proxy_info);
-		return;
-	}
-
-	purple_account_set_proxy_info(account, proxy_info);
-}
-
-static void
-parse_current_error(xmlnode *node, PurpleAccount *account)
-{
-	guint type;
-	char *type_str = NULL, *description = NULL;
-	xmlnode *child;
-	PurpleConnectionErrorInfo *current_error = NULL;
-
-	child = xmlnode_get_child(node, "type");
-	if (child == NULL || (type_str = xmlnode_get_data(child)) == NULL)
-		return;
-	type = atoi(type_str);
-	g_free(type_str);
-
-	if (type > PURPLE_CONNECTION_ERROR_OTHER_ERROR)
-	{
-		purple_debug_error("account",
-			"Invalid PurpleConnectionError value %d found when "
-			"loading account information for %s\n",
-			type, purple_account_get_username(account));
-		type = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-	}
-
-	child = xmlnode_get_child(node, "description");
-	if (child)
-		description = xmlnode_get_data(child);
-	if (description == NULL)
-		description = g_strdup("");
-
-	current_error = g_new0(PurpleConnectionErrorInfo, 1);
-	PURPLE_DBUS_REGISTER_POINTER(current_error, PurpleConnectionErrorInfo);
-	current_error->type = type;
-	current_error->description = description;
-
-	set_current_error(account, current_error);
-}
-
-static PurpleAccount *
-parse_account(xmlnode *node)
-{
-	PurpleAccount *ret;
-	xmlnode *child;
-	char *protocol_id = NULL;
-	char *name = NULL;
-	char *data;
-
-	child = xmlnode_get_child(node, "protocol");
-	if (child != NULL)
-		protocol_id = xmlnode_get_data(child);
-
-	child = xmlnode_get_child(node, "name");
-	if (child != NULL)
-		name = xmlnode_get_data(child);
-	if (name == NULL)
-	{
-		/* Do we really need to do this? */
-		child = xmlnode_get_child(node, "username");
-		if (child != NULL)
-			name = xmlnode_get_data(child);
-	}
-
-	if ((protocol_id == NULL) || (name == NULL))
-	{
-		g_free(protocol_id);
-		g_free(name);
-		return NULL;
-	}
-
-	ret = purple_account_new(name, protocol_id);
-	g_free(name);
-	g_free(protocol_id);
-
-	/* Read the alias */
-	child = xmlnode_get_child(node, "alias");
-	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
-	{
-		if (*data != '\0')
-			purple_account_set_alias(ret, data);
-		g_free(data);
-	}
-
-	/* Read the statuses */
-	child = xmlnode_get_child(node, "statuses");
-	if (child != NULL)
-	{
-		parse_statuses(child, ret);
-	}
-
-	/* Read the userinfo */
-	child = xmlnode_get_child(node, "userinfo");
-	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
-	{
-		purple_account_set_user_info(ret, data);
-		g_free(data);
-	}
-
-	/* Read an old buddyicon */
-	child = xmlnode_get_child(node, "buddyicon");
-	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
-	{
-		const char *dirname = purple_buddy_icons_get_cache_dir();
-		char *filename = g_build_filename(dirname, data, NULL);
-		gchar *contents;
-		gsize len;
-
-		if (g_file_get_contents(filename, &contents, &len, NULL))
-		{
-			purple_buddy_icons_set_account_icon(ret, (guchar *)contents, len);
-		}
-
-		g_free(filename);
-		g_free(data);
-	}
-
-	/* Read settings (both core and UI) */
-	for (child = xmlnode_get_child(node, "settings"); child != NULL;
-			child = xmlnode_get_next_twin(child))
-	{
-		parse_settings(child, ret);
-	}
-
-	/* Read proxy */
-	child = xmlnode_get_child(node, "proxy");
-	if (child != NULL)
-	{
-		parse_proxy_info(child, ret);
-	}
-
-	/* Read current error */
-	child = xmlnode_get_child(node, "current_error");
-	if (child != NULL)
-	{
-		parse_current_error(child, ret);
-	}
-
-	/* Read the password */
-	child = xmlnode_get_child(node, "password");
-	if (child != NULL)
-	{
-		const char *keyring_id = xmlnode_get_attrib(child, "keyring_id");
-		const char *mode = xmlnode_get_attrib(child, "mode");
-		gboolean result;
-
-		data = xmlnode_get_data(child);
-		result = purple_keyring_import_password(ret, keyring_id, mode, data, NULL);
-
-		if (result == TRUE || purple_keyring_get_inuse() == NULL) {
-			purple_account_set_remember_password(ret, TRUE);
-		} else {
-			purple_debug_error("account", "Failed to import password.\n");
-		} 
-		purple_str_wipe(data);
-	}
-
-	return ret;
-}
-
-static void
-load_accounts(void)
-{
-	xmlnode *node, *child;
-
-	accounts_loaded = TRUE;
-
-	node = purple_util_read_xml_from_file("accounts.xml", _("accounts"));
-
-	if (node == NULL)
-		return;
-
-	for (child = xmlnode_get_child(node, "account"); child != NULL;
-			child = xmlnode_get_next_twin(child))
-	{
-		PurpleAccount *new_acct;
-		new_acct = parse_account(child);
-		purple_accounts_add(new_acct);
-	}
-
-	xmlnode_free(node);
-
-	_purple_buddy_icons_account_loaded_cb();
-}
-
-
-static void
-delete_setting(void *data)
-{
-	PurpleAccountSetting *setting = (PurpleAccountSetting *)data;
-
-	g_free(setting->ui);
-
-	if (setting->type == PURPLE_PREF_STRING)
-		g_free(setting->value.string);
-
-	g_free(setting);
-}
-
-PurpleAccount *
-purple_account_new(const char *username, const char *protocol_id)
-{
-	PurpleAccount *account = NULL;
-	PurplePlugin *prpl = NULL;
-	PurplePluginProtocolInfo *prpl_info = NULL;
-	PurpleStatusType *status_type;
-
-	g_return_val_if_fail(username != NULL, NULL);
-	g_return_val_if_fail(protocol_id != NULL, NULL);
-
-	account = purple_accounts_find(username, protocol_id);
-
-	if (account != NULL)
-		return account;
-
-	account = g_new0(PurpleAccount, 1);
-	PURPLE_DBUS_REGISTER_POINTER(account, PurpleAccount);
-
-	purple_account_set_username(account, username);
-
-	purple_account_set_protocol_id(account, protocol_id);
-
-	account->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
-											  g_free, delete_setting);
-	account->ui_settings = g_hash_table_new_full(g_str_hash, g_str_equal,
-				g_free, (GDestroyNotify)g_hash_table_destroy);
-	account->system_log = NULL;
-	/* 0 is not a valid privacy setting */
-	account->perm_deny = PURPLE_PRIVACY_ALLOW_ALL;
-
-	purple_signal_emit(purple_accounts_get_handle(), "account-created", account);
-
-	prpl = purple_find_prpl(protocol_id);
-
-	if (prpl == NULL)
-		return account;
-
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-	if (prpl_info != NULL && prpl_info->status_types != NULL)
-		purple_account_set_status_types(account, prpl_info->status_types(account));
-
-	account->presence = purple_presence_new_for_account(account);
-
-	status_type = purple_account_get_status_type_with_primitive(account, PURPLE_STATUS_AVAILABLE);
-	if (status_type != NULL)
-		purple_presence_set_status_active(account->presence,
-										purple_status_type_get_id(status_type),
-										TRUE);
-	else
-		purple_presence_set_status_active(account->presence,
-										"offline",
-										TRUE);
-
-	return account;
-}
-
-void
-purple_account_destroy(PurpleAccount *account)
-{
-	GList *l;
-
-	g_return_if_fail(account != NULL);
-
-	purple_debug_info("account", "Destroying account %p\n", account);
-	purple_signal_emit(purple_accounts_get_handle(), "account-destroying", account);
-
-	for (l = purple_get_conversations(); l != NULL; l = l->next)
-	{
-		PurpleConversation *conv = (PurpleConversation *)l->data;
-
-		if (purple_conversation_get_account(conv) == account)
-			purple_conversation_set_account(conv, NULL);
-	}
-
-	g_free(account->username);
-	g_free(account->alias);
-	purple_str_wipe(account->password);
-	g_free(account->user_info);
-	g_free(account->buddy_icon_path);
-	g_free(account->protocol_id);
-
-	g_hash_table_destroy(account->settings);
-	g_hash_table_destroy(account->ui_settings);
-
-	if (account->proxy_info)
-		purple_proxy_info_destroy(account->proxy_info);
-
-	purple_account_set_status_types(account, NULL);
-
-	if (account->presence)
-		purple_presence_destroy(account->presence);
-
-	if(account->system_log)
-		purple_log_free(account->system_log);
-
-	while (account->deny) {
-		g_free(account->deny->data);
-		account->deny = g_slist_delete_link(account->deny, account->deny);
-	}
-
-	while (account->permit) {
-		g_free(account->permit->data);
-		account->permit = g_slist_delete_link(account->permit, account->permit);
-	}
-
-	PURPLE_DBUS_UNREGISTER_POINTER(account->current_error);
-	if (account->current_error) {
-		g_free(account->current_error->description);
-		g_free(account->current_error);
-	}
-
-	PURPLE_DBUS_UNREGISTER_POINTER(account);
-	g_free(account);
-}
+	PROP_0,
+	PROP_USERNAME,
+	PROP_PRIVATE_ALIAS,
+	PROP_ENABLED,
+	PROP_CONNECTION,
+	PROP_PROTOCOL_ID,
+	PROP_USER_INFO,
+	PROP_BUDDY_ICON_PATH,
+	PROP_REMEMBER_PASSWORD,
+	PROP_CHECK_MAIL,
+	PROP_LAST
+};
+
+static GObjectClass  *parent_class = NULL;
+static GList         *handles = NULL;
+
 
 void
 purple_account_set_register_callback(PurpleAccount *account, PurpleAccountRegistrationCb cb, void *user_data)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	account->registration_cb = cb;
-	account->registration_cb_user_data = user_data;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	priv->registration_cb = cb;
+	priv->registration_cb_user_data = user_data;
 }
 
 static void
@@ -1183,10 +186,14 @@
 void
 purple_account_register_completed(PurpleAccount *account, gboolean succeeded)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	if (account->registration_cb)
-		(account->registration_cb)(account, succeeded, account->registration_cb_user_data);
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	if (priv->registration_cb)
+		(priv->registration_cb)(account, succeeded, priv->registration_cb_user_data);
 }
 
 void
@@ -1299,6 +306,7 @@
 	PurplePlugin *prpl;
 	const char *username;
 	PurplePluginProtocolInfo *prpl_info;
+	PurpleAccountPrivate *priv;
 
 	g_return_if_fail(account != NULL);
 
@@ -1321,12 +329,14 @@
 		return;
 	}
 
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
 	purple_debug_info("account", "Connecting to account %s.\n", username);
 
 	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-	if (account->password != NULL) {
+	if (priv->password != NULL) {
 		purple_account_connect_got_password_cb(account,
-			account->password, NULL, prpl_info);
+			priv->password, NULL, prpl_info);
 	} else {
 		purple_keyring_get_password(account,
 			purple_account_connect_got_password_cb, prpl_info);
@@ -1337,30 +347,36 @@
 purple_account_disconnect(PurpleAccount *account)
 {
 	PurpleConnection *gc;
+	PurpleAccountPrivate *priv;
 	const char *username;
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(!purple_account_is_disconnected(account));
 
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
 	username = purple_account_get_username(account);
 	purple_debug_info("account", "Disconnecting account %s (%p)\n",
 	                  username ? username : "(null)", account);
 
-	account->disconnecting = TRUE;
+	priv->disconnecting = TRUE;
 
 	gc = purple_account_get_connection(account);
 	_purple_connection_destroy(gc);
 	purple_account_set_connection(account, NULL);
 
-	account->disconnecting = FALSE;
+	priv->disconnecting = FALSE;
 }
 
 gboolean
 purple_account_is_disconnecting(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, TRUE);
-	
-	return account->disconnecting;
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->disconnecting;
 }
 
 void
@@ -1692,13 +708,16 @@
 purple_account_set_username(PurpleAccount *account, const char *username)
 {
 	PurpleBlistUiOps *blist_ops;
+	PurpleAccountPrivate *priv;
 
 	g_return_if_fail(account != NULL);
 
-	g_free(account->username);
-	account->username = g_strdup(username);
-
-	schedule_accounts_save();
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	g_free(priv->username);
+	priv->username = g_strdup(username);
+
+	purple_accounts_schedule_save();
 
 	/* if the name changes, we should re-write the buddy list
 	 * to disk with the new name */
@@ -1711,12 +730,16 @@
 purple_account_set_password(PurpleAccount *account, const gchar *password,
 	PurpleKeyringSaveCallback cb, gpointer data)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	purple_str_wipe(account->password);
-	account->password = g_strdup(password);
-
-	schedule_accounts_save();
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	purple_str_wipe(priv->password);
+	priv->password = g_strdup(password);
+
+	purple_accounts_schedule_save();
 
 	if (!purple_account_get_remember_password(account)) {
 		purple_debug_info("account",
@@ -1731,80 +754,102 @@
 }
 
 void
-purple_account_set_alias(PurpleAccount *account, const char *alias)
+purple_account_set_private_alias(PurpleAccount *account, const char *alias)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
 	/*
-	 * Do nothing if alias and account->alias are both NULL.  Or if
+	 * Do nothing if alias and priv->alias are both NULL.  Or if
 	 * they're the exact same string.
 	 */
-	if (alias == account->alias)
+	if (alias == priv->alias)
 		return;
 
-	if ((!alias && account->alias) || (alias && !account->alias) ||
-			g_utf8_collate(account->alias, alias))
+	if ((!alias && priv->alias) || (alias && !priv->alias) ||
+			g_utf8_collate(priv->alias, alias))
 	{
-		char *old = account->alias;
-
-		account->alias = g_strdup(alias);
+		char *old = priv->alias;
+
+		priv->alias = g_strdup(alias);
 		purple_signal_emit(purple_accounts_get_handle(), "account-alias-changed",
 						 account, old);
 		g_free(old);
 
-		schedule_accounts_save();
+		purple_accounts_schedule_save();
 	}
 }
 
 void
 purple_account_set_user_info(PurpleAccount *account, const char *user_info)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	g_free(account->user_info);
-	account->user_info = g_strdup(user_info);
-
-	schedule_accounts_save();
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	g_free(priv->user_info);
+	priv->user_info = g_strdup(user_info);
+
+	purple_accounts_schedule_save();
 }
 
 void purple_account_set_buddy_icon_path(PurpleAccount *account, const char *path)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	g_free(account->buddy_icon_path);
-	account->buddy_icon_path = g_strdup(path);
-
-	schedule_accounts_save();
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	g_free(priv->buddy_icon_path);
+	priv->buddy_icon_path = g_strdup(path);
+
+	purple_accounts_schedule_save();
 }
 
 void
 purple_account_set_protocol_id(PurpleAccount *account, const char *protocol_id)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account     != NULL);
 	g_return_if_fail(protocol_id != NULL);
 
-	g_free(account->protocol_id);
-	account->protocol_id = g_strdup(protocol_id);
-
-	schedule_accounts_save();
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	g_free(priv->protocol_id);
+	priv->protocol_id = g_strdup(protocol_id);
+
+	purple_accounts_schedule_save();
 }
 
 void
 purple_account_set_connection(PurpleAccount *account, PurpleConnection *gc)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	account->gc = gc;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	priv->gc = gc;
 }
 
 void
 purple_account_set_remember_password(PurpleAccount *account, gboolean value)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	account->remember_pass = value;
-
-	schedule_accounts_save();
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	priv->remember_pass = value;
+
+	purple_accounts_schedule_save();
 }
 
 void
@@ -1820,6 +865,7 @@
 			 gboolean value)
 {
 	PurpleConnection *gc;
+	PurpleAccountPrivate *priv;
 	gboolean was_enabled = FALSE;
 
 	g_return_if_fail(account != NULL);
@@ -1838,7 +884,9 @@
 	if ((gc != NULL) && (gc->wants_to_die == TRUE))
 		return;
 
-	if (value && purple_presence_is_online(account->presence))
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	if (value && purple_presence_is_online(priv->presence))
 		purple_account_connect(account);
 	else if (!value && !purple_account_is_disconnected(account))
 		purple_account_disconnect(account);
@@ -1847,38 +895,49 @@
 void
 purple_account_set_proxy_info(PurpleAccount *account, PurpleProxyInfo *info)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	if (account->proxy_info != NULL)
-		purple_proxy_info_destroy(account->proxy_info);
-
-	account->proxy_info = info;
-
-	schedule_accounts_save();
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	if (priv->proxy_info != NULL)
+		purple_proxy_info_destroy(priv->proxy_info);
+
+	priv->proxy_info = info;
+
+	purple_accounts_schedule_save();
 }
 
 void
-purple_account_set_privacy_type(PurpleAccount *account, PurplePrivacyType privacy_type)
+purple_account_set_privacy_type(PurpleAccount *account, PurpleAccountPrivacyType privacy_type)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	account->perm_deny = privacy_type;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	priv->privacy_type = privacy_type;
 }
 
 void
 purple_account_set_status_types(PurpleAccount *account, GList *status_types)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
 	/* Out with the old... */
-	if (account->status_types != NULL)
+	if (priv->status_types != NULL)
 	{
-		g_list_foreach(account->status_types, (GFunc)purple_status_type_destroy, NULL);
-		g_list_free(account->status_types);
+		g_list_foreach(priv->status_types, (GFunc)purple_status_type_destroy, NULL);
+		g_list_free(priv->status_types);
 	}
 
 	/* In with the new... */
-	account->status_types = status_types;
+	priv->status_types = status_types;
 }
 
 void
@@ -1928,7 +987,7 @@
 	 * Our current statuses are saved to accounts.xml (so that when we
 	 * reconnect, we go back to the previous status).
 	 */
-	schedule_accounts_save();
+	purple_accounts_schedule_save();
 }
 
 struct public_alias_closure
@@ -2031,42 +1090,63 @@
 	purple_account_set_bool(account, "silence-suppression", value);
 }
 
+static void
+delete_setting(void *data)
+{
+	PurpleAccountSetting *setting = (PurpleAccountSetting *)data;
+
+	g_free(setting->ui);
+	g_value_unset(&setting->value);
+
+	g_free(setting);
+}
+
 void
 purple_account_clear_settings(PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	g_hash_table_destroy(account->settings);
-
-	account->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	g_hash_table_destroy(priv->settings);
+
+	priv->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
 											  g_free, delete_setting);
 }
 
 void
 purple_account_remove_setting(PurpleAccount *account, const char *setting)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(setting != NULL);
 
-	g_hash_table_remove(account->settings, setting);
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	g_hash_table_remove(priv->settings, setting);
 }
 
 void
 purple_account_set_int(PurpleAccount *account, const char *name, int value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountPrivate *priv;
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(name    != NULL);
 
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
 	setting = g_new0(PurpleAccountSetting, 1);
 
-	setting->type          = PURPLE_PREF_INT;
-	setting->value.integer = value;
-
-	g_hash_table_insert(account->settings, g_strdup(name), setting);
-
-	schedule_accounts_save();
+	g_value_init(&setting->value, G_TYPE_INT);
+	g_value_set_int(&setting->value, value);
+
+	g_hash_table_insert(priv->settings, g_strdup(name), setting);
+
+	purple_accounts_schedule_save();
 }
 
 void
@@ -2074,49 +1154,56 @@
 						const char *value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountPrivate *priv;
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(name    != NULL);
 
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
 	setting = g_new0(PurpleAccountSetting, 1);
 
-	setting->type         = PURPLE_PREF_STRING;
-	setting->value.string = g_strdup(value);
-
-	g_hash_table_insert(account->settings, g_strdup(name), setting);
-
-	schedule_accounts_save();
+	g_value_init(&setting->value, G_TYPE_STRING);
+	g_value_set_string(&setting->value, value);
+
+	g_hash_table_insert(priv->settings, g_strdup(name), setting);
+
+	purple_accounts_schedule_save();
 }
 
 void
 purple_account_set_bool(PurpleAccount *account, const char *name, gboolean value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountPrivate *priv;
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(name    != NULL);
 
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
 	setting = g_new0(PurpleAccountSetting, 1);
 
-	setting->type       = PURPLE_PREF_BOOLEAN;
-	setting->value.boolean = value;
-
-	g_hash_table_insert(account->settings, g_strdup(name), setting);
-
-	schedule_accounts_save();
+	g_value_init(&setting->value, G_TYPE_BOOLEAN);
+	g_value_set_boolean(&setting->value, value);
+
+	g_hash_table_insert(priv->settings, g_strdup(name), setting);
+
+	purple_accounts_schedule_save();
 }
 
 static GHashTable *
 get_ui_settings_table(PurpleAccount *account, const char *ui)
 {
 	GHashTable *table;
-
-	table = g_hash_table_lookup(account->ui_settings, ui);
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	table = g_hash_table_lookup(priv->ui_settings, ui);
 
 	if (table == NULL) {
 		table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
 									  delete_setting);
-		g_hash_table_insert(account->ui_settings, g_strdup(ui), table);
+		g_hash_table_insert(priv->ui_settings, g_strdup(ui), table);
 	}
 
 	return table;
@@ -2135,15 +1222,15 @@
 
 	setting = g_new0(PurpleAccountSetting, 1);
 
-	setting->type          = PURPLE_PREF_INT;
 	setting->ui            = g_strdup(ui);
-	setting->value.integer = value;
+	g_value_init(&setting->value, G_TYPE_INT);
+	g_value_set_int(&setting->value, value);
 
 	table = get_ui_settings_table(account, ui);
 
 	g_hash_table_insert(table, g_strdup(name), setting);
 
-	schedule_accounts_save();
+	purple_accounts_schedule_save();
 }
 
 void
@@ -2159,15 +1246,15 @@
 
 	setting = g_new0(PurpleAccountSetting, 1);
 
-	setting->type         = PURPLE_PREF_STRING;
 	setting->ui           = g_strdup(ui);
-	setting->value.string = g_strdup(value);
+	g_value_init(&setting->value, G_TYPE_STRING);
+	g_value_set_string(&setting->value, value);
 
 	table = get_ui_settings_table(account, ui);
 
 	g_hash_table_insert(table, g_strdup(name), setting);
 
-	schedule_accounts_save();
+	purple_accounts_schedule_save();
 }
 
 void
@@ -2183,15 +1270,15 @@
 
 	setting = g_new0(PurpleAccountSetting, 1);
 
-	setting->type       = PURPLE_PREF_BOOLEAN;
 	setting->ui         = g_strdup(ui);
-	setting->value.boolean = value;
+	g_value_init(&setting->value, G_TYPE_BOOLEAN);
+	g_value_set_boolean(&setting->value, value);
 
 	table = get_ui_settings_table(account, ui);
 
 	g_hash_table_insert(table, g_strdup(name), setting);
 
-	schedule_accounts_save();
+	purple_accounts_schedule_save();
 }
 
 static PurpleConnectionState
@@ -2229,9 +1316,12 @@
 const char *
 purple_account_get_username(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
 
-	return account->username;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->username;
 }
 
 static void
@@ -2240,13 +1330,14 @@
 {
 	PurpleCallbackBundle *cbb = data;
 	PurpleKeyringReadCallback cb;
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
 
 	purple_debug_info("account",
 		"Read password for account %s from async keyring.\n",
 		purple_account_get_username(account));
 
-	purple_str_wipe(account->password);
-	account->password = g_strdup(password);
+	purple_str_wipe(priv->password);
+	priv->password = g_strdup(password);
 
 	cb = (PurpleKeyringReadCallback)cbb->cb;
 	if (cb != NULL)
@@ -2259,16 +1350,20 @@
 purple_account_get_password(PurpleAccount *account,
 	PurpleKeyringReadCallback cb, gpointer data)
 {
+	PurpleAccountPrivate *priv;
+
 	if (account == NULL) {
 		cb(NULL, NULL, NULL, data);
 		return;
 	}
 
-	if (account->password != NULL) {
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	if (priv->password != NULL) {
 		purple_debug_info("account",
 			"Reading password for account %s from cache.\n",
 			purple_account_get_username(account));
-		cb(account, account->password, NULL, data);
+		cb(account, priv->password, NULL, data);
 	} else {
 		PurpleCallbackBundle *cbb = g_new0(PurpleCallbackBundle, 1);
 		cbb->cb = PURPLE_CALLBACK(cb);
@@ -2283,34 +1378,47 @@
 }
 
 const char *
-purple_account_get_alias(const PurpleAccount *account)
+purple_account_get_private_alias(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
 
-	return account->alias;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->alias;
 }
 
 const char *
 purple_account_get_user_info(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
 
-	return account->user_info;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->user_info;
 }
 
 const char *
 purple_account_get_buddy_icon_path(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
 
-	return account->buddy_icon_path;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->buddy_icon_path;
 }
 
 const char *
 purple_account_get_protocol_id(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
-	return account->protocol_id;
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->protocol_id;
 }
 
 const char *
@@ -2328,9 +1436,12 @@
 PurpleConnection *
 purple_account_get_connection(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
 
-	return account->gc;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->gc;
 }
 
 const gchar *
@@ -2340,7 +1451,7 @@
 	PurpleConnection *gc = NULL;
 	const gchar *name = NULL, *username = NULL, *displayname = NULL;
 
-	name = purple_account_get_alias(account);
+	name = purple_account_get_private_alias(account);
 
 	if (name) {
 		return name;
@@ -2372,9 +1483,12 @@
 gboolean
 purple_account_get_remember_password(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, FALSE);
 
-	return account->remember_pass;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->remember_pass;
 }
 
 gboolean
@@ -2397,34 +1511,436 @@
 PurpleProxyInfo *
 purple_account_get_proxy_info(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
 
-	return account->proxy_info;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->proxy_info;
 }
 
-PurplePrivacyType
+PurpleAccountPrivacyType
 purple_account_get_privacy_type(const PurpleAccount *account)
 {
-	g_return_val_if_fail(account != NULL, PURPLE_PRIVACY_ALLOW_ALL);
-
-	return account->perm_deny;
+	PurpleAccountPrivate *priv;
+
+	g_return_val_if_fail(account != NULL, PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL);
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->privacy_type;
+}
+
+gboolean
+purple_account_privacy_permit_add(PurpleAccount *account, const char *who,
+						gboolean local_only)
+{
+	GSList *l;
+	char *name;
+	PurpleBuddy *buddy;
+	PurpleBlistUiOps *blist_ops;
+	PurpleAccountPrivate *priv;
+	PurpleAccountUiOps *ui_ops = purple_accounts_get_ui_ops();
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	name = g_strdup(purple_normalize(account, who));
+
+	for (l = priv->permit; l != NULL; l = l->next) {
+		if (g_str_equal(name, l->data))
+			/* This buddy already exists */
+			break;
+	}
+
+	if (l != NULL)
+	{
+		/* This buddy already exists, so bail out */
+		g_free(name);
+		return FALSE;
+	}
+
+	priv->permit = g_slist_append(priv->permit, name);
+
+	if (!local_only && purple_account_is_connected(account))
+		serv_add_permit(purple_account_get_connection(account), who);
+
+	if (ui_ops != NULL && ui_ops->permit_added != NULL)
+		ui_ops->permit_added(account, who);
+
+	blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
+
+	/* This lets the UI know a buddy has had its privacy setting changed */
+	buddy = purple_find_buddy(account, name);
+	if (buddy != NULL) {
+		purple_signal_emit(purple_blist_get_handle(),
+                "buddy-privacy-changed", buddy);
+	}
+	return TRUE;
+}
+
+gboolean
+purple_account_privacy_permit_remove(PurpleAccount *account, const char *who,
+						   gboolean local_only)
+{
+	GSList *l;
+	const char *name;
+	PurpleBuddy *buddy;
+	char *del;
+	PurpleBlistUiOps *blist_ops;
+	PurpleAccountPrivate *priv;
+	PurpleAccountUiOps *ui_ops = purple_accounts_get_ui_ops();
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	name = purple_normalize(account, who);
+
+	for (l = priv->permit; l != NULL; l = l->next) {
+		if (g_str_equal(name, l->data))
+			/* We found the buddy we were looking for */
+			break;
+	}
+
+	if (l == NULL)
+		/* We didn't find the buddy we were looking for, so bail out */
+		return FALSE;
+
+	/* We should not free l->data just yet. There can be occasions where
+	 * l->data == who. In such cases, freeing l->data here can cause crashes
+	 * later when who is used. */
+	del = l->data;
+	priv->permit = g_slist_delete_link(priv->permit, l);
+
+	if (!local_only && purple_account_is_connected(account))
+		serv_rem_permit(purple_account_get_connection(account), who);
+
+	if (ui_ops != NULL && ui_ops->permit_removed != NULL)
+		ui_ops->permit_removed(account, who);
+
+	blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
+
+	buddy = purple_find_buddy(account, name);
+	if (buddy != NULL) {
+		purple_signal_emit(purple_blist_get_handle(),
+                "buddy-privacy-changed", buddy);
+	}
+	g_free(del);
+	return TRUE;
+}
+
+gboolean
+purple_account_privacy_deny_add(PurpleAccount *account, const char *who,
+					  gboolean local_only)
+{
+	GSList *l;
+	char *name;
+	PurpleBuddy *buddy;
+	PurpleBlistUiOps *blist_ops;
+	PurpleAccountPrivate *priv;
+	PurpleAccountUiOps *ui_ops = purple_accounts_get_ui_ops();
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	name = g_strdup(purple_normalize(account, who));
+
+	for (l = priv->deny; l != NULL; l = l->next) {
+		if (g_str_equal(name, l->data))
+			/* This buddy already exists */
+			break;
+	}
+
+	if (l != NULL)
+	{
+		/* This buddy already exists, so bail out */
+		g_free(name);
+		return FALSE;
+	}
+
+	priv->deny = g_slist_append(priv->deny, name);
+
+	if (!local_only && purple_account_is_connected(account))
+		serv_add_deny(purple_account_get_connection(account), who);
+
+	if (ui_ops != NULL && ui_ops->deny_added != NULL)
+		ui_ops->deny_added(account, who);
+
+	blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
+
+	buddy = purple_find_buddy(account, name);
+	if (buddy != NULL) {
+		purple_signal_emit(purple_blist_get_handle(),
+                "buddy-privacy-changed", buddy);
+	}
+	return TRUE;
+}
+
+gboolean
+purple_account_privacy_deny_remove(PurpleAccount *account, const char *who,
+						 gboolean local_only)
+{
+	GSList *l;
+	const char *normalized;
+	char *name;
+	PurpleBuddy *buddy;
+	PurpleBlistUiOps *blist_ops;
+	PurpleAccountPrivate *priv;
+	PurpleAccountUiOps *ui_ops = purple_accounts_get_ui_ops();
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	normalized = purple_normalize(account, who);
+
+	for (l = priv->deny; l != NULL; l = l->next) {
+		if (g_str_equal(normalized, l->data))
+			/* We found the buddy we were looking for */
+			break;
+	}
+
+	if (l == NULL)
+		/* We didn't find the buddy we were looking for, so bail out */
+		return FALSE;
+
+	buddy = purple_find_buddy(account, normalized);
+
+	name = l->data;
+	priv->deny = g_slist_delete_link(priv->deny, l);
+
+	if (!local_only && purple_account_is_connected(account))
+		serv_rem_deny(purple_account_get_connection(account), name);
+
+	if (ui_ops != NULL && ui_ops->deny_removed != NULL)
+		ui_ops->deny_removed(account, who);
+
+	if (buddy != NULL) {
+		purple_signal_emit(purple_blist_get_handle(),
+                "buddy-privacy-changed", buddy);
+	}
+
+	g_free(name);
+
+	blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
+
+	return TRUE;
+}
+
+/**
+ * This makes sure your permit list contains all buddies from your
+ * buddy list and ONLY buddies from your buddy list.
+ */
+static void
+add_all_buddies_to_permit_list(PurpleAccount *account, gboolean local)
+{
+	GSList *list;
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	/* Remove anyone in the permit list who is not in the buddylist */
+	for (list = priv->permit; list != NULL; ) {
+		char *person = list->data;
+		list = list->next;
+		if (!purple_find_buddy(account, person))
+			purple_account_privacy_permit_remove(account, person, local);
+	}
+
+	/* Now make sure everyone in the buddylist is in the permit list */
+	list = purple_find_buddies(account, NULL);
+	while (list != NULL)
+	{
+		PurpleBuddy *buddy = list->data;
+		const gchar *name = purple_buddy_get_name(buddy);
+
+		if (!g_slist_find_custom(priv->permit, name, (GCompareFunc)g_utf8_collate))
+			purple_account_privacy_permit_add(account, name, local);
+		list = g_slist_delete_link(list, list);
+	}
+}
+
+void
+purple_account_privacy_allow(PurpleAccount *account, const char *who)
+{
+	GSList *list;
+	PurpleAccountPrivacyType type = purple_account_get_privacy_type(account);
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	switch (type) {
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
+			return;
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
+			purple_account_privacy_permit_add(account, who, FALSE);
+			break;
+		case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
+			purple_account_privacy_deny_remove(account, who, FALSE);
+			break;
+		case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
+			{
+				/* Empty the allow-list. */
+				const char *norm = purple_normalize(account, who);
+				for (list = priv->permit; list != NULL;) {
+					char *person = list->data;
+					list = list->next;
+					if (!purple_strequal(norm, person))
+						purple_account_privacy_permit_remove(account, person, FALSE);
+				}
+				purple_account_privacy_permit_add(account, who, FALSE);
+				purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS);
+			}
+			break;
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST:
+			if (!purple_find_buddy(account, who)) {
+				add_all_buddies_to_permit_list(account, FALSE);
+				purple_account_privacy_permit_add(account, who, FALSE);
+				purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS);
+			}
+			break;
+		default:
+			g_return_if_reached();
+	}
+
+	/* Notify the server if the privacy setting was changed */
+	if (type != purple_account_get_privacy_type(account) && purple_account_is_connected(account))
+		serv_set_permit_deny(purple_account_get_connection(account));
+}
+
+void
+purple_account_privacy_deny(PurpleAccount *account, const char *who)
+{
+	GSList *list;
+	PurpleAccountPrivacyType type = purple_account_get_privacy_type(account);
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	switch (type) {
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
+			{
+				/* Empty the deny-list. */
+				const char *norm = purple_normalize(account, who);
+				for (list = priv->deny; list != NULL; ) {
+					char *person = list->data;
+					list = list->next;
+					if (!purple_strequal(norm, person))
+						purple_account_privacy_deny_remove(account, person, FALSE);
+				}
+				purple_account_privacy_deny_add(account, who, FALSE);
+				purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_DENY_USERS);
+			}
+			break;
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
+			purple_account_privacy_permit_remove(account, who, FALSE);
+			break;
+		case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
+			purple_account_privacy_deny_add(account, who, FALSE);
+			break;
+		case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
+			break;
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST:
+			if (purple_find_buddy(account, who)) {
+				add_all_buddies_to_permit_list(account, FALSE);
+				purple_account_privacy_permit_remove(account, who, FALSE);
+				purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS);
+			}
+			break;
+		default:
+			g_return_if_reached();
+	}
+
+	/* Notify the server if the privacy setting was changed */
+	if (type != purple_account_get_privacy_type(account) && purple_account_is_connected(account))
+		serv_set_permit_deny(purple_account_get_connection(account));
+}
+
+GSList *
+purple_account_privacy_get_permitted(PurpleAccount *account)
+{
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	g_return_val_if_fail(priv != NULL, NULL);
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	return priv->permit;
+}
+
+GSList *
+purple_account_privacy_get_denied(PurpleAccount *account)
+{
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	g_return_val_if_fail(priv != NULL, NULL);
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	return priv->deny;
+}
+
+gboolean
+purple_account_privacy_check(PurpleAccount *account, const char *who)
+{
+	GSList *list;
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	switch (purple_account_get_privacy_type(account)) {
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
+			return TRUE;
+
+		case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
+			return FALSE;
+
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
+			who = purple_normalize(account, who);
+			for (list=priv->permit; list!=NULL; list=list->next) {
+				if (g_str_equal(who, list->data))
+					return TRUE;
+			}
+			return FALSE;
+
+		case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
+			who = purple_normalize(account, who);
+			for (list=priv->deny; list!=NULL; list=list->next) {
+				if (g_str_equal(who, list->data))
+					return FALSE;
+			}
+			return TRUE;
+
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST:
+			return (purple_find_buddy(account, who) != NULL);
+
+		default:
+			g_return_val_if_reached(TRUE);
+	}
 }
 
 PurpleStatus *
 purple_account_get_active_status(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account   != NULL, NULL);
 
-	return purple_presence_get_active_status(account->presence);
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return purple_presence_get_active_status(priv->presence);
 }
 
 PurpleStatus *
 purple_account_get_status(const PurpleAccount *account, const char *status_id)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account   != NULL, NULL);
 	g_return_val_if_fail(status_id != NULL, NULL);
 
-	return purple_presence_get_status(account->presence, status_id);
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	return purple_presence_get_status(priv->presence, status_id);
 }
 
 PurpleStatusType *
@@ -2467,27 +1983,37 @@
 PurplePresence *
 purple_account_get_presence(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
 
-	return account->presence;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->presence;
 }
 
 gboolean
 purple_account_is_status_active(const PurpleAccount *account,
 							  const char *status_id)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account   != NULL, FALSE);
 	g_return_val_if_fail(status_id != NULL, FALSE);
 
-	return purple_presence_is_status_active(account->presence, status_id);
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	return purple_presence_is_status_active(priv->presence, status_id);
 }
 
 GList *
 purple_account_get_status_types(const PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
 
-	return account->status_types;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+	return priv->status_types;
 }
 
 int
@@ -2495,18 +2021,21 @@
 					 int default_value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountPrivate *priv;
 
 	g_return_val_if_fail(account != NULL, default_value);
 	g_return_val_if_fail(name    != NULL, default_value);
 
-	setting = g_hash_table_lookup(account->settings, name);
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	setting = g_hash_table_lookup(priv->settings, name);
 
 	if (setting == NULL)
 		return default_value;
 
-	g_return_val_if_fail(setting->type == PURPLE_PREF_INT, default_value);
-
-	return setting->value.integer;
+	g_return_val_if_fail(G_VALUE_HOLDS_INT(&setting->value), default_value);
+
+	return g_value_get_int(&setting->value);
 }
 
 const char *
@@ -2514,18 +2043,21 @@
 						const char *default_value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountPrivate *priv;
 
 	g_return_val_if_fail(account != NULL, default_value);
 	g_return_val_if_fail(name    != NULL, default_value);
 
-	setting = g_hash_table_lookup(account->settings, name);
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	setting = g_hash_table_lookup(priv->settings, name);
 
 	if (setting == NULL)
 		return default_value;
 
-	g_return_val_if_fail(setting->type == PURPLE_PREF_STRING, default_value);
-
-	return setting->value.string;
+	g_return_val_if_fail(G_VALUE_HOLDS_STRING(&setting->value), default_value);
+
+	return g_value_get_string(&setting->value);
 }
 
 gboolean
@@ -2533,18 +2065,21 @@
 					  gboolean default_value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountPrivate *priv;
 
 	g_return_val_if_fail(account != NULL, default_value);
 	g_return_val_if_fail(name    != NULL, default_value);
 
-	setting = g_hash_table_lookup(account->settings, name);
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	setting = g_hash_table_lookup(priv->settings, name);
 
 	if (setting == NULL)
 		return default_value;
 
-	g_return_val_if_fail(setting->type == PURPLE_PREF_BOOLEAN, default_value);
-
-	return setting->value.boolean;
+	g_return_val_if_fail(G_VALUE_HOLDS_BOOLEAN(&setting->value), default_value);
+
+	return g_value_get_boolean(&setting->value);
 }
 
 int
@@ -2552,21 +2087,24 @@
 						const char *name, int default_value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountPrivate *priv;
 	GHashTable *table;
 
 	g_return_val_if_fail(account != NULL, default_value);
 	g_return_val_if_fail(ui      != NULL, default_value);
 	g_return_val_if_fail(name    != NULL, default_value);
 
-	if ((table = g_hash_table_lookup(account->ui_settings, ui)) == NULL)
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	if ((table = g_hash_table_lookup(priv->ui_settings, ui)) == NULL)
 		return default_value;
 
 	if ((setting = g_hash_table_lookup(table, name)) == NULL)
 		return default_value;
 
-	g_return_val_if_fail(setting->type == PURPLE_PREF_INT, default_value);
-
-	return setting->value.integer;
+	g_return_val_if_fail(G_VALUE_HOLDS_INT(&setting->value), default_value);
+
+	return g_value_get_int(&setting->value);
 }
 
 const char *
@@ -2574,21 +2112,24 @@
 						   const char *name, const char *default_value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountPrivate *priv;
 	GHashTable *table;
 
 	g_return_val_if_fail(account != NULL, default_value);
 	g_return_val_if_fail(ui      != NULL, default_value);
 	g_return_val_if_fail(name    != NULL, default_value);
 
-	if ((table = g_hash_table_lookup(account->ui_settings, ui)) == NULL)
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	if ((table = g_hash_table_lookup(priv->ui_settings, ui)) == NULL)
 		return default_value;
 
 	if ((setting = g_hash_table_lookup(table, name)) == NULL)
 		return default_value;
 
-	g_return_val_if_fail(setting->type == PURPLE_PREF_STRING, default_value);
-
-	return setting->value.string;
+	g_return_val_if_fail(G_VALUE_HOLDS_STRING(&setting->value), default_value);
+
+	return g_value_get_string(&setting->value);
 }
 
 gboolean
@@ -2596,69 +2137,62 @@
 						 const char *name, gboolean default_value)
 {
 	PurpleAccountSetting *setting;
+	PurpleAccountPrivate *priv;
 	GHashTable *table;
 
 	g_return_val_if_fail(account != NULL, default_value);
 	g_return_val_if_fail(ui      != NULL, default_value);
 	g_return_val_if_fail(name    != NULL, default_value);
 
-	if ((table = g_hash_table_lookup(account->ui_settings, ui)) == NULL)
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	if ((table = g_hash_table_lookup(priv->ui_settings, ui)) == NULL)
 		return default_value;
 
 	if ((setting = g_hash_table_lookup(table, name)) == NULL)
 		return default_value;
 
-	g_return_val_if_fail(setting->type == PURPLE_PREF_BOOLEAN, default_value);
-
-	return setting->value.boolean;
+	g_return_val_if_fail(G_VALUE_HOLDS_BOOLEAN(&setting->value), default_value);
+
+	return g_value_get_boolean(&setting->value);
 }
 
-gpointer
-purple_account_get_ui_data(const PurpleAccount *account)
-{
-        g_return_val_if_fail(account != NULL, NULL);
-
-        return account->ui_data;
-}
-
-void
-purple_account_set_ui_data(PurpleAccount *account,
-                                 gpointer ui_data)
-{
-        g_return_if_fail(account != NULL);
-
-        account->ui_data = ui_data;
-}
-
-
 PurpleLog *
 purple_account_get_log(PurpleAccount *account, gboolean create)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_val_if_fail(account != NULL, NULL);
 
-	if(!account->system_log && create){
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	if(!priv->system_log && create){
 		PurplePresence *presence;
 		int login_time;
 
 		presence = purple_account_get_presence(account);
 		login_time = purple_presence_get_login_time(presence);
 
-		account->system_log	 = purple_log_new(PURPLE_LOG_SYSTEM,
+		priv->system_log	 = purple_log_new(PURPLE_LOG_SYSTEM,
 				purple_account_get_username(account), account, NULL,
 				(login_time != 0) ? login_time : time(NULL), NULL);
 	}
 
-	return account->system_log;
+	return priv->system_log;
 }
 
 void
 purple_account_destroy_log(PurpleAccount *account)
 {
+	PurpleAccountPrivate *priv;
+
 	g_return_if_fail(account != NULL);
 
-	if(account->system_log){
-		purple_log_free(account->system_log);
-		account->system_log = NULL;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	if(priv->system_log){
+		purple_log_free(priv->system_log);
+		priv->system_log = NULL;
 	}
 }
 
@@ -2829,45 +2363,27 @@
 	return prpl_info->offline_message(buddy);
 }
 
-static void
-signed_on_cb(PurpleConnection *gc,
-             gpointer unused)
-{
-	PurpleAccount *account = purple_connection_get_account(gc);
-	purple_account_clear_current_error(account);
-
-	purple_signal_emit(purple_accounts_get_handle(), "account-signed-on",
-	                   account);
-}
-
-static void
-signed_off_cb(PurpleConnection *gc,
-              gpointer unused)
-{
-	PurpleAccount *account = purple_connection_get_account(gc);
-
-	purple_signal_emit(purple_accounts_get_handle(), "account-signed-off",
-	                   account);
-}
-
-static void
-set_current_error(PurpleAccount *account, PurpleConnectionErrorInfo *new_err)
+void
+purple_account_set_current_error(PurpleAccount *account,
+		PurpleConnectionErrorInfo *new_err)
 {
 	PurpleConnectionErrorInfo *old_err;
+	PurpleAccountPrivate *priv;
 
 	g_return_if_fail(account != NULL);
-
-	old_err = account->current_error;
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	old_err = priv->current_error;
 
 	if(new_err == old_err)
 		return;
 
-	account->current_error = new_err;
+	priv->current_error = new_err;
 
 	purple_signal_emit(purple_accounts_get_handle(),
 	                   "account-error-changed",
 	                   account, old_err, new_err);
-	schedule_accounts_save();
+	purple_accounts_schedule_save();
 
 	if(old_err)
 		g_free(old_err->description);
@@ -2876,435 +2392,714 @@
 	g_free(old_err);
 }
 
-static void
-connection_error_cb(PurpleConnection *gc,
-                    PurpleConnectionError type,
-                    const gchar *description,
-                    gpointer unused)
-{
-	PurpleAccount *account;
-	PurpleConnectionErrorInfo *err;
-
-	account = purple_connection_get_account(gc);
-
-	g_return_if_fail(account != NULL);
-
-	err = g_new0(PurpleConnectionErrorInfo, 1);
-	PURPLE_DBUS_REGISTER_POINTER(err, PurpleConnectionErrorInfo);
-
-	err->type = type;
-	err->description = g_strdup(description);
-
-	set_current_error(account, err);
-
-	purple_signal_emit(purple_accounts_get_handle(), "account-connection-error",
-	                   account, type, description);
-}
-
-static void
-password_migration_cb(PurpleAccount *account)
-{
-	/* account may be NULL (means: all) */
-
-	schedule_accounts_save();
-}
-
 const PurpleConnectionErrorInfo *
 purple_account_get_current_error(PurpleAccount *account)
 {
-	return account->current_error;
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	return priv->current_error;
 }
 
 void
 purple_account_clear_current_error(PurpleAccount *account)
 {
-	set_current_error(account, NULL);
+	purple_account_set_current_error(account, NULL);
 }
 
-void
-purple_accounts_add(PurpleAccount *account)
+static xmlnode *
+status_attr_to_xmlnode(const PurpleStatus *status, const PurpleStatusType *type,
+		const PurpleStatusAttr *attr)
 {
-	g_return_if_fail(account != NULL);
-
-	if (g_list_find(accounts, account) != NULL)
-		return;
-
-	accounts = g_list_append(accounts, account);
-
-	schedule_accounts_save();
-
-	purple_signal_emit(purple_accounts_get_handle(), "account-added", account);
+	xmlnode *node;
+	const char *id;
+	char *value = NULL;
+	PurpleStatusAttr *default_attr;
+	PurpleValue *default_value;
+	PurpleType attr_type;
+	PurpleValue *attr_value;
+
+	id = purple_status_attr_get_id(attr);
+	g_return_val_if_fail(id, NULL);
+
+	attr_value = purple_status_get_attr_value(status, id);
+	g_return_val_if_fail(attr_value, NULL);
+	attr_type = purple_value_get_type(attr_value);
+
+	/*
+	 * If attr_value is a different type than it should be
+	 * then don't write it to the file.
+	 */
+	default_attr = purple_status_type_get_attr(type, id);
+	default_value = purple_status_attr_get_value(default_attr);
+	if (attr_type != purple_value_get_type(default_value))
+		return NULL;
+
+	/*
+	 * If attr_value is the same as the default for this status
+	 * then there is no need to write it to the file.
+	 */
+	if (attr_type == PURPLE_TYPE_STRING)
+	{
+		const char *string_value = purple_value_get_string(attr_value);
+		const char *default_string_value = purple_value_get_string(default_value);
+		if (purple_strequal(string_value, default_string_value))
+			return NULL;
+		value = g_strdup(purple_value_get_string(attr_value));
+	}
+	else if (attr_type == PURPLE_TYPE_INT)
+	{
+		int int_value = purple_value_get_int(attr_value);
+		if (int_value == purple_value_get_int(default_value))
+			return NULL;
+		value = g_strdup_printf("%d", int_value);
+	}
+	else if (attr_type == PURPLE_TYPE_BOOLEAN)
+	{
+		gboolean boolean_value = purple_value_get_boolean(attr_value);
+		if (boolean_value == purple_value_get_boolean(default_value))
+			return NULL;
+		value = g_strdup(boolean_value ?
+								"true" : "false");
+	}
+	else
+	{
+		return NULL;
+	}
+
+	g_return_val_if_fail(value, NULL);
+
+	node = xmlnode_new("attribute");
+
+	xmlnode_set_attrib(node, "id", id);
+	xmlnode_set_attrib(node, "value", value);
+
+	g_free(value);
+
+	return node;
+}
+
+static xmlnode *
+status_attrs_to_xmlnode(const PurpleStatus *status)
+{
+	PurpleStatusType *type = purple_status_get_type(status);
+	xmlnode *node, *child;
+	GList *attrs, *attr;
+
+	node = xmlnode_new("attributes");
+
+	attrs = purple_status_type_get_attrs(type);
+	for (attr = attrs; attr != NULL; attr = attr->next)
+	{
+		child = status_attr_to_xmlnode(status, type, (const PurpleStatusAttr *)attr->data);
+		if (child)
+			xmlnode_insert_child(node, child);
+	}
+
+	return node;
+}
+
+static xmlnode *
+status_to_xmlnode(const PurpleStatus *status)
+{
+	xmlnode *node, *child;
+
+	node = xmlnode_new("status");
+	xmlnode_set_attrib(node, "type", purple_status_get_id(status));
+	if (purple_status_get_name(status) != NULL)
+		xmlnode_set_attrib(node, "name", purple_status_get_name(status));
+	xmlnode_set_attrib(node, "active", purple_status_is_active(status) ? "true" : "false");
+
+	child = status_attrs_to_xmlnode(status);
+	xmlnode_insert_child(node, child);
+
+	return node;
 }
 
-void
-purple_accounts_remove(PurpleAccount *account)
+static xmlnode *
+statuses_to_xmlnode(const PurplePresence *presence)
+{
+	xmlnode *node, *child;
+	GList *statuses;
+	PurpleStatus *status;
+
+	node = xmlnode_new("statuses");
+
+	statuses = purple_presence_get_statuses(presence);
+	for (; statuses != NULL; statuses = statuses->next)
+	{
+		status = statuses->data;
+		if (purple_status_type_is_saveable(purple_status_get_type(status)))
+		{
+			child = status_to_xmlnode(status);
+			xmlnode_insert_child(node, child);
+		}
+	}
+
+	return node;
+}
+
+static xmlnode *
+proxy_settings_to_xmlnode(PurpleProxyInfo *proxy_info)
 {
-	g_return_if_fail(account != NULL);
-
-	accounts = g_list_remove(accounts, account);
-
-	schedule_accounts_save();
-
-	/* Clearing the error ensures that account-error-changed is emitted,
-	 * which is the end of the guarantee that the the error's pointer is
-	 * valid.
+	xmlnode *node, *child;
+	PurpleProxyType proxy_type;
+	const char *value;
+	int int_value;
+	char buf[21];
+
+	proxy_type = purple_proxy_info_get_type(proxy_info);
+
+	node = xmlnode_new("proxy");
+
+	child = xmlnode_new_child(node, "type");
+	xmlnode_insert_data(child,
+			(proxy_type == PURPLE_PROXY_USE_GLOBAL ? "global" :
+			 proxy_type == PURPLE_PROXY_NONE       ? "none"   :
+			 proxy_type == PURPLE_PROXY_HTTP       ? "http"   :
+			 proxy_type == PURPLE_PROXY_SOCKS4     ? "socks4" :
+			 proxy_type == PURPLE_PROXY_SOCKS5     ? "socks5" :
+			 proxy_type == PURPLE_PROXY_TOR        ? "tor" :
+			 proxy_type == PURPLE_PROXY_USE_ENVVAR ? "envvar" : "unknown"), -1);
+
+	if ((value = purple_proxy_info_get_host(proxy_info)) != NULL)
+	{
+		child = xmlnode_new_child(node, "host");
+		xmlnode_insert_data(child, value, -1);
+	}
+
+	if ((int_value = purple_proxy_info_get_port(proxy_info)) != 0)
+	{
+		g_snprintf(buf, sizeof(buf), "%d", int_value);
+		child = xmlnode_new_child(node, "port");
+		xmlnode_insert_data(child, buf, -1);
+	}
+
+	if ((value = purple_proxy_info_get_username(proxy_info)) != NULL)
+	{
+		child = xmlnode_new_child(node, "username");
+		xmlnode_insert_data(child, value, -1);
+	}
+
+	if ((value = purple_proxy_info_get_password(proxy_info)) != NULL)
+	{
+		child = xmlnode_new_child(node, "password");
+		xmlnode_insert_data(child, value, -1);
+	}
+
+	return node;
+}
+
+static xmlnode *
+current_error_to_xmlnode(PurpleConnectionErrorInfo *err)
+{
+	xmlnode *node, *child;
+	char type_str[3];
+
+	node = xmlnode_new("current_error");
+
+	if(err == NULL)
+		return node;
+
+	/* It doesn't make sense to have transient errors persist across a
+	 * restart.
 	 */
-	purple_account_clear_current_error(account);
-	purple_signal_emit(purple_accounts_get_handle(), "account-removed", account);
+	if(!purple_connection_error_is_fatal (err->type))
+		return node;
+
+	child = xmlnode_new_child(node, "type");
+	g_snprintf(type_str, sizeof(type_str), "%u", err->type);
+	xmlnode_insert_data(child, type_str, -1);
+
+	child = xmlnode_new_child(node, "description");
+	if(err->description) {
+		char *utf8ized = purple_utf8_try_convert(err->description);
+		if(utf8ized == NULL)
+			utf8ized = purple_utf8_salvage(err->description);
+		xmlnode_insert_data(child, utf8ized, -1);
+		g_free(utf8ized);
+	}
+
+	return node;
+}
+
+static void
+setting_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
+{
+	const char *name;
+	PurpleAccountSetting *setting;
+	xmlnode *node, *child;
+	char buf[21];
+
+	name    = (const char *)key;
+	setting = (PurpleAccountSetting *)value;
+	node    = (xmlnode *)user_data;
+
+	child = xmlnode_new_child(node, "setting");
+	xmlnode_set_attrib(child, "name", name);
+
+	if (G_VALUE_HOLDS_INT(&setting->value)) {
+		xmlnode_set_attrib(child, "type", "int");
+		g_snprintf(buf, sizeof(buf), "%d", g_value_get_int(&setting->value));
+		xmlnode_insert_data(child, buf, -1);
+	}
+	else if (G_VALUE_HOLDS_STRING(&setting->value) && g_value_get_string(&setting->value) != NULL) {
+		xmlnode_set_attrib(child, "type", "string");
+		xmlnode_insert_data(child, g_value_get_string(&setting->value), -1);
+	}
+	else if (G_VALUE_HOLDS_BOOLEAN(&setting->value)) {
+		xmlnode_set_attrib(child, "type", "bool");
+		g_snprintf(buf, sizeof(buf), "%d", g_value_get_boolean(&setting->value));
+		xmlnode_insert_data(child, buf, -1);
+	}
 }
 
 static void
-purple_accounts_delete_set(PurpleAccount *account, GError *error, gpointer data)
+ui_setting_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
 {
-	purple_account_destroy(account);
+	const char *ui;
+	GHashTable *table;
+	xmlnode *node, *child;
+
+	ui    = (const char *)key;
+	table = (GHashTable *)value;
+	node  = (xmlnode *)user_data;
+
+	if (g_hash_table_size(table) > 0)
+	{
+		child = xmlnode_new_child(node, "settings");
+		xmlnode_set_attrib(child, "ui", ui);
+		g_hash_table_foreach(table, setting_to_xmlnode, child);
+	}
 }
 
-void
-purple_accounts_delete(PurpleAccount *account)
+xmlnode *
+purple_account_to_xmlnode(PurpleAccount *account)
 {
-	PurpleBlistNode *gnode, *cnode, *bnode;
-	GList *iter;
-
-	g_return_if_fail(account != NULL);
-
-	/*
-	 * Disable the account before blowing it out of the water.
-	 * Conceptually it probably makes more sense to disable the
-	 * account for all UIs rather than the just the current UI,
-	 * but it doesn't really matter.
-	 */
-	purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
-
-	purple_notify_close_with_handle(account);
-	purple_request_close_with_handle(account);
-
-	purple_accounts_remove(account);
-
-	/* Remove this account's buddies */
-	for (gnode = purple_blist_get_root();
-	     gnode != NULL;
-		 gnode = purple_blist_node_get_sibling_next(gnode))
+	xmlnode *node, *child;
+	const char *tmp;
+	PurplePresence *presence;
+	PurpleProxyInfo *proxy_info;
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	node = xmlnode_new("account");
+
+	child = xmlnode_new_child(node, "protocol");
+	xmlnode_insert_data(child, purple_account_get_protocol_id(account), -1);
+
+	child = xmlnode_new_child(node, "name");
+	xmlnode_insert_data(child, purple_account_get_username(account), -1);
+
+	if (purple_account_get_remember_password(account))
 	{
-		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
-			continue;
-
-		cnode = purple_blist_node_get_first_child(gnode);
-		while (cnode) {
-			PurpleBlistNode *cnode_next = purple_blist_node_get_sibling_next(cnode);
-
-			if(PURPLE_BLIST_NODE_IS_CONTACT(cnode)) {
-				bnode = purple_blist_node_get_first_child(cnode);
-				while (bnode) {
-					PurpleBlistNode *bnode_next = purple_blist_node_get_sibling_next(bnode);
-
-					if (PURPLE_BLIST_NODE_IS_BUDDY(bnode)) {
-						PurpleBuddy *b = (PurpleBuddy *)bnode;
-
-						if (purple_buddy_get_account(b) == account)
-							purple_blist_remove_buddy(b);
-					}
-					bnode = bnode_next;
-				}
-			} else if (PURPLE_BLIST_NODE_IS_CHAT(cnode)) {
-				PurpleChat *c = (PurpleChat *)cnode;
-
-				if (purple_chat_get_account(c) == account)
-					purple_blist_remove_chat(c);
-			}
-			cnode = cnode_next;
+		const char *keyring_id = NULL;
+		const char *mode = NULL;
+		char *data = NULL;
+		GError *error = NULL;
+		GDestroyNotify destroy = NULL;
+		gboolean exported = purple_keyring_export_password(account,
+			&keyring_id, &mode, &data, &error, &destroy);
+
+		if (error != NULL) {
+			purple_debug_error("account",
+				"Failed to export password for account %s: %s.\n",
+				purple_account_get_username(account),
+				error->message);
+		} else if (exported) {
+			child = xmlnode_new_child(node, "password");
+			if (keyring_id != NULL)
+				xmlnode_set_attrib(child, "keyring_id", keyring_id);
+			if (mode != NULL)
+				xmlnode_set_attrib(child, "mode", mode);
+			if (data != NULL)
+				xmlnode_insert_data(child, data, -1);
+
+			if (destroy != NULL)
+				destroy(data);
 		}
 	}
 
-	/* Remove any open conversation for this account */
-	for (iter = purple_get_conversations(); iter; ) {
-		PurpleConversation *conv = iter->data;
-		iter = iter->next;
-		if (purple_conversation_get_account(conv) == account)
-			purple_conversation_destroy(conv);
+	if ((tmp = purple_account_get_private_alias(account)) != NULL)
+	{
+		child = xmlnode_new_child(node, "alias");
+		xmlnode_insert_data(child, tmp, -1);
+	}
+
+	if ((presence = purple_account_get_presence(account)) != NULL)
+	{
+		child = statuses_to_xmlnode(presence);
+		xmlnode_insert_child(node, child);
+	}
+
+	if ((tmp = purple_account_get_user_info(account)) != NULL)
+	{
+		/* TODO: Do we need to call purple_str_strip_char(tmp, '\r') here? */
+		child = xmlnode_new_child(node, "userinfo");
+		xmlnode_insert_data(child, tmp, -1);
+	}
+
+	if (g_hash_table_size(priv->settings) > 0)
+	{
+		child = xmlnode_new_child(node, "settings");
+		g_hash_table_foreach(priv->settings, setting_to_xmlnode, child);
+	}
+
+	if (g_hash_table_size(priv->ui_settings) > 0)
+	{
+		g_hash_table_foreach(priv->ui_settings, ui_setting_to_xmlnode, node);
+	}
+
+	if ((proxy_info = purple_account_get_proxy_info(account)) != NULL)
+	{
+		child = proxy_settings_to_xmlnode(proxy_info);
+		xmlnode_insert_child(node, child);
 	}
 
-	/* Remove this account's pounces */
-	purple_pounce_destroy_all_by_account(account);
-
-	/* This will cause the deletion of an old buddy icon. */
-	purple_buddy_icons_set_account_icon(account, NULL, 0);
-
-	/* This is async because we do not want the
-	 * account being overwritten before we are done.
-	 */
-	purple_keyring_set_password(account, NULL,
-		purple_accounts_delete_set, NULL);
+	child = current_error_to_xmlnode(priv->current_error);
+	xmlnode_insert_child(node, child);
+
+	return node;
 }
 
-void
-purple_accounts_reorder(PurpleAccount *account, gint new_index)
+/****************
+ * GObject Code *
+ ****************/
+
+/* GObject Property names */
+#define PROP_USERNAME_S           "username"
+#define PROP_PRIVATE_ALIAS_S      "private-alias"
+#define PROP_ENABLED_S            "enabled"
+#define PROP_CONNECTION_S         "connection"
+#define PROP_PROTOCOL_ID_S        "protocol-id"
+#define PROP_USER_INFO_S          "userinfo"
+#define PROP_BUDDY_ICON_PATH_S    "buddy-icon-path"
+#define PROP_REMEMBER_PASSWORD_S  "remember-password"
+#define PROP_CHECK_MAIL_S         "check-mail"
+
+/* Set method for GObject properties */
+static void
+purple_account_set_property(GObject *obj, guint param_id, const GValue *value,
+		GParamSpec *pspec)
 {
-	gint index;
-	GList *l;
-
-	g_return_if_fail(account != NULL);
-	g_return_if_fail(new_index <= g_list_length(accounts));
-
-	index = g_list_index(accounts, account);
-
-	if (index == -1) {
-		purple_debug_error("account",
-				   "Unregistered account (%s) discovered during reorder!\n",
-				   purple_account_get_username(account));
-		return;
+	PurpleAccount *account = PURPLE_ACCOUNT(obj);
+
+	switch (param_id) {
+		case PROP_USERNAME:
+			purple_account_set_username(account, g_value_get_string(value));
+			break;
+		case PROP_PRIVATE_ALIAS:
+			purple_account_set_private_alias(account, g_value_get_string(value));
+			break;
+		case PROP_ENABLED:
+			purple_account_set_enabled(account, purple_core_get_ui(),
+					g_value_get_boolean(value));
+			break;
+		case PROP_CONNECTION:
+#warning TODO: change get_pointer to get_object when PurpleConnection is a GObject
+			purple_account_set_connection(account, g_value_get_pointer(value));
+			break;
+		case PROP_PROTOCOL_ID:
+			purple_account_set_protocol_id(account, g_value_get_string(value));
+			break;
+		case PROP_USER_INFO:
+			purple_account_set_user_info(account, g_value_get_string(value));
+			break;
+		case PROP_BUDDY_ICON_PATH:
+			purple_account_set_buddy_icon_path(account,
+					g_value_get_string(value));
+			break;
+		case PROP_REMEMBER_PASSWORD:
+			purple_account_set_remember_password(account,
+					g_value_get_boolean(value));
+			break;
+		case PROP_CHECK_MAIL:
+			purple_account_set_check_mail(account, 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_account_get_property(GObject *obj, guint param_id, GValue *value,
+		GParamSpec *pspec)
+{
+	PurpleAccount *account = PURPLE_ACCOUNT(obj);
+
+	switch (param_id) {
+		case PROP_USERNAME:
+			g_value_set_string(value, purple_account_get_username(account));
+			break;
+		case PROP_PRIVATE_ALIAS:
+			g_value_set_string(value, purple_account_get_private_alias(account));
+			break;
+		case PROP_ENABLED:
+			g_value_set_boolean(value, purple_account_get_enabled(account,
+					purple_core_get_ui()));
+			break;
+		case PROP_CONNECTION:
+#warning TODO: change set_pointer to set_object when PurpleConnection is a GObject
+			g_value_set_pointer(value, purple_account_get_connection(account));
+			break;
+		case PROP_PROTOCOL_ID:
+			g_value_set_string(value, purple_account_get_protocol_id(account));
+			break;
+		case PROP_USER_INFO:
+			g_value_set_string(value, purple_account_get_user_info(account));
+			break;
+		case PROP_BUDDY_ICON_PATH:
+			g_value_set_string(value,
+					purple_account_get_buddy_icon_path(account));
+			break;
+		case PROP_REMEMBER_PASSWORD:
+			g_value_set_boolean(value,
+					purple_account_get_remember_password(account));
+			break;
+		case PROP_CHECK_MAIL:
+			g_value_set_boolean(value, purple_account_get_check_mail(account));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
 	}
-
-	l = g_list_nth(accounts, index);
-
-	if (new_index > index)
-		new_index--;
-
-	/* Remove the old one. */
-	accounts = g_list_delete_link(accounts, l);
-
-	/* Insert it where it should go. */
-	accounts = g_list_insert(accounts, account, new_index);
-
-	schedule_accounts_save();
+}
+
+/* GObject initialization function */
+static void purple_account_init(GTypeInstance *instance, gpointer klass)
+{
+	PurpleAccount *account = PURPLE_ACCOUNT(instance);
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	priv->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
+			g_free, delete_setting);
+	priv->ui_settings = g_hash_table_new_full(g_str_hash, g_str_equal,
+			g_free, (GDestroyNotify)g_hash_table_destroy);
+	priv->system_log = NULL;
+
+	priv->privacy_type = PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL;
 }
 
-GList *
-purple_accounts_get_all(void)
+/* GObject dispose function */
+static void
+purple_account_dispose(GObject *object)
+{
+	GList *l;
+	PurpleAccount *account = PURPLE_ACCOUNT(object);
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	purple_debug_info("account", "Destroying account %p\n", account);
+	purple_signal_emit(purple_accounts_get_handle(), "account-destroying",
+						account);
+
+	for (l = purple_get_conversations(); l != NULL; l = l->next)
+	{
+		PurpleConversation *conv = (PurpleConversation *)l->data;
+
+		if (purple_conversation_get_account(conv) == account)
+			purple_conversation_set_account(conv, NULL);
+	}
+
+	purple_account_set_status_types(account, NULL);
+
+	if (priv->proxy_info)
+		purple_proxy_info_destroy(priv->proxy_info);
+
+	if (priv->presence)
+		purple_presence_destroy(priv->presence);
+
+	if(priv->system_log)
+		purple_log_free(priv->system_log);
+
+	if (priv->current_error) {
+		g_free(priv->current_error->description);
+		g_free(priv->current_error);
+	}
+
+	PURPLE_DBUS_UNREGISTER_POINTER(priv->current_error);
+	PURPLE_DBUS_UNREGISTER_POINTER(account);
+
+	parent_class->dispose(object);
+}
+
+/* GObject finalize function */
+static void
+purple_account_finalize(GObject *object)
+{
+	PurpleAccount *account = PURPLE_ACCOUNT(object);
+	PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	g_free(priv->username);
+	g_free(priv->alias);
+	purple_str_wipe(priv->password);
+	g_free(priv->user_info);
+	g_free(priv->buddy_icon_path);
+	g_free(priv->protocol_id);
+
+	g_hash_table_destroy(priv->settings);
+	g_hash_table_destroy(priv->ui_settings);
+
+	while (priv->deny) {
+		g_free(priv->deny->data);
+		priv->deny = g_slist_delete_link(priv->deny, priv->deny);
+	}
+
+	while (priv->permit) {
+		g_free(priv->permit->data);
+		priv->permit = g_slist_delete_link(priv->permit, priv->permit);
+	}
+
+	parent_class->finalize(object);
+}
+
+/* Class initializer function */
+static void purple_account_class_init(PurpleAccountClass *klass)
 {
-	return accounts;
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	obj_class->dispose = purple_account_dispose;
+	obj_class->finalize = purple_account_finalize;
+
+	/* Setup properties */
+	obj_class->get_property = purple_account_get_property;
+	obj_class->set_property = purple_account_set_property;
+
+	g_object_class_install_property(obj_class, PROP_USERNAME,
+			g_param_spec_string(PROP_USERNAME_S, _("Username"),
+				_("The username for the account."), NULL,
+				G_PARAM_READWRITE | G_PARAM_CONSTRUCT)
+			);
+
+	g_object_class_install_property(obj_class, PROP_PRIVATE_ALIAS,
+			g_param_spec_string(PROP_PRIVATE_ALIAS_S, _("Private Alias"),
+				_("The private alias for the account."), NULL,
+				G_PARAM_READWRITE)
+			);
+
+	g_object_class_install_property(obj_class, PROP_USER_INFO,
+			g_param_spec_string(PROP_USER_INFO_S, _("User information"),
+				_("Detailed user information for the account."), NULL,
+				G_PARAM_READWRITE)
+			);
+
+	g_object_class_install_property(obj_class, PROP_BUDDY_ICON_PATH,
+			g_param_spec_string(PROP_BUDDY_ICON_PATH_S, _("Buddy icon path"),
+				_("Path to the buddyicon for the account."), NULL,
+				G_PARAM_READWRITE)
+			);
+
+	g_object_class_install_property(obj_class, PROP_ENABLED,
+			g_param_spec_boolean(PROP_ENABLED_S, _("Enabled"),
+				_("Whether the account is enabled or not."), FALSE,
+				G_PARAM_READWRITE | G_PARAM_CONSTRUCT)
+			);
+
+	g_object_class_install_property(obj_class, PROP_REMEMBER_PASSWORD,
+			g_param_spec_boolean(PROP_REMEMBER_PASSWORD_S, _("Remember password"),
+				_("Whether to remember and store the password for this account."), FALSE,
+				G_PARAM_READWRITE | G_PARAM_CONSTRUCT)
+			);
+
+	g_object_class_install_property(obj_class, PROP_CHECK_MAIL,
+			g_param_spec_boolean(PROP_CHECK_MAIL_S, _("Check mail"),
+				_("Whether to check mails for this account."), FALSE,
+				G_PARAM_READWRITE | G_PARAM_CONSTRUCT)
+			);
+
+#warning TODO: change spec_pointer to spec_object when PurpleConnection is a GObject
+	g_object_class_install_property(obj_class, PROP_CONNECTION,
+			g_param_spec_pointer(PROP_CONNECTION_S, _("Connection"),
+				_("The PurpleConnection object for the account."),
+				G_PARAM_READWRITE)
+			);
+
+	g_object_class_install_property(obj_class, PROP_PROTOCOL_ID,
+			g_param_spec_string(PROP_PROTOCOL_ID_S, _("Protocol ID"),
+				_("ID of the protocol that is responsible for the account."), NULL,
+				G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)
+			);
+
+	g_type_class_add_private(klass, sizeof(PurpleAccountPrivate));
 }
 
-GList *
-purple_accounts_get_all_active(void)
+GType
+purple_account_get_type(void)
 {
-	GList *list = NULL;
-	GList *all = purple_accounts_get_all();
-
-	while (all != NULL) {
-		PurpleAccount *account = all->data;
-
-		if (purple_account_get_enabled(account, purple_core_get_ui()))
-			list = g_list_append(list, account);
-
-		all = all->next;
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleAccountClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_account_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleAccount),
+			0,
+			(GInstanceInitFunc)purple_account_init,
+			NULL,
+		};
+
+		type = g_type_register_static(G_TYPE_OBJECT,
+				"PurpleAccount",
+				&info, 0);
 	}
 
-	return list;
+	return type;
 }
 
 PurpleAccount *
-purple_accounts_find(const char *name, const char *protocol_id)
+purple_account_new(const char *username, const char *protocol_id)
 {
 	PurpleAccount *account = NULL;
-	GList *l;
-	char *who;
-
-	g_return_val_if_fail(name != NULL, NULL);
+	PurplePlugin *prpl = NULL;
+	PurplePluginProtocolInfo *prpl_info = NULL;
+	PurpleStatusType *status_type;
+	PurpleAccountPrivate *priv;
+
+	g_return_val_if_fail(username != NULL, NULL);
 	g_return_val_if_fail(protocol_id != NULL, NULL);
 
-	for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
-		account = (PurpleAccount *)l->data;
-		if (!purple_strequal(account->protocol_id, protocol_id))
-			continue;
-
-		who = g_strdup(purple_normalize(account, name));
-		if (purple_strequal(purple_normalize(account, purple_account_get_username(account)), who)) {
-			g_free(who);
-			return account;
-		}
-		g_free(who);
-	}
-
-	return NULL;
-}
-
-void
-purple_accounts_restore_current_statuses()
-{
-	GList *l;
-	PurpleAccount *account;
-
-	/* If we're not connected to the Internet right now, we bail on this */
-	if (!purple_network_is_available())
-	{
-		purple_debug_warning("account", "Network not connected; skipping reconnect\n");
-		return;
-	}
-
-	for (l = purple_accounts_get_all(); l != NULL; l = l->next)
-	{
-		account = (PurpleAccount *)l->data;
-		if (purple_account_get_enabled(account, purple_core_get_ui()) &&
-			(purple_presence_is_online(account->presence)))
-		{
-			purple_account_connect(account);
-		}
-	}
-}
-
-void
-purple_accounts_set_ui_ops(PurpleAccountUiOps *ops)
-{
-	account_ui_ops = ops;
-}
-
-PurpleAccountUiOps *
-purple_accounts_get_ui_ops(void)
-{
-	return account_ui_ops;
-}
-
-void *
-purple_accounts_get_handle(void)
-{
-	static int handle;
-
-	return &handle;
+	account = purple_accounts_find(username, protocol_id);
+
+	if (account != NULL)
+		return account;
+
+	account = g_object_new(PURPLE_TYPE_ACCOUNT,
+					PROP_USERNAME_S, username,
+					PROP_PROTOCOL_ID_S, protocol_id,
+					NULL);
+	PURPLE_DBUS_REGISTER_POINTER(account, PurpleAccount);
+
+	purple_signal_emit(purple_accounts_get_handle(), "account-created",
+			account);
+
+	prpl = purple_find_prpl(protocol_id);
+	if (prpl == NULL)
+		return account;
+
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+	if (prpl_info != NULL && prpl_info->status_types != NULL)
+		purple_account_set_status_types(account,
+				prpl_info->status_types(account));
+
+	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
+
+	priv->presence = purple_presence_new_for_account(account);
+
+	status_type = purple_account_get_status_type_with_primitive(account,
+			PURPLE_STATUS_AVAILABLE);
+	if (status_type != NULL)
+		purple_presence_set_status_active(priv->presence,
+										purple_status_type_get_id(status_type),
+										TRUE);
+	else
+		purple_presence_set_status_active(priv->presence,
+										"offline",
+										TRUE);
+
+	return account;
 }
-
-void
-purple_accounts_init(void)
-{
-	void *handle = purple_accounts_get_handle();
-	void *conn_handle = purple_connections_get_handle();
-
-	purple_signal_register(handle, "account-connecting",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-disabled",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-enabled",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-setting-info",
-						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "account-set-info",
-						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "account-created",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-destroying",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-added",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-removed",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-status-changed",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_STATUS),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_STATUS));
-
-	purple_signal_register(handle, "account-actions-changed",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-alias-changed",
-						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-							 			PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "account-authorization-requested",
-						purple_marshal_INT__POINTER_POINTER_POINTER,
-						purple_value_new(PURPLE_TYPE_INT), 4,
-						purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						purple_value_new(PURPLE_TYPE_STRING),
-						purple_value_new(PURPLE_TYPE_STRING),
-						purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "account-authorization-denied",
-						purple_marshal_VOID__POINTER_POINTER, NULL, 3,
-						purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						purple_value_new(PURPLE_TYPE_STRING),
-						purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "account-authorization-granted",
-						purple_marshal_VOID__POINTER_POINTER, NULL, 3,
-						purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						purple_value_new(PURPLE_TYPE_STRING),
-						purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "account-error-changed",
-	                       purple_marshal_VOID__POINTER_POINTER_POINTER,
-	                       NULL, 3,
-	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
-	                                        PURPLE_SUBTYPE_ACCOUNT),
-	                       purple_value_new(PURPLE_TYPE_POINTER),
-	                       purple_value_new(PURPLE_TYPE_POINTER));
-
-	purple_signal_register(handle, "account-signed-on",
-	                       purple_marshal_VOID__POINTER, NULL, 1,
-	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
-	                                        PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-signed-off",
-	                       purple_marshal_VOID__POINTER, NULL, 1,
-	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
-	                                        PURPLE_SUBTYPE_ACCOUNT));
-
-	purple_signal_register(handle, "account-connection-error",
-	                       purple_marshal_VOID__POINTER_INT_POINTER, NULL, 3,
-	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
-	                                        PURPLE_SUBTYPE_ACCOUNT),
-	                       purple_value_new(PURPLE_TYPE_ENUM),
-	                       purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_connect(conn_handle, "signed-on", handle,
-	                      PURPLE_CALLBACK(signed_on_cb), NULL);
-	purple_signal_connect(conn_handle, "signed-off", handle,
-	                      PURPLE_CALLBACK(signed_off_cb), NULL);
-	purple_signal_connect(conn_handle, "connection-error", handle,
-	                      PURPLE_CALLBACK(connection_error_cb), NULL);
-	purple_signal_connect(purple_keyring_get_handle(), "password-migration", handle,
-	                      PURPLE_CALLBACK(password_migration_cb), NULL);
-
-	load_accounts();
-
-}
-
-void
-purple_accounts_uninit(void)
-{
-	gpointer handle = purple_accounts_get_handle();
-	if (save_timer != 0)
-	{
-		purple_timeout_remove(save_timer);
-		save_timer = 0;
-		sync_accounts();
-	}
-
-	for (; accounts; accounts = g_list_delete_link(accounts, accounts))
-		purple_account_destroy(accounts->data);
-
-	purple_signals_disconnect_by_handle(handle);
-	purple_signals_unregister_by_instance(handle);
-}
--- a/libpurple/account.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/account.h	Sun Jun 23 13:35:53 2013 +0530
@@ -30,10 +30,17 @@
 #include <glib.h>
 #include <glib-object.h>
 
-/** @copydoc _PurpleAccountUiOps */
-typedef struct _PurpleAccountUiOps PurpleAccountUiOps;
+#define PURPLE_TYPE_ACCOUNT             (purple_account_get_type())
+#define PURPLE_ACCOUNT(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_ACCOUNT, PurpleAccount))
+#define PURPLE_ACCOUNT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_ACCOUNT, PurpleAccountClass))
+#define PURPLE_IS_ACCOUNT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_ACCOUNT))
+#define PURPLE_IS_ACCOUNT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_ACCOUNT))
+#define PURPLE_ACCOUNT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_ACCOUNT, PurpleAccountClass))
+
 /** @copydoc _PurpleAccount */
-typedef struct _PurpleAccount      PurpleAccount;
+typedef struct _PurpleAccount       PurpleAccount;
+/** @copydoc _PurpleAccountClass */
+typedef struct _PurpleAccountClass  PurpleAccountClass;
 
 typedef gboolean (*PurpleFilterAccountFunc)(PurpleAccount *account);
 typedef void (*PurpleAccountRequestAuthorizationCb)(const char *, void *);
@@ -46,11 +53,11 @@
 
 #include "connection.h"
 #include "log.h"
-#include "privacy.h"
 #include "proxy.h"
 #include "prpl.h"
 #include "status.h"
 #include "keyring.h"
+#include "xmlnode.h"
 
 /**
  * Account request types.
@@ -71,51 +78,24 @@
 	PURPLE_ACCOUNT_RESPONSE_ACCEPT = 1
 } PurpleAccountRequestResponse;
 
-/**  Account UI operations, used to notify the user of status changes and when
- *   buddies add this account to their buddy lists.
+/**
+ * Privacy data types.
  */
-struct _PurpleAccountUiOps
+typedef enum
 {
-	/** A buddy who is already on this account's buddy list added this account
-	 *  to their buddy list.
-	 */
-	void (*notify_added)(PurpleAccount *account,
-	                     const char *remote_user,
-	                     const char *id,
-	                     const char *alias,
-	                     const char *message);
-
-	/** This account's status changed. */
-	void (*status_changed)(PurpleAccount *account,
-	                       PurpleStatus *status);
+	PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL = 1,
+	PURPLE_ACCOUNT_PRIVACY_DENY_ALL,
+	PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS,
+	PURPLE_ACCOUNT_PRIVACY_DENY_USERS,
+	PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST
+} PurpleAccountPrivacyType;
 
-	/** Someone we don't have on our list added us; prompt to add them. */
-	void (*request_add)(PurpleAccount *account,
-	                    const char *remote_user,
-	                    const char *id,
-	                    const char *alias,
-	                    const char *message);
-
-	/** Prompt for authorization when someone adds this account to their buddy
-	 * list.  To authorize them to see this account's presence, call \a
-	 * authorize_cb (\a message, \a user_data); otherwise call
-	 * \a deny_cb (\a message, \a user_data);
-	 * @return a UI-specific handle, as passed to #close_account_request.
-	 */
-	void *(*request_authorize)(PurpleAccount *account,
-	                           const char *remote_user,
-	                           const char *id,
-	                           const char *alias,
-	                           const char *message,
-	                           gboolean on_list,
-	                           PurpleAccountRequestAuthorizationCb authorize_cb,
-	                           PurpleAccountRequestAuthorizationCb deny_cb,
-	                           void *user_data);
-
-	/** Close a pending request for authorization.  \a ui_handle is a handle
-	 *  as returned by #request_authorize.
-	 */
-	void (*close_account_request)(void *ui_handle);
+/** Structure representing an account.
+ */
+struct _PurpleAccount
+{
+	/*< private >*/
+	GObject gparent;
 
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
@@ -123,58 +103,25 @@
 	void (*_purple_reserved4)(void);
 };
 
-/** Structure representing an account.
+/**
+ * PurpleAccountClass:
+ *
+ * The base class for all #PurpleAccount's.
  */
-struct _PurpleAccount
-{
-	char *username;             /**< The username.                          */
-	char *alias;                /**< How you appear to yourself.            */
-	char *password;             /**< The account password.                  */
-	char *user_info;            /**< User information.                      */
-
-	char *buddy_icon_path;      /**< The buddy icon's non-cached path.      */
-
-	gboolean remember_pass;     /**< Remember the password.                 */
-
-	char *protocol_id;          /**< The ID of the protocol.                */
-
-	PurpleConnection *gc;         /**< The connection handle.                 */
-	gboolean disconnecting;     /**< The account is currently disconnecting */
-
-	GHashTable *settings;       /**< Protocol-specific settings.            */
-	GHashTable *ui_settings;    /**< UI-specific settings.                  */
+struct _PurpleAccountClass {
+	/*< private >*/
+	GObjectClass parent_class;
 
-	PurpleProxyInfo *proxy_info;  /**< Proxy information.  This will be set   */
-								/*   to NULL when the account inherits      */
-								/*   proxy settings from global prefs.      */
-
-	/*
-	 * TODO: Supplementing the next two linked lists with hash tables
-	 * should help performance a lot when these lists are long.  This
-	 * matters quite a bit for protocols like MSN, where all your
-	 * buddies are added to your permit list.  Currently we have to
-	 * iterate through the entire list if we want to check if someone
-	 * is permitted or denied.  We should do this for 3.0.0.
-	 * Or maybe use a GTree.
-	 */
-	GSList *permit;             /**< Permit list.                           */
-	GSList *deny;               /**< Deny list.                             */
-	PurplePrivacyType perm_deny;  /**< The permit/deny setting.               */
-
-	GList *status_types;        /**< Status types.                          */
-
-	PurplePresence *presence;     /**< Presence.                              */
-	PurpleLog *system_log;        /**< The system log                         */
-
-	void *ui_data;              /**< The UI can put data here.              */
-	PurpleAccountRegistrationCb registration_cb;
-	void *registration_cb_user_data;
-
-	PurpleConnectionErrorInfo *current_error;	/**< Errors */
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
 };
 
 G_BEGIN_DECLS
 
+GType purple_account_get_type(void);
+
 /**************************************************************************/
 /** @name Account API                                                     */
 /**************************************************************************/
@@ -191,13 +138,6 @@
 PurpleAccount *purple_account_new(const char *username, const char *protocol_id);
 
 /**
- * Destroys an account.
- *
- * @param account The account to destroy.
- */
-void purple_account_destroy(PurpleAccount *account);
-
-/**
  * Connects to an account.
  *
  * @param account The account to connect to.
@@ -379,12 +319,12 @@
 	PurpleKeyringSaveCallback cb, gpointer data);
 
 /**
- * Sets the account's alias.
+ * Sets the account's private alias.
  *
  * @param account The account.
  * @param alias   The alias.
  */
-void purple_account_set_alias(PurpleAccount *account, const char *alias);
+void purple_account_set_private_alias(PurpleAccount *account, const char *alias);
 
 /**
  * Sets the account's user information
@@ -460,7 +400,7 @@
  * @param account      The account.
  * @param privacy_type The privacy type.
  */
-void purple_account_set_privacy_type(PurpleAccount *account, PurplePrivacyType privacy_type);
+void purple_account_set_privacy_type(PurpleAccount *account, PurpleAccountPrivacyType privacy_type);
 
 /**
  * Sets the account's status types.
@@ -629,25 +569,6 @@
 							  const char *name, gboolean value);
 
 /**
- * Returns the UI data associated with this account.
- *
- * @param account The account.
- *
- * @return The UI data associated with this object.  This is a
- *         convenience field provided to the UIs--it is not
- *         used by the libuprple core.
- */
-gpointer purple_account_get_ui_data(const PurpleAccount *account);
-
-/**
- * Set the UI data associated with this account.
- *
- * @param account The account.
- * @param ui_data A pointer to associate with this object.
- */
-void purple_account_set_ui_data(PurpleAccount *account, gpointer ui_data);
-
-/**
  * Returns whether or not the account is connected.
  *
  * @param account The account.
@@ -699,13 +620,13 @@
 	PurpleKeyringReadCallback cb, gpointer data);
 
 /**
- * Returns the account's alias.
+ * Returns the account's private alias.
  *
  * @param account The account.
  *
  * @return The alias.
  */
-const char *purple_account_get_alias(const PurpleAccount *account);
+const char *purple_account_get_private_alias(const PurpleAccount *account);
 
 /**
  * Returns the account's user information.
@@ -810,7 +731,135 @@
  *
  * @return The privacy type.
  */
-PurplePrivacyType purple_account_get_privacy_type(const PurpleAccount *account);
+PurpleAccountPrivacyType purple_account_get_privacy_type(const PurpleAccount *account);
+
+/**
+ * Adds a user to the account's permit list.
+ *
+ * @param account    The account.
+ * @param name       The name of the user to add to the list.
+ * @param local_only If TRUE, only the local list is updated, and not
+ *                   the server.
+ *
+ * @return TRUE if the user was added successfully, or @c FALSE otherwise.
+ */
+gboolean purple_account_privacy_permit_add(PurpleAccount *account,
+								const char *name, gboolean local_only);
+
+/**
+ * Removes a user from the account's permit list.
+ *
+ * @param account    The account.
+ * @param name       The name of the user to add to the list.
+ * @param local_only If TRUE, only the local list is updated, and not
+ *                   the server.
+ *
+ * @return TRUE if the user was removed successfully, or @c FALSE otherwise.
+ */
+gboolean purple_account_privacy_permit_remove(PurpleAccount *account,
+									const char *name, gboolean local_only);
+
+/**
+ * Adds a user to the account's deny list.
+ *
+ * @param account    The account.
+ * @param name       The name of the user to add to the list.
+ * @param local_only If TRUE, only the local list is updated, and not
+ *                   the server.
+ *
+ * @return TRUE if the user was added successfully, or @c FALSE otherwise.
+ */
+gboolean purple_account_privacy_deny_add(PurpleAccount *account,
+									const char *name, gboolean local_only);
+
+/**
+ * Removes a user from the account's deny list.
+ *
+ * @param account    The account.
+ * @param name       The name of the user to add to the list.
+ * @param local_only If TRUE, only the local list is updated, and not
+ *                   the server.
+ *
+ * @return TRUE if the user was removed successfully, or @c FALSE otherwise.
+ */
+gboolean purple_account_privacy_deny_remove(PurpleAccount *account,
+									const char *name, gboolean local_only);
+
+/**
+ * Allow a user to send messages. If current privacy setting for the account is:
+ *		PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:	The user is added to the allow-list.
+ *		PURPLE_ACCOUNT_PRIVACY_DENY_USERS	:	The user is removed from the
+ *		                                        deny-list.
+ *		PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL	:	No changes made.
+ *		PURPLE_ACCOUNT_PRIVACY_DENY_ALL	:	The privacy setting is changed to
+ *									PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS and the
+ *									user is added to the allow-list.
+ *		PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST: No changes made if the user is
+ *									already in the buddy-list. Otherwise the
+ *									setting is changed to
+ *		PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS, all the buddies are added to the
+ *									allow-list, and the user is also added to
+ *									the allow-list.
+ *
+ * The changes are reflected on the server. The previous allow/deny list is not
+ * restored if the privacy setting is changed.
+ *
+ * @param account	The account.
+ * @param who		The name of the user.
+ */
+void purple_account_privacy_allow(PurpleAccount *account, const char *who);
+
+/**
+ * Block messages from a user. If current privacy setting for the account is:
+ *		PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:	The user is removed from the
+ *											allow-list.
+ *		PURPLE_ACCOUNT_PRIVACY_DENY_USERS:	The user is added to the deny-list.
+ *		PURPLE_ACCOUNT_PRIVACY_DENY_ALL:	No changes made.
+ *		PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:	The privacy setting is changed to
+ *									PURPLE_ACCOUNT_PRIVACY_DENY_USERS and the
+ *									user is added to the deny-list.
+ *		PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST: If the user is not in the
+ *									buddy-list, then no changes made. Otherwise,
+ *									the setting is changed to
+ *									PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS, all
+ *									the buddies are added to the allow-list, and
+ *									this user is removed from the list.
+ *
+ * The changes are reflected on the server. The previous allow/deny list is not
+ * restored if the privacy setting is changed.
+ *
+ * @param account	The account.
+ * @param who		The name of the user.
+ */
+void purple_account_privacy_deny(PurpleAccount *account, const char *who);
+
+/**
+ * Returns the account's permit list.
+ *
+ * @param account	The account.
+ * @constreturn     A list of the permitted users
+ */
+GSList *purple_account_privacy_get_permitted(PurpleAccount *account);
+
+/**
+ * Returns the account's deny list.
+ *
+ * @param account	The account.
+ * @constreturn     A list of the denied users
+ */
+GSList *purple_account_privacy_get_denied(PurpleAccount *account);
+
+/**
+ * Check the privacy-setting for a user.
+ *
+ * @param account	The account.
+ * @param who		The name of the user.
+ *
+ * @return @c FALSE if the specified account's privacy settings block the user
+ *		or @c TRUE otherwise. The meaning of "block" is protocol-dependent and
+ *				generally relates to status and/or sending of messages.
+ */
+gboolean purple_account_privacy_check(PurpleAccount *account, const char *who);
 
 /**
  * Returns the active status for this account.  This looks through
@@ -1062,6 +1111,17 @@
 gboolean purple_account_supports_offline_message(PurpleAccount *account, PurpleBuddy *buddy);
 
 /**
+ * Sets the error that caused the account to be disconnected.
+ * You should not ever need to call this function directly, the error is set
+ * by the accouts subsystem. You should only need to retrieve this error.
+ *
+ * @param account The account whose error should be set.
+ * @param new_err The new error.
+ */
+void purple_account_set_current_error(PurpleAccount *account,
+									PurpleConnectionErrorInfo *new_err);
+
+/**
  * Get the error that caused the account to be disconnected, or @c NULL if the
  * account is happily connected or disconnected without an error.
  *
@@ -1080,128 +1140,13 @@
  */
 void purple_account_clear_current_error(PurpleAccount *account);
 
-/*@}*/
-
-/**************************************************************************/
-/** @name Accounts API                                                    */
-/**************************************************************************/
-/*@{*/
-
 /**
- * Adds an account to the list of accounts.
- *
- * @param account The account.
- */
-void purple_accounts_add(PurpleAccount *account);
-
-/**
- * Removes an account from the list of accounts.
- *
- * @param account The account.
- */
-void purple_accounts_remove(PurpleAccount *account);
-
-/**
- * Deletes an account.
- *
- * This will remove any buddies from the buddy list that belong to this
- * account, buddy pounces that belong to this account, and will also
- * destroy @a account.
- *
- * @param account The account.
- */
-void purple_accounts_delete(PurpleAccount *account);
-
-/**
- * Reorders an account.
- *
- * @param account   The account to reorder.
- * @param new_index The new index for the account.
- */
-void purple_accounts_reorder(PurpleAccount *account, gint new_index);
-
-/**
- * Returns a list of all accounts.
- *
- * @constreturn A list of all accounts.
- */
-GList *purple_accounts_get_all(void);
-
-/**
- * Returns a list of all enabled accounts
- *
- * @return A list of all enabled accounts. The list is owned
- *         by the caller, and must be g_list_free()d to avoid
- *         leaking the nodes.
- */
-GList *purple_accounts_get_all_active(void);
-
-/**
- * Finds an account with the specified name and protocol id.
+ * Get an XML description of an account.
  *
- * @param name     The account username.
- * @param protocol The account protocol ID.
- *
- * @return The account, if found, or @c FALSE otherwise.
- */
-PurpleAccount *purple_accounts_find(const char *name, const char *protocol);
-
-/**
- * This is called by the core after all subsystems and what
- * not have been initialized.  It sets all enabled accounts
- * to their startup status by signing them on, setting them
- * away, etc.
- *
- * You probably shouldn't call this unless you really know
- * what you're doing.
- */
-void purple_accounts_restore_current_statuses(void);
-
-/*@}*/
-
-
-/**************************************************************************/
-/** @name UI Registration Functions                                       */
-/**************************************************************************/
-/*@{*/
-/**
- * Sets the UI operations structure to be used for accounts.
- *
- * @param ops The UI operations structure.
+ * @param account  The account
+ * @return  The XML description of the account.
  */
-void purple_accounts_set_ui_ops(PurpleAccountUiOps *ops);
-
-/**
- * Returns the UI operations structure used for accounts.
- *
- * @return The UI operations structure in use.
- */
-PurpleAccountUiOps *purple_accounts_get_ui_ops(void);
-
-/*@}*/
-
-
-/**************************************************************************/
-/** @name Accounts Subsystem                                              */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Returns the accounts subsystem handle.
- *
- * @return The accounts subsystem handle.
- */
-void *purple_accounts_get_handle(void);
-
-/**
- * Initializes the accounts subsystem.
- */
-void purple_accounts_init(void);
-
-/**
- * Uninitializes the accounts subsystem.
- */
-void purple_accounts_uninit(void);
+xmlnode *purple_account_to_xmlnode(PurpleAccount *account);
 
 /*@}*/
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/accounts.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,1047 @@
+/**
+ * @file accounts.c Accounts API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+#include "accounts.h"
+#include "core.h"
+#include "dbus-maybe.h"
+#include "debug.h"
+#include "network.h"
+#include "pounce.h"
+
+static PurpleAccountUiOps *account_ui_ops = NULL;
+
+static GList   *accounts = NULL;
+static guint    save_timer = 0;
+static gboolean accounts_loaded = FALSE;
+
+/*********************************************************************
+ * Writing to disk                                                   *
+ *********************************************************************/
+static xmlnode *
+accounts_to_xmlnode(void)
+{
+	xmlnode *node, *child;
+	GList *cur;
+
+	node = xmlnode_new("account");
+	xmlnode_set_attrib(node, "version", "1.0");
+
+	for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
+	{
+		child = purple_account_to_xmlnode(cur->data);
+		xmlnode_insert_child(node, child);
+	}
+
+	return node;
+}
+
+static void
+sync_accounts(void)
+{
+	xmlnode *node;
+	char *data;
+
+	if (!accounts_loaded)
+	{
+		purple_debug_error("account", "Attempted to save accounts before "
+						 "they were read!\n");
+		return;
+	}
+
+	node = accounts_to_xmlnode();
+	data = xmlnode_to_formatted_str(node, NULL);
+	purple_util_write_data_to_file("accounts.xml", data, -1);
+	g_free(data);
+	xmlnode_free(node);
+}
+
+static gboolean
+save_cb(gpointer data)
+{
+	sync_accounts();
+	save_timer = 0;
+	return FALSE;
+}
+
+void
+purple_accounts_schedule_save(void)
+{
+	if (save_timer == 0)
+		save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
+}
+
+/*********************************************************************
+ * Reading from disk                                                 *
+ *********************************************************************/
+static void
+migrate_yahoo_japan(PurpleAccount *account)
+{
+	/* detect a Yahoo! JAPAN account that existed prior to 2.6.0 and convert it
+	 * to use the new prpl-yahoojp.  Also remove the account-specific settings
+	 * we no longer need */
+
+	if(purple_strequal(purple_account_get_protocol_id(account), "prpl-yahoo")) {
+		if(purple_account_get_bool(account, "yahoojp", FALSE)) {
+			const char *serverjp = purple_account_get_string(account, "serverjp", NULL);
+			const char *xferjp_host = purple_account_get_string(account, "xferjp_host", NULL);
+
+			g_return_if_fail(serverjp != NULL);
+			g_return_if_fail(xferjp_host != NULL);
+
+			purple_account_set_string(account, "server", serverjp);
+			purple_account_set_string(account, "xfer_host", xferjp_host);
+
+			purple_account_set_protocol_id(account, "prpl-yahoojp");
+		}
+
+		/* these should always be nuked */
+		purple_account_remove_setting(account, "yahoojp");
+		purple_account_remove_setting(account, "serverjp");
+		purple_account_remove_setting(account, "xferjp_host");
+
+	}
+}
+
+static void
+migrate_icq_server(PurpleAccount *account)
+{
+	/* Migrate the login server setting for ICQ accounts.  See
+	 * 'mtn log --last 1 --no-graph --from b6d7712e90b68610df3bd2d8cbaf46d94c8b3794'
+	 * for details on the change. */
+
+	if(purple_strequal(purple_account_get_protocol_id(account), "prpl-icq")) {
+		const char *tmp = purple_account_get_string(account, "server", NULL);
+
+		/* Non-secure server */
+		if(purple_strequal(tmp,	"login.messaging.aol.com") ||
+				purple_strequal(tmp, "login.oscar.aol.com"))
+			purple_account_set_string(account, "server", "login.icq.com");
+
+		/* Secure server */
+		if(purple_strequal(tmp, "slogin.oscar.aol.com"))
+			purple_account_set_string(account, "server", "slogin.icq.com");
+	}
+}
+
+static void
+migrate_xmpp_encryption(PurpleAccount *account)
+{
+	/* When this is removed, nuke the "old_ssl" and "require_tls" settings */
+	if (g_str_equal(purple_account_get_protocol_id(account), "prpl-jabber")) {
+		const char *sec = purple_account_get_string(account, "connection_security", "");
+
+		if (g_str_equal("", sec)) {
+			const char *val = "require_tls";
+			if (purple_account_get_bool(account, "old_ssl", FALSE))
+				val = "old_ssl";
+			else if (!purple_account_get_bool(account, "require_tls", TRUE))
+				val = "opportunistic_tls";
+
+			purple_account_set_string(account, "connection_security", val);
+		}
+	}
+}
+
+static void
+parse_settings(xmlnode *node, PurpleAccount *account)
+{
+	const char *ui;
+	xmlnode *child;
+
+	/* Get the UI string, if these are UI settings */
+	ui = xmlnode_get_attrib(node, "ui");
+
+	/* Read settings, one by one */
+	for (child = xmlnode_get_child(node, "setting"); child != NULL;
+			child = xmlnode_get_next_twin(child))
+	{
+		const char *name, *str_type;
+		PurplePrefType type;
+		char *data;
+
+		name = xmlnode_get_attrib(child, "name");
+		if (name == NULL)
+			/* Ignore this setting */
+			continue;
+
+		str_type = xmlnode_get_attrib(child, "type");
+		if (str_type == NULL)
+			/* Ignore this setting */
+			continue;
+
+		if (purple_strequal(str_type, "string"))
+			type = PURPLE_PREF_STRING;
+		else if (purple_strequal(str_type, "int"))
+			type = PURPLE_PREF_INT;
+		else if (purple_strequal(str_type, "bool"))
+			type = PURPLE_PREF_BOOLEAN;
+		else
+			/* Ignore this setting */
+			continue;
+
+		data = xmlnode_get_data(child);
+		if (data == NULL)
+			/* Ignore this setting */
+			continue;
+
+		if (ui == NULL)
+		{
+			if (type == PURPLE_PREF_STRING)
+				purple_account_set_string(account, name, data);
+			else if (type == PURPLE_PREF_INT)
+				purple_account_set_int(account, name, atoi(data));
+			else if (type == PURPLE_PREF_BOOLEAN)
+				purple_account_set_bool(account, name,
+									  (*data == '0' ? FALSE : TRUE));
+		} else {
+			if (type == PURPLE_PREF_STRING)
+				purple_account_set_ui_string(account, ui, name, data);
+			else if (type == PURPLE_PREF_INT)
+				purple_account_set_ui_int(account, ui, name, atoi(data));
+			else if (type == PURPLE_PREF_BOOLEAN)
+				purple_account_set_ui_bool(account, ui, name,
+										 (*data == '0' ? FALSE : TRUE));
+		}
+
+		g_free(data);
+	}
+
+	/* we do this here because we need access to account settings to determine
+	 * if we can/should migrate an old Yahoo! JAPAN account */
+	migrate_yahoo_japan(account);
+	/* we do this here because we need access to account settings to determine
+	 * if we can/should migrate an ICQ account's server setting */
+	migrate_icq_server(account);
+	/* we do this here because we need to do it before the user views the
+	 * Edit Account dialog. */
+	migrate_xmpp_encryption(account);
+}
+
+static GList *
+parse_status_attrs(xmlnode *node, PurpleStatus *status)
+{
+	GList *list = NULL;
+	xmlnode *child;
+	PurpleValue *attr_value;
+
+	for (child = xmlnode_get_child(node, "attribute"); child != NULL;
+			child = xmlnode_get_next_twin(child))
+	{
+		const char *id = xmlnode_get_attrib(child, "id");
+		const char *value = xmlnode_get_attrib(child, "value");
+
+		if (!id || !*id || !value || !*value)
+			continue;
+
+		attr_value = purple_status_get_attr_value(status, id);
+		if (!attr_value)
+			continue;
+
+		list = g_list_append(list, (char *)id);
+
+		switch (purple_value_get_type(attr_value))
+		{
+			case PURPLE_TYPE_STRING:
+				list = g_list_append(list, (char *)value);
+				break;
+			case PURPLE_TYPE_INT:
+			case PURPLE_TYPE_BOOLEAN:
+			{
+				int v;
+				if (sscanf(value, "%d", &v) == 1)
+					list = g_list_append(list, GINT_TO_POINTER(v));
+				else
+					list = g_list_remove(list, id);
+				break;
+			}
+			default:
+				break;
+		}
+	}
+
+	return list;
+}
+
+static void
+parse_status(xmlnode *node, PurpleAccount *account)
+{
+	gboolean active = FALSE;
+	const char *data;
+	const char *type;
+	xmlnode *child;
+	GList *attrs = NULL;
+
+	/* Get the active/inactive state */
+	data = xmlnode_get_attrib(node, "active");
+	if (data == NULL)
+		return;
+	if (g_ascii_strcasecmp(data, "true") == 0)
+		active = TRUE;
+	else if (g_ascii_strcasecmp(data, "false") == 0)
+		active = FALSE;
+	else
+		return;
+
+	/* Get the type of the status */
+	type = xmlnode_get_attrib(node, "type");
+	if (type == NULL)
+		return;
+
+	/* Read attributes into a GList */
+	child = xmlnode_get_child(node, "attributes");
+	if (child != NULL)
+	{
+		attrs = parse_status_attrs(child,
+						purple_account_get_status(account, type));
+	}
+
+	purple_account_set_status_list(account, type, active, attrs);
+
+	g_list_free(attrs);
+}
+
+static void
+parse_statuses(xmlnode *node, PurpleAccount *account)
+{
+	xmlnode *child;
+
+	for (child = xmlnode_get_child(node, "status"); child != NULL;
+			child = xmlnode_get_next_twin(child))
+	{
+		parse_status(child, account);
+	}
+}
+
+static void
+parse_proxy_info(xmlnode *node, PurpleAccount *account)
+{
+	PurpleProxyInfo *proxy_info;
+	xmlnode *child;
+	char *data;
+
+	proxy_info = purple_proxy_info_new();
+
+	/* Use the global proxy settings, by default */
+	purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_GLOBAL);
+
+	/* Read proxy type */
+	child = xmlnode_get_child(node, "type");
+	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+	{
+		if (purple_strequal(data, "global"))
+			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_GLOBAL);
+		else if (purple_strequal(data, "none"))
+			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_NONE);
+		else if (purple_strequal(data, "http"))
+			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_HTTP);
+		else if (purple_strequal(data, "socks4"))
+			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS4);
+		else if (purple_strequal(data, "socks5"))
+			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS5);
+		else if (purple_strequal(data, "tor"))
+			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_TOR);
+		else if (purple_strequal(data, "envvar"))
+			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_ENVVAR);
+		else
+		{
+			purple_debug_error("account", "Invalid proxy type found when "
+							 "loading account information for %s\n",
+							 purple_account_get_username(account));
+		}
+		g_free(data);
+	}
+
+	/* Read proxy host */
+	child = xmlnode_get_child(node, "host");
+	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+	{
+		purple_proxy_info_set_host(proxy_info, data);
+		g_free(data);
+	}
+
+	/* Read proxy port */
+	child = xmlnode_get_child(node, "port");
+	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+	{
+		purple_proxy_info_set_port(proxy_info, atoi(data));
+		g_free(data);
+	}
+
+	/* Read proxy username */
+	child = xmlnode_get_child(node, "username");
+	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+	{
+		purple_proxy_info_set_username(proxy_info, data);
+		g_free(data);
+	}
+
+	/* Read proxy password */
+	child = xmlnode_get_child(node, "password");
+	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+	{
+		purple_proxy_info_set_password(proxy_info, data);
+		g_free(data);
+	}
+
+	/* If there are no values set then proxy_info NULL */
+	if ((purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_USE_GLOBAL) &&
+		(purple_proxy_info_get_host(proxy_info) == NULL) &&
+		(purple_proxy_info_get_port(proxy_info) == 0) &&
+		(purple_proxy_info_get_username(proxy_info) == NULL) &&
+		(purple_proxy_info_get_password(proxy_info) == NULL))
+	{
+		purple_proxy_info_destroy(proxy_info);
+		return;
+	}
+
+	purple_account_set_proxy_info(account, proxy_info);
+}
+
+static void
+parse_current_error(xmlnode *node, PurpleAccount *account)
+{
+	guint type;
+	char *type_str = NULL, *description = NULL;
+	xmlnode *child;
+	PurpleConnectionErrorInfo *current_error = NULL;
+
+	child = xmlnode_get_child(node, "type");
+	if (child == NULL || (type_str = xmlnode_get_data(child)) == NULL)
+		return;
+	type = atoi(type_str);
+	g_free(type_str);
+
+	if (type > PURPLE_CONNECTION_ERROR_OTHER_ERROR)
+	{
+		purple_debug_error("account",
+			"Invalid PurpleConnectionError value %d found when "
+			"loading account information for %s\n",
+			type, purple_account_get_username(account));
+		type = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+	}
+
+	child = xmlnode_get_child(node, "description");
+	if (child)
+		description = xmlnode_get_data(child);
+	if (description == NULL)
+		description = g_strdup("");
+
+	current_error = g_new0(PurpleConnectionErrorInfo, 1);
+	PURPLE_DBUS_REGISTER_POINTER(current_error, PurpleConnectionErrorInfo);
+	current_error->type = type;
+	current_error->description = description;
+
+	purple_account_set_current_error(account, current_error);
+}
+
+static PurpleAccount *
+parse_account(xmlnode *node)
+{
+	PurpleAccount *ret;
+	xmlnode *child;
+	char *protocol_id = NULL;
+	char *name = NULL;
+	char *data;
+
+	child = xmlnode_get_child(node, "protocol");
+	if (child != NULL)
+		protocol_id = xmlnode_get_data(child);
+
+	child = xmlnode_get_child(node, "name");
+	if (child != NULL)
+		name = xmlnode_get_data(child);
+	if (name == NULL)
+	{
+		/* Do we really need to do this? */
+		child = xmlnode_get_child(node, "username");
+		if (child != NULL)
+			name = xmlnode_get_data(child);
+	}
+
+	if ((protocol_id == NULL) || (name == NULL))
+	{
+		g_free(protocol_id);
+		g_free(name);
+		return NULL;
+	}
+
+	ret = purple_account_new(name, protocol_id);
+	g_free(name);
+	g_free(protocol_id);
+
+	/* Read the alias */
+	child = xmlnode_get_child(node, "alias");
+	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+	{
+		if (*data != '\0')
+			purple_account_set_private_alias(ret, data);
+		g_free(data);
+	}
+
+	/* Read the statuses */
+	child = xmlnode_get_child(node, "statuses");
+	if (child != NULL)
+	{
+		parse_statuses(child, ret);
+	}
+
+	/* Read the userinfo */
+	child = xmlnode_get_child(node, "userinfo");
+	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+	{
+		purple_account_set_user_info(ret, data);
+		g_free(data);
+	}
+
+	/* Read an old buddyicon */
+	child = xmlnode_get_child(node, "buddyicon");
+	if ((child != NULL) && ((data = xmlnode_get_data(child)) != NULL))
+	{
+		const char *dirname = purple_buddy_icons_get_cache_dir();
+		char *filename = g_build_filename(dirname, data, NULL);
+		gchar *contents;
+		gsize len;
+
+		if (g_file_get_contents(filename, &contents, &len, NULL))
+		{
+			purple_buddy_icons_set_account_icon(ret, (guchar *)contents, len);
+		}
+
+		g_free(filename);
+		g_free(data);
+	}
+
+	/* Read settings (both core and UI) */
+	for (child = xmlnode_get_child(node, "settings"); child != NULL;
+			child = xmlnode_get_next_twin(child))
+	{
+		parse_settings(child, ret);
+	}
+
+	/* Read proxy */
+	child = xmlnode_get_child(node, "proxy");
+	if (child != NULL)
+	{
+		parse_proxy_info(child, ret);
+	}
+
+	/* Read current error */
+	child = xmlnode_get_child(node, "current_error");
+	if (child != NULL)
+	{
+		parse_current_error(child, ret);
+	}
+
+	/* Read the password */
+	child = xmlnode_get_child(node, "password");
+	if (child != NULL)
+	{
+		const char *keyring_id = xmlnode_get_attrib(child, "keyring_id");
+		const char *mode = xmlnode_get_attrib(child, "mode");
+		gboolean result;
+
+		data = xmlnode_get_data(child);
+		result = purple_keyring_import_password(ret, keyring_id, mode, data, NULL);
+
+		if (result == TRUE || purple_keyring_get_inuse() == NULL) {
+			purple_account_set_remember_password(ret, TRUE);
+		} else {
+			purple_debug_error("account", "Failed to import password.\n");
+		} 
+		purple_str_wipe(data);
+	}
+
+	return ret;
+}
+
+static void
+load_accounts(void)
+{
+	xmlnode *node, *child;
+
+	accounts_loaded = TRUE;
+
+	node = purple_util_read_xml_from_file("accounts.xml", _("accounts"));
+
+	if (node == NULL)
+		return;
+
+	for (child = xmlnode_get_child(node, "account"); child != NULL;
+			child = xmlnode_get_next_twin(child))
+	{
+		PurpleAccount *new_acct;
+		new_acct = parse_account(child);
+		purple_accounts_add(new_acct);
+	}
+
+	xmlnode_free(node);
+
+	_purple_buddy_icons_account_loaded_cb();
+}
+
+void
+purple_accounts_add(PurpleAccount *account)
+{
+	g_return_if_fail(account != NULL);
+
+	if (g_list_find(accounts, account) != NULL)
+		return;
+
+	accounts = g_list_append(accounts, account);
+
+	purple_accounts_schedule_save();
+
+	purple_signal_emit(purple_accounts_get_handle(), "account-added", account);
+}
+
+void
+purple_accounts_remove(PurpleAccount *account)
+{
+	g_return_if_fail(account != NULL);
+
+	accounts = g_list_remove(accounts, account);
+
+	purple_accounts_schedule_save();
+
+	/* Clearing the error ensures that account-error-changed is emitted,
+	 * which is the end of the guarantee that the the error's pointer is
+	 * valid.
+	 */
+	purple_account_clear_current_error(account);
+	purple_signal_emit(purple_accounts_get_handle(), "account-removed", account);
+}
+
+static void
+purple_accounts_delete_set(PurpleAccount *account, GError *error, gpointer data)
+{
+	g_object_unref(G_OBJECT(account));
+}
+
+void
+purple_accounts_delete(PurpleAccount *account)
+{
+	PurpleBlistNode *gnode, *cnode, *bnode;
+	GList *iter;
+
+	g_return_if_fail(account != NULL);
+
+	/*
+	 * Disable the account before blowing it out of the water.
+	 * Conceptually it probably makes more sense to disable the
+	 * account for all UIs rather than the just the current UI,
+	 * but it doesn't really matter.
+	 */
+	purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
+
+	purple_notify_close_with_handle(account);
+	purple_request_close_with_handle(account);
+
+	purple_accounts_remove(account);
+
+	/* Remove this account's buddies */
+	for (gnode = purple_blist_get_root();
+	     gnode != NULL;
+		 gnode = purple_blist_node_get_sibling_next(gnode))
+	{
+		if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
+			continue;
+
+		cnode = purple_blist_node_get_first_child(gnode);
+		while (cnode) {
+			PurpleBlistNode *cnode_next = purple_blist_node_get_sibling_next(cnode);
+
+			if(PURPLE_BLIST_NODE_IS_CONTACT(cnode)) {
+				bnode = purple_blist_node_get_first_child(cnode);
+				while (bnode) {
+					PurpleBlistNode *bnode_next = purple_blist_node_get_sibling_next(bnode);
+
+					if (PURPLE_BLIST_NODE_IS_BUDDY(bnode)) {
+						PurpleBuddy *b = (PurpleBuddy *)bnode;
+
+						if (purple_buddy_get_account(b) == account)
+							purple_blist_remove_buddy(b);
+					}
+					bnode = bnode_next;
+				}
+			} else if (PURPLE_BLIST_NODE_IS_CHAT(cnode)) {
+				PurpleChat *c = (PurpleChat *)cnode;
+
+				if (purple_chat_get_account(c) == account)
+					purple_blist_remove_chat(c);
+			}
+			cnode = cnode_next;
+		}
+	}
+
+	/* Remove any open conversation for this account */
+	for (iter = purple_get_conversations(); iter; ) {
+		PurpleConversation *conv = iter->data;
+		iter = iter->next;
+		if (purple_conversation_get_account(conv) == account)
+			purple_conversation_destroy(conv);
+	}
+
+	/* Remove this account's pounces */
+	purple_pounce_destroy_all_by_account(account);
+
+	/* This will cause the deletion of an old buddy icon. */
+	purple_buddy_icons_set_account_icon(account, NULL, 0);
+
+	/* This is async because we do not want the
+	 * account being overwritten before we are done.
+	 */
+	purple_keyring_set_password(account, NULL,
+		purple_accounts_delete_set, NULL);
+}
+
+void
+purple_accounts_reorder(PurpleAccount *account, gint new_index)
+{
+	gint index;
+	GList *l;
+
+	g_return_if_fail(account != NULL);
+	g_return_if_fail(new_index <= g_list_length(accounts));
+
+	index = g_list_index(accounts, account);
+
+	if (index == -1) {
+		purple_debug_error("account",
+				   "Unregistered account (%s) discovered during reorder!\n",
+				   purple_account_get_username(account));
+		return;
+	}
+
+	l = g_list_nth(accounts, index);
+
+	if (new_index > index)
+		new_index--;
+
+	/* Remove the old one. */
+	accounts = g_list_delete_link(accounts, l);
+
+	/* Insert it where it should go. */
+	accounts = g_list_insert(accounts, account, new_index);
+
+	purple_accounts_schedule_save();
+}
+
+GList *
+purple_accounts_get_all(void)
+{
+	return accounts;
+}
+
+GList *
+purple_accounts_get_all_active(void)
+{
+	GList *list = NULL;
+	GList *all = purple_accounts_get_all();
+
+	while (all != NULL) {
+		PurpleAccount *account = all->data;
+
+		if (purple_account_get_enabled(account, purple_core_get_ui()))
+			list = g_list_append(list, account);
+
+		all = all->next;
+	}
+
+	return list;
+}
+
+PurpleAccount *
+purple_accounts_find(const char *name, const char *protocol_id)
+{
+	PurpleAccount *account = NULL;
+	GList *l;
+	char *who;
+
+	g_return_val_if_fail(name != NULL, NULL);
+	g_return_val_if_fail(protocol_id != NULL, NULL);
+
+	for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
+		account = (PurpleAccount *)l->data;
+
+		if (!purple_strequal(purple_account_get_protocol_id(account), protocol_id))
+			continue;
+
+		who = g_strdup(purple_normalize(account, name));
+		if (purple_strequal(purple_normalize(account, purple_account_get_username(account)), who)) {
+			g_free(who);
+			return account;
+		}
+		g_free(who);
+	}
+
+	return NULL;
+}
+
+void
+purple_accounts_restore_current_statuses()
+{
+	GList *l;
+	PurpleAccount *account;
+
+	/* If we're not connected to the Internet right now, we bail on this */
+	if (!purple_network_is_available())
+	{
+		purple_debug_warning("account", "Network not connected; skipping reconnect\n");
+		return;
+	}
+
+	for (l = purple_accounts_get_all(); l != NULL; l = l->next)
+	{
+		account = (PurpleAccount *)l->data;
+
+		if (purple_account_get_enabled(account, purple_core_get_ui()) &&
+			(purple_presence_is_online(purple_account_get_presence(account))))
+		{
+			purple_account_connect(account);
+		}
+	}
+}
+
+void
+purple_accounts_set_ui_ops(PurpleAccountUiOps *ops)
+{
+	account_ui_ops = ops;
+}
+
+PurpleAccountUiOps *
+purple_accounts_get_ui_ops(void)
+{
+	return account_ui_ops;
+}
+
+void *
+purple_accounts_get_handle(void)
+{
+	static int handle;
+
+	return &handle;
+}
+
+static void
+signed_on_cb(PurpleConnection *gc,
+             gpointer unused)
+{
+	PurpleAccount *account = purple_connection_get_account(gc);
+	purple_account_clear_current_error(account);
+
+	purple_signal_emit(purple_accounts_get_handle(), "account-signed-on",
+	                   account);
+}
+
+static void
+signed_off_cb(PurpleConnection *gc,
+              gpointer unused)
+{
+	PurpleAccount *account = purple_connection_get_account(gc);
+
+	purple_signal_emit(purple_accounts_get_handle(), "account-signed-off",
+	                   account);
+}
+
+static void
+connection_error_cb(PurpleConnection *gc,
+                    PurpleConnectionError type,
+                    const gchar *description,
+                    gpointer unused)
+{
+	PurpleAccount *account;
+	PurpleConnectionErrorInfo *err;
+
+	account = purple_connection_get_account(gc);
+
+	g_return_if_fail(account != NULL);
+
+	err = g_new0(PurpleConnectionErrorInfo, 1);
+	PURPLE_DBUS_REGISTER_POINTER(err, PurpleConnectionErrorInfo);
+
+	err->type = type;
+	err->description = g_strdup(description);
+
+	purple_account_set_current_error(account, err);
+
+	purple_signal_emit(purple_accounts_get_handle(), "account-connection-error",
+	                   account, type, description);
+}
+
+static void
+password_migration_cb(PurpleAccount *account)
+{
+	/* account may be NULL (means: all) */
+
+	purple_accounts_schedule_save();
+}
+
+void
+purple_accounts_init(void)
+{
+	void *handle = purple_accounts_get_handle();
+	void *conn_handle = purple_connections_get_handle();
+
+	purple_signal_register(handle, "account-connecting",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-disabled",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-enabled",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-setting-info",
+						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "account-set-info",
+						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "account-created",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-destroying",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-added",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-removed",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-status-changed",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_STATUS),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_STATUS));
+
+	purple_signal_register(handle, "account-actions-changed",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-alias-changed",
+						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+							 			PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "account-authorization-requested",
+						purple_marshal_INT__POINTER_POINTER_POINTER,
+						purple_value_new(PURPLE_TYPE_INT), 4,
+						purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						purple_value_new(PURPLE_TYPE_STRING),
+						purple_value_new(PURPLE_TYPE_STRING),
+						purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "account-authorization-denied",
+						purple_marshal_VOID__POINTER_POINTER, NULL, 3,
+						purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						purple_value_new(PURPLE_TYPE_STRING),
+						purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "account-authorization-granted",
+						purple_marshal_VOID__POINTER_POINTER, NULL, 3,
+						purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						purple_value_new(PURPLE_TYPE_STRING),
+						purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "account-error-changed",
+	                       purple_marshal_VOID__POINTER_POINTER_POINTER,
+	                       NULL, 3,
+	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
+	                                        PURPLE_SUBTYPE_ACCOUNT),
+	                       purple_value_new(PURPLE_TYPE_POINTER),
+	                       purple_value_new(PURPLE_TYPE_POINTER));
+
+	purple_signal_register(handle, "account-signed-on",
+	                       purple_marshal_VOID__POINTER, NULL, 1,
+	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
+	                                        PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-signed-off",
+	                       purple_marshal_VOID__POINTER, NULL, 1,
+	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
+	                                        PURPLE_SUBTYPE_ACCOUNT));
+
+	purple_signal_register(handle, "account-connection-error",
+	                       purple_marshal_VOID__POINTER_INT_POINTER, NULL, 3,
+	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
+	                                        PURPLE_SUBTYPE_ACCOUNT),
+	                       purple_value_new(PURPLE_TYPE_ENUM),
+	                       purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_connect(conn_handle, "signed-on", handle,
+	                      PURPLE_CALLBACK(signed_on_cb), NULL);
+	purple_signal_connect(conn_handle, "signed-off", handle,
+	                      PURPLE_CALLBACK(signed_off_cb), NULL);
+	purple_signal_connect(conn_handle, "connection-error", handle,
+	                      PURPLE_CALLBACK(connection_error_cb), NULL);
+	purple_signal_connect(purple_keyring_get_handle(), "password-migration", handle,
+	                      PURPLE_CALLBACK(password_migration_cb), NULL);
+
+	load_accounts();
+
+}
+
+void
+purple_accounts_uninit(void)
+{
+	gpointer handle = purple_accounts_get_handle();
+	if (save_timer != 0)
+	{
+		purple_timeout_remove(save_timer);
+		save_timer = 0;
+		sync_accounts();
+	}
+
+	for (; accounts; accounts = g_list_delete_link(accounts, accounts))
+		g_object_unref(G_OBJECT(accounts->data));
+
+	purple_signals_disconnect_by_handle(handle);
+	purple_signals_unregister_by_instance(handle);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/accounts.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,224 @@
+/**
+ * @file accounts.h Accounts API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef _PURPLE_ACCOUNTS_H_
+#define _PURPLE_ACCOUNTS_H_
+
+#include "account.h"
+#include "status.h"
+
+/** @copydoc _PurpleAccountUiOps */
+typedef struct _PurpleAccountUiOps  PurpleAccountUiOps;
+
+/**  Account UI operations, used to notify the user of status changes and when
+ *   buddies add this account to their buddy lists.
+ */
+struct _PurpleAccountUiOps
+{
+	/** A buddy who is already on this account's buddy list added this account
+	 *  to their buddy list.
+	 */
+	void (*notify_added)(PurpleAccount *account,
+	                     const char *remote_user,
+	                     const char *id,
+	                     const char *alias,
+	                     const char *message);
+
+	/** This account's status changed. */
+	void (*status_changed)(PurpleAccount *account,
+	                       PurpleStatus *status);
+
+	/** Someone we don't have on our list added us; prompt to add them. */
+	void (*request_add)(PurpleAccount *account,
+	                    const char *remote_user,
+	                    const char *id,
+	                    const char *alias,
+	                    const char *message);
+
+	/** Prompt for authorization when someone adds this account to their buddy
+	 * list.  To authorize them to see this account's presence, call \a
+	 * authorize_cb (\a message, \a user_data); otherwise call
+	 * \a deny_cb (\a message, \a user_data);
+	 * @return a UI-specific handle, as passed to #close_account_request.
+	 */
+	void *(*request_authorize)(PurpleAccount *account,
+	                           const char *remote_user,
+	                           const char *id,
+	                           const char *alias,
+	                           const char *message,
+	                           gboolean on_list,
+	                           PurpleAccountRequestAuthorizationCb authorize_cb,
+	                           PurpleAccountRequestAuthorizationCb deny_cb,
+	                           void *user_data);
+
+	/** Close a pending request for authorization.  \a ui_handle is a handle
+	 *  as returned by #request_authorize.
+	 */
+	void (*close_account_request)(void *ui_handle);
+
+	void (*permit_added)(PurpleAccount *account, const char *name);
+	void (*permit_removed)(PurpleAccount *account, const char *name);
+	void (*deny_added)(PurpleAccount *account, const char *name);
+	void (*deny_removed)(PurpleAccount *account, const char *name);
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+/**************************************************************************/
+/** @name Accounts API                                                    */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Adds an account to the list of accounts.
+ *
+ * @param account The account.
+ */
+void purple_accounts_add(PurpleAccount *account);
+
+/**
+ * Removes an account from the list of accounts.
+ *
+ * @param account The account.
+ */
+void purple_accounts_remove(PurpleAccount *account);
+
+/**
+ * Deletes an account.
+ *
+ * This will remove any buddies from the buddy list that belong to this
+ * account, buddy pounces that belong to this account, and will also
+ * destroy @a account.
+ *
+ * @param account The account.
+ */
+void purple_accounts_delete(PurpleAccount *account);
+
+/**
+ * Reorders an account.
+ *
+ * @param account   The account to reorder.
+ * @param new_index The new index for the account.
+ */
+void purple_accounts_reorder(PurpleAccount *account, gint new_index);
+
+/**
+ * Returns a list of all accounts.
+ *
+ * @constreturn A list of all accounts.
+ */
+GList *purple_accounts_get_all(void);
+
+/**
+ * Returns a list of all enabled accounts
+ *
+ * @return A list of all enabled accounts. The list is owned
+ *         by the caller, and must be g_list_free()d to avoid
+ *         leaking the nodes.
+ */
+GList *purple_accounts_get_all_active(void);
+
+/**
+ * Finds an account with the specified name and protocol id.
+ *
+ * @param name     The account username.
+ * @param protocol The account protocol ID.
+ *
+ * @return The account, if found, or @c FALSE otherwise.
+ */
+PurpleAccount *purple_accounts_find(const char *name, const char *protocol);
+
+/**
+ * This is called by the core after all subsystems and what
+ * not have been initialized.  It sets all enabled accounts
+ * to their startup status by signing them on, setting them
+ * away, etc.
+ *
+ * You probably shouldn't call this unless you really know
+ * what you're doing.
+ */
+void purple_accounts_restore_current_statuses(void);
+
+/*@}*/
+
+
+/**************************************************************************/
+/** @name UI Registration Functions                                       */
+/**************************************************************************/
+/*@{*/
+/**
+ * Sets the UI operations structure to be used for accounts.
+ *
+ * @param ops The UI operations structure.
+ */
+void purple_accounts_set_ui_ops(PurpleAccountUiOps *ops);
+
+/**
+ * Returns the UI operations structure used for accounts.
+ *
+ * @return The UI operations structure in use.
+ */
+PurpleAccountUiOps *purple_accounts_get_ui_ops(void);
+
+/*@}*/
+
+
+/**************************************************************************/
+/** @name Accounts Subsystem                                              */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Returns the accounts subsystem handle.
+ *
+ * @return The accounts subsystem handle.
+ */
+void *purple_accounts_get_handle(void);
+
+/**
+ * Initializes the accounts subsystem.
+ */
+void purple_accounts_init(void);
+
+/**
+ * Uninitializes the accounts subsystem.
+ */
+void purple_accounts_uninit(void);
+
+/**
+ * Schedules saving of accounts
+ */
+void purple_accounts_schedule_save(void);
+
+/*@}*/
+
+G_END_DECLS
+
+#endif /* _PURPLE_ACCOUNTS_H_ */
--- a/libpurple/blist.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/blist.c	Sun Jun 23 13:35:53 2013 +0530
@@ -30,7 +30,6 @@
 #include "notify.h"
 #include "pounce.h"
 #include "prefs.h"
-#include "privacy.h"
 #include "prpl.h"
 #include "server.h"
 #include "signals.h"
@@ -317,13 +316,13 @@
 	g_snprintf(buf, sizeof(buf), "%d", purple_account_get_privacy_type(account));
 	xmlnode_set_attrib(node, "mode", buf);
 
-	for (cur = account->permit; cur; cur = cur->next)
+	for (cur = purple_account_privacy_get_permitted(account); cur; cur = cur->next)
 	{
 		child = xmlnode_new_child(node, "permit");
 		xmlnode_insert_data(child, cur->data, -1);
 	}
 
-	for (cur = account->deny; cur; cur = cur->next)
+	for (cur = purple_account_privacy_get_denied(account); cur; cur = cur->next)
 	{
 		child = xmlnode_new_child(node, "block");
 		xmlnode_insert_data(child, cur->data, -1);
@@ -640,7 +639,7 @@
 				continue;
 
 			imode = atoi(mode);
-			purple_account_set_privacy_type(account, (imode != 0 ? imode : PURPLE_PRIVACY_ALLOW_ALL));
+			purple_account_set_privacy_type(account, (imode != 0 ? imode : PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL));
 
 			for (x = anode->child; x; x = x->next) {
 				char *name;
@@ -649,11 +648,11 @@
 
 				if (purple_strequal(x->name, "permit")) {
 					name = xmlnode_get_data(x);
-					purple_privacy_permit_add(account, name, TRUE);
+					purple_account_privacy_permit_add(account, name, TRUE);
 					g_free(name);
 				} else if (purple_strequal(x->name, "block")) {
 					name = xmlnode_get_data(x);
-					purple_privacy_deny_add(account, name, TRUE);
+					purple_account_privacy_deny_add(account, name, TRUE);
 					g_free(name);
 				}
 			}
--- a/libpurple/cipher.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/cipher.c	Sun Jun 23 13:35:53 2013 +0530
@@ -1,24 +1,9 @@
-/*
- * purple
+/* purple
  *
  * Purple is the legal property of its developers, whose names are too numerous
  * to list here.  Please refer to the COPYRIGHT file distributed with this
  * source distribution.
  *
- * Original des taken from gpg
- *
- * des.c - DES and Triple-DES encryption/decryption Algorithm
- *	Copyright (C) 1998 Free Software Foundation, Inc.
- *
- *	Please see below for more legal information!
- *
- *	 According to the definition of DES in FIPS PUB 46-2 from December 1993.
- *	 For a description of triple encryption, see:
- *	   Bruce Schneier: Applied Cryptography. Second Edition.
- *	   John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
- *
- *	 This file is part of GnuPG.
- *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -35,435 +20,230 @@
  */
 #include "internal.h"
 #include "cipher.h"
-#include "ciphers/ciphers.h"
-#include "dbus-maybe.h"
 #include "debug.h"
-#include "signals.h"
-#include "value.h"
-
-/*******************************************************************************
- * Structs
- ******************************************************************************/
-struct _PurpleCipher {
-	gchar *name;          /**< Internal name - used for searching */
-	PurpleCipherOps *ops; /**< Operations supported by this cipher */
-	guint ref;            /**< Reference count */
-};
-
-struct _PurpleCipherContext {
-	PurpleCipher *cipher; /**< Cipher this context is under */
-	gpointer data;        /**< Internal cipher state data */
-};
 
 /******************************************************************************
- * Globals
+ * Object Stuff
  *****************************************************************************/
-static GList *ciphers = NULL;
+static void
+purple_cipher_class_init(PurpleCipherClass *klass) {
+	klass->reset = NULL;
+	klass->reset_state = NULL;
+	klass->set_iv = NULL;
+	klass->append = NULL;
+	klass->digest = NULL;
+	klass->get_digest_size = NULL;
+	klass->encrypt = NULL;
+	klass->decrypt = NULL;
+	klass->set_salt = NULL;
+	klass->set_key = NULL;
+	klass->get_key_size = NULL;
+	klass->set_batch_mode = NULL;
+	klass->get_batch_mode = NULL;
+	klass->get_block_size = NULL;
+	klass->get_name = NULL;
+}
 
 /******************************************************************************
  * PurpleCipher API
  *****************************************************************************/
 const gchar *
 purple_cipher_get_name(PurpleCipher *cipher) {
+	PurpleCipherClass *klass = NULL;
+
 	g_return_val_if_fail(cipher, NULL);
+	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), NULL);
 
-	return cipher->name;
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
+	g_return_val_if_fail(klass->get_name, NULL);
+
+	return klass->get_name(cipher);
 }
 
-guint
-purple_cipher_get_capabilities(PurpleCipher *cipher) {
-	PurpleCipherOps *ops = NULL;
-	guint caps = 0;
-
-	g_return_val_if_fail(cipher, 0);
-
-	ops = cipher->ops;
-	g_return_val_if_fail(ops, 0);
+GType
+purple_cipher_get_type(void) {
+	static GType type = 0;
 
-	if(ops->set_option)
-		caps |= PURPLE_CIPHER_CAPS_SET_OPT;
-	if(ops->get_option)
-		caps |= PURPLE_CIPHER_CAPS_GET_OPT;
-	if(ops->init)
-		caps |= PURPLE_CIPHER_CAPS_INIT;
-	if(ops->reset)
-		caps |= PURPLE_CIPHER_CAPS_RESET;
-	if(ops->reset_state)
-		caps |= PURPLE_CIPHER_CAPS_RESET_STATE;
-	if(ops->uninit)
-		caps |= PURPLE_CIPHER_CAPS_UNINIT;
-	if(ops->set_iv)
-		caps |= PURPLE_CIPHER_CAPS_SET_IV;
-	if(ops->append)
-		caps |= PURPLE_CIPHER_CAPS_APPEND;
-	if(ops->digest)
-		caps |= PURPLE_CIPHER_CAPS_DIGEST;
-	if(ops->get_digest_size)
-		caps |= PURPLE_CIPHER_CAPS_GET_DIGEST_SIZE;
-	if(ops->encrypt)
-		caps |= PURPLE_CIPHER_CAPS_ENCRYPT;
-	if(ops->decrypt)
-		caps |= PURPLE_CIPHER_CAPS_DECRYPT;
-	if(ops->set_salt)
-		caps |= PURPLE_CIPHER_CAPS_SET_SALT;
-	if(ops->get_salt_size)
-		caps |= PURPLE_CIPHER_CAPS_GET_SALT_SIZE;
-	if(ops->set_key)
-		caps |= PURPLE_CIPHER_CAPS_SET_KEY;
-	if (ops->get_key_size)
-		caps |= PURPLE_CIPHER_CAPS_GET_KEY_SIZE;
-	if(ops->set_batch_mode)
-		caps |= PURPLE_CIPHER_CAPS_SET_BATCH_MODE;
-	if(ops->get_batch_mode)
-		caps |= PURPLE_CIPHER_CAPS_GET_BATCH_MODE;
-	if(ops->get_block_size)
-		caps |= PURPLE_CIPHER_CAPS_GET_BLOCK_SIZE;
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleCipherClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_cipher_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleCipher),
+			0,
+			NULL,
+			NULL
+		};
 
-	return caps;
-}
-
-ssize_t
-purple_cipher_digest_region(const gchar *name, const guchar *data,
-	size_t data_len, guchar digest[], size_t out_size)
-{
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
-	ssize_t digest_size;
-	gboolean succ;
-
-	g_return_val_if_fail(name, -1);
-	g_return_val_if_fail(data, -1);
-
-	cipher = purple_ciphers_find_cipher(name);
-
-	g_return_val_if_fail(cipher, -1);
-
-	if(!cipher->ops->append || !cipher->ops->digest || !cipher->ops->get_digest_size) {
-		purple_debug_warning("cipher", "purple_cipher_region failed: "
-						"the %s cipher does not support appending and or "
-						"digesting.", cipher->name);
-		return -1;
+		type = g_type_register_static(G_TYPE_OBJECT,
+									  "PurpleCipher",
+									  &info, G_TYPE_FLAG_ABSTRACT);
 	}
 
-	context = purple_cipher_context_new(cipher, NULL);
-	digest_size = purple_cipher_context_get_digest_size(context);
-	if (out_size < digest_size) {
-		purple_debug_error("cipher", "purple_cipher_region failed: "
-			"provided output buffer too small\n");
-		purple_cipher_context_destroy(context);
-		return -1;
-	}
-	purple_cipher_context_append(context, data, data_len);
-	succ = purple_cipher_context_digest(context, digest, out_size);
-	purple_cipher_context_destroy(context);
-
-	return succ ? digest_size : -1;
-}
-
-/******************************************************************************
- * PurpleCiphers API
- *****************************************************************************/
-PurpleCipher *
-purple_ciphers_find_cipher(const gchar *name) {
-	PurpleCipher *cipher;
-	GList *l;
-
-	g_return_val_if_fail(name, NULL);
-
-	for(l = ciphers; l; l = l->next) {
-		cipher = PURPLE_CIPHER(l->data);
-
-		if(!g_ascii_strcasecmp(cipher->name, name))
-			return cipher;
-	}
-
-	return NULL;
+	return type;
 }
 
-PurpleCipher *
-purple_ciphers_register_cipher(const gchar *name, PurpleCipherOps *ops) {
-	PurpleCipher *cipher = NULL;
-
-	g_return_val_if_fail(name, NULL);
-	g_return_val_if_fail(ops, NULL);
-	g_return_val_if_fail(!purple_ciphers_find_cipher(name), NULL);
+/**
+ * purple_cipher_reset:
+ * @cipher: The cipher to reset
+ *
+ * Resets a cipher to it's default value
+ *
+ * @note If you have set an IV you will have to set it after resetting
+ */
+void
+purple_cipher_reset(PurpleCipher *cipher) {
+	PurpleCipherClass *klass = NULL;
 
-	cipher = g_new0(PurpleCipher, 1);
-	PURPLE_DBUS_REGISTER_POINTER(cipher, PurpleCipher);
+	g_return_if_fail(PURPLE_IS_CIPHER(cipher));
 
-	cipher->name = g_strdup(name);
-	cipher->ops = ops;
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	ciphers = g_list_append(ciphers, cipher);
-
-	purple_signal_emit(purple_ciphers_get_handle(), "cipher-added", cipher);
-
-	return cipher;
+	if(klass && klass->reset)
+		klass->reset(cipher);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"reset method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 }
 
-gboolean
-purple_ciphers_unregister_cipher(PurpleCipher *cipher) {
-	g_return_val_if_fail(cipher, FALSE);
-	g_return_val_if_fail(cipher->ref == 0, FALSE);
-
-	purple_signal_emit(purple_ciphers_get_handle(), "cipher-removed", cipher);
-
-	ciphers = g_list_remove(ciphers, cipher);
-
-	g_free(cipher->name);
-
-	PURPLE_DBUS_UNREGISTER_POINTER(cipher);
-	g_free(cipher);
-
-	return TRUE;
-}
-
-GList *
-purple_ciphers_get_ciphers() {
-	return ciphers;
-}
+/**
+ * Resets a cipher state to it's default value, but doesn't touch stateless
+ * configuration.
+ *
+ * That means, IV and digest context will be wiped out, but keys, ops or salt
+ * will remain untouched.
+ */
+void
+purple_cipher_reset_state(PurpleCipher *cipher) {
+	PurpleCipherClass *klass = NULL;
 
-/******************************************************************************
- * PurpleCipher Subsystem API
- *****************************************************************************/
-gpointer
-purple_ciphers_get_handle() {
-	static gint handle;
+	g_return_if_fail(PURPLE_IS_CIPHER(cipher));
 
-	return &handle;
-}
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-void
-purple_ciphers_init() {
-	gpointer handle;
-
-	handle = purple_ciphers_get_handle();
-
-	purple_signal_register(handle, "cipher-added",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CIPHER));
-	purple_signal_register(handle, "cipher-removed",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CIPHER));
-
-	purple_ciphers_register_all();
+	if(klass && klass->reset_state)
+		klass->reset_state(cipher);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"reset_state method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 }
 
-void
-purple_ciphers_uninit() {
-	PurpleCipher *cipher;
-	GList *l, *ll;
-
-	for(l = ciphers; l; l = ll) {
-		ll = l->next;
-
-		cipher = PURPLE_CIPHER(l->data);
-		purple_ciphers_unregister_cipher(cipher);
-	}
-
-	g_list_free(ciphers);
-
-	purple_signals_unregister_by_instance(purple_ciphers_get_handle());
-}
-
-/******************************************************************************
- * PurpleCipherContext API
- *****************************************************************************/
+/**
+ * purple_cipher_set_iv:
+ * @cipher: The cipher to set the IV to
+ * @iv: The initialization vector to set
+ * @len: The len of the IV
+ *
+ * @note This should only be called right after a cipher is created or reset
+ *
+ * Sets the initialization vector for a cipher
+ */
 void
-purple_cipher_context_set_option(PurpleCipherContext *context, const gchar *name,
-							   gpointer value)
+purple_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len)
 {
-	PurpleCipher *cipher = NULL;
-
-	g_return_if_fail(context);
-	g_return_if_fail(name);
-
-	cipher = context->cipher;
-	g_return_if_fail(cipher);
-
-	if(cipher->ops && cipher->ops->set_option)
-		cipher->ops->set_option(context, name, value);
-	else
-		purple_debug_warning("cipher", "the %s cipher does not support the "
-						"set_option operation\n", cipher->name);
-}
-
-gpointer
-purple_cipher_context_get_option(PurpleCipherContext *context, const gchar *name) {
-	PurpleCipher *cipher = NULL;
+	PurpleCipherClass *klass = NULL;
 
-	g_return_val_if_fail(context, NULL);
-	g_return_val_if_fail(name, NULL);
-
-	cipher = context->cipher;
-	g_return_val_if_fail(cipher, NULL);
+	g_return_if_fail(PURPLE_IS_CIPHER(cipher));
+	g_return_if_fail(iv);
 
-	if(cipher->ops && cipher->ops->get_option)
-		return cipher->ops->get_option(context, name);
-	else {
-		purple_debug_warning("cipher", "the %s cipher does not support the "
-						"get_option operation\n", cipher->name);
-
-		return NULL;
-	}
-}
-
-PurpleCipherContext *
-purple_cipher_context_new(PurpleCipher *cipher, void *extra) {
-	PurpleCipherContext *context = NULL;
-
-	g_return_val_if_fail(cipher, NULL);
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	cipher->ref++;
-
-	context = g_new0(PurpleCipherContext, 1);
-	context->cipher = cipher;
-
-	if(cipher->ops->init)
-		cipher->ops->init(context, extra);
-
-	return context;
-}
-
-PurpleCipherContext *
-purple_cipher_context_new_by_name(const gchar *name, void *extra) {
-	PurpleCipher *cipher;
-
-	g_return_val_if_fail(name, NULL);
-
-	cipher = purple_ciphers_find_cipher(name);
-
-	g_return_val_if_fail(cipher, NULL);
-
-	return purple_cipher_context_new(cipher, extra);
+	if(klass && klass->set_iv)
+		klass->set_iv(cipher, iv, len);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"set_iv method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 }
 
+/**
+ * purple_cipher_append:
+ * @cipher: The cipher to append data to
+ * @data: The data to append
+ * @len: The length of the data
+ *
+ * Appends data to the cipher
+ */
 void
-purple_cipher_context_reset(PurpleCipherContext *context, void *extra) {
-	PurpleCipher *cipher = NULL;
-
-	g_return_if_fail(context);
-
-	cipher = context->cipher;
-	g_return_if_fail(cipher);
-
-	if(cipher->ops && cipher->ops->reset)
-		context->cipher->ops->reset(context, extra);
-}
-
-void
-purple_cipher_context_reset_state(PurpleCipherContext *context, void *extra) {
-	PurpleCipher *cipher = NULL;
-
-	g_return_if_fail(context);
-
-	cipher = context->cipher;
-	g_return_if_fail(cipher);
-	g_return_if_fail(cipher->ops);
+purple_cipher_append(PurpleCipher *cipher, const guchar *data,
+								size_t len)
+{
+	PurpleCipherClass *klass = NULL;
 
-	if (cipher->ops->reset_state) {
-		context->cipher->ops->reset_state(context, extra);
-		return;
-	}
+	g_return_if_fail(PURPLE_IS_CIPHER(cipher));
 
-	purple_debug_warning("cipher", "the %s cipher does not support the "
-		"reset_state operation\n", cipher->name);
-	purple_cipher_context_reset(context, extra);
-}
-
-void
-purple_cipher_context_destroy(PurpleCipherContext *context) {
-	PurpleCipher *cipher = NULL;
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	g_return_if_fail(context);
-
-	cipher = context->cipher;
-	g_return_if_fail(cipher);
-
-	cipher->ref--;
-
-	if(cipher->ops && cipher->ops->uninit)
-		cipher->ops->uninit(context);
-
-	memset(context, 0, sizeof(*context));
-	g_free(context);
-	context = NULL;
+	if(klass && klass->append)
+		klass->append(cipher, data, len);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"append method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 }
 
-void
-purple_cipher_context_set_iv(PurpleCipherContext *context, guchar *iv, size_t len)
+/**
+ * purple_cipher_digest:
+ * @cipher: The cipher to digest
+ * @in_len: The length of the buffer
+ * @digest: The return buffer for the digest
+ * @out_len: The length of the returned value
+ *
+ * Digests a cipher
+ *
+ * Return Value: TRUE if the digest was successful, FALSE otherwise.
+ */
+gboolean
+purple_cipher_digest(PurpleCipher *cipher, guchar digest[], size_t len)
 {
-	PurpleCipher *cipher = NULL;
-
-	g_return_if_fail(context);
-	g_return_if_fail(iv);
+	PurpleCipherClass *klass = NULL;
 
-	cipher = context->cipher;
-	g_return_if_fail(cipher);
+	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), FALSE);
+
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	if(cipher->ops && cipher->ops->set_iv)
-		cipher->ops->set_iv(context, iv, len);
+	if(klass && klass->digest)
+		return klass->digest(cipher, digest, len);
 	else
-		purple_debug_warning("cipher", "the %s cipher does not support the set"
-						"initialization vector operation\n", cipher->name);
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"digest method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
+
+	return FALSE;
 }
 
-void
-purple_cipher_context_append(PurpleCipherContext *context, const guchar *data,
-								size_t len)
-{
-	PurpleCipher *cipher = NULL;
-
-	g_return_if_fail(context);
-
-	cipher = context->cipher;
-	g_return_if_fail(cipher);
-
-	if(cipher->ops && cipher->ops->append)
-		cipher->ops->append(context, data, len);
-	else
-		purple_debug_warning("cipher", "the %s cipher does not support the append "
-						"operation\n", cipher->name);
-}
-
+/**
+ * purple_cipher_digest_to_str:
+ * @cipher: The cipher to get a digest from
+ * @in_len: The length of the buffer
+ * @digest_s: The return buffer for the string digest
+ * @out_len: The length of the returned value
+ *
+ * Converts a guchar digest into a hex string
+ *
+ * Return Value: TRUE if the digest was successful, FALSE otherwise.
+ */
 gboolean
-purple_cipher_context_digest(PurpleCipherContext *context, guchar digest[],
-	size_t len)
-{
-	PurpleCipher *cipher = NULL;
-
-	g_return_val_if_fail(context, FALSE);
-
-	cipher = context->cipher;
-
-	if(cipher->ops && cipher->ops->digest)
-		return cipher->ops->digest(context, digest, len);
-	else {
-		purple_debug_warning("cipher", "the %s cipher does not support the digest "
-						"operation\n", cipher->name);
-		return FALSE;
-	}
-}
-
-gboolean
-purple_cipher_context_digest_to_str(PurpleCipherContext *context,
-	gchar digest_s[], size_t len)
+purple_cipher_digest_to_str(PurpleCipher *cipher, gchar digest_s[], size_t len)
 {
 	/* 8k is a bit excessive, will tweak later. */
 	guchar digest[BUF_LEN * 4];
 	gint n = 0;
 	size_t digest_size;
 
-	g_return_val_if_fail(context, FALSE);
+	g_return_val_if_fail(cipher, FALSE);
 	g_return_val_if_fail(digest_s, FALSE);
 
-	digest_size = purple_cipher_context_get_digest_size(context);
+	digest_size = purple_cipher_get_digest_size(cipher);
 
 	g_return_val_if_fail(digest_size <= BUF_LEN * 4, FALSE);
 
-	if(!purple_cipher_context_digest(context, digest, sizeof(digest)))
+	if(!purple_cipher_digest(cipher, digest, sizeof(digest)))
 		return FALSE;
 
 	/* Every digest byte occupies 2 chars + the NUL at the end. */
@@ -478,373 +258,240 @@
 }
 
 size_t
-purple_cipher_context_get_digest_size(PurpleCipherContext *context)
+purple_cipher_get_digest_size(PurpleCipher *cipher)
 {
-	PurpleCipher *cipher = NULL;
+	PurpleCipherClass *klass = NULL;
 
-	g_return_val_if_fail(context, 0);
+	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), FALSE);
+
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	cipher = context->cipher;
-	g_return_val_if_fail(cipher, 0);
+	if(klass && klass->get_digest_size)
+		return klass->get_digest_size(cipher);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"get_digest_size method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 
-	if(cipher->ops && cipher->ops->get_digest_size)
-		return cipher->ops->get_digest_size(context);
-	else {
-		purple_debug_warning("cipher", "The %s cipher does not support "
-			"the get_digest_size operation\n", cipher->name);
-		return 0;
-	}
+	return FALSE;
 }
 
+/**
+ * purple_cipher_encrypt:
+ * @cipher: The cipher
+ * @data: The data to encrypt
+ * @len: The length of the data
+ * @output: The output buffer
+ * @outlen: The len of data that was outputed
+ *
+ * Encrypts data using the cipher
+ *
+ * Return Value: A cipher specific status code
+ */
 ssize_t
-purple_cipher_context_encrypt(PurpleCipherContext *context,
-	const guchar input[], size_t in_len, guchar output[], size_t out_size)
+purple_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
 {
-	PurpleCipher *cipher = NULL;
+	PurpleCipherClass *klass = NULL;
 
-	g_return_val_if_fail(context != NULL, -1);
+	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
 	g_return_val_if_fail(input != NULL, -1);
 	g_return_val_if_fail(output != NULL, -1);
 	g_return_val_if_fail(out_size >= in_len, -1);
 
-	cipher = context->cipher;
-	g_return_val_if_fail(cipher, -1);
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	if(cipher->ops && cipher->ops->encrypt)
-		return cipher->ops->encrypt(context, input, in_len, output, out_size);
-	else {
-		purple_debug_warning("cipher", "the %s cipher does not support the encrypt"
-						"operation\n", cipher->name);
+	if(klass && klass->encrypt)
+		return klass->encrypt(cipher, input, in_len, output, out_size);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"encrypt method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 
-		return -1;
-	}
+	return -1;
 }
 
+/**
+ * purple_cipher_decrypt:
+ * @cipher: The cipher
+ * @data: The data to encrypt
+ * @len: The length of the returned value
+ * @output: The output buffer
+ * @outlen: The len of data that was outputed
+ *
+ * Decrypts data using the cipher
+ *
+ * Return Value: A cipher specific status code
+ */
 ssize_t
-purple_cipher_context_decrypt(PurpleCipherContext *context,
-	const guchar input[], size_t in_len, guchar output[], size_t out_size)
+purple_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
 {
-	PurpleCipher *cipher = NULL;
+	PurpleCipherClass *klass = NULL;
 
-	g_return_val_if_fail(context != NULL, -1);
+	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
 	g_return_val_if_fail(input != NULL, -1);
 	g_return_val_if_fail(output != NULL, -1);
 
-	cipher = context->cipher;
-	g_return_val_if_fail(cipher, -1);
-
-	if(cipher->ops && cipher->ops->decrypt)
-		return cipher->ops->decrypt(context, input, in_len, output, out_size);
-	else {
-		purple_debug_warning("cipher", "the %s cipher does not support the decrypt"
-						"operation\n", cipher->name);
-
-		return -1;
-	}
-}
-
-void
-purple_cipher_context_set_salt(PurpleCipherContext *context, const guchar *salt, size_t len) {
-	PurpleCipher *cipher = NULL;
-
-	g_return_if_fail(context);
-
-	cipher = context->cipher;
-	g_return_if_fail(cipher);
-
-	if(cipher->ops && cipher->ops->set_salt)
-		cipher->ops->set_salt(context, salt, len);
-	else
-		purple_debug_warning("cipher", "the %s cipher does not support the "
-						"set_salt operation\n", cipher->name);
-}
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-size_t
-purple_cipher_context_get_salt_size(PurpleCipherContext *context) {
-	PurpleCipher *cipher = NULL;
-
-	g_return_val_if_fail(context, -1);
-
-	cipher = context->cipher;
-	g_return_val_if_fail(cipher, -1);
-
-	if(cipher->ops && cipher->ops->get_salt_size)
-		return cipher->ops->get_salt_size(context);
-	else {
-		purple_debug_warning("cipher", "the %s cipher does not support the "
-						"get_salt_size operation\n", cipher->name);
+	if(klass && klass->decrypt)
+		return klass->decrypt(cipher, input, in_len, output, out_size);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"decrypt method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 
-		return -1;
-	}
-}
-
-void
-purple_cipher_context_set_key(PurpleCipherContext *context, const guchar *key, size_t len) {
-	PurpleCipher *cipher = NULL;
-
-	g_return_if_fail(context);
-
-	cipher = context->cipher;
-	g_return_if_fail(cipher);
-
-	if(cipher->ops && cipher->ops->set_key)
-		cipher->ops->set_key(context, key, len);
-	else
-		purple_debug_warning("cipher", "the %s cipher does not support the "
-						"set_key operation\n", cipher->name);
+	return -1;
 }
 
-size_t
-purple_cipher_context_get_key_size(PurpleCipherContext *context) {
-	PurpleCipher *cipher = NULL;
-
-	g_return_val_if_fail(context, 0);
-
-	cipher = context->cipher;
-	g_return_val_if_fail(cipher, 0);
-
-	if (cipher->ops && cipher->ops->get_key_size)
-		return cipher->ops->get_key_size(context);
-	else {
-		purple_debug_warning("cipher", "the %s cipher does not support "
-			"the get_key_size operation\n", cipher->name);
+/**
+ * purple_cipher_set_salt:
+ * @cipher: The cipher whose salt to set
+ * @salt: The salt
+ *
+ * Sets the salt on a cipher
+ */
+void
+purple_cipher_set_salt(PurpleCipher *cipher, const guchar *salt, size_t len) {
+	PurpleCipherClass *klass = NULL;
 
-		return 0;
-	}
-}
+	g_return_if_fail(PURPLE_IS_CIPHER(cipher));
 
-void
-purple_cipher_context_set_batch_mode(PurpleCipherContext *context,
-                                     PurpleCipherBatchMode mode)
-{
-	PurpleCipher *cipher = NULL;
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	g_return_if_fail(context);
-
-	cipher = context->cipher;
-	g_return_if_fail(cipher);
-
-	if(cipher->ops && cipher->ops->set_batch_mode)
-		cipher->ops->set_batch_mode(context, mode);
+	if(klass && klass->set_salt)
+		klass->set_salt(cipher, salt, len);
 	else
-		purple_debug_warning("cipher", "The %s cipher does not support the "
-		                            "set_batch_mode operation\n", cipher->name);
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"set_salt method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 }
 
-PurpleCipherBatchMode
-purple_cipher_context_get_batch_mode(PurpleCipherContext *context)
-{
-	PurpleCipher *cipher = NULL;
-
-	g_return_val_if_fail(context, -1);
-
-	cipher = context->cipher;
-	g_return_val_if_fail(cipher, -1);
-
-	if(cipher->ops && cipher->ops->get_batch_mode)
-		return cipher->ops->get_batch_mode(context);
-	else {
-		purple_debug_warning("cipher", "The %s cipher does not support the "
-		                            "get_batch_mode operation\n", cipher->name);
-		return -1;
-	}
-}
-
-size_t
-purple_cipher_context_get_block_size(PurpleCipherContext *context)
-{
-	PurpleCipher *cipher = NULL;
+/**
+ * purple_cipher_set_key:
+ * @cipher: The cipher whose key to set
+ * @key: The key
+ *
+ * Sets the key on a cipher
+ */
+void
+purple_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len) {
+	PurpleCipherClass *klass = NULL;
 
-	g_return_val_if_fail(context, -1);
+	g_return_if_fail(PURPLE_IS_CIPHER(cipher));
 
-	cipher = context->cipher;
-	g_return_val_if_fail(cipher, -1);
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	if(cipher->ops && cipher->ops->get_block_size)
-		return cipher->ops->get_block_size(context);
-	else {
-		purple_debug_warning("cipher", "The %s cipher does not support the "
-		                            "get_block_size operation\n", cipher->name);
-		return -1;
-	}
-}
-
-void
-purple_cipher_context_set_data(PurpleCipherContext *context, gpointer data) {
-	g_return_if_fail(context);
-
-	context->data = data;
-}
-
-gpointer
-purple_cipher_context_get_data(PurpleCipherContext *context) {
-	g_return_val_if_fail(context, NULL);
-
-	return context->data;
+	if(klass && klass->set_key)
+		klass->set_key(cipher, key, len);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"set_key method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 }
 
-gchar *purple_cipher_http_digest_calculate_session_key(
-		const gchar *algorithm,
-		const gchar *username,
-		const gchar *realm,
-		const gchar *password,
-		const gchar *nonce,
-		const gchar *client_nonce)
-{
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
-	gchar hash[33]; /* We only support MD5. */
+/**
+ * purple_cipher_get_key_size:
+ * @cipher: The cipher whose key size to get
+ *
+ * Gets the key size for a cipher
+ *
+ * Return Value: The size of the key
+ */
+size_t
+purple_cipher_get_key_size(PurpleCipher *cipher) {
+	PurpleCipherClass *klass = NULL;
 
-	g_return_val_if_fail(username != NULL, NULL);
-	g_return_val_if_fail(realm    != NULL, NULL);
-	g_return_val_if_fail(password != NULL, NULL);
-	g_return_val_if_fail(nonce    != NULL, NULL);
+	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
+
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	/* Check for a supported algorithm. */
-	g_return_val_if_fail(algorithm == NULL ||
-						 *algorithm == '\0' ||
-						 g_ascii_strcasecmp(algorithm, "MD5") ||
-						 g_ascii_strcasecmp(algorithm, "MD5-sess"), NULL);
-
-	cipher = purple_ciphers_find_cipher("md5");
-	g_return_val_if_fail(cipher != NULL, NULL);
-
-	context = purple_cipher_context_new(cipher, NULL);
+	if(klass && klass->get_key_size)
+		return klass->get_key_size(cipher);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"get_key_size method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 
-	purple_cipher_context_append(context, (guchar *)username, strlen(username));
-	purple_cipher_context_append(context, (guchar *)":", 1);
-	purple_cipher_context_append(context, (guchar *)realm, strlen(realm));
-	purple_cipher_context_append(context, (guchar *)":", 1);
-	purple_cipher_context_append(context, (guchar *)password, strlen(password));
-
-	if (algorithm != NULL && !g_ascii_strcasecmp(algorithm, "MD5-sess"))
-	{
-		guchar digest[16];
+	return -1;
+}
 
-		if (client_nonce == NULL)
-		{
-			purple_cipher_context_destroy(context);
-			purple_debug_error("cipher", "Required client_nonce missing for MD5-sess digest calculation.\n");
-			return NULL;
-		}
-
-		purple_cipher_context_digest(context, digest, sizeof(digest));
-		purple_cipher_context_destroy(context);
+/**
+ * purple_cipher_set_batch_mode:
+ * @cipher: The cipher whose batch mode to set
+ * @mode: The batch mode under which the cipher should operate
+ *
+ * Sets the batch mode of a cipher
+ */
+void
+purple_cipher_set_batch_mode(PurpleCipher *cipher,
+                                     PurpleCipherBatchMode mode)
+{
+	PurpleCipherClass *klass = NULL;
 
-		context = purple_cipher_context_new(cipher, NULL);
-		purple_cipher_context_append(context, digest, sizeof(digest));
-		purple_cipher_context_append(context, (guchar *)":", 1);
-		purple_cipher_context_append(context, (guchar *)nonce, strlen(nonce));
-		purple_cipher_context_append(context, (guchar *)":", 1);
-		purple_cipher_context_append(context, (guchar *)client_nonce, strlen(client_nonce));
-	}
+	g_return_if_fail(PURPLE_IS_CIPHER(cipher));
+
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	purple_cipher_context_digest_to_str(context, hash, sizeof(hash));
-	purple_cipher_context_destroy(context);
-
-	return g_strdup(hash);
+	if(klass && klass->set_batch_mode)
+		klass->set_batch_mode(cipher, mode);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"set_batch_mode method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 }
 
-gchar *purple_cipher_http_digest_calculate_response(
-		const gchar *algorithm,
-		const gchar *method,
-		const gchar *digest_uri,
-		const gchar *qop,
-		const gchar *entity,
-		const gchar *nonce,
-		const gchar *nonce_count,
-		const gchar *client_nonce,
-		const gchar *session_key)
+/**
+ * purple_cipher_get_batch_mode:
+ * @cipher: The cipher whose batch mode to get
+ *
+ * Gets the batch mode of a cipher
+ *
+ * Return Value: The batch mode under which the cipher is operating
+ */
+PurpleCipherBatchMode
+purple_cipher_get_batch_mode(PurpleCipher *cipher)
 {
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
-	static gchar hash2[33]; /* We only support MD5. */
-
-	g_return_val_if_fail(method      != NULL, NULL);
-	g_return_val_if_fail(digest_uri  != NULL, NULL);
-	g_return_val_if_fail(nonce       != NULL, NULL);
-	g_return_val_if_fail(session_key != NULL, NULL);
+	PurpleCipherClass *klass = NULL;
 
-	/* Check for a supported algorithm. */
-	g_return_val_if_fail(algorithm == NULL ||
-						 *algorithm == '\0' ||
-						 g_ascii_strcasecmp(algorithm, "MD5") ||
-						 g_ascii_strcasecmp(algorithm, "MD5-sess"), NULL);
+	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
 
-	/* Check for a supported "quality of protection". */
-	g_return_val_if_fail(qop == NULL ||
-						 *qop == '\0' ||
-						 g_ascii_strcasecmp(qop, "auth") ||
-						 g_ascii_strcasecmp(qop, "auth-int"), NULL);
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-	cipher = purple_ciphers_find_cipher("md5");
-	g_return_val_if_fail(cipher != NULL, NULL);
-
-	context = purple_cipher_context_new(cipher, NULL);
+	if(klass && klass->get_batch_mode)
+		return klass->get_batch_mode(cipher);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"get_batch_mode method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 
-	purple_cipher_context_append(context, (guchar *)method, strlen(method));
-	purple_cipher_context_append(context, (guchar *)":", 1);
-	purple_cipher_context_append(context, (guchar *)digest_uri, strlen(digest_uri));
-
-	if (qop != NULL && !g_ascii_strcasecmp(qop, "auth-int"))
-	{
-		PurpleCipherContext *context2;
-		gchar entity_hash[33];
+	return -1;
+}
 
-		if (entity == NULL)
-		{
-			purple_cipher_context_destroy(context);
-			purple_debug_error("cipher", "Required entity missing for auth-int digest calculation.\n");
-			return NULL;
-		}
-
-		context2 = purple_cipher_context_new(cipher, NULL);
-		purple_cipher_context_append(context2, (guchar *)entity, strlen(entity));
-		purple_cipher_context_digest_to_str(context2, entity_hash, sizeof(entity_hash));
-		purple_cipher_context_destroy(context2);
-
-		purple_cipher_context_append(context, (guchar *)":", 1);
-		purple_cipher_context_append(context, (guchar *)entity_hash, strlen(entity_hash));
-	}
-
-	purple_cipher_context_digest_to_str(context, hash2, sizeof(hash2));
-	purple_cipher_context_destroy(context);
-
-	context = purple_cipher_context_new(cipher, NULL);
-	purple_cipher_context_append(context, (guchar *)session_key, strlen(session_key));
-	purple_cipher_context_append(context, (guchar *)":", 1);
-	purple_cipher_context_append(context, (guchar *)nonce, strlen(nonce));
-	purple_cipher_context_append(context, (guchar *)":", 1);
+/**
+ * purple_cipher_get_block_size:
+ * @cipher: The cipher whose block size to get
+ *
+ * Gets the block size of a cipher
+ *
+ * Return Value: The block size of the cipher
+ */
+size_t
+purple_cipher_get_block_size(PurpleCipher *cipher)
+{
+	PurpleCipherClass *klass = NULL;
 
-	if (qop != NULL && *qop != '\0')
-	{
-		if (nonce_count == NULL)
-		{
-			purple_cipher_context_destroy(context);
-			purple_debug_error("cipher", "Required nonce_count missing for digest calculation.\n");
-			return NULL;
-		}
+	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
 
-		if (client_nonce == NULL)
-		{
-			purple_cipher_context_destroy(context);
-			purple_debug_error("cipher", "Required client_nonce missing for digest calculation.\n");
-			return NULL;
-		}
+	klass = PURPLE_CIPHER_GET_CLASS(cipher);
 
-		purple_cipher_context_append(context, (guchar *)nonce_count, strlen(nonce_count));
-		purple_cipher_context_append(context, (guchar *)":", 1);
-		purple_cipher_context_append(context, (guchar *)client_nonce, strlen(client_nonce));
-		purple_cipher_context_append(context, (guchar *)":", 1);
-
-		purple_cipher_context_append(context, (guchar *)qop, strlen(qop));
+	if(klass && klass->get_block_size)
+		return klass->get_block_size(cipher);
+	else
+		purple_debug_warning("cipher", "the %s cipher does not implement the "
+						"get_block_size method\n",
+						klass->get_name ? klass->get_name(cipher) : "");
 
-		purple_cipher_context_append(context, (guchar *)":", 1);
-	}
-
-	purple_cipher_context_append(context, (guchar *)hash2, strlen(hash2));
-	purple_cipher_context_digest_to_str(context, hash2, sizeof(hash2));
-	purple_cipher_context_destroy(context);
-
-	return g_strdup(hash2);
+	return -1;
 }
--- a/libpurple/cipher.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/cipher.h	Sun Jun 23 13:35:53 2013 +0530
@@ -28,110 +28,101 @@
 #define PURPLE_CIPHER_H
 
 #include <glib.h>
+#include <glib-object.h>
 #include <string.h>
 
-#define PURPLE_CIPHER(obj)			((PurpleCipher *)(obj))			/**< PurpleCipher typecast helper			*/
-#define PURPLE_CIPHER_OPS(obj)		((PurpleCipherOps *)(obj))		/**< PurpleCipherInfo typecase helper		*/
-#define PURPLE_CIPHER_CONTEXT(obj)	((PurpleCipherContext *)(obj))	/**< PurpleCipherContext typecast helper	*/
+#include "internal.h"
 
-typedef struct _PurpleCipher			PurpleCipher;			/**< A handle to a PurpleCipher	*/
-typedef struct _PurpleCipherOps		PurpleCipherOps;		/**< Ops for a PurpleCipher		*/
-typedef struct _PurpleCipherContext	PurpleCipherContext;	/**< A context for a PurpleCipher	*/
+#define PURPLE_TYPE_CIPHER				(purple_cipher_get_type())
+#define PURPLE_CIPHER(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_CIPHER, PurpleCipher))
+#define PURPLE_CIPHER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_CIPHER, PurpleCipherClass))
+#define PURPLE_IS_CIPHER(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_CIPHER))
+#define PURPLE_IS_CIPHER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_CIPHER))
+#define PURPLE_CIPHER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_CIPHER, PurpleCipherClass))
+
+typedef struct _PurpleCipher       PurpleCipher;
+typedef struct _PurpleCipherClass  PurpleCipherClass;
 
 /**
+ * PurpleCipherBatchMode:
+ * @PURPLE_CIPHER_BATCH_MODE_ECB: Electronic Codebook Mode
+ * @PURPLE_CIPHER_BATCH_MODE_CBC: Cipher Block Chaining Mode
+ *
  * Modes for batch encrypters
  */
-typedef enum {
-	PURPLE_CIPHER_BATCH_MODE_ECB,
-	PURPLE_CIPHER_BATCH_MODE_CBC
+typedef enum  {
+	PURPLE_CIPHER_BATCH_MODE_ECB, /*< nick=ECB Batch Mode >*/
+	PURPLE_CIPHER_BATCH_MODE_CBC /*< nick=CBC Batch Mode >*/
 } PurpleCipherBatchMode;
 
 /**
- * The operation flags for a cipher
+ * PurpleCipher:
+ *
+ * Purple Cipher is an opaque data structure and should not be used directly.
  */
-typedef enum {
-	PURPLE_CIPHER_CAPS_SET_OPT          = 1 << 1,   /**< Set option flag */
-	PURPLE_CIPHER_CAPS_GET_OPT          = 1 << 2,   /**< Get option flag */
-	PURPLE_CIPHER_CAPS_INIT             = 1 << 3,   /**< Init flag */
-	PURPLE_CIPHER_CAPS_RESET            = 1 << 4,   /**< Reset flag */
-	PURPLE_CIPHER_CAPS_RESET_STATE      = 1 << 5,   /**< Reset state flag */
-	PURPLE_CIPHER_CAPS_UNINIT           = 1 << 6,   /**< Uninit flag */
-	PURPLE_CIPHER_CAPS_SET_IV           = 1 << 7,   /**< Set IV flag */
-	PURPLE_CIPHER_CAPS_APPEND           = 1 << 8,   /**< Append flag */
-	PURPLE_CIPHER_CAPS_DIGEST           = 1 << 9,   /**< Digest flag */
-	PURPLE_CIPHER_CAPS_GET_DIGEST_SIZE  = 1 << 10,   /**< The get digest size flag */
-	PURPLE_CIPHER_CAPS_ENCRYPT          = 1 << 11,  /**< Encrypt flag */
-	PURPLE_CIPHER_CAPS_DECRYPT          = 1 << 12,  /**< Decrypt flag */
-	PURPLE_CIPHER_CAPS_SET_SALT         = 1 << 13,  /**< Set salt flag */
-	PURPLE_CIPHER_CAPS_GET_SALT_SIZE    = 1 << 14,  /**< Get salt size flag */
-	PURPLE_CIPHER_CAPS_SET_KEY          = 1 << 15,  /**< Set key flag */
-	PURPLE_CIPHER_CAPS_GET_KEY_SIZE     = 1 << 16,  /**< Get key size flag */
-	PURPLE_CIPHER_CAPS_SET_BATCH_MODE   = 1 << 17,  /**< Set batch mode flag */
-	PURPLE_CIPHER_CAPS_GET_BATCH_MODE   = 1 << 18,  /**< Get batch mode flag */
-	PURPLE_CIPHER_CAPS_GET_BLOCK_SIZE   = 1 << 19,  /**< The get block size flag */
-	PURPLE_CIPHER_CAPS_UNKNOWN          = 1 << 20   /**< Unknown */
-} PurpleCipherCaps;
+struct _PurpleCipher {
+	/*< private >*/
+	GObject gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
 
 /**
- * The operations of a cipher.  Every cipher must implement one of these.
+ * PurpleCipherClass:
+ *
+ * The base class for all #PurpleCipher's.
  */
-struct _PurpleCipherOps {
-	/** The set option function	*/
-	void (*set_option)(PurpleCipherContext *context, const gchar *name, void *value);
-
-	/** The get option function */
-	void *(*get_option)(PurpleCipherContext *context, const gchar *name);
-
-	/** The init function */
-	void (*init)(PurpleCipherContext *context, void *extra);
+struct _PurpleCipherClass {
+	/*< private >*/
+	GObjectClass parent_class;
 
 	/** The reset function */
-	void (*reset)(PurpleCipherContext *context, void *extra);
+	void (*reset)(PurpleCipher *cipher);
 
 	/** The reset state function */
-	void (*reset_state)(PurpleCipherContext *context, void *extra);
-
-	/** The uninit function */
-	void (*uninit)(PurpleCipherContext *context);
+	void (*reset_state)(PurpleCipher *cipher);
 
 	/** The set initialization vector function */
-	void (*set_iv)(PurpleCipherContext *context, guchar *iv, size_t len);
+	void (*set_iv)(PurpleCipher *cipher, guchar *iv, size_t len);
 
 	/** The append data function */
-	void (*append)(PurpleCipherContext *context, const guchar *data, size_t len);
+	void (*append)(PurpleCipher *cipher, const guchar *data, size_t len);
 
 	/** The digest function */
-	gboolean (*digest)(PurpleCipherContext *context, guchar digest[], size_t len);
+	gboolean (*digest)(PurpleCipher *cipher, guchar digest[], size_t len);
 
 	/** The get digest size function */
-	size_t (*get_digest_size)(PurpleCipherContext *context);
+	size_t (*get_digest_size)(PurpleCipher *cipher);
 
 	/** The encrypt function */
-	ssize_t (*encrypt)(PurpleCipherContext *context, const guchar input[], size_t in_len, guchar output[], size_t out_size);
+	ssize_t (*encrypt)(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size);
 
 	/** The decrypt function */
-	ssize_t (*decrypt)(PurpleCipherContext *context, const guchar input[], size_t in_len, guchar output[], size_t out_size);
+	ssize_t (*decrypt)(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size);
 
 	/** The set salt function */
-	void (*set_salt)(PurpleCipherContext *context, const guchar *salt, size_t len);
-
-	/** The get salt size function */
-	size_t (*get_salt_size)(PurpleCipherContext *context);
+	void (*set_salt)(PurpleCipher *cipher, const guchar *salt, size_t len);
 
 	/** The set key function */
-	void (*set_key)(PurpleCipherContext *context, const guchar *key, size_t len);
+	void (*set_key)(PurpleCipher *cipher, const guchar *key, size_t len);
 
 	/** The get key size function */
-	size_t (*get_key_size)(PurpleCipherContext *context);
+	size_t (*get_key_size)(PurpleCipher *cipher);
 
 	/** The set batch mode function */
-	void (*set_batch_mode)(PurpleCipherContext *context, PurpleCipherBatchMode mode);
+	void (*set_batch_mode)(PurpleCipher *cipher, PurpleCipherBatchMode mode);
 
 	/** The get batch mode function */
-	PurpleCipherBatchMode (*get_batch_mode)(PurpleCipherContext *context);
+	PurpleCipherBatchMode (*get_batch_mode)(PurpleCipher *cipher);
 
 	/** The get block size function */
-	size_t (*get_block_size)(PurpleCipherContext *context);
+	size_t (*get_block_size)(PurpleCipher *cipher);
+
+	/** The get cipher name function */
+	const gchar* (*get_name)(PurpleCipher *cipher);
 
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
@@ -141,380 +132,31 @@
 
 G_BEGIN_DECLS
 
-/*****************************************************************************/
-/** @name PurpleCipher API													 */
-/*****************************************************************************/
-/*@{*/
+GType purple_cipher_get_type(void);
 
-/**
- * Gets a cipher's name
- *
- * @param cipher The cipher handle
- *
- * @return The cipher's name
- */
 const gchar *purple_cipher_get_name(PurpleCipher *cipher);
 
-/**
- * Gets a cipher's capabilities
- *
- * @param cipher The cipher handle
- *
- * @return The cipher's info
- */
-guint purple_cipher_get_capabilities(PurpleCipher *cipher);
-
-/**
- * Gets a digest from a cipher
- *
- * @param name     The cipher's name
- * @param data     The data to hash
- * @param data_len The length of the data
- * @param digest   The returned digest
- * @param out_size The size of digest buffer
- *
- * @return The count of bytes written, or -1 if failed
- */
-ssize_t purple_cipher_digest_region(const gchar *name, const guchar *data, size_t data_len, guchar digest[], size_t out_size);
-
-/*@}*/
-/******************************************************************************/
-/** @name PurpleCiphers API													  */
-/******************************************************************************/
-/*@{*/
-
-/**
- * Finds a cipher by it's name
- *
- * @param name The name of the cipher to find
- *
- * @return The cipher handle or @c NULL
- */
-PurpleCipher *purple_ciphers_find_cipher(const gchar *name);
-
-/**
- * Registers a cipher as a usable cipher
- *
- * @param name The name of the new cipher
- * @param ops  The cipher ops to register
- *
- * @return The handle to the new cipher or @c NULL if it failed
- */
-PurpleCipher *purple_ciphers_register_cipher(const gchar *name, PurpleCipherOps *ops);
-
-/**
- * Unregisters a cipher
- *
- * @param cipher The cipher handle to unregister
- *
- * @return Whether or not the cipher was successfully unloaded
- */
-gboolean purple_ciphers_unregister_cipher(PurpleCipher *cipher);
-
-/**
- * Gets the list of ciphers
- *
- * @return The list of available ciphers
- * @note This list should not be modified, it is owned by the cipher core
- */
-GList *purple_ciphers_get_ciphers(void);
-
-/*@}*/
-/******************************************************************************/
-/** @name PurpleCipher Subsystem API											  */
-/******************************************************************************/
-/*@{*/
-
-/**
- * Gets the handle to the cipher subsystem
- *
- * @return The handle to the cipher subsystem
- */
-gpointer purple_ciphers_get_handle(void);
-
-/**
- * Initializes the cipher core
- */
-void purple_ciphers_init(void);
-
-/**
- * Uninitializes the cipher core
- */
-void purple_ciphers_uninit(void);
+void purple_cipher_reset(PurpleCipher *cipher);
+void purple_cipher_reset_state(PurpleCipher *cipher);
+void purple_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len);
 
-/*@}*/
-/******************************************************************************/
-/** @name PurpleCipherContext API												  */
-/******************************************************************************/
-/*@{*/
-
-/**
- * Sets the value an option on a cipher context
- *
- * @param context The cipher context
- * @param name    The name of the option
- * @param value   The value to set
- */
-void purple_cipher_context_set_option(PurpleCipherContext *context, const gchar *name, gpointer value);
-
-/**
- * Gets the vale of an option on a cipher context
- *
- * @param context The cipher context
- * @param name    The name of the option
- * @return The value of the option
- */
-gpointer purple_cipher_context_get_option(PurpleCipherContext *context, const gchar *name);
-
-/**
- * Creates a new cipher context and initializes it
- *
- * @param cipher The cipher to use
- * @param extra  Extra data for the specific cipher
- *
- * @return The new cipher context
- */
-PurpleCipherContext *purple_cipher_context_new(PurpleCipher *cipher, void *extra);
-
-/**
- * Creates a new cipher context by the cipher name and initializes it
- *
- * @param name  The cipher's name
- * @param extra Extra data for the specific cipher
- *
- * @return The new cipher context
- */
-PurpleCipherContext *purple_cipher_context_new_by_name(const gchar *name, void *extra);
-
-/**
- * Resets a cipher context to it's default value
- * @note If you have set an IV you will have to set it after resetting
- *
- * @param context The context to reset
- * @param extra   Extra data for the specific cipher
- */
-void purple_cipher_context_reset(PurpleCipherContext *context, gpointer extra);
-
-/**
- * Resets a cipher state to it's default value, but doesn't touch stateless
- * configuration.
- *
- * That means, IV and digest context will be wiped out, but keys, ops or salt
- * will remain untouched.
- *
- * @param context The context to reset
- * @param extra   Extra data for the specific cipher
- */
-void purple_cipher_context_reset_state(PurpleCipherContext *context, gpointer extra);
-
-/**
- * Destorys a cipher context and deinitializes it
- *
- * @param context The cipher context to destory
- */
-void purple_cipher_context_destroy(PurpleCipherContext *context);
-
-/**
- * Sets the initialization vector for a context
- * @note This should only be called right after a cipher context is created or reset
- *
- * @param context The context to set the IV to
- * @param iv      The initialization vector to set
- * @param len     The len of the IV
- */
-void purple_cipher_context_set_iv(PurpleCipherContext *context, guchar *iv, size_t len);
-
-/**
- * Appends data to the context
- *
- * @param context The context to append data to
- * @param data    The data to append
- * @param len     The length of the data
- */
-void purple_cipher_context_append(PurpleCipherContext *context, const guchar *data, size_t len);
+void purple_cipher_append(PurpleCipher *cipher, const guchar *data, size_t len);
+gboolean purple_cipher_digest(PurpleCipher *cipher, guchar digest[], size_t len);
+gboolean purple_cipher_digest_to_str(PurpleCipher *cipher, gchar digest_s[], size_t len);
+size_t purple_cipher_get_digest_size(PurpleCipher *cipher);
 
-/**
- * Digests a context
- *
- * @param context The context to digest
- * @param digest  The return buffer for the digest
- * @param len     The length of the buffer
- */
-gboolean purple_cipher_context_digest(PurpleCipherContext *context, guchar digest[], size_t len);
-
-/**
- * Converts a guchar digest into a hex string
- *
- * @param context  The context to get a digest from
- * @param digest_s The return buffer for the string digest
- * @param len      The length of the buffer
- */
-gboolean purple_cipher_context_digest_to_str(PurpleCipherContext *context, gchar digest_s[], size_t len);
-
-/**
- * Gets the digest size of a context
- *
- * @param context The context whose digest size to get
- *
- * @return The digest size of the context
- */
-size_t purple_cipher_context_get_digest_size(PurpleCipherContext *context);
-
-/**
- * Encrypts data using the context
- *
- * @param context  The context
- * @param input    The data to encrypt
- * @param in_len   The length of the data
- * @param output   The output buffer
- * @param out_size The size of the output buffer
- *
- * @return A length of data that was outputed or -1, if failed
- */
-ssize_t purple_cipher_context_encrypt(PurpleCipherContext *context, const guchar input[], size_t in_len, guchar output[], size_t out_size);
+ssize_t purple_cipher_encrypt(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size);
+ssize_t purple_cipher_decrypt(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size);
 
-/**
- * Decrypts data using the context
- *
- * @param context  The context
- * @param input    The data to encrypt
- * @param in_len   The length of the returned value
- * @param output   The output buffer
- * @param out_size The size of the output buffer
- *
- * @return A length of data that was outputed or -1, if failed
- */
-ssize_t purple_cipher_context_decrypt(PurpleCipherContext *context, const guchar input[], size_t in_len, guchar output[], size_t out_size);
-
-/**
- * Sets the salt on a context
- *
- * @param context The context whose salt to set
- * @param salt    The salt
- * @param len     The length of the salt
- */
-void purple_cipher_context_set_salt(PurpleCipherContext *context, const guchar *salt, size_t len);
-
-/**
- * Gets the size of the salt if the cipher supports it
- *
- * @param context The context whose salt size to get
- *
- * @return The size of the salt
- */
-size_t purple_cipher_context_get_salt_size(PurpleCipherContext *context);
-
-/**
- * Sets the key on a context
- *
- * @param context The context whose key to set
- * @param key     The key
- * @param len     The size of the key
- */
-void purple_cipher_context_set_key(PurpleCipherContext *context, const guchar *key, size_t len);
-
-/**
- * Gets the size of the key if the cipher supports it
- *
- * @param context The context whose key size to get
- *
- * @return The size of the key
- */
-size_t purple_cipher_context_get_key_size(PurpleCipherContext *context);
+void purple_cipher_set_salt(PurpleCipher *cipher, const guchar *salt, size_t len);
 
-/**
- * Sets the batch mode of a context
- *
- * @param context The context whose batch mode to set
- * @param mode    The batch mode under which the cipher should operate
- *
- */
-void purple_cipher_context_set_batch_mode(PurpleCipherContext *context, PurpleCipherBatchMode mode);
-
-/**
- * Gets the batch mode of a context
- *
- * @param context The context whose batch mode to get
- *
- * @return The batch mode under which the cipher is operating
- */
-PurpleCipherBatchMode purple_cipher_context_get_batch_mode(PurpleCipherContext *context);
-
-/**
- * Gets the block size of a context
- *
- * @param context The context whose block size to get
- *
- * @return The block size of the context
- */
-size_t purple_cipher_context_get_block_size(PurpleCipherContext *context);
-
-/**
- * Sets the cipher data for a context
- *
- * @param context The context whose cipher data to set
- * @param data    The cipher data to set
- */
-void purple_cipher_context_set_data(PurpleCipherContext *context, gpointer data);
-
-/**
- * Gets the cipher data for a context
- *
- * @param context The context whose cipher data to get
- *
- * @return The cipher data
- */
-gpointer purple_cipher_context_get_data(PurpleCipherContext *context);
+void purple_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len);
+size_t purple_cipher_get_key_size(PurpleCipher *cipher);
 
-/*@}*/
-/*****************************************************************************/
-/** @name Purple Cipher HTTP Digest Helper Functions							 */
-/*****************************************************************************/
-/*@{*/
-
-/**
- * Calculates a session key for HTTP Digest authentation
- *
- * See RFC 2617 for more information.
- *
- * @param algorithm    The hash algorithm to use
- * @param username     The username provided by the user
- * @param realm        The authentication realm provided by the server
- * @param password     The password provided by the user
- * @param nonce        The nonce provided by the server
- * @param client_nonce The nonce provided by the client
- *
- * @return The session key, or @c NULL if an error occurred.
- */
-gchar *purple_cipher_http_digest_calculate_session_key(
-		const gchar *algorithm, const gchar *username,
-		const gchar *realm, const gchar *password,
-		const gchar *nonce, const gchar *client_nonce);
+void purple_cipher_set_batch_mode(PurpleCipher *cipher, PurpleCipherBatchMode mode);
+PurpleCipherBatchMode purple_cipher_get_batch_mode(PurpleCipher *cipher);
 
-/** Calculate a response for HTTP Digest authentication
- *
- * See RFC 2617 for more information.
- *
- * @param algorithm         The hash algorithm to use
- * @param method            The HTTP method in use
- * @param digest_uri        The URI from the initial request
- * @param qop               The "quality of protection"
- * @param entity            The entity body
- * @param nonce             The nonce provided by the server
- * @param nonce_count       The nonce count
- * @param client_nonce      The nonce provided by the client
- * @param session_key       The session key from purple_cipher_http_digest_calculate_session_key()
- *
- * @return The hashed response, or @c NULL if an error occurred.
- */
-gchar *purple_cipher_http_digest_calculate_response(
-		const gchar *algorithm, const gchar *method,
-		const gchar *digest_uri, const gchar *qop,
-		const gchar *entity, const gchar *nonce,
-		const gchar *nonce_count, const gchar *client_nonce,
-		const gchar *session_key);
-
-/*@}*/
+size_t purple_cipher_get_block_size(PurpleCipher *cipher);
 
 G_END_DECLS
 
--- a/libpurple/ciphers/Makefile.am	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/ciphers/Makefile.am	Sun Jun 23 13:35:53 2013 +0530
@@ -1,24 +1,23 @@
 noinst_LTLIBRARIES=libpurple-ciphers.la
-# XXX: cipher.lo won't be updated after a change in cipher files
 
 if USE_NSS
-AES_SOURCE = aes.c
+AES_SOURCE = aescipher.c
 endif
 if USE_GNUTLS
-AES_SOURCE = aes.c
+AES_SOURCE = aescipher.c
 endif
 
 libpurple_ciphers_la_SOURCES=\
 	$(AES_SOURCE) \
-	des.c \
-	gchecksum.c \
-	hmac.c \
-	md4.c \
-	pbkdf2.c \
-	rc4.c
-
-noinst_HEADERS =\
-	ciphers.h
+	descipher.c \
+	des3cipher.c \
+	hmaccipher.c \
+	md4hash.c \
+	md5hash.c \
+	pbkdf2cipher.c \
+	rc4cipher.c \
+	sha1hash.c \
+	sha256hash.c
 
 INCLUDES = -I$(top_srcdir)/libpurple
 
--- a/libpurple/ciphers/aes.c	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,566 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- *
- * Written by Tomek Wasilczyk <tomkiewicz@cpw.pidgin.im>
- */
-
-#include "internal.h"
-#include "cipher.h"
-#include "ciphers.h"
-#include "debug.h"
-
-#if defined(HAVE_GNUTLS)
-#  define PURPLE_AES_USE_GNUTLS 1
-#  include <gnutls/gnutls.h>
-#  include <gnutls/crypto.h>
-#elif defined(HAVE_NSS)
-#  define PURPLE_AES_USE_NSS 1
-#  include <nss.h>
-#  include <pk11pub.h>
-#  include <prerror.h>
-#else
-#  error "No GnuTLS or NSS support"
-#endif
-
-/* 128bit */
-#define PURPLE_AES_BLOCK_SIZE 16
-
-typedef struct
-{
-	guchar iv[PURPLE_AES_BLOCK_SIZE];
-	guchar key[32];
-	guint key_size;
-	gboolean failure;
-} AESContext;
-
-typedef gboolean (*purple_aes_crypt_func)(
-	const guchar *input, guchar *output, size_t len,
-	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size);
-
-static void
-purple_aes_init(PurpleCipherContext *context, void *extra)
-{
-	AESContext *ctx_data;
-
-	ctx_data = g_new0(AESContext, 1);
-	purple_cipher_context_set_data(context, ctx_data);
-
-	purple_cipher_context_reset(context, extra);
-}
-
-static void
-purple_aes_uninit(PurpleCipherContext *context)
-{
-	AESContext *ctx_data;
-
-	purple_cipher_context_reset(context, NULL);
-
-	ctx_data = purple_cipher_context_get_data(context);
-	g_free(ctx_data);
-	purple_cipher_context_set_data(context, NULL);
-}
-
-static void
-purple_aes_reset(PurpleCipherContext *context, void *extra)
-{
-	AESContext *ctx_data = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(ctx_data != NULL);
-
-	memset(ctx_data->iv, 0, sizeof(ctx_data->iv));
-	memset(ctx_data->key, 0, sizeof(ctx_data->key));
-	ctx_data->key_size = 32; /* 256bit */
-	ctx_data->failure = FALSE;
-}
-
-static void
-purple_aes_set_option(PurpleCipherContext *context, const gchar *name,
-	void *value)
-{
-	AESContext *ctx_data = purple_cipher_context_get_data(context);
-
-	purple_debug_error("cipher-aes", "set_option not supported\n");
-	ctx_data->failure = TRUE;
-}
-
-static void
-purple_aes_set_iv(PurpleCipherContext *context, guchar *iv, size_t len)
-{
-	AESContext *ctx_data = purple_cipher_context_get_data(context);
-
-	if ((len > 0 && iv == NULL) ||
-		(len != 0 && len != sizeof(ctx_data->iv))) {
-		purple_debug_error("cipher-aes", "invalid IV length\n");
-		ctx_data->failure = TRUE;
-		return;
-	}
-
-	if (len == 0)
-		memset(ctx_data->iv, 0, sizeof(ctx_data->iv));
-	else
-		memcpy(ctx_data->iv, iv, len);
-}
-
-static void
-purple_aes_set_key(PurpleCipherContext *context, const guchar *key, size_t len)
-{
-	AESContext *ctx_data = purple_cipher_context_get_data(context);
-
-	if ((len > 0 && key == NULL) ||
-		(len != 0 && len != 16 && len != 24 && len != 32)) {
-		purple_debug_error("cipher-aes", "invalid key length\n");
-		ctx_data->failure = TRUE;
-		return;
-	}
-
-	ctx_data->key_size = len;
-	memset(ctx_data->key, 0, sizeof(ctx_data->key));
-	if (len > 0)
-		memcpy(ctx_data->key, key, len);
-}
-
-static guchar *
-purple_aes_pad_pkcs7(const guchar input[], size_t in_len, size_t *out_len)
-{
-	int padding_len, total_len;
-	guchar *padded;
-
-	g_return_val_if_fail(input != NULL, NULL);
-	g_return_val_if_fail(out_len != NULL, NULL);
-
-	padding_len = PURPLE_AES_BLOCK_SIZE - (in_len % PURPLE_AES_BLOCK_SIZE);
-	total_len = in_len + padding_len;
-	g_assert((total_len % PURPLE_AES_BLOCK_SIZE) == 0);
-
-	padded = g_new(guchar, total_len);
-	*out_len = total_len;
-
-	memcpy(padded, input, in_len);
-	memset(padded + in_len, padding_len, padding_len);
-
-	return padded;
-}
-
-static ssize_t
-purple_aes_unpad_pkcs7(guchar input[], size_t in_len)
-{
-	int padding_len, i;
-	size_t out_len;
-
-	g_return_val_if_fail(input != NULL, -1);
-	g_return_val_if_fail(in_len > 0, -1);
-
-	padding_len = input[in_len - 1];
-	if (padding_len <= 0 || padding_len > PURPLE_AES_BLOCK_SIZE ||
-		padding_len > in_len) {
-		purple_debug_warning("cipher-aes",
-			"Invalid padding length: %d (total %d) - "
-			"most probably, the key was invalid\n",
-			padding_len, in_len);
-		return -1;
-	}
-
-	out_len = in_len - padding_len;
-	for (i = 0; i < padding_len; i++) {
-		if (input[out_len + i] != padding_len) {
-			purple_debug_warning("cipher-aes",
-				"Padding doesn't match at pos %d (found %02x, "
-				"expected %02x) - "
-				"most probably, the key was invalid\n",
-				i, input[out_len + i], padding_len);
-			return -1;
-		}
-	}
-
-	memset(input + out_len, 0, padding_len);
-	return out_len;
-}
-
-#ifdef PURPLE_AES_USE_GNUTLS
-
-static gnutls_cipher_hd_t
-purple_aes_crypt_gnutls_init(guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32],
-	guint key_size)
-{
-	gnutls_cipher_hd_t handle;
-	gnutls_cipher_algorithm_t algorithm;
-	gnutls_datum_t key_info, iv_info;
-	int ret;
-
-	if (key_size == 16)
-		algorithm = GNUTLS_CIPHER_AES_128_CBC;
-	else if (key_size == 24)
-		algorithm = GNUTLS_CIPHER_AES_192_CBC;
-	else if (key_size == 32)
-		algorithm = GNUTLS_CIPHER_AES_256_CBC;
-	else
-		g_return_val_if_reached(NULL);
-
-	key_info.data = key;
-	key_info.size = key_size;
-
-	iv_info.data = iv;
-	iv_info.size = PURPLE_AES_BLOCK_SIZE;
-
-	ret = gnutls_cipher_init(&handle, algorithm, &key_info, &iv_info);
-	if (ret != 0) {
-		purple_debug_error("cipher-aes",
-			"gnutls_cipher_init failed: %d\n", ret);
-		return NULL;
-	}
-
-	return handle;
-}
-
-static gboolean
-purple_aes_encrypt_gnutls(const guchar *input, guchar *output, size_t len,
-	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
-{
-	gnutls_cipher_hd_t handle;
-	int ret;
-
-	handle = purple_aes_crypt_gnutls_init(iv, key, key_size);
-	if (handle == NULL)
-		return FALSE;
-
-	ret = gnutls_cipher_encrypt2(handle, input, len, output, len);
-	gnutls_cipher_deinit(handle);
-
-	if (ret != 0) {
-		purple_debug_error("cipher-aes",
-			"gnutls_cipher_encrypt2 failed: %d\n", ret);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static gboolean
-purple_aes_decrypt_gnutls(const guchar *input, guchar *output, size_t len,
-	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
-{
-	gnutls_cipher_hd_t handle;
-	int ret;
-
-	handle = purple_aes_crypt_gnutls_init(iv, key, key_size);
-	if (handle == NULL)
-		return FALSE;
-
-	ret = gnutls_cipher_decrypt2(handle, input, len, output, len);
-	gnutls_cipher_deinit(handle);
-
-	if (ret != 0) {
-		purple_debug_error("cipher-aes",
-			"gnutls_cipher_decrypt2 failed: %d\n", ret);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-#endif /* PURPLE_AES_USE_GNUTLS */
-
-#ifdef PURPLE_AES_USE_NSS
-
-typedef struct
-{
-	PK11SlotInfo *slot;
-	PK11SymKey *sym_key;
-	SECItem *sec_param;
-	PK11Context *enc_context;
-} purple_aes_encrypt_nss_context;
-
-static void
-purple_aes_encrypt_nss_context_cleanup(purple_aes_encrypt_nss_context *ctx)
-{
-	g_return_if_fail(ctx != NULL);
-
-	if (ctx->enc_context != NULL)
-		PK11_DestroyContext(ctx->enc_context, TRUE);
-	if (ctx->sec_param != NULL)
-		SECITEM_FreeItem(ctx->sec_param, TRUE);
-	if (ctx->sym_key != NULL)
-		PK11_FreeSymKey(ctx->sym_key);
-	if (ctx->slot != NULL)
-		PK11_FreeSlot(ctx->slot);
-
-	memset(ctx, 0, sizeof(purple_aes_encrypt_nss_context));
-}
-
-static gboolean
-purple_aes_crypt_nss(const guchar *input, guchar *output, size_t len,
-	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
-	CK_ATTRIBUTE_TYPE operation)
-{
-	purple_aes_encrypt_nss_context ctx;
-	CK_MECHANISM_TYPE cipher_mech = CKM_AES_CBC;
-	SECItem key_item, iv_item;
-	SECStatus ret;
-	int outlen = 0;
-	unsigned int outlen_tmp = 0;
-
-	memset(&ctx, 0, sizeof(purple_aes_encrypt_nss_context));
-
-	if (NSS_NoDB_Init(NULL) != SECSuccess) {
-		purple_debug_error("cipher-aes",
-			"NSS_NoDB_Init failed: %d\n", PR_GetError());
-		return FALSE;
-	}
-
-	ctx.slot = PK11_GetBestSlot(cipher_mech, NULL);
-	if (ctx.slot == NULL) {
-		purple_debug_error("cipher-aes",
-			"PK11_GetBestSlot failed: %d\n", PR_GetError());
-		return FALSE;
-	}
-
-	key_item.type = siBuffer;
-	key_item.data = key;
-	key_item.len = key_size;
-	ctx.sym_key = PK11_ImportSymKey(ctx.slot, cipher_mech,
-		PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL);
-	if (ctx.sym_key == NULL) {
-		purple_debug_error("cipher-aes",
-			"PK11_ImportSymKey failed: %d\n", PR_GetError());
-		purple_aes_encrypt_nss_context_cleanup(&ctx);
-		return FALSE;
-	}
-
-	iv_item.type = siBuffer;
-	iv_item.data = iv;
-	iv_item.len = PURPLE_AES_BLOCK_SIZE;
-	ctx.sec_param = PK11_ParamFromIV(cipher_mech, &iv_item);
-	if (ctx.sec_param == NULL) {
-		purple_debug_error("cipher-aes",
-			"PK11_ParamFromIV failed: %d\n", PR_GetError());
-		purple_aes_encrypt_nss_context_cleanup(&ctx);
-		return FALSE;
-	}
-
-	ctx.enc_context = PK11_CreateContextBySymKey(cipher_mech, operation,
-		ctx.sym_key, ctx.sec_param);
-	if (ctx.enc_context == NULL) {
-		purple_debug_error("cipher-aes",
-			"PK11_CreateContextBySymKey failed: %d\n",
-				PR_GetError());
-		purple_aes_encrypt_nss_context_cleanup(&ctx);
-		return FALSE;
-	}
-
-	ret = PK11_CipherOp(ctx.enc_context, output, &outlen, len, input, len);
-	if (ret != SECSuccess) {
-		purple_debug_error("cipher-aes",
-			"PK11_CipherOp failed: %d\n", PR_GetError());
-		purple_aes_encrypt_nss_context_cleanup(&ctx);
-		return FALSE;
-	}
-
-	ret = PK11_DigestFinal(ctx.enc_context, output + outlen, &outlen_tmp,
-		len - outlen);
-	if (ret != SECSuccess) {
-		purple_debug_error("cipher-aes",
-			"PK11_DigestFinal failed: %d\n", PR_GetError());
-		purple_aes_encrypt_nss_context_cleanup(&ctx);
-		return FALSE;
-	}
-
-	purple_aes_encrypt_nss_context_cleanup(&ctx);
-
-	outlen += outlen_tmp;
-	if (outlen != len) {
-		purple_debug_error("cipher-aes",
-			"resulting length doesn't match: %d (expected: %d)\n",
-			outlen, len);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static gboolean
-purple_aes_encrypt_nss(const guchar *input, guchar *output, size_t len,
-	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
-{
-	return purple_aes_crypt_nss(input, output, len, iv, key, key_size,
-		CKA_ENCRYPT);
-}
-
-static gboolean
-purple_aes_decrypt_nss(const guchar *input, guchar *output, size_t len,
-	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
-{
-	return purple_aes_crypt_nss(input, output, len, iv, key, key_size,
-		CKA_DECRYPT);
-}
-
-#endif /* PURPLE_AES_USE_NSS */
-
-static ssize_t
-purple_aes_encrypt(PurpleCipherContext *context, const guchar input[],
-	size_t in_len, guchar output[], size_t out_size)
-{
-	AESContext *ctx_data = purple_cipher_context_get_data(context);
-	purple_aes_crypt_func encrypt_func;
-	guchar *input_padded;
-	size_t out_len = 0;
-	gboolean succ;
-
-	if (ctx_data->failure)
-		return -1;
-
-	input_padded = purple_aes_pad_pkcs7(input, in_len, &out_len);
-
-	if (out_len > out_size) {
-		purple_debug_error("cipher-aes", "Output buffer too small\n");
-		memset(input_padded, 0, out_len);
-		g_free(input_padded);
-		return -1;
-	}
-
-#if defined(PURPLE_AES_USE_GNUTLS)
-	encrypt_func = purple_aes_encrypt_gnutls;
-#elif defined(PURPLE_AES_USE_NSS)
-	encrypt_func = purple_aes_encrypt_nss;
-#else
-#  error "No matching encrypt_func"
-#endif
-
-	succ = encrypt_func(input_padded, output, out_len, ctx_data->iv,
-		ctx_data->key, ctx_data->key_size);
-
-	memset(input_padded, 0, out_len);
-	g_free(input_padded);
-
-	if (!succ) {
-		memset(output, 0, out_len);
-		return -1;
-	}
-
-	return out_len;
-}
-
-static ssize_t
-purple_aes_decrypt(PurpleCipherContext *context, const guchar input[],
-	size_t in_len, guchar output[], size_t out_size)
-{
-	AESContext *ctx_data = purple_cipher_context_get_data(context);
-	purple_aes_crypt_func decrypt_func;
-	gboolean succ;
-	ssize_t out_len;
-
-	if (ctx_data->failure)
-		return -1;
-
-	if (in_len > out_size) {
-		purple_debug_error("cipher-aes", "Output buffer too small\n");
-		return -1;
-	}
-
-	if ((in_len % PURPLE_AES_BLOCK_SIZE) != 0 || in_len == 0) {
-		purple_debug_error("cipher-aes", "Malformed data\n");
-		return -1;
-	}
-
-#if defined(PURPLE_AES_USE_GNUTLS)
-	decrypt_func = purple_aes_decrypt_gnutls;
-#elif defined(PURPLE_AES_USE_NSS)
-	decrypt_func = purple_aes_decrypt_nss;
-#else
-#  error "No matching encrypt_func"
-#endif
-
-	succ = decrypt_func(input, output, in_len, ctx_data->iv, ctx_data->key,
-		ctx_data->key_size);
-
-	if (!succ) {
-		memset(output, 0, in_len);
-		return -1;
-	}
-
-	out_len = purple_aes_unpad_pkcs7(output, in_len);
-	if (out_len < 0) {
-		memset(output, 0, in_len);
-		return -1;
-	}
-
-	return out_len;
-}
-
-static size_t
-purple_aes_get_key_size(PurpleCipherContext *context)
-{
-	AESContext *ctx_data = purple_cipher_context_get_data(context);
-
-	return ctx_data->key_size;
-}
-
-static void
-purple_aes_set_batch_mode(PurpleCipherContext *context,
-	PurpleCipherBatchMode mode)
-{
-	AESContext *ctx_data = purple_cipher_context_get_data(context);
-
-	if (mode == PURPLE_CIPHER_BATCH_MODE_CBC)
-		return;
-
-	purple_debug_error("cipher-aes", "unsupported batch mode\n");
-	ctx_data->failure = TRUE;
-}
-
-static PurpleCipherBatchMode
-purple_aes_get_batch_mode(PurpleCipherContext *context)
-{
-	return PURPLE_CIPHER_BATCH_MODE_CBC;
-}
-
-static size_t
-purple_aes_get_block_size(PurpleCipherContext *context)
-{
-	return PURPLE_AES_BLOCK_SIZE;
-}
-
-static PurpleCipherOps AESOps = {
-	purple_aes_set_option,     /* set_option */
-	NULL,                      /* get_option */
-	purple_aes_init,           /* init */
-	purple_aes_reset,          /* reset */
-	NULL,                      /* reset_state */
-	purple_aes_uninit,         /* uninit */
-	purple_aes_set_iv,         /* set_iv */
-	NULL,                      /* append */
-	NULL,                      /* digest */
-	NULL,                      /* get_digest_size */
-	purple_aes_encrypt,        /* encrypt */
-	purple_aes_decrypt,        /* decrypt */
-	NULL,                      /* set_salt */
-	NULL,                      /* get_salt_size */
-	purple_aes_set_key,        /* set_key */
-	purple_aes_get_key_size,   /* get_key_size */
-	purple_aes_set_batch_mode, /* set_batch_mode */
-	purple_aes_get_batch_mode, /* get_batch_mode */
-	purple_aes_get_block_size, /* get_block_size */
-	NULL, NULL, NULL, NULL     /* reserved */
-};
-
-PurpleCipherOps *
-purple_aes_cipher_get_ops(void) {
-	return &AESOps;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/aescipher.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,658 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ * Written by Tomek Wasilczyk <tomkiewicz@cpw.pidgin.im>
+ */
+
+#include "aescipher.h"
+#include "debug.h"
+
+#include <string.h>
+
+#if defined(HAVE_GNUTLS)
+#  define PURPLE_AES_USE_GNUTLS 1
+#  include <gnutls/gnutls.h>
+#  include <gnutls/crypto.h>
+#elif defined(HAVE_NSS)
+#  define PURPLE_AES_USE_NSS 1
+#  include <nss.h>
+#  include <pk11pub.h>
+#  include <prerror.h>
+#else
+#  error "No GnuTLS or NSS support"
+#endif
+
+/* 128bit */
+#define PURPLE_AES_BLOCK_SIZE 16
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+#define PURPLE_AES_CIPHER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_AES_CIPHER, PurpleAESCipherPrivate))
+
+typedef struct {
+	guchar iv[PURPLE_AES_BLOCK_SIZE];
+	guchar key[32];
+	guint key_size;
+	gboolean failure;
+} PurpleAESCipherPrivate;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+	PROP_NONE,
+	PROP_BATCH_MODE,
+	PROP_IV,
+	PROP_KEY,
+	PROP_LAST,
+};
+
+/******************************************************************************
+ * Cipher Stuff
+ *****************************************************************************/
+
+typedef gboolean (*purple_aes_cipher_crypt_func)(
+	const guchar *input, guchar *output, size_t len,
+	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size);
+
+static void
+purple_aes_cipher_reset(PurpleCipher *cipher)
+{
+	PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
+
+	g_return_if_fail(priv != NULL);
+
+	memset(priv->iv, 0, sizeof(priv->iv));
+	memset(priv->key, 0, sizeof(priv->key));
+	priv->key_size = 32; /* 256bit */
+	priv->failure = FALSE;
+}
+
+static void
+purple_aes_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len)
+{
+	PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
+
+	if ((len > 0 && iv == NULL) ||
+		(len != 0 && len != sizeof(priv->iv))) {
+		purple_debug_error("cipher-aes", "invalid IV length\n");
+		priv->failure = TRUE;
+		return;
+	}
+
+	if (len == 0)
+		memset(priv->iv, 0, sizeof(priv->iv));
+	else
+		memcpy(priv->iv, iv, len);
+
+	g_object_notify(G_OBJECT(cipher), "iv");
+}
+
+static void
+purple_aes_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len)
+{
+	PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
+
+	if ((len > 0 && key == NULL) ||
+		(len != 0 && len != 16 && len != 24 && len != 32)) {
+		purple_debug_error("cipher-aes", "invalid key length\n");
+		priv->failure = TRUE;
+		return;
+	}
+
+	priv->key_size = len;
+	memset(priv->key, 0, sizeof(priv->key));
+	if (len > 0)
+		memcpy(priv->key, key, len);
+
+	g_object_notify(G_OBJECT(cipher), "key");
+}
+
+static guchar *
+purple_aes_cipher_pad_pkcs7(const guchar input[], size_t in_len, size_t *out_len)
+{
+	int padding_len, total_len;
+	guchar *padded;
+
+	g_return_val_if_fail(input != NULL, NULL);
+	g_return_val_if_fail(out_len != NULL, NULL);
+
+	padding_len = PURPLE_AES_BLOCK_SIZE - (in_len % PURPLE_AES_BLOCK_SIZE);
+	total_len = in_len + padding_len;
+	g_assert((total_len % PURPLE_AES_BLOCK_SIZE) == 0);
+
+	padded = g_new(guchar, total_len);
+	*out_len = total_len;
+
+	memcpy(padded, input, in_len);
+	memset(padded + in_len, padding_len, padding_len);
+
+	return padded;
+}
+
+static ssize_t
+purple_aes_cipher_unpad_pkcs7(guchar input[], size_t in_len)
+{
+	int padding_len, i;
+	size_t out_len;
+
+	g_return_val_if_fail(input != NULL, -1);
+	g_return_val_if_fail(in_len > 0, -1);
+
+	padding_len = input[in_len - 1];
+	if (padding_len <= 0 || padding_len > PURPLE_AES_BLOCK_SIZE ||
+		padding_len > in_len) {
+		purple_debug_warning("cipher-aes",
+			"Invalid padding length: %d (total %lu) - "
+			"most probably, the key was invalid\n",
+			padding_len, in_len);
+		return -1;
+	}
+
+	out_len = in_len - padding_len;
+	for (i = 0; i < padding_len; i++) {
+		if (input[out_len + i] != padding_len) {
+			purple_debug_warning("cipher-aes",
+				"Padding doesn't match at pos %d (found %02x, "
+				"expected %02x) - "
+				"most probably, the key was invalid\n",
+				i, input[out_len + i], padding_len);
+			return -1;
+		}
+	}
+
+	memset(input + out_len, 0, padding_len);
+	return out_len;
+}
+
+#ifdef PURPLE_AES_USE_GNUTLS
+
+static gnutls_cipher_hd_t
+purple_aes_cipher_gnutls_crypt_init(guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32],
+	guint key_size)
+{
+	gnutls_cipher_hd_t handle;
+	gnutls_cipher_algorithm_t algorithm;
+	gnutls_datum_t key_info, iv_info;
+	int ret;
+
+	if (key_size == 16)
+		algorithm = GNUTLS_CIPHER_AES_128_CBC;
+	else if (key_size == 24)
+		algorithm = GNUTLS_CIPHER_AES_192_CBC;
+	else if (key_size == 32)
+		algorithm = GNUTLS_CIPHER_AES_256_CBC;
+	else
+		g_return_val_if_reached(NULL);
+
+	key_info.data = key;
+	key_info.size = key_size;
+
+	iv_info.data = iv;
+	iv_info.size = PURPLE_AES_BLOCK_SIZE;
+
+	ret = gnutls_cipher_init(&handle, algorithm, &key_info, &iv_info);
+	if (ret != 0) {
+		purple_debug_error("cipher-aes",
+			"gnutls_cipher_init failed: %d\n", ret);
+		return NULL;
+	}
+
+	return handle;
+}
+
+static gboolean
+purple_aes_cipher_gnutls_encrypt(const guchar *input, guchar *output, size_t len,
+	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
+{
+	gnutls_cipher_hd_t handle;
+	int ret;
+
+	handle = purple_aes_cipher_gnutls_crypt_init(iv, key, key_size);
+	if (handle == NULL)
+		return FALSE;
+
+	ret = gnutls_cipher_encrypt2(handle, (guchar *) input, len, output, len);
+	gnutls_cipher_deinit(handle);
+
+	if (ret != 0) {
+		purple_debug_error("cipher-aes",
+			"gnutls_cipher_encrypt2 failed: %d\n", ret);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+purple_aes_cipher_gnutls_decrypt(const guchar *input, guchar *output, size_t len,
+	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
+{
+	gnutls_cipher_hd_t handle;
+	int ret;
+
+	handle = purple_aes_cipher_gnutls_crypt_init(iv, key, key_size);
+	if (handle == NULL)
+		return FALSE;
+
+	ret = gnutls_cipher_decrypt2(handle, input, len, output, len);
+	gnutls_cipher_deinit(handle);
+
+	if (ret != 0) {
+		purple_debug_error("cipher-aes",
+			"gnutls_cipher_decrypt2 failed: %d\n", ret);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+#endif /* PURPLE_AES_USE_GNUTLS */
+
+#ifdef PURPLE_AES_USE_NSS
+
+typedef struct {
+	PK11SlotInfo *slot;
+	PK11SymKey *sym_key;
+	SECItem *sec_param;
+	PK11Context *enc_context;
+} PurpleAESCipherNSSContext;
+
+static void
+purple_aes_cipher_nss_cleanup(PurpleAESCipherNSSContext *context)
+{
+	g_return_if_fail(context != NULL);
+
+	if (context->enc_context != NULL)
+		PK11_DestroyContext(context->enc_context, TRUE);
+	if (context->sec_param != NULL)
+		SECITEM_FreeItem(context->sec_param, TRUE);
+	if (context->sym_key != NULL)
+		PK11_FreeSymKey(context->sym_key);
+	if (context->slot != NULL)
+		PK11_FreeSlot(context->slot);
+
+	memset(context, 0, sizeof(PurpleAESCipherNSSContext));
+}
+
+static gboolean
+purple_aes_cipher_nss_crypt(const guchar *input, guchar *output, size_t len,
+	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
+	CK_ATTRIBUTE_TYPE operation)
+{
+	PurpleAESCipherNSSContext context;
+	CK_MECHANISM_TYPE cipher_mech = CKM_AES_CBC;
+	SECItem key_item, iv_item;
+	SECStatus ret;
+	int outlen = 0;
+	unsigned int outlen_tmp = 0;
+
+	memset(&context, 0, sizeof(PurpleAESCipherNSSContext));
+
+	if (NSS_NoDB_Init(NULL) != SECSuccess) {
+		purple_debug_error("cipher-aes",
+			"NSS_NoDB_Init failed: %d\n", PR_GetError());
+		return FALSE;
+	}
+
+	context.slot = PK11_GetBestSlot(cipher_mech, NULL);
+	if (context.slot == NULL) {
+		purple_debug_error("cipher-aes",
+			"PK11_GetBestSlot failed: %d\n", PR_GetError());
+		return FALSE;
+	}
+
+	key_item.type = siBuffer;
+	key_item.data = key;
+	key_item.len = key_size;
+	context.sym_key = PK11_ImportSymKey(context.slot, cipher_mech,
+		PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL);
+	if (context.sym_key == NULL) {
+		purple_debug_error("cipher-aes",
+			"PK11_ImportSymKey failed: %d\n", PR_GetError());
+		purple_aes_cipher_nss_cleanup(&context);
+		return FALSE;
+	}
+
+	iv_item.type = siBuffer;
+	iv_item.data = iv;
+	iv_item.len = PURPLE_AES_BLOCK_SIZE;
+	context.sec_param = PK11_ParamFromIV(cipher_mech, &iv_item);
+	if (context.sec_param == NULL) {
+		purple_debug_error("cipher-aes",
+			"PK11_ParamFromIV failed: %d\n", PR_GetError());
+		purple_aes_cipher_nss_cleanup(&context);
+		return FALSE;
+	}
+
+	context.enc_context = PK11_CreateContextBySymKey(cipher_mech, operation,
+		context.sym_key, context.sec_param);
+	if (context.enc_context == NULL) {
+		purple_debug_error("cipher-aes",
+			"PK11_CreateContextBySymKey failed: %d\n",
+				PR_GetError());
+		purple_aes_cipher_nss_cleanup(&context);
+		return FALSE;
+	}
+
+	ret = PK11_CipherOp(context.enc_context, output, &outlen, len, input, len);
+	if (ret != SECSuccess) {
+		purple_debug_error("cipher-aes",
+			"PK11_CipherOp failed: %d\n", PR_GetError());
+		purple_aes_cipher_nss_cleanup(&context);
+		return FALSE;
+	}
+
+	ret = PK11_DigestFinal(context.enc_context, output + outlen, &outlen_tmp,
+		len - outlen);
+	if (ret != SECSuccess) {
+		purple_debug_error("cipher-aes",
+			"PK11_DigestFinal failed: %d\n", PR_GetError());
+		purple_aes_cipher_nss_cleanup(&context);
+		return FALSE;
+	}
+
+	purple_aes_cipher_nss_cleanup(&context);
+
+	outlen += outlen_tmp;
+	if (outlen != len) {
+		purple_debug_error("cipher-aes",
+			"resulting length doesn't match: %d (expected: %lu)\n",
+			outlen, len);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+purple_aes_cipher_nss_encrypt(const guchar *input, guchar *output, size_t len,
+	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
+{
+	return purple_aes_cipher_nss_crypt(input, output, len, iv, key, key_size,
+		CKA_ENCRYPT);
+}
+
+static gboolean
+purple_aes_cipher_nss_decrypt(const guchar *input, guchar *output, size_t len,
+	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
+{
+	return purple_aes_cipher_nss_crypt(input, output, len, iv, key, key_size,
+		CKA_DECRYPT);
+}
+
+#endif /* PURPLE_AES_USE_NSS */
+
+static ssize_t
+purple_aes_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
+	size_t in_len, guchar output[], size_t out_size)
+{
+	PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
+	purple_aes_cipher_crypt_func encrypt_func;
+	guchar *input_padded;
+	size_t out_len = 0;
+	gboolean succ;
+
+	if (priv->failure)
+		return -1;
+
+	input_padded = purple_aes_cipher_pad_pkcs7(input, in_len, &out_len);
+
+	if (out_len > out_size) {
+		purple_debug_error("cipher-aes", "Output buffer too small\n");
+		memset(input_padded, 0, out_len);
+		g_free(input_padded);
+		return -1;
+	}
+
+#if defined(PURPLE_AES_USE_GNUTLS)
+	encrypt_func = purple_aes_cipher_gnutls_encrypt;
+#elif defined(PURPLE_AES_USE_NSS)
+	encrypt_func = purple_aes_cipher_nss_encrypt;
+#else
+#  error "No matching encrypt_func"
+#endif
+
+	succ = encrypt_func(input_padded, output, out_len, priv->iv,
+		priv->key, priv->key_size);
+
+	memset(input_padded, 0, out_len);
+	g_free(input_padded);
+
+	if (!succ) {
+		memset(output, 0, out_len);
+		return -1;
+	}
+
+	return out_len;
+}
+
+static ssize_t
+purple_aes_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
+	size_t in_len, guchar output[], size_t out_size)
+{
+	PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
+	purple_aes_cipher_crypt_func decrypt_func;
+	gboolean succ;
+	ssize_t out_len;
+
+	if (priv->failure)
+		return -1;
+
+	if (in_len > out_size) {
+		purple_debug_error("cipher-aes", "Output buffer too small\n");
+		return -1;
+	}
+
+	if ((in_len % PURPLE_AES_BLOCK_SIZE) != 0 || in_len == 0) {
+		purple_debug_error("cipher-aes", "Malformed data\n");
+		return -1;
+	}
+
+#if defined(PURPLE_AES_USE_GNUTLS)
+	decrypt_func = purple_aes_cipher_gnutls_decrypt;
+#elif defined(PURPLE_AES_USE_NSS)
+	decrypt_func = purple_aes_cipher_nss_decrypt;
+#else
+#  error "No matching encrypt_func"
+#endif
+
+	succ = decrypt_func(input, output, in_len, priv->iv, priv->key,
+		priv->key_size);
+
+	if (!succ) {
+		memset(output, 0, in_len);
+		return -1;
+	}
+
+	out_len = purple_aes_cipher_unpad_pkcs7(output, in_len);
+	if (out_len < 0) {
+		memset(output, 0, in_len);
+		return -1;
+	}
+
+	return out_len;
+}
+
+static size_t
+purple_aes_cipher_get_key_size(PurpleCipher *cipher)
+{
+	PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
+
+	return priv->key_size;
+}
+
+static void
+purple_aes_cipher_set_batch_mode(PurpleCipher *cipher,
+	PurpleCipherBatchMode mode)
+{
+	PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
+
+	if (mode == PURPLE_CIPHER_BATCH_MODE_CBC) {
+		g_object_notify(G_OBJECT(cipher), "batch_mode");
+		return;
+	}
+
+	purple_debug_error("cipher-aes", "unsupported batch mode\n");
+	priv->failure = TRUE;
+}
+
+static PurpleCipherBatchMode
+purple_aes_cipher_get_batch_mode(PurpleCipher *cipher)
+{
+	return PURPLE_CIPHER_BATCH_MODE_CBC;
+}
+
+static size_t
+purple_aes_cipher_get_block_size(PurpleCipher *cipher)
+{
+	return PURPLE_AES_BLOCK_SIZE;
+}
+
+static const gchar*
+purple_aes_cipher_get_name(PurpleCipher *cipher)
+{
+	return "aes";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_aes_cipher_get_property(GObject *obj, guint param_id, GValue *value,
+								GParamSpec *pspec)
+{
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+
+	switch(param_id) {
+		case PROP_BATCH_MODE:
+			g_value_set_enum(value,
+							 purple_cipher_get_batch_mode(cipher));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_aes_cipher_set_property(GObject *obj, guint param_id,
+								const GValue *value, GParamSpec *pspec)
+{
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+
+	switch(param_id) {
+		case PROP_BATCH_MODE:
+			purple_cipher_set_batch_mode(cipher,
+										 g_value_get_enum(value));
+			break;
+		case PROP_IV:
+			{
+				guchar *iv = (guchar *)g_value_get_string(value);
+				purple_cipher_set_iv(cipher, iv, strlen((gchar*)iv));
+			}
+			break;
+		case PROP_KEY:
+			purple_cipher_set_key(cipher, (guchar *)g_value_get_string(value),
+				purple_aes_cipher_get_key_size(cipher));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_aes_cipher_class_init(PurpleAESCipherClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
+	GParamSpec *pspec;
+
+	obj_class->get_property = purple_aes_cipher_get_property;
+	obj_class->set_property = purple_aes_cipher_set_property;
+
+	cipher_class->reset = purple_aes_cipher_reset;
+	cipher_class->set_iv = purple_aes_cipher_set_iv;
+	cipher_class->encrypt = purple_aes_cipher_encrypt;
+	cipher_class->decrypt = purple_aes_cipher_decrypt;
+	cipher_class->set_key = purple_aes_cipher_set_key;
+	cipher_class->get_key_size = purple_aes_cipher_get_key_size;
+	cipher_class->set_batch_mode = purple_aes_cipher_set_batch_mode;
+	cipher_class->get_batch_mode = purple_aes_cipher_get_batch_mode;
+	cipher_class->get_block_size = purple_aes_cipher_get_block_size;
+	cipher_class->get_name = purple_aes_cipher_get_name;
+
+	pspec = g_param_spec_enum("batch_mode", "batch_mode", "batch_mode",
+							  PURPLE_TYPE_CIPHER_BATCH_MODE, 0,
+							  G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_BATCH_MODE, pspec);
+
+	pspec = g_param_spec_string("iv", "iv", "iv", NULL,
+								G_PARAM_WRITABLE);
+	g_object_class_install_property(obj_class, PROP_IV, pspec);
+
+	pspec = g_param_spec_string("key", "key", "key", NULL,
+								G_PARAM_WRITABLE);
+	g_object_class_install_property(obj_class, PROP_KEY, pspec);
+
+	g_type_class_add_private(klass, sizeof(PurpleAESCipherPrivate));
+}
+
+static void
+purple_aes_cipher_init(PurpleCipher *cipher) {
+	purple_cipher_reset(cipher);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_aes_cipher_get_gtype(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleAESCipherClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_aes_cipher_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleAESCipher),
+			0,
+			(GInstanceInitFunc)purple_aes_cipher_init,
+			NULL
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_CIPHER,
+									  "PurpleAESCipher",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+PurpleCipher *
+purple_aes_cipher_new(void) {
+	return g_object_new(PURPLE_TYPE_AES_CIPHER, NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/aescipher.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,67 @@
+/**
+ * @file aes.h Purple AES Cipher
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_AES_CIPHER_H
+#define PURPLE_AES_CIPHER_H
+
+#include "cipher.h"
+
+#define PURPLE_TYPE_AES_CIPHER				(purple_aes_cipher_get_gtype())
+#define PURPLE_AES_CIPHER(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_AES_CIPHER, PurpleAESCipher))
+#define PURPLE_AES_CIPHER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_AES_CIPHER, PurpleAESCipherClass))
+#define PURPLE_IS_AES_CIPHER(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_AES_CIPHER))
+#define PURPLE_IS_AES_CIPHER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_AES_CIPHER))
+#define PURPLE_AES_CIPHER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_AES_CIPHER, PurpleAESCipherClass))
+
+typedef struct _PurpleAESCipher			PurpleAESCipher;
+typedef struct _PurpleAESCipherClass		PurpleAESCipherClass;
+
+struct _PurpleAESCipher {
+	PurpleCipher gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurpleAESCipherClass {
+	PurpleCipherClass gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_aes_cipher_get_gtype(void);
+
+PurpleCipher *purple_aes_cipher_new(void);
+
+G_END_DECLS
+
+#endif /* PURPLE_AES_CIPHER_H */
--- a/libpurple/ciphers/ciphers.h	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- */
-
-/* aes.c */
-PurpleCipherOps * purple_aes_cipher_get_ops(void);
-
-/* des.c */
-PurpleCipherOps * purple_des_cipher_get_ops(void);
-PurpleCipherOps * purple_des3_cipher_get_ops(void);
-
-/* gchecksum.c */
-PurpleCipherOps * purple_md5_cipher_get_ops(void);
-PurpleCipherOps * purple_sha1_cipher_get_ops(void);
-PurpleCipherOps * purple_sha256_cipher_get_ops(void);
-
-/* hmac.c */
-PurpleCipherOps * purple_hmac_cipher_get_ops(void);
-
-/* md4.c */
-PurpleCipherOps * purple_md4_cipher_get_ops(void);
-
-/* pbkdf2.c */
-PurpleCipherOps * purple_pbkdf2_cipher_get_ops(void);
-
-/* rc4.c */
-PurpleCipherOps * purple_rc4_cipher_get_ops(void);
-
-static inline void purple_ciphers_register_all(void)
-{
-#if defined(HAVE_GNUTLS) || defined(HAVE_NSS)
-	purple_ciphers_register_cipher("aes", purple_aes_cipher_get_ops());
-#endif
-
-	purple_ciphers_register_cipher("des", purple_des_cipher_get_ops());
-	purple_ciphers_register_cipher("des3", purple_des3_cipher_get_ops());
-
-	purple_ciphers_register_cipher("md5", purple_md5_cipher_get_ops());
-	purple_ciphers_register_cipher("sha1", purple_sha1_cipher_get_ops());
-	purple_ciphers_register_cipher("sha256", purple_sha256_cipher_get_ops());
-
-	purple_ciphers_register_cipher("hmac", purple_hmac_cipher_get_ops());
-
-	purple_ciphers_register_cipher("md4", purple_md4_cipher_get_ops());
-
-	purple_ciphers_register_cipher("pbkdf2", purple_pbkdf2_cipher_get_ops());
-
-	purple_ciphers_register_cipher("rc4", purple_rc4_cipher_get_ops());
-}
--- a/libpurple/ciphers/des.c	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,897 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * Original des taken from gpg
- *
- * des.c - DES and Triple-DES encryption/decryption Algorithm
- *  Copyright (C) 1998 Free Software Foundation, Inc.
- *
- *  Please see below for more legal information!
- *
- *   According to the definition of DES in FIPS PUB 46-2 from December 1993.
- *   For a description of triple encryption, see:
- *     Bruce Schneier: Applied Cryptography. Second Edition.
- *     John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
- *
- *   This file is part of GnuPG.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#include "internal.h"
-#include <cipher.h>
-#include "ciphers.h"
-
-/******************************************************************************
- * DES
- *****************************************************************************/
-typedef struct _des_ctx
-{
-	guint32 encrypt_subkeys[32];
-	guint32 decrypt_subkeys[32];
-} des_ctx[1];
-
-/*
- *  The s-box values are permuted according to the 'primitive function P'
- */
-static const guint32 sbox1[64] =
-{
-	0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000,
-	0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002,
-	0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202,
-	0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000,
-	0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200,
-	0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202,
-	0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200,
-	0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002
-};
-
-static const guint32 sbox2[64] =
-{
-	0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010,
-	0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010,
-	0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000,
-	0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010,
-	0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000,
-	0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000,
-	0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010,
-	0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000
-};
-
-static const guint32 sbox3[64] =
-{
-	0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100,
-	0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104,
-	0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104,
-	0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000,
-	0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000,
-	0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004,
-	0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004,
-	0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100
-};
-
-static const guint32 sbox4[64] =
-{
-	0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000,
-	0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000,
-	0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040,
-	0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040,
-	0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000,
-	0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040,
-	0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040,
-	0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040
-};
-
-static const guint32 sbox5[64] =
-{
-	0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000,
-	0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000,
-	0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080,
-	0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080,
-	0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080,
-	0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000,
-	0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000,
-	0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080
-};
-
-static const guint32 sbox6[64] =
-{
-	0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000,
-	0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008,
-	0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008,
-	0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000,
-	0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008,
-	0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000,
-	0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008,
-	0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008
-};
-
-static const guint32 sbox7[64] =
-{
-	0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400,
-	0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401,
-	0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001,
-	0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400,
-	0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001,
-	0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400,
-	0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401,
-	0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001
-};
-
-static const guint32 sbox8[64] =
-{
-	0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000,
-	0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020,
-	0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800,
-	0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000,
-	0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820,
-	0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820,
-	0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000,
-	0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800
-};
-
-
-/*
- *  * These two tables are part of the 'permuted choice 1' function.
- *   * In this implementation several speed improvements are done.
- *    */
-static const guint32 leftkey_swap[16] =
-{
-	0x00000000, 0x00000001, 0x00000100, 0x00000101,
-	0x00010000, 0x00010001, 0x00010100, 0x00010101,
-	0x01000000, 0x01000001, 0x01000100, 0x01000101,
-	0x01010000, 0x01010001, 0x01010100, 0x01010101
-};
-
-static const guint32 rightkey_swap[16] =
-{
-	0x00000000, 0x01000000, 0x00010000, 0x01010000,
-	0x00000100, 0x01000100, 0x00010100, 0x01010100,
-	0x00000001, 0x01000001, 0x00010001, 0x01010001,
-	0x00000101, 0x01000101, 0x00010101, 0x01010101,
-};
-
-
-/*
- *  Numbers of left shifts per round for encryption subkey schedule
- *  To calculate the decryption key scheduling we just reverse the
- *  ordering of the subkeys so we can omit the table for decryption
- *  subkey schedule.
- */
-static const guint8 encrypt_rotate_tab[16] =
-{
-	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
-};
-
-/*
- *  Macro to swap bits across two words
- **/
-#define DO_PERMUTATION(a, temp, b, offset, mask)    \
-	temp = ((a>>offset) ^ b) & mask;            \
-	b ^= temp;                      \
-	a ^= temp<<offset;
-
-
-/*
- *  This performs the 'initial permutation' for the data to be encrypted or decrypted
- **/
-#define INITIAL_PERMUTATION(left, temp, right)      \
-	DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)    \
-	DO_PERMUTATION(left, temp, right, 16, 0x0000ffff)   \
-	DO_PERMUTATION(right, temp, left, 2, 0x33333333)    \
-	DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff)    \
-	DO_PERMUTATION(left, temp, right, 1, 0x55555555)
-
-
-/*
- * The 'inverse initial permutation'
- **/
-#define FINAL_PERMUTATION(left, temp, right)        \
-	DO_PERMUTATION(left, temp, right, 1, 0x55555555)    \
-	DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff)    \
-	DO_PERMUTATION(right, temp, left, 2, 0x33333333)    \
-	DO_PERMUTATION(left, temp, right, 16, 0x0000ffff)   \
-	DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)
-
-
-/*
- * A full DES round including 'expansion function', 'sbox substitution'
- * and 'primitive function P' but without swapping the left and right word.
- **/
-#define DES_ROUND(from, to, work, subkey)       \
-	work = ((from<<1) | (from>>31)) ^ *subkey++;    \
-	to ^= sbox8[  work      & 0x3f ];           \
-	to ^= sbox6[ (work>>8)  & 0x3f ];           \
-	to ^= sbox4[ (work>>16) & 0x3f ];           \
-	to ^= sbox2[ (work>>24) & 0x3f ];           \
-	work = ((from>>3) | (from<<29)) ^ *subkey++;    \
-	to ^= sbox7[  work      & 0x3f ];           \
-	to ^= sbox5[ (work>>8)  & 0x3f ];           \
-	to ^= sbox3[ (work>>16) & 0x3f ];           \
-	to ^= sbox1[ (work>>24) & 0x3f ];
-
-
-/*
- * Macros to convert 8 bytes from/to 32bit words
- **/
-#define READ_64BIT_DATA(data, left, right)                  \
-	left  = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];   \
-	right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
-
-#define WRITE_64BIT_DATA(data, left, right)                 \
-	data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff;         \
-	data[2] = (left >> 8) &0xff; data[3] = left &0xff;              \
-	data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff;       \
-	data[6] = (right >> 8) &0xff; data[7] = right &0xff;
-
-
-/*
- * des_key_schedule():    Calculate 16 subkeys pairs (even/odd) for
- *            16 encryption rounds.
- *            To calculate subkeys for decryption the caller
- *                have to reorder the generated subkeys.
- *
- *        rawkey:       8 Bytes of key data
- *        subkey:       Array of at least 32 guint32s. Will be filled
- *              with calculated subkeys.
- *
- **/
-static void
-des_key_schedule (const guint8 * rawkey, guint32 * subkey)
-{
-	guint32 left, right, work;
-	int round;
-
-	READ_64BIT_DATA (rawkey, left, right)
-
-	DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f)
-	DO_PERMUTATION (right, work, left, 0, 0x10101010)
-
-	left = (leftkey_swap[(left >> 0) & 0xf] << 3) | (leftkey_swap[(left >> 8) & 0xf] << 2)
-	| (leftkey_swap[(left >> 16) & 0xf] << 1) | (leftkey_swap[(left >> 24) & 0xf])
-	| (leftkey_swap[(left >> 5) & 0xf] << 7) | (leftkey_swap[(left >> 13) & 0xf] << 6)
-	| (leftkey_swap[(left >> 21) & 0xf] << 5) | (leftkey_swap[(left >> 29) & 0xf] << 4);
-
-	left &= 0x0fffffff;
-
-	right = (rightkey_swap[(right >> 1) & 0xf] << 3) | (rightkey_swap[(right >> 9) & 0xf] << 2)
-		| (rightkey_swap[(right >> 17) & 0xf] << 1) | (rightkey_swap[(right >> 25) & 0xf])
-		| (rightkey_swap[(right >> 4) & 0xf] << 7) | (rightkey_swap[(right >> 12) & 0xf] << 6)
-		| (rightkey_swap[(right >> 20) & 0xf] << 5) | (rightkey_swap[(right >> 28) & 0xf] << 4);
-
-	right &= 0x0fffffff;
-
-	for (round = 0; round < 16; ++round)
-	{
-        left = ((left << encrypt_rotate_tab[round]) | (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
-        right = ((right << encrypt_rotate_tab[round]) | (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
-
-		*subkey++ = ((left << 4) & 0x24000000)
-			| ((left << 28) & 0x10000000)
-			| ((left << 14) & 0x08000000)
-			| ((left << 18) & 0x02080000)
-			| ((left << 6) & 0x01000000)
-			| ((left << 9) & 0x00200000)
-			| ((left >> 1) & 0x00100000)
-			| ((left << 10) & 0x00040000)
-			| ((left << 2) & 0x00020000)
-			| ((left >> 10) & 0x00010000)
-			| ((right >> 13) & 0x00002000)
-			| ((right >> 4) & 0x00001000)
-			| ((right << 6) & 0x00000800)
-			| ((right >> 1) & 0x00000400)
-			| ((right >> 14) & 0x00000200)
-			| (right & 0x00000100)
-			| ((right >> 5) & 0x00000020)
-			| ((right >> 10) & 0x00000010)
-			| ((right >> 3) & 0x00000008)
-			| ((right >> 18) & 0x00000004)
-			| ((right >> 26) & 0x00000002)
-			| ((right >> 24) & 0x00000001);
-
-		*subkey++ = ((left << 15) & 0x20000000)
-			| ((left << 17) & 0x10000000)
-			| ((left << 10) & 0x08000000)
-			| ((left << 22) & 0x04000000)
-			| ((left >> 2) & 0x02000000)
-			| ((left << 1) & 0x01000000)
-			| ((left << 16) & 0x00200000)
-			| ((left << 11) & 0x00100000)
-			| ((left << 3) & 0x00080000)
-			| ((left >> 6) & 0x00040000)
-			| ((left << 15) & 0x00020000)
-			| ((left >> 4) & 0x00010000)
-			| ((right >> 2) & 0x00002000)
-			| ((right << 8) & 0x00001000)
-			| ((right >> 14) & 0x00000808)
-			| ((right >> 9) & 0x00000400)
-			| ((right) & 0x00000200)
-			| ((right << 7) & 0x00000100)
-			| ((right >> 7) & 0x00000020)
-			| ((right >> 3) & 0x00000011)
-			| ((right << 2) & 0x00000004)
-			| ((right >> 21) & 0x00000002);
-	}
-}
-
-
-/*
- *  Fill a DES context with subkeys calculated from a 64bit key.
- *  Does not check parity bits, but simply ignore them.
- *  Does not check for weak keys.
- **/
-static void
-des_set_key (PurpleCipherContext *context, const guchar * key, size_t len)
-{
-	struct _des_ctx *ctx = purple_cipher_context_get_data(context);
-	int i;
-
-	g_return_if_fail(len == 8);
-
-	des_key_schedule (key, ctx->encrypt_subkeys);
-
-	for(i=0; i<32; i+=2)
-	{
-		ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i];
-		ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i];
-	}
-}
-
-static size_t
-des_get_key_size(PurpleCipherContext *context)
-{
-	return 8;
-}
-
-/*
- *  Electronic Codebook Mode DES encryption/decryption of data according
- *  to 'mode'.
- **/
-static int
-des_ecb_crypt (struct _des_ctx *ctx, const guint8 * from, guint8 * to, int mode)
-{
-	guint32 left, right, work;
-	guint32 *keys;
-
-	keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
-
-	READ_64BIT_DATA (from, left, right)
-	INITIAL_PERMUTATION (left, work, right)
-
-	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
-	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
-	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
-	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
-	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
-	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
-	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
-	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
-
-	FINAL_PERMUTATION (right, work, left)
-	WRITE_64BIT_DATA (to, right, left)
-
-	return 0;
-}
-
-static ssize_t
-des_encrypt(PurpleCipherContext *context, const guchar input[], size_t in_len,
-	guchar output[], size_t out_size)
-{
-	int offset = 0;
-	int i = 0;
-	int tmp;
-	guint8 buf[8] = {0,0,0,0,0,0,0,0};
-	ssize_t out_len;
-
-	g_return_val_if_fail(out_size >= in_len, -1);
-
-	while(offset+8<=in_len) {
-		des_ecb_crypt(purple_cipher_context_get_data(context),
-		              input+offset,
-		              output+offset,
-		              0);
-		offset+=8;
-	}
-	out_len = in_len;
-	if(offset<in_len) {
-		out_len += in_len - offset;
-		g_return_val_if_fail(out_size >= out_len, -1);
-		tmp = offset;
-		while(tmp<in_len) {
-			buf[i++] = input[tmp];
-			tmp++;
-		}
-		des_ecb_crypt(purple_cipher_context_get_data(context),
-		              buf,
-		              output+offset,
-		              0);
-	}
-	return out_len;
-}
-
-static ssize_t
-des_decrypt(PurpleCipherContext *context, const guchar input[], size_t in_len,
-	guchar output[], size_t out_size)
-{
-	int offset = 0;
-	int i = 0;
-	int tmp;
-	guint8 buf[8] = {0,0,0,0,0,0,0,0};
-	ssize_t out_len;
-
-	g_return_val_if_fail(out_size >= in_len, -1);
-
-	while(offset+8<=in_len) {
-		des_ecb_crypt(purple_cipher_context_get_data(context),
-		              input+offset,
-		              output+offset,
-		              1);
-		offset+=8;
-	}
-	out_len = in_len;
-	if(offset<in_len) {
-		out_len += in_len - offset;
-		g_return_val_if_fail(out_size >= out_len, -1);
-		tmp = offset;
-		while(tmp<in_len) {
-			buf[i++] = input[tmp];
-			tmp++;
-		}
-		des_ecb_crypt(purple_cipher_context_get_data(context),
-		              buf,
-		              output+offset,
-		              1);
-	}
-	return out_len;
-}
-
-static void
-des_init(PurpleCipherContext *context, gpointer extra) {
-	struct _des_ctx *mctx;
-	mctx = g_new0(struct _des_ctx, 1);
-	purple_cipher_context_set_data(context, mctx);
-}
-
-static void
-des_uninit(PurpleCipherContext *context) {
-	struct _des_ctx *des_context;
-
-	des_context = purple_cipher_context_get_data(context);
-	memset(des_context, 0, sizeof(*des_context));
-
-	g_free(des_context);
-	des_context = NULL;
-}
-
-static PurpleCipherOps DESOps = {
-	NULL,              /* Set option */
-	NULL,              /* Get option */
-	des_init,          /* init */
- 	NULL,              /* reset */
- 	NULL,              /* reset state */
-	des_uninit,        /* uninit */
-	NULL,              /* set iv */
-	NULL,              /* append */
-	NULL,              /* digest */
-	NULL,              /* get_digest_size */
-	des_encrypt,       /* encrypt */
-	des_decrypt,       /* decrypt */
-	NULL,              /* set salt */
-	NULL,              /* get salt size */
-	des_set_key,       /* set key */
-	des_get_key_size,  /* get key size */
-	NULL,              /* set batch mode */
-	NULL,              /* get batch mode */
-	NULL,              /* get block size */
-	NULL, NULL, NULL, NULL /* reserved */
-};
-
-/******************************************************************************
- * Triple-DES
- *****************************************************************************/
-
-typedef struct _des3_ctx
-{
-	PurpleCipherBatchMode mode;
-	guchar iv[8];
-	/* First key for encryption */
-	struct _des_ctx key1;
-	/* Second key for decryption */
-	struct _des_ctx key2;
-	/* Third key for encryption */
-	struct _des_ctx key3;
-} des3_ctx[1];
-
-/*
- *  Fill a DES3 context with subkeys calculated from 3 64bit key.
- *  Does not check parity bits, but simply ignore them.
- *  Does not check for weak keys.
- **/
-static void
-des3_set_key(PurpleCipherContext *context, const guchar * key, size_t len)
-{
-	struct _des3_ctx *ctx = purple_cipher_context_get_data(context);
-	int i;
-
-	g_return_if_fail(len == 24);
-
-	des_key_schedule (key +  0, ctx->key1.encrypt_subkeys);
-	des_key_schedule (key +  8, ctx->key2.encrypt_subkeys);
-	des_key_schedule (key + 16, ctx->key3.encrypt_subkeys);
-
-	for (i = 0; i < 32; i += 2)
-	{
-		ctx->key1.decrypt_subkeys[i]    = ctx->key1.encrypt_subkeys[30-i];
-		ctx->key1.decrypt_subkeys[i+1]  = ctx->key1.encrypt_subkeys[31-i];
-		ctx->key2.decrypt_subkeys[i]    = ctx->key2.encrypt_subkeys[30-i];
-		ctx->key2.decrypt_subkeys[i+1]  = ctx->key2.encrypt_subkeys[31-i];
-		ctx->key3.decrypt_subkeys[i]    = ctx->key3.encrypt_subkeys[30-i];
-		ctx->key3.decrypt_subkeys[i+1]  = ctx->key3.encrypt_subkeys[31-i];
-	}
-}
-
-static size_t
-des3_get_key_size(PurpleCipherContext *context)
-{
-	return 24;
-}
-
-static ssize_t
-des3_ecb_encrypt(struct _des3_ctx *ctx, const guchar input[], size_t in_len,
-	guchar output[], size_t out_size)
-{
-	int offset = 0;
-	int i = 0;
-	int tmp;
-	guint8 buf[8] = {0,0,0,0,0,0,0,0};
-	ssize_t out_len;
-
-	g_return_val_if_fail(out_size >= in_len, -1);
-
-	while (offset + 8 <= in_len) {
-		des_ecb_crypt(&ctx->key1,
-		              input+offset,
-		              output+offset,
-		              0);
-		des_ecb_crypt(&ctx->key2,
-		              output+offset,
-		              buf,
-		              1);
-		des_ecb_crypt(&ctx->key3,
-		              buf,
-		              output+offset,
-		              0);
-		offset += 8;
-	}
-	out_len = in_len;
-	if (offset < in_len) {
-		out_len += in_len - offset;
-		g_return_val_if_fail(out_size >= out_len, -1);
-		tmp = offset;
-		memset(buf, 0, 8);
-		while (tmp < in_len) {
-			buf[i++] = input[tmp];
-			tmp++;
-		}
-		des_ecb_crypt(&ctx->key1,
-		              buf,
-		              output+offset,
-		              0);
-		des_ecb_crypt(&ctx->key2,
-		              output+offset,
-		              buf,
-		              1);
-		des_ecb_crypt(&ctx->key3,
-		              buf,
-		              output+offset,
-		              0);
-	}
-	return out_len;
-}
-
-static ssize_t
-des3_cbc_encrypt(struct _des3_ctx *ctx, const guchar input[], size_t in_len,
-	guchar output[], size_t out_size)
-{
-	int offset = 0;
-	int i = 0;
-	int tmp;
-	guint8 buf[8];
-	ssize_t out_len;
-	memcpy(buf, ctx->iv, 8);
-
-	g_return_val_if_fail(out_size >= in_len, -1);
-
-	while (offset + 8 <= in_len) {
-		for (i = 0; i < 8; i++)
-			buf[i] ^= input[offset + i];
-
-		des_ecb_crypt(&ctx->key1,
-		              buf,
-		              output+offset,
-		              0);
-		des_ecb_crypt(&ctx->key2,
-		              output+offset,
-		              buf,
-		              1);
-		des_ecb_crypt(&ctx->key3,
-		              buf,
-		              output+offset,
-		              0);
-		memcpy(buf, output+offset, 8);
-		offset += 8;
-	}
-	out_len = in_len;
-	if (offset < in_len) {
-		out_len += in_len - offset;
-		g_return_val_if_fail(out_size >= out_len, -1);
-		tmp = offset;
-		i = 0;
-		while (tmp < in_len) {
-			buf[i++] ^= input[tmp];
-			tmp++;
-		}
-		des_ecb_crypt(&ctx->key1,
-		              buf,
-		              output+offset,
-		              0);
-		des_ecb_crypt(&ctx->key2,
-		              output+offset,
-		              buf,
-		              1);
-		des_ecb_crypt(&ctx->key3,
-		              buf,
-		              output+offset,
-		              0);
-	}
-	return out_len;
-}
-
-static ssize_t
-des3_encrypt(PurpleCipherContext *context, const guchar input[], size_t in_len,
-	guchar output[], size_t out_size)
-{
-	struct _des3_ctx *ctx = purple_cipher_context_get_data(context);
-
-	if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_ECB) {
-		return des3_ecb_encrypt(ctx, input, in_len, output, out_size);
-	} else if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_CBC) {
-		return des3_cbc_encrypt(ctx, input, in_len, output, out_size);
-	} else {
-		g_return_val_if_reached(0);
-	}
-
-	return 0;
-}
-
-static ssize_t
-des3_ecb_decrypt(struct _des3_ctx *ctx, const guchar input[], size_t in_len,
-	guchar output[], size_t out_size)
-{
-	int offset = 0;
-	int i = 0;
-	int tmp;
-	guint8 buf[8] = {0,0,0,0,0,0,0,0};
-	ssize_t out_len;
-
-	g_return_val_if_fail(out_size >= in_len, -1);
-
-	while (offset + 8 <= in_len) {
-		/* NOTE: Apply key in reverse */
-		des_ecb_crypt(&ctx->key3,
-		              input+offset,
-		              output+offset,
-		              1);
-		des_ecb_crypt(&ctx->key2,
-		              output+offset,
-		              buf,
-		              0);
-		des_ecb_crypt(&ctx->key1,
-		              buf,
-		              output+offset,
-		              1);
-		offset+=8;
-	}
-	out_len = in_len;
-	if (offset < in_len) {
-		out_len += in_len - offset;
-		g_return_val_if_fail(out_size >= out_len, -1);
-		tmp = offset;
-		memset(buf, 0, 8);
-		while (tmp < in_len) {
-			buf[i++] = input[tmp];
-			tmp++;
-		}
-		des_ecb_crypt(&ctx->key3,
-		              buf,
-		              output+offset,
-		              1);
-		des_ecb_crypt(&ctx->key2,
-		              output+offset,
-		              buf,
-		              0);
-		des_ecb_crypt(&ctx->key1,
-		              buf,
-		              output+offset,
-		              1);
-	}
-	return out_len;
-}
-
-static ssize_t
-des3_cbc_decrypt(struct _des3_ctx *ctx, const guchar input[], size_t in_len,
-	guchar output[], size_t out_size)
-{
-	int offset = 0;
-	int i = 0;
-	int tmp;
-	guint8 buf[8] = {0,0,0,0,0,0,0,0};
-	guint8 link[8];
-	ssize_t out_len;
-
-	g_return_val_if_fail(out_size >= in_len, -1);
-
-	memcpy(link, ctx->iv, 8);
-	while (offset + 8 <= in_len) {
-		des_ecb_crypt(&ctx->key3,
-		              input+offset,
-		              output+offset,
-		              1);
-		des_ecb_crypt(&ctx->key2,
-		              output+offset,
-		              buf,
-		              0);
-		des_ecb_crypt(&ctx->key1,
-		              buf,
-		              output+offset,
-		              1);
-		for (i = 0; i < 8; i++)
-			output[offset + i] ^= link[i];
-		memcpy(link, input + offset, 8);
-		offset+=8;
-	}
-	out_len = in_len;
-	if(offset<in_len) {
-		out_len += in_len - offset;
-		g_return_val_if_fail(out_size >= out_len, -1);
-		tmp = offset;
-		memset(buf, 0, 8);
-		i = 0;
-		while(tmp<in_len) {
-			buf[i++] = input[tmp];
-			tmp++;
-		}
-		des_ecb_crypt(&ctx->key3,
-		              buf,
-		              output+offset,
-		              1);
-		des_ecb_crypt(&ctx->key2,
-		              output+offset,
-		              buf,
-		              0);
-		des_ecb_crypt(&ctx->key1,
-		              buf,
-		              output+offset,
-		              1);
-		for (i = 0; i < 8; i++)
-			output[offset + i] ^= link[i];
-	}
-	return out_len;
-}
-
-static ssize_t
-des3_decrypt(PurpleCipherContext *context, const guchar input[], size_t in_len,
-	guchar output[], size_t out_size)
-{
-	struct _des3_ctx *ctx = purple_cipher_context_get_data(context);
-
-	if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_ECB) {
-		return des3_ecb_decrypt(ctx, input, in_len, output, out_size);
-	} else if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_CBC) {
-		return des3_cbc_decrypt(ctx, input, in_len, output, out_size);
-	} else {
-		g_return_val_if_reached(0);
-	}
-
-	return 0;
-}
-
-static void
-des3_set_batch(PurpleCipherContext *context, PurpleCipherBatchMode mode)
-{
-	struct _des3_ctx *ctx = purple_cipher_context_get_data(context);
-
-	ctx->mode = mode;
-}
-
-static PurpleCipherBatchMode
-des3_get_batch(PurpleCipherContext *context)
-{
-	struct _des3_ctx *ctx = purple_cipher_context_get_data(context);
-
-	return ctx->mode;
-}
-
-static void
-des3_set_iv(PurpleCipherContext *context, guchar *iv, size_t len)
-{
-	struct _des3_ctx *ctx;
-
-	g_return_if_fail(len == 8);
-
-	ctx = purple_cipher_context_get_data(context);
-
-	memcpy(ctx->iv, iv, len);
-}
-
-static void
-des3_init(PurpleCipherContext *context, gpointer extra)
-{
-	struct _des3_ctx *mctx;
-	mctx = g_new0(struct _des3_ctx, 1);
-	purple_cipher_context_set_data(context, mctx);
-}
-
-static void
-des3_uninit(PurpleCipherContext *context)
-{
-	struct _des3_ctx *des3_context;
-
-	des3_context = purple_cipher_context_get_data(context);
-	memset(des3_context, 0, sizeof(*des3_context));
-
-	g_free(des3_context);
-	des3_context = NULL;
-}
-
-static PurpleCipherOps DES3Ops = {
-	NULL,              /* Set option */
-	NULL,              /* Get option */
-	des3_init,         /* init */
-	NULL,              /* reset */
-	NULL,              /* reset state */
-	des3_uninit,       /* uninit */
-	des3_set_iv,       /* set iv */
-	NULL,              /* append */
-	NULL,              /* digest */
-	NULL,              /* get_digest_size */
-	des3_encrypt,      /* encrypt */
-	des3_decrypt,      /* decrypt */
-	NULL,              /* set salt */
-	NULL,              /* get salt size */
-	des3_set_key,      /* set key */
-	des3_get_key_size, /* get_key_size */
-	des3_set_batch,    /* set batch mode */
-	des3_get_batch,    /* get batch mode */
-	NULL,              /* get block size */
-	NULL, NULL, NULL, NULL /* reserved */
-};
-
-/******************************************************************************
- * Registration
- *****************************************************************************/
-PurpleCipherOps *
-purple_des_cipher_get_ops(void) {
-	return &DESOps;
-}
-
-PurpleCipherOps *
-purple_des3_cipher_get_ops(void) {
-	return &DES3Ops;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/des3cipher.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,523 @@
+/*
+ * Original des taken from gpg
+ *
+ * des.c - Triple-DES encryption/decryption Algorithm
+ *  Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ *  Please see below for more legal information!
+ *  
+ *   According to the definition of DES in FIPS PUB 46-2 from December 1993.
+ *   For a description of triple encryption, see:
+ *     Bruce Schneier: Applied Cryptography. Second Edition.
+ *     John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
+ *  
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "des3cipher.h"
+#include "descipher.h"
+
+#include <string.h>
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+
+#define PURPLE_DES3_CIPHER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_DES3_CIPHER, PurpleDES3CipherPrivate))
+
+typedef struct _PurpleDES3CipherPrivate		PurpleDES3CipherPrivate;
+struct _PurpleDES3CipherPrivate
+{
+	PurpleCipherBatchMode mode;
+	guchar iv[8];
+	/* First key for encryption */
+	PurpleCipher *key1;
+	/* Second key for decryption */
+	PurpleCipher *key2;
+	/* Third key for encryption */
+	PurpleCipher *key3;
+};
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+	PROP_NONE,
+	PROP_BATCH_MODE,
+	PROP_IV,
+	PROP_KEY,
+	PROP_LAST,
+};
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Cipher Stuff
+ *****************************************************************************/
+
+static size_t
+purple_des3_cipher_get_key_size(PurpleCipher *cipher)
+{
+	return 24;
+}
+
+/*
+ *  Fill a DES3 context with subkeys calculated from 3 64bit key.
+ *  Does not check parity bits, but simply ignore them.
+ *  Does not check for weak keys.
+ **/
+static void
+purple_des3_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len)
+{
+	PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	g_return_if_fail(len == 24);
+
+	purple_cipher_set_key(PURPLE_CIPHER(priv->key1), key +  0,
+					purple_cipher_get_key_size(PURPLE_CIPHER(priv->key1)));
+	purple_cipher_set_key(PURPLE_CIPHER(priv->key2), key +  8,
+					purple_cipher_get_key_size(PURPLE_CIPHER(priv->key2)));
+	purple_cipher_set_key(PURPLE_CIPHER(priv->key3), key + 16,
+					purple_cipher_get_key_size(PURPLE_CIPHER(priv->key3)));
+
+	g_object_notify(G_OBJECT(des3_cipher), "key");
+}
+
+static ssize_t
+purple_des3_cipher_ecb_encrypt(PurpleDES3Cipher *des3_cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
+{
+	int offset = 0;
+	int i = 0;
+	int tmp;
+	guint8 buf[8] = {0,0,0,0,0,0,0,0};
+	ssize_t out_len;
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	g_return_val_if_fail(out_size >= in_len, -1);
+
+	while (offset + 8 <= in_len) {
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
+									input + offset, output + offset, 0);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
+									output + offset, buf, 1);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
+									buf, output + offset, 0);
+
+		offset += 8;
+	}
+
+	out_len = in_len;
+	if (offset < in_len) {
+		out_len += in_len - offset;
+		g_return_val_if_fail(out_size >= out_len, -1);
+		tmp = offset;
+		memset(buf, 0, 8);
+		while (tmp < in_len) {
+			buf[i++] = input[tmp];
+			tmp++;
+		}
+
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
+									buf, output + offset, 0);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
+									output + offset, buf, 1);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
+									buf, output + offset, 0);
+	}
+
+	return out_len;
+}
+
+static ssize_t
+purple_des3_cipher_cbc_encrypt(PurpleDES3Cipher *des3_cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
+{
+	int offset = 0;
+	int i = 0;
+	int tmp;
+	guint8 buf[8];
+	ssize_t out_len;
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+	memcpy(buf, priv->iv, 8);
+
+	g_return_val_if_fail(out_size >= in_len, -1);
+
+	while (offset + 8 <= in_len) {
+		for (i = 0; i < 8; i++)
+			buf[i] ^= input[offset + i];
+
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
+									buf, output + offset, 0);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
+									output + offset, buf, 1);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
+									buf, output + offset, 0);
+
+		memcpy(buf, output+offset, 8);
+		offset += 8;
+	}
+
+	out_len = in_len;
+	if (offset < in_len) {
+		out_len += in_len - offset;
+		g_return_val_if_fail(out_size >= out_len, -1);
+		tmp = offset;
+		i = 0;
+		while (tmp < in_len) {
+			buf[i++] ^= input[tmp];
+			tmp++;
+		}
+
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
+									buf, output + offset, 0);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
+									output + offset, buf, 1);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
+									buf, output + offset, 0);
+	}
+
+	return out_len;
+}
+
+static ssize_t
+purple_des3_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
+{
+	PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	if (priv->mode == PURPLE_CIPHER_BATCH_MODE_ECB) {
+		return purple_des3_cipher_ecb_encrypt(des3_cipher, input, in_len, output, out_size);
+	} else if (priv->mode == PURPLE_CIPHER_BATCH_MODE_CBC) {
+		return purple_des3_cipher_cbc_encrypt(des3_cipher, input, in_len, output, out_size);
+	} else {
+		g_return_val_if_reached(0);
+	}
+
+	return 0;
+}
+
+static ssize_t
+purple_des3_cipher_ecb_decrypt(PurpleDES3Cipher *des3_cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
+{
+	int offset = 0;
+	int i = 0;
+	int tmp;
+	guint8 buf[8] = {0,0,0,0,0,0,0,0};
+	ssize_t out_len;
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	g_return_val_if_fail(out_size >= in_len, -1);
+
+	while (offset + 8 <= in_len) {
+		/* NOTE: Apply key in reverse */
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
+									input + offset, output + offset, 1);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
+									output + offset, buf, 0);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
+									buf, output + offset, 1);
+
+		offset += 8;
+	}
+
+	out_len = in_len;
+	if (offset < in_len) {
+		out_len += in_len - offset;
+		g_return_val_if_fail(out_size >= out_len, -1);
+		tmp = offset;
+		memset(buf, 0, 8);
+		while (tmp < in_len) {
+			buf[i++] = input[tmp];
+			tmp++;
+		}
+
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
+									buf, output + offset, 1);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
+									output + offset, buf, 0);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
+									buf, output + offset, 1);
+	}
+
+	return out_len;
+}
+
+static ssize_t
+purple_des3_cipher_cbc_decrypt(PurpleDES3Cipher *des3_cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
+{
+	int offset = 0;
+	int i = 0;
+	int tmp;
+	guint8 buf[8] = {0,0,0,0,0,0,0,0};
+	guint8 link[8];
+	ssize_t out_len;
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	g_return_val_if_fail(out_size >= in_len, -1);
+
+	memcpy(link, priv->iv, 8);
+	while (offset + 8 <= in_len) {
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
+									input + offset, output + offset, 1);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
+									output + offset, buf, 0);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
+									buf, output + offset, 1);
+
+		for (i = 0; i < 8; i++)
+			output[offset + i] ^= link[i];
+
+		memcpy(link, input + offset, 8);
+
+		offset+=8;
+	}
+
+	out_len = in_len;
+	if(offset<in_len) {
+		out_len += in_len - offset;
+		g_return_val_if_fail(out_size >= out_len, -1);
+		tmp = offset;
+		memset(buf, 0, 8);
+		i = 0;
+		while(tmp<in_len) {
+			buf[i++] = input[tmp];
+			tmp++;
+		}
+
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
+									buf, output + offset, 1);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
+									output + offset, buf, 0);
+		purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
+									buf, output + offset, 1);
+
+		for (i = 0; i < 8; i++)
+			output[offset + i] ^= link[i];
+	}
+
+	return out_len;
+}
+
+static ssize_t
+purple_des3_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
+{
+	PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(cipher);
+
+	if (priv->mode == PURPLE_CIPHER_BATCH_MODE_ECB) {
+		return purple_des3_cipher_ecb_decrypt(des3_cipher, input, in_len, output, out_size);
+	} else if (priv->mode == PURPLE_CIPHER_BATCH_MODE_CBC) {
+		return purple_des3_cipher_cbc_decrypt(des3_cipher, input, in_len, output, out_size);
+	} else {
+		g_return_val_if_reached(0);
+	}
+
+	return 0;
+}
+
+static void
+purple_des3_cipher_set_batch_mode(PurpleCipher *cipher, PurpleCipherBatchMode mode)
+{
+	PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	priv->mode = mode;
+
+	g_object_notify(G_OBJECT(des3_cipher), "batch_mode");
+}
+
+static PurpleCipherBatchMode
+purple_des3_cipher_get_batch_mode(PurpleCipher *cipher)
+{
+	PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	return priv->mode;
+}
+
+static void
+purple_des3_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len)
+{
+	PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	g_return_if_fail(len == 8);
+
+	memcpy(priv->iv, iv, len);
+
+	g_object_notify(G_OBJECT(des3_cipher), "iv");
+}
+
+static const gchar*
+purple_des3_cipher_get_name(PurpleCipher *cipher)
+{
+	return "des3";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_des3_cipher_get_property(GObject *obj, guint param_id, GValue *value,
+								GParamSpec *pspec)
+{
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+
+	switch(param_id) {
+		case PROP_BATCH_MODE:
+			g_value_set_enum(value,
+							 purple_cipher_get_batch_mode(cipher));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_des3_cipher_set_property(GObject *obj, guint param_id,
+								const GValue *value, GParamSpec *pspec)
+{
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+
+	switch(param_id) {
+		case PROP_BATCH_MODE:
+			purple_cipher_set_batch_mode(cipher,
+										 g_value_get_enum(value));
+			break;
+		case PROP_IV:
+			{
+				guchar *iv = (guchar *)g_value_get_string(value);
+				purple_cipher_set_iv(cipher, iv, strlen((gchar*)iv));
+			}
+			break;
+		case PROP_KEY:
+			purple_cipher_set_key(cipher, (guchar *)g_value_get_string(value),
+				purple_des3_cipher_get_key_size(cipher));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_des3_cipher_finalize(GObject *obj)
+{
+	PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(obj);
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	g_object_unref(G_OBJECT(priv->key1));
+	g_object_unref(G_OBJECT(priv->key2));
+	g_object_unref(G_OBJECT(priv->key3));
+
+	memset(priv->iv, 0, sizeof(priv->iv));
+
+	parent_class->finalize(obj);
+}
+
+static void
+purple_des3_cipher_class_init(PurpleDES3CipherClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
+	GParamSpec *pspec;
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	obj_class->finalize = purple_des3_cipher_finalize;
+	obj_class->get_property = purple_des3_cipher_get_property;
+	obj_class->set_property = purple_des3_cipher_set_property;
+
+	cipher_class->set_iv = purple_des3_cipher_set_iv;
+	cipher_class->encrypt = purple_des3_cipher_encrypt;
+	cipher_class->decrypt = purple_des3_cipher_decrypt;
+	cipher_class->set_key = purple_des3_cipher_set_key;
+	cipher_class->set_batch_mode = purple_des3_cipher_set_batch_mode;
+	cipher_class->get_batch_mode = purple_des3_cipher_get_batch_mode;
+	cipher_class->get_key_size = purple_des3_cipher_get_key_size;
+	cipher_class->get_name = purple_des3_cipher_get_name;
+
+	pspec = g_param_spec_enum("batch_mode", "batch_mode", "batch_mode",
+							  PURPLE_TYPE_CIPHER_BATCH_MODE, 0,
+							  G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_BATCH_MODE, pspec);
+
+	pspec = g_param_spec_string("iv", "iv", "iv", NULL,
+								G_PARAM_WRITABLE);
+	g_object_class_install_property(obj_class, PROP_IV, pspec);
+
+	pspec = g_param_spec_string("key", "key", "key", NULL,
+								G_PARAM_WRITABLE);
+	g_object_class_install_property(obj_class, PROP_KEY, pspec);
+
+	g_type_class_add_private(klass, sizeof(PurpleDES3CipherPrivate));
+}
+
+static void
+purple_des3_cipher_init(PurpleCipher *cipher) {
+	PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
+	PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
+
+	priv->key1 = purple_des_cipher_new();
+	priv->key2 = purple_des_cipher_new();
+	priv->key3 = purple_des_cipher_new();
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_des3_cipher_get_gtype(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleDES3CipherClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_des3_cipher_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleDES3Cipher),
+			0,
+			(GInstanceInitFunc)purple_des3_cipher_init,
+			NULL
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_CIPHER,
+									  "PurpleDES3Cipher",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+PurpleCipher *
+purple_des3_cipher_new(void) {
+	return g_object_new(PURPLE_TYPE_DES3_CIPHER, NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/des3cipher.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,68 @@
+/**
+ * @file des3.h Purple Triple-DES Cipher
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_DES3_CIPHER_H
+#define PURPLE_DES3_CIPHER_H
+
+#include "cipher.h"
+
+#define PURPLE_TYPE_DES3_CIPHER				(purple_des3_cipher_get_gtype())
+#define PURPLE_DES3_CIPHER(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_DES3_CIPHER, PurpleDES3Cipher))
+#define PURPLE_DES3_CIPHER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_DES3_CIPHER, PurpleDES3CipherClass))
+#define PURPLE_IS_DES3_CIPHER(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_DES3_CIPHER))
+#define PURPLE_IS_DES3_CIPHER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_DES3_CIPHER))
+#define PURPLE_DES3_CIPHER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_DES3_CIPHER, PurpleDES3CipherClass))
+
+typedef struct _PurpleDES3Cipher			PurpleDES3Cipher;
+typedef struct _PurpleDES3CipherClass		PurpleDES3CipherClass;
+
+struct _PurpleDES3Cipher {
+	PurpleCipher gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurpleDES3CipherClass {
+	PurpleCipherClass gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_des3_cipher_get_gtype(void);
+
+PurpleCipher *purple_des3_cipher_new(void);
+
+G_END_DECLS
+
+#endif /* PURPLE_DES3_CIPHER_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/descipher.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,576 @@
+/*
+ * Original des taken from gpg
+ *
+ * des.c - DES encryption/decryption Algorithm
+ *  Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ *  Please see below for more legal information!
+ *  
+ *   According to the definition of DES in FIPS PUB 46-2 from December 1993.
+ *   For a description of triple encryption, see:
+ *     Bruce Schneier: Applied Cryptography. Second Edition.
+ *     John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
+ *  
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "descipher.h"
+
+#include <string.h>
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+#define PURPLE_DES_CIPHER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_DES_CIPHER, PurpleDESCipherPrivate))
+
+typedef struct {
+	guint32 encrypt_subkeys[32];
+	guint32 decrypt_subkeys[32];
+} PurpleDESCipherPrivate;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+	PROP_NONE,
+	PROP_KEY,
+	PROP_LAST,
+};
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/*  
+ *  The s-box values are permuted according to the 'primitive function P'
+ */
+static guint32 sbox1[64] = {
+	0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202,
+	0x00000002, 0x00008000, 0x00000200, 0x00808200, 0x00808202, 0x00000200,
+	0x00800202, 0x00808002, 0x00800000, 0x00000002, 0x00000202, 0x00800200,
+	0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202,
+	0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202,
+	0x00008202, 0x00800000, 0x00008000, 0x00808202, 0x00000002, 0x00808000,
+	0x00808200, 0x00800000, 0x00800000, 0x00000200, 0x00808002, 0x00008000,
+	0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202,
+	0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202,
+	0x00008202, 0x00808200, 0x00000202, 0x00800200, 0x00800200, 0x00000000,
+	0x00008002, 0x00008200, 0x00000000, 0x00808002
+};
+
+static guint32 sbox2[64] = {
+	0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010,
+	0x40080010, 0x40004010, 0x40000010, 0x40084010, 0x40084000, 0x40000000,
+	0x40004000, 0x00080000, 0x00000010, 0x40080010, 0x00084000, 0x00080010,
+	0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000,
+	0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000,
+	0x40080000, 0x00004010, 0x00000000, 0x00084010, 0x40080010, 0x00080000,
+	0x40004010, 0x40080000, 0x40084000, 0x00004000, 0x40080000, 0x40004000,
+	0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000,
+	0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010,
+	0x40000010, 0x00080010, 0x00084000, 0x00000000, 0x40004000, 0x00004010,
+	0x40000000, 0x40080010, 0x40084010, 0x00084000
+};
+
+static guint32 sbox3[64] = {
+	0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000,
+	0x00010104, 0x04000100, 0x00010004, 0x04000004, 0x04000004, 0x00010000,
+	0x04010104, 0x00010004, 0x04010000, 0x00000104, 0x04000000, 0x00000004,
+	0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104,
+	0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104,
+	0x00000100, 0x04000000, 0x04010100, 0x04000000, 0x00010004, 0x00000104,
+	0x00010000, 0x04010100, 0x04000100, 0x00000000, 0x00000100, 0x00010004,
+	0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004,
+	0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104,
+	0x00010100, 0x04000004, 0x04010000, 0x04000104, 0x00000104, 0x04010000,
+	0x00010104, 0x00000004, 0x04010004, 0x00010100
+};
+
+static guint32 sbox4[64] = {
+	0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040,
+	0x80400000, 0x80001000, 0x00000000, 0x00401000, 0x00401000, 0x80401040,
+	0x80000040, 0x00000000, 0x00400040, 0x80400000, 0x80000000, 0x00001000,
+	0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040,
+	0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040,
+	0x80401040, 0x80000040, 0x00400040, 0x80400000, 0x00401000, 0x80401040,
+	0x80000040, 0x00000000, 0x00000000, 0x00401000, 0x00001040, 0x00400040,
+	0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040,
+	0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000,
+	0x00401040, 0x80400040, 0x80001000, 0x00001040, 0x00400000, 0x80401000,
+	0x00000040, 0x00400000, 0x00001000, 0x00401040
+};
+
+static guint32 sbox5[64] = {
+	0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080,
+	0x20000000, 0x01040000, 0x20040080, 0x00040000, 0x01000080, 0x20040080,
+	0x21000080, 0x21040000, 0x00040080, 0x20000000, 0x01000000, 0x20040000,
+	0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080,
+	0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000,
+	0x21000000, 0x00040080, 0x00040000, 0x21000080, 0x00000080, 0x01000000,
+	0x20000000, 0x01040000, 0x21000080, 0x20040080, 0x01000080, 0x20000000,
+	0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000,
+	0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000,
+	0x20040000, 0x21000000, 0x00040080, 0x01000080, 0x20000080, 0x00040000,
+	0x00000000, 0x20040000, 0x01040080, 0x20000080
+};
+
+static guint32 sbox6[64] = {
+	0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008,
+	0x10202008, 0x00200000, 0x10002000, 0x00202008, 0x00200000, 0x10000008,
+	0x00200008, 0x10002000, 0x10000000, 0x00002008, 0x00000000, 0x00200008,
+	0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008,
+	0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000,
+	0x10202000, 0x10000000, 0x10002000, 0x00000008, 0x10200008, 0x00202000,
+	0x10202008, 0x00200000, 0x00002008, 0x10000008, 0x00200000, 0x10002000,
+	0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000,
+	0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000,
+	0x10200000, 0x00202008, 0x00002000, 0x00200008, 0x10002008, 0x00000000,
+	0x10202000, 0x10000000, 0x00200008, 0x10002008
+};
+
+static guint32 sbox7[64] = {
+	0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401,
+	0x00100401, 0x02100400, 0x02100401, 0x00100000, 0x00000000, 0x02000001,
+	0x00000001, 0x02000000, 0x02100001, 0x00000401, 0x02000400, 0x00100401,
+	0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001,
+	0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001,
+	0x02000000, 0x00100400, 0x02000000, 0x00100400, 0x00100000, 0x02000401,
+	0x02000401, 0x02100001, 0x02100001, 0x00000001, 0x00100001, 0x02000000,
+	0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400,
+	0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000,
+	0x00000001, 0x02100401, 0x00000000, 0x00100401, 0x02100000, 0x00000400,
+	0x02000001, 0x02000400, 0x00000400, 0x00100001
+};
+
+static guint32 sbox8[64] = {
+	0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820,
+	0x00000020, 0x08000000, 0x00020020, 0x08020000, 0x08020820, 0x00020800,
+	0x08020800, 0x00020820, 0x00000800, 0x00000020, 0x08020000, 0x08000020,
+	0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800,
+	0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800,
+	0x00020820, 0x00020000, 0x00020820, 0x00020000, 0x08020800, 0x00000800,
+	0x00000020, 0x08020020, 0x00000800, 0x00020820, 0x08000800, 0x00000020,
+	0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820,
+	0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800,
+	0x08000820, 0x00000000, 0x08020820, 0x00020800, 0x00020800, 0x00000820,
+	0x00000820, 0x00020020, 0x08000000, 0x08020800
+};
+
+/*
+ * These two tables are part of the 'permuted choice 1' function.
+ * In this implementation several speed improvements are done.
+ */
+static guint32 leftkey_swap[16] = {
+	0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00010000, 0x00010001,
+	0x00010100, 0x00010101, 0x01000000, 0x01000001, 0x01000100, 0x01000101,
+	0x01010000, 0x01010001, 0x01010100, 0x01010101
+};
+
+static guint32 rightkey_swap[16] = {
+	0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100,
+	0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001,
+	0x00000101, 0x01000101, 0x00010101, 0x01010101,
+};
+
+/*
+ *  Numbers of left shifts per round for encryption subkey schedule
+ *  To calculate the decryption key scheduling we just reverse the
+ *  ordering of the subkeys so we can omit the table for decryption
+ *  subkey schedule.
+ */
+static guint8 encrypt_rotate_tab[16] = {
+	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+/*
+ * Macro to swap bits across two words
+ */
+#define DO_PERMUTATION(a, temp, b, offset, mask)	\
+	temp = ((a>>offset) ^ b) & mask;				\
+	b ^= temp;										\
+	a ^= temp<<offset;
+
+/*
+ * This performs the 'initial permutation' for the data to be encrypted or
+ * decrypted
+ */
+#define INITIAL_PERMUTATION(left, temp, right)			\
+	DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)	\
+	DO_PERMUTATION(left, temp, right, 16, 0x0000ffff)	\
+	DO_PERMUTATION(right, temp, left, 2, 0x33333333)	\
+	DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff)	\
+	DO_PERMUTATION(left, temp, right, 1, 0x55555555)
+
+/*
+ * The 'inverse initial permutation'
+ */
+#define FINAL_PERMUTATION(left, temp, right)			\
+    DO_PERMUTATION(left, temp, right, 1, 0x55555555)	\
+	DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff)	\
+	DO_PERMUTATION(right, temp, left, 2, 0x33333333)	\
+	DO_PERMUTATION(left, temp, right, 16, 0x0000ffff)	\
+	DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)
+
+/*
+ * A full DES round including 'expansion function', 'sbox substitution'
+ * and 'primitive function P' but without swapping the left and right word.
+ */
+#define DES_ROUND(from, to, work, subkey)			\
+	work = ((from<<1) | (from>>31)) ^ *subkey++;	\
+	to ^= sbox8[  work      & 0x3f ];				\
+	to ^= sbox6[ (work>>8)  & 0x3f ];				\
+	to ^= sbox4[ (work>>16) & 0x3f ];				\
+	to ^= sbox2[ (work>>24) & 0x3f ];				\
+	work = ((from>>3) | (from<<29)) ^ *subkey++;	\
+	to ^= sbox7[  work      & 0x3f ];				\
+	to ^= sbox5[ (work>>8)  & 0x3f ];				\
+	to ^= sbox3[ (work>>16) & 0x3f ];				\
+	to ^= sbox1[ (work>>24) & 0x3f ];
+
+
+/*
+ * Macros to convert 8 bytes from/to 32bit words
+ */
+#define READ_64BIT_DATA(data, left, right)									\
+	left  = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];	\
+	right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
+
+#define WRITE_64BIT_DATA(data, left, right)							\
+	data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff;		\
+	data[2] = (left >> 8) &0xff; data[3] = left &0xff;				\
+	data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff;	\
+	data[6] = (right >> 8) &0xff; data[7] = right &0xff;
+
+/******************************************************************************
+ * Cipher Stuff
+ *****************************************************************************/
+/*
+ * des_key_schedule():    Calculate 16 subkeys pairs (even/odd) for
+ *            16 encryption rounds.
+ *            To calculate subkeys for decryption the caller
+ *                have to reorder the generated subkeys.
+ *     
+ *        rawkey:       8 Bytes of key data
+ *        subkey:       Array of at least 32 guint32s. Will be filled
+ *              with calculated subkeys.
+ *     
+ */
+static void
+purple_des_cipher_key_schedule(const guint8 * rawkey, guint32 * subkey) {
+	guint32 left, right, work;
+	int round;
+
+	READ_64BIT_DATA (rawkey, left, right)
+
+	DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f)
+	DO_PERMUTATION (right, work, left, 0, 0x10101010)
+
+	left = (leftkey_swap[(left >>  0) & 0xf] << 3)
+		 | (leftkey_swap[(left >>  8) & 0xf] << 2)
+		 | (leftkey_swap[(left >> 16) & 0xf] << 1)
+		 | (leftkey_swap[(left >> 24) & 0xf]     )
+		 | (leftkey_swap[(left >>  5) & 0xf] << 7)
+		 | (leftkey_swap[(left >> 13) & 0xf] << 6)
+		 | (leftkey_swap[(left >> 21) & 0xf] << 5)
+		 | (leftkey_swap[(left >> 29) & 0xf] << 4);
+
+	left &= 0x0fffffff;
+
+	right = (rightkey_swap[(right >>  1) & 0xf] << 3)
+		  | (rightkey_swap[(right >>  9) & 0xf] << 2)
+		  | (rightkey_swap[(right >> 17) & 0xf] << 1)
+		  | (rightkey_swap[(right >> 25) & 0xf]     )
+		  | (rightkey_swap[(right >>  4) & 0xf] << 7)
+		  | (rightkey_swap[(right >> 12) & 0xf] << 6)
+		  | (rightkey_swap[(right >> 20) & 0xf] << 5)
+		  | (rightkey_swap[(right >> 28) & 0xf] << 4);
+
+	right &= 0x0fffffff;
+
+	for (round = 0; round < 16; ++round) {
+		left = ((left << encrypt_rotate_tab[round]) |
+			    (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
+		right = ((right << encrypt_rotate_tab[round]) |
+				 (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
+
+		*subkey++ = ((left  <<  4) & 0x24000000)
+				  | ((left  << 28) & 0x10000000)
+				  | ((left  << 14) & 0x08000000)
+				  | ((left  << 18) & 0x02080000)
+				  | ((left  <<  6) & 0x01000000)
+				  | ((left  <<  9) & 0x00200000)
+				  | ((left  >>  1) & 0x00100000)
+				  | ((left  << 10) & 0x00040000)
+				  | ((left  <<  2) & 0x00020000)
+				  | ((left  >> 10) & 0x00010000)
+				  | ((right >> 13) & 0x00002000)
+				  | ((right >>  4) & 0x00001000)
+				  | ((right <<  6) & 0x00000800)
+				  | ((right >>  1) & 0x00000400)
+				  | ((right >> 14) & 0x00000200)
+				  | (right         & 0x00000100)
+				  | ((right >>  5) & 0x00000020)
+				  | ((right >> 10) & 0x00000010)
+				  | ((right >>  3) & 0x00000008)
+				  | ((right >> 18) & 0x00000004)
+				  | ((right >> 26) & 0x00000002)
+				  | ((right >> 24) & 0x00000001);
+
+		*subkey++ = ((left  << 15) & 0x20000000)
+				  | ((left  << 17) & 0x10000000)
+				  | ((left  << 10) & 0x08000000)
+				  | ((left  << 22) & 0x04000000)
+				  | ((left  >>  2) & 0x02000000)
+				  | ((left  <<  1) & 0x01000000)
+				  | ((left  << 16) & 0x00200000)
+				  | ((left  << 11) & 0x00100000)
+				  | ((left  <<  3) & 0x00080000)
+				  | ((left  >>  6) & 0x00040000)
+				  | ((left  << 15) & 0x00020000)
+				  | ((left  >>  4) & 0x00010000)
+				  | ((right >>  2) & 0x00002000)
+				  | ((right <<  8) & 0x00001000)
+				  | ((right >> 14) & 0x00000808)
+				  | ((right >>  9) & 0x00000400)
+				  | ((right)       & 0x00000200)
+				  | ((right <<  7) & 0x00000100)
+				  | ((right >>  7) & 0x00000020)
+				  | ((right >>  3) & 0x00000011)
+				  | ((right <<  2) & 0x00000004)
+				  | ((right >> 21) & 0x00000002);
+	}
+}
+
+/*
+ * Fill a DES context with subkeys calculated from a 64bit key.
+ * Does not check parity bits, but simply ignore them.
+ * Does not check for weak keys.
+ */
+static void
+purple_des_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len) {
+	PurpleDESCipher *des_cipher = PURPLE_DES_CIPHER(cipher);
+	PurpleDESCipherPrivate *priv = PURPLE_DES_CIPHER_GET_PRIVATE(des_cipher);
+	int i;
+
+	g_return_if_fail(len == 8);
+
+	purple_des_cipher_key_schedule(key, priv->encrypt_subkeys);
+
+	for(i = 0; i < 32; i += 2) {
+		priv->decrypt_subkeys[i] = priv->encrypt_subkeys[30 - i];
+		priv->decrypt_subkeys[i + 1] = priv->encrypt_subkeys[31 - i];
+	}
+
+	g_object_notify(G_OBJECT(cipher), "key");
+}
+
+static size_t
+purple_des_cipher_get_key_size(PurpleCipher *cipher)
+{
+	return 8;
+}
+
+/*
+ * Electronic Codebook Mode DES encryption/decryption of data according to
+ * 'mode'.
+ */
+int
+purple_des_cipher_ecb_crypt(PurpleDESCipher *des_cipher, const guint8 * from, guint8 * to,
+			  int mode)
+{
+	guint32 left, right, work;
+	guint32 *keys;
+	PurpleDESCipherPrivate *priv = PURPLE_DES_CIPHER_GET_PRIVATE(des_cipher);
+
+	keys = mode ? priv->decrypt_subkeys :
+				  priv->encrypt_subkeys;
+
+	READ_64BIT_DATA (from, left, right)
+	INITIAL_PERMUTATION (left, work, right)
+
+	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
+	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
+	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
+	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
+	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
+	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
+	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
+	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
+
+	FINAL_PERMUTATION (right, work, left)
+	WRITE_64BIT_DATA (to, right, left)
+
+	return 0;
+}
+
+static ssize_t
+purple_des_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
+{
+	PurpleDESCipher *des_cipher = PURPLE_DES_CIPHER(cipher);
+	gint offset = 0, i = 0, tmp;
+	guint8 buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+	ssize_t out_len;
+
+	g_return_val_if_fail(out_size >= in_len, -1);
+
+	while(offset + 8 <= in_len) {
+		purple_des_cipher_ecb_crypt(des_cipher, input + offset, output + offset, 0);
+		offset += 8;
+	}
+
+	out_len = in_len;
+
+	if(offset<in_len) {
+		out_len += in_len - offset;
+		g_return_val_if_fail(out_size >= out_len, -1);
+		tmp = offset;
+		while(tmp<in_len) {
+			buf[i++] = input[tmp];
+			tmp++;
+		}
+
+		purple_des_cipher_ecb_crypt(des_cipher, buf, output + offset, 0);
+	}
+
+	return out_len;
+}
+
+static ssize_t
+purple_des_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
+							size_t in_len, guchar output[], size_t out_size)
+{
+	PurpleDESCipher *des_cipher = PURPLE_DES_CIPHER(cipher);
+	int offset = 0, i = 0, tmp;
+	guint8 buf[8] = {0,0,0,0,0,0,0,0};
+	ssize_t out_len;
+
+	g_return_val_if_fail(out_size >= in_len, -1);
+
+	while(offset + 8 <= in_len) {
+		purple_des_cipher_ecb_crypt(des_cipher, input + offset, output + offset, 1);
+		offset += 8;
+	}
+
+	out_len = in_len;
+	if(offset<in_len) {
+		out_len += in_len - offset;
+		g_return_val_if_fail(out_size >= out_len, -1);
+		tmp = offset;
+		while(tmp<in_len) {
+			buf[i++] = input[tmp];
+			tmp++;
+		}
+
+		purple_des_cipher_ecb_crypt(des_cipher, buf, output + offset, 1);
+	}
+
+	return out_len;
+}
+
+static const gchar*
+purple_des_cipher_get_name(PurpleCipher *cipher)
+{
+	return "des";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_des_cipher_set_property(GObject *obj, guint param_id,
+							   const GValue *value, GParamSpec *pspec)
+{
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+
+	switch(param_id) {
+		case PROP_KEY:
+			purple_cipher_set_key(cipher, (guchar *)g_value_get_string(value),
+										purple_des_cipher_get_key_size(cipher));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_des_cipher_class_init(PurpleDESCipherClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
+	GParamSpec *pspec;
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	obj_class->set_property = purple_des_cipher_set_property;
+
+	cipher_class->encrypt = purple_des_cipher_encrypt;
+	cipher_class->decrypt = purple_des_cipher_decrypt;
+	cipher_class->set_key = purple_des_cipher_set_key;
+	cipher_class->get_key_size = purple_des_cipher_get_key_size;
+	cipher_class->get_name = purple_des_cipher_get_name;
+
+	pspec = g_param_spec_string("key", "key", "key", NULL,
+								G_PARAM_WRITABLE);
+	g_object_class_install_property(obj_class, PROP_KEY, pspec);
+
+	g_type_class_add_private(klass, sizeof(PurpleDESCipherPrivate));
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_des_cipher_get_type(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			.class_size = sizeof(PurpleDESCipherClass),
+			.class_init = (GClassInitFunc)purple_des_cipher_class_init,
+			.instance_size = sizeof(PurpleDESCipher),
+			.instance_init = (GInstanceInitFunc)purple_cipher_reset,
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_CIPHER,
+									  "PurpleDESCipher",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * purple_des_cipher_new:
+ *
+ * Creates a new #PurpleCipher instance which implements the DES block cipher.
+ *
+ * Return Value: The new DES implementation of #PurpleCipher.
+ */
+PurpleCipher *
+purple_des_cipher_new(void) {
+	return g_object_new(PURPLE_TYPE_DES_CIPHER, NULL);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/descipher.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,71 @@
+/**
+ * @file des.h Purple DES Cipher
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef PURPLE_DES_CIPHER_H
+#define PURPLE_DES_CIPHER_H
+
+#include "cipher.h"
+
+#define PURPLE_TYPE_DES_CIPHER            (purple_des_cipher_get_type())
+#define PURPLE_DES_CIPHER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_DES_CIPHER, PurpleDESCipher))
+#define PURPLE_DES_CIPHER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_DES_CIPHER, PurpleDESCipherClass))
+#define PURPLE_IS_DES_CIPHER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_DES_CIPHER))
+#define PURPLE_IS_DES_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_DES_CIPHER))
+#define PURPLE_DES_CIPHER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_DES_CIPHER, PurpleDESCipherClass))
+
+typedef struct _PurpleDESCipher           PurpleDESCipher;
+typedef struct _PurpleDESCipherClass      PurpleDESCipherClass;
+
+struct _PurpleDESCipher {
+	/*< private >*/
+	PurpleCipher gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurpleDESCipherClass {
+	/*< private >*/
+	PurpleCipherClass gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_des_cipher_get_type(void);
+
+PurpleCipher *purple_des_cipher_new(void);
+
+int purple_des_cipher_ecb_crypt(PurpleDESCipher *des_cipher, const guint8 * from, guint8 * to, int mode);
+
+G_END_DECLS
+
+#endif /* PURPLE_DES_CIPHER_H */
--- a/libpurple/ciphers/gchecksum.c	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-#include "internal.h"
-#include <cipher.h>
-#include "ciphers.h"
-
-static void
-purple_g_checksum_init(PurpleCipherContext *context, GChecksumType type)
-{
-    GChecksum *checksum;
-
-    checksum = g_checksum_new(type);
-    purple_cipher_context_set_data(context, checksum);
-}
-
-static void
-purple_g_checksum_reset(PurpleCipherContext *context, GChecksumType type)
-{
-    GChecksum *checksum;
-
-    checksum = purple_cipher_context_get_data(context);
-    g_return_if_fail(checksum != NULL);
-
-    g_checksum_reset(checksum);
-}
-
-static void
-purple_g_checksum_uninit(PurpleCipherContext *context)
-{
-    GChecksum *checksum;
-
-    checksum = purple_cipher_context_get_data(context);
-    g_return_if_fail(checksum != NULL);
-
-    g_checksum_free(checksum);
-}
-
-static void
-purple_g_checksum_append(PurpleCipherContext *context, const guchar *data,
-                         gsize len)
-{
-    GChecksum *checksum;
-
-    checksum = purple_cipher_context_get_data(context);
-    g_return_if_fail(checksum != NULL);
-
-    while (len >= G_MAXSSIZE) {
-        g_checksum_update(checksum, data, G_MAXSSIZE);
-        len -= G_MAXSSIZE;
-        data += G_MAXSSIZE;
-    }
-
-    if (len)
-        g_checksum_update(checksum, data, len);
-}
-
-static gboolean
-purple_g_checksum_digest(PurpleCipherContext *context, GChecksumType type,
-                         guchar *digest, size_t buff_len)
-{
-    GChecksum *checksum;
-    const gssize required_len = g_checksum_type_get_length(type);
-    gsize digest_len = buff_len;
-
-    checksum = purple_cipher_context_get_data(context);
-
-    g_return_val_if_fail(buff_len >= required_len, FALSE);
-    g_return_val_if_fail(checksum != NULL, FALSE);
-
-    g_checksum_get_digest(checksum, digest, &digest_len);
-
-    if (digest_len != required_len)
-        return FALSE;
-
-    purple_cipher_context_reset(context, NULL);
-
-    return TRUE;
-}
-
-/******************************************************************************
- * Macros
- *****************************************************************************/
-#define PURPLE_G_CHECKSUM_IMPLEMENTATION(lower, camel, type, block_size) \
-	static size_t \
-	lower##_get_block_size(PurpleCipherContext *context) { \
-		return (block_size); \
-	} \
-	\
-	static void \
-	lower##_init(PurpleCipherContext *context, gpointer extra) { \
-		purple_g_checksum_init(context, (type)); \
-	} \
-	\
-	static void \
-	lower##_reset(PurpleCipherContext *context, gpointer extra) { \
-		purple_g_checksum_reset(context, (type)); \
-	} \
-	\
-	static gboolean \
-	lower##_digest(PurpleCipherContext *context, guchar digest[], \
-		size_t len) \
-	{ \
-		return purple_g_checksum_digest(context, (type), digest, len); \
-	} \
-	\
-	static size_t \
-	lower##_get_digest_size(PurpleCipherContext *context) \
-	{ \
-		return g_checksum_type_get_length((type)); \
-	} \
-	\
-	static PurpleCipherOps camel##Ops = { \
-		NULL,                     /* Set option */       \
-		NULL,                     /* Get option */       \
-		lower##_init,             /* init */             \
-		lower##_reset,            /* reset */            \
-		lower##_reset,            /* reset state */      \
-		purple_g_checksum_uninit, /* uninit */           \
-		NULL,                     /* set iv */           \
-		purple_g_checksum_append, /* append */           \
-		lower##_digest,           /* digest */           \
-		lower##_get_digest_size,  /* get digest size */  \
-		NULL,                     /* encrypt */          \
-		NULL,                     /* decrypt */          \
-		NULL,                     /* set salt */         \
-		NULL,                     /* get salt size */    \
-		NULL,                     /* set key */          \
-		NULL,                     /* get key size */     \
-		NULL,                     /* set batch mode */   \
-		NULL,                     /* get batch mode */   \
-		lower##_get_block_size,   /* get block size */   \
-		NULL, NULL, NULL, NULL    /* reserved */         \
-	}; \
-	\
-	PurpleCipherOps * \
-	purple_##lower##_cipher_get_ops(void) { \
-		return &camel##Ops; \
-	}
-
-/******************************************************************************
- * Macro Expansion
- *****************************************************************************/
-PURPLE_G_CHECKSUM_IMPLEMENTATION(md5, MD5, G_CHECKSUM_MD5, 64);
-PURPLE_G_CHECKSUM_IMPLEMENTATION(sha1, SHA1, G_CHECKSUM_SHA1, 64);
-PURPLE_G_CHECKSUM_IMPLEMENTATION(sha256, SHA256, G_CHECKSUM_SHA256, 64);
--- a/libpurple/ciphers/hmac.c	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,247 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#include "internal.h"
-#include <cipher.h>
-#include "ciphers.h"
-
-#include <util.h>
-
-struct HMAC_Context {
-	PurpleCipherContext *hash;
-	char *name;
-	int blocksize;
-	guchar *opad, *ipad;
-};
-
-	static void
-hmac_init(PurpleCipherContext *context, gpointer extra)
-{
-	struct HMAC_Context *hctx;
-	hctx = g_new0(struct HMAC_Context, 1);
-	purple_cipher_context_set_data(context, hctx);
-	purple_cipher_context_reset(context, extra);
-}
-
-	static void
-hmac_reset(PurpleCipherContext *context, gpointer extra)
-{
-	struct HMAC_Context *hctx;
-
-	hctx = purple_cipher_context_get_data(context);
-
-	g_free(hctx->name);
-	hctx->name = NULL;
-	if (hctx->hash)
-		purple_cipher_context_destroy(hctx->hash);
-	hctx->hash = NULL;
-	hctx->blocksize = 0;
-	g_free(hctx->opad);
-	hctx->opad = NULL;
-	g_free(hctx->ipad);
-	hctx->ipad = NULL;
-}
-
-	static void
-hmac_reset_state(PurpleCipherContext *context, gpointer extra)
-{
-	struct HMAC_Context *hctx;
-
-	hctx = purple_cipher_context_get_data(context);
-
-	if (hctx->hash) {
-		purple_cipher_context_reset_state(hctx->hash, NULL);
-		purple_cipher_context_append(hctx->hash, hctx->ipad, hctx->blocksize);
-	}
-}
-
-	static void
-hmac_set_opt(PurpleCipherContext *context, const gchar *name, void *value)
-{
-	struct HMAC_Context *hctx;
-
-	hctx = purple_cipher_context_get_data(context);
-
-	if (purple_strequal(name, "hash")) {
-		g_free(hctx->name);
-		if (hctx->hash)
-			purple_cipher_context_destroy(hctx->hash);
-		hctx->name = g_strdup((char*)value);
-		hctx->hash = purple_cipher_context_new_by_name((char *)value, NULL);
-		hctx->blocksize = purple_cipher_context_get_block_size(hctx->hash);
-	}
-}
-
-	static void *
-hmac_get_opt(PurpleCipherContext *context, const gchar *name)
-{
-	struct HMAC_Context *hctx;
-
-	hctx = purple_cipher_context_get_data(context);
-
-	if (purple_strequal(name, "hash")) {
-		return hctx->name;
-	}
-
-	return NULL;
-}
-
-	static void
-hmac_append(PurpleCipherContext *context, const guchar *data, size_t len)
-{
-	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(hctx->hash != NULL);
-
-	purple_cipher_context_append(hctx->hash, data, len);
-}
-
-	static gboolean
-hmac_digest(PurpleCipherContext *context, guchar *out, size_t len)
-{
-	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
-	PurpleCipherContext *hash = hctx->hash;
-	guchar *inner_hash;
-	size_t hash_len;
-	gboolean result;
-
-	g_return_val_if_fail(hash != NULL, FALSE);
-
-	hash_len = purple_cipher_context_get_digest_size(hash);
-	g_return_val_if_fail(hash_len > 0, FALSE);
-
-	inner_hash = g_malloc(hash_len);
-	result = purple_cipher_context_digest(hash, inner_hash, hash_len);
-
-	purple_cipher_context_reset(hash, NULL);
-
-	purple_cipher_context_append(hash, hctx->opad, hctx->blocksize);
-	purple_cipher_context_append(hash, inner_hash, hash_len);
-
-	g_free(inner_hash);
-
-	result = result && purple_cipher_context_digest(hash, out, len);
-
-	return result;
-}
-
-	static size_t
-hmac_get_digest_size(PurpleCipherContext *context)
-{
-	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
-	PurpleCipherContext *hash = hctx->hash;
-
-	g_return_val_if_fail(hash != NULL, 0);
-
-	return purple_cipher_context_get_digest_size(hash);
-}
-
-	static void
-hmac_uninit(PurpleCipherContext *context)
-{
-	struct HMAC_Context *hctx;
-
-	purple_cipher_context_reset(context, NULL);
-
-	hctx = purple_cipher_context_get_data(context);
-
-	g_free(hctx);
-}
-
-	static void
-hmac_set_key(PurpleCipherContext *context, const guchar * key, size_t key_len)
-{
-	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
-	int blocksize, i;
-	guchar *full_key;
-
-	g_return_if_fail(hctx->hash != NULL);
-
-	g_free(hctx->opad);
-	g_free(hctx->ipad);
-
-	blocksize = hctx->blocksize;
-	hctx->ipad = g_malloc(blocksize);
-	hctx->opad = g_malloc(blocksize);
-
-	if (key_len > blocksize) {
-		purple_cipher_context_reset(hctx->hash, NULL);
-		purple_cipher_context_append(hctx->hash, key, key_len);
-
-		key_len = purple_cipher_context_get_digest_size(hctx->hash);
-		full_key = g_malloc(key_len);
-		purple_cipher_context_digest(hctx->hash, full_key, key_len);
-	} else
-		full_key = g_memdup(key, key_len);
-
-	if (key_len < blocksize) {
-		full_key = g_realloc(full_key, blocksize);
-		memset(full_key + key_len, 0, blocksize - key_len);
-	}
-
-	for(i = 0; i < blocksize; i++) {
-		hctx->ipad[i] = 0x36 ^ full_key[i];
-		hctx->opad[i] = 0x5c ^ full_key[i];
-	}
-
-	g_free(full_key);
-
-	purple_cipher_context_reset(hctx->hash, NULL);
-	purple_cipher_context_append(hctx->hash, hctx->ipad, blocksize);
-}
-
-	static size_t
-hmac_get_block_size(PurpleCipherContext *context)
-{
-	struct HMAC_Context *hctx = purple_cipher_context_get_data(context);
-
-	return hctx->blocksize;
-}
-
-static PurpleCipherOps HMACOps = {
-	hmac_set_opt,           /* Set option */
-	hmac_get_opt,           /* Get option */
-	hmac_init,              /* init */
-	hmac_reset,             /* reset */
-	hmac_reset_state,       /* reset state */
-	hmac_uninit,            /* uninit */
-	NULL,                   /* set iv */
-	hmac_append,            /* append */
-	hmac_digest,            /* digest */
-	hmac_get_digest_size,   /* get digest size */
-	NULL,                   /* encrypt */
-	NULL,                   /* decrypt */
-	NULL,                   /* set salt */
-	NULL,                   /* get salt size */
-	hmac_set_key,           /* set key */
-	NULL,                   /* get key size */
-	NULL,                   /* set batch mode */
-	NULL,                   /* get batch mode */
-	hmac_get_block_size,    /* get block size */
-	NULL, NULL, NULL, NULL  /* reserved */
-};
-
-PurpleCipherOps *
-purple_hmac_cipher_get_ops(void) {
-	return &HMACOps;
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/hmaccipher.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,345 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "hmaccipher.h"
+
+#include <string.h>
+
+/*******************************************************************************
+ * Structs
+ ******************************************************************************/
+#define PURPLE_HMAC_CIPHER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_HMAC_CIPHER, PurpleHMACCipherPrivate))
+
+typedef struct {
+	PurpleHash *hash;
+	guchar *ipad;
+	guchar *opad;
+} PurpleHMACCipherPrivate;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+	PROP_NONE,
+	PROP_HASH,
+	PROP_LAST,
+};
+
+/*******************************************************************************
+ * Globals
+ ******************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/*******************************************************************************
+ * Helpers
+ ******************************************************************************/
+static void
+purple_hmac_cipher_set_hash(PurpleCipher *cipher,
+							PurpleHash *hash)
+{
+	PurpleHMACCipherPrivate *priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+
+	priv->hash = g_object_ref(G_OBJECT(hash));
+	g_object_notify(G_OBJECT(cipher), "hash");
+}
+
+/*******************************************************************************
+ * Cipher Stuff
+ ******************************************************************************/
+static void
+purple_hmac_cipher_reset(PurpleCipher *cipher) {
+	PurpleHMACCipherPrivate *priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+
+	if(PURPLE_IS_HASH(priv->hash))
+		purple_hash_reset(priv->hash);
+
+	if(priv->ipad) {
+		g_free(priv->ipad);
+		priv->ipad = NULL;
+	}
+	if(priv->opad) {
+		g_free(priv->opad);
+		priv->opad = NULL;
+	}
+}
+
+static void
+purple_hmac_cipher_reset_state(PurpleCipher *cipher) {
+	PurpleHMACCipherPrivate *priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+
+	if(PURPLE_IS_HASH(priv->hash)) {
+		purple_hash_reset_state(priv->hash);
+		purple_hash_append(priv->hash, priv->ipad,
+								purple_hash_get_block_size(priv->hash));
+	}
+}
+
+static void
+purple_hmac_cipher_append(PurpleCipher *cipher, const guchar *d, size_t l) {
+	PurpleHMACCipherPrivate *priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+
+	g_return_if_fail(PURPLE_IS_HASH(priv->hash));
+
+	purple_hash_append(priv->hash, d, l);
+}
+
+static gboolean
+purple_hmac_cipher_digest(PurpleCipher *cipher, guchar *out, size_t len)
+{
+	PurpleHMACCipherPrivate *priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+	guchar *digest = NULL;
+	size_t hash_len, block_size;
+	gboolean result = FALSE;
+
+	g_return_val_if_fail(PURPLE_IS_HASH(priv->hash), FALSE);
+
+	hash_len = purple_hash_get_digest_size(priv->hash);
+	g_return_val_if_fail(hash_len > 0, FALSE);
+
+	block_size = purple_hash_get_block_size(priv->hash);
+	digest = g_malloc(hash_len);
+
+	/* get the digest of the data */
+	result = purple_hash_digest(priv->hash, digest, hash_len);
+	purple_hash_reset(priv->hash);
+
+	if(!result) {
+		g_free(digest);
+
+		return FALSE;
+	}
+
+	/* now append the opad and the digest from above */
+	purple_hash_append(priv->hash, priv->opad, block_size);
+	purple_hash_append(priv->hash, digest, hash_len);
+
+	/* do our last digest */
+	result = purple_hash_digest(priv->hash, out, len);
+
+	/* cleanup */
+	g_free(digest);
+
+	return result;
+}
+
+static size_t
+purple_hmac_cipher_get_digest_size(PurpleCipher *cipher)
+{
+	PurpleHMACCipherPrivate *priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+
+	g_return_val_if_fail(priv->hash != NULL, 0);
+
+	return purple_hash_get_digest_size(priv->hash);
+}
+
+static void
+purple_hmac_cipher_set_key(PurpleCipher *cipher, const guchar *key,
+								size_t key_len)
+{
+	PurpleHMACCipherPrivate *priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+	gint block_size, i;
+	guchar *full_key;
+
+	g_return_if_fail(priv->hash);
+
+	g_free(priv->ipad);
+	g_free(priv->opad);
+
+	block_size = purple_hash_get_block_size(priv->hash);
+	priv->ipad = g_malloc(block_size);
+	priv->opad = g_malloc(block_size);
+
+	if (key_len > block_size) {
+		purple_hash_reset(priv->hash);
+		purple_hash_append(priv->hash, key, key_len);
+
+		key_len = purple_hash_get_digest_size(priv->hash);
+		full_key = g_malloc(key_len);
+		purple_hash_digest(priv->hash, full_key, key_len);
+	} else {
+		full_key = g_memdup(key, key_len);
+	}
+
+    if (key_len < block_size) {
+		full_key = g_realloc(full_key, block_size);
+		memset(full_key + key_len, 0, block_size - key_len);
+    }
+
+	for(i = 0; i < block_size; i++) {
+		priv->ipad[i] = 0x36 ^ full_key[i];
+		priv->opad[i] = 0x5c ^ full_key[i];
+	}
+
+	g_free(full_key);
+
+	purple_hash_reset(priv->hash);
+	purple_hash_append(priv->hash, priv->ipad, block_size);
+}
+
+static size_t
+purple_hmac_cipher_get_block_size(PurpleCipher *cipher)
+{
+	PurpleHMACCipherPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_HMAC_CIPHER(cipher), 0);
+
+	priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+
+	return purple_hash_get_block_size(priv->hash);
+}
+
+static const gchar*
+purple_hmac_cipher_get_name(PurpleCipher *cipher)
+{
+	return "hmac";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_hmac_cipher_set_property(GObject *obj, guint param_id,
+								const GValue *value,
+								GParamSpec *pspec)
+{
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+
+	switch(param_id) {
+		case PROP_HASH:
+			purple_hmac_cipher_set_hash(cipher, g_value_get_object(value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_hmac_cipher_get_property(GObject *obj, guint param_id, GValue *value,
+								GParamSpec *pspec)
+{
+	PurpleHMACCipher *cipher = PURPLE_HMAC_CIPHER(obj);
+
+	switch(param_id) {
+		case PROP_HASH:
+			g_value_set_object(value,
+							   purple_hmac_cipher_get_hash(cipher));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_hmac_cipher_finalize(GObject *obj) {
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+	PurpleHMACCipherPrivate *priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+
+	purple_hmac_cipher_reset(cipher);
+
+	if (priv->hash != NULL)
+		g_object_unref(priv->hash);
+
+	parent_class->finalize(obj);
+}
+
+static void
+purple_hmac_cipher_class_init(PurpleHMACCipherClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
+	GParamSpec *pspec;
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	g_type_class_add_private(klass, sizeof(PurpleHMACCipherPrivate));
+
+	obj_class->finalize = purple_hmac_cipher_finalize;
+	obj_class->get_property = purple_hmac_cipher_get_property;
+	obj_class->set_property = purple_hmac_cipher_set_property;
+
+	cipher_class->reset = purple_hmac_cipher_reset;
+	cipher_class->reset_state = purple_hmac_cipher_reset_state;
+	cipher_class->append = purple_hmac_cipher_append;
+	cipher_class->digest = purple_hmac_cipher_digest;
+	cipher_class->get_digest_size = purple_hmac_cipher_get_digest_size;
+	cipher_class->set_key = purple_hmac_cipher_set_key;
+	cipher_class->get_block_size = purple_hmac_cipher_get_block_size;
+	cipher_class->get_name = purple_hmac_cipher_get_name;
+
+	pspec = g_param_spec_object("hash", "hash", "hash", PURPLE_TYPE_HASH,
+								G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+	g_object_class_install_property(obj_class, PROP_HASH, pspec);
+}
+
+/******************************************************************************
+ * PurpleHMACCipher API
+ *****************************************************************************/
+GType
+purple_hmac_cipher_get_gtype(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleHMACCipherClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_hmac_cipher_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleHMACCipher),
+			0,
+			(GInstanceInitFunc)purple_cipher_reset,
+			NULL,
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_CIPHER,
+									  "PurpleHMACCipher",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+PurpleCipher *
+purple_hmac_cipher_new(PurpleHash *hash) {
+	g_return_val_if_fail(PURPLE_IS_HASH(hash), NULL);
+
+	return g_object_new(PURPLE_TYPE_HMAC_CIPHER,
+						"hash", hash,
+						NULL);
+}
+
+PurpleHash *
+purple_hmac_cipher_get_hash(const PurpleHMACCipher *cipher) {
+	PurpleHMACCipherPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_HMAC_CIPHER(cipher), NULL);
+
+	priv = PURPLE_HMAC_CIPHER_GET_PRIVATE(cipher);
+
+	if(priv && priv->hash)
+		return priv->hash;
+
+	return NULL;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/hmaccipher.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,70 @@
+/**
+ * @file hmac.h Purple HMAC Cipher
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_HMAC_CIPHER_H
+#define PURPLE_HMAC_CIPHER_H
+
+#include "cipher.h"
+#include "hash.h"
+
+#define PURPLE_TYPE_HMAC_CIPHER				(purple_hmac_cipher_get_gtype())
+#define PURPLE_HMAC_CIPHER(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_HMAC_CIPHER, PurpleHMACCipher))
+#define PURPLE_HMAC_CIPHER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_HMAC_CIPHER, PurpleHMACCipherClass))
+#define PURPLE_IS_HMAC_CIPHER(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_HMAC_CIPHER))
+#define PURPLE_IS_HMAC_CIPHER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_HMAC_CIPHER))
+#define PURPLE_HMAC_CIPHER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_HMAC_CIPHER, PurpleHMACCipherClass))
+
+typedef struct _PurpleHMACCipher				PurpleHMACCipher;
+typedef struct _PurpleHMACCipherClass			PurpleHMACCipherClass;
+
+struct _PurpleHMACCipher {
+	PurpleCipher gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurpleHMACCipherClass {
+	PurpleCipherClass gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_hmac_cipher_get_gtype(void);
+
+PurpleCipher *purple_hmac_cipher_new(PurpleHash *hash);
+
+PurpleHash *purple_hmac_cipher_get_hash(const PurpleHMACCipher *cipher);
+
+G_END_DECLS
+
+#endif /* PURPLE_HMAC_CIPHER_H */
--- a/libpurple/ciphers/md4.c	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,306 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * Original md4 taken from linux kernel
- * MD4 Message Digest Algorithm (RFC1320).
- *
- * Implementation derived from Andrew Tridgell and Steve French's
- * CIFS MD4 implementation, and the cryptoapi implementation
- * originally based on the public domain implementation written
- * by Colin Plumb in 1993.
- *
- * Copyright (c) Andrew Tridgell 1997-1998.
- * Modified by Steve French (sfrench@us.ibm.com) 2002
- * Copyright (c) Cryptoapi developers.
- * Copyright (c) 2002 David S. Miller (davem@redhat.com)
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#include "internal.h"
-#include <cipher.h>
-#include "ciphers.h"
-
-#define MD4_DIGEST_SIZE     16
-#define MD4_HMAC_BLOCK_SIZE 64
-#define MD4_BLOCK_WORDS     16
-#define MD4_HASH_WORDS      4
-
-struct MD4_Context {
-	guint32 hash[MD4_HASH_WORDS];
-	guint32 block[MD4_BLOCK_WORDS];
-	guint64 byte_count;
-};
-
-static inline guint32 lshift(guint32 x, unsigned int s)
-{
-	x &= 0xFFFFFFFF;
-	return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
-}
-
-static inline guint32 F(guint32 x, guint32 y, guint32 z)
-{
-	return (x & y) | ((~x) & z);
-}
-
-static inline guint32 G(guint32 x, guint32 y, guint32 z)
-{
-	return (x & y) | (x & z) | (y & z);
-}
-
-static inline guint32 H(guint32 x, guint32 y, guint32 z)
-{
-	return x ^ y ^ z;
-}
-
-#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
-#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (guint32)0x5A827999,s))
-#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (guint32)0x6ED9EBA1,s))
-
-static inline void le32_to_cpu_array(guint32 *buf, unsigned int words)
-{
-	while (words--) {
-		*buf=GUINT_FROM_LE(*buf);
-		buf++;
-	}
-}
-
-static inline void cpu_to_le32_array(guint32 *buf, unsigned int words)
-{
-	while (words--) {
-		*buf=GUINT_TO_LE(*buf);
-		buf++;
-	}
-}
-
-static void md4_transform(guint32 *hash, guint32 const *in)
-{
-	guint32 a, b, c, d;
-
-	a = hash[0];
-	b = hash[1];
-	c = hash[2];
-	d = hash[3];
-
-	ROUND1(a, b, c, d, in[0], 3);
-	ROUND1(d, a, b, c, in[1], 7);
-	ROUND1(c, d, a, b, in[2], 11);
-	ROUND1(b, c, d, a, in[3], 19);
-	ROUND1(a, b, c, d, in[4], 3);
-	ROUND1(d, a, b, c, in[5], 7);
-	ROUND1(c, d, a, b, in[6], 11);
-	ROUND1(b, c, d, a, in[7], 19);
-	ROUND1(a, b, c, d, in[8], 3);
-	ROUND1(d, a, b, c, in[9], 7);
-	ROUND1(c, d, a, b, in[10], 11);
-	ROUND1(b, c, d, a, in[11], 19);
-	ROUND1(a, b, c, d, in[12], 3);
-	ROUND1(d, a, b, c, in[13], 7);
-	ROUND1(c, d, a, b, in[14], 11);
-	ROUND1(b, c, d, a, in[15], 19);
-
-	ROUND2(a, b, c, d,in[ 0], 3);
-	ROUND2(d, a, b, c, in[4], 5);
-	ROUND2(c, d, a, b, in[8], 9);
-	ROUND2(b, c, d, a, in[12], 13);
-	ROUND2(a, b, c, d, in[1], 3);
-	ROUND2(d, a, b, c, in[5], 5);
-	ROUND2(c, d, a, b, in[9], 9);
-	ROUND2(b, c, d, a, in[13], 13);
-	ROUND2(a, b, c, d, in[2], 3);
-	ROUND2(d, a, b, c, in[6], 5);
-	ROUND2(c, d, a, b, in[10], 9);
-	ROUND2(b, c, d, a, in[14], 13);
-	ROUND2(a, b, c, d, in[3], 3);
-	ROUND2(d, a, b, c, in[7], 5);
-	ROUND2(c, d, a, b, in[11], 9);
-	ROUND2(b, c, d, a, in[15], 13);
-
-	ROUND3(a, b, c, d,in[ 0], 3);
-	ROUND3(d, a, b, c, in[8], 9);
-	ROUND3(c, d, a, b, in[4], 11);
-	ROUND3(b, c, d, a, in[12], 15);
-	ROUND3(a, b, c, d, in[2], 3);
-	ROUND3(d, a, b, c, in[10], 9);
-	ROUND3(c, d, a, b, in[6], 11);
-	ROUND3(b, c, d, a, in[14], 15);
-	ROUND3(a, b, c, d, in[1], 3);
-	ROUND3(d, a, b, c, in[9], 9);
-	ROUND3(c, d, a, b, in[5], 11);
-	ROUND3(b, c, d, a, in[13], 15);
-	ROUND3(a, b, c, d, in[3], 3);
-	ROUND3(d, a, b, c, in[11], 9);
-	ROUND3(c, d, a, b, in[7], 11);
-	ROUND3(b, c, d, a, in[15], 15);
-
-	hash[0] += a;
-	hash[1] += b;
-	hash[2] += c;
-	hash[3] += d;
-}
-
-static inline void md4_transform_helper(struct MD4_Context *ctx)
-{
-	le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(guint32));
-	md4_transform(ctx->hash, ctx->block);
-}
-
-static void
-md4_init(PurpleCipherContext *context, gpointer extra) {
-	struct MD4_Context *mctx;
-	mctx = g_new0(struct MD4_Context, 1);
-	purple_cipher_context_set_data(context, mctx);
-	purple_cipher_context_reset(context, extra);
-
-	mctx->hash[0] = 0x67452301;
-	mctx->hash[1] = 0xefcdab89;
-	mctx->hash[2] = 0x98badcfe;
-	mctx->hash[3] = 0x10325476;
-	mctx->byte_count = 0;
-}
-
-static void
-md4_reset(PurpleCipherContext *context, gpointer extra) {
-	struct MD4_Context *mctx;
-
-	mctx = purple_cipher_context_get_data(context);
-
-	mctx->hash[0] = 0x67452301;
-	mctx->hash[1] = 0xefcdab89;
-	mctx->hash[2] = 0x98badcfe;
-	mctx->hash[3] = 0x10325476;
-	mctx->byte_count = 0;
-}
-
-	static void
-md4_append(PurpleCipherContext *context, const guchar *data, size_t len)
-{
-	struct MD4_Context *mctx = purple_cipher_context_get_data(context);
-	const guint32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
-
-	mctx->byte_count += len;
-
-	if (avail > len) {
-		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
-				data, len);
-		return;
-	}
-
-	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
-			data, avail);
-
-	md4_transform_helper(mctx);
-	data += avail;
-	len -= avail;
-
-	while (len >= sizeof(mctx->block)) {
-		memcpy(mctx->block, data, sizeof(mctx->block));
-		md4_transform_helper(mctx);
-		data += sizeof(mctx->block);
-		len -= sizeof(mctx->block);
-	}
-
-	memcpy(mctx->block, data, len);
-}
-
-	static gboolean
-md4_digest(PurpleCipherContext *context, guchar *out, size_t len)
-{
-	struct MD4_Context *mctx = purple_cipher_context_get_data(context);
-	const unsigned int offset = mctx->byte_count & 0x3f;
-	char *p = (char *)mctx->block + offset;
-	int padding = 56 - (offset + 1);
-
-
-	if(len<16) return FALSE;
-	*p++ = 0x80;
-	if (padding < 0) {
-		memset(p, 0x00, padding + sizeof (guint64));
-		md4_transform_helper(mctx);
-		p = (char *)mctx->block;
-		padding = 56;
-	}
-
-	memset(p, 0, padding);
-	mctx->block[14] = mctx->byte_count << 3;
-	mctx->block[15] = mctx->byte_count >> 29;
-	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
-				sizeof(guint64)) / sizeof(guint32));
-	md4_transform(mctx->hash, mctx->block);
-	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(guint32));
-	memcpy(out, mctx->hash, sizeof(mctx->hash));
-	memset(mctx, 0, sizeof(*mctx));
-	return TRUE;
-}
-
-	static size_t
-md4_get_digest_size(PurpleCipherContext *context)
-{
-	return 16;
-}
-
-static void
-md4_uninit(PurpleCipherContext *context) {
-	struct MD4_Context *md4_context;
-
-	purple_cipher_context_reset(context, NULL);
-
-	md4_context = purple_cipher_context_get_data(context);
-	memset(md4_context, 0, sizeof(*md4_context));
-
-	g_free(md4_context);
-	md4_context = NULL;
-}
-
-	static size_t
-md4_get_block_size(PurpleCipherContext *context)
-{
-	/* This does not change (in this case) */
-	return MD4_HMAC_BLOCK_SIZE;
-}
-
-static PurpleCipherOps MD4Ops = {
-	NULL,                   /* Set option */
-	NULL,                   /* Get option */
-	md4_init,               /* init */
-	md4_reset,              /* reset */
-	md4_reset,              /* reset state */
-	md4_uninit,             /* uninit */
-	NULL,                   /* set iv */
-	md4_append,             /* append */
-	md4_digest,             /* digest */
-	md4_get_digest_size,    /* get digest size */
-	NULL,                   /* encrypt */
-	NULL,                   /* decrypt */
-	NULL,                   /* set salt */
-	NULL,                   /* get salt size */
-	NULL,                   /* set key */
-	NULL,                   /* get key size */
-	NULL,                   /* set batch mode */
-	NULL,                   /* get batch mode */
-	md4_get_block_size,     /* get block size */
-	NULL, NULL, NULL, NULL  /* reserved */
-};
-
-PurpleCipherOps *
-purple_md4_cipher_get_ops(void) {
-	return &MD4Ops;
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/md4hash.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,317 @@
+/*
+ * Original md4 taken from linux kernel
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ */
+#include "md4hash.h"
+
+#include <string.h>
+
+#define MD4_DIGEST_SIZE		16
+#define MD4_BLOCK_WORDS		16
+#define MD4_HASH_WORDS		4
+
+#define PURPLE_MD4_HASH_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MD4_HASH, PurpleMD4HashPrivate))
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+typedef struct {
+	guint32 hash[MD4_HASH_WORDS];
+	guint32 block[MD4_BLOCK_WORDS];
+	guint64 byte_count;
+} PurpleMD4HashPrivate;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+#define ROUND1(a,b,c,d,k,s) \
+	(a = lshift(a + F(b,c,d) + k, s))
+
+#define ROUND2(a,b,c,d,k,s) \
+	(a = lshift(a + G(b,c,d) + k + (guint32)0x5a827999,s))
+
+#define ROUND3(a,b,c,d,k,s) \
+	(a = lshift(a + H(b,c,d) + k + (guint32)0x6ed9eba1,s))
+
+static inline guint32
+lshift(guint32 x, unsigned int s) {
+	x &= 0xffffffff;
+	return (((x << s) & 0xffffffff) | (x >> (32 - s)));
+}
+
+static inline guint32
+F(guint32 x, guint32 y, guint32 z) {
+	return ((x & y) | ((~x) & z));
+}
+
+static inline guint32
+G(guint32 x, guint32 y, guint32 z) {
+	return ((x & y) | (x & z) | (y & z));
+}
+
+static inline guint32
+H(guint32 x, guint32 y, guint32 z) {
+	return (x ^ y ^ z);
+}
+
+static inline void
+le32_to_cpu_array(guint32 *buf, unsigned int words) {
+	while(words--) {
+		*buf = GUINT_FROM_LE(*buf);
+		buf++;
+	}
+}
+
+static inline void
+cpu_to_le32_array(guint32 *buf, unsigned int words) {
+	while(words--) {
+		*buf = GUINT_TO_LE(*buf);
+		buf++;
+	}
+}
+
+static void
+md4_transform(guint32 *hash, guint32 const *in) {
+	guint32 a, b, c, d;
+
+	a = hash[0];
+	b = hash[1];
+	c = hash[2];
+	d = hash[3];
+
+	ROUND1(a, b, c, d, in[0], 3);
+	ROUND1(d, a, b, c, in[1], 7);
+	ROUND1(c, d, a, b, in[2], 11);
+	ROUND1(b, c, d, a, in[3], 19);
+	ROUND1(a, b, c, d, in[4], 3);
+	ROUND1(d, a, b, c, in[5], 7);
+	ROUND1(c, d, a, b, in[6], 11);
+	ROUND1(b, c, d, a, in[7], 19);
+	ROUND1(a, b, c, d, in[8], 3);
+	ROUND1(d, a, b, c, in[9], 7);
+	ROUND1(c, d, a, b, in[10], 11);
+	ROUND1(b, c, d, a, in[11], 19);
+	ROUND1(a, b, c, d, in[12], 3);
+	ROUND1(d, a, b, c, in[13], 7);
+	ROUND1(c, d, a, b, in[14], 11);
+	ROUND1(b, c, d, a, in[15], 19);
+
+	ROUND2(a, b, c, d,in[ 0], 3);
+	ROUND2(d, a, b, c, in[4], 5);
+	ROUND2(c, d, a, b, in[8], 9);
+	ROUND2(b, c, d, a, in[12], 13);
+	ROUND2(a, b, c, d, in[1], 3);
+	ROUND2(d, a, b, c, in[5], 5);
+	ROUND2(c, d, a, b, in[9], 9);
+	ROUND2(b, c, d, a, in[13], 13);
+	ROUND2(a, b, c, d, in[2], 3);
+	ROUND2(d, a, b, c, in[6], 5);
+	ROUND2(c, d, a, b, in[10], 9);
+	ROUND2(b, c, d, a, in[14], 13);
+	ROUND2(a, b, c, d, in[3], 3);
+	ROUND2(d, a, b, c, in[7], 5);
+	ROUND2(c, d, a, b, in[11], 9);
+	ROUND2(b, c, d, a, in[15], 13);
+
+	ROUND3(a, b, c, d,in[ 0], 3);
+	ROUND3(d, a, b, c, in[8], 9);
+	ROUND3(c, d, a, b, in[4], 11);
+	ROUND3(b, c, d, a, in[12], 15);
+	ROUND3(a, b, c, d, in[2], 3);
+	ROUND3(d, a, b, c, in[10], 9);
+	ROUND3(c, d, a, b, in[6], 11);
+	ROUND3(b, c, d, a, in[14], 15);
+	ROUND3(a, b, c, d, in[1], 3);
+	ROUND3(d, a, b, c, in[9], 9);
+	ROUND3(c, d, a, b, in[5], 11);
+	ROUND3(b, c, d, a, in[13], 15);
+	ROUND3(a, b, c, d, in[3], 3);
+	ROUND3(d, a, b, c, in[11], 9);
+	ROUND3(c, d, a, b, in[7], 11);
+	ROUND3(b, c, d, a, in[15], 15);
+
+	hash[0] += a;
+	hash[1] += b;
+	hash[2] += c;
+	hash[3] += d;
+}
+
+static inline void
+md4_transform_helper(PurpleHash *hash) {
+	PurpleMD4HashPrivate *priv = PURPLE_MD4_HASH_GET_PRIVATE(hash);
+
+	le32_to_cpu_array(priv->block, sizeof(priv->block) / sizeof(guint32));
+	md4_transform(priv->hash, priv->block);
+}
+
+/******************************************************************************
+ * Hash Stuff
+ *****************************************************************************/
+static void
+purple_md4_hash_reset(PurpleHash *hash) {
+	PurpleMD4HashPrivate *priv = PURPLE_MD4_HASH_GET_PRIVATE(hash);
+
+	priv->hash[0] = 0x67452301;
+	priv->hash[1] = 0xefcdab89;
+	priv->hash[2] = 0x98badcfe;
+	priv->hash[3] = 0x10325476;
+
+	priv->byte_count = 0;
+
+	memset(priv->block, 0, sizeof(priv->block));
+}
+
+static void
+purple_md4_hash_append(PurpleHash *hash, const guchar *data, size_t len) {
+	PurpleMD4HashPrivate *priv = PURPLE_MD4_HASH_GET_PRIVATE(hash);
+	const guint32 avail = sizeof(priv->block) - (priv->byte_count & 0x3f);
+
+	priv->byte_count += len;
+
+	if(avail > len) {
+		memcpy((char *)priv->block +
+			   (sizeof(priv->block) - avail),
+			   data, len);
+		return;
+	}
+
+	memcpy((char *)priv->block +
+		   (sizeof(priv->block) - avail),
+		   data, avail);
+
+	md4_transform_helper(hash);
+	data += avail;
+	len -= avail;
+
+	while(len >= sizeof(priv->block)) {
+		memcpy(priv->block, data, sizeof(priv->block));
+		md4_transform_helper(hash);
+		data += sizeof(priv->block);
+		len -= sizeof(priv->block);
+	}
+
+	memcpy(priv->block, data, len);
+}
+
+static gboolean
+purple_md4_hash_digest(PurpleHash *hash, guchar *out, size_t len)
+{
+	PurpleMD4HashPrivate *priv = PURPLE_MD4_HASH_GET_PRIVATE(hash);
+	const unsigned int offset = priv->byte_count & 0x3f;
+	gchar *p = (gchar *)priv->block + offset;
+	gint padding = 56 - (offset + 1);
+
+	if(len < 16)
+		return FALSE;
+
+	*p++ = 0x80;
+
+	if(padding < 0) {
+		memset(p, 0x00, padding + sizeof(guint64));
+		md4_transform_helper(hash);
+		p = (gchar *)priv->block;
+		padding = 56;
+	}
+
+	memset(p, 0, padding);
+	priv->block[14] = priv->byte_count << 3;
+	priv->block[15] = priv->byte_count >> 29;
+	le32_to_cpu_array(priv->block,
+					  (sizeof(priv->block) - sizeof(guint64)) /
+					  sizeof(guint32));
+	md4_transform(priv->hash, priv->block);
+	cpu_to_le32_array(priv->hash, sizeof(priv->hash) / sizeof(guint32));
+	memcpy(out, priv->hash, sizeof(priv->hash));
+
+	return TRUE;
+}
+
+static size_t
+purple_md4_hash_get_digest_size(PurpleHash *hash)
+{
+	return 16;
+}
+
+static size_t
+purple_md4_hash_get_block_size(PurpleHash *hash)
+{
+	/* This does not change (in this case) */
+	return 64;
+}
+
+static const gchar*
+purple_md4_hash_get_name(PurpleHash *hash)
+{
+	return "md4";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_md4_hash_class_init(PurpleMD4HashClass *klass) {
+	PurpleHashClass *hash_class = PURPLE_HASH_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	g_type_class_add_private(klass, sizeof(PurpleMD4HashPrivate));
+
+	hash_class->reset = purple_md4_hash_reset;
+	hash_class->reset_state = purple_md4_hash_reset;
+	hash_class->append = purple_md4_hash_append;
+	hash_class->digest = purple_md4_hash_digest;
+	hash_class->get_digest_size = purple_md4_hash_get_digest_size;
+	hash_class->get_block_size = purple_md4_hash_get_block_size;
+	hash_class->get_name = purple_md4_hash_get_name;
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_md4_hash_get_gtype(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleMD4HashClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_md4_hash_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleMD4Hash),
+			0,
+			(GInstanceInitFunc)purple_hash_reset,
+			NULL,
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_HASH,
+									  "PurpleMD4Hash",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+PurpleHash *
+purple_md4_hash_new(void) {
+	return g_object_new(PURPLE_TYPE_MD4_HASH, NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/md4hash.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,66 @@
+/**
+ * @file md4.h Purple MD4 hash
+ * @ingroup core
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef PURPLE_MD4_HASH_H
+#define PURPLE_MD4_HASH_H
+
+#include "hash.h"
+
+#define PURPLE_TYPE_MD4_HASH				(purple_md4_hash_get_gtype())
+#define PURPLE_MD4_HASH(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MD4_HASH, PurpleMD4Hash))
+#define PURPLE_MD4_HASH_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MD4_HASH, PurpleMD4HashClass))
+#define PURPLE_IS_MD4_HASH(obj)				(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MD4_HASH))
+#define PURPLE_IS_MD4_HASH_CLASS(klass)		(G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_MD4_HASH))
+#define PURPLE_MD4_HASH_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MD4_HASH, PurpleMD4HashClass))
+
+typedef struct _PurpleMD4Hash				PurpleMD4Hash;
+typedef struct _PurpleMD4HashClass			PurpleMD4HashClass;
+
+struct _PurpleMD4Hash {
+	PurpleHash parent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurpleMD4HashClass {
+	PurpleHashClass parent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_md4_hash_get_gtype(void);
+
+PurpleHash *purple_md4_hash_new(void);
+
+G_END_DECLS
+
+#endif /* PURPLE_MD4_HASH_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/md5hash.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,195 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "md5hash.h"
+
+/*******************************************************************************
+ * Structs
+ ******************************************************************************/
+#define PURPLE_MD5_HASH_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MD5_HASH, PurpleMD5HashPrivate))
+
+typedef struct {
+  GChecksum *checksum;
+} PurpleMD5HashPrivate;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Hash Stuff
+ *****************************************************************************/
+
+static void
+purple_md5_hash_reset(PurpleHash *hash)
+{
+	PurpleMD5Hash *md5_hash = PURPLE_MD5_HASH(hash);
+	PurpleMD5HashPrivate *priv = PURPLE_MD5_HASH_GET_PRIVATE(md5_hash);
+
+	g_return_if_fail(priv != NULL);
+	g_return_if_fail(priv->checksum != NULL);
+
+	g_checksum_reset(priv->checksum);
+}
+
+static void
+purple_md5_hash_append(PurpleHash *hash, const guchar *data,
+								gsize len)
+{
+	PurpleMD5Hash *md5_hash = PURPLE_MD5_HASH(hash);
+	PurpleMD5HashPrivate *priv = PURPLE_MD5_HASH_GET_PRIVATE(md5_hash);
+
+	g_return_if_fail(priv != NULL);
+	g_return_if_fail(priv->checksum != NULL);
+
+	while (len >= G_MAXSSIZE) {
+		g_checksum_update(priv->checksum, data, G_MAXSSIZE);
+		len -= G_MAXSSIZE;
+		data += G_MAXSSIZE;
+	}
+
+	if (len)
+		g_checksum_update(priv->checksum, data, len);
+}
+
+static gboolean
+purple_md5_hash_digest(PurpleHash *hash, guchar *digest, size_t buff_len)
+{
+	PurpleMD5Hash *md5_hash = PURPLE_MD5_HASH(hash);
+	PurpleMD5HashPrivate *priv = PURPLE_MD5_HASH_GET_PRIVATE(md5_hash);
+
+	const gssize required_len = g_checksum_type_get_length(G_CHECKSUM_MD5);
+	gsize digest_len = buff_len;
+
+	g_return_val_if_fail(priv != NULL, FALSE);
+	g_return_val_if_fail(priv->checksum != NULL, FALSE);
+	g_return_val_if_fail(buff_len >= required_len, FALSE);
+
+	g_checksum_get_digest(priv->checksum, digest, &digest_len);
+
+	if (digest_len != required_len)
+		return FALSE;
+
+	purple_md5_hash_reset(hash);
+
+	return TRUE;
+}
+
+static size_t
+purple_md5_hash_get_block_size(PurpleHash *hash)
+{
+	return 64;
+}
+
+static size_t
+purple_md5_hash_get_digest_size(PurpleHash *hash)
+{
+	return g_checksum_type_get_length(G_CHECKSUM_MD5);
+}
+
+static const gchar*
+purple_md5_hash_get_name(PurpleHash *hash)
+{
+	return "md5";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+
+static void
+purple_md5_hash_finalize(GObject *obj)
+{
+	PurpleMD5Hash *md5_hash = PURPLE_MD5_HASH(obj);
+	PurpleMD5HashPrivate *priv = PURPLE_MD5_HASH_GET_PRIVATE(md5_hash);
+
+	if (priv->checksum)
+		g_checksum_free(priv->checksum);
+
+	parent_class->finalize(obj);
+}
+
+static void
+purple_md5_hash_class_init(PurpleMD5HashClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleHashClass *hash_class = PURPLE_HASH_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	obj_class->finalize = purple_md5_hash_finalize;
+
+	hash_class->reset = purple_md5_hash_reset;
+	hash_class->reset_state = purple_md5_hash_reset;
+	hash_class->append = purple_md5_hash_append;
+	hash_class->digest = purple_md5_hash_digest;
+	hash_class->get_digest_size = purple_md5_hash_get_digest_size;
+	hash_class->get_block_size = purple_md5_hash_get_block_size;
+	hash_class->get_name = purple_md5_hash_get_name;
+
+	g_type_class_add_private(klass, sizeof(PurpleMD5HashPrivate));
+}
+
+static void
+purple_md5_hash_init(PurpleHash *hash)
+{
+	PurpleMD5Hash *md5_hash = PURPLE_MD5_HASH(hash);
+	PurpleMD5HashPrivate *priv = PURPLE_MD5_HASH_GET_PRIVATE(md5_hash);
+
+	priv->checksum = g_checksum_new(G_CHECKSUM_MD5);
+
+	purple_md5_hash_reset(hash);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_md5_hash_get_gtype(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleMD5HashClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_md5_hash_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleMD5Hash),
+			0,
+			(GInstanceInitFunc)purple_md5_hash_init,
+			NULL,
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_HASH,
+									  "PurpleMD5Hash",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+PurpleHash *
+purple_md5_hash_new(void) {
+	return g_object_new(PURPLE_TYPE_MD5_HASH, NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/md5hash.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,67 @@
+/**
+ * @file md5.h Purple MD5 Hash
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_MD5_HASH_H
+#define PURPLE_MD5_HASH_H
+
+#include "hash.h"
+
+#define PURPLE_TYPE_MD5_HASH				(purple_md5_hash_get_gtype())
+#define PURPLE_MD5_HASH(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MD5_HASH, PurpleMD5Hash))
+#define PURPLE_MD5_HASH_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MD5_HASH, PurpleMD5HashClass))
+#define PURPLE_IS_MD5_HASH(obj)				(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MD5_HASH))
+#define PURPLE_IS_MD5_HASH_CLASS(klass)		(G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_MD5_HASH))
+#define PURPLE_MD5_HASH_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MD5_HASH, PurpleMD5HashClass))
+
+typedef struct _PurpleMD5Hash				PurpleMD5Hash;
+typedef struct _PurpleMD5HashClass			PurpleMD5HashClass;
+
+struct _PurpleMD5Hash {
+	PurpleHash gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurpleMD5HashClass {
+	PurpleHashClass gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_md5_hash_get_gtype(void);
+
+PurpleHash *purple_md5_hash_new(void);
+
+G_END_DECLS
+
+#endif /* PURPLE_MD5_HASH_H */
--- a/libpurple/ciphers/pbkdf2.c	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,323 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- *
- * Written by Tomek Wasilczyk <tomkiewicz@cpw.pidgin.im>
- */
-
-#include "internal.h"
-#include "cipher.h"
-#include "ciphers.h"
-#include "debug.h"
-
-/* 1024bit */
-#define PBKDF2_HASH_MAX_LEN 128
-
-typedef struct
-{
-	gchar *hash_func;
-	guint iter_count;
-	size_t out_len;
-
-	guchar *salt;
-	size_t salt_len;
-	guchar *passphrase;
-	size_t passphrase_len;
-} Pbkdf2Context;
-
-static void
-purple_pbkdf2_init(PurpleCipherContext *context, void *extra)
-{
-	Pbkdf2Context *ctx_data;
-
-	ctx_data = g_new0(Pbkdf2Context, 1);
-	purple_cipher_context_set_data(context, ctx_data);
-
-	purple_cipher_context_reset(context, extra);
-}
-
-static void
-purple_pbkdf2_uninit(PurpleCipherContext *context)
-{
-	Pbkdf2Context *ctx_data;
-
-	purple_cipher_context_reset(context, NULL);
-
-	ctx_data = purple_cipher_context_get_data(context);
-	g_free(ctx_data);
-	purple_cipher_context_set_data(context, NULL);
-}
-
-static void
-purple_pbkdf2_reset(PurpleCipherContext *context, void *extra)
-{
-	Pbkdf2Context *ctx_data = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(ctx_data != NULL);
-
-	g_free(ctx_data->hash_func);
-	ctx_data->hash_func = NULL;
-	ctx_data->iter_count = 1;
-	ctx_data->out_len = 256;
-
-	purple_cipher_context_reset_state(context, extra);
-}
-
-static void
-purple_pbkdf2_reset_state(PurpleCipherContext *context, void *extra)
-{
-	Pbkdf2Context *ctx_data = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(ctx_data != NULL);
-
-	purple_cipher_context_set_salt(context, NULL, 0);
-	purple_cipher_context_set_key(context, NULL, 0);
-}
-
-static void
-purple_pbkdf2_set_option(PurpleCipherContext *context, const gchar *name,
-	void *value)
-{
-	Pbkdf2Context *ctx_data = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(ctx_data != NULL);
-
-	if (g_strcmp0(name, "hash") == 0) {
-		g_free(ctx_data->hash_func);
-		ctx_data->hash_func = g_strdup(value);
-		return;
-	}
-
-	if (g_strcmp0(name, "iter_count") == 0) {
-		ctx_data->iter_count = GPOINTER_TO_UINT(value);
-		return;
-	}
-
-	if (g_strcmp0(name, "out_len") == 0) {
-		ctx_data->out_len = GPOINTER_TO_UINT(value);
-		return;
-	}
-
-	purple_debug_warning("pbkdf2", "Unknown option: %s\n",
-		name ? name : "(null)");
-}
-
-static void *
-purple_pbkdf2_get_option(PurpleCipherContext *context, const gchar *name)
-{
-	Pbkdf2Context *ctx_data = purple_cipher_context_get_data(context);
-
-	g_return_val_if_fail(ctx_data != NULL, NULL);
-
-	if (g_strcmp0(name, "hash") == 0)
-		return ctx_data->hash_func;
-
-	if (g_strcmp0(name, "iter_count") == 0)
-		return GUINT_TO_POINTER(ctx_data->iter_count);
-
-	if (g_strcmp0(name, "out_len") == 0)
-		return GUINT_TO_POINTER(ctx_data->out_len);
-
-	purple_debug_warning("pbkdf2", "Unknown option: %s\n",
-		name ? name : "(null)");
-	return NULL;
-}
-
-static size_t
-purple_pbkdf2_get_digest_size(PurpleCipherContext *context)
-{
-	Pbkdf2Context *ctx_data = purple_cipher_context_get_data(context);
-
-	g_return_val_if_fail(ctx_data != NULL, 0);
-
-	return ctx_data->out_len;
-}
-
-static void
-purple_pbkdf2_set_salt(PurpleCipherContext *context, const guchar *salt, size_t len)
-{
-	Pbkdf2Context *ctx_data = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(ctx_data != NULL);
-
-	g_free(ctx_data->salt);
-	ctx_data->salt = NULL;
-	ctx_data->salt_len = 0;
-
-	if (len == 0)
-		return;
-	g_return_if_fail(salt != NULL);
-
-	ctx_data->salt = g_memdup(salt, len);
-	ctx_data->salt_len = len;
-}
-
-static void
-purple_pbkdf2_set_key(PurpleCipherContext *context, const guchar *key,
-	size_t len)
-{
-	Pbkdf2Context *ctx_data = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(ctx_data != NULL);
-
-	if (ctx_data->passphrase != NULL) {
-		memset(ctx_data->passphrase, 0, ctx_data->passphrase_len);
-		g_free(ctx_data->passphrase);
-		ctx_data->passphrase = NULL;
-	}
-	ctx_data->passphrase_len = 0;
-
-	if (len == 0)
-		return;
-	g_return_if_fail(key != NULL);
-
-	ctx_data->passphrase = g_memdup(key, len);
-	ctx_data->passphrase_len = len;
-}
-
-/* inspired by gnutls 3.1.10, pbkdf2-sha1.c */
-static gboolean
-purple_pbkdf2_digest(PurpleCipherContext *context, guchar digest[], size_t len)
-{
-	Pbkdf2Context *ctx_data = purple_cipher_context_get_data(context);
-	guchar halfkey[PBKDF2_HASH_MAX_LEN], halfkey_hash[PBKDF2_HASH_MAX_LEN];
-	guint halfkey_len, halfkey_count, halfkey_pad, halfkey_no;
-	guchar *salt_ext;
-	size_t salt_ext_len;
-	guint iter_no;
-	PurpleCipherContext *hash;
-
-	g_return_val_if_fail(ctx_data != NULL, FALSE);
-	g_return_val_if_fail(digest != NULL, FALSE);
-	g_return_val_if_fail(len >= ctx_data->out_len, FALSE);
-
-	g_return_val_if_fail(ctx_data->hash_func != NULL, FALSE);
-	g_return_val_if_fail(ctx_data->iter_count > 0, FALSE);
-	g_return_val_if_fail(ctx_data->passphrase != NULL ||
-		ctx_data->passphrase_len == 0, FALSE);
-	g_return_val_if_fail(ctx_data->salt != NULL || ctx_data->salt_len == 0,
-		FALSE);
-	g_return_val_if_fail(ctx_data->out_len > 0, FALSE);
-	g_return_val_if_fail(ctx_data->out_len < 0xFFFFFFFFU, FALSE);
-
-	salt_ext_len = ctx_data->salt_len + 4;
-
-	hash = purple_cipher_context_new_by_name("hmac", NULL);
-	if (hash == NULL) {
-		purple_debug_error("pbkdf2", "Couldn't create new hmac "
-			"context\n");
-		return FALSE;
-	}
-	purple_cipher_context_set_option(hash, "hash",
-		(void*)ctx_data->hash_func);
-	purple_cipher_context_set_key(hash, (const guchar*)ctx_data->passphrase,
-		ctx_data->passphrase_len);
-
-	halfkey_len = purple_cipher_context_get_digest_size(hash);
-	if (halfkey_len <= 0 || halfkey_len > PBKDF2_HASH_MAX_LEN) {
-		purple_debug_error("pbkdf2", "Unsupported hash function: %s "
-			"(digest size: %d)\n",
-			ctx_data->hash_func ? ctx_data->hash_func : "(null)",
-			halfkey_len);
-		return FALSE;
-	}
-
-	halfkey_count = ((ctx_data->out_len - 1) / halfkey_len) + 1;
-	halfkey_pad = ctx_data->out_len - (halfkey_count - 1) * halfkey_len;
-
-	salt_ext = g_new(guchar, salt_ext_len);
-	memcpy(salt_ext, ctx_data->salt, ctx_data->salt_len);
-
-	for (halfkey_no = 1; halfkey_no <= halfkey_count; halfkey_no++) {
-		memset(halfkey, 0, halfkey_len);
-
-		for (iter_no = 1; iter_no <= ctx_data->iter_count; iter_no++) {
-			int i;
-
-			purple_cipher_context_reset_state(hash, NULL);
-
-			if (iter_no == 1) {
-				salt_ext[salt_ext_len - 4] =
-					(halfkey_no & 0xff000000) >> 24;
-				salt_ext[salt_ext_len - 3] =
-					(halfkey_no & 0x00ff0000) >> 16;
-				salt_ext[salt_ext_len - 2] =
-					(halfkey_no & 0x0000ff00) >> 8;
-				salt_ext[salt_ext_len - 1] =
-					(halfkey_no & 0x000000ff) >> 0;
-
-				purple_cipher_context_append(hash, salt_ext,
-					salt_ext_len);
-			}
-			else
-				purple_cipher_context_append(hash, halfkey_hash,
-					halfkey_len);
-
-			if (!purple_cipher_context_digest(hash, halfkey_hash,
-				halfkey_len)) {
-				purple_debug_error("pbkdf2",
-					"Couldn't retrieve a digest\n");
-				g_free(salt_ext);
-				purple_cipher_context_destroy(hash);
-				return FALSE;
-			}
-
-			for (i = 0; i < halfkey_len; i++)
-				halfkey[i] ^= halfkey_hash[i];
-		}
-
-		memcpy(digest + (halfkey_no - 1) * halfkey_len, halfkey,
-			(halfkey_no == halfkey_count) ? halfkey_pad :
-				halfkey_len);
-	}
-
-	g_free(salt_ext);
-	purple_cipher_context_destroy(hash);
-
-	return TRUE;
-}
-
-static PurpleCipherOps PBKDF2Ops = {
-	purple_pbkdf2_set_option,      /* set_option */
-	purple_pbkdf2_get_option,      /* get_option */
-	purple_pbkdf2_init,            /* init */
-	purple_pbkdf2_reset,           /* reset */
-	purple_pbkdf2_reset_state,     /* reset_state */
-	purple_pbkdf2_uninit,          /* uninit */
-	NULL,                          /* set_iv */
-	NULL,                          /* append */
-	purple_pbkdf2_digest,          /* digest */
-	purple_pbkdf2_get_digest_size, /* get_digest_size */
-	NULL,                          /* encrypt */
-	NULL,                          /* decrypt */
-	purple_pbkdf2_set_salt,        /* set_salt */
-	NULL,                          /* get_salt_size */
-	purple_pbkdf2_set_key,         /* set_key */
-	NULL,                          /* get_key_size */
-	NULL,                          /* set_batch_mode */
-	NULL,                          /* get_batch_mode */
-	NULL,                          /* get_block_size */
-	NULL, NULL, NULL, NULL         /* reserved */
-};
-
-PurpleCipherOps *
-purple_pbkdf2_cipher_get_ops(void) {
-	return &PBKDF2Ops;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/pbkdf2cipher.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,418 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ * Written by Tomek Wasilczyk <tomkiewicz@cpw.pidgin.im>
+ */
+
+#include "pbkdf2cipher.h"
+#include "hmaccipher.h"
+#include "debug.h"
+
+/* 1024bit */
+#define PBKDF2_HASH_MAX_LEN 128
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+#define PURPLE_PBKDF2_CIPHER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_PBKDF2_CIPHER, PurplePBKDF2CipherPrivate))
+
+typedef struct {
+	PurpleHash *hash;
+	guint iter_count;
+	size_t out_len;
+
+	guchar *salt;
+	size_t salt_len;
+	guchar *passphrase;
+	size_t passphrase_len;
+} PurplePBKDF2CipherPrivate;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+	PROP_NONE,
+	PROP_HASH,
+	PROP_ITER_COUNT,
+	PROP_OUT_LEN,
+	PROP_LAST,
+};
+
+/*******************************************************************************
+ * Globals
+ ******************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/*******************************************************************************
+ * Helpers
+ ******************************************************************************/
+static void
+purple_pbkdf2_cipher_set_hash(PurpleCipher *cipher,
+								PurpleHash *hash)
+{
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	priv->hash = g_object_ref(G_OBJECT(hash));
+	g_object_notify(G_OBJECT(cipher), "hash");
+}
+
+/******************************************************************************
+ * Cipher Stuff
+ *****************************************************************************/
+static void
+purple_pbkdf2_cipher_reset(PurpleCipher *cipher)
+{
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	g_return_if_fail(priv != NULL);
+
+	if(PURPLE_IS_HASH(priv->hash))
+		purple_hash_reset(priv->hash);
+	priv->iter_count = 1;
+	priv->out_len = 256;
+
+	purple_cipher_reset_state(cipher);
+}
+
+static void
+purple_pbkdf2_cipher_reset_state(PurpleCipher *cipher)
+{
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	g_return_if_fail(priv != NULL);
+
+	purple_cipher_set_salt(cipher, NULL, 0);
+	purple_cipher_set_key(cipher, NULL, 0);
+}
+
+static size_t
+purple_pbkdf2_cipher_get_digest_size(PurpleCipher *cipher)
+{
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	g_return_val_if_fail(priv != NULL, 0);
+
+	return priv->out_len;
+}
+
+static void
+purple_pbkdf2_cipher_set_salt(PurpleCipher *cipher, const guchar *salt, size_t len)
+{
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	g_return_if_fail(priv != NULL);
+
+	g_free(priv->salt);
+	priv->salt = NULL;
+	priv->salt_len = 0;
+
+	if (len == 0)
+		return;
+	g_return_if_fail(salt != NULL);
+
+	priv->salt = g_memdup(salt, len);
+	priv->salt_len = len;
+}
+
+static void
+purple_pbkdf2_cipher_set_key(PurpleCipher *cipher, const guchar *key,
+	size_t len)
+{
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	g_return_if_fail(priv != NULL);
+
+	if (priv->passphrase != NULL) {
+		memset(priv->passphrase, 0, priv->passphrase_len);
+		g_free(priv->passphrase);
+		priv->passphrase = NULL;
+	}
+	priv->passphrase_len = 0;
+
+	if (len == 0)
+		return;
+	g_return_if_fail(key != NULL);
+
+	priv->passphrase = g_memdup(key, len);
+	priv->passphrase_len = len;
+}
+
+/* inspired by gnutls 3.1.10, pbkdf2-sha1.c */
+static gboolean
+purple_pbkdf2_cipher_digest(PurpleCipher *cipher, guchar digest[], size_t len)
+{
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	guchar halfkey[PBKDF2_HASH_MAX_LEN], halfkey_hash[PBKDF2_HASH_MAX_LEN];
+	guint halfkey_len, halfkey_count, halfkey_pad, halfkey_no;
+	guchar *salt_ext;
+	size_t salt_ext_len;
+	guint iter_no;
+	PurpleCipher *hash;
+
+	g_return_val_if_fail(priv != NULL, FALSE);
+	g_return_val_if_fail(digest != NULL, FALSE);
+	g_return_val_if_fail(len >= priv->out_len, FALSE);
+
+	g_return_val_if_fail(priv->hash != NULL, FALSE);
+	g_return_val_if_fail(priv->iter_count > 0, FALSE);
+	g_return_val_if_fail(priv->passphrase != NULL ||
+		priv->passphrase_len == 0, FALSE);
+	g_return_val_if_fail(priv->salt != NULL || priv->salt_len == 0,
+		FALSE);
+	g_return_val_if_fail(priv->out_len > 0, FALSE);
+	g_return_val_if_fail(priv->out_len < 0xFFFFFFFFU, FALSE);
+
+	salt_ext_len = priv->salt_len + 4;
+
+	hash = purple_hmac_cipher_new(priv->hash);
+	if (hash == NULL) {
+		purple_debug_error("pbkdf2", "Couldn't create new hmac "
+			"cipher\n");
+		return FALSE;
+	}
+	purple_cipher_set_key(hash, (const guchar*)priv->passphrase,
+		priv->passphrase_len);
+
+	halfkey_len = purple_cipher_get_digest_size(hash);
+	if (halfkey_len <= 0 || halfkey_len > PBKDF2_HASH_MAX_LEN) {
+		purple_debug_error("pbkdf2", "Unsupported hash function. "
+			"(digest size: %d)\n", halfkey_len);
+		return FALSE;
+	}
+
+	halfkey_count = ((priv->out_len - 1) / halfkey_len) + 1;
+	halfkey_pad = priv->out_len - (halfkey_count - 1) * halfkey_len;
+
+	salt_ext = g_new(guchar, salt_ext_len);
+	memcpy(salt_ext, priv->salt, priv->salt_len);
+
+	for (halfkey_no = 1; halfkey_no <= halfkey_count; halfkey_no++) {
+		memset(halfkey, 0, halfkey_len);
+
+		for (iter_no = 1; iter_no <= priv->iter_count; iter_no++) {
+			int i;
+
+			purple_cipher_reset_state(hash);
+
+			if (iter_no == 1) {
+				salt_ext[salt_ext_len - 4] =
+					(halfkey_no & 0xff000000) >> 24;
+				salt_ext[salt_ext_len - 3] =
+					(halfkey_no & 0x00ff0000) >> 16;
+				salt_ext[salt_ext_len - 2] =
+					(halfkey_no & 0x0000ff00) >> 8;
+				salt_ext[salt_ext_len - 1] =
+					(halfkey_no & 0x000000ff) >> 0;
+
+				purple_cipher_append(hash, salt_ext,
+					salt_ext_len);
+			}
+			else
+				purple_cipher_append(hash, halfkey_hash,
+					halfkey_len);
+
+			if (!purple_cipher_digest(hash, halfkey_hash,
+				halfkey_len)) {
+				purple_debug_error("pbkdf2",
+					"Couldn't retrieve a digest\n");
+				g_free(salt_ext);
+				g_object_unref(hash);
+				return FALSE;
+			}
+
+			for (i = 0; i < halfkey_len; i++)
+				halfkey[i] ^= halfkey_hash[i];
+		}
+
+		memcpy(digest + (halfkey_no - 1) * halfkey_len, halfkey,
+			(halfkey_no == halfkey_count) ? halfkey_pad :
+				halfkey_len);
+	}
+
+	g_free(salt_ext);
+	g_object_unref(hash);
+
+	return TRUE;
+}
+
+static const gchar*
+purple_pbkdf2_cipher_get_name(PurpleCipher *cipher)
+{
+	return "pbkdf2";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_pbkdf2_cipher_get_property(GObject *obj, guint param_id, GValue *value,
+								GParamSpec *pspec)
+{
+	PurplePBKDF2Cipher *cipher = PURPLE_PBKDF2_CIPHER(obj);
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	switch(param_id) {
+		case PROP_HASH:
+			g_value_set_object(value, purple_pbkdf2_cipher_get_hash(cipher));
+			break;
+		case PROP_ITER_COUNT:
+			g_value_set_uint(value, priv->iter_count);
+			break;
+		case PROP_OUT_LEN:
+			g_value_set_uint(value, priv->out_len);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_pbkdf2_cipher_set_property(GObject *obj, guint param_id,
+								const GValue *value, GParamSpec *pspec)
+{
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	switch(param_id) {
+		case PROP_HASH:
+			purple_pbkdf2_cipher_set_hash(cipher, g_value_get_object(value));
+			break;
+		case PROP_ITER_COUNT:
+			priv->iter_count = GPOINTER_TO_UINT(value);
+			break;
+		case PROP_OUT_LEN:
+			priv->out_len = GPOINTER_TO_UINT(value);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_pbkdf2_cipher_finalize(GObject *obj)
+{
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+	PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	purple_pbkdf2_cipher_reset(cipher);
+
+	if (priv->hash != NULL)
+		g_object_unref(priv->hash);
+
+	parent_class->finalize(obj);
+}
+
+static void
+purple_pbkdf2_cipher_class_init(PurplePBKDF2CipherClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
+	GParamSpec *pspec;
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	obj_class->finalize = purple_pbkdf2_cipher_finalize;
+	obj_class->get_property = purple_pbkdf2_cipher_get_property;
+	obj_class->set_property = purple_pbkdf2_cipher_set_property;
+
+	cipher_class->reset = purple_pbkdf2_cipher_reset;
+	cipher_class->reset_state = purple_pbkdf2_cipher_reset_state;
+	cipher_class->digest = purple_pbkdf2_cipher_digest;
+	cipher_class->get_digest_size = purple_pbkdf2_cipher_get_digest_size;
+	cipher_class->set_salt = purple_pbkdf2_cipher_set_salt;
+	cipher_class->set_key = purple_pbkdf2_cipher_set_key;
+	cipher_class->get_name = purple_pbkdf2_cipher_get_name;
+
+	pspec = g_param_spec_object("hash", "hash", "hash", PURPLE_TYPE_HASH,
+								G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+	g_object_class_install_property(obj_class, PROP_HASH, pspec);
+
+	pspec = g_param_spec_uint("iter_count", "iter_count", "iter_count", 0,
+								G_MAXUINT, 0, G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_ITER_COUNT, pspec);
+
+	pspec = g_param_spec_uint("out_len", "out_len", "out_len", 0,
+								G_MAXUINT, 0, G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_OUT_LEN, pspec);
+
+	g_type_class_add_private(klass, sizeof(PurplePBKDF2CipherPrivate));
+}
+
+static void
+purple_pbkdf2_cipher_init(PurpleCipher *cipher)
+{
+	purple_cipher_reset(cipher);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_pbkdf2_cipher_get_gtype(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurplePBKDF2CipherClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_pbkdf2_cipher_class_init,
+			NULL,
+			NULL,
+			sizeof(PurplePBKDF2Cipher),
+			0,
+			(GInstanceInitFunc)purple_pbkdf2_cipher_init,
+			NULL
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_CIPHER,
+									  "PurplePBKDF2Cipher",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+PurpleCipher *
+purple_pbkdf2_cipher_new(PurpleHash *hash) {
+	g_return_val_if_fail(PURPLE_IS_HASH(hash), NULL);
+
+	return g_object_new(PURPLE_TYPE_PBKDF2_CIPHER,
+						"hash", hash,
+						NULL);
+}
+
+PurpleHash *
+purple_pbkdf2_cipher_get_hash(const PurplePBKDF2Cipher *cipher) {
+	PurplePBKDF2CipherPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PBKDF2_CIPHER(cipher), NULL);
+
+	priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	if(priv && priv->hash)
+		return priv->hash;
+
+	return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/pbkdf2cipher.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,71 @@
+/**
+ * @file pbkdf2.h Purple PBKDF2 Cipher
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_PBKDF2_CIPHER_H
+#define PURPLE_PBKDF2_CIPHER_H
+
+#include "cipher.h"
+#include "hash.h"
+
+#define PURPLE_TYPE_PBKDF2_CIPHER				(purple_pbkdf2_cipher_get_gtype())
+#define PURPLE_PBKDF2_CIPHER(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_PBKDF2_CIPHER, PurplePBKDF2Cipher))
+#define PURPLE_PBKDF2_CIPHER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_PBKDF2_CIPHER, PurplePBKDF2CipherClass))
+#define PURPLE_IS_PBKDF2_CIPHER(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_PBKDF2_CIPHER))
+#define PURPLE_IS_PBKDF2_CIPHER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_PBKDF2_CIPHER))
+#define PURPLE_PBKDF2_CIPHER_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_PBKDF2_CIPHER, PurplePBKDF2CipherClass))
+
+typedef struct _PurplePBKDF2Cipher			PurplePBKDF2Cipher;
+typedef struct _PurplePBKDF2CipherClass		PurplePBKDF2CipherClass;
+
+struct _PurplePBKDF2Cipher {
+	PurpleCipher gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurplePBKDF2CipherClass {
+	PurpleCipherClass gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_pbkdf2_cipher_get_gtype(void);
+
+PurpleCipher *purple_pbkdf2_cipher_new(PurpleHash *hash);
+
+PurpleHash *purple_pbkdf2_cipher_get_hash(const PurplePBKDF2Cipher *cipher);
+
+G_END_DECLS
+
+#endif /* PURPLE_PBKDF2_CIPHER_H */
+
--- a/libpurple/ciphers/rc4.c	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#include "internal.h"
-#include <cipher.h>
-#include "ciphers.h"
-#include <util.h>
-
-struct RC4Context {
-	guchar state[256];
-	guchar x;
-	guchar y;
-	gint key_len;
-};
-
-static void
-rc4_init(PurpleCipherContext *context, void *extra) {
-	struct RC4Context *rc4_ctx;
-	rc4_ctx = g_new0(struct RC4Context, 1);
-	purple_cipher_context_set_data(context, rc4_ctx);
-	purple_cipher_context_reset(context, extra);
-}
-
-
-static void
-rc4_reset(PurpleCipherContext *context, void *extra) {
-	struct RC4Context *rc4_ctx;
-	guint i;
-
-	rc4_ctx = purple_cipher_context_get_data(context);
-
-	g_return_if_fail(rc4_ctx);
-
-	for(i = 0; i < 256; i++)
-		rc4_ctx->state[i] = i;
-	rc4_ctx->x = 0;
-	rc4_ctx->y = 0;
-
-	/* default is 5 bytes (40bit key) */
-	rc4_ctx->key_len = 5;
-
-}
-
-static void
-rc4_uninit(PurpleCipherContext *context) {
-	struct RC4Context *rc4_ctx;
-
-	rc4_ctx = purple_cipher_context_get_data(context);
-	memset(rc4_ctx, 0, sizeof(*rc4_ctx));
-
-	g_free(rc4_ctx);
-	rc4_ctx = NULL;
-}
-
-
-
-static void
-rc4_set_key (PurpleCipherContext *context, const guchar * key, size_t len) {
-	struct RC4Context *ctx;
-	guchar *state;
-	guchar temp_swap;
-	guchar x, y;
-	guint i;
-
-	ctx = purple_cipher_context_get_data(context);
-
-	x = 0;
-	y = 0;
-	state = &ctx->state[0];
-	ctx->key_len = len;
-	for(i = 0; i < 256; i++)
-	{
-		y = (key[x] + state[i] + y) % 256;
-		temp_swap = state[i];
-		state[i] = state[y];
-		state[y] = temp_swap;
-		x = (x + 1) % len;
-	}
-}
-
-
-static ssize_t
-rc4_encrypt(PurpleCipherContext *context, const guchar input[], size_t in_len,
-	guchar output[], size_t out_size) {
-	struct RC4Context *ctx;
-	guchar temp_swap;
-	guchar x, y, z;
-	guchar *state;
-	guint i;
-
-	ctx = purple_cipher_context_get_data(context);
-
-	x = ctx->x;
-	y = ctx->y;
-	state = &ctx->state[0];
-
-	for(i = 0; i < in_len; i++)
-	{
-		x = (x + 1) % 256;
-		y = (state[x] + y) % 256;
-		temp_swap = state[x];
-		state[x] = state[y];
-		state[y] = temp_swap;
-		z = state[x] + (state[y]) % 256;
-		output[i] = input[i] ^ state[z];
-	}
-	ctx->x = x;
-	ctx->y = y;
-
-	return in_len;
-}
-
-static PurpleCipherOps RC4Ops = {
-	NULL,          /* Set Option    */
-	NULL,          /* Get Option    */
-	rc4_init,      /* init          */
-	rc4_reset,     /* reset         */
-	NULL,          /* reset state   */
-	rc4_uninit,    /* uninit        */
-	NULL,          /* set iv        */
-	NULL,          /* append        */
-	NULL,          /* digest        */
-	NULL,          /* get digest size */
-	rc4_encrypt,   /* encrypt       */
-	NULL,          /* decrypt       */
-	NULL,          /* set salt      */
-	NULL,          /* get salt size */
-	rc4_set_key,   /* set key       */
-	NULL,          /* get key size  */
-	NULL,          /* set batch mode */
-	NULL,          /* get batch mode */
-	NULL,          /* get block size */
-	NULL, NULL, NULL, NULL /* reserved */
-};
-
-PurpleCipherOps *
-purple_rc4_cipher_get_ops(void) {
-	return &RC4Ops;
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/rc4cipher.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,266 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "rc4cipher.h"
+
+/*******************************************************************************
+ * Structs
+ ******************************************************************************/
+#define PURPLE_RC4_CIPHER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_RC4_CIPHER, PurpleRC4CipherPrivate))
+
+typedef struct {
+  guchar state[256];
+  guchar x;
+  guchar y;
+  gint key_len;
+} PurpleRC4CipherPrivate;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+	PROP_ZERO,
+	PROP_KEY_LEN,
+	PROP_KEY,
+	PROP_LAST,
+};
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Cipher Stuff
+ *****************************************************************************/
+static void
+purple_rc4_cipher_reset(PurpleCipher *cipher) {
+	PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(cipher);
+	PurpleRC4CipherPrivate *priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
+	guint i;
+
+	for(i = 0; i < 256; i++)
+		priv->state[i] = i;
+	priv->x = 0;
+	priv->y = 0;
+
+	/* default is 5 bytes (40bit key) */
+	priv->key_len = 5;
+}
+
+static void
+purple_rc4_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len) {
+	PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(cipher);
+	PurpleRC4CipherPrivate *priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
+	guchar *state;
+	guchar temp_swap;
+	guchar x, y;
+	guint i;
+
+	x = 0;
+	y = 0;
+	state = &priv->state[0];
+	priv->key_len = len;
+	for(i = 0; i < 256; i++)
+	{
+		y = (key[x] + state[i] + y) % 256;
+		temp_swap = state[i];
+		state[i] = state[y];
+		state[y] = temp_swap;
+		x = (x + 1) % len;
+	}
+
+	g_object_notify(G_OBJECT(rc4_cipher), "key");
+}
+
+static ssize_t
+purple_rc4_cipher_encrypt(PurpleCipher *cipher, const guchar input[], size_t in_len,
+							guchar output[], size_t out_size)
+{
+	PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(cipher);
+	guchar temp_swap;
+	guchar x, y, z;
+	guchar *state;
+	guint i;
+	PurpleRC4CipherPrivate *priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
+
+	x = priv->x;
+	y = priv->y;
+	state = &priv->state[0];
+
+	for(i = 0; i < in_len; i++)
+	{
+		x = (x + 1) % 256;
+		y = (state[x] + y) % 256;
+		temp_swap = state[x];
+		state[x] = state[y];
+		state[y] = temp_swap;
+		z = state[x] + (state[y]) % 256;
+		output[i] = input[i] ^ state[z];
+	}
+	priv->x = x;
+	priv->y = y;
+
+	return in_len;
+}
+
+static const gchar*
+purple_rc4_cipher_get_name(PurpleCipher *cipher)
+{
+	return "rc4";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_rc4_cipher_set_property(GObject *obj, guint param_id,
+							   const GValue *value, GParamSpec *pspec)
+{
+	PurpleCipher *cipher = PURPLE_CIPHER(obj);
+	PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(obj);
+
+	switch(param_id) {
+		case PROP_KEY_LEN:
+			purple_rc4_cipher_set_key_len(rc4_cipher, g_value_get_int(value));
+			break;
+		case PROP_KEY:
+			{
+				guchar *key = (guchar *)g_value_get_string(value);
+				purple_rc4_cipher_set_key(cipher, key, strlen((gchar *) key));
+			}
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_rc4_cipher_get_property(GObject *obj, guint param_id, GValue *value,
+							   GParamSpec *pspec)
+{
+	PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(obj);
+
+	switch(param_id) {
+		case PROP_KEY_LEN:
+			g_value_set_int(value,
+							purple_rc4_cipher_get_key_len(rc4_cipher));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_rc4_cipher_class_init(PurpleRC4CipherClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
+	GParamSpec *pspec = NULL;
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	obj_class->set_property = purple_rc4_cipher_set_property;
+	obj_class->get_property = purple_rc4_cipher_get_property;
+
+	cipher_class->reset = purple_rc4_cipher_reset;
+	cipher_class->encrypt = purple_rc4_cipher_encrypt;
+	cipher_class->set_key = purple_rc4_cipher_set_key;
+	cipher_class->get_name = purple_rc4_cipher_get_name;
+
+	pspec = g_param_spec_int("key_len", "key_len", "key_len",
+							 G_MININT, G_MAXINT, 0,
+							 G_PARAM_READWRITE);
+	g_object_class_install_property(obj_class, PROP_KEY_LEN, pspec);
+
+	pspec = g_param_spec_string("key", "key", "key", NULL,
+								G_PARAM_WRITABLE);
+	g_object_class_install_property(obj_class, PROP_KEY, pspec);
+
+	g_type_class_add_private(klass, sizeof(PurpleRC4CipherPrivate));
+}
+
+static void
+purple_rc4_cipher_init(PurpleCipher *cipher) {
+	purple_rc4_cipher_reset(cipher);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_rc4_cipher_get_gtype(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleRC4CipherClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_rc4_cipher_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleRC4Cipher),
+			0,
+			(GInstanceInitFunc)purple_rc4_cipher_init,
+			NULL,
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_CIPHER,
+									  "PurpleRC4Cipher",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+PurpleCipher *
+purple_rc4_cipher_new(void) {
+	return g_object_new(PURPLE_TYPE_RC4_CIPHER, NULL);
+}
+
+void
+purple_rc4_cipher_set_key_len(PurpleRC4Cipher *rc4_cipher,
+							  gint key_len)
+{
+	PurpleRC4CipherPrivate *priv;
+
+	g_return_if_fail(PURPLE_IS_RC4_CIPHER(rc4_cipher));
+
+	priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
+	priv->key_len = key_len;
+
+	g_object_notify(G_OBJECT(rc4_cipher), "key_len");
+}
+
+gint
+purple_rc4_cipher_get_key_len(PurpleRC4Cipher *rc4_cipher)
+{
+	PurpleRC4CipherPrivate *priv;
+
+	g_return_val_if_fail(PURPLE_IS_RC4_CIPHER(rc4_cipher), 0);
+
+	priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
+
+	return priv->key_len;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/rc4cipher.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,72 @@
+/**
+ * @file rc4.h Purple RC4 Cipher
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_RC4_CIPHER_H
+#define PURPLE_RC4_CIPHER_H
+
+#include "cipher.h"
+
+#define PURPLE_TYPE_RC4_CIPHER				(purple_rc4_cipher_get_gtype())
+#define PURPLE_RC4_CIPHER(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_RC4_CIPHER, PurpleRC4Cipher))
+#define PURPLE_RC4_CIPHER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_RC4_CIPHER, PurpleRC4CipherClass))
+#define PURPLE_IS_RC4_CIPHER(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_RC4_CIPHER))
+#define PURPLE_IS_RC4_CIPHER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_RC4_CIPHER))
+#define PURPLE_RC4_CIPHER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_RC4_CIPHER, PurpleRC4CipherClass))
+
+typedef struct _PurpleRC4Cipher				PurpleRC4Cipher;
+typedef struct _PurpleRC4CipherClass		PurpleRC4CipherClass;
+
+struct _PurpleRC4Cipher {
+	PurpleCipher gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurpleRC4CipherClass {
+	PurpleCipherClass gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_rc4_cipher_get_gtype(void);
+
+PurpleCipher *purple_rc4_cipher_new(void);
+
+gint purple_rc4_cipher_get_key_len(PurpleRC4Cipher *rc4_cipher);
+void purple_rc4_cipher_set_key_len(PurpleRC4Cipher *rc4_cipher, gint key_len);
+
+G_END_DECLS
+
+#endif /* PURPLE_RC4_CIPHER_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/sha1hash.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,195 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "sha1hash.h"
+
+/*******************************************************************************
+ * Structs
+ ******************************************************************************/
+#define PURPLE_SHA1_HASH_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_SHA1_HASH, PurpleSHA1HashPrivate))
+
+typedef struct {
+  GChecksum *checksum;
+} PurpleSHA1HashPrivate;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Hash Stuff
+ *****************************************************************************/
+
+static void
+purple_sha1_hash_reset(PurpleHash *hash)
+{
+	PurpleSHA1Hash *sha1_hash = PURPLE_SHA1_HASH(hash);
+	PurpleSHA1HashPrivate *priv = PURPLE_SHA1_HASH_GET_PRIVATE(sha1_hash);
+
+	g_return_if_fail(priv != NULL);
+	g_return_if_fail(priv->checksum != NULL);
+
+	g_checksum_reset(priv->checksum);
+}
+
+static void
+purple_sha1_hash_append(PurpleHash *hash, const guchar *data,
+								gsize len)
+{
+	PurpleSHA1Hash *sha1_hash = PURPLE_SHA1_HASH(hash);
+	PurpleSHA1HashPrivate *priv = PURPLE_SHA1_HASH_GET_PRIVATE(sha1_hash);
+
+	g_return_if_fail(priv != NULL);
+	g_return_if_fail(priv->checksum != NULL);
+
+	while (len >= G_MAXSSIZE) {
+		g_checksum_update(priv->checksum, data, G_MAXSSIZE);
+		len -= G_MAXSSIZE;
+		data += G_MAXSSIZE;
+	}
+
+	if (len)
+		g_checksum_update(priv->checksum, data, len);
+}
+
+static gboolean
+purple_sha1_hash_digest(PurpleHash *hash, guchar *digest, size_t buff_len)
+{
+	PurpleSHA1Hash *sha1_hash = PURPLE_SHA1_HASH(hash);
+	PurpleSHA1HashPrivate *priv = PURPLE_SHA1_HASH_GET_PRIVATE(sha1_hash);
+
+	const gssize required_len = g_checksum_type_get_length(G_CHECKSUM_SHA1);
+	gsize digest_len = buff_len;
+
+	g_return_val_if_fail(priv != NULL, FALSE);
+	g_return_val_if_fail(priv->checksum != NULL, FALSE);
+	g_return_val_if_fail(buff_len >= required_len, FALSE);
+
+	g_checksum_get_digest(priv->checksum, digest, &digest_len);
+
+	if (digest_len != required_len)
+		return FALSE;
+
+	purple_sha1_hash_reset(hash);
+
+	return TRUE;
+}
+
+static size_t
+purple_sha1_hash_get_block_size(PurpleHash *hash)
+{
+	return 64;
+}
+
+static size_t
+purple_sha1_hash_get_digest_size(PurpleHash *hash)
+{
+	return g_checksum_type_get_length(G_CHECKSUM_SHA1);
+}
+
+static const gchar*
+purple_sha1_hash_get_name(PurpleHash *hash)
+{
+	return "sha1";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+
+static void
+purple_sha1_hash_finalize(GObject *obj)
+{
+	PurpleSHA1Hash *sha1_hash = PURPLE_SHA1_HASH(obj);
+	PurpleSHA1HashPrivate *priv = PURPLE_SHA1_HASH_GET_PRIVATE(sha1_hash);
+
+	if (priv->checksum)
+		g_checksum_free(priv->checksum);
+
+	parent_class->finalize(obj);
+}
+
+static void
+purple_sha1_hash_class_init(PurpleSHA1HashClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleHashClass *hash_class = PURPLE_HASH_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	obj_class->finalize = purple_sha1_hash_finalize;
+
+	hash_class->reset = purple_sha1_hash_reset;
+	hash_class->reset_state = purple_sha1_hash_reset;
+	hash_class->append = purple_sha1_hash_append;
+	hash_class->digest = purple_sha1_hash_digest;
+	hash_class->get_digest_size = purple_sha1_hash_get_digest_size;
+	hash_class->get_block_size = purple_sha1_hash_get_block_size;
+	hash_class->get_name = purple_sha1_hash_get_name;
+
+	g_type_class_add_private(klass, sizeof(PurpleSHA1HashPrivate));
+}
+
+static void
+purple_sha1_hash_init(PurpleHash *hash)
+{
+	PurpleSHA1Hash *sha1_hash = PURPLE_SHA1_HASH(hash);
+	PurpleSHA1HashPrivate *priv = PURPLE_SHA1_HASH_GET_PRIVATE(sha1_hash);
+
+	priv->checksum = g_checksum_new(G_CHECKSUM_SHA1);
+
+	purple_sha1_hash_reset(hash);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_sha1_hash_get_gtype(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleSHA1HashClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_sha1_hash_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleSHA1Hash),
+			0,
+			(GInstanceInitFunc)purple_sha1_hash_init,
+			NULL,
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_HASH,
+									  "PurpleSHA1Hash",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+PurpleHash *
+purple_sha1_hash_new(void) {
+	return g_object_new(PURPLE_TYPE_SHA1_HASH, NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/sha1hash.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,67 @@
+/**
+ * @file sha1.h Purple SHA1 Hash
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_SHA1_HASH_H
+#define PURPLE_SHA1_HASH_H
+
+#include "hash.h"
+
+#define PURPLE_TYPE_SHA1_HASH				(purple_sha1_hash_get_gtype())
+#define PURPLE_SHA1_HASH(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_SHA1_HASH, PurpleSHA1Hash))
+#define PURPLE_SHA1_HASH_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_SHA1_HASH, PurpleSHA1HashClass))
+#define PURPLE_IS_SHA1_HASH(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_SHA1_HASH))
+#define PURPLE_IS_SHA1_HASH_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_SHA1_HASH))
+#define PURPLE_SHA1_HASH_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_SHA1_HASH, PurpleSHA1HashClass))
+
+typedef struct _PurpleSHA1Hash				PurpleSHA1Hash;
+typedef struct _PurpleSHA1HashClass			PurpleSHA1HashClass;
+
+struct _PurpleSHA1Hash {
+	PurpleHash gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurpleSHA1HashClass {
+	PurpleHashClass gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_sha1_hash_get_gtype(void);
+
+PurpleHash *purple_sha1_hash_new(void);
+
+G_END_DECLS
+
+#endif /* PURPLE_SHA1_HASH_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/sha256hash.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,195 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "sha256hash.h"
+
+/*******************************************************************************
+ * Structs
+ ******************************************************************************/
+#define PURPLE_SHA256_HASH_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_SHA256_HASH, PurpleSHA256HashPrivate))
+
+typedef struct {
+  GChecksum *checksum;
+} PurpleSHA256HashPrivate;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Hash Stuff
+ *****************************************************************************/
+
+static void
+purple_sha256_hash_reset(PurpleHash *hash)
+{
+	PurpleSHA256Hash *sha256_hash = PURPLE_SHA256_HASH(hash);
+	PurpleSHA256HashPrivate *priv = PURPLE_SHA256_HASH_GET_PRIVATE(sha256_hash);
+
+	g_return_if_fail(priv != NULL);
+	g_return_if_fail(priv->checksum != NULL);
+
+	g_checksum_reset(priv->checksum);
+}
+
+static void
+purple_sha256_hash_append(PurpleHash *hash, const guchar *data,
+								gsize len)
+{
+	PurpleSHA256Hash *sha256_hash = PURPLE_SHA256_HASH(hash);
+	PurpleSHA256HashPrivate *priv = PURPLE_SHA256_HASH_GET_PRIVATE(sha256_hash);
+
+	g_return_if_fail(priv != NULL);
+	g_return_if_fail(priv->checksum != NULL);
+
+	while (len >= G_MAXSSIZE) {
+		g_checksum_update(priv->checksum, data, G_MAXSSIZE);
+		len -= G_MAXSSIZE;
+		data += G_MAXSSIZE;
+	}
+
+	if (len)
+		g_checksum_update(priv->checksum, data, len);
+}
+
+static gboolean
+purple_sha256_hash_digest(PurpleHash *hash, guchar *digest, size_t buff_len)
+{
+	PurpleSHA256Hash *sha256_hash = PURPLE_SHA256_HASH(hash);
+	PurpleSHA256HashPrivate *priv = PURPLE_SHA256_HASH_GET_PRIVATE(sha256_hash);
+
+	const gssize required_len = g_checksum_type_get_length(G_CHECKSUM_SHA256);
+	gsize digest_len = buff_len;
+
+	g_return_val_if_fail(priv != NULL, FALSE);
+	g_return_val_if_fail(priv->checksum != NULL, FALSE);
+	g_return_val_if_fail(buff_len >= required_len, FALSE);
+
+	g_checksum_get_digest(priv->checksum, digest, &digest_len);
+
+	if (digest_len != required_len)
+		return FALSE;
+
+	purple_sha256_hash_reset(hash);
+
+	return TRUE;
+}
+
+static size_t
+purple_sha256_hash_get_block_size(PurpleHash *hash)
+{
+	return 64;
+}
+
+static size_t
+purple_sha256_hash_get_digest_size(PurpleHash *hash)
+{
+	return g_checksum_type_get_length(G_CHECKSUM_SHA256);
+}
+
+static const gchar*
+purple_sha256_hash_get_name(PurpleHash *hash)
+{
+	return "sha256";
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+
+static void
+purple_sha256_hash_finalize(GObject *obj)
+{
+	PurpleSHA256Hash *sha256_hash = PURPLE_SHA256_HASH(obj);
+	PurpleSHA256HashPrivate *priv = PURPLE_SHA256_HASH_GET_PRIVATE(sha256_hash);
+
+	if (priv->checksum)
+		g_checksum_free(priv->checksum);
+
+	parent_class->finalize(obj);
+}
+
+static void
+purple_sha256_hash_class_init(PurpleSHA256HashClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleHashClass *hash_class = PURPLE_HASH_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	obj_class->finalize = purple_sha256_hash_finalize;
+
+	hash_class->reset = purple_sha256_hash_reset;
+	hash_class->reset_state = purple_sha256_hash_reset;
+	hash_class->append = purple_sha256_hash_append;
+	hash_class->digest = purple_sha256_hash_digest;
+	hash_class->get_digest_size = purple_sha256_hash_get_digest_size;
+	hash_class->get_block_size = purple_sha256_hash_get_block_size;
+	hash_class->get_name = purple_sha256_hash_get_name;
+
+	g_type_class_add_private(klass, sizeof(PurpleSHA256HashPrivate));
+}
+
+static void
+purple_sha256_hash_init(PurpleHash *hash)
+{
+	PurpleSHA256Hash *sha256_hash = PURPLE_SHA256_HASH(hash);
+	PurpleSHA256HashPrivate *priv = PURPLE_SHA256_HASH_GET_PRIVATE(sha256_hash);
+
+	priv->checksum = g_checksum_new(G_CHECKSUM_SHA256);
+
+	purple_sha256_hash_reset(hash);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_sha256_hash_get_gtype(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleSHA256HashClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_sha256_hash_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleSHA256Hash),
+			0,
+			(GInstanceInitFunc)purple_sha256_hash_init,
+			NULL,
+		};
+
+		type = g_type_register_static(PURPLE_TYPE_HASH,
+									  "PurpleSHA256Hash",
+									  &info, 0);
+	}
+
+	return type;
+}
+
+PurpleHash *
+purple_sha256_hash_new(void) {
+	return g_object_new(PURPLE_TYPE_SHA256_HASH, NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/ciphers/sha256hash.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,67 @@
+/**
+ * @file sha256.h Purple SHA256 Hash
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_SHA256_HASH_H
+#define PURPLE_SHA256_HASH_H
+
+#include "hash.h"
+
+#define PURPLE_TYPE_SHA256_HASH				(purple_sha256_hash_get_gtype())
+#define PURPLE_SHA256_HASH(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_SHA256_HASH, PurpleSHA256Hash))
+#define PURPLE_SHA256_HASH_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_SHA256_HASH, PurpleSHA256HashClass))
+#define PURPLE_IS_SHA256_HASH(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_SHA256_HASH))
+#define PURPLE_IS_SHA256_HASH_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_SHA256_HASH))
+#define PURPLE_SHA256_HASH_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_SHA256_HASH, PurpleSHA256HashClass))
+
+typedef struct _PurpleSHA256Hash			PurpleSHA256Hash;
+typedef struct _PurpleSHA256HashClass		PurpleSHA256HashClass;
+
+struct _PurpleSHA256Hash {
+	PurpleHash gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+struct _PurpleSHA256HashClass {
+	PurpleHashClass gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_sha256_hash_get_gtype(void);
+
+PurpleHash *purple_sha256_hash_new(void);
+
+G_END_DECLS
+
+#endif /* PURPLE_SHA256_HASH_H */
--- a/libpurple/circbuffer.c	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-/*
- * @file circbuffer.h Buffer Utility Functions
- * @ingroup core
- */
-
-/* Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#include "internal.h"
-
-#include "circbuffer.h"
-
-#define DEFAULT_BUF_SIZE 256
-
-PurpleCircBuffer *
-purple_circ_buffer_new(gsize growsize) {
-	PurpleCircBuffer *buf = g_new0(PurpleCircBuffer, 1);
-	buf->growsize = growsize ? growsize : DEFAULT_BUF_SIZE;
-	return buf;
-}
-
-void purple_circ_buffer_destroy(PurpleCircBuffer *buf) {
-	g_return_if_fail(buf != NULL);
-
-	g_free(buf->buffer);
-	g_free(buf);
-}
-
-static void grow_circ_buffer(PurpleCircBuffer *buf, gsize len) {
-	int in_offset = 0, out_offset = 0;
-	int start_buflen;
-
-	g_return_if_fail(buf != NULL);
-
-	start_buflen = buf->buflen;
-
-	while ((buf->buflen - buf->bufused) < len)
-		buf->buflen += buf->growsize;
-
-	if (buf->inptr != NULL) {
-		in_offset = buf->inptr - buf->buffer;
-		out_offset = buf->outptr - buf->buffer;
-	}
-	buf->buffer = g_realloc(buf->buffer, buf->buflen);
-
-	/* adjust the fill and remove pointer locations */
-	if (buf->inptr == NULL) {
-		buf->inptr = buf->outptr = buf->buffer;
-	} else {
-		buf->inptr = buf->buffer + in_offset;
-		buf->outptr = buf->buffer + out_offset;
-	}
-
-	/* If the fill pointer is wrapped to before the remove
-	 * pointer, we need to shift the data */
-	if (in_offset < out_offset
-			|| (in_offset == out_offset && buf->bufused > 0)) {
-		int shift_n = MIN(buf->buflen - start_buflen,
-			in_offset);
-		memcpy(buf->buffer + start_buflen, buf->buffer,
-			shift_n);
-
-		/* If we couldn't fit the wrapped read buffer
-		 * at the end */
-		if (shift_n < in_offset) {
-			memmove(buf->buffer,
-				buf->buffer + shift_n,
-				in_offset - shift_n);
-			buf->inptr = buf->buffer +
-				(in_offset - shift_n);
-		} else {
-			buf->inptr = buf->buffer +
-				start_buflen + in_offset;
-		}
-	}
-}
-
-void purple_circ_buffer_append(PurpleCircBuffer *buf, gconstpointer src, gsize len) {
-
-	int len_stored;
-
-	g_return_if_fail(buf != NULL);
-
-	/* Grow the buffer, if necessary */
-	if ((buf->buflen - buf->bufused) < len)
-		grow_circ_buffer(buf, len);
-
-	/* If there is not enough room to copy all of src before hitting
-	 * the end of the buffer then we will need to do two copies.
-	 * One copy from inptr to the end of the buffer, and the
-	 * second copy from the start of the buffer to the end of src. */
-	if (buf->inptr >= buf->outptr)
-		len_stored = MIN(len, buf->buflen
-			- (buf->inptr - buf->buffer));
-	else
-		len_stored = len;
-
-	if (len_stored > 0)
-		memcpy(buf->inptr, src, len_stored);
-
-	if (len_stored < len) {
-		memcpy(buf->buffer, (char*)src + len_stored, len - len_stored);
-		buf->inptr = buf->buffer + (len - len_stored);
-	} else {
-		buf->inptr += len_stored;
-	}
-
-	buf->bufused += len;
-}
-
-gsize purple_circ_buffer_get_max_read(const PurpleCircBuffer *buf) {
-	gsize max_read;
-
-	g_return_val_if_fail(buf != NULL, 0);
-
-	if (buf->bufused == 0)
-		max_read = 0;
-	else if ((buf->outptr - buf->inptr) >= 0)
-		max_read = buf->buflen - (buf->outptr - buf->buffer);
-	else
-		max_read = buf->inptr - buf->outptr;
-
-	return max_read;
-}
-
-gboolean purple_circ_buffer_mark_read(PurpleCircBuffer *buf, gsize len) {
-	g_return_val_if_fail(buf != NULL, FALSE);
-	g_return_val_if_fail(purple_circ_buffer_get_max_read(buf) >= len, FALSE);
-
-	buf->outptr += len;
-	buf->bufused -= len;
-	/* wrap to the start if we're at the end */
-	if ((buf->outptr - buf->buffer) == buf->buflen)
-		buf->outptr = buf->buffer;
-
-	return TRUE;
-}
-
--- a/libpurple/circbuffer.h	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/**
- * @file circbuffer.h Buffer Utility Functions
- * @ingroup core
- */
-
-/* Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#ifndef _CIRCBUFFER_H
-#define _CIRCBUFFER_H
-
-#include <glib.h>
-
-typedef struct _PurpleCircBuffer {
-
-	/** A pointer to the starting address of our chunk of memory. */
-	gchar *buffer;
-
-	/** The incremental amount to increase this buffer by when
-	 *  the buffer is not big enough to hold incoming data, in bytes. */
-	gsize growsize;
-
-	/** The length of this buffer, in bytes. */
-	gsize buflen;
-
-	/** The number of bytes of this buffer that contain unread data. */
-	gsize bufused;
-
-	/** A pointer to the next byte where new incoming data is
-	 *  buffered to. */
-	gchar *inptr;
-
-	/** A pointer to the next byte of buffered data that should be
-	 *  read by the consumer. */
-	gchar *outptr;
-
-} PurpleCircBuffer;
-
-G_BEGIN_DECLS
-
-/**
- * Creates a new circular buffer.  This will not allocate any memory for the
- * actual buffer until data is appended to it.
- *
- * @param growsize The amount that the buffer should grow the first time data
- *                 is appended and every time more space is needed.  Pass in
- *                 "0" to use the default of 256 bytes.
- *
- * @return The new PurpleCircBuffer. This should be freed with
- *         purple_circ_buffer_destroy when you are done with it
- */
-PurpleCircBuffer *purple_circ_buffer_new(gsize growsize);
-
-/**
- * Dispose of the PurpleCircBuffer and free any memory used by it (including any
- * memory used by the internal buffer).
- *
- * @param buf The PurpleCircBuffer to free
- */
-void purple_circ_buffer_destroy(PurpleCircBuffer *buf);
-
-/**
- * Append data to the PurpleCircBuffer.  This will grow the internal
- * buffer to fit the added data, if needed.
- *
- * @param buf The PurpleCircBuffer to which to append the data
- * @param src pointer to the data to copy into the buffer
- * @param len number of bytes to copy into the buffer
- */
-void purple_circ_buffer_append(PurpleCircBuffer *buf, gconstpointer src, gsize len);
-
-/**
- * Determine the maximum number of contiguous bytes that can be read from the
- * PurpleCircBuffer.
- * Note: This may not be the total number of bytes that are buffered - a
- * subsequent call after calling purple_circ_buffer_mark_read() may indicate more
- * data is available to read.
- *
- * @param buf the PurpleCircBuffer for which to determine the maximum contiguous
- *            bytes that can be read.
- *
- * @return the number of bytes that can be read from the PurpleCircBuffer
- */
-gsize purple_circ_buffer_get_max_read(const PurpleCircBuffer *buf);
-
-/**
- * Mark the number of bytes that have been read from the buffer.
- *
- * @param buf The PurpleCircBuffer to mark bytes read from
- * @param len The number of bytes to mark as read
- *
- * @return TRUE if we successfully marked the bytes as having been read, FALSE
- *         otherwise.
- */
-gboolean purple_circ_buffer_mark_read(PurpleCircBuffer *buf, gsize len);
-
-G_END_DECLS
-
-#endif /* _CIRCBUFFER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/circularbuffer.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,444 @@
+/*
+ * @file circbuffer.h Buffer Utility Functions
+ * @ingroup core
+ */
+
+/* Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+
+#include "circularbuffer.h"
+
+#define DEFAULT_BUF_SIZE 256
+
+#define PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_CIRCULAR_BUFFER, PurpleCircularBufferPrivate))
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+typedef struct {
+	gchar *buffer;
+	gsize growsize;
+	gsize buflen;
+	gsize bufused;
+	gchar *input;
+	gchar *output;
+} PurpleCircularBufferPrivate;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+	PROP_ZERO,
+	PROP_GROW_SIZE,
+	PROP_BUFFER_USED,
+	PROP_INPUT,
+	PROP_OUTPUT,
+	PROP_LAST,
+};
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+
+/******************************************************************************
+ * Circular Buffer Implementation
+ *****************************************************************************/
+static void
+purple_circular_buffer_real_grow(PurpleCircularBuffer *buffer, gsize len) {
+	PurpleCircularBufferPrivate *priv = NULL;
+	gint in_offset = 0, out_offset = 0;
+	gint start_buflen;
+
+	priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	start_buflen = priv->buflen;
+
+	while((priv->buflen - priv->bufused) < len)
+		priv->buflen += priv->growsize;
+
+	if(priv->input != NULL) {
+		in_offset = priv->input - priv->buffer;
+		out_offset = priv->output - priv->buffer;
+	}
+
+	priv->buffer = g_realloc(priv->buffer, priv->buflen);
+
+	/* adjust the fill and remove pointer locations */
+	if(priv->input == NULL) {
+		priv->input = priv->output = priv->buffer;
+	} else {
+		priv->input = priv->buffer + in_offset;
+		priv->output = priv->buffer + out_offset;
+	}
+
+	/* If the fill pointer is wrapped to before the remove
+	 * pointer, we need to shift the data */
+	if(in_offset < out_offset
+			|| (in_offset == out_offset && priv->bufused > 0))
+	{
+		gint shift_n = MIN(priv->buflen - start_buflen, in_offset);
+		memcpy(priv->buffer + start_buflen, priv->buffer, shift_n);
+
+		/* If we couldn't fit the wrapped read buffer at the end */
+		if (shift_n < in_offset) {
+			memmove(priv->buffer, priv->buffer + shift_n, in_offset - shift_n);
+			priv->input = priv->buffer + (in_offset - shift_n);
+		} else {
+			priv->input = priv->buffer + start_buflen + in_offset;
+		}
+	}
+}
+
+static void
+purple_circular_buffer_real_append(PurpleCircularBuffer *buffer,
+                                   gconstpointer src, gsize len)
+{
+	PurpleCircularBufferPrivate *priv = NULL;
+	gint len_stored;
+
+	priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	/* Grow the buffer, if necessary */
+	if((priv->buflen - priv->bufused) < len)
+		purple_circular_buffer_grow(buffer, len);
+
+	/* If there is not enough room to copy all of src before hitting
+	 * the end of the buffer then we will need to do two copies.
+	 * One copy from input to the end of the buffer, and the
+	 * second copy from the start of the buffer to the end of src. */
+	if(priv->input >= priv->output)
+		len_stored = MIN(len, priv->buflen - (priv->input - priv->buffer));
+	else
+		len_stored = len;
+
+	if(len_stored > 0)
+		memcpy(priv->input, src, len_stored);
+
+	if(len_stored < len) {
+		memcpy(priv->buffer, (char*)src + len_stored, len - len_stored);
+		priv->input = priv->buffer + (len - len_stored);
+	} else {
+		priv->input += len_stored;
+	}
+
+	priv->bufused += len;
+}
+
+static gsize
+purple_circular_buffer_real_max_read_size(const PurpleCircularBuffer *buffer) {
+	PurpleCircularBufferPrivate *priv = NULL;
+	gsize max_read;
+
+	priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	if(priv->bufused == 0)
+		max_read = 0;
+	else if((priv->output - priv->input) >= 0)
+		max_read = priv->buflen - (priv->output - priv->buffer);
+	else
+		max_read = priv->input - priv->output;
+
+	return max_read;
+}
+
+static gboolean
+purple_circular_buffer_real_mark_read(PurpleCircularBuffer *buffer,
+                                      gsize len)
+{
+	PurpleCircularBufferPrivate *priv = NULL;
+
+	g_return_val_if_fail(purple_circular_buffer_get_max_read(buffer) >= len, FALSE);
+
+	priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	priv->output += len;
+	priv->bufused -= len;
+
+	/* wrap to the start if we're at the end */
+	if((priv->output - priv->buffer) == priv->buflen)
+		priv->output = priv->buffer;
+
+	return TRUE;
+}
+
+/******************************************************************************
+ * Private API
+ *****************************************************************************/
+static void
+purple_circular_buffer_set_grow_size(PurpleCircularBuffer *buffer,
+                                     gsize grow_size)
+{
+	PurpleCircularBufferPrivate *priv =
+		PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	priv->growsize = (grow_size != 0) ? grow_size : DEFAULT_BUF_SIZE;
+
+	g_object_notify(G_OBJECT(buffer), "grow-size");
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_circular_buffer_finalize(GObject *obj) {
+	PurpleCircularBufferPrivate *priv =
+		PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(obj);
+
+	g_free(priv->buffer);
+
+	G_OBJECT_CLASS(parent_class)->finalize(obj);
+}
+
+static void
+purple_circular_buffer_get_property(GObject *obj, guint param_id,
+                                    GValue *value, GParamSpec *pspec)
+{
+	PurpleCircularBuffer *buffer = PURPLE_CIRCULAR_BUFFER(obj);
+
+	switch(param_id) {
+		case PROP_GROW_SIZE:
+			g_value_set_ulong(value,
+			                  purple_circular_buffer_get_grow_size(buffer));
+			break;
+		case PROP_BUFFER_USED:
+			g_value_set_ulong(value,
+			                  purple_circular_buffer_get_used(buffer));
+			break;
+		case PROP_INPUT:
+			g_value_set_pointer(value,
+			                    (void*) purple_circular_buffer_get_input(buffer));
+			break;
+		case PROP_OUTPUT:
+			g_value_set_pointer(value,
+			                    (void*) purple_circular_buffer_get_output(buffer));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_circular_buffer_set_property(GObject *obj, guint param_id,
+                                    const GValue *value, GParamSpec *pspec)
+{
+	PurpleCircularBuffer *buffer = PURPLE_CIRCULAR_BUFFER(obj);
+
+	switch(param_id) {
+		case PROP_GROW_SIZE:
+			purple_circular_buffer_set_grow_size(buffer,
+			                                     g_value_get_uint(value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_circular_buffer_class_init(PurpleCircularBufferClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	PurpleCircularBufferClass *buffer_class = PURPLE_CIRCULAR_BUFFER_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent(klass);
+
+	g_type_class_add_private(klass, sizeof(PurpleCircularBufferPrivate));
+
+	obj_class->finalize = purple_circular_buffer_finalize;
+	obj_class->get_property = purple_circular_buffer_get_property;
+	obj_class->set_property = purple_circular_buffer_set_property;
+
+	buffer_class->grow = purple_circular_buffer_real_grow;
+	buffer_class->append = purple_circular_buffer_real_append;
+	buffer_class->max_read_size = purple_circular_buffer_real_max_read_size;
+	buffer_class->mark_read = purple_circular_buffer_real_mark_read;
+
+	/* using a ulong for the gsize properties since there is no
+	 * g_param_spec_size, and the ulong should always work. --gk 3/21/11
+	 */
+	g_object_class_install_property(obj_class, PROP_GROW_SIZE,
+		g_param_spec_ulong("grow-size", "grow-size",
+		                   "The grow size of the buffer",
+		                   0, G_MAXSIZE, 0,
+		                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property(obj_class, PROP_BUFFER_USED,
+		g_param_spec_ulong("buffer-used", "buffer-used",
+		                   "The amount of the buffer used",
+		                   0, G_MAXSIZE, 0,
+		                   G_PARAM_READABLE));
+
+	g_object_class_install_property(obj_class, PROP_INPUT,
+		g_param_spec_pointer("input", "input",
+		                     "The input pointer of the buffer",
+		                     G_PARAM_READABLE));
+
+	g_object_class_install_property(obj_class, PROP_OUTPUT,
+		g_param_spec_pointer("output", "output",
+		                     "The output pointer of the buffer",
+		                     G_PARAM_READABLE));
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GType
+purple_circular_buffer_get_type(void) {
+	static GType type = 0;
+
+	if(G_UNLIKELY(type == 0)) {
+		static const GTypeInfo info = {
+			.class_size = sizeof(PurpleCircularBufferClass),
+			.class_init = (GClassInitFunc)purple_circular_buffer_class_init,
+			.instance_size = sizeof(PurpleCircularBuffer),
+		};
+
+		type = g_type_register_static(G_TYPE_OBJECT,
+		                              "PurpleCircularBuffer",
+		                              &info, 0);
+	}
+
+	return type;
+}
+
+PurpleCircularBuffer *
+purple_circular_buffer_new(gsize growsize) {
+	return g_object_new(PURPLE_TYPE_CIRCULAR_BUFFER,
+	                    "grow-size", growsize ? growsize : DEFAULT_BUF_SIZE,
+	                    NULL);
+}
+
+void
+purple_circular_buffer_grow(PurpleCircularBuffer *buffer, gsize len) {
+	PurpleCircularBufferClass *klass = NULL;
+
+	g_return_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer));
+
+	klass = PURPLE_CIRCULAR_BUFFER_GET_CLASS(buffer);
+	if(klass && klass->grow)
+		klass->grow(buffer, len);
+}
+
+void
+purple_circular_buffer_append(PurpleCircularBuffer *buffer, gconstpointer src,
+                              gsize len)
+{
+	PurpleCircularBufferClass *klass = NULL;
+
+	g_return_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer));
+	g_return_if_fail(src != NULL);
+
+	klass = PURPLE_CIRCULAR_BUFFER_GET_CLASS(buffer);
+	if(klass && klass->append)
+		klass->append(buffer, src, len);
+}
+
+gsize
+purple_circular_buffer_get_max_read(const PurpleCircularBuffer *buffer) {
+	PurpleCircularBufferClass *klass = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), 0);
+
+	klass = PURPLE_CIRCULAR_BUFFER_GET_CLASS(buffer);
+	if(klass && klass->max_read_size)
+		return klass->max_read_size(buffer);
+
+	return 0;
+}
+
+gboolean
+purple_circular_buffer_mark_read(PurpleCircularBuffer *buffer, gsize len) {
+	PurpleCircularBufferClass *klass = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), FALSE);
+
+	klass = PURPLE_CIRCULAR_BUFFER_CLASS(buffer);
+	if(klass && klass->mark_read)
+		return klass->mark_read(buffer, len);
+
+	return FALSE;
+}
+
+gsize
+purple_circular_buffer_get_grow_size(const PurpleCircularBuffer *buffer) {
+
+	PurpleCircularBufferPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), 0);
+
+	priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	return priv->growsize;
+}
+
+gsize
+purple_circular_buffer_get_used(const PurpleCircularBuffer *buffer) {
+	PurpleCircularBufferPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), 0);
+
+	priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	return priv->bufused;
+}
+
+const gchar *
+purple_circular_buffer_get_input(const PurpleCircularBuffer *buffer) {
+	PurpleCircularBufferPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), NULL);
+
+	priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	return priv->input;
+}
+
+const gchar *
+purple_circular_buffer_get_output(const PurpleCircularBuffer *buffer) {
+	PurpleCircularBufferPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), NULL);
+
+	priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	return priv->output;
+}
+
+void
+purple_circular_buffer_reset(PurpleCircularBuffer *buffer) {
+	PurpleCircularBufferPrivate *priv = NULL;
+	GObject *obj = NULL;
+
+	g_return_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer));
+
+	priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
+
+	priv->input = priv->buffer;
+	priv->output = priv->buffer;
+
+	obj = G_OBJECT(buffer);
+	g_object_freeze_notify(obj);
+	g_object_notify(obj, "input");
+	g_object_notify(obj, "output");
+	g_object_thaw_notify(obj);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/circularbuffer.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,125 @@
+/**
+ * @file circbuffer.h Buffer Utility Functions
+ * @ingroup core
+ */
+
+/* Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_CIRCULAR_BUFFER_H
+#define PURPLE_CIRCULAR_BUFFER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#define PURPLE_TYPE_CIRCULAR_BUFFER            (purple_circular_buffer_get_type())
+#define PURPLE_CIRCULAR_BUFFER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_CIRCULAR_BUFFER, PurpleCircularBuffer))
+#define PURPLE_CIRCULAR_BUFFER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_CIRCULAR_BUFFER, PurpleCircularBufferClass))
+#define PURPLE_IS_CIRCULAR_BUFFER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_CIRCULAR_BUFFER))
+#define PURPLE_IS_CIRCULAR_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_CIRCULAR_BUFFER))
+#define PURPLE_CIRCULAR_BUFFER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_CIRCULAR_BUFFER, PurpleCircularBufferClass))
+
+typedef struct _PurpleCircularBuffer           PurpleCircularBuffer;
+typedef struct _PurpleCircularBufferClass      PurpleCircularBufferClass;
+
+struct _PurpleCircularBuffer {
+	GObject parent;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
+};
+
+struct _PurpleCircularBufferClass {
+	GObjectClass parent;
+
+	void (*grow)(PurpleCircularBuffer *buffer, gsize len);
+	void (*append)(PurpleCircularBuffer *buffer, gconstpointer src, gsize len);
+	gsize (*max_read_size)(const PurpleCircularBuffer *buffer);
+	gboolean (*mark_read)(PurpleCircularBuffer *buffer, gsize len);
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_circular_buffer_get_type(void);
+
+/**
+ * Creates a new circular buffer.  This will not allocate any memory for the
+ * actual buffer until data is appended to it.
+ *
+ * @param growsize The amount that the buffer should grow the first time data
+ *                 is appended and every time more space is needed.  Pass in
+ *                 "0" to use the default of 256 bytes.
+ *
+ * @return The new PurpleCircBuffer. This should be freed with
+ *         purple_circ_buffer_destroy when you are done with it
+ */
+PurpleCircularBuffer *purple_circular_buffer_new(gsize growsize);
+
+/**
+ * Append data to the PurpleCircBuffer.  This will grow the internal
+ * buffer to fit the added data, if needed.
+ *
+ * @param buf The PurpleCircBuffer to which to append the data
+ * @param src pointer to the data to copy into the buffer
+ * @param len number of bytes to copy into the buffer
+ */
+void purple_circular_buffer_append(PurpleCircularBuffer *buf, gconstpointer src, gsize len);
+
+/**
+ * Determine the maximum number of contiguous bytes that can be read from the
+ * PurpleCircBuffer.
+ * Note: This may not be the total number of bytes that are buffered - a
+ * subsequent call after calling purple_circ_buffer_mark_read() may indicate more
+ * data is available to read.
+ *
+ * @param buf the PurpleCircBuffer for which to determine the maximum contiguous
+ *            bytes that can be read.
+ *
+ * @return the number of bytes that can be read from the PurpleCircBuffer
+ */
+gsize purple_circular_buffer_get_max_read(const PurpleCircularBuffer *buf);
+
+/**
+ * Mark the number of bytes that have been read from the buffer.
+ *
+ * @param buf The PurpleCircBuffer to mark bytes read from
+ * @param len The number of bytes to mark as read
+ *
+ * @return TRUE if we successfully marked the bytes as having been read, FALSE
+ *         otherwise.
+ */
+gboolean purple_circular_buffer_mark_read(PurpleCircularBuffer *buf, gsize len);
+
+void purple_circular_buffer_grow(PurpleCircularBuffer *buffer, gsize len);
+gsize purple_circular_buffer_get_grow_size(const PurpleCircularBuffer *buffer);
+gsize purple_circular_buffer_get_used(const PurpleCircularBuffer *buffer);
+const gchar *purple_circular_buffer_get_input(const PurpleCircularBuffer *buffer);
+const gchar *purple_circular_buffer_get_output(const PurpleCircularBuffer *buffer);
+void purple_circular_buffer_reset(PurpleCircularBuffer *buffer);
+
+G_END_DECLS
+
+#endif /* PURPLE_CIRCULAR_BUFFER_H */
+
--- a/libpurple/conversation.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/conversation.c	Sun Jun 23 13:35:53 2013 +0530
@@ -33,89 +33,15 @@
 #include "signals.h"
 #include "util.h"
 
-#define SEND_TYPED_TIMEOUT_SECONDS 5
-
-/**
- * Data specific to Chats.
- */
-struct _PurpleConvChat
-{
-	PurpleConversation *conv;          /**< The parent conversation.      */
-
-	GList *in_room;                  /**< The users in the room.
-	                                  *   @deprecated Will be removed in 3.0.0
-									  */
-	GList *ignored;                  /**< Ignored users.                */
-	char  *who;                      /**< The person who set the topic. */
-	char  *topic;                    /**< The topic.                    */
-	int    id;                       /**< The chat ID.                  */
-	char *nick;                      /**< Your nick in this chat.       */
-
-	gboolean left;                   /**< We left the chat and kept the window open */
-	GHashTable *users;               /**< Hash table of the users in the room. */
-};
-
-/**
- * Data specific to Instant Messages.
- */
-struct _PurpleConvIm
-{
-	PurpleConversation *conv;            /**< The parent conversation.     */
-
-	PurpleTypingState typing_state;      /**< The current typing state.    */
-	guint  typing_timeout;             /**< The typing timer handle.     */
-	time_t type_again;                 /**< The type again time.         */
-	guint  send_typed_timeout;         /**< The type again timer handle. */
-
-	PurpleBuddyIcon *icon;               /**< The buddy icon.              */
-};
-
-/**
- * Data for "Chat Buddies"
- */
-struct _PurpleConvChatBuddy
-{
-	/** The chat participant's name in the chat. */
-	char *name;
-
-	/** The chat participant's alias, if known; @a NULL otherwise. */
-	char *alias;
-
-	/**
-	 * A string by which this buddy will be sorted, or @c NULL if the
-	 * buddy should be sorted by its @c name.  (This is currently always
-	 * @c NULL.
-	 */
-	char *alias_key;
-
-	/**
-	 * @a TRUE if this chat participant is on the buddy list;
-	 * @a FALSE otherwise.
-	 */
-	gboolean buddy;
-
-	/**
-	 * A bitwise OR of flags for this participant, such as whether they
-	 * are a channel operator.
-	 */
-	PurpleConvChatBuddyFlags flags;
-
-	/**
-	 * A hash table of attributes about the user, such as real name,
-	 * user\@host, etc.
-	 */
-	GHashTable *attributes;
-
-	/** The UI can put whatever it wants here. */
-	gpointer ui_data;
-};
+/** @copydoc _PurpleConversationPrivate */
+typedef struct _PurpleConversationPrivate  PurpleConversationPrivate;
 
 /**
  * A core representation of a conversation between two or more people.
  *
  * The conversation can be an IM or a chat.
  */
-struct _PurpleConversation
+struct _PurpleConversationPrivate
 {
 	PurpleConversationType type;  /**< The type of conversation.          */
 
@@ -129,42 +55,28 @@
 
 	GList *logs;                /**< This conversation's logs           */
 
-	union
-	{
-		PurpleConvIm   *im;       /**< IM-specific data.                  */
-		PurpleConvChat *chat;     /**< Chat-specific data.                */
-		void *misc;               /**< Misc. data.                        */
-
-	} u;
-
 	PurpleConversationUiOps *ui_ops;           /**< UI-specific operations. */
 	void *ui_data;                           /**< UI-specific data.       */
 
 	GHashTable *data;                        /**< Plugin-specific data.   */
 
 	PurpleConnectionFlags features; /**< The supported features */
-	GList *message_history;         /**< Message history, as a GList of PurpleConvMessage's */
+	GList *message_history;         /**< Message history, as a GList of PurpleConversationMessage's */
 };
 
-/**
+/** TODO GBoxed
  * Description of a conversation message
  */
-struct _PurpleConvMessage
+struct _PurpleConversationMessage
 {
 	char *who;
 	char *what;
-	PurpleMessageFlags flags;
+	PurpleConversationMessageFlags flags;
 	time_t when;
 	PurpleConversation *conv;
 	char *alias;
 };
 
-
-static GList *conversations = NULL;
-static GList *ims = NULL;
-static GList *chats = NULL;
-static PurpleConversationUiOps *default_ops = NULL;
-
 /**
  * A hash table used for efficient lookups of conversations by name.
  * struct _purple_hconv => PurpleConversation*
@@ -212,22 +124,16 @@
 	return !g_utf8_collate(a, b);
 }
 
-void
-purple_conversations_set_ui_ops(PurpleConversationUiOps *ops)
-{
-	default_ops = ops;
-}
-
 static gboolean
 reset_typing_cb(gpointer data)
 {
 	PurpleConversation *c = (PurpleConversation *)data;
-	PurpleConvIm *im;
+	PurpleIMConversationPrivate *priv;
 
-	im = PURPLE_CONV_IM(c);
+	im = PURPLE_IM_CONVERSATION_GET_PRIVATE(c);
 
-	purple_conv_im_set_typing_state(im, PURPLE_NOT_TYPING);
-	purple_conv_im_stop_typing_timeout(im);
+	purple_im_conversation_set_typing_state(im, PURPLE_IM_CONVERSATION_NOT_TYPING);
+	purple_im_conversation_stop_typing_timeout(im);
 
 	return FALSE;
 }
@@ -245,12 +151,12 @@
 	name = purple_conversation_get_name(conv);
 
 	if (gc != NULL && name != NULL) {
-		/* We set this to 1 so that PURPLE_TYPING will be sent
+		/* We set this to 1 so that PURPLE_IM_CONVERSATION_TYPING will be sent
 		 * if the Purple user types anything else.
 		 */
-		purple_conv_im_set_type_again(PURPLE_CONV_IM(conv), 1);
+		purple_im_conversation_set_type_again(PURPLE_IM_CONVERSATION_GET_PRIVATE(conv), 1);
 
-		serv_send_typing(gc, name, PURPLE_TYPED);
+		serv_send_typing(gc, name, PURPLE_IM_CONVERSATION_TYPED);
 
 		purple_debug(PURPLE_DEBUG_MISC, "conversation", "typed...\n");
 	}
@@ -259,7 +165,7 @@
 }
 
 static void
-common_send(PurpleConversation *conv, const char *message, PurpleMessageFlags msgflags)
+common_send(PurpleConversation *conv, const char *message, PurpleConversationMessageFlags msgflags)
 {
 	PurpleConversationType type;
 	PurpleAccount *account;
@@ -280,23 +186,23 @@
 
 	/* Always linkfy the text for display, unless we're
 	 * explicitly asked to do otheriwse*/
-	if (!(msgflags & PURPLE_MESSAGE_INVISIBLE)) {
-		if(msgflags & PURPLE_MESSAGE_NO_LINKIFY)
+	if (!(msgflags & PURPLE_CONVERSATION_MESSAGE_INVISIBLE)) {
+		if(msgflags & PURPLE_CONVERSATION_MESSAGE_NO_LINKIFY)
 			displayed = g_strdup(message);
 		else
 			displayed = purple_markup_linkify(message);
 	}
 
 	if (displayed && (conv->features & PURPLE_CONNECTION_HTML) &&
-		!(msgflags & PURPLE_MESSAGE_RAW)) {
+		!(msgflags & PURPLE_CONVERSATION_MESSAGE_RAW)) {
 		sent = g_strdup(displayed);
 	} else
 		sent = g_strdup(message);
 
-	msgflags |= PURPLE_MESSAGE_SEND;
+	msgflags |= PURPLE_CONVERSATION_MESSAGE_SEND;
 
-	if (type == PURPLE_CONV_TYPE_IM) {
-		PurpleConvIm *im = PURPLE_CONV_IM(conv);
+	if (type == PURPLE_CONVERSATION_TYPE_IM) {
+		PurpleIMConversationPrivate *priv = PURPLE_IM_CONVERSATION_GET_PRIVATE(conv);
 
 		purple_signal_emit(purple_conversations_get_handle(), "sending-im-msg",
 						 account,
@@ -308,7 +214,7 @@
 			                   sent, msgflags);
 
 			if ((err > 0) && (displayed != NULL))
-				purple_conv_im_write(im, NULL, displayed, msgflags, time(NULL));
+				purple_im_conversation_write(im, NULL, displayed, msgflags, time(NULL));
 
 			purple_signal_emit(purple_conversations_get_handle(), "sent-im-msg",
 							 account,
@@ -318,14 +224,14 @@
 	else {
 		purple_signal_emit(purple_conversations_get_handle(), "sending-chat-msg",
 						 account, &sent,
-						 purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)));
+						 purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv)));
 
 		if (sent != NULL && sent[0] != '\0') {
-			err = serv_chat_send(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), sent, msgflags);
+			err = serv_chat_send(gc, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv)), sent, msgflags);
 
 			purple_signal_emit(purple_conversations_get_handle(), "sent-chat-msg",
 							 account, sent,
-							 purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)));
+							 purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv)));
 		}
 	}
 
@@ -338,7 +244,7 @@
 		if (err == -E2BIG) {
 			msg = _("Unable to send message: The message is too large.");
 
-			if (!purple_conv_present_error(who, account, msg)) {
+			if (!purple_conversation_helper_present_error(who, account, msg)) {
 				char *msg2 = g_strdup_printf(_("Unable to send message to %s."), who);
 				purple_notify_error(gc, NULL, msg2, _("The message is too large."));
 				g_free(msg2);
@@ -351,7 +257,7 @@
 		else {
 			msg = _("Unable to send message.");
 
-			if (!purple_conv_present_error(who, account, msg)) {
+			if (!purple_conversation_helper_present_error(who, account, msg)) {
 				char *msg2 = g_strdup_printf(_("Unable to send message to %s."), who);
 				purple_notify_error(gc, NULL, msg2, NULL);
 				g_free(msg2);
@@ -366,23 +272,23 @@
 static void
 open_log(PurpleConversation *conv)
 {
-	conv->logs = g_list_append(NULL, purple_log_new(conv->type == PURPLE_CONV_TYPE_CHAT ? PURPLE_LOG_CHAT :
+	conv->logs = g_list_append(NULL, purple_log_new(conv->type == PURPLE_CONVERSATION_TYPE_CHAT ? PURPLE_LOG_CHAT :
 							   PURPLE_LOG_IM, conv->name, conv->account,
 							   conv, time(NULL), NULL));
 }
 
-/* Functions that deal with PurpleConvMessage */
+/* Functions that deal with PurpleConversationMessage */
 
 static void
 add_message_to_history(PurpleConversation *conv, const char *who, const char *alias,
-		const char *message, PurpleMessageFlags flags, time_t when)
+		const char *message, PurpleConversationMessageFlags flags, time_t when)
 {
-	PurpleConvMessage *msg;
+	PurpleConversationMessage *msg;
 	PurpleConnection *gc;
 
 	gc = purple_account_get_connection(conv->account);
 
-	if (flags & PURPLE_MESSAGE_SEND) {
+	if (flags & PURPLE_CONVERSATION_MESSAGE_SEND) {
 		const char *me = NULL;
 		if (gc)
 			me = purple_connection_get_display_name(gc);
@@ -391,8 +297,8 @@
 		who = me;
 	}
 
-	msg = g_new0(PurpleConvMessage, 1);
-	PURPLE_DBUS_REGISTER_POINTER(msg, PurpleConvMessage);
+	msg = g_new0(PurpleConversationMessage, 1);
+	PURPLE_DBUS_REGISTER_POINTER(msg, PurpleConversationMessage);
 	msg->who = g_strdup(who);
 	msg->alias = g_strdup(alias);
 	msg->flags = flags;
@@ -404,7 +310,7 @@
 }
 
 static void
-free_conv_message(PurpleConvMessage *msg)
+free_conv_message(PurpleConversationMessage *msg)
 {
 	g_free(msg->who);
 	g_free(msg->alias);
@@ -438,18 +344,18 @@
 	gc = purple_account_get_connection(account);
 
 	if ((disp = purple_connection_get_display_name(gc)) != NULL)
-		purple_conv_chat_set_nick(PURPLE_CONV_CHAT(conv), disp);
+		purple_chat_conversation_set_nick(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv), disp);
 	else
 	{
-		purple_conv_chat_set_nick(PURPLE_CONV_CHAT(conv),
+		purple_chat_conversation_set_nick(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv),
 								purple_account_get_username(account));
 	}
 
-	purple_conv_chat_clear_users(PURPLE_CONV_CHAT(conv));
-	purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv), NULL, NULL);
-	PURPLE_CONV_CHAT(conv)->left = FALSE;
+	purple_chat_conversation_clear_users(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv));
+	purple_chat_conversation_set_topic(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv), NULL, NULL);
+	PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv)->left = FALSE;
 
-	purple_conversation_update(conv, PURPLE_CONV_UPDATE_CHATLEFT);
+	purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_CHATLEFT);
 }
 
 PurpleConversation *
@@ -461,15 +367,15 @@
 	PurpleConversationUiOps *ops;
 	struct _purple_hconv *hc;
 
-	g_return_val_if_fail(type    != PURPLE_CONV_TYPE_UNKNOWN, NULL);
+	g_return_val_if_fail(type    != PURPLE_CONVERSATION_TYPE_UNKNOWN, NULL);
 	g_return_val_if_fail(account != NULL, NULL);
 	g_return_val_if_fail(name    != NULL, NULL);
 
 	/* Check if this conversation already exists. */
-	if ((conv = purple_find_conversation_with_account(type, name, account)) != NULL)
+	if ((conv = purple_conversations_find_with_account(type, name, account)) != NULL)
 	{
-		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT &&
-				!purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv))) {
+		if (purple_conversation_get_type(conv) == PURPLE_CONVERSATION_TYPE_CHAT &&
+				!purple_chat_conversation_has_left(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv))) {
 			purple_debug_warning("conversation", "Trying to create multiple "
 					"chats (%s) with the same name is deprecated and will be "
 					"removed in libpurple 3.0.0", name);
@@ -483,10 +389,10 @@
 		 * chat.
 		 * TODO 3.0.0: Remove this workaround and mandate unique names.
 		 */
-		if (purple_conversation_get_type(conv) != PURPLE_CONV_TYPE_CHAT ||
-				purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
+		if (purple_conversation_get_type(conv) != PURPLE_CONVERSATION_TYPE_CHAT ||
+				purple_chat_conversation_has_left(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv)))
 		{
-			if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
+			if (purple_conversation_get_type(conv) == PURPLE_CONVERSATION_TYPE_CHAT)
 				purple_conversation_chat_cleanup_for_rejoin(conv);
 
 			return conv;
@@ -508,18 +414,18 @@
 	/* copy features from the connection. */
 	conv->features = purple_connection_get_flags(gc);
 
-	if (type == PURPLE_CONV_TYPE_IM)
+	if (type == PURPLE_CONVERSATION_TYPE_IM)
 	{
 		PurpleBuddyIcon *icon;
-		conv->u.im = g_new0(PurpleConvIm, 1);
+		conv->u.im = g_new0(PurpleIMConversationPrivate, 1);
 		conv->u.im->conv = conv;
-		PURPLE_DBUS_REGISTER_POINTER(conv->u.im, PurpleConvIm);
+		PURPLE_DBUS_REGISTER_POINTER(conv->u.im, PurpleIMConversationPrivate);
 
 		ims = g_list_prepend(ims, conv);
 		if ((icon = purple_buddy_icons_find(account, name)))
 		{
-			purple_conv_im_set_icon(conv->u.im, icon);
-			/* purple_conv_im_set_icon refs the icon. */
+			purple_im_conversation_set_icon(conv->u.im, icon);
+			/* purple_im_conversation_set_icon refs the icon. */
 			purple_buddy_icon_unref(icon);
 		}
 
@@ -529,22 +435,22 @@
 			open_log(conv);
 		}
 	}
-	else if (type == PURPLE_CONV_TYPE_CHAT)
+	else if (type == PURPLE_CONVERSATION_TYPE_CHAT)
 	{
 		const char *disp;
 
-		conv->u.chat = g_new0(PurpleConvChat, 1);
+		conv->u.chat = g_new0(PurpleChatConversationPrivate, 1);
 		conv->u.chat->conv = conv;
 		conv->u.chat->users = g_hash_table_new_full(_purple_conversation_user_hash,
 				_purple_conversation_user_equal, g_free, NULL);
-		PURPLE_DBUS_REGISTER_POINTER(conv->u.chat, PurpleConvChat);
+		PURPLE_DBUS_REGISTER_POINTER(conv->u.chat, PurpleChatConversationPrivate);
 
 		chats = g_list_prepend(chats, conv);
 
 		if ((disp = purple_connection_get_display_name(purple_account_get_connection(account))))
-			purple_conv_chat_set_nick(conv->u.chat, disp);
+			purple_chat_conversation_set_nick(conv->u.chat, disp);
 		else
-			purple_conv_chat_set_nick(conv->u.chat,
+			purple_chat_conversation_set_nick(conv->u.chat,
 									purple_account_get_username(account));
 
 		if (purple_prefs_get_bool("/purple/logging/log_chats"))
@@ -602,17 +508,17 @@
 		/* Still connected */
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
 
-		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
+		if (purple_conversation_get_type(conv) == PURPLE_CONVERSATION_TYPE_IM)
 		{
 			if (purple_prefs_get_bool("/purple/conversations/im/send_typing"))
-				serv_send_typing(gc, name, PURPLE_NOT_TYPING);
+				serv_send_typing(gc, name, PURPLE_IM_CONVERSATION_NOT_TYPING);
 
 			if (gc && prpl_info->convo_closed != NULL)
 				prpl_info->convo_closed(gc, name);
 		}
-		else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
+		else if (purple_conversation_get_type(conv) == PURPLE_CONVERSATION_TYPE_CHAT)
 		{
-			int chat_id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv));
+			int chat_id = purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv));
 #if 0
 			/*
 			 * This is unfortunately necessary, because calling
@@ -644,14 +550,14 @@
 			 * internals on it's own time. Don't do this if the prpl already
 			 * knows it left the chat.
 			 */
-			if (!purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
+			if (!purple_chat_conversation_has_left(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv)))
 				serv_chat_leave(gc, chat_id);
 
 			/*
 			 * If they didn't call serv_got_chat_left by now, it's too late.
 			 * So we better do it for them before we destroy the thing.
 			 */
-			if (!purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
+			if (!purple_chat_conversation_has_left(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv)))
 				serv_got_chat_left(gc, chat_id);
 		}
 	}
@@ -659,9 +565,9 @@
 	/* remove from conversations and im/chats lists prior to emit */
 	conversations = g_list_remove(conversations, conv);
 
-	if(conv->type==PURPLE_CONV_TYPE_IM)
+	if(conv->type==PURPLE_CONVERSATION_TYPE_IM)
 		ims = g_list_remove(ims, conv);
-	else if(conv->type==PURPLE_CONV_TYPE_CHAT)
+	else if(conv->type==PURPLE_CONVERSATION_TYPE_CHAT)
 		chats = g_list_remove(chats, conv);
 
 	hc.name = (gchar *)purple_normalize(conv->account, conv->name);
@@ -679,9 +585,9 @@
 	conv->name = NULL;
 	conv->title = NULL;
 
-	if (conv->type == PURPLE_CONV_TYPE_IM) {
-		purple_conv_im_stop_typing_timeout(conv->u.im);
-		purple_conv_im_stop_send_typed_timeout(conv->u.im);
+	if (conv->type == PURPLE_CONVERSATION_TYPE_IM) {
+		purple_im_conversation_stop_typing_timeout(conv->u.im);
+		purple_im_conversation_stop_send_typed_timeout(conv->u.im);
 
 		purple_buddy_icon_unref(conv->u.im->icon);
 		conv->u.im->icon = NULL;
@@ -690,11 +596,11 @@
 		g_free(conv->u.im);
 		conv->u.im = NULL;
 	}
-	else if (conv->type == PURPLE_CONV_TYPE_CHAT) {
+	else if (conv->type == PURPLE_CONVERSATION_TYPE_CHAT) {
 		g_hash_table_destroy(conv->u.chat->users);
 		conv->u.chat->users = NULL;
 
-		g_list_foreach(conv->u.chat->in_room, (GFunc)purple_conv_chat_cb_destroy, NULL);
+		g_list_foreach(conv->u.chat->in_room, (GFunc)purple_chat_conversation_buddy_destroy, NULL);
 		g_list_free(conv->u.chat->in_room);
 
 		g_list_foreach(conv->u.chat->ignored, (GFunc)g_free, NULL);
@@ -752,7 +658,7 @@
 
 	conv->features = features;
 
-	purple_conversation_update(conv, PURPLE_CONV_UPDATE_FEATURES);
+	purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_FEATURES);
 }
 
 
@@ -767,7 +673,7 @@
 PurpleConversationType
 purple_conversation_get_type(const PurpleConversation *conv)
 {
-	g_return_val_if_fail(conv != NULL, PURPLE_CONV_TYPE_UNKNOWN);
+	g_return_val_if_fail(conv != NULL, PURPLE_CONVERSATION_TYPE_UNKNOWN);
 
 	return conv->type;
 }
@@ -807,7 +713,7 @@
 
 	conv->account = account;
 
-	purple_conversation_update(conv, PURPLE_CONV_UPDATE_ACCOUNT);
+	purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_ACCOUNT);
 }
 
 PurpleAccount *
@@ -842,7 +748,7 @@
 	g_free(conv->title);
 	conv->title = g_strdup(title);
 
-	purple_conversation_update(conv, PURPLE_CONV_UPDATE_TITLE);
+	purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_TITLE);
 }
 
 const char *
@@ -866,10 +772,10 @@
 	account = purple_conversation_get_account(conv);
 	name = purple_conversation_get_name(conv);
 
-	if(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
+	if(purple_conversation_get_type(conv) == PURPLE_CONVERSATION_TYPE_IM) {
 		if(account && ((b = purple_find_buddy(account, name)) != NULL))
 			text = purple_buddy_get_contact_alias(b);
-	} else if(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
+	} else if(purple_conversation_get_type(conv) == PURPLE_CONVERSATION_TYPE_CHAT) {
 		if(account && ((chat = purple_blist_find_chat(account, name)) != NULL))
 			text = purple_chat_get_name(chat);
 	}
@@ -882,21 +788,6 @@
 }
 
 void
-purple_conversation_foreach(void (*func)(PurpleConversation *conv))
-{
-	PurpleConversation *conv;
-	GList *l;
-
-	g_return_if_fail(func != NULL);
-
-	for (l = purple_get_conversations(); l != NULL; l = l->next) {
-		conv = (PurpleConversation *)l->data;
-
-		func(conv);
-	}
-}
-
-void
 purple_conversation_set_name(PurpleConversation *conv, const char *name)
 {
 	struct _purple_hconv *hc;
@@ -933,7 +824,7 @@
 	if (conv->logging != log)
 	{
 		conv->logging = log;
-		purple_conversation_update(conv, PURPLE_CONV_UPDATE_LOGGING);
+		purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_LOGGING);
 	}
 }
 
@@ -955,28 +846,6 @@
 	conv->logs = NULL;
 }
 
-PurpleConvIm *
-purple_conversation_get_im_data(const PurpleConversation *conv)
-{
-	g_return_val_if_fail(conv != NULL, NULL);
-
-	if (purple_conversation_get_type(conv) != PURPLE_CONV_TYPE_IM)
-		return NULL;
-
-	return conv->u.im;
-}
-
-PurpleConvChat *
-purple_conversation_get_chat_data(const PurpleConversation *conv)
-{
-	g_return_val_if_fail(conv != NULL, NULL);
-
-	if (purple_conversation_get_type(conv) != PURPLE_CONV_TYPE_CHAT)
-		return NULL;
-
-	return conv->u.chat;
-}
-
 void
 purple_conversation_set_data(PurpleConversation *conv, const char *key,
 						   gpointer data)
@@ -996,62 +865,9 @@
 	return g_hash_table_lookup(conv->data, key);
 }
 
-GList *
-purple_get_conversations(void)
-{
-	return conversations;
-}
-
-GList *
-purple_get_ims(void)
-{
-	return ims;
-}
-
-GList *
-purple_get_chats(void)
-{
-	return chats;
-}
-
-
-PurpleConversation *
-purple_find_conversation_with_account(PurpleConversationType type,
-									const char *name,
-									const PurpleAccount *account)
-{
-	PurpleConversation *c = NULL;
-	struct _purple_hconv hc;
-
-	g_return_val_if_fail(name != NULL, NULL);
-
-	hc.name = (gchar *)purple_normalize(account, name);
-	hc.account = account;
-	hc.type = type;
-
-	switch (type) {
-		case PURPLE_CONV_TYPE_IM:
-		case PURPLE_CONV_TYPE_CHAT:
-			c = g_hash_table_lookup(conversation_cache, &hc);
-			break;
-		case PURPLE_CONV_TYPE_ANY:
-			hc.type = PURPLE_CONV_TYPE_IM;
-			c = g_hash_table_lookup(conversation_cache, &hc);
-			if (!c) {
-				hc.type = PURPLE_CONV_TYPE_CHAT;
-				c = g_hash_table_lookup(conversation_cache, &hc);
-			}
-			break;
-		default:
-			g_return_val_if_reached(NULL);
-	}
-
-	return c;
-}
-
 void
 purple_conversation_write(PurpleConversation *conv, const char *who,
-						const char *message, PurpleMessageFlags flags,
+						const char *message, PurpleConversationMessageFlags flags,
 						time_t mtime)
 {
 	PurplePluginProtocolInfo *prpl_info = NULL;
@@ -1076,12 +892,12 @@
 	if (account != NULL)
 		gc = purple_account_get_connection(account);
 
-	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT &&
+	if (purple_conversation_get_type(conv) == PURPLE_CONVERSATION_TYPE_CHAT &&
 		(gc != NULL && !g_slist_find(gc->buddy_chats, conv)))
 		return;
 
-	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM &&
-		!g_list_find(purple_get_conversations(), conv))
+	if (purple_conversation_get_type(conv) == PURPLE_CONVERSATION_TYPE_IM &&
+		!g_list_find(purple_conversations_get(), conv))
 		return;
 
 	displayed = g_strdup(message);
@@ -1093,7 +909,7 @@
 	plugin_return =
 		GPOINTER_TO_INT(purple_signal_emit_return_1(
 			purple_conversations_get_handle(),
-			(type == PURPLE_CONV_TYPE_IM ? "writing-im-msg" : "writing-chat-msg"),
+			(type == PURPLE_CONVERSATION_TYPE_IM ? "writing-im-msg" : "writing-chat-msg"),
 			account, who, &displayed, conv, flags));
 
 	if (displayed == NULL)
@@ -1107,15 +923,15 @@
 	if (account != NULL) {
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account)));
 
-		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM ||
+		if (purple_conversation_get_type(conv) == PURPLE_CONVERSATION_TYPE_IM ||
 			!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
 
-			if (flags & PURPLE_MESSAGE_SEND) {
+			if (flags & PURPLE_CONVERSATION_MESSAGE_SEND) {
 				b = purple_find_buddy(account,
 							purple_account_get_username(account));
 
-				if (purple_account_get_alias(account) != NULL)
-					alias = purple_account_get_alias(account);
+				if (purple_account_get_private_alias(account) != NULL)
+					alias = purple_account_get_private_alias(account);
 				else if (b != NULL && !purple_strequal(purple_buddy_get_name(b), purple_buddy_get_contact_alias(b)))
 					alias = purple_buddy_get_contact_alias(b);
 				else if (purple_connection_get_display_name(gc) != NULL)
@@ -1133,7 +949,7 @@
 		}
 	}
 
-	if (!(flags & PURPLE_MESSAGE_NO_LOG) && purple_conversation_is_logging(conv)) {
+	if (!(flags & PURPLE_CONVERSATION_MESSAGE_NO_LOG) && purple_conversation_is_logging(conv)) {
 		GList *log;
 
 		if (conv->logs == NULL)
@@ -1152,7 +968,7 @@
 	add_message_to_history(conv, who, alias, message, flags, mtime);
 
 	purple_signal_emit(purple_conversations_get_handle(),
-		(type == PURPLE_CONV_TYPE_IM ? "wrote-im-msg" : "wrote-chat-msg"),
+		(type == PURPLE_CONVERSATION_TYPE_IM ? "wrote-im-msg" : "wrote-chat-msg"),
 		account, who, displayed, conv, flags);
 
 	g_free(displayed);
@@ -1181,7 +997,7 @@
  * when chats are added/removed from the blist.
  */
 void
-purple_conversation_update(PurpleConversation *conv, PurpleConvUpdateType type)
+purple_conversation_update(PurpleConversation *conv, PurpleConversationUpdateType type)
 {
 	g_return_if_fail(conv != NULL);
 
@@ -1189,194 +1005,7 @@
 					 "conversation-updated", conv, type);
 }
 
-/**************************************************************************
- * IM Conversation API
- **************************************************************************/
-PurpleConversation *
-purple_conv_im_get_conversation(const PurpleConvIm *im)
-{
-	g_return_val_if_fail(im != NULL, NULL);
-
-	return im->conv;
-}
-
-void
-purple_conv_im_set_icon(PurpleConvIm *im, PurpleBuddyIcon *icon)
-{
-	g_return_if_fail(im != NULL);
-
-	if (im->icon != icon)
-	{
-		purple_buddy_icon_unref(im->icon);
-
-		im->icon = (icon == NULL ? NULL : purple_buddy_icon_ref(icon));
-	}
-
-	purple_conversation_update(purple_conv_im_get_conversation(im),
-							 PURPLE_CONV_UPDATE_ICON);
-}
-
-PurpleBuddyIcon *
-purple_conv_im_get_icon(const PurpleConvIm *im)
-{
-	g_return_val_if_fail(im != NULL, NULL);
-
-	return im->icon;
-}
-
-void
-purple_conv_im_set_typing_state(PurpleConvIm *im, PurpleTypingState state)
-{
-	g_return_if_fail(im != NULL);
-
-	if (im->typing_state != state)
-	{
-		im->typing_state = state;
-
-		switch (state)
-		{
-			case PURPLE_TYPING:
-				purple_signal_emit(purple_conversations_get_handle(),
-								   "buddy-typing", im->conv->account, im->conv->name);
-				break;
-			case PURPLE_TYPED:
-				purple_signal_emit(purple_conversations_get_handle(),
-								   "buddy-typed", im->conv->account, im->conv->name);
-				break;
-			case PURPLE_NOT_TYPING:
-				purple_signal_emit(purple_conversations_get_handle(),
-								   "buddy-typing-stopped", im->conv->account, im->conv->name);
-				break;
-		}
-
-		purple_conv_im_update_typing(im);
-	}
-}
-
-PurpleTypingState
-purple_conv_im_get_typing_state(const PurpleConvIm *im)
-{
-	g_return_val_if_fail(im != NULL, 0);
-
-	return im->typing_state;
-}
-
-void
-purple_conv_im_start_typing_timeout(PurpleConvIm *im, int timeout)
-{
-	PurpleConversation *conv;
-
-	g_return_if_fail(im != NULL);
-
-	if (im->typing_timeout > 0)
-		purple_conv_im_stop_typing_timeout(im);
-
-	conv = purple_conv_im_get_conversation(im);
-
-	im->typing_timeout = purple_timeout_add_seconds(timeout, reset_typing_cb, conv);
-}
-
-void
-purple_conv_im_stop_typing_timeout(PurpleConvIm *im)
-{
-	g_return_if_fail(im != NULL);
-
-	if (im->typing_timeout == 0)
-		return;
-
-	purple_timeout_remove(im->typing_timeout);
-	im->typing_timeout = 0;
-}
-
-guint
-purple_conv_im_get_typing_timeout(const PurpleConvIm *im)
-{
-	g_return_val_if_fail(im != NULL, 0);
-
-	return im->typing_timeout;
-}
-
-void
-purple_conv_im_set_type_again(PurpleConvIm *im, unsigned int val)
-{
-	g_return_if_fail(im != NULL);
-
-	if (val == 0)
-		im->type_again = 0;
-	else
-		im->type_again = time(NULL) + val;
-}
-
-time_t
-purple_conv_im_get_type_again(const PurpleConvIm *im)
-{
-	g_return_val_if_fail(im != NULL, 0);
-
-	return im->type_again;
-}
-
-void
-purple_conv_im_start_send_typed_timeout(PurpleConvIm *im)
-{
-	g_return_if_fail(im != NULL);
-
-	im->send_typed_timeout = purple_timeout_add_seconds(SEND_TYPED_TIMEOUT_SECONDS,
-	                                                    send_typed_cb,
-	                                                    purple_conv_im_get_conversation(im));
-}
-
-void
-purple_conv_im_stop_send_typed_timeout(PurpleConvIm *im)
-{
-	g_return_if_fail(im != NULL);
-
-	if (im->send_typed_timeout == 0)
-		return;
-
-	purple_timeout_remove(im->send_typed_timeout);
-	im->send_typed_timeout = 0;
-}
-
-guint
-purple_conv_im_get_send_typed_timeout(const PurpleConvIm *im)
-{
-	g_return_val_if_fail(im != NULL, 0);
-
-	return im->send_typed_timeout;
-}
-
-void
-purple_conv_im_update_typing(PurpleConvIm *im)
-{
-	g_return_if_fail(im != NULL);
-
-	purple_conversation_update(purple_conv_im_get_conversation(im),
-							 PURPLE_CONV_UPDATE_TYPING);
-}
-
-void
-purple_conv_im_write(PurpleConvIm *im, const char *who, const char *message,
-			  PurpleMessageFlags flags, time_t mtime)
-{
-	PurpleConversation *c;
-
-	g_return_if_fail(im != NULL);
-	g_return_if_fail(message != NULL);
-
-	c = purple_conv_im_get_conversation(im);
-
-	if ((flags & PURPLE_MESSAGE_RECV) == PURPLE_MESSAGE_RECV) {
-		purple_conv_im_set_typing_state(im, PURPLE_NOT_TYPING);
-	}
-
-	/* Pass this on to either the ops structure or the default write func. */
-	if (c->ui_ops != NULL && c->ui_ops->write_im != NULL)
-		c->ui_ops->write_im(c, who, message, flags, mtime);
-	else
-		purple_conversation_write(c, who, message, flags, mtime);
-}
-
-gboolean purple_conv_present_error(const char *who, PurpleAccount *account, const char *what)
+gboolean purple_conversation_helper_present_error(const char *who, PurpleAccount *account, const char *what)
 {
 	PurpleConversation *conv;
 
@@ -1384,23 +1013,17 @@
 	g_return_val_if_fail(account !=NULL, FALSE);
 	g_return_val_if_fail(what != NULL, FALSE);
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, account);
+	conv = purple_conversations_find_with_account(PURPLE_CONVERSATION_TYPE_ANY, who, account);
 	if (conv != NULL)
-		purple_conversation_write(conv, NULL, what, PURPLE_MESSAGE_ERROR, time(NULL));
+		purple_conversation_write(conv, NULL, what, PURPLE_CONVERSATION_MESSAGE_ERROR, time(NULL));
 	else
 		return FALSE;
 
 	return TRUE;
 }
 
-void
-purple_conv_im_send(PurpleConvIm *im, const char *message)
-{
-	purple_conv_im_send_with_flags(im, message, 0);
-}
-
 static void
-purple_conv_send_confirm_cb(gpointer *data)
+purple_conversation_send_confirm_cb(gpointer *data)
 {
 	PurpleConversation *conv = data[0];
 	char *message = data[1];
@@ -1410,7 +1033,7 @@
 }
 
 void
-purple_conv_send_confirm(PurpleConversation *conv, const char *message)
+purple_conversation_send_confirm(PurpleConversation *conv, const char *message)
 {
 	char *text;
 	gpointer *data;
@@ -1432,21 +1055,12 @@
 	purple_request_action(conv, NULL, _("Send Message"), text, 0,
 						  purple_conversation_get_account(conv), NULL, conv,
 						  data, 2,
-						  _("_Send Message"), G_CALLBACK(purple_conv_send_confirm_cb),
+						  _("_Send Message"), G_CALLBACK(purple_conversation_send_confirm_cb),
 						  _("Cancel"), NULL);
 }
 
-void
-purple_conv_im_send_with_flags(PurpleConvIm *im, const char *message, PurpleMessageFlags flags)
-{
-	g_return_if_fail(im != NULL);
-	g_return_if_fail(message != NULL);
-
-	common_send(purple_conv_im_get_conversation(im), message, flags);
-}
-
 gboolean
-purple_conv_custom_smiley_add(PurpleConversation *conv, const char *smile,
+purple_conversation_custom_smiley_add(PurpleConversation *conv, const char *smile,
                             const char *cksum_type, const char *chksum,
 							gboolean remote)
 {
@@ -1466,7 +1080,7 @@
 }
 
 void
-purple_conv_custom_smiley_write(PurpleConversation *conv, const char *smile,
+purple_conversation_custom_smiley_write(PurpleConversation *conv, const char *smile,
                                    const guchar *data, gsize size)
 {
 	g_return_if_fail(conv != NULL);
@@ -1479,7 +1093,7 @@
 }
 
 void
-purple_conv_custom_smiley_close(PurpleConversation *conv, const char *smile)
+purple_conversation_custom_smiley_close(PurpleConversation *conv, const char *smile)
 {
 	g_return_if_fail(conv != NULL);
 	g_return_if_fail(smile != NULL && *smile);
@@ -1490,728 +1104,35 @@
 		purple_debug_info("conversation", "Could not find custom smiley close function");
 }
 
-
-/**************************************************************************
- * Chat Conversation API
- **************************************************************************/
-
-PurpleConversation *
-purple_conv_chat_get_conversation(const PurpleConvChat *chat)
-{
-	g_return_val_if_fail(chat != NULL, NULL);
-
-	return chat->conv;
-}
-
-GList *
-purple_conv_chat_get_users(const PurpleConvChat *chat)
-{
-	g_return_val_if_fail(chat != NULL, NULL);
-
-	return chat->in_room;
-}
-
-void
-purple_conv_chat_ignore(PurpleConvChat *chat, const char *name)
-{
-	g_return_if_fail(chat != NULL);
-	g_return_if_fail(name != NULL);
-
-	/* Make sure the user isn't already ignored. */
-	if (purple_conv_chat_is_user_ignored(chat, name))
-		return;
-
-	purple_conv_chat_set_ignored(chat,
-		g_list_append(chat->ignored, g_strdup(name)));
-}
-
-void
-purple_conv_chat_unignore(PurpleConvChat *chat, const char *name)
-{
-	GList *item;
-
-	g_return_if_fail(chat != NULL);
-	g_return_if_fail(name != NULL);
-
-	/* Make sure the user is actually ignored. */
-	if (!purple_conv_chat_is_user_ignored(chat, name))
-		return;
-
-	item = g_list_find(purple_conv_chat_get_ignored(chat),
-					   purple_conv_chat_get_ignored_user(chat, name));
-
-	purple_conv_chat_set_ignored(chat,
-		g_list_remove_link(chat->ignored, item));
-
-	g_free(item->data);
-	g_list_free_1(item);
-}
-
-GList *
-purple_conv_chat_set_ignored(PurpleConvChat *chat, GList *ignored)
-{
-	g_return_val_if_fail(chat != NULL, NULL);
-
-	chat->ignored = ignored;
-
-	return ignored;
-}
-
-GList *
-purple_conv_chat_get_ignored(const PurpleConvChat *chat)
-{
-	g_return_val_if_fail(chat != NULL, NULL);
-
-	return chat->ignored;
-}
-
-const char *
-purple_conv_chat_get_ignored_user(const PurpleConvChat *chat, const char *user)
-{
-	GList *ignored;
-
-	g_return_val_if_fail(chat != NULL, NULL);
-	g_return_val_if_fail(user != NULL, NULL);
-
-	for (ignored = purple_conv_chat_get_ignored(chat);
-		 ignored != NULL;
-		 ignored = ignored->next) {
-
-		const char *ign = (const char *)ignored->data;
-
-		if (!purple_utf8_strcasecmp(user, ign) ||
-			((*ign == '+' || *ign == '%') && !purple_utf8_strcasecmp(user, ign + 1)))
-			return ign;
-
-		if (*ign == '@') {
-			ign++;
-
-			if ((*ign == '+' && !purple_utf8_strcasecmp(user, ign + 1)) ||
-				(*ign != '+' && !purple_utf8_strcasecmp(user, ign)))
-				return ign;
-		}
-	}
-
-	return NULL;
-}
-
-gboolean
-purple_conv_chat_is_user_ignored(const PurpleConvChat *chat, const char *user)
-{
-	g_return_val_if_fail(chat != NULL, FALSE);
-	g_return_val_if_fail(user != NULL, FALSE);
-
-	return (purple_conv_chat_get_ignored_user(chat, user) != NULL);
-}
-
-void
-purple_conv_chat_set_topic(PurpleConvChat *chat, const char *who, const char *topic)
-{
-	g_return_if_fail(chat != NULL);
-
-	g_free(chat->who);
-	g_free(chat->topic);
-
-	chat->who   = g_strdup(who);
-	chat->topic = g_strdup(topic);
-
-	purple_conversation_update(purple_conv_chat_get_conversation(chat),
-							 PURPLE_CONV_UPDATE_TOPIC);
-
-	purple_signal_emit(purple_conversations_get_handle(), "chat-topic-changed",
-					 chat->conv, chat->who, chat->topic);
-}
-
-const char *
-purple_conv_chat_get_topic(const PurpleConvChat *chat)
-{
-	g_return_val_if_fail(chat != NULL, NULL);
-
-	return chat->topic;
-}
-
-void
-purple_conv_chat_set_id(PurpleConvChat *chat, int id)
-{
-	g_return_if_fail(chat != NULL);
-
-	chat->id = id;
-}
-
-int
-purple_conv_chat_get_id(const PurpleConvChat *chat)
-{
-	g_return_val_if_fail(chat != NULL, -1);
-
-	return chat->id;
-}
-
-void
-purple_conv_chat_write(PurpleConvChat *chat, const char *who, const char *message,
-				PurpleMessageFlags flags, time_t mtime)
-{
-	PurpleAccount *account;
-	PurpleConversation *conv;
-	PurpleConnection *gc;
-
-	g_return_if_fail(chat != NULL);
-	g_return_if_fail(who != NULL);
-	g_return_if_fail(message != NULL);
-
-	conv      = purple_conv_chat_get_conversation(chat);
-	gc        = purple_conversation_get_connection(conv);
-	account   = purple_connection_get_account(gc);
-
-	/* Don't display this if the person who wrote it is ignored. */
-	if (purple_conv_chat_is_user_ignored(chat, who))
-		return;
-
-	if (!(flags & PURPLE_MESSAGE_WHISPER)) {
-		const char *str;
-
-		str = purple_normalize(account, who);
-
-		if (purple_strequal(str, chat->nick)) {
-			flags |= PURPLE_MESSAGE_SEND;
-		} else {
-			flags |= PURPLE_MESSAGE_RECV;
-
-			if (purple_utf8_has_word(message, chat->nick))
-				flags |= PURPLE_MESSAGE_NICK;
-		}
-	}
-
-	/* Pass this on to either the ops structure or the default write func. */
-	if (conv->ui_ops != NULL && conv->ui_ops->write_chat != NULL)
-		conv->ui_ops->write_chat(conv, who, message, flags, mtime);
-	else
-		purple_conversation_write(conv, who, message, flags, mtime);
-}
-
-void
-purple_conv_chat_send(PurpleConvChat *chat, const char *message)
-{
-	purple_conv_chat_send_with_flags(chat, message, 0);
-}
-
-void
-purple_conv_chat_send_with_flags(PurpleConvChat *chat, const char *message, PurpleMessageFlags flags)
-{
-	g_return_if_fail(chat != NULL);
-	g_return_if_fail(message != NULL);
-
-	common_send(purple_conv_chat_get_conversation(chat), message, flags);
-}
-
-void
-purple_conv_chat_add_user(PurpleConvChat *chat, const char *user,
-						const char *extra_msg, PurpleConvChatBuddyFlags flags,
-						gboolean new_arrival)
-{
-	GList *users = g_list_append(NULL, (char *)user);
-	GList *extra_msgs = g_list_append(NULL, (char *)extra_msg);
-	GList *flags2 = g_list_append(NULL, GINT_TO_POINTER(flags));
-
-	purple_conv_chat_add_users(chat, users, extra_msgs, flags2, new_arrival);
-
-	g_list_free(users);
-	g_list_free(extra_msgs);
-	g_list_free(flags2);
-}
-
-static int
-purple_conv_chat_cb_compare(PurpleConvChatBuddy *a, PurpleConvChatBuddy *b)
-{
-	PurpleConvChatBuddyFlags f1 = 0, f2 = 0;
-	char *user1 = NULL, *user2 = NULL;
-	gint ret = 0;
-
-	if (a) {
-		f1 = a->flags;
-		if (a->alias_key)
-			user1 = a->alias_key;
-		else if (a->name)
-			user1 = a->name;
-	}
-
-	if (b) {
-		f2 = b->flags;
-		if (b->alias_key)
-			user2 = b->alias_key;
-		else if (b->name)
-			user2 = b->name;
-	}
-
-	if (user1 == NULL || user2 == NULL) {
-		if (!(user1 == NULL && user2 == NULL))
-			ret = (user1 == NULL) ? -1: 1;
-	} else if (f1 != f2) {
-		/* sort more important users first */
-		ret = (f1 > f2) ? -1 : 1;
-	} else if (a->buddy != b->buddy) {
-		ret = a->buddy ? -1 : 1;
-	} else {
-		ret = purple_utf8_strcasecmp(user1, user2);
-	}
-
-	return ret;
-}
-
-void
-purple_conv_chat_add_users(PurpleConvChat *chat, GList *users, GList *extra_msgs,
-						 GList *flags, gboolean new_arrivals)
-{
-	PurpleConversation *conv;
-	PurpleConversationUiOps *ops;
-	PurpleConvChatBuddy *cbuddy;
-	PurpleConnection *gc;
-	PurplePluginProtocolInfo *prpl_info;
-	GList *ul, *fl;
-	GList *cbuddies = NULL;
-
-	g_return_if_fail(chat  != NULL);
-	g_return_if_fail(users != NULL);
-
-	conv = purple_conv_chat_get_conversation(chat);
-	ops  = purple_conversation_get_ui_ops(conv);
-
-	gc = purple_conversation_get_connection(conv);
-	g_return_if_fail(gc != NULL);
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
-	g_return_if_fail(prpl_info != NULL);
-
-	ul = users;
-	fl = flags;
-	while ((ul != NULL) && (fl != NULL)) {
-		const char *user = (const char *)ul->data;
-		const char *alias = user;
-		gboolean quiet;
-		PurpleConvChatBuddyFlags flag = GPOINTER_TO_INT(fl->data);
-		const char *extra_msg = (extra_msgs ? extra_msgs->data : NULL);
-
-		if(!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
-			if (purple_strequal(chat->nick, purple_normalize(conv->account, user))) {
-				const char *alias2 = purple_account_get_alias(conv->account);
-				if (alias2 != NULL)
-					alias = alias2;
-				else
-				{
-					const char *display_name = purple_connection_get_display_name(gc);
-					if (display_name != NULL)
-						alias = display_name;
-				}
-			} else {
-				PurpleBuddy *buddy;
-				if ((buddy = purple_find_buddy(purple_connection_get_account(gc), user)) != NULL)
-					alias = purple_buddy_get_contact_alias(buddy);
-			}
-		}
-
-		quiet = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
-						 "chat-buddy-joining", conv, user, flag)) ||
-				purple_conv_chat_is_user_ignored(chat, user);
-
-		cbuddy = purple_conv_chat_cb_new(user, alias, flag);
-		cbuddy->buddy = purple_find_buddy(conv->account, user) != NULL;
-
-		chat->in_room = g_list_prepend(chat->in_room, cbuddy);
-		g_hash_table_replace(chat->users, g_strdup(cbuddy->name), cbuddy);
-
-		cbuddies = g_list_prepend(cbuddies, cbuddy);
-
-		if (!quiet && new_arrivals) {
-			char *alias_esc = g_markup_escape_text(alias, -1);
-			char *tmp;
-
-			if (extra_msg == NULL)
-				tmp = g_strdup_printf(_("%s entered the room."), alias_esc);
-			else {
-				char *extra_msg_esc = g_markup_escape_text(extra_msg, -1);
-				tmp = g_strdup_printf(_("%s [<I>%s</I>] entered the room."),
-				                      alias_esc, extra_msg_esc);
-				g_free(extra_msg_esc);
-			}
-			g_free(alias_esc);
-
-			purple_conversation_write(conv, NULL, tmp,
-					PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
-					time(NULL));
-			g_free(tmp);
-		}
-
-		purple_signal_emit(purple_conversations_get_handle(),
-						 "chat-buddy-joined", conv, user, flag, new_arrivals);
-		ul = ul->next;
-		fl = fl->next;
-		if (extra_msgs != NULL)
-			extra_msgs = extra_msgs->next;
-	}
-
-	cbuddies = g_list_sort(cbuddies, (GCompareFunc)purple_conv_chat_cb_compare);
-
-	if (ops != NULL && ops->chat_add_users != NULL)
-		ops->chat_add_users(conv, cbuddies, new_arrivals);
-
-	g_list_free(cbuddies);
-}
-
-void
-purple_conv_chat_rename_user(PurpleConvChat *chat, const char *old_user,
-						   const char *new_user)
-{
-	PurpleConversation *conv;
-	PurpleConversationUiOps *ops;
-	PurpleConnection *gc;
-	PurplePluginProtocolInfo *prpl_info;
-	PurpleConvChatBuddy *cb;
-	PurpleConvChatBuddyFlags flags;
-	const char *new_alias = new_user;
-	char tmp[BUF_LONG];
-	gboolean is_me = FALSE;
-
-	g_return_if_fail(chat != NULL);
-	g_return_if_fail(old_user != NULL);
-	g_return_if_fail(new_user != NULL);
-
-	conv = purple_conv_chat_get_conversation(chat);
-	ops  = purple_conversation_get_ui_ops(conv);
-
-	gc = purple_conversation_get_connection(conv);
-	g_return_if_fail(gc != NULL);
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
-	g_return_if_fail(prpl_info != NULL);
-
-	if (purple_strequal(chat->nick, purple_normalize(conv->account, old_user))) {
-		const char *alias;
-
-		/* Note this for later. */
-		is_me = TRUE;
-
-		if(!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
-			alias = purple_account_get_alias(conv->account);
-			if (alias != NULL)
-				new_alias = alias;
-			else
-			{
-				const char *display_name = purple_connection_get_display_name(gc);
-				if (display_name != NULL)
-					new_alias = display_name;
-			}
-		}
-	} else if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
-		PurpleBuddy *buddy;
-		if ((buddy = purple_find_buddy(purple_connection_get_account(gc), new_user)) != NULL)
-			new_alias = purple_buddy_get_contact_alias(buddy);
-	}
-
-	flags = purple_conv_chat_user_get_flags(chat, old_user);
-	cb = purple_conv_chat_cb_new(new_user, new_alias, flags);
-	cb->buddy = purple_find_buddy(conv->account, new_user) != NULL;
-
-	chat->in_room = g_list_prepend(chat->in_room, cb);
-	g_hash_table_replace(chat->users, g_strdup(cb->name), cb);
-
-	if (ops != NULL && ops->chat_rename_user != NULL)
-		ops->chat_rename_user(conv, old_user, new_user, new_alias);
-
-	cb = purple_conv_chat_cb_find(chat, old_user);
-
-	if (cb) {
-		chat->in_room = g_list_remove(chat->in_room, cb);
-		g_hash_table_remove(chat->users, cb->name);
-		purple_conv_chat_cb_destroy(cb);
-	}
-
-	if (purple_conv_chat_is_user_ignored(chat, old_user)) {
-		purple_conv_chat_unignore(chat, old_user);
-		purple_conv_chat_ignore(chat, new_user);
-	}
-	else if (purple_conv_chat_is_user_ignored(chat, new_user))
-		purple_conv_chat_unignore(chat, new_user);
-
-	if (is_me)
-		purple_conv_chat_set_nick(chat, new_user);
-
-	if (purple_prefs_get_bool("/purple/conversations/chat/show_nick_change") &&
-	    !purple_conv_chat_is_user_ignored(chat, new_user)) {
-
-		if (is_me) {
-			char *escaped = g_markup_escape_text(new_user, -1);
-			g_snprintf(tmp, sizeof(tmp),
-					_("You are now known as %s"), escaped);
-			g_free(escaped);
-		} else {
-			const char *old_alias = old_user;
-			const char *new_alias = new_user;
-			char *escaped;
-			char *escaped2;
-
-			if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
-				PurpleBuddy *buddy;
-
-				if ((buddy = purple_find_buddy(purple_connection_get_account(gc), old_user)) != NULL)
-					old_alias = purple_buddy_get_contact_alias(buddy);
-				if ((buddy = purple_find_buddy(purple_connection_get_account(gc), new_user)) != NULL)
-					new_alias = purple_buddy_get_contact_alias(buddy);
-			}
-
-			escaped = g_markup_escape_text(old_alias, -1);
-			escaped2 = g_markup_escape_text(new_alias, -1);
-			g_snprintf(tmp, sizeof(tmp),
-					_("%s is now known as %s"), escaped, escaped2);
-			g_free(escaped);
-			g_free(escaped2);
-		}
-
-		purple_conversation_write(conv, NULL, tmp,
-				PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
-				time(NULL));
-	}
-}
-
-void
-purple_conv_chat_remove_user(PurpleConvChat *chat, const char *user, const char *reason)
-{
-	GList *users = g_list_append(NULL, (char *)user);
-
-	purple_conv_chat_remove_users(chat, users, reason);
-
-	g_list_free(users);
-}
-
-void
-purple_conv_chat_remove_users(PurpleConvChat *chat, GList *users, const char *reason)
-{
-	PurpleConversation *conv;
-	PurpleConnection *gc;
-	PurplePluginProtocolInfo *prpl_info;
-	PurpleConversationUiOps *ops;
-	PurpleConvChatBuddy *cb;
-	GList *l;
-	gboolean quiet;
-
-	g_return_if_fail(chat  != NULL);
-	g_return_if_fail(users != NULL);
-
-	conv = purple_conv_chat_get_conversation(chat);
-
-	gc = purple_conversation_get_connection(conv);
-	g_return_if_fail(gc != NULL);
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
-	g_return_if_fail(prpl_info != NULL);
-
-	ops  = purple_conversation_get_ui_ops(conv);
-
-	for (l = users; l != NULL; l = l->next) {
-		const char *user = (const char *)l->data;
-		quiet = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
-					"chat-buddy-leaving", conv, user, reason)) |
-				purple_conv_chat_is_user_ignored(chat, user);
-
-		cb = purple_conv_chat_cb_find(chat, user);
-
-		if (cb) {
-			chat->in_room = g_list_remove(chat->in_room, cb);
-			g_hash_table_remove(chat->users, cb->name);
-			purple_conv_chat_cb_destroy(cb);
-		}
-
-		/* NOTE: Don't remove them from ignored in case they re-enter. */
-
-		if (!quiet) {
-			const char *alias = user;
-			char *alias_esc;
-			char *tmp;
-
-			if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
-				PurpleBuddy *buddy;
-
-				if ((buddy = purple_find_buddy(purple_connection_get_account(gc), user)) != NULL)
-					alias = purple_buddy_get_contact_alias(buddy);
-			}
-
-			alias_esc = g_markup_escape_text(alias, -1);
-
-			if (reason == NULL || !*reason)
-				tmp = g_strdup_printf(_("%s left the room."), alias_esc);
-			else {
-				char *reason_esc = g_markup_escape_text(reason, -1);
-				tmp = g_strdup_printf(_("%s left the room (%s)."),
-				                      alias_esc, reason_esc);
-				g_free(reason_esc);
-			}
-			g_free(alias_esc);
-
-			purple_conversation_write(conv, NULL, tmp,
-					PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY,
-					time(NULL));
-			g_free(tmp);
-		}
-
-		purple_signal_emit(purple_conversations_get_handle(), "chat-buddy-left",
-						 conv, user, reason);
-	}
-
-	if (ops != NULL && ops->chat_remove_users != NULL)
-		ops->chat_remove_users(conv, users);
-}
-
-void
-purple_conv_chat_clear_users(PurpleConvChat *chat)
-{
-	PurpleConversation *conv;
-	PurpleConversationUiOps *ops;
-	GList *users;
-	GList *l;
-	GList *names = NULL;
-
-	g_return_if_fail(chat != NULL);
-
-	conv  = purple_conv_chat_get_conversation(chat);
-	ops   = purple_conversation_get_ui_ops(conv);
-	users = chat->in_room;
-
-	if (ops != NULL && ops->chat_remove_users != NULL) {
-		for (l = users; l; l = l->next) {
-			PurpleConvChatBuddy *cb = l->data;
-			names = g_list_prepend(names, cb->name);
-		}
-		ops->chat_remove_users(conv, names);
-		g_list_free(names);
-	}
-
-	for (l = users; l; l = l->next)
-	{
-		PurpleConvChatBuddy *cb = l->data;
-
-		purple_signal_emit(purple_conversations_get_handle(),
-						 "chat-buddy-leaving", conv, cb->name, NULL);
-		purple_signal_emit(purple_conversations_get_handle(),
-						 "chat-buddy-left", conv, cb->name, NULL);
-
-		purple_conv_chat_cb_destroy(cb);
-	}
-
-	g_hash_table_remove_all(chat->users);
-
-	g_list_free(users);
-	chat->in_room = NULL;
-}
-
-
-gboolean
-purple_conv_chat_find_user(PurpleConvChat *chat, const char *user)
-{
-	g_return_val_if_fail(chat != NULL, FALSE);
-	g_return_val_if_fail(user != NULL, FALSE);
-
-	return (purple_conv_chat_cb_find(chat, user) != NULL);
-}
-
-void
-purple_conv_chat_user_set_flags(PurpleConvChat *chat, const char *user,
-							  PurpleConvChatBuddyFlags flags)
-{
-	PurpleConversation *conv;
-	PurpleConversationUiOps *ops;
-	PurpleConvChatBuddy *cb;
-	PurpleConvChatBuddyFlags oldflags;
-
-	g_return_if_fail(chat != NULL);
-	g_return_if_fail(user != NULL);
-
-	cb = purple_conv_chat_cb_find(chat, user);
-
-	if (!cb)
-		return;
-
-	if (flags == cb->flags)
-		return;
-
-	oldflags = cb->flags;
-	cb->flags = flags;
-
-	conv = purple_conv_chat_get_conversation(chat);
-	ops = purple_conversation_get_ui_ops(conv);
-
-	if (ops != NULL && ops->chat_update_user != NULL)
-		ops->chat_update_user(conv, user);
-
-	purple_signal_emit(purple_conversations_get_handle(),
-					 "chat-buddy-flags", conv, user, oldflags, flags);
-}
-
-PurpleConvChatBuddyFlags
-purple_conv_chat_user_get_flags(PurpleConvChat *chat, const char *user)
-{
-	PurpleConvChatBuddy *cb;
-
-	g_return_val_if_fail(chat != NULL, 0);
-	g_return_val_if_fail(user != NULL, 0);
-
-	cb = purple_conv_chat_cb_find(chat, user);
-
-	if (!cb)
-		return PURPLE_CBFLAGS_NONE;
-
-	return cb->flags;
-}
-
-void purple_conv_chat_set_nick(PurpleConvChat *chat, const char *nick) {
+void purple_chat_conversation_set_nick(PurpleChatConversation *chat, const char *nick) {
 	g_return_if_fail(chat != NULL);
 
 	g_free(chat->nick);
 	chat->nick = g_strdup(purple_normalize(chat->conv->account, nick));
 }
 
-const char *purple_conv_chat_get_nick(PurpleConvChat *chat) {
+const char *purple_chat_conversation_get_nick(PurpleChatConversation *chat) {
 	g_return_val_if_fail(chat != NULL, NULL);
 
 	return chat->nick;
 }
 
-PurpleConversation *
-purple_find_chat(const PurpleConnection *gc, int id)
-{
-	GList *l;
-	PurpleConversation *conv;
-
-	for (l = purple_get_chats(); l != NULL; l = l->next) {
-		conv = (PurpleConversation *)l->data;
-
-		if (purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)) == id &&
-			purple_conversation_get_connection(conv) == gc)
-			return conv;
-	}
-
-	return NULL;
-}
-
-void
-purple_conv_chat_left(PurpleConvChat *chat)
-{
-	g_return_if_fail(chat != NULL);
-
-	chat->left = TRUE;
-	purple_conversation_update(chat->conv, PURPLE_CONV_UPDATE_CHATLEFT);
-}
-
 static void
 invite_user_to_chat(gpointer data, PurpleRequestFields *fields)
 {
 	PurpleConversation *conv;
-	PurpleConvChat *chat;
+	PurpleChatConversationPrivate *priv;
 	const char *user, *message;
 
 	conv = data;
-	chat = PURPLE_CONV_CHAT(conv);
+	chat = PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv);
 	user = purple_request_fields_get_string(fields, "screenname");
 	message = purple_request_fields_get_string(fields, "message");
 
 	serv_chat_invite(purple_conversation_get_connection(conv), chat->id, message, user);
 }
 
-void purple_conv_chat_invite_user(PurpleConvChat *chat, const char *user,
+void purple_chat_conversation_invite_user(PurpleChatConversation *chat, const char *user,
 		const char *message, gboolean confirm)
 {
 	PurpleAccount *account;
@@ -2230,7 +1151,7 @@
 
 	if (!confirm) {
 		serv_chat_invite(purple_account_get_connection(account),
-				purple_conv_chat_get_id(chat), message, user);
+				purple_chat_conversation_get_id(chat), message, user);
 		return;
 	}
 
@@ -2256,113 +1177,27 @@
 			conv);
 }
 
-gboolean
-purple_conv_chat_has_left(PurpleConvChat *chat)
-{
-	g_return_val_if_fail(chat != NULL, TRUE);
-
-	return chat->left;
-}
-
-PurpleConvChatBuddy *
-purple_conv_chat_cb_new(const char *name, const char *alias, PurpleConvChatBuddyFlags flags)
-{
-	PurpleConvChatBuddy *cb;
-
-	g_return_val_if_fail(name != NULL, NULL);
-
-	cb = g_new0(PurpleConvChatBuddy, 1);
-	cb->name = g_strdup(name);
-	cb->flags = flags;
-	cb->alias = g_strdup(alias);
-	cb->attributes = g_hash_table_new_full(g_str_hash, g_str_equal,
-										   g_free, g_free);
-
-	PURPLE_DBUS_REGISTER_POINTER(cb, PurpleConvChatBuddy);
-	return cb;
-}
-
-PurpleConvChatBuddy *
-purple_conv_chat_cb_find(PurpleConvChat *chat, const char *name)
-{
-	g_return_val_if_fail(chat != NULL, NULL);
-	g_return_val_if_fail(name != NULL, NULL);
-
-	return g_hash_table_lookup(chat->users, name);
-}
-
-void
-purple_conv_chat_cb_destroy(PurpleConvChatBuddy *cb)
-{
-	if (cb == NULL)
-		return;
-
-	purple_signal_emit(purple_conversations_get_handle(),
-			"deleting-chat-buddy", cb);
-
-	g_free(cb->alias);
-	g_free(cb->alias_key);
-	g_free(cb->name);
-	g_hash_table_destroy(cb->attributes);
-
-	PURPLE_DBUS_UNREGISTER_POINTER(cb);
-	g_free(cb);
-}
-
-void purple_conv_chat_cb_set_ui_data(PurpleConvChatBuddy *cb, gpointer ui_data)
+void purple_chat_conversation_buddy_set_ui_data(PurpleChatConversationBuddy *cb, gpointer ui_data)
 {
 	g_return_if_fail(cb != NULL);
 
 	cb->ui_data = ui_data;
 }
 
-gpointer purple_conv_chat_cb_get_ui_data(const PurpleConvChatBuddy *cb)
+gpointer purple_chat_conversation_buddy_get_ui_data(const PurpleChatConversationBuddy *cb)
 {
 	g_return_val_if_fail(cb != NULL, NULL);
 
 	return cb->ui_data;
 }
 
-const char *
-purple_conv_chat_cb_get_alias(const PurpleConvChatBuddy *cb)
-{
-	g_return_val_if_fail(cb != NULL, NULL);
-
-	return cb->alias;
-}
-
-const char *
-purple_conv_chat_cb_get_name(const PurpleConvChatBuddy *cb)
-{
-	g_return_val_if_fail(cb != NULL, NULL);
-
-	return cb->name;
-}
-
-PurpleConvChatBuddyFlags
-purple_conv_chat_cb_get_flags(const PurpleConvChatBuddy *cb)
-{
-	g_return_val_if_fail(cb != NULL, PURPLE_CBFLAGS_NONE);
-
-	return cb->flags;
-}
-
-gboolean purple_conv_chat_cb_is_buddy(const PurpleConvChatBuddy *cb)
+gboolean purple_chat_conversation_buddy_is_buddy(const PurpleChatConversationBuddy *cb)
 {
 	g_return_val_if_fail(cb != NULL, FALSE);
 
 	return cb->buddy;
 }
 
-const char *
-purple_conv_chat_cb_get_attribute(PurpleConvChatBuddy *cb, const char *key)
-{
-	g_return_val_if_fail(cb != NULL, NULL);
-	g_return_val_if_fail(key != NULL, NULL);
-	
-	return g_hash_table_lookup(cb->attributes, key);
-}
-
 static void
 append_attribute_key(gpointer key, gpointer value, gpointer user_data)
 {
@@ -2371,60 +1206,6 @@
 }
 
 GList *
-purple_conv_chat_cb_get_attribute_keys(PurpleConvChatBuddy *cb)
-{
-	GList *keys = NULL;
-	
-	g_return_val_if_fail(cb != NULL, NULL);
-	
-	g_hash_table_foreach(cb->attributes, (GHFunc)append_attribute_key, &keys);
-	
-	return keys;
-}
-
-void
-purple_conv_chat_cb_set_attribute(PurpleConvChat *chat, PurpleConvChatBuddy *cb, const char *key, const char *value)
-{
-	PurpleConversation *conv;
-	PurpleConversationUiOps *ops;
-	
-	g_return_if_fail(cb != NULL);
-	g_return_if_fail(key != NULL);
-	g_return_if_fail(value != NULL);
-	
-	g_hash_table_replace(cb->attributes, g_strdup(key), g_strdup(value));
-	
-	conv = purple_conv_chat_get_conversation(chat);
-	ops = purple_conversation_get_ui_ops(conv);
-	
-	if (ops != NULL && ops->chat_update_user != NULL)
-		ops->chat_update_user(conv, cb->name);
-}
-
-void
-purple_conv_chat_cb_set_attributes(PurpleConvChat *chat, PurpleConvChatBuddy *cb, GList *keys, GList *values)
-{
-	PurpleConversation *conv;
-	PurpleConversationUiOps *ops;
-	
-	g_return_if_fail(cb != NULL);
-	g_return_if_fail(keys != NULL);
-	g_return_if_fail(values != NULL);
-	
-	while (keys != NULL && values != NULL) {
-		g_hash_table_replace(cb->attributes, g_strdup(keys->data), g_strdup(values->data));
-		keys = g_list_next(keys);
-		values = g_list_next(values);
-	}
-	
-	conv = purple_conv_chat_get_conversation(chat);
-	ops = purple_conversation_get_ui_ops(conv);
-	
-	if (ops != NULL && ops->chat_update_user != NULL)
-		ops->chat_update_user(conv, cb->name);
-}
-
-GList *
 purple_conversation_get_extended_menu(PurpleConversation *conv)
 {
 	GList *menu = NULL;
@@ -2451,37 +1232,37 @@
 	return conv->message_history;
 }
 
-const char *purple_conversation_message_get_sender(const PurpleConvMessage *msg)
+const char *purple_conversation_message_get_sender(const PurpleConversationMessage *msg)
 {
 	g_return_val_if_fail(msg, NULL);
 	return msg->who;
 }
 
-const char *purple_conversation_message_get_message(const PurpleConvMessage *msg)
+const char *purple_conversation_message_get_message(const PurpleConversationMessage *msg)
 {
 	g_return_val_if_fail(msg, NULL);
 	return msg->what;
 }
 
-PurpleMessageFlags purple_conversation_message_get_flags(const PurpleConvMessage *msg)
+PurpleConversationMessageFlags purple_conversation_message_get_flags(const PurpleConversationMessage *msg)
 {
 	g_return_val_if_fail(msg, 0);
 	return msg->flags;
 }
 
-time_t purple_conversation_message_get_timestamp(const PurpleConvMessage *msg)
+time_t purple_conversation_message_get_timestamp(const PurpleConversationMessage *msg)
 {
 	g_return_val_if_fail(msg, 0);
 	return msg->when;
 }
 
-const char *purple_conversation_message_get_alias(const PurpleConvMessage *msg)
+const char *purple_conversation_message_get_alias(const PurpleConversationMessage *msg)
 {
 	g_return_val_if_fail(msg, NULL);
 	return msg->alias;
 }
 
-PurpleConversation *purple_conversation_message_get_conv(const PurpleConvMessage *msg)
+PurpleConversation *purple_conversation_message_get_conv(const PurpleConversationMessage *msg)
 {
 	g_return_val_if_fail(msg, NULL);
 	return msg->conv;
@@ -2512,344 +1293,3 @@
 	g_free(err);
 	return (status == PURPLE_CMD_STATUS_OK);
 }
-
-void *
-purple_conversations_get_handle(void)
-{
-	static int handle;
-
-	return &handle;
-}
-
-void
-purple_conversations_init(void)
-{
-	void *handle = purple_conversations_get_handle();
-
-	conversation_cache = g_hash_table_new_full((GHashFunc)_purple_conversations_hconv_hash,
-						(GEqualFunc)_purple_conversations_hconv_equal,
-						(GDestroyNotify)_purple_conversations_hconv_free_key, NULL);
-
-	/**********************************************************************
-	 * Register preferences
-	 **********************************************************************/
-
-	/* Conversations */
-	purple_prefs_add_none("/purple/conversations");
-
-	/* Conversations -> Chat */
-	purple_prefs_add_none("/purple/conversations/chat");
-	purple_prefs_add_bool("/purple/conversations/chat/show_nick_change", TRUE);
-
-	/* Conversations -> IM */
-	purple_prefs_add_none("/purple/conversations/im");
-	purple_prefs_add_bool("/purple/conversations/im/send_typing", TRUE);
-
-
-	/**********************************************************************
-	 * Register signals
-	 **********************************************************************/
-	purple_signal_register(handle, "writing-im-msg",
-						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_UINT,
-						 purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "wrote-im-msg",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
-						 NULL, 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "sent-attention",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT,
-						 NULL, 4,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "got-attention",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT,
-						 NULL, 4,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "sending-im-msg",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER,
-						 NULL, 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new_outgoing(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "sent-im-msg",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER,
-						 NULL, 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "receiving-im-msg",
-						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
-						 purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
-						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new_outgoing(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "received-im-msg",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
-						 NULL, 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "blocked-im-msg",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT_UINT,
-						 NULL, 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-							 PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_UINT),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "writing-chat-msg",
-						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_UINT,
-						 purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "wrote-chat-msg",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
-						 NULL, 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "sending-chat-msg",
-						 purple_marshal_VOID__POINTER_POINTER_UINT, NULL, 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "sent-chat-msg",
-						 purple_marshal_VOID__POINTER_POINTER_UINT, NULL, 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "receiving-chat-msg",
-						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
-						 purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
-						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new_outgoing(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "received-chat-msg",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
-						 NULL, 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "conversation-created",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION));
-
-	purple_signal_register(handle, "conversation-updated",
-						 purple_marshal_VOID__POINTER_UINT, NULL, 2,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "deleting-conversation",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION));
-
-	purple_signal_register(handle, "buddy-typing",
-						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "buddy-typed",
-						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "buddy-typing-stopped",
-						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "chat-buddy-joining",
-						 purple_marshal_BOOLEAN__POINTER_POINTER_UINT,
-						 purple_value_new(PURPLE_TYPE_BOOLEAN), 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "chat-buddy-joined",
-						 purple_marshal_VOID__POINTER_POINTER_UINT_UINT, NULL, 4,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_UINT),
-						 purple_value_new(PURPLE_TYPE_BOOLEAN));
-
-	purple_signal_register(handle, "chat-buddy-flags",
-						 purple_marshal_VOID__POINTER_POINTER_UINT_UINT, NULL, 4,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_UINT),
-						 purple_value_new(PURPLE_TYPE_UINT));
-
-	purple_signal_register(handle, "chat-buddy-leaving",
-						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER,
-						 purple_value_new(PURPLE_TYPE_BOOLEAN), 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "chat-buddy-left",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "deleting-chat-buddy",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CHATBUDDY));
-
-	purple_signal_register(handle, "chat-inviting-user",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new_outgoing(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "chat-invited-user",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "chat-invited",
-						 purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER,
-						 purple_value_new(PURPLE_TYPE_INT), 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_POINTER));
-
-	purple_signal_register(handle, "chat-invite-blocked",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_POINTER,
-						 NULL, 5,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-							 PURPLE_SUBTYPE_ACCOUNT),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_BOXED, "GHashTable *"));
-
-	purple_signal_register(handle, "chat-joined",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION));
-
-	purple_signal_register(handle, "chat-join-failed",
-						   purple_marshal_VOID__POINTER_POINTER, NULL, 2,
-						   purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONNECTION),
-						   purple_value_new(PURPLE_TYPE_POINTER));
-
-	purple_signal_register(handle, "chat-left",
-						 purple_marshal_VOID__POINTER, NULL, 1,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION));
-
-	purple_signal_register(handle, "chat-topic-changed",
-						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
-						 purple_value_new(PURPLE_TYPE_SUBTYPE,
-										PURPLE_SUBTYPE_CONVERSATION),
-						 purple_value_new(PURPLE_TYPE_STRING),
-						 purple_value_new(PURPLE_TYPE_STRING));
-
-	purple_signal_register(handle, "cleared-message-history",
-	                       purple_marshal_VOID__POINTER, NULL, 1,
-	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
-	                                        PURPLE_SUBTYPE_CONVERSATION));
-
-	purple_signal_register(handle, "conversation-extended-menu",
-			     purple_marshal_VOID__POINTER_POINTER, NULL, 2,
-			     purple_value_new(PURPLE_TYPE_SUBTYPE,
-					    PURPLE_SUBTYPE_CONVERSATION),
-			     purple_value_new(PURPLE_TYPE_BOXED, "GList **"));
-}
-
-void
-purple_conversations_uninit(void)
-{
-	while (conversations)
-		purple_conversation_destroy((PurpleConversation*)conversations->data);
-	g_hash_table_destroy(conversation_cache);
-	purple_signals_unregister_by_instance(purple_conversations_get_handle());
-}
-
--- a/libpurple/conversation.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/conversation.h	Sun Jun 23 13:35:53 2013 +0530
@@ -1,7 +1,6 @@
 /**
  * @file conversation.h Conversation API
  * @ingroup core
- * @see @ref conversation-signals
  */
 
 /* purple
@@ -27,128 +26,133 @@
 #ifndef _PURPLE_CONVERSATION_H_
 #define _PURPLE_CONVERSATION_H_
 
+#define PURPLE_TYPE_CONVERSATION             (purple_conversation_get_type())
+#define PURPLE_CONVERSATION(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_CONVERSATION, PurpleConversation))
+#define PURPLE_CONVERSATION_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_CONVERSATION, PurpleConversationClass))
+#define PURPLE_IS_CONVERSATION(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_CONVERSATION))
+#define PURPLE_IS_CONVERSATION_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_CONVERSATION))
+#define PURPLE_CONVERSATION_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_CONVERSATION, PurpleConversationClass))
+
 /**************************************************************************/
 /** Data Structures                                                       */
 /**************************************************************************/
 
+/** @copydoc _PurpleConversation */
+typedef struct _PurpleConversation           PurpleConversation;
+/** @copydoc _PurpleConversation */
+typedef struct _PurpleConversationClass      PurpleConversationClass;
 
 /** @copydoc _PurpleConversationUiOps */
-typedef struct _PurpleConversationUiOps PurpleConversationUiOps;
-/** @copydoc _PurpleConversation */
-typedef struct _PurpleConversation      PurpleConversation;
-/** @copydoc _PurpleConvIm */
-typedef struct _PurpleConvIm            PurpleConvIm;
-/** @copydoc _PurpleConvChat */
-typedef struct _PurpleConvChat          PurpleConvChat;
-/** @copydoc _PurpleConvChatBuddy */
-typedef struct _PurpleConvChatBuddy     PurpleConvChatBuddy;
-/** @copydoc _PurpleConvMessage */
-typedef struct _PurpleConvMessage       PurpleConvMessage;
-
-/**
- * A type of conversation.
- */
-typedef enum
-{
-	PURPLE_CONV_TYPE_UNKNOWN = 0, /**< Unknown conversation type. */
-	PURPLE_CONV_TYPE_IM,          /**< Instant Message.           */
-	PURPLE_CONV_TYPE_CHAT,        /**< Chat room.                 */
-	PURPLE_CONV_TYPE_MISC,        /**< A misc. conversation.      */
-	PURPLE_CONV_TYPE_ANY          /**< Any type of conversation.  */
-
-} PurpleConversationType;
+typedef struct _PurpleConversationUiOps      PurpleConversationUiOps;
+/** @copydoc _PurpleConversationMessage */
+typedef struct _PurpleConversationMessage    PurpleConversationMessage;
 
 /**
  * Conversation update type.
  */
 typedef enum
 {
-	PURPLE_CONV_UPDATE_ADD = 0, /**< The buddy associated with the conversation
-	                               was added.   */
-	PURPLE_CONV_UPDATE_REMOVE,  /**< The buddy associated with the conversation
-	                               was removed. */
-	PURPLE_CONV_UPDATE_ACCOUNT, /**< The purple_account was changed. */
-	PURPLE_CONV_UPDATE_TYPING,  /**< The typing state was updated. */
-	PURPLE_CONV_UPDATE_UNSEEN,  /**< The unseen state was updated. */
-	PURPLE_CONV_UPDATE_LOGGING, /**< Logging for this conversation was
-	                               enabled or disabled. */
-	PURPLE_CONV_UPDATE_TOPIC,   /**< The topic for a chat was updated. */
+	PURPLE_CONVERSATION_UPDATE_ADD = 0, /**< The buddy associated with the conversation
+	                                         was added.   */
+	PURPLE_CONVERSATION_UPDATE_REMOVE,  /**< The buddy associated with the conversation
+	                                         was removed. */
+	PURPLE_CONVERSATION_UPDATE_ACCOUNT, /**< The purple_account was changed. */
+	PURPLE_CONVERSATION_UPDATE_TYPING,  /**< The typing state was updated. */
+	PURPLE_CONVERSATION_UPDATE_UNSEEN,  /**< The unseen state was updated. */
+	PURPLE_CONVERSATION_UPDATE_LOGGING, /**< Logging for this conversation was
+	                                         enabled or disabled. */
+	PURPLE_CONVERSATION_UPDATE_TOPIC,   /**< The topic for a chat was updated. */
 	/*
 	 * XXX These need to go when we implement a more generic core/UI event
 	 * system.
 	 */
-	PURPLE_CONV_ACCOUNT_ONLINE,  /**< One of the user's accounts went online.  */
-	PURPLE_CONV_ACCOUNT_OFFLINE, /**< One of the user's accounts went offline. */
-	PURPLE_CONV_UPDATE_AWAY,     /**< The other user went away.                */
-	PURPLE_CONV_UPDATE_ICON,     /**< The other user's buddy icon changed.     */
-	PURPLE_CONV_UPDATE_TITLE,
-	PURPLE_CONV_UPDATE_CHATLEFT,
-
-	PURPLE_CONV_UPDATE_FEATURES  /**< The features for a chat have changed */
-
-} PurpleConvUpdateType;
+	PURPLE_CONVERSATION_ACCOUNT_ONLINE,  /**< One of the user's accounts went online.  */
+	PURPLE_CONVERSATION_ACCOUNT_OFFLINE, /**< One of the user's accounts went offline. */
+	PURPLE_CONVERSATION_UPDATE_AWAY,     /**< The other user went away.                */
+	PURPLE_CONVERSATION_UPDATE_ICON,     /**< The other user's buddy icon changed.     */
+	PURPLE_CONVERSATION_UPDATE_TITLE,
+	PURPLE_CONVERSATION_UPDATE_CHATLEFT,
 
-/**
- * The typing state of a user.
- */
-typedef enum
-{
-	PURPLE_NOT_TYPING = 0,  /**< Not typing.                 */
-	PURPLE_TYPING,          /**< Currently typing.           */
-	PURPLE_TYPED            /**< Stopped typing momentarily. */
+	PURPLE_CONVERSATION_UPDATE_FEATURES  /**< The features for a chat have changed */
 
-} PurpleTypingState;
+} PurpleConversationUpdateType;
 
 /**
  * Flags applicable to a message. Most will have send, recv or system.
  */
-typedef enum
+typedef enum /*< flags >*/
 {
-	PURPLE_MESSAGE_SEND        = 0x0001, /**< Outgoing message.        */
-	PURPLE_MESSAGE_RECV        = 0x0002, /**< Incoming message.        */
-	PURPLE_MESSAGE_SYSTEM      = 0x0004, /**< System message.          */
-	PURPLE_MESSAGE_AUTO_RESP   = 0x0008, /**< Auto response.           */
-	PURPLE_MESSAGE_ACTIVE_ONLY = 0x0010,  /**< Hint to the UI that this
-	                                        message should not be
-	                                        shown in conversations
-	                                        which are only open for
-	                                        internal UI purposes
-	                                        (e.g. for contact-aware
-	                                         conversations).           */
-	PURPLE_MESSAGE_NICK        = 0x0020, /**< Contains your nick.      */
-	PURPLE_MESSAGE_NO_LOG      = 0x0040, /**< Do not log.              */
-	PURPLE_MESSAGE_WHISPER     = 0x0080, /**< Whispered message.       */
-	PURPLE_MESSAGE_ERROR       = 0x0200, /**< Error message.           */
-	PURPLE_MESSAGE_DELAYED     = 0x0400, /**< Delayed message.         */
-	PURPLE_MESSAGE_RAW         = 0x0800, /**< "Raw" message - don't
-	                                        apply formatting         */
-	PURPLE_MESSAGE_IMAGES      = 0x1000, /**< Message contains images  */
-	PURPLE_MESSAGE_NOTIFY      = 0x2000, /**< Message is a notification */
-	PURPLE_MESSAGE_NO_LINKIFY  = 0x4000, /**< Message should not be auto-
-										   linkified */
-	PURPLE_MESSAGE_INVISIBLE   = 0x8000  /**< Message should not be displayed */
-} PurpleMessageFlags;
-
-/**
- * Flags applicable to users in Chats.
- */
-typedef enum
-{
-	PURPLE_CBFLAGS_NONE          = 0x0000, /**< No flags                     */
-	PURPLE_CBFLAGS_VOICE         = 0x0001, /**< Voiced user or "Participant" */
-	PURPLE_CBFLAGS_HALFOP        = 0x0002, /**< Half-op                      */
-	PURPLE_CBFLAGS_OP            = 0x0004, /**< Channel Op or Moderator      */
-	PURPLE_CBFLAGS_FOUNDER       = 0x0008, /**< Channel Founder              */
-	PURPLE_CBFLAGS_TYPING        = 0x0010, /**< Currently typing             */
-	PURPLE_CBFLAGS_AWAY          = 0x0020  /**< Currently away.              */
-
-} PurpleConvChatBuddyFlags;
+	PURPLE_CONVERSATION_MESSAGE_SEND        = 0x0001, /**< Outgoing message.        */
+	PURPLE_CONVERSATION_MESSAGE_RECV        = 0x0002, /**< Incoming message.        */
+	PURPLE_CONVERSATION_MESSAGE_SYSTEM      = 0x0004, /**< System message.          */
+	PURPLE_CONVERSATION_MESSAGE_AUTO_RESP   = 0x0008, /**< Auto response.           */
+	PURPLE_CONVERSATION_MESSAGE_ACTIVE_ONLY = 0x0010,  /**< Hint to the UI that this
+	                                                        message should not be
+	                                                        shown in conversations
+	                                                        which are only open for
+	                                                        internal UI purposes
+	                                                        (e.g. for contact-aware
+	                                                        conversations).         */
+	PURPLE_CONVERSATION_MESSAGE_NICK        = 0x0020, /**< Contains your nick.      */
+	PURPLE_CONVERSATION_MESSAGE_NO_LOG      = 0x0040, /**< Do not log.              */
+	PURPLE_CONVERSATION_MESSAGE_WHISPER     = 0x0080, /**< Whispered message.       */
+	PURPLE_CONVERSATION_MESSAGE_ERROR       = 0x0200, /**< Error message.           */
+	PURPLE_CONVERSATION_MESSAGE_DELAYED     = 0x0400, /**< Delayed message.         */
+	PURPLE_CONVERSATION_MESSAGE_RAW         = 0x0800, /**< "Raw" message - don't
+	                                                        apply formatting        */
+	PURPLE_CONVERSATION_MESSAGE_IMAGES      = 0x1000, /**< Message contains images  */
+	PURPLE_CONVERSATION_MESSAGE_NOTIFY      = 0x2000, /**< Message is a notification */
+	PURPLE_CONVERSATION_MESSAGE_NO_LINKIFY  = 0x4000, /**< Message should not be auto-
+										                   linkified */
+	PURPLE_CONVERSATION_MESSAGE_INVISIBLE   = 0x8000  /**< Message should not be displayed */
+} PurpleConversationMessageFlags;
 
 #include "account.h"
 #include "buddyicon.h"
 #include "log.h"
-#include "server.h"
+
+/**************************************************************************/
+/** PurpleConversation                                                    */
+/**************************************************************************/
+/** Structure representing a conversation instance. */
+struct _PurpleConversation
+{
+	/*< private >*/
+	GObject gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+/** Base class for all #PurpleConversation's */
+struct _PurpleConversationClass {
+	/*< private >*/
+	GObjectClass parent_class;
 
+	/** Writes a message to a chat or IM conversation. TODO
+	 *  @see purple_conversation_write_message()
+	 */
+	void (*write_message)(PurpleConversation *conv, const char *who,
+			const char *message, PurpleConversationMessageFlags flags,
+			time_t mtime);
+
+	/** Sends a message to a chat or IM conversation. TODO
+	 *  @see purple_conversation_send_message()
+	 */
+	void (*send_message)(PurpleConversation *conv,
+			const char *message, PurpleConversationMessageFlags flags);
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+/**************************************************************************/
+/** PurpleConversationUiOps                                               */
+/**************************************************************************/
 /**
  * Conversation operations and events.
  *
@@ -166,17 +170,17 @@
 	void (*destroy_conversation)(PurpleConversation *conv);
 	/** Write a message to a chat.  If this field is @c NULL, libpurple will
 	 *  fall back to using #write_conv.
-	 *  @see purple_conv_chat_write()
+	 *  @see purple_chat_conversation_write()
 	 */
 	void (*write_chat)(PurpleConversation *conv, const char *who,
-	                   const char *message, PurpleMessageFlags flags,
-	                   time_t mtime);
+	                  const char *message, PurpleConversationMessageFlags flags,
+	                  time_t mtime);
 	/** Write a message to an IM conversation.  If this field is @c NULL,
 	 *  libpurple will fall back to using #write_conv.
-	 *  @see purple_conv_im_write()
+	 *  @see purple_im_conversation_write()
 	 */
 	void (*write_im)(PurpleConversation *conv, const char *who,
-	                 const char *message, PurpleMessageFlags flags,
+	                 const char *message, PurpleConversationMessageFlags flags,
 	                 time_t mtime);
 	/** Write a message to a conversation.  This is used rather than the
 	 *  chat- or im-specific ops for errors, system messages (such as "x is
@@ -190,14 +194,15 @@
 	                   const char *name,
 	                   const char *alias,
 	                   const char *message,
-	                   PurpleMessageFlags flags,
+	                   PurpleConversationMessageFlags flags,
 	                   time_t mtime);
 
 	/** Add @a cbuddies to a chat.
-	 *  @param cbuddies      A @c GList of #PurpleConvChatBuddy structs.
+	 *  @param cbuddies      A @c GList of #PurpleChatConversationBuddy structs.
 	 *  @param new_arrivals  Whether join notices should be shown.
 	 *                       (Join notices are actually written to the
-	 *                       conversation by #purple_conv_chat_add_users().)
+	 *                       conversation by
+	 *                       #purple_chat_conversation_add_users().)
 	 */
 	void (*chat_add_users)(PurpleConversation *conv,
 	                       GList *cbuddies,
@@ -205,17 +210,17 @@
 	/** Rename the user in this chat named @a old_name to @a new_name.  (The
 	 *  rename message is written to the conversation by libpurple.)
 	 *  @param new_alias  @a new_name's new alias, if they have one.
-	 *  @see purple_conv_chat_add_users()
+	 *  @see purple_chat_conversation_add_users()
 	 */
 	void (*chat_rename_user)(PurpleConversation *conv, const char *old_name,
 	                         const char *new_name, const char *new_alias);
 	/** Remove @a users from a chat.
 	 *  @param users    A @c GList of <tt>const char *</tt>s.
-	 *  @see purple_conv_chat_rename_user()
+	 *  @see purple_chat_conversation_rename_user()
 	 */
 	void (*chat_remove_users)(PurpleConversation *conv, GList *users);
 	/** Called when a user's flags are changed.
-	 *  @see purple_conv_chat_user_set_flags()
+	 *  @see purple_chat_conversation_user_set_flags()
 	 */
 	void (*chat_update_user)(PurpleConversation *conv, const char *user);
 
@@ -231,7 +236,8 @@
 	gboolean (*has_focus)(PurpleConversation *conv);
 
 	/* Custom Smileys */
-	gboolean (*custom_smiley_add)(PurpleConversation *conv, const char *smile, gboolean remote);
+	gboolean (*custom_smiley_add)(PurpleConversation *conv, const char *smile,
+	                            gboolean remote);
 	void (*custom_smiley_write)(PurpleConversation *conv, const char *smile,
 	                            const guchar *data, gsize size);
 	void (*custom_smiley_close)(PurpleConversation *conv, const char *smile);
@@ -256,22 +262,12 @@
 /**************************************************************************/
 /*@{*/
 
-/**
- * Creates a new conversation of the specified type.
- *
- * @param type    The type of conversation.
- * @param account The account opening the conversation window on the purple
- *                user's end.
- * @param name    The name of the conversation.  For PURPLE_CONV_TYPE_IM,
- *                this is the name of the buddy.
- *
- * @return The new conversation.
+/** TODO
+ * Returns the GType for the Conversation object.
  */
-PurpleConversation *purple_conversation_new(PurpleConversationType type,
-										PurpleAccount *account,
-										const char *name);
+GType purple_conversation_get_type(void);
 
-/**
+/** TODO dispose/fnalize
  * Destroys the specified conversation and removes it from the parent
  * window.
  *
@@ -282,7 +278,6 @@
  */
 void purple_conversation_destroy(PurpleConversation *conv);
 
-
 /**
  * Present a conversation to the user. This allows core code to initiate a
  * conversation by displaying the IM dialog.
@@ -290,16 +285,6 @@
  */
 void purple_conversation_present(PurpleConversation *conv);
 
-
-/**
- * Returns the specified conversation's type.
- *
- * @param conv The conversation.
- *
- * @return The conversation's type.
- */
-PurpleConversationType purple_conversation_get_type(const PurpleConversation *conv);
-
 /**
  * Sets the specified conversation's UI operations structure.
  *
@@ -310,21 +295,13 @@
 								  PurpleConversationUiOps *ops);
 
 /**
- * Sets the default conversation UI operations structure.
- *
- * @param ops  The UI conversation operations structure.
- */
-void purple_conversations_set_ui_ops(PurpleConversationUiOps *ops);
-
-/**
  * Returns the specified conversation's UI operations structure.
  *
  * @param conv The conversation.
  *
  * @return The operations structure.
  */
-PurpleConversationUiOps *purple_conversation_get_ui_ops(
-		const PurpleConversation *conv);
+PurpleConversationUiOps *purple_conversation_get_ui_ops(const PurpleConversation *conv);
 
 /**
  * Sets the specified conversation's purple_account.
@@ -405,46 +382,6 @@
 const char *purple_conversation_get_name(const PurpleConversation *conv);
 
 /**
- * Get an attribute of a chat buddy
- *
- * @param cb	The chat buddy.
- * @param key	The key of the attribute.
- *
- * @return The value of the attribute key.
- */
-const char *purple_conv_chat_cb_get_attribute(PurpleConvChatBuddy *cb, const char *key);
-
-/**
- * Get the keys of all atributes of a chat buddy
- *
- * @param cb	The chat buddy.
- *
- * @return A list of the attributes of a chat buddy.
- */
-GList *purple_conv_chat_cb_get_attribute_keys(PurpleConvChatBuddy *cb);
-	
-/**
- * Set an attribute of a chat buddy
- *
- * @param chat	The chat.
- * @param cb	The chat buddy.
- * @param key	The key of the attribute.
- * @param value	The value of the attribute.
- */
-void purple_conv_chat_cb_set_attribute(PurpleConvChat *chat, PurpleConvChatBuddy *cb, const char *key, const char *value);
-
-/**
- * Set attributes of a chat buddy
- *
- * @param chat	The chat.
- * @param cb	The chat buddy.
- * @param keys	A GList of the keys.
- * @param values A GList of the values.
- */
-void
-purple_conv_chat_cb_set_attributes(PurpleConvChat *chat, PurpleConvChatBuddy *cb, GList *keys, GList *values);
-
-/**
  * Enables or disables logging for this conversation.
  *
  * @param conv The conversation.
@@ -473,32 +410,6 @@
 void purple_conversation_close_logs(PurpleConversation *conv);
 
 /**
- * Returns the specified conversation's IM-specific data.
- *
- * If the conversation type is not PURPLE_CONV_TYPE_IM, this will return @c NULL.
- *
- * @param conv The conversation.
- *
- * @return The IM-specific data.
- */
-PurpleConvIm *purple_conversation_get_im_data(const PurpleConversation *conv);
-
-#define PURPLE_CONV_IM(c) (purple_conversation_get_im_data(c))
-
-/**
- * Returns the specified conversation's chat-specific data.
- *
- * If the conversation type is not PURPLE_CONV_TYPE_CHAT, this will return @c NULL.
- *
- * @param conv The conversation.
- *
- * @return The chat-specific data.
- */
-PurpleConvChat *purple_conversation_get_chat_data(const PurpleConversation *conv);
-
-#define PURPLE_CONV_CHAT(c) (purple_conversation_get_chat_data(c))
-
-/**
  * Sets extra data for a conversation.
  *
  * @param conv The conversation.
@@ -519,48 +430,13 @@
 gpointer purple_conversation_get_data(PurpleConversation *conv, const char *key);
 
 /**
- * Returns a list of all conversations.
- *
- * This list includes both IMs and chats.
- *
- * @constreturn A GList of all conversations.
- */
-GList *purple_get_conversations(void);
-
-/**
- * Returns a list of all IMs.
- *
- * @constreturn A GList of all IMs.
- */
-GList *purple_get_ims(void);
-
-/**
- * Returns a list of all chats.
- *
- * @constreturn A GList of all chats.
- */
-GList *purple_get_chats(void);
-
-/**
- * Finds a conversation with the specified type, name, and Purple account.
- *
- * @param type The type of the conversation.
- * @param name The name of the conversation.
- * @param account The purple_account associated with the conversation.
- *
- * @return The conversation if found, or @c NULL otherwise.
- */
-PurpleConversation *purple_find_conversation_with_account(
-		PurpleConversationType type, const char *name,
-		const PurpleAccount *account);
-
-/**
  * Writes to a conversation window.
  *
  * This function should not be used to write IM or chat messages. Use
- * purple_conv_im_write() and purple_conv_chat_write() instead. Those functions will
- * most likely call this anyway, but they may do their own formatting,
- * sound playback, etc.
+ * purple_conversation_write_message() instead. This function will
+ * most likely call this anyway, but it may do it's own formatting,
+ * sound playback, etc. depending on whether the conversation is a chat or an
+ * IM.
  *
  * This can be used to write generic messages, such as "so and so closed
  * the conversation window."
@@ -571,13 +447,45 @@
  * @param flags   The message flags.
  * @param mtime   The time the message was sent.
  *
- * @see purple_conv_im_write()
- * @see purple_conv_chat_write()
+ * @see purple_conversation_write_message()
  */
 void purple_conversation_write(PurpleConversation *conv, const char *who,
-		const char *message, PurpleMessageFlags flags,
+		const char *message, PurpleConversationMessageFlags flags,
 		time_t mtime);
 
+/** TODO pure virtual
+ * Writes to a chat or an IM.
+ *
+ * @param conv    The conversation.
+ * @param who     The user who sent the message.
+ * @param message The message to write.
+ * @param flags   The message flags.
+ * @param mtime   The time the message was sent.
+ */
+void purple_conversation_write_message(PurpleConversation *conv,
+		const char *who, const char *message,
+		PurpleConversationMessageFlags flags, time_t mtime);
+
+/** TODO forward to send_message
+ * Sends a message to this conversation. This function calls
+ * purple_conversation_send_message() with no additional flags.
+ *
+ * @param conv    The conversation.
+ * @param message The message to send.
+ */
+void purple_conversation_send(PurpleConversation *conv, const char *message);
+
+/** TODO pure virtual
+ * Sends a message to this conversation with specified flags.
+ *
+ * @param conv    The conversation.
+ * @param message The message to send.
+ * @param flags   The PurpleConversationMessageFlags flags to use in addition to
+ *                PURPLE_CONVERSATION_MESSAGE_SEND.
+ */
+void purple_conversation_send_message(PurpleConversation *conv, const char *message,
+		PurpleConversationMessageFlags flags);
+
 /**
 	Set the features as supported for the given conversation.
 	@param conv      The conversation
@@ -609,21 +517,14 @@
  * @param conv The conversation.
  * @param type The update type.
  */
-void purple_conversation_update(PurpleConversation *conv, PurpleConvUpdateType type);
-
-/**
- * Calls a function on each conversation.
- *
- * @param func The function.
- */
-void purple_conversation_foreach(void (*func)(PurpleConversation *conv));
+void purple_conversation_update(PurpleConversation *conv, PurpleConversationUpdateType type);
 
 /**
  * Retrieve the message history of a conversation.
  *
  * @param conv   The conversation
  *
- * @return  A GList of PurpleConvMessage's. The must not modify the list or the data within.
+ * @return  A GList of PurpleConversationMessage's. The must not modify the list or the data within.
  *          The list contains the newest message at the beginning, and the oldest message at
  *          the end.
  */
@@ -637,60 +538,6 @@
 void purple_conversation_clear_message_history(PurpleConversation *conv);
 
 /**
- * Get the sender from a PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The name of the sender of the message
- */
-const char *purple_conversation_message_get_sender(const PurpleConvMessage *msg);
-
-/**
- * Get the message from a PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The name of the sender of the message
- */
-const char *purple_conversation_message_get_message(const PurpleConvMessage *msg);
-
-/**
- * Get the message-flags of a PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The message flags
- */
-PurpleMessageFlags purple_conversation_message_get_flags(const PurpleConvMessage *msg);
-
-/**
- * Get the timestamp of a PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The timestamp of the message
- */
-time_t purple_conversation_message_get_timestamp(const PurpleConvMessage *msg);
-
-/**
- * Get the alias from a PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The alias of the sender of the message
- */
-const char *purple_conversation_message_get_alias(const PurpleConvMessage *msg);
-
-/**
- * Get the conversation associated with the PurpleConvMessage
- *
- * @param msg   A PurpleConvMessage
- *
- * @return   The conversation
- */
-PurpleConversation *purple_conversation_message_get_conv(const PurpleConvMessage *msg);
-
-/**
  * Set the UI data associated with this conversation.
  *
  * @param conv			The conversation.
@@ -709,175 +556,6 @@
  */
 gpointer purple_conversation_get_ui_data(const PurpleConversation *conv);
 
-/*@}*/
-
-
-/**************************************************************************/
-/** @name IM Conversation API                                             */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Gets an IM's parent conversation.
- *
- * @param im The IM.
- *
- * @return The parent conversation.
- */
-PurpleConversation *purple_conv_im_get_conversation(const PurpleConvIm *im);
-
-/**
- * Sets the IM's buddy icon.
- *
- * This should only be called from within Purple. You probably want to
- * call purple_buddy_icon_set_data().
- *
- * @param im   The IM.
- * @param icon The buddy icon.
- *
- * @see purple_buddy_icon_set_data()
- */
-void purple_conv_im_set_icon(PurpleConvIm *im, PurpleBuddyIcon *icon);
-
-/**
- * Returns the IM's buddy icon.
- *
- * @param im The IM.
- *
- * @return The buddy icon.
- */
-PurpleBuddyIcon *purple_conv_im_get_icon(const PurpleConvIm *im);
-
-/**
- * Sets the IM's typing state.
- *
- * @param im    The IM.
- * @param state The typing state.
- */
-void purple_conv_im_set_typing_state(PurpleConvIm *im, PurpleTypingState state);
-
-/**
- * Returns the IM's typing state.
- *
- * @param im The IM.
- *
- * @return The IM's typing state.
- */
-PurpleTypingState purple_conv_im_get_typing_state(const PurpleConvIm *im);
-
-/**
- * Starts the IM's typing timeout.
- *
- * @param im      The IM.
- * @param timeout The timeout.
- */
-void purple_conv_im_start_typing_timeout(PurpleConvIm *im, int timeout);
-
-/**
- * Stops the IM's typing timeout.
- *
- * @param im The IM.
- */
-void purple_conv_im_stop_typing_timeout(PurpleConvIm *im);
-
-/**
- * Returns the IM's typing timeout.
- *
- * @param im The IM.
- *
- * @return The timeout.
- */
-guint purple_conv_im_get_typing_timeout(const PurpleConvIm *im);
-
-/**
- * Sets the quiet-time when no PURPLE_TYPING messages will be sent.
- * Few protocols need this (maybe only MSN).  If the user is still
- * typing after this quiet-period, then another PURPLE_TYPING message
- * will be sent.
- *
- * @param im  The IM.
- * @param val The number of seconds to wait before allowing another
- *            PURPLE_TYPING message to be sent to the user.  Or 0 to
- *            not send another PURPLE_TYPING message.
- */
-void purple_conv_im_set_type_again(PurpleConvIm *im, unsigned int val);
-
-/**
- * Returns the time after which another PURPLE_TYPING message should be sent.
- *
- * @param im The IM.
- *
- * @return The time in seconds since the epoch.  Or 0 if no additional
- *         PURPLE_TYPING message should be sent.
- */
-time_t purple_conv_im_get_type_again(const PurpleConvIm *im);
-
-/**
- * Starts the IM's type again timeout.
- *
- * @param im      The IM.
- */
-void purple_conv_im_start_send_typed_timeout(PurpleConvIm *im);
-
-/**
- * Stops the IM's type again timeout.
- *
- * @param im The IM.
- */
-void purple_conv_im_stop_send_typed_timeout(PurpleConvIm *im);
-
-/**
- * Returns the IM's type again timeout interval.
- *
- * @param im The IM.
- *
- * @return The type again timeout interval.
- */
-guint purple_conv_im_get_send_typed_timeout(const PurpleConvIm *im);
-
-/**
- * Updates the visual typing notification for an IM conversation.
- *
- * @param im The IM.
- */
-void purple_conv_im_update_typing(PurpleConvIm *im);
-
-/**
- * Writes to an IM.
- *
- * @param im      The IM.
- * @param who     The user who sent the message.
- * @param message The message to write.
- * @param flags   The message flags.
- * @param mtime   The time the message was sent.
- */
-void purple_conv_im_write(PurpleConvIm *im, const char *who,
-						const char *message, PurpleMessageFlags flags,
-						time_t mtime);
-
-/**
- * Presents an IM-error to the user
- *
- * This is a helper function to find a conversation, write an error to it, and
- * raise the window.  If a conversation with this user doesn't already exist,
- * the function will return FALSE and the calling function can attempt to present
- * the error another way (purple_notify_error, most likely)
- *
- * @param who     The user this error is about
- * @param account The account this error is on
- * @param what    The error
- * @return        TRUE if the error was presented, else FALSE
- */
-gboolean purple_conv_present_error(const char *who, PurpleAccount *account, const char *what);
-
-/**
- * Sends a message to this IM conversation.
- *
- * @param im      The IM.
- * @param message The message to send.
- */
-void purple_conv_im_send(PurpleConvIm *im, const char *message);
-
 /**
  * Sends a message to a conversation after confirming with
  * the user.
@@ -890,21 +568,12 @@
  * @param conv    The conversation.
  * @param message The message to send.
  */
-void purple_conv_send_confirm(PurpleConversation *conv, const char *message);
-
-/**
- * Sends a message to this IM conversation with specified flags.
- *
- * @param im      The IM.
- * @param message The message to send.
- * @param flags   The PurpleMessageFlags flags to use in addition to PURPLE_MESSAGE_SEND.
- */
-void purple_conv_im_send_with_flags(PurpleConvIm *im, const char *message, PurpleMessageFlags flags);
+void purple_conversation_send_confirm(PurpleConversation *conv, const char *message);
 
 /**
  * Adds a smiley to the conversation's smiley tree. If this returns
- * @c TRUE you should call purple_conv_custom_smiley_write() one or more
- * times, and then purple_conv_custom_smiley_close(). If this returns
+ * @c TRUE you should call purple_conversation_custom_smiley_write() one or more
+ * times, and then purple_conversation_custom_smiley_close(). If this returns
  * @c FALSE, either the conv or smile were invalid, or the icon was
  * found in the cache. In either case, calling write or close would
  * be an error.
@@ -915,16 +584,15 @@
  * @param chksum The checksum, as a NUL terminated base64 string.
  * @param remote @c TRUE if the custom smiley is set by the remote user (buddy).
  * @return      @c TRUE if an icon is expected, else FALSE. Note that
- *              it is an error to never call purple_conv_custom_smiley_close if
+ *              it is an error to never call purple_conversation_custom_smiley_close if
  *              this function returns @c TRUE, but an error to call it if
  *              @c FALSE is returned.
  */
 
-gboolean purple_conv_custom_smiley_add(PurpleConversation *conv, const char *smile,
+gboolean purple_conversation_custom_smiley_add(PurpleConversation *conv, const char *smile,
                                       const char *cksum_type, const char *chksum,
 									  gboolean remote);
 
-
 /**
  * Updates the image associated with the current smiley.
  *
@@ -934,421 +602,21 @@
  * @param size The length of the data.
  */
 
-void purple_conv_custom_smiley_write(PurpleConversation *conv,
+void purple_conversation_custom_smiley_write(PurpleConversation *conv,
                                    const char *smile,
                                    const guchar *data,
                                    gsize size);
 
 /**
  * Close the custom smiley, all data has been written with
- * purple_conv_custom_smiley_write, and it is no longer valid
+ * purple_conversation_custom_smiley_write, and it is no longer valid
  * to call that function on that smiley.
  *
  * @param conv The purple conversation associated with the smiley.
  * @param smile The text associated with the smiley
  */
 
-void purple_conv_custom_smiley_close(PurpleConversation *conv, const char *smile);
-
-/*@}*/
-
-
-/**************************************************************************/
-/** @name Chat Conversation API                                           */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Gets a chat's parent conversation.
- *
- * @param chat The chat.
- *
- * @return The parent conversation.
- */
-PurpleConversation *purple_conv_chat_get_conversation(const PurpleConvChat *chat);
-
-/**
- * Returns a list of users in the chat room.  The members of the list
- * are PurpleConvChatBuddy objects.
- *
- * @param chat The chat.
- *
- * @constreturn The list of users.
- */
-GList *purple_conv_chat_get_users(const PurpleConvChat *chat);
-
-/**
- * Ignores a user in a chat room.
- *
- * @param chat The chat.
- * @param name The name of the user.
- */
-void purple_conv_chat_ignore(PurpleConvChat *chat, const char *name);
-
-/**
- * Unignores a user in a chat room.
- *
- * @param chat The chat.
- * @param name The name of the user.
- */
-void purple_conv_chat_unignore(PurpleConvChat *chat, const char *name);
-
-/**
- * Sets the list of ignored users in the chat room.
- *
- * @param chat    The chat.
- * @param ignored The list of ignored users.
- *
- * @return The list passed.
- */
-GList *purple_conv_chat_set_ignored(PurpleConvChat *chat, GList *ignored);
-
-/**
- * Returns the list of ignored users in the chat room.
- *
- * @param chat The chat.
- *
- * @constreturn The list of ignored users.
- */
-GList *purple_conv_chat_get_ignored(const PurpleConvChat *chat);
-
-/**
- * Returns the actual name of the specified ignored user, if it exists in
- * the ignore list.
- *
- * If the user found contains a prefix, such as '+' or '\@', this is also
- * returned. The username passed to the function does not have to have this
- * formatting.
- *
- * @param chat The chat.
- * @param user The user to check in the ignore list.
- *
- * @return The ignored user if found, complete with prefixes, or @c NULL
- *         if not found.
- */
-const char *purple_conv_chat_get_ignored_user(const PurpleConvChat *chat,
-											const char *user);
-
-/**
- * Returns @c TRUE if the specified user is ignored.
- *
- * @param chat The chat.
- * @param user The user.
- *
- * @return @c TRUE if the user is in the ignore list; @c FALSE otherwise.
- */
-gboolean purple_conv_chat_is_user_ignored(const PurpleConvChat *chat,
-										const char *user);
-
-/**
- * Sets the chat room's topic.
- *
- * @param chat  The chat.
- * @param who   The user that set the topic.
- * @param topic The topic.
- */
-void purple_conv_chat_set_topic(PurpleConvChat *chat, const char *who,
-							  const char *topic);
-
-/**
- * Returns the chat room's topic.
- *
- * @param chat The chat.
- *
- * @return The chat's topic.
- */
-const char *purple_conv_chat_get_topic(const PurpleConvChat *chat);
-
-/**
- * Sets the chat room's ID.
- *
- * @param chat The chat.
- * @param id   The ID.
- */
-void purple_conv_chat_set_id(PurpleConvChat *chat, int id);
-
-/**
- * Returns the chat room's ID.
- *
- * @param chat The chat.
- *
- * @return The ID.
- */
-int purple_conv_chat_get_id(const PurpleConvChat *chat);
-
-/**
- * Writes to a chat.
- *
- * @param chat    The chat.
- * @param who     The user who sent the message.
- * @param message The message to write.
- * @param flags   The flags.
- * @param mtime   The time the message was sent.
- */
-void purple_conv_chat_write(PurpleConvChat *chat, const char *who,
-						  const char *message, PurpleMessageFlags flags,
-						  time_t mtime);
-
-/**
- * Sends a message to this chat conversation.
- *
- * @param chat    The chat.
- * @param message The message to send.
- */
-void purple_conv_chat_send(PurpleConvChat *chat, const char *message);
-
-/**
- * Sends a message to this chat conversation with specified flags.
- *
- * @param chat    The chat.
- * @param message The message to send.
- * @param flags   The PurpleMessageFlags flags to use.
- */
-void purple_conv_chat_send_with_flags(PurpleConvChat *chat, const char *message, PurpleMessageFlags flags);
-
-/**
- * Adds a user to a chat.
- *
- * @param chat        The chat.
- * @param user        The user to add.
- * @param extra_msg   An extra message to display with the join message.
- * @param flags       The users flags
- * @param new_arrival Decides whether or not to show a join notice.
- */
-void purple_conv_chat_add_user(PurpleConvChat *chat, const char *user,
-							 const char *extra_msg, PurpleConvChatBuddyFlags flags,
-							 gboolean new_arrival);
-
-/**
- * Adds a list of users to a chat.
- *
- * The data is copied from @a users, @a extra_msgs, and @a flags, so it is up to
- * the caller to free this list after calling this function.
- *
- * @param chat         The chat.
- * @param users        The list of users to add.
- * @param extra_msgs   An extra message to display with the join message for each
- *                     user.  This list may be shorter than @a users, in which
- *                     case, the users after the end of extra_msgs will not have
- *                     an extra message.  By extension, this means that extra_msgs
- *                     can simply be @c NULL and none of the users will have an
- *                     extra message.
- * @param flags        The list of flags for each user.
- * @param new_arrivals Decides whether or not to show join notices.
- */
-void purple_conv_chat_add_users(PurpleConvChat *chat, GList *users, GList *extra_msgs,
-							  GList *flags, gboolean new_arrivals);
-
-/**
- * Renames a user in a chat.
- *
- * @param chat     The chat.
- * @param old_user The old username.
- * @param new_user The new username.
- */
-void purple_conv_chat_rename_user(PurpleConvChat *chat, const char *old_user,
-								const char *new_user);
-
-/**
- * Removes a user from a chat, optionally with a reason.
- *
- * It is up to the developer to free this list after calling this function.
- *
- * @param chat   The chat.
- * @param user   The user that is being removed.
- * @param reason The optional reason given for the removal. Can be @c NULL.
- */
-void purple_conv_chat_remove_user(PurpleConvChat *chat, const char *user,
-								const char *reason);
-
-/**
- * Removes a list of users from a chat, optionally with a single reason.
- *
- * @param chat   The chat.
- * @param users  The users that are being removed.
- * @param reason The optional reason given for the removal. Can be @c NULL.
- */
-void purple_conv_chat_remove_users(PurpleConvChat *chat, GList *users,
-								 const char *reason);
-
-/**
- * Finds a user in a chat
- *
- * @param chat   The chat.
- * @param user   The user to look for.
- *
- * @return TRUE if the user is in the chat, FALSE if not
- */
-gboolean purple_conv_chat_find_user(PurpleConvChat *chat, const char *user);
-
-/**
- * Set a users flags in a chat
- *
- * @param chat   The chat.
- * @param user   The user to update.
- * @param flags  The new flags.
- */
-void purple_conv_chat_user_set_flags(PurpleConvChat *chat, const char *user,
-								   PurpleConvChatBuddyFlags flags);
-
-/**
- * Get the flags for a user in a chat
- *
- * @param chat   The chat.
- * @param user   The user to find the flags for
- *
- * @return The flags for the user
- */
-PurpleConvChatBuddyFlags purple_conv_chat_user_get_flags(PurpleConvChat *chat,
-													 const char *user);
-
-/**
- * Clears all users from a chat.
- *
- * @param chat The chat.
- */
-void purple_conv_chat_clear_users(PurpleConvChat *chat);
-
-/**
- * Sets your nickname (used for hilighting) for a chat.
- *
- * @param chat The chat.
- * @param nick The nick.
- */
-void purple_conv_chat_set_nick(PurpleConvChat *chat, const char *nick);
-
-/**
- * Gets your nickname (used for hilighting) for a chat.
- *
- * @param chat The chat.
- * @return  The nick.
- */
-const char *purple_conv_chat_get_nick(PurpleConvChat *chat);
-
-/**
- * Finds a chat with the specified chat ID.
- *
- * @param gc The purple_connection.
- * @param id The chat ID.
- *
- * @return The chat conversation.
- */
-PurpleConversation *purple_find_chat(const PurpleConnection *gc, int id);
-
-/**
- * Lets the core know we left a chat, without destroying it.
- * Called from serv_got_chat_left().
- *
- * @param chat The chat.
- */
-void purple_conv_chat_left(PurpleConvChat *chat);
-
-/**
- * Invite a user to a chat.
- * The user will be prompted to enter the user's name or a message if one is
- * not given.
- *
- * @param chat     The chat.
- * @param user     The user to invite to the chat.
- * @param message  The message to send with the invitation.
- * @param confirm  Prompt before sending the invitation. The user is always
- *                 prompted if either \a user or \a message is @c NULL.
- */
-void purple_conv_chat_invite_user(PurpleConvChat *chat, const char *user,
-		const char *message, gboolean confirm);
-
-/**
- * Returns true if we're no longer in this chat,
- * and just left the window open.
- *
- * @param chat The chat.
- *
- * @return @c TRUE if we left the chat already, @c FALSE if
- * we're still there.
- */
-gboolean purple_conv_chat_has_left(PurpleConvChat *chat);
-
-/**
- * Creates a new chat buddy
- *
- * @param name The name.
- * @param alias The alias.
- * @param flags The flags.
- *
- * @return The new chat buddy
- */
-PurpleConvChatBuddy *purple_conv_chat_cb_new(const char *name, const char *alias,
-										PurpleConvChatBuddyFlags flags);
-
-/**
- * Find a chat buddy in a chat
- *
- * @param chat The chat.
- * @param name The name of the chat buddy to find.
- */
-PurpleConvChatBuddy *purple_conv_chat_cb_find(PurpleConvChat *chat, const char *name);
-
-/**
- * Set the UI data associated with this chat buddy.
- *
- * @param cb			The chat buddy
- * @param ui_data		A pointer to associate with this chat buddy.
- */
-void purple_conv_chat_cb_set_ui_data(PurpleConvChatBuddy *cb, gpointer ui_data);
-
-/**
- * Get the UI data associated with this chat buddy.
- *
- * @param cb			The chat buddy.
- *
- * @return The UI data associated with this chat buddy.  This is a
- *         convenience field provided to the UIs--it is not
- *         used by the libpurple core.
- */
-gpointer purple_conv_chat_cb_get_ui_data(const PurpleConvChatBuddy *conv);
-
-/**
- * Get the alias of a chat buddy
- *
- * @param cb    The chat buddy.
- *
- * @return The alias of the chat buddy.
- */
-const char *purple_conv_chat_cb_get_alias(const PurpleConvChatBuddy *cb);
-
-/**
- * Get the name of a chat buddy
- *
- * @param cb    The chat buddy.
- *
- * @return The name of the chat buddy.
- */
-const char *purple_conv_chat_cb_get_name(const PurpleConvChatBuddy *cb);
-
-/**
- * Get the flags of a chat buddy.
- *
- * @param cb	The chat buddy.
- *
- * @return The flags of the chat buddy.
- */
-PurpleConvChatBuddyFlags purple_conv_chat_cb_get_flags(const PurpleConvChatBuddy *cb);
-
-/**
- * Indicates if this chat buddy is on the buddy list.
- *
- * @param cb	The chat buddy.
- *
- * @return TRUE if the chat buddy is on the buddy list.
- */
-gboolean purple_conv_chat_cb_is_buddy(const PurpleConvChatBuddy *cb);
-
-/**
- * Destroys a chat buddy
- *
- * @param cb The chat buddy to destroy
- */
-void purple_conv_chat_cb_destroy(PurpleConvChatBuddy *cb);
+void purple_conversation_custom_smiley_close(PurpleConversation *conv, const char *smile);
 
 /**
  * Retrieves the extended menu items for the conversation.
@@ -1372,31 +640,91 @@
  *
  * @return  @c TRUE if the command was executed successfully, @c FALSE otherwise.
  */
-gboolean purple_conversation_do_command(PurpleConversation *conv, const gchar *cmdline, const gchar *markup, gchar **error);
+gboolean purple_conversation_do_command(PurpleConversation *conv,
+		const gchar *cmdline, const gchar *markup, gchar **error);
 
 /*@}*/
 
 /**************************************************************************/
-/** @name Conversations Subsystem                                         */
+/** @name Conversation Helper API                                         */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Presents an IM-error to the user
+ *
+ * This is a helper function to find a conversation, write an error to it, and
+ * raise the window.  If a conversation with this user doesn't already exist,
+ * the function will return FALSE and the calling function can attempt to present
+ * the error another way (purple_notify_error, most likely)
+ *
+ * @param who     The user this error is about
+ * @param account The account this error is on
+ * @param what    The error
+ * @return        TRUE if the error was presented, else FALSE
+ */
+gboolean purple_conversation_helper_present_error(const char *who, PurpleAccount *account, const char *what);
+
+/*@}*/
+
+/**************************************************************************/
+/** @name Conversation Message API                                        */
 /**************************************************************************/
 /*@{*/
 
 /**
- * Returns the conversation subsystem handle.
+ * Get the sender from a PurpleConversationMessage
+ *
+ * @param msg   A PurpleConversationMessage
  *
- * @return The conversation subsystem handle.
+ * @return   The name of the sender of the message
  */
-void *purple_conversations_get_handle(void);
+const char *purple_conversation_message_get_sender(const PurpleConversationMessage *msg);
+
+/**
+ * Get the message from a PurpleConversationMessage
+ *
+ * @param msg   A PurpleConversationMessage
+ *
+ * @return   The name of the sender of the message
+ */
+const char *purple_conversation_message_get_message(const PurpleConversationMessage *msg);
 
 /**
- * Initializes the conversation subsystem.
+ * Get the message-flags of a PurpleConversationMessage
+ *
+ * @param msg   A PurpleConversationMessage
+ *
+ * @return   The message flags
  */
-void purple_conversations_init(void);
+PurpleConversationMessageFlags purple_conversation_message_get_flags(const PurpleConversationMessage *msg);
 
 /**
- * Uninitializes the conversation subsystem.
+ * Get the timestamp of a PurpleConversationMessage
+ *
+ * @param msg   A PurpleConversationMessage
+ *
+ * @return   The timestamp of the message
  */
-void purple_conversations_uninit(void);
+time_t purple_conversation_message_get_timestamp(const PurpleConversationMessage *msg);
+
+/**
+ * Get the alias from a PurpleConversationMessage
+ *
+ * @param msg   A PurpleConversationMessage
+ *
+ * @return   The alias of the sender of the message
+ */
+const char *purple_conversation_message_get_alias(const PurpleConversationMessage *msg);
+
+/**
+ * Get the conversation associated with the PurpleConversationMessage
+ *
+ * @param msg   A PurpleConversationMessage
+ *
+ * @return   The conversation
+ */
+PurpleConversation *purple_conversation_message_get_conv(const PurpleConversationMessage *msg);
 
 /*@}*/
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/conversations.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,442 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "conversations.h"
+
+static GList *conversations = NULL;
+static GList *ims = NULL;
+static GList *chats = NULL;
+static PurpleConversationUiOps *default_ops = NULL;
+
+GList *
+purple_conversations_get(void)
+{
+	return conversations;
+}
+
+GList *
+purple_conversations_get_ims(void)
+{
+	return ims;
+}
+
+GList *
+purple_conversations_get_chats(void)
+{
+	return chats;
+}
+
+PurpleConversation *
+purple_conversations_find_with_account(PurpleConversationType type,
+									const char *name,
+									const PurpleAccount *account)
+{
+	PurpleConversation *c = NULL;
+	struct _purple_hconv hc;
+
+	g_return_val_if_fail(name != NULL, NULL);
+
+	hc.name = (gchar *)purple_normalize(account, name);
+	hc.account = account;
+	hc.type = type;
+
+	switch (type) {
+		case PURPLE_CONVERSATION_TYPE_IM:
+		case PURPLE_CONVERSATION_TYPE_CHAT:
+			c = g_hash_table_lookup(conversation_cache, &hc);
+			break;
+		case PURPLE_CONVERSATION_TYPE_ANY:
+			hc.type = PURPLE_CONVERSATION_TYPE_IM;
+			c = g_hash_table_lookup(conversation_cache, &hc);
+			if (!c) {
+				hc.type = PURPLE_CONVERSATION_TYPE_CHAT;
+				c = g_hash_table_lookup(conversation_cache, &hc);
+			}
+			break;
+		default:
+			g_return_val_if_reached(NULL);
+	}
+
+	return c;
+}
+
+PurpleChatConversation *
+purple_conversations_find_chat(const PurpleConnection *gc, int id)
+{
+	GList *l;
+	PurpleConversation *conv;
+
+	for (l = purple_conversations_get_chats(); l != NULL; l = l->next) {
+		conv = (PurpleConversation *)l->data;
+
+		if (purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION_GET_PRIVATE(conv)) == id &&
+			purple_conversation_get_connection(conv) == gc)
+			return conv;
+	}
+
+	return NULL;
+}
+
+void
+purple_conversations_set_ui_ops(PurpleConversationUiOps *ops)
+{
+	default_ops = ops;
+}
+
+void *
+purple_conversations_get_handle(void)
+{
+	static int handle;
+
+	return &handle;
+}
+
+void
+purple_conversations_init(void)
+{
+	void *handle = purple_conversations_get_handle();
+
+	conversation_cache = g_hash_table_new_full((GHashFunc)_purple_conversations_hconv_hash,
+						(GEqualFunc)_purple_conversations_hconv_equal,
+						(GDestroyNotify)_purple_conversations_hconv_free_key, NULL);
+
+	/**********************************************************************
+	 * Register preferences
+	 **********************************************************************/
+
+	/* Conversations */
+	purple_prefs_add_none("/purple/conversations");
+
+	/* Conversations -> Chat */
+	purple_prefs_add_none("/purple/conversations/chat");
+	purple_prefs_add_bool("/purple/conversations/chat/show_nick_change", TRUE);
+
+	/* Conversations -> IM */
+	purple_prefs_add_none("/purple/conversations/im");
+	purple_prefs_add_bool("/purple/conversations/im/send_typing", TRUE);
+
+
+	/**********************************************************************
+	 * Register signals
+	 **********************************************************************/
+	purple_signal_register(handle, "writing-im-msg",
+						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_UINT,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "wrote-im-msg",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
+						 NULL, 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "sent-attention",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT,
+						 NULL, 4,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "got-attention",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT,
+						 NULL, 4,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "sending-im-msg",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER,
+						 NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new_outgoing(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "sent-im-msg",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER,
+						 NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "receiving-im-msg",
+						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
+						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new_outgoing(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "received-im-msg",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
+						 NULL, 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "blocked-im-msg",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT_UINT,
+						 NULL, 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+							 PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_UINT),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "writing-chat-msg",
+						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_UINT,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "wrote-chat-msg",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
+						 NULL, 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "sending-chat-msg",
+						 purple_marshal_VOID__POINTER_POINTER_UINT, NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "sent-chat-msg",
+						 purple_marshal_VOID__POINTER_POINTER_UINT, NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "receiving-chat-msg",
+						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
+						 purple_value_new_outgoing(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new_outgoing(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "received-chat-msg",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
+						 NULL, 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "conversation-created",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION));
+
+	purple_signal_register(handle, "conversation-updated",
+						 purple_marshal_VOID__POINTER_UINT, NULL, 2,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "deleting-conversation",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION));
+
+	purple_signal_register(handle, "buddy-typing",
+						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "buddy-typed",
+						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "buddy-typing-stopped",
+						 purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "chat-buddy-joining",
+						 purple_marshal_BOOLEAN__POINTER_POINTER_UINT,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "chat-buddy-joined",
+						 purple_marshal_VOID__POINTER_POINTER_UINT_UINT, NULL, 4,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_UINT),
+						 purple_value_new(PURPLE_TYPE_BOOLEAN));
+
+	purple_signal_register(handle, "chat-buddy-flags",
+						 purple_marshal_VOID__POINTER_POINTER_UINT_UINT, NULL, 4,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_UINT),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+	purple_signal_register(handle, "chat-buddy-leaving",
+						 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "chat-buddy-left",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "deleting-chat-buddy",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CHATBUDDY));
+
+	purple_signal_register(handle, "chat-inviting-user",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new_outgoing(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "chat-invited-user",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "chat-invited",
+						 purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER,
+						 purple_value_new(PURPLE_TYPE_INT), 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_POINTER));
+
+	purple_signal_register(handle, "chat-invite-blocked",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_POINTER,
+						 NULL, 5,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+							 PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_BOXED, "GHashTable *"));
+
+	purple_signal_register(handle, "chat-joined",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION));
+
+	purple_signal_register(handle, "chat-join-failed",
+						   purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+						   purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONNECTION),
+						   purple_value_new(PURPLE_TYPE_POINTER));
+
+	purple_signal_register(handle, "chat-left",
+						 purple_marshal_VOID__POINTER, NULL, 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION));
+
+	purple_signal_register(handle, "chat-topic-changed",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_STRING));
+
+	purple_signal_register(handle, "cleared-message-history",
+	                       purple_marshal_VOID__POINTER, NULL, 1,
+	                       purple_value_new(PURPLE_TYPE_SUBTYPE,
+	                                        PURPLE_SUBTYPE_CONVERSATION));
+
+	purple_signal_register(handle, "conversation-extended-menu",
+			     purple_marshal_VOID__POINTER_POINTER, NULL, 2,
+			     purple_value_new(PURPLE_TYPE_SUBTYPE,
+					    PURPLE_SUBTYPE_CONVERSATION),
+			     purple_value_new(PURPLE_TYPE_BOXED, "GList **"));
+}
+
+void
+purple_conversations_uninit(void)
+{
+	while (conversations)
+		purple_conversation_destroy((PurpleConversation*)conversations->data);
+	g_hash_table_destroy(conversation_cache);
+	purple_signals_unregister_by_instance(purple_conversations_get_handle());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/conversations.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,135 @@
+/**
+ * @file conversations.h Conversations API
+ * @ingroup core
+ * @see @ref conversation-signals
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef _PURPLE_CONVERSATIONS_H_
+#define _PURPLE_CONVERSATIONS_H_
+
+#include "conversation.h"
+#include "conversationtypes.h"
+#include "server.h"
+
+G_BEGIN_DECLS
+
+/**************************************************************************/
+/** @name Conversations Subsystem                                         */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Returns a list of all conversations.
+ *
+ * This list includes both IMs and chats.
+ *
+ * @constreturn A GList of all conversations.
+ */
+GList *purple_conversations_get(void);
+
+/**
+ * Returns a list of all IMs.
+ *
+ * @constreturn A GList of all IMs.
+ */
+GList *purple_conversations_get_ims(void);
+
+/**
+ * Returns a list of all chats.
+ *
+ * @constreturn A GList of all chats.
+ */
+GList *purple_conversations_get_chats(void);
+
+/** TODO all
+ * Finds a conversation of any type with the specified name and Purple account.
+ *
+ * @param name The name of the conversation.
+ * @param account The purple_account associated with the conversation.
+ *
+ * @return The conversation if found, or @c NULL otherwise.
+ */
+PurpleConversation *purple_conversations_find_with_account(const char *name,
+		const PurpleAccount *account);
+
+/** TODO IMs
+ * Finds an IM with the specified name and Purple account.
+ *
+ * @param name The name of the conversation.
+ * @param account The purple_account associated with the conversation.
+ *
+ * @return The conversation if found, or @c NULL otherwise.
+ */
+PurpleConversation *purple_conversations_find_im_with_account(const char *name,
+		const PurpleAccount *account);
+
+/** TODO chats
+ * Finds a chat with the specified name and Purple account.
+ *
+ * @param name The name of the conversation.
+ * @param account The purple_account associated with the conversation.
+ *
+ * @return The conversation if found, or @c NULL otherwise.
+ */
+PurpleConversation *purple_conversations_find_chat_with_account(const char *name,
+		const PurpleAccount *account);
+
+/**
+ * Finds a chat with the specified chat ID.
+ *
+ * @param gc The purple_connection.
+ * @param id The chat ID.
+ *
+ * @return The chat conversation.
+ */
+PurpleConversation *purple_conversations_find_chat(const PurpleConnection *gc, int id);
+
+/**
+ * Sets the default conversation UI operations structure.
+ *
+ * @param ops  The UI conversation operations structure.
+ */
+void purple_conversations_set_ui_ops(PurpleConversationUiOps *ops);
+
+/**
+ * Returns the conversation subsystem handle.
+ *
+ * @return The conversation subsystem handle.
+ */
+void *purple_conversations_get_handle(void);
+
+/**
+ * Initializes the conversation subsystem.
+ */
+void purple_conversations_init(void);
+
+/**
+ * Uninitializes the conversation subsystem.
+ */
+void purple_conversations_uninit(void);
+
+/*@}*/
+
+G_END_DECLS
+
+#endif /* _PURPLE_CONVERSATIONS_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/conversationtypes.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,1113 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "conversationtypes.h"
+
+#define SEND_TYPED_TIMEOUT_SECONDS 5
+
+/** @copydoc _PurpleChatConversationPrivate */
+typedef struct _PurpleChatConversationPrivate     PurpleChatConversationPrivate;
+/** @copydoc _PurpleIMConversationPrivate */
+typedef struct _PurpleIMConversationPrivate       PurpleIMConversationPrivate;
+/** @copydoc _PurpleChatConversationBuddyPrivate */
+typedef struct _PurpleChatConversationBuddyPrivate  PurpleChatConversationBuddyPrivate;
+
+/**
+ * Data specific to Chats.
+ */
+struct _PurpleChatConversationPrivate
+{
+	GList *in_room;                  /**< The users in the room.
+	                                  *   @deprecated Will be removed in 3.0.0 TODO
+									  */
+	GList *ignored;                  /**< Ignored users.                */
+	char  *who;                      /**< The person who set the topic. */
+	char  *topic;                    /**< The topic.                    */
+	int    id;                       /**< The chat ID.                  */
+	char *nick;                      /**< Your nick in this chat.       */
+
+	gboolean left;                   /**< We left the chat and kept the window open */
+	GHashTable *users;               /**< Hash table of the users in the room. */
+};
+
+/**
+ * Data specific to Instant Messages.
+ */
+struct _PurpleIMConversationPrivate
+{
+	PurpleIMConversationTypingState typing_state;      /**< The current typing state.    */
+	guint  typing_timeout;             /**< The typing timer handle.     */
+	time_t type_again;                 /**< The type again time.         */
+	guint  send_typed_timeout;         /**< The type again timer handle. */
+
+	PurpleBuddyIcon *icon;               /**< The buddy icon.              */
+};
+
+/**
+ * Data for "Chat Buddies"
+ */
+struct _PurpleChatConversationBuddyPrivate
+{
+	/** The chat participant's name in the chat. */
+	char *name;
+
+	/** The chat participant's alias, if known; @a NULL otherwise. */
+	char *alias;
+
+	/**
+	 * A string by which this buddy will be sorted, or @c NULL if the
+	 * buddy should be sorted by its @c name.  (This is currently always
+	 * @c NULL.
+	 */
+	char *alias_key;
+
+	/**
+	 * @a TRUE if this chat participant is on the buddy list;
+	 * @a FALSE otherwise.
+	 */
+	gboolean buddy;
+
+	/**
+	 * A bitwise OR of flags for this participant, such as whether they
+	 * are a channel operator.
+	 */
+	PurpleChatConversationBuddyFlags flags;
+
+	/**
+	 * A hash table of attributes about the user, such as real name,
+	 * user\@host, etc.
+	 */
+	GHashTable *attributes;
+
+	/** The UI can put whatever it wants here. */
+	gpointer ui_data;
+};
+
+/**************************************************************************
+ * IM Conversation API
+ **************************************************************************/
+void
+purple_im_conversation_set_icon(PurpleIMConversation *im, PurpleBuddyIcon *icon)
+{
+	g_return_if_fail(im != NULL);
+
+	if (im->icon != icon)
+	{
+		purple_buddy_icon_unref(im->icon);
+
+		im->icon = (icon == NULL ? NULL : purple_buddy_icon_ref(icon));
+	}
+
+	purple_conversation_update(purple_im_conversation_get_conversation(im),
+							 PURPLE_CONVERSATION_UPDATE_ICON);
+}
+
+PurpleBuddyIcon *
+purple_im_conversation_get_icon(const PurpleIMConversation *im)
+{
+	g_return_val_if_fail(im != NULL, NULL);
+
+	return im->icon;
+}
+
+void
+purple_im_conversation_set_typing_state(PurpleIMConversation *im, PurpleIMConversationTypingState state)
+{
+	g_return_if_fail(im != NULL);
+
+	if (im->typing_state != state)
+	{
+		im->typing_state = state;
+
+		switch (state)
+		{
+			case PURPLE_IM_CONVERSATION_TYPING:
+				purple_signal_emit(purple_conversations_get_handle(),
+								   "buddy-typing", im->conv->account, im->conv->name);
+				break;
+			case PURPLE_IM_CONVERSATION_TYPED:
+				purple_signal_emit(purple_conversations_get_handle(),
+								   "buddy-typed", im->conv->account, im->conv->name);
+				break;
+			case PURPLE_IM_CONVERSATION_NOT_TYPING:
+				purple_signal_emit(purple_conversations_get_handle(),
+								   "buddy-typing-stopped", im->conv->account, im->conv->name);
+				break;
+		}
+
+		purple_im_conversation_update_typing(im);
+	}
+}
+
+PurpleIMConversationTypingState
+purple_im_conversation_get_typing_state(const PurpleIMConversation *im)
+{
+	g_return_val_if_fail(im != NULL, 0);
+
+	return im->typing_state;
+}
+
+void
+purple_im_conversation_start_typing_timeout(PurpleIMConversation *im, int timeout)
+{
+	PurpleConversation *conv;
+
+	g_return_if_fail(im != NULL);
+
+	if (im->typing_timeout > 0)
+		purple_im_conversation_stop_typing_timeout(im);
+
+	conv = purple_im_conversation_get_conversation(im);
+
+	im->typing_timeout = purple_timeout_add_seconds(timeout, reset_typing_cb, conv);
+}
+
+void
+purple_im_conversation_stop_typing_timeout(PurpleIMConversation *im)
+{
+	g_return_if_fail(im != NULL);
+
+	if (im->typing_timeout == 0)
+		return;
+
+	purple_timeout_remove(im->typing_timeout);
+	im->typing_timeout = 0;
+}
+
+guint
+purple_im_conversation_get_typing_timeout(const PurpleIMConversation *im)
+{
+	g_return_val_if_fail(im != NULL, 0);
+
+	return im->typing_timeout;
+}
+
+void
+purple_im_conversation_set_type_again(PurpleIMConversation *im, unsigned int val)
+{
+	g_return_if_fail(im != NULL);
+
+	if (val == 0)
+		im->type_again = 0;
+	else
+		im->type_again = time(NULL) + val;
+}
+
+time_t
+purple_im_conversation_get_type_again(const PurpleIMConversation *im)
+{
+	g_return_val_if_fail(im != NULL, 0);
+
+	return im->type_again;
+}
+
+void
+purple_im_conversation_start_send_typed_timeout(PurpleIMConversation *im)
+{
+	g_return_if_fail(im != NULL);
+
+	im->send_typed_timeout = purple_timeout_add_seconds(SEND_TYPED_TIMEOUT_SECONDS,
+	                                                    send_typed_cb,
+	                                                    purple_im_conversation_get_conversation(im));
+}
+
+void
+purple_im_conversation_stop_send_typed_timeout(PurpleIMConversation *im)
+{
+	g_return_if_fail(im != NULL);
+
+	if (im->send_typed_timeout == 0)
+		return;
+
+	purple_timeout_remove(im->send_typed_timeout);
+	im->send_typed_timeout = 0;
+}
+
+guint
+purple_im_conversation_get_send_typed_timeout(const PurpleIMConversation *im)
+{
+	g_return_val_if_fail(im != NULL, 0);
+
+	return im->send_typed_timeout;
+}
+
+void
+purple_im_conversation_update_typing(PurpleIMConversation *im)
+{
+	g_return_if_fail(im != NULL);
+
+	purple_conversation_update(purple_im_conversation_get_conversation(im),
+							 PURPLE_CONVERSATION_UPDATE_TYPING);
+}
+
+void
+purple_im_conversation_write(PurpleIMConversation *im, const char *who, const char *message,
+			  PurpleConversationMessageFlags flags, time_t mtime)
+{
+	PurpleConversation *c;
+
+	g_return_if_fail(im != NULL);
+	g_return_if_fail(message != NULL);
+
+	c = purple_im_conversation_get_conversation(im);
+
+	if ((flags & PURPLE_CONVERSATION_MESSAGE_RECV) == PURPLE_CONVERSATION_MESSAGE_RECV) {
+		purple_im_conversation_set_typing_state(im, PURPLE_IM_CONVERSATION_NOT_TYPING);
+	}
+
+	/* Pass this on to either the ops structure or the default write func. */
+	if (c->ui_ops != NULL && c->ui_ops->write_im != NULL)
+		c->ui_ops->write_im(c, who, message, flags, mtime);
+	else
+		purple_conversation_write(c, who, message, flags, mtime);
+}
+
+void
+purple_im_conversation_send(PurpleIMConversation *im, const char *message)
+{
+	purple_im_conversation_send_with_flags(im, message, 0);
+}
+
+void
+purple_im_conversation_send_with_flags(PurpleIMConversation *im, const char *message, PurpleConversationMessageFlags flags)
+{
+	g_return_if_fail(im != NULL);
+	g_return_if_fail(message != NULL);
+
+	common_send(purple_im_conversation_get_conversation(im), message, flags);
+}
+
+/**************************************************************************
+ * Chat Conversation API
+ **************************************************************************/
+PurpleConversation *
+purple_chat_conversation_get_conversation(const PurpleChatConversation *chat)
+{
+	g_return_val_if_fail(chat != NULL, NULL);
+
+	return chat->conv;
+}
+
+GList *
+purple_chat_conversation_get_users(const PurpleChatConversation *chat)
+{
+	g_return_val_if_fail(chat != NULL, NULL);
+
+	return chat->in_room;
+}
+
+void
+purple_chat_conversation_ignore(PurpleChatConversation *chat, const char *name)
+{
+	g_return_if_fail(chat != NULL);
+	g_return_if_fail(name != NULL);
+
+	/* Make sure the user isn't already ignored. */
+	if (purple_chat_conversation_is_ignored_user(chat, name))
+		return;
+
+	purple_chat_conversation_set_ignored(chat,
+		g_list_append(chat->ignored, g_strdup(name)));
+}
+
+void
+purple_chat_conversation_unignore(PurpleChatConversation *chat, const char *name)
+{
+	GList *item;
+
+	g_return_if_fail(chat != NULL);
+	g_return_if_fail(name != NULL);
+
+	/* Make sure the user is actually ignored. */
+	if (!purple_chat_conversation_is_ignored_user(chat, name))
+		return;
+
+	item = g_list_find(purple_chat_conversation_get_ignored(chat),
+					   purple_chat_conversation_get_ignored_user(chat, name));
+
+	purple_chat_conversation_set_ignored(chat,
+		g_list_remove_link(chat->ignored, item));
+
+	g_free(item->data);
+	g_list_free_1(item);
+}
+
+GList *
+purple_chat_conversation_set_ignored(PurpleChatConversation *chat, GList *ignored)
+{
+	g_return_val_if_fail(chat != NULL, NULL);
+
+	chat->ignored = ignored;
+
+	return ignored;
+}
+
+GList *
+purple_chat_conversation_get_ignored(const PurpleChatConversation *chat)
+{
+	g_return_val_if_fail(chat != NULL, NULL);
+
+	return chat->ignored;
+}
+
+const char *
+purple_chat_conversation_get_ignored_user(const PurpleChatConversation *chat, const char *user)
+{
+	GList *ignored;
+
+	g_return_val_if_fail(chat != NULL, NULL);
+	g_return_val_if_fail(user != NULL, NULL);
+
+	for (ignored = purple_chat_conversation_get_ignored(chat);
+		 ignored != NULL;
+		 ignored = ignored->next) {
+
+		const char *ign = (const char *)ignored->data;
+
+		if (!purple_utf8_strcasecmp(user, ign) ||
+			((*ign == '+' || *ign == '%') && !purple_utf8_strcasecmp(user, ign + 1)))
+			return ign;
+
+		if (*ign == '@') {
+			ign++;
+
+			if ((*ign == '+' && !purple_utf8_strcasecmp(user, ign + 1)) ||
+				(*ign != '+' && !purple_utf8_strcasecmp(user, ign)))
+				return ign;
+		}
+	}
+
+	return NULL;
+}
+
+gboolean
+purple_chat_conversation_is_ignored_user(const PurpleChatConversation *chat, const char *user)
+{
+	g_return_val_if_fail(chat != NULL, FALSE);
+	g_return_val_if_fail(user != NULL, FALSE);
+
+	return (purple_chat_conversation_get_ignored_user(chat, user) != NULL);
+}
+
+void
+purple_chat_conversation_set_topic(PurpleChatConversation *chat, const char *who, const char *topic)
+{
+	g_return_if_fail(chat != NULL);
+
+	g_free(chat->who);
+	g_free(chat->topic);
+
+	chat->who   = g_strdup(who);
+	chat->topic = g_strdup(topic);
+
+	purple_conversation_update(purple_chat_conversation_get_conversation(chat),
+							 PURPLE_CONVERSATION_UPDATE_TOPIC);
+
+	purple_signal_emit(purple_conversations_get_handle(), "chat-topic-changed",
+					 chat->conv, chat->who, chat->topic);
+}
+
+const char *
+purple_chat_conversation_get_topic(const PurpleChatConversation *chat)
+{
+	g_return_val_if_fail(chat != NULL, NULL);
+
+	return chat->topic;
+}
+
+void
+purple_chat_conversation_set_id(PurpleChatConversation *chat, int id)
+{
+	g_return_if_fail(chat != NULL);
+
+	chat->id = id;
+}
+
+int
+purple_chat_conversation_get_id(const PurpleChatConversation *chat)
+{
+	g_return_val_if_fail(chat != NULL, -1);
+
+	return chat->id;
+}
+
+void
+purple_chat_conversation_write(PurpleChatConversation *chat, const char *who, const char *message,
+				PurpleConversationMessageFlags flags, time_t mtime)
+{
+	PurpleAccount *account;
+	PurpleConversation *conv;
+	PurpleConnection *gc;
+
+	g_return_if_fail(chat != NULL);
+	g_return_if_fail(who != NULL);
+	g_return_if_fail(message != NULL);
+
+	conv      = purple_chat_conversation_get_conversation(chat);
+	gc        = purple_conversation_get_connection(conv);
+	account   = purple_connection_get_account(gc);
+
+	/* Don't display this if the person who wrote it is ignored. */
+	if (purple_chat_conversation_is_ignored_user(chat, who))
+		return;
+
+	if (!(flags & PURPLE_CONVERSATION_MESSAGE_WHISPER)) {
+		const char *str;
+
+		str = purple_normalize(account, who);
+
+		if (purple_strequal(str, chat->nick)) {
+			flags |= PURPLE_CONVERSATION_MESSAGE_SEND;
+		} else {
+			flags |= PURPLE_CONVERSATION_MESSAGE_RECV;
+
+			if (purple_utf8_has_word(message, chat->nick))
+				flags |= PURPLE_CONVERSATION_MESSAGE_NICK;
+		}
+	}
+
+	/* Pass this on to either the ops structure or the default write func. */
+	if (conv->ui_ops != NULL && conv->ui_ops->write_chat != NULL)
+		conv->ui_ops->write_chat(conv, who, message, flags, mtime);
+	else
+		purple_conversation_write(conv, who, message, flags, mtime);
+}
+
+void
+purple_chat_conversation_send(PurpleChatConversation *chat, const char *message)
+{
+	purple_chat_conversation_send_with_flags(chat, message, 0);
+}
+
+void
+purple_chat_conversation_send_with_flags(PurpleChatConversation *chat, const char *message, PurpleConversationMessageFlags flags)
+{
+	g_return_if_fail(chat != NULL);
+	g_return_if_fail(message != NULL);
+
+	common_send(purple_chat_conversation_get_conversation(chat), message, flags);
+}
+
+void
+purple_chat_conversation_add_user(PurpleChatConversation *chat, const char *user,
+						const char *extra_msg, PurpleChatConversationBuddyFlags flags,
+						gboolean new_arrival)
+{
+	GList *users = g_list_append(NULL, (char *)user);
+	GList *extra_msgs = g_list_append(NULL, (char *)extra_msg);
+	GList *flags2 = g_list_append(NULL, GINT_TO_POINTER(flags));
+
+	purple_chat_conversation_add_users(chat, users, extra_msgs, flags2, new_arrival);
+
+	g_list_free(users);
+	g_list_free(extra_msgs);
+	g_list_free(flags2);
+}
+
+void
+purple_chat_conversation_add_users(PurpleChatConversation *chat, GList *users, GList *extra_msgs,
+						 GList *flags, gboolean new_arrivals)
+{
+	PurpleConversation *conv;
+	PurpleConversationUiOps *ops;
+	PurpleChatConversationBuddy *cbuddy;
+	PurpleConnection *gc;
+	PurplePluginProtocolInfo *prpl_info;
+	GList *ul, *fl;
+	GList *cbuddies = NULL;
+
+	g_return_if_fail(chat  != NULL);
+	g_return_if_fail(users != NULL);
+
+	conv = purple_chat_conversation_get_conversation(chat);
+	ops  = purple_conversation_get_ui_ops(conv);
+
+	gc = purple_conversation_get_connection(conv);
+	g_return_if_fail(gc != NULL);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
+	g_return_if_fail(prpl_info != NULL);
+
+	ul = users;
+	fl = flags;
+	while ((ul != NULL) && (fl != NULL)) {
+		const char *user = (const char *)ul->data;
+		const char *alias = user;
+		gboolean quiet;
+		PurpleChatConversationBuddyFlags flag = GPOINTER_TO_INT(fl->data);
+		const char *extra_msg = (extra_msgs ? extra_msgs->data : NULL);
+
+		if(!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+			if (purple_strequal(chat->nick, purple_normalize(conv->account, user))) {
+				const char *alias2 = purple_account_get_private_alias(conv->account);
+				if (alias2 != NULL)
+					alias = alias2;
+				else
+				{
+					const char *display_name = purple_connection_get_display_name(gc);
+					if (display_name != NULL)
+						alias = display_name;
+				}
+			} else {
+				PurpleBuddy *buddy;
+				if ((buddy = purple_find_buddy(purple_connection_get_account(gc), user)) != NULL)
+					alias = purple_buddy_get_contact_alias(buddy);
+			}
+		}
+
+		quiet = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
+						 "chat-buddy-joining", conv, user, flag)) ||
+				purple_chat_conversation_is_ignored_user(chat, user);
+
+		cbuddy = purple_chat_conversation_buddy_new(user, alias, flag);
+		cbuddy->buddy = purple_find_buddy(conv->account, user) != NULL;
+
+		chat->in_room = g_list_prepend(chat->in_room, cbuddy);
+		g_hash_table_replace(chat->users, g_strdup(cbuddy->name), cbuddy);
+
+		cbuddies = g_list_prepend(cbuddies, cbuddy);
+
+		if (!quiet && new_arrivals) {
+			char *alias_esc = g_markup_escape_text(alias, -1);
+			char *tmp;
+
+			if (extra_msg == NULL)
+				tmp = g_strdup_printf(_("%s entered the room."), alias_esc);
+			else {
+				char *extra_msg_esc = g_markup_escape_text(extra_msg, -1);
+				tmp = g_strdup_printf(_("%s [<I>%s</I>] entered the room."),
+				                      alias_esc, extra_msg_esc);
+				g_free(extra_msg_esc);
+			}
+			g_free(alias_esc);
+
+			purple_conversation_write(conv, NULL, tmp,
+					PURPLE_CONVERSATION_MESSAGE_SYSTEM | PURPLE_CONVERSATION_MESSAGE_NO_LINKIFY,
+					time(NULL));
+			g_free(tmp);
+		}
+
+		purple_signal_emit(purple_conversations_get_handle(),
+						 "chat-buddy-joined", conv, user, flag, new_arrivals);
+		ul = ul->next;
+		fl = fl->next;
+		if (extra_msgs != NULL)
+			extra_msgs = extra_msgs->next;
+	}
+
+	cbuddies = g_list_sort(cbuddies, (GCompareFunc)purple_chat_conversation_buddy_compare);
+
+	if (ops != NULL && ops->chat_add_users != NULL)
+		ops->chat_add_users(conv, cbuddies, new_arrivals);
+
+	g_list_free(cbuddies);
+}
+
+void
+purple_chat_conversation_rename_user(PurpleChatConversation *chat, const char *old_user,
+						   const char *new_user)
+{
+	PurpleConversation *conv;
+	PurpleConversationUiOps *ops;
+	PurpleConnection *gc;
+	PurplePluginProtocolInfo *prpl_info;
+	PurpleChatConversationBuddy *cb;
+	PurpleChatConversationBuddyFlags flags;
+	const char *new_alias = new_user;
+	char tmp[BUF_LONG];
+	gboolean is_me = FALSE;
+
+	g_return_if_fail(chat != NULL);
+	g_return_if_fail(old_user != NULL);
+	g_return_if_fail(new_user != NULL);
+
+	conv = purple_chat_conversation_get_conversation(chat);
+	ops  = purple_conversation_get_ui_ops(conv);
+
+	gc = purple_conversation_get_connection(conv);
+	g_return_if_fail(gc != NULL);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
+	g_return_if_fail(prpl_info != NULL);
+
+	if (purple_strequal(chat->nick, purple_normalize(conv->account, old_user))) {
+		const char *alias;
+
+		/* Note this for later. */
+		is_me = TRUE;
+
+		if(!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+			alias = purple_account_get_private_alias(conv->account);
+			if (alias != NULL)
+				new_alias = alias;
+			else
+			{
+				const char *display_name = purple_connection_get_display_name(gc);
+				if (display_name != NULL)
+					new_alias = display_name;
+			}
+		}
+	} else if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+		PurpleBuddy *buddy;
+		if ((buddy = purple_find_buddy(purple_connection_get_account(gc), new_user)) != NULL)
+			new_alias = purple_buddy_get_contact_alias(buddy);
+	}
+
+	flags = purple_chat_conversation_user_get_flags(chat, old_user);
+	cb = purple_chat_conversation_buddy_new(new_user, new_alias, flags);
+	cb->buddy = purple_find_buddy(conv->account, new_user) != NULL;
+
+	chat->in_room = g_list_prepend(chat->in_room, cb);
+	g_hash_table_replace(chat->users, g_strdup(cb->name), cb);
+
+	if (ops != NULL && ops->chat_rename_user != NULL)
+		ops->chat_rename_user(conv, old_user, new_user, new_alias);
+
+	cb = purple_chat_conversation_find_buddy(chat, old_user);
+
+	if (cb) {
+		chat->in_room = g_list_remove(chat->in_room, cb);
+		g_hash_table_remove(chat->users, cb->name);
+		purple_chat_conversation_buddy_destroy(cb);
+	}
+
+	if (purple_chat_conversation_is_ignored_user(chat, old_user)) {
+		purple_chat_conversation_unignore(chat, old_user);
+		purple_chat_conversation_ignore(chat, new_user);
+	}
+	else if (purple_chat_conversation_is_ignored_user(chat, new_user))
+		purple_chat_conversation_unignore(chat, new_user);
+
+	if (is_me)
+		purple_chat_conversation_set_nick(chat, new_user);
+
+	if (purple_prefs_get_bool("/purple/conversations/chat/show_nick_change") &&
+	    !purple_chat_conversation_is_ignored_user(chat, new_user)) {
+
+		if (is_me) {
+			char *escaped = g_markup_escape_text(new_user, -1);
+			g_snprintf(tmp, sizeof(tmp),
+					_("You are now known as %s"), escaped);
+			g_free(escaped);
+		} else {
+			const char *old_alias = old_user;
+			const char *new_alias = new_user;
+			char *escaped;
+			char *escaped2;
+
+			if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+				PurpleBuddy *buddy;
+
+				if ((buddy = purple_find_buddy(purple_connection_get_account(gc), old_user)) != NULL)
+					old_alias = purple_buddy_get_contact_alias(buddy);
+				if ((buddy = purple_find_buddy(purple_connection_get_account(gc), new_user)) != NULL)
+					new_alias = purple_buddy_get_contact_alias(buddy);
+			}
+
+			escaped = g_markup_escape_text(old_alias, -1);
+			escaped2 = g_markup_escape_text(new_alias, -1);
+			g_snprintf(tmp, sizeof(tmp),
+					_("%s is now known as %s"), escaped, escaped2);
+			g_free(escaped);
+			g_free(escaped2);
+		}
+
+		purple_conversation_write(conv, NULL, tmp,
+				PURPLE_CONVERSATION_MESSAGE_SYSTEM | PURPLE_CONVERSATION_MESSAGE_NO_LINKIFY,
+				time(NULL));
+	}
+}
+
+void
+purple_chat_conversation_remove_user(PurpleChatConversation *chat, const char *user, const char *reason)
+{
+	GList *users = g_list_append(NULL, (char *)user);
+
+	purple_chat_conversation_remove_users(chat, users, reason);
+
+	g_list_free(users);
+}
+
+void
+purple_chat_conversation_remove_users(PurpleChatConversation *chat, GList *users, const char *reason)
+{
+	PurpleConversation *conv;
+	PurpleConnection *gc;
+	PurplePluginProtocolInfo *prpl_info;
+	PurpleConversationUiOps *ops;
+	PurpleChatConversationBuddy *cb;
+	GList *l;
+	gboolean quiet;
+
+	g_return_if_fail(chat  != NULL);
+	g_return_if_fail(users != NULL);
+
+	conv = purple_chat_conversation_get_conversation(chat);
+
+	gc = purple_conversation_get_connection(conv);
+	g_return_if_fail(gc != NULL);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
+	g_return_if_fail(prpl_info != NULL);
+
+	ops  = purple_conversation_get_ui_ops(conv);
+
+	for (l = users; l != NULL; l = l->next) {
+		const char *user = (const char *)l->data;
+		quiet = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
+					"chat-buddy-leaving", conv, user, reason)) |
+				purple_chat_conversation_is_ignored_user(chat, user);
+
+		cb = purple_chat_conversation_find_buddy(chat, user);
+
+		if (cb) {
+			chat->in_room = g_list_remove(chat->in_room, cb);
+			g_hash_table_remove(chat->users, cb->name);
+			purple_chat_conversation_buddy_destroy(cb);
+		}
+
+		/* NOTE: Don't remove them from ignored in case they re-enter. */
+
+		if (!quiet) {
+			const char *alias = user;
+			char *alias_esc;
+			char *tmp;
+
+			if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+				PurpleBuddy *buddy;
+
+				if ((buddy = purple_find_buddy(purple_connection_get_account(gc), user)) != NULL)
+					alias = purple_buddy_get_contact_alias(buddy);
+			}
+
+			alias_esc = g_markup_escape_text(alias, -1);
+
+			if (reason == NULL || !*reason)
+				tmp = g_strdup_printf(_("%s left the room."), alias_esc);
+			else {
+				char *reason_esc = g_markup_escape_text(reason, -1);
+				tmp = g_strdup_printf(_("%s left the room (%s)."),
+				                      alias_esc, reason_esc);
+				g_free(reason_esc);
+			}
+			g_free(alias_esc);
+
+			purple_conversation_write(conv, NULL, tmp,
+					PURPLE_CONVERSATION_MESSAGE_SYSTEM | PURPLE_CONVERSATION_MESSAGE_NO_LINKIFY,
+					time(NULL));
+			g_free(tmp);
+		}
+
+		purple_signal_emit(purple_conversations_get_handle(), "chat-buddy-left",
+						 conv, user, reason);
+	}
+
+	if (ops != NULL && ops->chat_remove_users != NULL)
+		ops->chat_remove_users(conv, users);
+}
+
+void
+purple_chat_conversation_clear_users(PurpleChatConversation *chat)
+{
+	PurpleConversation *conv;
+	PurpleConversationUiOps *ops;
+	GList *users;
+	GList *l;
+	GList *names = NULL;
+
+	g_return_if_fail(chat != NULL);
+
+	conv  = purple_chat_conversation_get_conversation(chat);
+	ops   = purple_conversation_get_ui_ops(conv);
+	users = chat->in_room;
+
+	if (ops != NULL && ops->chat_remove_users != NULL) {
+		for (l = users; l; l = l->next) {
+			PurpleChatConversationBuddy *cb = l->data;
+			names = g_list_prepend(names, cb->name);
+		}
+		ops->chat_remove_users(conv, names);
+		g_list_free(names);
+	}
+
+	for (l = users; l; l = l->next)
+	{
+		PurpleChatConversationBuddy *cb = l->data;
+
+		purple_signal_emit(purple_conversations_get_handle(),
+						 "chat-buddy-leaving", conv, cb->name, NULL);
+		purple_signal_emit(purple_conversations_get_handle(),
+						 "chat-buddy-left", conv, cb->name, NULL);
+
+		purple_chat_conversation_buddy_destroy(cb);
+	}
+
+	g_hash_table_remove_all(chat->users);
+
+	g_list_free(users);
+	chat->in_room = NULL;
+}
+
+
+gboolean
+purple_chat_conversation_find_user(PurpleChatConversation *chat, const char *user)
+{
+	g_return_val_if_fail(chat != NULL, FALSE);
+	g_return_val_if_fail(user != NULL, FALSE);
+
+	return (purple_chat_conversation_find_buddy(chat, user) != NULL);
+}
+
+void
+purple_chat_conversation_user_set_flags(PurpleChatConversation *chat, const char *user,
+							  PurpleChatConversationBuddyFlags flags)
+{
+	PurpleConversation *conv;
+	PurpleConversationUiOps *ops;
+	PurpleChatConversationBuddy *cb;
+	PurpleChatConversationBuddyFlags oldflags;
+
+	g_return_if_fail(chat != NULL);
+	g_return_if_fail(user != NULL);
+
+	cb = purple_chat_conversation_find_buddy(chat, user);
+
+	if (!cb)
+		return;
+
+	if (flags == cb->flags)
+		return;
+
+	oldflags = cb->flags;
+	cb->flags = flags;
+
+	conv = purple_chat_conversation_get_conversation(chat);
+	ops = purple_conversation_get_ui_ops(conv);
+
+	if (ops != NULL && ops->chat_update_user != NULL)
+		ops->chat_update_user(conv, user);
+
+	purple_signal_emit(purple_conversations_get_handle(),
+					 "chat-buddy-flags", conv, user, oldflags, flags);
+}
+
+PurpleChatConversationBuddyFlags
+purple_chat_conversation_user_get_flags(PurpleChatConversation *chat, const char *user)
+{
+	PurpleChatConversationBuddy *cb;
+
+	g_return_val_if_fail(chat != NULL, 0);
+	g_return_val_if_fail(user != NULL, 0);
+
+	cb = purple_chat_conversation_find_buddy(chat, user);
+
+	if (!cb)
+		return PURPLE_CHAT_CONVERSATION_BUDDY_NONE;
+
+	return cb->flags;
+}
+
+void
+purple_chat_conversation_leave(PurpleChatConversation *chat)
+{
+	g_return_if_fail(chat != NULL);
+
+	chat->left = TRUE;
+	purple_conversation_update(chat->conv, PURPLE_CONVERSATION_UPDATE_CHATLEFT);
+}
+
+gboolean
+purple_chat_conversation_has_left(PurpleChatConversation *chat)
+{
+	g_return_val_if_fail(chat != NULL, TRUE);
+
+	return chat->left;
+}
+
+PurpleChatConversationBuddy *
+purple_chat_conversation_find_buddy(PurpleChatConversation *chat, const char *name)
+{
+	g_return_val_if_fail(chat != NULL, NULL);
+	g_return_val_if_fail(name != NULL, NULL);
+
+	return g_hash_table_lookup(chat->users, name);
+}
+
+/**************************************************************************
+ * Chat Conversation Buddy API
+ **************************************************************************/
+static int
+purple_chat_conversation_buddy_compare(PurpleChatConversationBuddy *a, PurpleChatConversationBuddy *b)
+{
+	PurpleChatConversationBuddyFlags f1 = 0, f2 = 0;
+	char *user1 = NULL, *user2 = NULL;
+	gint ret = 0;
+
+	if (a) {
+		f1 = a->flags;
+		if (a->alias_key)
+			user1 = a->alias_key;
+		else if (a->name)
+			user1 = a->name;
+	}
+
+	if (b) {
+		f2 = b->flags;
+		if (b->alias_key)
+			user2 = b->alias_key;
+		else if (b->name)
+			user2 = b->name;
+	}
+
+	if (user1 == NULL || user2 == NULL) {
+		if (!(user1 == NULL && user2 == NULL))
+			ret = (user1 == NULL) ? -1: 1;
+	} else if (f1 != f2) {
+		/* sort more important users first */
+		ret = (f1 > f2) ? -1 : 1;
+	} else if (a->buddy != b->buddy) {
+		ret = a->buddy ? -1 : 1;
+	} else {
+		ret = purple_utf8_strcasecmp(user1, user2);
+	}
+
+	return ret;
+}
+
+PurpleChatConversationBuddy *
+purple_chat_conversation_buddy_new(const char *name, const char *alias, PurpleChatConversationBuddyFlags flags)
+{
+	PurpleChatConversationBuddy *cb;
+
+	g_return_val_if_fail(name != NULL, NULL);
+
+	cb = g_new0(PurpleChatConversationBuddy, 1);
+	cb->name = g_strdup(name);
+	cb->flags = flags;
+	cb->alias = g_strdup(alias);
+	cb->attributes = g_hash_table_new_full(g_str_hash, g_str_equal,
+										   g_free, g_free);
+
+	PURPLE_DBUS_REGISTER_POINTER(cb, PurpleChatConversationBuddy);
+	return cb;
+}
+
+void
+purple_chat_conversation_buddy_destroy(PurpleChatConversationBuddy *cb)
+{
+	if (cb == NULL)
+		return;
+
+	purple_signal_emit(purple_conversations_get_handle(),
+			"deleting-chat-buddy", cb);
+
+	g_free(cb->alias);
+	g_free(cb->alias_key);
+	g_free(cb->name);
+	g_hash_table_destroy(cb->attributes);
+
+	PURPLE_DBUS_UNREGISTER_POINTER(cb);
+	g_free(cb);
+}
+
+const char *
+purple_chat_conversation_buddy_get_alias(const PurpleChatConversationBuddy *cb)
+{
+	g_return_val_if_fail(cb != NULL, NULL);
+
+	return cb->alias;
+}
+
+const char *
+purple_chat_conversation_buddy_get_name(const PurpleChatConversationBuddy *cb)
+{
+	g_return_val_if_fail(cb != NULL, NULL);
+
+	return cb->name;
+}
+
+PurpleChatConversationBuddyFlags
+purple_chat_conversation_buddy_get_flags(const PurpleChatConversationBuddy *cb)
+{
+	g_return_val_if_fail(cb != NULL, PURPLE_CHAT_CONVERSATION_BUDDY_NONE);
+
+	return cb->flags;
+}
+
+const char *
+purple_chat_conversation_buddy_get_attribute(PurpleChatConversationBuddy *cb, const char *key)
+{
+	g_return_val_if_fail(cb != NULL, NULL);
+	g_return_val_if_fail(key != NULL, NULL);
+	
+	return g_hash_table_lookup(cb->attributes, key);
+}
+
+GList *
+purple_chat_conversation_buddy_get_attribute_keys(PurpleChatConversationBuddy *cb)
+{
+	GList *keys = NULL;
+	
+	g_return_val_if_fail(cb != NULL, NULL);
+	
+	g_hash_table_foreach(cb->attributes, (GHFunc)append_attribute_key, &keys);
+	
+	return keys;
+}
+
+void
+purple_chat_conversation_buddy_set_attribute(PurpleChatConversation *chat, PurpleChatConversationBuddy *cb, const char *key, const char *value)
+{
+	PurpleConversation *conv;
+	PurpleConversationUiOps *ops;
+	
+	g_return_if_fail(cb != NULL);
+	g_return_if_fail(key != NULL);
+	g_return_if_fail(value != NULL);
+	
+	g_hash_table_replace(cb->attributes, g_strdup(key), g_strdup(value));
+	
+	conv = purple_chat_conversation_get_conversation(chat);
+	ops = purple_conversation_get_ui_ops(conv);
+	
+	if (ops != NULL && ops->chat_update_user != NULL)
+		ops->chat_update_user(conv, cb->name);
+}
+
+void
+purple_chat_conversation_buddy_set_attributes(PurpleChatConversation *chat, PurpleChatConversationBuddy *cb, GList *keys, GList *values)
+{
+	PurpleConversation *conv;
+	PurpleConversationUiOps *ops;
+	
+	g_return_if_fail(cb != NULL);
+	g_return_if_fail(keys != NULL);
+	g_return_if_fail(values != NULL);
+	
+	while (keys != NULL && values != NULL) {
+		g_hash_table_replace(cb->attributes, g_strdup(keys->data), g_strdup(values->data));
+		keys = g_list_next(keys);
+		values = g_list_next(values);
+	}
+	
+	conv = purple_chat_conversation_get_conversation(chat);
+	ops = purple_conversation_get_ui_ops(conv);
+	
+	if (ops != NULL && ops->chat_update_user != NULL)
+		ops->chat_update_user(conv, cb->name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/conversationtypes.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,829 @@
+/**
+ * @file conversationtypes.h Chat and IM Conversation API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef _PURPLE_CONVERSATION_TYPES_H_
+#define _PURPLE_CONVERSATION_TYPES_H_
+
+/**************************************************************************/
+/** Data Structures                                                       */
+/**************************************************************************/
+
+#define PURPLE_TYPE_IM_CONVERSATION       (purple_im_conversation_get_type())
+#define PURPLE_IM_CONVERSATION(obj)       (G_TYPE_CHECK_INSTANCE_CAST((obj),  \
+                                           PURPLE_TYPE_IM_CONVERSATION,       \
+                                           PurpleIMConversation))
+#define PURPLE_IM_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+                                           PURPLE_TYPE_IM_CONVERSATION,       \
+                                           PurpleIMConversationClass))
+#define PURPLE_IS_IM_CONVERSATION(obj)    (G_TYPE_CHECK_INSTANCE_TYPE((obj),  \
+                                           PURPLE_TYPE_IM_CONVERSATION))
+#define PURPLE_IS_IM_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
+                                           PURPLE_TYPE_IM_CONVERSATION))
+#define PURPLE_IM_CONVERSATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),\
+                                           PURPLE_TYPE_IM_CONVERSATION,       \
+                                           PurpleIMConversationClass))
+
+/** @copydoc _PurpleIMConversation */
+typedef struct _PurpleIMConversation         PurpleIMConversation;
+/** @copydoc _PurpleIMConversationClass */
+typedef struct _PurpleIMConversationClass    PurpleIMConversationClass;
+
+#define PURPLE_TYPE_CHAT_CONVERSATION     (purple_chat_conversation_get_type())
+#define PURPLE_CHAT_CONVERSATION(obj)     (G_TYPE_CHECK_INSTANCE_CAST((obj),  \
+                                           PURPLE_TYPE_CHAT_CONVERSATION,     \
+                                           PurpleChatConversation))
+#define PURPLE_CHAT_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
+                                           PURPLE_TYPE_CHAT_CONVERSATION,     \
+                                           PurpleChatConversationClass))
+#define PURPLE_IS_CHAT_CONVERSATION(obj)  (G_TYPE_CHECK_INSTANCE_TYPE((obj),  \
+                                           PURPLE_TYPE_CHAT_CONVERSATION))
+#define PURPLE_IS_CHAT_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
+                                           PURPLE_TYPE_CHAT_CONVERSATION))
+#define PURPLE_CHAT_CONVERSATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),\
+                                           PURPLE_TYPE_CHAT_CONVERSATION,     \
+                                           PurpleChatConversationClass))
+
+/** @copydoc _PurpleChatConversation */
+typedef struct _PurpleChatConversation       PurpleChatConversation;
+/** @copydoc _PurpleChatConversationClass */
+typedef struct _PurpleChatConversationClass  PurpleChatConversationClass;
+
+#define PURPLE_TYPE_CHAT_CONVERSATION_BUDDY (purple_chat_conversation_buddy_get_type())
+#define PURPLE_CHAT_CONVERSATION_BUDDY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+                                           PURPLE_TYPE_CHAT_CONVERSATION_BUDDY,\
+                                           PurpleChatConversationBuddy))
+#define PURPLE_CHAT_CONVERSATION_BUDDY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
+                                           PURPLE_TYPE_CHAT_CONVERSATION_BUDDY,\
+                                           PurpleChatConversationBuddyClass))
+#define PURPLE_IS_CHAT_CONVERSATION_BUDDY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
+                                           PURPLE_TYPE_CHAT_CONVERSATION_BUDDY))
+#define PURPLE_IS_CHAT_CONVERSATION_BUDDY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
+                                           PURPLE_TYPE_CHAT_CONVERSATION_BUDDY))
+#define PURPLE_CHAT_CONVERSATION_BUDDY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),\
+                                           PURPLE_TYPE_CHAT_CONVERSATION_BUDDY,\
+                                           PurpleChatConversationBuddyClass))
+
+/** @copydoc _PurpleChatConversationBuddy */
+typedef struct _PurpleChatConversationBuddy       PurpleChatConversationBuddy;
+/** @copydoc _PurpleChatConversationBuddyClass */
+typedef struct _PurpleChatConversationBuddyClass  PurpleChatConversationBuddyClass;
+
+/**
+ * The typing state of a user.
+ */
+typedef enum
+{
+	PURPLE_IM_CONVERSATION_NOT_TYPING = 0,  /**< Not typing.                 */
+	PURPLE_IM_CONVERSATION_TYPING,          /**< Currently typing.           */
+	PURPLE_IM_CONVERSATION_TYPED            /**< Stopped typing momentarily. */
+
+} PurpleIMConversationTypingState;
+
+/**
+ * Flags applicable to users in Chats.
+ */
+typedef enum /*< flags >*/
+{
+	PURPLE_CHAT_CONVERSATION_BUDDY_NONE     = 0x0000, /**< No flags                     */
+	PURPLE_CHAT_CONVERSATION_BUDDY_VOICE    = 0x0001, /**< Voiced user or "Participant" */
+	PURPLE_CHAT_CONVERSATION_BUDDY_HALFOP   = 0x0002, /**< Half-op                      */
+	PURPLE_CHAT_CONVERSATION_BUDDY_OP       = 0x0004, /**< Channel Op or Moderator      */
+	PURPLE_CHAT_CONVERSATION_BUDDY_FOUNDER  = 0x0008, /**< Channel Founder              */
+	PURPLE_CHAT_CONVERSATION_BUDDY_TYPING   = 0x0010, /**< Currently typing             */
+	PURPLE_CHAT_CONVERSATION_BUDDY_AWAY     = 0x0020  /**< Currently away.              */
+
+} PurpleChatConversationBuddyFlags;
+
+#include "conversation.h"
+
+/**************************************************************************/
+/** PurpleIMConversation                                                  */
+/**************************************************************************/
+/** Structure representing an IM conversation instance. */
+struct _PurpleIMConversation
+{
+	/*< private >*/
+	PurpleConversation parent_object;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+/** Base class for all #PurpleIMConversation's */
+struct _PurpleIMConversationClass {
+	/*< private >*/
+	PurpleConversationClass parent_class;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+/**************************************************************************/
+/** PurpleChatConversation                                                */
+/**************************************************************************/
+/** Structure representing a chat conversation instance. */
+struct _PurpleChatConversation
+{
+	/*< private >*/
+	PurpleConversation parent_object;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+/** Base class for all #PurpleChatConversation's */
+struct _PurpleChatConversationClass {
+	/*< private >*/
+	PurpleConversationClass parent_class;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+/**************************************************************************/
+/** PurpleChatConversationBuddy                                           */
+/**************************************************************************/
+/** Structure representing a chat buddy instance. */
+struct _PurpleChatConversationBuddy
+{
+	/*< private >*/
+	GObject gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+/** Base class for all #PurpleChatConversationBuddy's */
+struct _PurpleChatConversationBuddyClass {
+	/*< private >*/
+	GObjectClass parent_class;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+/**************************************************************************/
+/** @name IM Conversation API                                             */
+/**************************************************************************/
+/*@{*/
+
+/** TODO
+ * Returns the GType for the IMConversation object.
+ */
+GType purple_im_conversation_get_type(void);
+
+/** TODO take from conversation.c purple_conversation_new()
+ * Creates a new IM conversation.
+ *
+ * @param account The account opening the conversation window on the purple
+ *                user's end.
+ * @param name    Name of the buddy.
+ *
+ * @return The new conversation.
+ */
+PurpleConversation *purple_im_conversation_new(PurpleAccount *account,
+		const char *name);
+
+/**
+ * Sets the IM's buddy icon.
+ *
+ * This should only be called from within Purple. You probably want to
+ * call purple_buddy_icon_set_data().
+ *
+ * @param im   The IM.
+ * @param icon The buddy icon.
+ *
+ * @see purple_buddy_icon_set_data()
+ */
+void purple_im_conversation_set_icon(PurpleIMConversation *im, PurpleBuddyIcon *icon);
+
+/**
+ * Returns the IM's buddy icon.
+ *
+ * @param im The IM.
+ *
+ * @return The buddy icon.
+ */
+PurpleBuddyIcon *purple_im_conversation_get_icon(const PurpleIMConversation *im);
+
+/**
+ * Sets the IM's typing state.
+ *
+ * @param im    The IM.
+ * @param state The typing state.
+ */
+void purple_im_conversation_set_typing_state(PurpleIMConversation *im, PurpleIMConversationTypingState state);
+
+/**
+ * Returns the IM's typing state.
+ *
+ * @param im The IM.
+ *
+ * @return The IM's typing state.
+ */
+PurpleIMConversationTypingState purple_im_conversation_get_typing_state(const PurpleIMConversation *im);
+
+/**
+ * Starts the IM's typing timeout.
+ *
+ * @param im      The IM.
+ * @param timeout The timeout.
+ */
+void purple_im_conversation_start_typing_timeout(PurpleIMConversation *im, int timeout);
+
+/**
+ * Stops the IM's typing timeout.
+ *
+ * @param im The IM.
+ */
+void purple_im_conversation_stop_typing_timeout(PurpleIMConversation *im);
+
+/**
+ * Returns the IM's typing timeout.
+ *
+ * @param im The IM.
+ *
+ * @return The timeout.
+ */
+guint purple_im_conversation_get_typing_timeout(const PurpleIMConversation *im);
+
+/**
+ * Sets the quiet-time when no PURPLE_IM_CONVERSATION_TYPING messages will be sent.
+ * Few protocols need this (maybe only MSN).  If the user is still
+ * typing after this quiet-period, then another PURPLE_IM_CONVERSATION_TYPING message
+ * will be sent.
+ *
+ * @param im  The IM.
+ * @param val The number of seconds to wait before allowing another
+ *            PURPLE_IM_CONVERSATION_TYPING message to be sent to the user.  Or 0 to
+ *            not send another PURPLE_IM_CONVERSATION_TYPING message.
+ */
+void purple_im_conversation_set_type_again(PurpleIMConversation *im, unsigned int val);
+
+/**
+ * Returns the time after which another PURPLE_IM_CONVERSATION_TYPING message should be sent.
+ *
+ * @param im The IM.
+ *
+ * @return The time in seconds since the epoch.  Or 0 if no additional
+ *         PURPLE_IM_CONVERSATION_TYPING message should be sent.
+ */
+time_t purple_im_conversation_get_type_again(const PurpleIMConversation *im);
+
+/**
+ * Starts the IM's type again timeout.
+ *
+ * @param im      The IM.
+ */
+void purple_im_conversation_start_send_typed_timeout(PurpleIMConversation *im);
+
+/**
+ * Stops the IM's type again timeout.
+ *
+ * @param im The IM.
+ */
+void purple_im_conversation_stop_send_typed_timeout(PurpleIMConversation *im);
+
+/**
+ * Returns the IM's type again timeout interval.
+ *
+ * @param im The IM.
+ *
+ * @return The type again timeout interval.
+ */
+guint purple_im_conversation_get_send_typed_timeout(const PurpleIMConversation *im);
+
+/**
+ * Updates the visual typing notification for an IM conversation.
+ *
+ * @param im The IM.
+ */
+void purple_im_conversation_update_typing(PurpleIMConversation *im);
+
+/** TODO override
+ * Writes to an IM.
+ *
+ * @param im      The IM.
+ * @param who     The user who sent the message.
+ * @param message The message to write.
+ * @param flags   The message flags.
+ * @param mtime   The time the message was sent.
+ */
+/*void purple_im_conversation_write(PurpleIMConversation *im, const char *who,
+						const char *message, PurpleConversationMessageFlags flags,
+						time_t mtime);*/
+
+/** TODO write forward
+ * Sends a message to this IM conversation.
+ *
+ * @param im      The IM.
+ * @param message The message to send.
+ */
+/*void purple_im_conversation_send(PurpleIMConversation *im, const char *message);*/
+
+/** TODO override
+ * Sends a message to this IM conversation with specified flags.
+ *
+ * @param im      The IM.
+ * @param message The message to send.
+ * @param flags   The PurpleConversationMessageFlags flags to use in addition to
+ *                PURPLE_CONVERSATION_MESSAGE_SEND.
+ */
+/*void purple_im_conversation_send_with_flags(PurpleIMConversation *im,
+		const char *message, PurpleConversationMessageFlags flags);*/
+
+/*@}*/
+
+/**************************************************************************/
+/** @name Chat Conversation API                                           */
+/**************************************************************************/
+/*@{*/
+
+/** TODO
+ * Returns the GType for the ChatConversation object.
+ */
+GType purple_chat_conversation_get_type(void);
+
+/** TODO take from conversation.c purple_conversation_new()
+ * Creates a new chat conversation.
+ *
+ * @param account The account opening the conversation window on the purple
+ *                user's end.
+ * @param name    The name of the conversation.
+ *
+ * @return The new conversation.
+ */
+PurpleConversation *purple_chat_conversation_new(PurpleAccount *account,
+		const char *name);
+
+/**
+ * Returns a list of users in the chat room.  The members of the list
+ * are PurpleChatConversationBuddy objects.
+ *
+ * @param chat The chat.
+ *
+ * @constreturn The list of users.
+ */
+GList *purple_chat_conversation_get_users(const PurpleChatConversation *chat);
+
+/**
+ * Ignores a user in a chat room.
+ *
+ * @param chat The chat.
+ * @param name The name of the user.
+ */
+void purple_chat_conversation_ignore(PurpleChatConversation *chat, const char *name);
+
+/**
+ * Unignores a user in a chat room.
+ *
+ * @param chat The chat.
+ * @param name The name of the user.
+ */
+void purple_chat_conversation_unignore(PurpleChatConversation *chat, const char *name);
+
+/**
+ * Sets the list of ignored users in the chat room.
+ *
+ * @param chat    The chat.
+ * @param ignored The list of ignored users.
+ *
+ * @return The list passed.
+ */
+GList *purple_chat_conversation_set_ignored(PurpleChatConversation *chat, GList *ignored);
+
+/**
+ * Returns the list of ignored users in the chat room.
+ *
+ * @param chat The chat.
+ *
+ * @constreturn The list of ignored users.
+ */
+GList *purple_chat_conversation_get_ignored(const PurpleChatConversation *chat);
+
+/**
+ * Returns the actual name of the specified ignored user, if it exists in
+ * the ignore list.
+ *
+ * If the user found contains a prefix, such as '+' or '\@', this is also
+ * returned. The username passed to the function does not have to have this
+ * formatting.
+ *
+ * @param chat The chat.
+ * @param user The user to check in the ignore list.
+ *
+ * @return The ignored user if found, complete with prefixes, or @c NULL
+ *         if not found.
+ */
+const char *purple_chat_conversation_get_ignored_user(const PurpleChatConversation *chat,
+											const char *user);
+
+/**
+ * Returns @c TRUE if the specified user is ignored.
+ *
+ * @param chat The chat.
+ * @param user The user.
+ *
+ * @return @c TRUE if the user is in the ignore list; @c FALSE otherwise.
+ */
+gboolean purple_chat_conversation_is_ignored_user(const PurpleChatConversation *chat,
+										const char *user);
+
+/**
+ * Sets the chat room's topic.
+ *
+ * @param chat  The chat.
+ * @param who   The user that set the topic.
+ * @param topic The topic.
+ */
+void purple_chat_conversation_set_topic(PurpleChatConversation *chat, const char *who,
+							  const char *topic);
+
+/**
+ * Returns the chat room's topic.
+ *
+ * @param chat The chat.
+ *
+ * @return The chat's topic.
+ */
+const char *purple_chat_conversation_get_topic(const PurpleChatConversation *chat);
+
+/**
+ * Sets the chat room's ID.
+ *
+ * @param chat The chat.
+ * @param id   The ID.
+ */
+void purple_chat_conversation_set_id(PurpleChatConversation *chat, int id);
+
+/**
+ * Returns the chat room's ID.
+ *
+ * @param chat The chat.
+ *
+ * @return The ID.
+ */
+int purple_chat_conversation_get_id(const PurpleChatConversation *chat);
+
+/** TODO override
+ * Writes to a chat.
+ *
+ * @param chat    The chat.
+ * @param who     The user who sent the message.
+ * @param message The message to write.
+ * @param flags   The flags.
+ * @param mtime   The time the message was sent.
+ */
+/*void purple_chat_conversation_write(PurpleChatConversation *chat, const char *who,
+						  const char *message, PurpleConversationMessageFlags flags,
+						  time_t mtime);*/
+
+/** TODO write forward
+ * Sends a message to this chat conversation.
+ *
+ * @param chat    The chat.
+ * @param message The message to send.
+ */
+/*void purple_chat_conversation_send(PurpleChatConversation *chat, const char *message);*/
+
+/** TODO override
+ * Sends a message to this chat conversation with specified flags.
+ *
+ * @param chat    The chat.
+ * @param message The message to send.
+ * @param flags   The PurpleConversationMessageFlags flags to use.
+ */
+/*void purple_chat_conversation_send_with_flags(PurpleChatConversation *chat,
+		const char *message, PurpleConversationMessageFlags flags);*/
+
+/**
+ * Adds a user to a chat.
+ *
+ * @param chat        The chat.
+ * @param user        The user to add.
+ * @param extra_msg   An extra message to display with the join message.
+ * @param flags       The users flags
+ * @param new_arrival Decides whether or not to show a join notice.
+ */
+void purple_chat_conversation_add_user(PurpleChatConversation *chat, const char *user,
+							 const char *extra_msg, PurpleChatConversationBuddyFlags flags,
+							 gboolean new_arrival);
+
+/**
+ * Adds a list of users to a chat.
+ *
+ * The data is copied from @a users, @a extra_msgs, and @a flags, so it is up to
+ * the caller to free this list after calling this function.
+ *
+ * @param chat         The chat.
+ * @param users        The list of users to add.
+ * @param extra_msgs   An extra message to display with the join message for each
+ *                     user.  This list may be shorter than @a users, in which
+ *                     case, the users after the end of extra_msgs will not have
+ *                     an extra message.  By extension, this means that extra_msgs
+ *                     can simply be @c NULL and none of the users will have an
+ *                     extra message.
+ * @param flags        The list of flags for each user.
+ * @param new_arrivals Decides whether or not to show join notices.
+ */
+void purple_chat_conversation_add_users(PurpleChatConversation *chat,
+		GList *users, GList *extra_msgs, GList *flags, gboolean new_arrivals);
+
+/**
+ * Renames a user in a chat.
+ *
+ * @param chat     The chat.
+ * @param old_user The old username.
+ * @param new_user The new username.
+ */
+void purple_chat_conversation_rename_user(PurpleChatConversation *chat,
+		const char *old_user, const char *new_user);
+
+/**
+ * Removes a user from a chat, optionally with a reason.
+ *
+ * It is up to the developer to free this list after calling this function.
+ *
+ * @param chat   The chat.
+ * @param user   The user that is being removed.
+ * @param reason The optional reason given for the removal. Can be @c NULL.
+ */
+void purple_chat_conversation_remove_user(PurpleChatConversation *chat,
+		const char *user, const char *reason);
+
+/**
+ * Removes a list of users from a chat, optionally with a single reason.
+ *
+ * @param chat   The chat.
+ * @param users  The users that are being removed.
+ * @param reason The optional reason given for the removal. Can be @c NULL.
+ */
+void purple_chat_conversation_remove_users(PurpleChatConversation *chat,
+		GList *users, const char *reason);
+
+/**
+ * Finds a user in a chat
+ *
+ * @param chat   The chat.
+ * @param user   The user to look for.
+ *
+ * @return TRUE if the user is in the chat, FALSE if not
+ */
+gboolean purple_chat_conversation_find_user(PurpleChatConversation *chat,
+		const char *user);
+
+/**
+ * Set a users flags in a chat
+ *
+ * @param chat   The chat.
+ * @param user   The user to update.
+ * @param flags  The new flags.
+ */
+void purple_chat_conversation_user_set_flags(PurpleChatConversation *chat,
+		const char *user, PurpleChatConversationBuddyFlags flags);
+
+/**
+ * Get the flags for a user in a chat
+ *
+ * @param chat   The chat.
+ * @param user   The user to find the flags for
+ *
+ * @return The flags for the user
+ */
+PurpleChatConversationBuddyFlags purple_chat_conversation_user_get_flags(PurpleChatConversation *chat,
+													 const char *user);
+
+/**
+ * Clears all users from a chat.
+ *
+ * @param chat The chat.
+ */
+void purple_chat_conversation_clear_users(PurpleChatConversation *chat);
+
+/**
+ * Sets your nickname (used for hilighting) for a chat.
+ *
+ * @param chat The chat.
+ * @param nick The nick.
+ */
+void purple_chat_conversation_set_nick(PurpleChatConversation *chat,
+		const char *nick);
+
+/**
+ * Gets your nickname (used for hilighting) for a chat.
+ *
+ * @param chat The chat.
+ * @return  The nick.
+ */
+const char *purple_chat_conversation_get_nick(PurpleChatConversation *chat);
+
+/**
+ * Lets the core know we left a chat, without destroying it.
+ * Called from serv_got_chat_left().
+ *
+ * @param chat The chat.
+ */
+void purple_chat_conversation_leave(PurpleChatConversation *chat);
+
+/**
+ * Find a chat buddy in a chat
+ *
+ * @param chat The chat.
+ * @param name The name of the chat buddy to find.
+ */
+PurpleChatConversationBuddy *purple_chat_conversation_find_buddy(PurpleChatConversation *chat, const char *name);
+
+/**
+ * Invite a user to a chat.
+ * The user will be prompted to enter the user's name or a message if one is
+ * not given.
+ *
+ * @param chat     The chat.
+ * @param user     The user to invite to the chat.
+ * @param message  The message to send with the invitation.
+ * @param confirm  Prompt before sending the invitation. The user is always
+ *                 prompted if either \a user or \a message is @c NULL.
+ */
+void purple_chat_conversation_invite_user(PurpleChatConversation *chat,
+		const char *user, const char *message, gboolean confirm);
+
+/**
+ * Returns true if we're no longer in this chat,
+ * and just left the window open.
+ *
+ * @param chat The chat.
+ *
+ * @return @c TRUE if we left the chat already, @c FALSE if
+ * we're still there.
+ */
+gboolean purple_chat_conversation_has_left(PurpleChatConversation *chat);
+
+/*@}*/
+
+/**************************************************************************/
+/** @name Chat Conversation Buddy API                                     */
+/**************************************************************************/
+/*@{*/
+
+/** TODO
+ * Returns the GType for the ChatConversationBuddy object.
+ */
+GType purple_chat_conversation_buddy_get_type(void);
+
+/**
+ * Get an attribute of a chat buddy
+ *
+ * @param cb	The chat buddy.
+ * @param key	The key of the attribute.
+ *
+ * @return The value of the attribute key.
+ */
+const char *purple_chat_conversation_buddy_get_attribute(PurpleChatConversationBuddy *cb, const char *key);
+
+/**
+ * Get the keys of all atributes of a chat buddy
+ *
+ * @param cb	The chat buddy.
+ *
+ * @return A list of the attributes of a chat buddy.
+ */
+GList *purple_chat_conversation_buddy_get_attribute_keys(PurpleChatConversationBuddy *cb);
+	
+/**
+ * Set an attribute of a chat buddy
+ *
+ * @param chat	The chat.
+ * @param cb	The chat buddy.
+ * @param key	The key of the attribute.
+ * @param value	The value of the attribute.
+ */
+void purple_chat_conversation_buddy_set_attribute(PurpleChatConversation *chat,
+		PurpleChatConversationBuddy *cb, const char *key, const char *value);
+
+/**
+ * Set attributes of a chat buddy
+ *
+ * @param chat	The chat.
+ * @param cb	The chat buddy.
+ * @param keys	A GList of the keys.
+ * @param values A GList of the values.
+ */
+void
+purple_chat_conversation_buddy_set_attributes(PurpleChatConversation *chat,
+		PurpleChatConversationBuddy *cb, GList *keys, GList *values);
+
+/** TODO GObjectify
+ * Creates a new chat buddy
+ *
+ * @param name The name.
+ * @param alias The alias.
+ * @param flags The flags.
+ *
+ * @return The new chat buddy
+ */
+PurpleChatConversationBuddy *purple_chat_conversation_buddy_new(const char *name,
+		const char *alias, PurpleChatConversationBuddyFlags flags);
+
+/**
+ * Set the UI data associated with this chat buddy.
+ *
+ * @param cb			The chat buddy
+ * @param ui_data		A pointer to associate with this chat buddy.
+ */
+void purple_chat_conversation_buddy_set_ui_data(PurpleChatConversationBuddy *cb, gpointer ui_data);
+
+/**
+ * Get the UI data associated with this chat buddy.
+ *
+ * @param cb			The chat buddy.
+ *
+ * @return The UI data associated with this chat buddy.  This is a
+ *         convenience field provided to the UIs--it is not
+ *         used by the libpurple core.
+ */
+gpointer purple_chat_conversation_buddy_get_ui_data(const PurpleChatConversationBuddy *cb);
+
+/**
+ * Get the alias of a chat buddy
+ *
+ * @param cb    The chat buddy.
+ *
+ * @return The alias of the chat buddy.
+ */
+const char *purple_chat_conversation_buddy_get_alias(const PurpleChatConversationBuddy *cb);
+
+/**
+ * Get the name of a chat buddy
+ *
+ * @param cb    The chat buddy.
+ *
+ * @return The name of the chat buddy.
+ */
+const char *purple_chat_conversation_buddy_get_name(const PurpleChatConversationBuddy *cb);
+
+/**
+ * Get the flags of a chat buddy.
+ *
+ * @param cb	The chat buddy.
+ *
+ * @return The flags of the chat buddy.
+ */
+PurpleChatConversationBuddyFlags purple_chat_conversation_buddy_get_flags(const PurpleChatConversationBuddy *cb);
+
+/**
+ * Indicates if this chat buddy is on the buddy list.
+ *
+ * @param cb	The chat buddy.
+ *
+ * @return TRUE if the chat buddy is on the buddy list.
+ */
+gboolean purple_chat_conversation_buddy_is_buddy(const PurpleChatConversationBuddy *cb);
+
+/** TODO finalize/dispose
+ * Destroys a chat buddy
+ *
+ * @param cb The chat buddy to destroy
+ */
+void purple_chat_conversation_buddy_destroy(PurpleChatConversationBuddy *cb);
+
+/*@}*/
+
+G_END_DECLS
+
+#endif /* _PURPLE_CONVERSATION_TYPES_H_ */
--- a/libpurple/core.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/core.c	Sun Jun 23 13:35:53 2013 +0530
@@ -43,7 +43,6 @@
 #include "plugin.h"
 #include "pounce.h"
 #include "prefs.h"
-#include "privacy.h"
 #include "proxy.h"
 #include "savedstatuses.h"
 #include "signals.h"
@@ -139,7 +138,6 @@
 	purple_dbus_init();
 #endif
 
-	purple_ciphers_init();
 	purple_cmds_init();
 
 	/* Since plugins get probed so early we should probably initialize their
@@ -173,7 +171,6 @@
 	purple_blist_init();
 	purple_log_init();
 	purple_network_init();
-	purple_privacy_init();
 	purple_pounces_init();
 	purple_proxy_init();
 	purple_dnsquery_init();
@@ -240,7 +237,6 @@
 	purple_idle_uninit();
 	purple_pounces_uninit();
 	purple_blist_uninit();
-	purple_ciphers_uninit();
 	purple_notify_uninit();
 	purple_conversations_uninit();
 	purple_connections_uninit();
--- a/libpurple/dbus-useful.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/dbus-useful.c	Sun Jun 23 13:35:53 2013 +0530
@@ -2,6 +2,7 @@
 #include <glib.h>
 
 #include "dbus-useful.h"
+#include "accounts.h"
 #include "conversation.h"
 #include "util.h"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/enums.c.template	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,64 @@
+/*** BEGIN file-header ***/
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "enums.h"
+
+/*** END file-header ***/
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+#include "@filename@"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+@enum_name@_get_type(void) {
+    static volatile gsize g_define_type_id__volatile = 0;
+
+    if(g_once_init_enter(&g_define_type_id__volatile)) {
+        static const G@Type@Value values [] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+            { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+            { 0, NULL, NULL }
+        };
+
+        GType g_define_type_id =
+            g_@type@_register_static(g_intern_static_string("@EnumName@"), values);
+        g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
+    }
+
+    return g_define_type_id__volatile;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+/*** END file-tail ***/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/enums.h.template	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,45 @@
+/*** BEGIN file-header ***/
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_ENUM_H
+#define PURPLE_ENUM_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type(void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* PURPLE_ENUM_H */
+
+/*** END file-tail ***/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/hash.c	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,268 @@
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+#include "hash.h"
+#include "debug.h"
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_hash_class_init(PurpleHashClass *klass) {
+	klass->reset = NULL;
+	klass->reset_state = NULL;
+	klass->append = NULL;
+	klass->digest = NULL;
+	klass->get_digest_size = NULL;
+	klass->get_block_size = NULL;
+	klass->get_name = NULL;
+}
+
+/******************************************************************************
+ * PurpleHash API
+ *****************************************************************************/
+const gchar *
+purple_hash_get_name(PurpleHash *hash) {
+	PurpleHashClass *klass = NULL;
+
+	g_return_val_if_fail(hash, NULL);
+	g_return_val_if_fail(PURPLE_IS_HASH(hash), NULL);
+
+	klass = PURPLE_HASH_GET_CLASS(hash);
+	g_return_val_if_fail(klass->get_name, NULL);
+
+	return klass->get_name(hash);
+}
+
+GType
+purple_hash_get_type(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleHashClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_hash_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleHash),
+			0,
+			NULL,
+			NULL
+		};
+
+		type = g_type_register_static(G_TYPE_OBJECT,
+									  "PurpleHash",
+									  &info, G_TYPE_FLAG_ABSTRACT);
+	}
+
+	return type;
+}
+
+/**
+ * purple_hash_reset:
+ * @hash: The hash to reset
+ *
+ * Resets a hash to it's default value
+ *
+ * @note If you have set an IV you will have to set it after resetting
+ */
+void
+purple_hash_reset(PurpleHash *hash) {
+	PurpleHashClass *klass = NULL;
+
+	g_return_if_fail(PURPLE_IS_HASH(hash));
+
+	klass = PURPLE_HASH_GET_CLASS(hash);
+
+	if(klass && klass->reset)
+		klass->reset(hash);
+	else
+		purple_debug_warning("hash", "the %s hash does not implement the "
+						"reset method\n",
+						klass->get_name ? klass->get_name(hash) : "");
+}
+
+/**
+ * Resets a hash state to it's default value, but doesn't touch stateless
+ * configuration.
+ *
+ * That means, IV and digest context will be wiped out, but keys, ops or salt
+ * will remain untouched.
+ */
+void
+purple_hash_reset_state(PurpleHash *hash) {
+	PurpleHashClass *klass = NULL;
+
+	g_return_if_fail(PURPLE_IS_HASH(hash));
+
+	klass = PURPLE_HASH_GET_CLASS(hash);
+
+	if(klass && klass->reset_state)
+		klass->reset_state(hash);
+	else
+		purple_debug_warning("hash", "the %s hash does not implement the "
+						"reset_state method\n",
+						klass->get_name ? klass->get_name(hash) : "");
+}
+
+/**
+ * purple_hash_append:
+ * @hash: The hash to append data to
+ * @data: The data to append
+ * @len: The length of the data
+ *
+ * Appends data to the hash
+ */
+void
+purple_hash_append(PurpleHash *hash, const guchar *data,
+								size_t len)
+{
+	PurpleHashClass *klass = NULL;
+
+	g_return_if_fail(PURPLE_IS_HASH(hash));
+
+	klass = PURPLE_HASH_GET_CLASS(hash);
+
+	if(klass && klass->append)
+		klass->append(hash, data, len);
+	else
+		purple_debug_warning("hash", "the %s hash does not implement the "
+						"append method\n",
+						klass->get_name ? klass->get_name(hash) : "");
+}
+
+/**
+ * purple_hash_digest:
+ * @hash: The hash to digest
+ * @in_len: The length of the buffer
+ * @digest: The return buffer for the digest
+ * @out_len: The length of the returned value
+ *
+ * Digests a hash
+ *
+ * Return Value: TRUE if the digest was successful, FALSE otherwise.
+ */
+gboolean
+purple_hash_digest(PurpleHash *hash, guchar digest[], size_t len)
+{
+	PurpleHashClass *klass = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_HASH(hash), FALSE);
+
+	klass = PURPLE_HASH_GET_CLASS(hash);
+
+	if(klass && klass->digest)
+		return klass->digest(hash, digest, len);
+	else
+		purple_debug_warning("hash", "the %s hash does not implement the "
+						"digest method\n",
+						klass->get_name ? klass->get_name(hash) : "");
+
+	return FALSE;
+}
+
+/**
+ * purple_hash_digest_to_str:
+ * @hash: The hash to get a digest from
+ * @in_len: The length of the buffer
+ * @digest_s: The return buffer for the string digest
+ * @out_len: The length of the returned value
+ *
+ * Converts a guchar digest into a hex string
+ *
+ * Return Value: TRUE if the digest was successful, FALSE otherwise.
+ */
+gboolean
+purple_hash_digest_to_str(PurpleHash *hash, gchar digest_s[], size_t len)
+{
+	/* 8k is a bit excessive, will tweak later. */
+	guchar digest[BUF_LEN * 4];
+	gint n = 0;
+	size_t digest_size;
+
+	g_return_val_if_fail(hash, FALSE);
+	g_return_val_if_fail(digest_s, FALSE);
+
+	digest_size = purple_hash_get_digest_size(hash);
+
+	g_return_val_if_fail(digest_size <= BUF_LEN * 4, FALSE);
+
+	if(!purple_hash_digest(hash, digest, sizeof(digest)))
+		return FALSE;
+
+	/* Every digest byte occupies 2 chars + the NUL at the end. */
+	g_return_val_if_fail(digest_size * 2 + 1 <= len, FALSE);
+
+	for(n = 0; n < digest_size; n++)
+		sprintf(digest_s + (n * 2), "%02x", digest[n]);
+
+	digest_s[n * 2] = '\0';
+
+	return TRUE;
+}
+
+size_t
+purple_hash_get_digest_size(PurpleHash *hash)
+{
+	PurpleHashClass *klass = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_HASH(hash), FALSE);
+
+	klass = PURPLE_HASH_GET_CLASS(hash);
+
+	if(klass && klass->get_digest_size)
+		return klass->get_digest_size(hash);
+	else
+		purple_debug_warning("hash", "the %s hash does not implement the "
+						"get_digest_size method\n",
+						klass->get_name ? klass->get_name(hash) : "");
+
+	return FALSE;
+}
+
+/**
+ * purple_hash_get_block_size:
+ * @hash: The hash whose block size to get
+ *
+ * Gets the block size of a hash
+ *
+ * Return Value: The block size of the hash
+ */
+size_t
+purple_hash_get_block_size(PurpleHash *hash)
+{
+	PurpleHashClass *klass = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_HASH(hash), -1);
+
+	klass = PURPLE_HASH_GET_CLASS(hash);
+
+	if(klass && klass->get_block_size)
+		return klass->get_block_size(hash);
+	else
+		purple_debug_warning("hash", "the %s hash does not implement the "
+						"get_block_size method\n",
+						klass->get_name ? klass->get_name(hash) : "");
+
+	return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/hash.h	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,115 @@
+/**
+ * @file hash.h Purple Hash API
+ * @ingroup core
+ * @see @ref hash-signals
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef PURPLE_HASH_H
+#define PURPLE_HASH_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <string.h>
+
+#include "internal.h"
+
+#define PURPLE_TYPE_HASH				(purple_hash_get_type())
+#define PURPLE_HASH(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_HASH, PurpleHash))
+#define PURPLE_HASH_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_HASH, PurpleHashClass))
+#define PURPLE_IS_HASH(obj)				(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_HASH))
+#define PURPLE_IS_HASH_CLASS(klass)		(G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_HASH))
+#define PURPLE_HASH_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_HASH, PurpleHashClass))
+
+typedef struct _PurpleHash       		PurpleHash;
+typedef struct _PurpleHashClass  		PurpleHashClass;
+
+/**
+ * PurpleHash:
+ *
+ * Purple Hash is an opaque data structure and should not be used directly.
+ */
+struct _PurpleHash {
+	/*< private >*/
+	GObject gparent;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+/**
+ * PurpleHashClass:
+ *
+ * The base class for all #PurpleHash's.
+ */
+struct _PurpleHashClass {
+	/*< private >*/
+	GObjectClass parent_class;
+
+	/** The reset function */
+	void (*reset)(PurpleHash *hash);
+
+	/** The reset state function */
+	void (*reset_state)(PurpleHash *hash);
+
+	/** The append data function */
+	void (*append)(PurpleHash *hash, const guchar *data, size_t len);
+
+	/** The digest function */
+	gboolean (*digest)(PurpleHash *hash, guchar digest[], size_t len);
+
+	/** The get digest size function */
+	size_t (*get_digest_size)(PurpleHash *hash);
+
+	/** The get block size function */
+	size_t (*get_block_size)(PurpleHash *hash);
+
+	/** The get hash name function */
+	const gchar* (*get_name)(PurpleHash *hash);
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType purple_hash_get_type(void);
+
+const gchar *purple_hash_get_name(PurpleHash *hash);
+
+void purple_hash_reset(PurpleHash *hash);
+void purple_hash_reset_state(PurpleHash *hash);
+
+void purple_hash_append(PurpleHash *hash, const guchar *data, size_t len);
+gboolean purple_hash_digest(PurpleHash *hash, guchar digest[], size_t len);
+gboolean purple_hash_digest_to_str(PurpleHash *hash, gchar digest_s[], size_t len);
+size_t purple_hash_get_digest_size(PurpleHash *hash);
+
+size_t purple_hash_get_block_size(PurpleHash *hash);
+
+G_END_DECLS
+
+#endif /* PURPLE_HASH_H */
--- a/libpurple/internal.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/internal.h	Sun Jun 23 13:35:53 2013 +0530
@@ -156,7 +156,7 @@
 
 /* INTERNAL FUNCTIONS */
 
-#include "account.h"
+#include "accounts.h"
 #include "connection.h"
 
 /* This is for the accounts code to notify the buddy icon code that
--- a/libpurple/log.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/log.h	Sun Jun 23 13:35:53 2013 +0530
@@ -70,7 +70,7 @@
 
 	/** This is used to write to the log file */
 	gsize (*write)(PurpleLog *log,
-		     PurpleMessageFlags type,
+		     PurpleConversationMessageFlags type,
 		     const char *from,
 		     time_t time,
 		     const char *message);
@@ -222,7 +222,7 @@
  * @param message      The message to log
  */
 void purple_log_write(PurpleLog *log,
-		    PurpleMessageFlags type,
+		    PurpleConversationMessageFlags type,
 		    const char *from,
 		    time_t time,
 		    const char *message);
--- a/libpurple/media.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/media.c	Sun Jun 23 13:35:53 2013 +0530
@@ -44,23 +44,6 @@
 typedef struct _PurpleMediaSession PurpleMediaSession;
 /** @copydoc _PurpleMediaStream */
 typedef struct _PurpleMediaStream PurpleMediaStream;
-/** @copydoc _PurpleMediaClass */
-typedef struct _PurpleMediaClass PurpleMediaClass;
-/** @copydoc _PurpleMediaPrivate */
-typedef struct _PurpleMediaPrivate PurpleMediaPrivate;
-
-/** The media class */
-struct _PurpleMediaClass
-{
-	GObjectClass parent_class;     /**< The parent class. */
-};
-
-/** The media class's private data */
-struct _PurpleMedia
-{
-	GObject parent;                /**< The parent of this object. */
-	PurpleMediaPrivate *priv;      /**< The private data of this object. */
-};
 
 struct _PurpleMediaSession
 {
--- a/libpurple/media.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/media.h	Sun Jun 23 13:35:53 2013 +0530
@@ -41,12 +41,44 @@
 #define PURPLE_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA))
 #define PURPLE_MEDIA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA, PurpleMediaClass))
 
-/** An opaque structure representing a media call. */
+/** A structure representing a media call. */
 typedef struct _PurpleMedia PurpleMedia;
 
 #include "signals.h"
 #include "util.h"
 
+#ifdef USE_VV
+
+/** @copydoc _PurpleMediaClass */
+typedef struct _PurpleMediaClass    PurpleMediaClass;
+/** @copydoc _PurpleMediaPrivate */
+typedef struct _PurpleMediaPrivate  PurpleMediaPrivate;
+
+/** The media instance */
+struct _PurpleMedia
+{
+	GObject parent;                /**< The parent of this object. */
+	PurpleMediaPrivate *priv;      /**< The private data of this object. */
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
+};
+
+/** The media class */
+struct _PurpleMediaClass
+{
+	GObjectClass parent_class;     /**< The parent class. */
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
+};
+
+#endif
+
 G_BEGIN_DECLS
 
 /**
--- a/libpurple/ntlm.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/ntlm.c	Sun Jun 23 13:35:53 2013 +0530
@@ -28,8 +28,11 @@
 
 #include "util.h"
 #include "ntlm.h"
-#include "cipher.h"
 #include "debug.h"
+
+#include "ciphers/descipher.h"
+#include "ciphers/md4hash.h"
+
 #include <string.h>
 
 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
@@ -191,13 +194,11 @@
 des_ecb_encrypt(const guint8 *plaintext, guint8 *result, const guint8 *key)
 {
 	PurpleCipher *cipher;
-	PurpleCipherContext *context;
 
-	cipher = purple_ciphers_find_cipher("des");
-	context = purple_cipher_context_new(cipher, NULL);
-	purple_cipher_context_set_key(context, key, 8);
-	purple_cipher_context_encrypt(context, plaintext, 8, result, 8);
-	purple_cipher_context_destroy(context);
+	cipher = purple_des_cipher_new();
+	purple_cipher_set_key(cipher, key, 8);
+	purple_cipher_encrypt(cipher, plaintext, 8, result, 8);
+	g_object_unref(cipher);
 }
 
 /*
@@ -273,8 +274,7 @@
 	unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
 	unsigned char nt_hpw[21];
 	char nt_pw[128];
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
+	PurpleHash *hash;
 	char *tmp;
 	int idx;
 	gchar *ucs2le;
@@ -375,11 +375,10 @@
 		nt_pw[2 * idx + 1] = 0;
 	}
 
-	cipher = purple_ciphers_find_cipher("md4");
-	context = purple_cipher_context_new(cipher, NULL);
-	purple_cipher_context_append(context, (guint8 *)nt_pw, 2 * lennt);
-	purple_cipher_context_digest(context, nt_hpw, sizeof(nt_hpw));
-	purple_cipher_context_destroy(context);
+	hash = purple_md4_hash_new();
+	purple_hash_append(hash, (guint8 *)nt_pw, 2 * lennt);
+	purple_hash_digest(hash, nt_hpw, sizeof(nt_hpw));
+	g_object_unref(hash);
 
 	memset(nt_hpw + 16, 0, 5);
 	calc_resp(nt_hpw, nonce, nt_resp);
--- a/libpurple/plugins/ciphertest.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/ciphertest.c	Sun Jun 23 13:35:53 2013 +0530
@@ -32,10 +32,16 @@
 #include <glib.h>
 #include <string.h>
 
-#include "cipher.h"
 #include "debug.h"
 #include "plugin.h"
 #include "version.h"
+#include "util.h"
+
+#include "ciphers/aescipher.h"
+#include "ciphers/md5hash.h"
+#include "ciphers/pbkdf2cipher.h"
+#include "ciphers/sha1hash.h"
+#include "ciphers/sha256hash.h"
 
 struct test {
 	const gchar *question;
@@ -62,14 +68,13 @@
 
 static void
 cipher_test_md5(void) {
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
+	PurpleHash *hash;
 	gchar digest[33];
 	gboolean ret;
 	gint i = 0;
 
-	cipher = purple_ciphers_find_cipher("md5");
-	if(!cipher) {
+	hash = purple_md5_hash_new();
+	if(!hash) {
 		purple_debug_info("cipher-test",
 						"could not find md5 cipher, not testing\n");
 		return;
@@ -77,16 +82,14 @@
 
 	purple_debug_info("cipher-test", "Running md5 tests\n");
 
-	context = purple_cipher_context_new(cipher, NULL);
-
 	while(md5_tests[i].answer) {
 		purple_debug_info("cipher-test", "Test %02d:\n", i);
 		purple_debug_info("cipher-test", "Testing '%s'\n", md5_tests[i].question);
 
-		purple_cipher_context_append(context, (guchar *)md5_tests[i].question,
+		purple_hash_append(hash, (guchar *)md5_tests[i].question,
 								   strlen(md5_tests[i].question));
 
-		ret = purple_cipher_context_digest_to_str(context, digest, sizeof(digest));
+		ret = purple_hash_digest_to_str(hash, digest, sizeof(digest));
 
 		if(!ret) {
 			purple_debug_info("cipher-test", "failed\n");
@@ -96,11 +99,11 @@
 							md5_tests[i].answer);
 		}
 
-		purple_cipher_context_reset(context, NULL);
+		purple_hash_reset(hash);
 		i++;
 	}
 
-	purple_cipher_context_destroy(context);
+	g_object_unref(hash);
 
 	purple_debug_info("cipher-test", "md5 tests completed\n\n");
 }
@@ -118,14 +121,13 @@
 
 static void
 cipher_test_sha1(void) {
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
+	PurpleHash *hash;
 	gchar digest[41];
 	gint i = 0;
 	gboolean ret;
 
-	cipher = purple_ciphers_find_cipher("sha1");
-	if(!cipher) {
+	hash = purple_sha1_hash_new();
+	if(!hash) {
 		purple_debug_info("cipher-test",
 						"could not find sha1 cipher, not testing\n");
 		return;
@@ -133,8 +135,6 @@
 
 	purple_debug_info("cipher-test", "Running sha1 tests\n");
 
-	context = purple_cipher_context_new(cipher, NULL);
-
 	while(sha1_tests[i].answer) {
 		purple_debug_info("cipher-test", "Test %02d:\n", i);
 		purple_debug_info("cipher-test", "Testing '%s'\n",
@@ -142,7 +142,7 @@
 						sha1_tests[i].question : "'a'x1000, 1000 times");
 
 		if(sha1_tests[i].question) {
-			purple_cipher_context_append(context, (guchar *)sha1_tests[i].question,
+			purple_hash_append(hash, (guchar *)sha1_tests[i].question,
 									   strlen(sha1_tests[i].question));
 		} else {
 			gint j;
@@ -151,10 +151,10 @@
 			memset(buff, 'a', 1000);
 
 			for(j = 0; j < 1000; j++)
-				purple_cipher_context_append(context, buff, 1000);
+				purple_hash_append(hash, buff, 1000);
 		}
 
-		ret = purple_cipher_context_digest_to_str(context, digest, sizeof(digest));
+		ret = purple_hash_digest_to_str(hash, digest, sizeof(digest));
 
 		if(!ret) {
 			purple_debug_info("cipher-test", "failed\n");
@@ -164,11 +164,11 @@
 							sha1_tests[i].answer);
 		}
 
-		purple_cipher_context_reset(context, NULL);
+		purple_hash_reset(hash);
 		i++;
 	}
 
-	purple_cipher_context_destroy(context);
+	g_object_unref(hash);
 
 	purple_debug_info("cipher-test", "sha1 tests completed\n\n");
 }
@@ -192,7 +192,7 @@
 
 	purple_debug_info("cipher-test", "Running HTTP Digest tests\n");
 
-	session_key = purple_cipher_http_digest_calculate_session_key(
+	session_key = purple_http_digest_calculate_session_key(
 						algorithm, username, realm, password,
 						nonce, client_nonce);
 
@@ -208,7 +208,7 @@
 		purple_debug_info("cipher-test", "\tsession_key: Got:    %s\n", session_key);
 		purple_debug_info("cipher-test", "\tsession_key: Wanted: %s\n", "939e7578ed9e3c518a452acee763bce9");
 
-		response = purple_cipher_http_digest_calculate_response(
+		response = purple_http_digest_calculate_response(
 				algorithm, method, digest_uri, qop, entity,
 				nonce, nonce_count, client_nonce, session_key);
 
@@ -362,14 +362,13 @@
 static void
 cipher_test_pbkdf2(void)
 {
-	PurpleCipherContext *context;
+	PurpleCipher *cipher;
+	PurpleHash *hash;
 	int i = 0;
 	gboolean fail = FALSE;
 
 	purple_debug_info("cipher-test", "Running PBKDF2 tests\n");
 
-	context = purple_cipher_context_new_by_name("pbkdf2", NULL);
-
 	while (!fail && pbkdf2_tests[i].answer) {
 		pbkdf2_test *test = &pbkdf2_tests[i];
 		gchar digest[2 * 32 + 1 + 10];
@@ -384,18 +383,28 @@
 			test->passphrase, test->salt, test->hash,
 			test->iter_count);
 
-		purple_cipher_context_set_option(context, "hash", (gpointer)test->hash);
-		purple_cipher_context_set_option(context, "iter_count", GUINT_TO_POINTER(test->iter_count));
-		purple_cipher_context_set_option(context, "out_len", GUINT_TO_POINTER(test->out_len));
-		purple_cipher_context_set_salt(context, (const guchar*)test->salt, test->salt ? strlen(test->salt): 0);
-		purple_cipher_context_set_key(context, (const guchar*)test->passphrase, strlen(test->passphrase));
+		if (!strcmp(test->hash, "sha1"))
+			hash = purple_sha1_hash_new();
+		else if (!strcmp(test->hash, "sha256"))
+			hash = purple_sha256_hash_new();
+		else
+			hash = NULL;
 
-		ret = purple_cipher_context_digest_to_str(context, digest, sizeof(digest));
-		purple_cipher_context_reset(context, NULL);
+		cipher = purple_pbkdf2_cipher_new(hash);
+
+		g_object_set(G_OBJECT(cipher), "iter_count", GUINT_TO_POINTER(test->iter_count), NULL);
+		g_object_set(G_OBJECT(cipher), "out_len", GUINT_TO_POINTER(test->out_len), NULL);
+		purple_cipher_set_salt(cipher, (const guchar*)test->salt, test->salt ? strlen(test->salt): 0);
+		purple_cipher_set_key(cipher, (const guchar*)test->passphrase, strlen(test->passphrase));
+
+		ret = purple_cipher_digest_to_str(cipher, digest, sizeof(digest));
+		purple_cipher_reset(cipher);
 
 		if (!ret) {
 			purple_debug_info("cipher-test", "\tfailed\n");
 			fail = TRUE;
+			g_object_unref(cipher);
+			g_object_unref(hash);
 			continue;
 		}
 
@@ -431,10 +440,11 @@
 			purple_debug_info("cipher-test", "\twrong answer\n");
 			fail = TRUE;
 		}
+
+		g_object_unref(cipher);
+		g_object_unref(hash);
 	}
 
-	purple_cipher_context_destroy(context);
-
 	if (fail)
 		purple_debug_info("cipher-test", "PBKDF2 tests FAILED\n\n");
 	else
@@ -466,14 +476,14 @@
 static void
 cipher_test_aes(void)
 {
-	PurpleCipherContext *context;
+	PurpleCipher *cipher;
 	int i = 0;
 	gboolean fail = FALSE;
 
 	purple_debug_info("cipher-test", "Running AES tests\n");
 
-	context = purple_cipher_context_new_by_name("aes", NULL);
-	if (context == NULL) {
+	cipher = purple_aes_cipher_new();
+	if (cipher == NULL) {
 		purple_debug_error("cipher-test", "AES cipher not found\n");
 		fail = TRUE;
 	}
@@ -482,49 +492,49 @@
 		aes_test *test = &aes_tests[i];
 		gsize key_size;
 		guchar *key;
-		guchar cipher[1024], decipher[1024];
+		guchar cipher_s[1024], decipher_s[1024];
 		ssize_t cipher_len, decipher_len;
 		gchar *cipher_b16, *deciphered;
 
 		purple_debug_info("cipher-test", "Test %02d:\n", i);
-		purple_debug_info("cipher-test", "\tTesting '%s' (%dbit) \n",
+		purple_debug_info("cipher-test", "\tTesting '%s' (%lubit) \n",
 			test->plaintext ? test->plaintext : "(null)",
 			strlen(test->key) * 8 / 2);
 
 		i++;
 
-		purple_cipher_context_reset(context, NULL);
+		purple_cipher_reset(cipher);
 
 		if (test->iv) {
 			gsize iv_size;
 			guchar *iv = purple_base16_decode(test->iv, &iv_size);
 			g_assert(iv != NULL);
-			purple_cipher_context_set_iv(context, iv, iv_size);
+			purple_cipher_set_iv(cipher, iv, iv_size);
 			g_free(iv);
 		}
 
 		key = purple_base16_decode(test->key, &key_size);
 		g_assert(key != NULL);
-		purple_cipher_context_set_key(context, key, key_size);
+		purple_cipher_set_key(cipher, key, key_size);
 		g_free(key);
 
-		if (purple_cipher_context_get_key_size(context) != key_size) {
+		if (purple_cipher_get_key_size(cipher) != key_size) {
 			purple_debug_info("cipher-test", "\tinvalid key size\n");
 			fail = TRUE;
 			continue;
 		}
 
-		cipher_len = purple_cipher_context_encrypt(context,
+		cipher_len = purple_cipher_encrypt(cipher,
 			(const guchar*)(test->plaintext ? test->plaintext : ""),
 			test->plaintext ? (strlen(test->plaintext) + 1) : 0,
-			cipher, sizeof(cipher));
+			cipher_s, sizeof(cipher_s));
 		if (cipher_len < 0) {
 			purple_debug_info("cipher-test", "\tencryption failed\n");
 			fail = TRUE;
 			continue;
 		}
 
-		cipher_b16 = purple_base16_encode(cipher, cipher_len);
+		cipher_b16 = purple_base16_encode(cipher_s, cipher_len);
 
 		purple_debug_info("cipher-test", "\tGot:          %s\n", cipher_b16);
 		purple_debug_info("cipher-test", "\tWanted:       %s\n", test->cipher);
@@ -538,15 +548,15 @@
 		}
 		g_free(cipher_b16);
 
-		decipher_len = purple_cipher_context_decrypt(context,
-			cipher, cipher_len, decipher, sizeof(decipher));
+		decipher_len = purple_cipher_decrypt(cipher,
+			cipher_s, cipher_len, decipher_s, sizeof(decipher_s));
 		if (decipher_len < 0) {
 			purple_debug_info("cipher-test", "\tdecryption failed\n");
 			fail = TRUE;
 			continue;
 		}
 
-		deciphered = (decipher_len > 0) ? (gchar*)decipher : NULL;
+		deciphered = (decipher_len > 0) ? (gchar*)decipher_s : NULL;
 
 		if (g_strcmp0(deciphered, test->plaintext) != 0) {
 			purple_debug_info("cipher-test",
@@ -558,8 +568,8 @@
 		purple_debug_info("cipher-test", "\tTest OK\n");
 	}
 
-	if (context != NULL)
-		purple_cipher_context_destroy(context);
+	if (cipher != NULL)
+		g_object_unref(cipher);
 
 	if (fail)
 		purple_debug_info("cipher-test", "AES tests FAILED\n\n");
--- a/libpurple/plugins/keyrings/internalkeyring.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/keyrings/internalkeyring.c	Sun Jun 23 13:35:53 2013 +0530
@@ -26,12 +26,15 @@
 
 #include "internal.h"
 #include "account.h"
-#include "cipher.h"
 #include "debug.h"
 #include "keyring.h"
 #include "plugin.h"
 #include "version.h"
 
+#include "ciphers/aescipher.h"
+#include "ciphers/pbkdf2cipher.h"
+#include "ciphers/sha256hash.h"
+
 #define INTKEYRING_NAME N_("Internal keyring")
 #define INTKEYRING_DESCRIPTION N_("This plugin provides the default password " \
 	"storage behaviour for libpurple.")
@@ -147,30 +150,31 @@
 static intkeyring_buff_t *
 intkeyring_derive_key(const gchar *passphrase, intkeyring_buff_t *salt)
 {
-	PurpleCipherContext *context;
+	PurpleCipher *cipher;
+	PurpleHash *hash;
 	gboolean succ;
 	intkeyring_buff_t *ret;
 
 	g_return_val_if_fail(passphrase != NULL, NULL);
 
-	context = purple_cipher_context_new_by_name("pbkdf2", NULL);
-	g_return_val_if_fail(context != NULL, NULL);
+	hash = purple_sha256_hash_new();
+	cipher = purple_pbkdf2_cipher_new(hash);
 
-	purple_cipher_context_set_option(context, "hash", "sha256");
-	purple_cipher_context_set_option(context, "iter_count",
+	g_object_set(G_OBJECT(cipher), "iter_count",
 		GUINT_TO_POINTER(purple_prefs_get_int(INTKEYRING_PREFS
-		"pbkdf2_iterations")));
-	purple_cipher_context_set_option(context, "out_len", GUINT_TO_POINTER(
-		INTKEYRING_KEY_LEN));
-	purple_cipher_context_set_salt(context, salt->data, salt->len);
-	purple_cipher_context_set_key(context, (const guchar*)passphrase,
+		"pbkdf2_iterations")), NULL);
+	g_object_set(G_OBJECT(cipher), "out_len", GUINT_TO_POINTER(
+		INTKEYRING_KEY_LEN), NULL);
+	purple_cipher_set_salt(cipher, salt->data, salt->len);
+	purple_cipher_set_key(cipher, (const guchar*)passphrase,
 		strlen(passphrase));
 
 	ret = intkeyring_buff_new(g_new(guchar, INTKEYRING_KEY_LEN),
 		INTKEYRING_KEY_LEN);
-	succ = purple_cipher_context_digest(context, ret->data, ret->len);
+	succ = purple_cipher_digest(cipher, ret->data, ret->len);
 
-	purple_cipher_context_destroy(context);
+	g_object_unref(cipher);
+	g_object_unref(hash);
 
 	if (!succ) {
 		intkeyring_buff_free(ret);
@@ -229,7 +233,7 @@
 static gchar *
 intkeyring_encrypt(intkeyring_buff_t *key, const gchar *str)
 {
-	PurpleCipherContext *context;
+	PurpleCipher *cipher;
 	intkeyring_buff_t *iv;
 	guchar plaintext[INTKEYRING_ENCRYPT_BUFF_LEN];
 	size_t plaintext_len, text_len, verify_len;
@@ -248,30 +252,30 @@
 	g_return_val_if_fail(plaintext_len + verify_len <= sizeof(plaintext),
 		NULL);
 
-	context = purple_cipher_context_new_by_name("aes", NULL);
-	g_return_val_if_fail(context != NULL, NULL);
+	cipher = purple_aes_cipher_new();
+	g_return_val_if_fail(cipher != NULL, NULL);
 
 	memset(plaintext, 0, plaintext_len);
 	memcpy(plaintext, str, text_len);
 	memcpy(plaintext + plaintext_len, INTKEYRING_VERIFY_STR, verify_len);
 	plaintext_len += verify_len;
 
-	iv = intkeyring_gen_salt(purple_cipher_context_get_block_size(context));
-	purple_cipher_context_set_iv(context, iv->data, iv->len);
-	purple_cipher_context_set_key(context, key->data, key->len);
-	purple_cipher_context_set_batch_mode(context,
+	iv = intkeyring_gen_salt(purple_cipher_get_block_size(cipher));
+	purple_cipher_set_iv(cipher, iv->data, iv->len);
+	purple_cipher_set_key(cipher, key->data, key->len);
+	purple_cipher_set_batch_mode(cipher,
 		PURPLE_CIPHER_BATCH_MODE_CBC);
 
 	memcpy(encrypted_raw, iv->data, iv->len);
 
-	encrypted_size = purple_cipher_context_encrypt(context,
+	encrypted_size = purple_cipher_encrypt(cipher,
 		plaintext, plaintext_len, encrypted_raw + iv->len,
 		sizeof(encrypted_raw) - iv->len);
 	encrypted_size += iv->len;
 
 	memset(plaintext, 0, plaintext_len);
 	intkeyring_buff_free(iv);
-	purple_cipher_context_destroy(context);
+	g_object_unref(cipher);
 
 	if (encrypted_size < 0)
 		return NULL;
@@ -283,7 +287,7 @@
 static gchar *
 intkeyring_decrypt(intkeyring_buff_t *key, const gchar *str)
 {
-	PurpleCipherContext *context;
+	PurpleCipher *cipher;
 	guchar *encrypted_raw;
 	gsize encrypted_size;
 	size_t iv_len, verify_len, text_len;
@@ -295,29 +299,29 @@
 	g_return_val_if_fail(key != NULL, NULL);
 	g_return_val_if_fail(str != NULL, NULL);
 
-	context = purple_cipher_context_new_by_name("aes", NULL);
-	g_return_val_if_fail(context != NULL, NULL);
+	cipher = purple_aes_cipher_new();
+	g_return_val_if_fail(cipher != NULL, NULL);
 
 	encrypted_raw = purple_base64_decode(str, &encrypted_size);
 	g_return_val_if_fail(encrypted_raw != NULL, NULL);
 
-	iv_len = purple_cipher_context_get_block_size(context);
+	iv_len = purple_cipher_get_block_size(cipher);
 	if (encrypted_size < iv_len) {
 		g_free(encrypted_raw);
 		return NULL;
 	}
 
-	purple_cipher_context_set_iv(context, encrypted_raw, iv_len);
-	purple_cipher_context_set_key(context, key->data, key->len);
-	purple_cipher_context_set_batch_mode(context,
+	purple_cipher_set_iv(cipher, encrypted_raw, iv_len);
+	purple_cipher_set_key(cipher, key->data, key->len);
+	purple_cipher_set_batch_mode(cipher,
 		PURPLE_CIPHER_BATCH_MODE_CBC);
 
-	plaintext_len = purple_cipher_context_decrypt(context,
+	plaintext_len = purple_cipher_decrypt(cipher,
 		encrypted_raw + iv_len, encrypted_size - iv_len,
 		plaintext, sizeof(plaintext));
 
 	g_free(encrypted_raw);
-	purple_cipher_context_destroy(context);
+	g_object_unref(cipher);
 
 	verify_len = strlen(INTKEYRING_VERIFY_STR);
 	/* Don't remove the len > 0 check! */
--- a/libpurple/plugins/log_reader.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/log_reader.c	Sun Jun 23 13:35:53 2013 +0530
@@ -986,7 +986,7 @@
 				if (buddy)
 					their_name = purple_buddy_get_alias(buddy);
 
-				alias = purple_account_get_alias(log->account);
+				alias = purple_account_get_private_alias(log->account);
 				if (alias) {
 					alias_length = strlen(alias);
 				} else {
@@ -1111,8 +1111,8 @@
 			text = g_string_append(text, "<b>");
 
 			if (name_guessed == NAME_GUESS_ME) {
-				if (purple_account_get_alias(log->account))
-					text = g_string_append(text, purple_account_get_alias(log->account));
+				if (purple_account_get_private_alias(log->account))
+					text = g_string_append(text, purple_account_get_private_alias(log->account));
 				else
 					text = g_string_append(text, purple_account_get_username(log->account));
 			}
@@ -1663,7 +1663,7 @@
 					const char *acct_name;
 					line2++;
 					line = line2;
-					acct_name = purple_account_get_alias(log->account);
+					acct_name = purple_account_get_private_alias(log->account);
 					if (!acct_name)
 						acct_name = purple_account_get_username(log->account);
 
@@ -2032,7 +2032,7 @@
 						}
 					} else {
 						const char *acct_name;
-						acct_name = purple_account_get_alias(log->account);
+						acct_name = purple_account_get_private_alias(log->account);
 						if (!acct_name)
 							acct_name = purple_account_get_username(log->account);
 
--- a/libpurple/plugins/perl/common/Account.xs	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/perl/common/Account.xs	Sun Jun 23 13:35:53 2013 +0530
@@ -1,6 +1,57 @@
 #include "module.h"
 #include "../perl-handlers.h"
 
+MODULE = Purple::Account  PACKAGE = Purple::Accounts  PREFIX = purple_accounts_
+PROTOTYPES: ENABLE
+
+void
+purple_accounts_add(account)
+    Purple::Account account
+
+void
+purple_accounts_remove(account)
+    Purple::Account account
+
+void
+purple_accounts_delete(account)
+    Purple::Account account
+
+void
+purple_accounts_reorder(account, new_index)
+    Purple::Account account
+    size_t new_index
+
+void
+purple_accounts_get_all()
+PREINIT:
+    GList *l;
+PPCODE:
+    for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
+        XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Account")));
+    }
+
+void
+purple_accounts_get_all_active()
+PREINIT:
+    GList *list, *iter;
+PPCODE:
+    list = purple_accounts_get_all_active();
+    for (iter = list; iter != NULL; iter = iter->next) {
+        XPUSHs(sv_2mortal(purple_perl_bless_object(iter->data, "Purple::Account")));
+    }
+    g_list_free(list);
+
+void
+purple_accounts_restore_current_statuses()
+
+Purple::Account
+purple_accounts_find(name, protocol)
+    const char * name
+    const char * protocol
+
+Purple::Handle
+purple_accounts_get_handle()
+
 MODULE = Purple::Account  PACKAGE = Purple::Account  PREFIX = purple_account_
 PROTOTYPES: ENABLE
 
@@ -16,10 +67,6 @@
     username, protocol_id
 
 void
-purple_account_destroy(account)
-    Purple::Account account
-
-void
 purple_account_connect(account)
     Purple::Account account
 
@@ -54,7 +101,7 @@
     purple_perl_account_set_password(account, password, func, data);
 
 void
-purple_account_set_alias(account, alias)
+purple_account_set_private_alias(account, alias)
     Purple::Account account
     const char * alias
 
@@ -144,7 +191,7 @@
     purple_perl_account_get_password(account, func, data);
 
 const char *
-purple_account_get_alias(account)
+purple_account_get_private_alias(account)
     Purple::Account account
 
 const char *
@@ -273,53 +320,34 @@
     Purple::Account account
     Purple::BuddyList::Group group
 
-MODULE = Purple::Account  PACKAGE = Purple::Accounts  PREFIX = purple_accounts_
+MODULE = Purple::Account  PACKAGE = Purple::Account::Privacy  PREFIX = purple_account_privacy_
 PROTOTYPES: ENABLE
 
-void
-purple_accounts_add(account)
-    Purple::Account account
-
-void
-purple_accounts_remove(account)
-    Purple::Account account
+gboolean
+purple_account_privacy_permit_add(account, name, local_only)
+	Purple::Account account
+	const char * name
+	gboolean local_only
 
-void
-purple_accounts_delete(account)
-    Purple::Account account
-
-void
-purple_accounts_reorder(account, new_index)
-    Purple::Account account
-    size_t new_index
+gboolean
+purple_account_privacy_permit_remove(account, name, local_only)
+	Purple::Account account
+	const char * name
+	gboolean local_only
 
-void
-purple_accounts_get_all()
-PREINIT:
-    GList *l;
-PPCODE:
-    for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
-        XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Account")));
-    }
+gboolean
+purple_account_privacy_deny_add(account, name, local_only)
+	Purple::Account account
+	const char * name
+	gboolean local_only
 
-void
-purple_accounts_get_all_active()
-PREINIT:
-    GList *list, *iter;
-PPCODE:
-    list = purple_accounts_get_all_active();
-    for (iter = list; iter != NULL; iter = iter->next) {
-        XPUSHs(sv_2mortal(purple_perl_bless_object(iter->data, "Purple::Account")));
-    }
-    g_list_free(list);
+gboolean
+purple_account_privacy_deny_remove(account, name, local_only)
+	Purple::Account account
+	const char * name
+	gboolean local_only
 
-void
-purple_accounts_restore_current_statuses()
-
-Purple::Account
-purple_accounts_find(name, protocol)
-    const char * name
-    const char * protocol
-
-Purple::Handle
-purple_accounts_get_handle()
+gboolean
+purple_account_privacy_check(account, who)
+	Purple::Account account
+	const char * who
--- a/libpurple/plugins/perl/common/Cipher.xs	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/perl/common/Cipher.xs	Sun Jun 23 13:35:53 2013 +0530
@@ -6,7 +6,6 @@
 BOOT:
 {
 	HV *stash = gv_stashpv("Purple::Cipher::BatchMode", 1);
-	HV *cipher_caps = gv_stashpv("Purple::Cipher::Caps", 1);
 
 	static const constiv *civ, const_iv[] = {
 #define const_iv(name) {#name, (IV)PURPLE_CIPHER_BATCH_MODE_##name}
@@ -15,74 +14,16 @@
 #undef const_iv
 	};
 
-	static const constiv bm_const_iv[] = {
-#define const_iv(name) {#name, (IV)PURPLE_CIPHER_CAPS_##name}
-		const_iv(SET_OPT),
-		const_iv(GET_OPT),
-		const_iv(INIT),
-		const_iv(RESET),
-		const_iv(UNINIT),
-		const_iv(SET_IV),
-		const_iv(APPEND),
-		const_iv(DIGEST),
-		const_iv(GET_DIGEST_SIZE),
-		const_iv(ENCRYPT),
-		const_iv(DECRYPT),
-		const_iv(SET_SALT),
-		const_iv(GET_SALT_SIZE),
-		const_iv(SET_KEY),
-		const_iv(GET_KEY_SIZE),
-		const_iv(SET_BATCH_MODE),
-		const_iv(GET_BATCH_MODE),
-		const_iv(GET_BLOCK_SIZE),
-		const_iv(UNKNOWN),
-#undef const_iv
-	};
-
 	for (civ = const_iv + sizeof(const_iv) / sizeof(const_iv[0]); civ-- > const_iv; )
 		newCONSTSUB(stash, (char *)civ->name, newSViv(civ->iv));
-
-	for (civ = bm_const_iv + sizeof(bm_const_iv) / sizeof(bm_const_iv[0]); civ-- > bm_const_iv; )
-		newCONSTSUB(cipher_caps, (char *)civ->name, newSViv(civ->iv));
 }
 
 const gchar *
 purple_cipher_get_name(cipher)
 	Purple::Cipher cipher
 
-guint
-purple_cipher_get_capabilities(cipher)
-	Purple::Cipher cipher
-
-gboolean
-purple_cipher_digest_region(name, data_sv, data_len, digest)
-	const gchar *name
-	SV *data_sv
-	size_t data_len
-	SV *digest
-	PREINIT:
-		guchar *buff = NULL;
-		guchar *data = NULL;
-		ssize_t digest_len;
-		size_t max_digest_len = 100;
-	CODE:
-		data = (guchar *)SvPV(data_sv, data_len);
-		SvUPGRADE(digest, SVt_PV);
-		buff = (guchar *)SvGROW(digest, max_digest_len);
-		digest_len = purple_cipher_digest_region(name, data, data_len, buff, max_digest_len);
-		if(digest_len == -1) {
-			SvSetSV_nosteal(digest, &PL_sv_undef);
-			RETVAL = 0;
-		} else {
-			SvCUR_set(digest, digest_len);
-			SvPOK_only(digest);
-			RETVAL = 1;
-		}
-	OUTPUT:
-		RETVAL
-
 gchar_own*
-purple_cipher_http_digest_calculate_response(algorithm, method, digest_uri, qop, entity, nonce, nonce_count, client_nonce, session_key)
+purple_http_digest_calculate_response(algorithm, method, digest_uri, qop, entity, nonce, nonce_count, client_nonce, session_key)
 	const gchar* algorithm
 	const gchar* method
 	const gchar* digest_uri
@@ -94,7 +35,7 @@
 	const gchar* session_key
 
 gchar_own*
-purple_cipher_http_digest_calculate_session_key(algorithm, username, realm, password, nonce, client_nonce)
+purple_http_digest_calculate_session_key(algorithm, username, realm, password, nonce, client_nonce)
 	const gchar* algorithm
 	const gchar* username
 	const gchar* realm
@@ -102,89 +43,30 @@
 	const gchar* nonce
 	const gchar* client_nonce
 
-MODULE = Purple::Cipher  PACKAGE = Purple::Ciphers  PREFIX = purple_ciphers_
-PROTOTYPES: ENABLE
-
-Purple::Cipher
-purple_ciphers_find_cipher(name)
-	gchar * name
-
-Purple::Cipher
-purple_ciphers_register_cipher(name, ops)
-	gchar * name
-	Purple::Cipher::Ops ops
-
-gboolean
-purple_ciphers_unregister_cipher(cipher)
+void
+purple_cipher_reset(cipher)
 	Purple::Cipher cipher
 
 void
-purple_ciphers_get_ciphers()
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = purple_ciphers_get_ciphers(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Cipher")));
-	}
-
-Purple::Handle
-purple_ciphers_get_handle()
-
-MODULE = Purple::Cipher  PACKAGE = Purple::Cipher::Context  PREFIX = purple_cipher_context_
-PROTOTYPES: ENABLE
-
-void
-purple_cipher_context_set_option(context, name, value)
-	Purple::Cipher::Context context
-	gchar *name
-	gpointer value
-
-gpointer
-purple_cipher_context_get_option(context, name)
-	Purple::Cipher::Context context
-	gchar *name
-
-Purple::Cipher::Context
-purple_cipher_context_new(klass, cipher, extra = NULL)
-	Purple::Cipher cipher
-	void *extra
-	C_ARGS: cipher, extra
-
-Purple::Cipher::Context
-purple_cipher_context_new_by_name(klass, name, extra = NULL)
-	gchar *name
-	void *extra
-	C_ARGS: name, extra
-
-void
-purple_cipher_context_reset(context, extra = NULL)
-	Purple::Cipher::Context context
-	gpointer extra
-
-void
-purple_cipher_context_destroy(context)
-	Purple::Cipher::Context context
-
-void
-purple_cipher_context_set_iv(Purple::Cipher::Context context, guchar *iv, size_t length(iv))
+purple_cipher_set_iv(Purple::Cipher cipher, guchar *iv, size_t length(iv))
 	PROTOTYPE: $$
 
 void
-purple_cipher_context_append(Purple::Cipher::Context context, guchar *data, size_t length(data))
+purple_cipher_append(Purple::Cipher cipher, guchar *data, size_t length(data))
 	PROTOTYPE: $$
 
 gboolean
-purple_cipher_context_digest(context, digest)
-	Purple::Cipher::Context context
+purple_cipher_digest(cipher, digest)
+	Purple::Cipher cipher
 	SV *digest
 	PREINIT:
 		guchar *buff = NULL;
 		size_t digest_size;
 	CODE:
-		digest_size = purple_cipher_context_get_digest_size(context);
+		digest_size = purple_cipher_get_digest_size(cipher);
 		SvUPGRADE(digest, SVt_PV);
 		buff = (guchar *)SvGROW(digest, digest_size);
-		if (purple_cipher_context_digest(context, buff, digest_size)) {
+		if (purple_cipher_digest(cipher, buff, digest_size)) {
 			SvCUR_set(digest, digest_size);
 			SvPOK_only(digest);
 			RETVAL = 1;
@@ -196,18 +78,18 @@
 		RETVAL
 
 gboolean
-purple_cipher_context_digest_to_str(context, digest_s)
-	Purple::Cipher::Context context
+purple_cipher_digest_to_str(cipher, digest_s)
+	Purple::Cipher cipher
 	SV *digest_s
 	PREINIT:
 		gchar *buff = NULL;
 		size_t digest_size, str_len;
 	CODE:
-		digest_size = purple_cipher_context_get_digest_size(context);
+		digest_size = purple_cipher_get_digest_size(cipher);
 		str_len = 2 * digest_size;
 		SvUPGRADE(digest_s, SVt_PV);
 		buff = SvGROW(digest_s, str_len + 1);
-		if (purple_cipher_context_digest_to_str(context, buff, str_len + 1)) {
+		if (purple_cipher_digest_to_str(cipher, buff, str_len + 1)) {
 			SvCUR_set(digest_s, str_len);
 			SvPOK_only(digest_s);
 			RETVAL = 1;
@@ -219,8 +101,8 @@
 		RETVAL
 
 gboolean
-purple_cipher_context_encrypt(context, input, output)
-	Purple::Cipher::Context context
+purple_cipher_encrypt(cipher, input, output)
+	Purple::Cipher cipher
 	SV *input
 	SV *output
 	PREINIT:
@@ -230,10 +112,10 @@
 		guchar *data = NULL;
 	CODE:
 		data = (guchar *)SvPV(input, input_len);
-		output_len = input_len + purple_cipher_context_get_block_size(context);
+		output_len = input_len + purple_cipher_get_block_size(cipher);
 		SvUPGRADE(output, SVt_PV);
 		buff = (guchar *)SvGROW(output, output_len);
-		ret = purple_cipher_context_encrypt(context, data, input_len, buff, output_len);
+		ret = purple_cipher_encrypt(cipher, data, input_len, buff, output_len);
 		if (ret >= 0) {
 			RETVAL = 1;
 			SvPOK_only(output);
@@ -246,8 +128,8 @@
 		RETVAL
 
 gboolean
-purple_cipher_context_decrypt(context, input, output)
-	Purple::Cipher::Context context
+purple_cipher_decrypt(cipher, input, output)
+	Purple::Cipher cipher
 	SV *input
 	SV *output
 	PREINIT:
@@ -257,10 +139,10 @@
 		guchar *data = NULL;
 	CODE:
 		data = (guchar *)SvPV(input, input_len);
-		output_len = input_len + purple_cipher_context_get_block_size(context);
+		output_len = input_len + purple_cipher_get_block_size(cipher);
 		SvUPGRADE(output, SVt_PV);
 		buff = (guchar *)SvGROW(output, output_len);
-		ret = purple_cipher_context_decrypt(context, data, input_len, buff, output_len);
+		ret = purple_cipher_decrypt(cipher, data, input_len, buff, output_len);
 		if (ret >= 0) {
 			RETVAL = 1;
 			SvPOK_only(output);
@@ -273,44 +155,68 @@
 		RETVAL
 
 void
-purple_cipher_context_set_salt(context, salt, len)
-	Purple::Cipher::Context context
+purple_cipher_set_salt(cipher, salt, len)
+	Purple::Cipher cipher
 	guchar *salt
 	size_t len
 
-size_t
-purple_cipher_context_get_salt_size(context)
-	Purple::Cipher::Context context
-
 void
-purple_cipher_context_set_key(context, key, len)
-	Purple::Cipher::Context context
+purple_cipher_set_key(cipher, key, len)
+	Purple::Cipher cipher
 	guchar *key
 	size_t len
 
 size_t
-purple_cipher_context_get_key_size(context)
-	Purple::Cipher::Context context
-
-void
-purple_cipher_context_set_data(context, data)
-	Purple::Cipher::Context context
-	gpointer data
-
-gpointer
-purple_cipher_context_get_data(context)
-	Purple::Cipher::Context context
+purple_cipher_get_key_size(cipher)
+	Purple::Cipher cipher
 
 Purple::Cipher::BatchMode
-purple_cipher_context_get_batch_mode(context)
-	Purple::Cipher::Context context
+purple_cipher_get_batch_mode(cipher)
+	Purple::Cipher cipher
 
 size_t
-purple_cipher_context_get_block_size(context)
-	Purple::Cipher::Context context
+purple_cipher_get_block_size(cipher)
+	Purple::Cipher cipher
 
 void
-purple_cipher_context_set_batch_mode(context, mode)
-	Purple::Cipher::Context context
+purple_cipher_set_batch_mode(cipher, mode)
+	Purple::Cipher cipher
 	Purple::Cipher::BatchMode mode
 
+MODULE = Purple::Cipher  PACKAGE = Purple::AESCipher  PREFIX = purple_aes_cipher_
+PROTOTYPES: ENABLE
+
+Purple::Cipher
+purple_aes_cipher_new()
+
+MODULE = Purple::Cipher  PACKAGE = Purple::DES3Cipher  PREFIX = purple_des3_cipher_
+PROTOTYPES: ENABLE
+
+Purple::Cipher
+purple_des3_cipher_new()
+
+MODULE = Purple::Cipher  PACKAGE = Purple::DESCipher  PREFIX = purple_des_cipher_
+PROTOTYPES: ENABLE
+
+Purple::Cipher
+purple_des_cipher_new()
+
+MODULE = Purple::Cipher  PACKAGE = Purple::HMACCipher  PREFIX = purple_hmac_cipher_
+PROTOTYPES: ENABLE
+
+Purple::Cipher
+purple_hmac_cipher_new(hash)
+	Purple::Hash hash
+
+MODULE = Purple::Cipher  PACKAGE = Purple::PBKDF2Cipher  PREFIX = purple_pbkdf2_cipher_
+PROTOTYPES: ENABLE
+
+Purple::Cipher
+purple_pbkdf2_cipher_new(hash)
+	Purple::Hash hash
+
+MODULE = Purple::Cipher  PACKAGE = Purple::RC4Cipher  PREFIX = purple_rc4_cipher_
+PROTOTYPES: ENABLE
+
+Purple::Cipher
+purple_rc4_cipher_new()
--- a/libpurple/plugins/perl/common/Conversation.xs	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/perl/common/Conversation.xs	Sun Jun 23 13:35:53 2013 +0530
@@ -5,23 +5,14 @@
 
 BOOT:
 {
-	HV *type_stash = gv_stashpv("Purple::Conversation::Type", 1);
-	HV *update_stash = gv_stashpv("Purple::Conversation::Update::Type", 1);
-	HV *typing_stash = gv_stashpv("Purple::Conversation::TypingState", 1);
-	HV *flags_stash = gv_stashpv("Purple::Conversation::Flags", 1);
-	HV *cbflags_stash = gv_stashpv("Purple::Conversation::ChatBuddy::Flags", 1);
+	HV *update_stash = gv_stashpv("Purple::Conversation::UpdateType", 1);
+	HV *typing_stash = gv_stashpv("Purple::IMConversation::TypingState", 1);
+	HV *flags_stash = gv_stashpv("Purple::Conversation::MessageFlags", 1);
+	HV *cbflags_stash = gv_stashpv("Purple::ChatConversation::Buddy::Flags", 1);
 
-	static const constiv *civ, type_const_iv[] = {
-#define const_iv(name) {#name, (IV)PURPLE_CONV_TYPE_##name}
-		const_iv(UNKNOWN),
-		const_iv(IM),
-		const_iv(CHAT),
-		const_iv(MISC),
-		const_iv(ANY),
-	};
-	static const constiv update_const_iv[] = {
+	static const constiv *civ, update_const_iv[] = {
 #undef const_iv
-#define const_iv(name) {#name, (IV)PURPLE_CONV_UPDATE_##name}
+#define const_iv(name) {#name, (IV)PURPLE_CONVERSATION_UPDATE_##name}
 		const_iv(ADD),
 		const_iv(REMOVE),
 		const_iv(ACCOUNT),
@@ -41,14 +32,14 @@
 	};
 	static const constiv typing_const_iv[] = {
 #undef const_iv
-#define const_iv(name) {#name, (IV)PURPLE_##name}
+#define const_iv(name) {#name, (IV)PURPLE_IM_CONVERSATION_##name}
 		const_iv(NOT_TYPING),
 		const_iv(TYPING),
 		const_iv(TYPED),
 	};
 	static const constiv flags_const_iv[] = {
 #undef const_iv
-#define const_iv(name) {#name, (IV)PURPLE_MESSAGE_##name}
+#define const_iv(name) {#name, (IV)PURPLE_CONVERSATION_MESSAGE_##name}
 		const_iv(SEND),
 		const_iv(RECV),
 		const_iv(SYSTEM),
@@ -66,7 +57,7 @@
 	};
 	static const constiv cbflags_const_iv[] = {
 #undef const_iv
-#define const_iv(name) {#name, (IV)PURPLE_CBFLAGS_##name}
+#define const_iv(name) {#name, (IV)PURPLE_CHAT_CONVERSATION_BUDDY_##name}
 		const_iv(NONE),
 		const_iv(VOICE),
 		const_iv(HALFOP),
@@ -75,9 +66,6 @@
 		const_iv(TYPING),
 	};
 
-	for (civ = type_const_iv + sizeof(type_const_iv) / sizeof(type_const_iv[0]); civ-- > type_const_iv; )
-		newCONSTSUB(type_stash, (char *)civ->name, newSViv(civ->iv));
-
 	for (civ = update_const_iv + sizeof(update_const_iv) / sizeof(update_const_iv[0]); civ-- > update_const_iv; )
 		newCONSTSUB(update_stash, (char *)civ->name, newSViv(civ->iv));
 
@@ -91,55 +79,61 @@
 		newCONSTSUB(cbflags_stash, (char *)civ->name, newSViv(civ->iv));
 }
 
-void
-purple_get_ims()
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = purple_get_ims(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation")));
-	}
-
-void
-purple_get_conversations()
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = purple_get_conversations(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation")));
-	}
-
-void
-purple_get_chats()
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = purple_get_chats(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation")));
-	}
-
-Purple::Conversation
-purple_find_conversation_with_account(type, name, account)
-	Purple::ConversationType type
-	const char *name
-	Purple::Account account
-
 MODULE = Purple::Conversation  PACKAGE = Purple::Conversations  PREFIX = purple_conversations_
 PROTOTYPES: ENABLE
 
 Purple::Handle
 purple_conversations_get_handle()
 
-MODULE = Purple::Conversation  PACKAGE = Purple::Conversation  PREFIX = purple_conversation_
-PROTOTYPES: ENABLE
+Purple::ChatConversation
+purple_conversations_find_chat(gc, id)
+	Purple::Connection gc
+	int id
+
+void
+purple_conversations_get_ims()
+PREINIT:
+	GList *l;
+PPCODE:
+	for (l = purple_conversations_get_ims(); l != NULL; l = l->next) {
+		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation")));
+	}
+
+void
+purple_conversations_get()
+PREINIT:
+	GList *l;
+PPCODE:
+	for (l = purple_conversations_get(); l != NULL; l = l->next) {
+		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation")));
+	}
 
 void
-purple_conversation_destroy(conv)
-	Purple::Conversation conv
+purple_conversations_get_chats()
+PREINIT:
+	GList *l;
+PPCODE:
+	for (l = purple_conversations_get_chats(); l != NULL; l = l->next) {
+		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation")));
+	}
+
+Purple::Conversation
+purple_conversations_find_with_account(name, account)
+	const char *name
+	Purple::Account account
 
-Purple::ConversationType
-purple_conversation_get_type(conv)
-	Purple::Conversation conv
+Purple::ChatConversation
+purple_conversations_find_chat_with_account(name, account)
+	const char *name
+	Purple::Account account
+
+Purple::IMConversation
+purple_conversations_find_im_with_account(name, account)
+	const char *name
+	Purple::Account account
+
+MODULE = Purple::Conversation  PACKAGE = Purple::Conversation  PREFIX = purple_conversation_
+PROTOTYPES: ENABLE
 
 Purple::Account
 purple_conversation_get_account(conv)
@@ -180,14 +174,6 @@
 purple_conversation_is_logging(conv)
 	Purple::Conversation conv
 
-Purple::Conversation::IM
-purple_conversation_get_im_data(conv)
-	Purple::Conversation conv
-
-Purple::Conversation::Chat
-purple_conversation_get_chat_data(conv)
-	Purple::Conversation conv
-
 gpointer
 purple_conversation_get_data(conv, key)
 	Purple::Conversation conv
@@ -204,15 +190,7 @@
 void
 purple_conversation_update(conv, type)
 	Purple::Conversation conv
-	Purple::ConvUpdateType type
-
-Purple::Conversation
-purple_conversation_new(class, type, account, name)
-	Purple::ConversationType type
-	Purple::Account account
-	const char *name
-    C_ARGS:
-	type, account, name
+	Purple::Conversation::UpdateType type
 
 void
 purple_conversation_set_account(conv, account);
@@ -224,9 +202,28 @@
 	Purple::Conversation conv
 	const char *who
 	const char *message
-	Purple::MessageFlags flags
+	Purple::Conversation::MessageFlags flags
+	time_t mtime
+
+void
+purple_conversation_write_message(conv, who, message, flags, mtime)
+	Purple::Conversation conv
+	const char *who
+	const char *message
+	Purple::Conversation::MessageFlags flags
 	time_t mtime
 
+void
+purple_conversation_send(conv, message)
+	Purple::Conversation conv
+	const char *message
+
+void
+purple_conversation_send_message(conv, message, flags)
+	Purple::Conversation conv
+	const char *message
+	Purple::Conversation::MessageFlags flags
+
 gboolean
 purple_conversation_do_command(conv, cmdline, markup, error)
 	Purple::Conversation conv
@@ -234,132 +231,122 @@
 	const char *markup
 	char **error
 
-MODULE = Purple::Conversation  PACKAGE = Purple::Conversation::IM  PREFIX = purple_conv_im_
+MODULE = Purple::Conversation  PACKAGE = Purple::IMConversation  PREFIX = purple_im_conversation_
 PROTOTYPES: ENABLE
 
 Purple::Conversation
-purple_conv_im_get_conversation(im)
-	Purple::Conversation::IM im
+purple_im_conversation_new(class, account, name)
+	Purple::Account account
+	const char *name
+    C_ARGS:
+	account, name
 
 void
-purple_conv_im_set_icon(im, icon)
-	Purple::Conversation::IM im
+purple_im_conversation_set_icon(im, icon)
+	Purple::IMConversation im
 	Purple::Buddy::Icon icon
 
 Purple::Buddy::Icon
-purple_conv_im_get_icon(im)
-	Purple::Conversation::IM im
+purple_im_conversation_get_icon(im)
+	Purple::IMConversation im
 
 void
-purple_conv_im_set_typing_state(im, state)
-	Purple::Conversation::IM im
-	Purple::TypingState state
+purple_im_conversation_set_typing_state(im, state)
+	Purple::IMConversation im
+	Purple::IMConversation::TypingState state
 
-Purple::TypingState
-purple_conv_im_get_typing_state(im)
-	Purple::Conversation::IM im
+Purple::IMConversation::TypingState
+purple_im_conversation_get_typing_state(im)
+	Purple::IMConversation im
 
 void
-purple_conv_im_start_typing_timeout(im, timeout)
-	Purple::Conversation::IM im
+purple_im_conversation_start_typing_timeout(im, timeout)
+	Purple::IMConversation im
 	int timeout
 
 void
-purple_conv_im_stop_typing_timeout(im)
-	Purple::Conversation::IM im
+purple_im_conversation_stop_typing_timeout(im)
+	Purple::IMConversation im
 
 guint
-purple_conv_im_get_typing_timeout(im)
-	Purple::Conversation::IM im
+purple_im_conversation_get_typing_timeout(im)
+	Purple::IMConversation im
 
 void
-purple_conv_im_set_type_again(im, val)
-	Purple::Conversation::IM im
+purple_im_conversation_set_type_again(im, val)
+	Purple::IMConversation im
 	time_t val
 
 time_t
-purple_conv_im_get_type_again(im)
-	Purple::Conversation::IM im
-
-void
-purple_conv_im_start_send_typed_timeout(im)
-	Purple::Conversation::IM im
+purple_im_conversation_get_type_again(im)
+	Purple::IMConversation im
 
 void
-purple_conv_im_stop_send_typed_timeout(im)
-	Purple::Conversation::IM im
-
-guint
-purple_conv_im_get_send_typed_timeout(im)
-	Purple::Conversation::IM im
-
-void
-purple_conv_im_update_typing(im)
-	Purple::Conversation::IM im
+purple_im_conversation_start_send_typed_timeout(im)
+	Purple::IMConversation im
 
 void
-purple_conv_im_send(im, message)
-	Purple::Conversation::IM im
-	const char *message
+purple_im_conversation_stop_send_typed_timeout(im)
+	Purple::IMConversation im
+
+guint
+purple_im_conversation_get_send_typed_timeout(im)
+	Purple::IMConversation im
 
 void
-purple_conv_im_send_with_flags(im, message, flags)
-	Purple::Conversation::IM im
-	const char *message
-	Purple::MessageFlags flags
+purple_im_conversation_update_typing(im)
+	Purple::IMConversation im
 
-void
-purple_conv_im_write(im, who, message, flags, mtime)
-	Purple::Conversation::IM im
-	const char *who
-	const char *message
-	Purple::MessageFlags flags
-	time_t mtime
-
-MODULE = Purple::Conversation  PACKAGE = Purple::Conversation  PREFIX = purple_conv_
+MODULE = Purple::Conversation  PACKAGE = Purple::Conversation::Helper  PREFIX = purple_conversation_helper_
 PROTOTYPES: ENABLE
 
 gboolean
-purple_conv_present_error(who, account, what)
+purple_conversation_helper_present_error(who, account, what)
 	const char *who
 	Purple::Account account
 	const char *what
 
+MODULE = Purple::Conversation  PACKAGE = Purple::Conversation  PREFIX = purple_conversation_
+PROTOTYPES: ENABLE
+
 void
-purple_conv_custom_smiley_close(conv, smile)
+purple_conversation_custom_smiley_close(conv, smile)
 	Purple::Conversation conv
 	const char *smile
 
-MODULE = Purple::Conversation  PACKAGE = Purple::Conversation::Chat  PREFIX = purple_conv_chat_
+MODULE = Purple::Conversation  PACKAGE = Purple::ChatConversation  PREFIX = purple_chat_conversation_
 PROTOTYPES: ENABLE
 
 Purple::Conversation
-purple_conv_chat_get_conversation(chat)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_new(class, account, name)
+	Purple::Account account
+	const char *name
+    C_ARGS:
+	account, name
 
 void
-purple_conv_chat_get_users(chat)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_get_users(chat)
+	Purple::ChatConversation chat
 PREINIT:
 	GList *l;
 PPCODE:
-	for (l = purple_conv_chat_get_users(chat); l != NULL; l = l->next) {
+	for (l = purple_chat_conversation_get_users(chat); l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::ListEntry")));
 	}
 
 void
-purple_conv_chat_ignore(chat, name)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_ignore(chat, name)
+	Purple::ChatConversation chat
 	const char *name
 
 void
-purple_conv_chat_unignore(chat, name)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_unignore(chat, name)
+	Purple::ChatConversation chat
 	const char *name
 
 void
-purple_conv_chat_set_ignored(chat, ignored)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_set_ignored(chat, ignored)
+	Purple::ChatConversation chat
 	SV * ignored
 PREINIT:
 	GList *l, *t_GL;
@@ -371,55 +358,36 @@
 	for (i = 0; i <= t_len; i++)
 		t_GL = g_list_append(t_GL, SvPVutf8_nolen(*av_fetch((AV *)SvRV(ignored), i, 0)));
 
-	for (l = purple_conv_chat_set_ignored(chat, t_GL); l != NULL; l = l->next) {
+	for (l = purple_chat_conversation_set_ignored(chat, t_GL); l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::ListEntry")));
 	}
 
 void
-purple_conv_chat_get_ignored(chat)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_get_ignored(chat)
+	Purple::ChatConversation chat
 PREINIT:
 	GList *l;
 PPCODE:
-	for (l = purple_conv_chat_get_ignored(chat); l != NULL; l = l->next) {
+	for (l = purple_chat_conversation_get_ignored(chat); l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::ListEntry")));
 	}
 
 const char *
-purple_conv_chat_get_topic(chat)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_get_topic(chat)
+	Purple::ChatConversation chat
 
 void
-purple_conv_chat_set_id(chat, id)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_set_id(chat, id)
+	Purple::ChatConversation chat
 	int id
 
 int
-purple_conv_chat_get_id(chat)
-	Purple::Conversation::Chat chat
-
-void
-purple_conv_chat_send(chat, message)
-	Purple::Conversation::Chat chat
-	const char * message
+purple_chat_conversation_get_id(chat)
+	Purple::ChatConversation chat
 
 void
-purple_conv_chat_send_with_flags(chat, message, flags)
-	Purple::Conversation::Chat chat
-	const char * message
-	Purple::MessageFlags flags
-
-void
-purple_conv_chat_write(chat, who, message, flags, mtime)
-	Purple::Conversation::Chat chat
-	const char *who
-	const char *message
-	Purple::MessageFlags flags
-	time_t mtime
-
-void
-purple_conv_chat_add_users(chat, users, extra_msgs, flags, new_arrivals)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_add_users(chat, users, extra_msgs, flags, new_arrivals)
+	Purple::ChatConversation chat
 	SV * users
 	SV * extra_msgs
 	SV * flags
@@ -446,48 +414,43 @@
 	for (i = 0; i <= t_len; i++)
 		t_GL_extra_msgs = g_list_append(t_GL_extra_msgs, SvPVutf8_nolen(*av_fetch((AV *)SvRV(extra_msgs), i, 0)));
 
-	purple_conv_chat_add_users(chat, t_GL_users, t_GL_extra_msgs, t_GL_flags, new_arrivals);
+	purple_chat_conversation_add_users(chat, t_GL_users, t_GL_extra_msgs, t_GL_flags, new_arrivals);
 
 	g_list_free(t_GL_users);
 	g_list_free(t_GL_extra_msgs);
 	g_list_free(t_GL_flags);
 
 gboolean
-purple_conv_chat_find_user(chat, user)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_find_user(chat, user)
+	Purple::ChatConversation chat
 	const char * user
 
-void purple_conv_chat_clear_users(chat)
-	Purple::Conversation::Chat chat
+void purple_chat_conversation_clear_users(chat)
+	Purple::ChatConversation chat
 
-void purple_conv_chat_set_nick(chat, nick)
-	Purple::Conversation::Chat chat
+void purple_chat_conversation_set_nick(chat, nick)
+	Purple::ChatConversation chat
 	const char * nick
 
 const char *
-purple_conv_chat_get_nick(chat)
-	Purple::Conversation::Chat chat
+purple_chat_conversation_get_nick(chat)
+	Purple::ChatConversation chat
 
-Purple::Conversation
-purple_find_chat(gc, id)
-	Purple::Connection gc
-	int id
+void purple_chat_conversation_leave(chat)
+	Purple::ChatConversation chat
 
-void purple_conv_chat_left(chat)
-	Purple::Conversation::Chat chat
+gboolean purple_chat_conversation_has_left(chat)
+	Purple::ChatConversation chat
 
-gboolean purple_conv_chat_has_left(chat)
-	Purple::Conversation::Chat chat
-
-Purple::Conversation::ChatBuddy
-purple_conv_chat_cb_find(chat, name)
-	Purple::Conversation::Chat chat
+Purple::ChatConversation::Buddy
+purple_chat_conversation_find_buddy(chat, name)
+	Purple::ChatConversation chat
 	const char *name
 
 const char *
-purple_conv_chat_cb_get_name(cb)
-	Purple::Conversation::ChatBuddy cb
+purple_chat_conversation_buddy_get_name(cb)
+	Purple::ChatConversation::Buddy cb
 
 void
-purple_conv_chat_cb_destroy(cb);
-	Purple::Conversation::ChatBuddy cb
+purple_chat_conversation_buddy_destroy(cb);
+	Purple::ChatConversation::Buddy cb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/perl/common/Hash.xs	Sun Jun 23 13:35:53 2013 +0530
@@ -0,0 +1,110 @@
+#include "module.h"
+
+MODULE = Purple::Hash  PACKAGE = Purple::Hash  PREFIX = purple_hash_
+PROTOTYPES: ENABLE
+
+const gchar *
+purple_hash_get_name(hash)
+	Purple::Hash hash
+
+gchar_own*
+purple_http_digest_calculate_response(algorithm, method, digest_uri, qop, entity, nonce, nonce_count, client_nonce, session_key)
+	const gchar* algorithm
+	const gchar* method
+	const gchar* digest_uri
+	const gchar* qop
+	const gchar* entity
+	const gchar* nonce
+	const gchar* nonce_count
+	const gchar* client_nonce
+	const gchar* session_key
+
+gchar_own*
+purple_http_digest_calculate_session_key(algorithm, username, realm, password, nonce, client_nonce)
+	const gchar* algorithm
+	const gchar* username
+	const gchar* realm
+	const gchar* password
+	const gchar* nonce
+	const gchar* client_nonce
+
+void
+purple_hash_reset(hash)
+	Purple::Hash hash
+
+void
+purple_hash_append(Purple::Hash hash, guchar *data, size_t length(data))
+	PROTOTYPE: $$
+
+gboolean
+purple_hash_digest(hash, digest)
+	Purple::Hash hash
+	SV *digest
+	PREINIT:
+		guchar *buff = NULL;
+		size_t digest_size;
+	CODE:
+		digest_size = purple_hash_get_digest_size(hash);
+		SvUPGRADE(digest, SVt_PV);
+		buff = (guchar *)SvGROW(digest, digest_size);
+		if (purple_hash_digest(hash, buff, digest_size)) {
+			SvCUR_set(digest, digest_size);
+			SvPOK_only(digest);
+			RETVAL = 1;
+		} else {
+			SvSetSV_nosteal(digest, &PL_sv_undef);
+			RETVAL = 0;
+		}
+	OUTPUT:
+		RETVAL
+
+gboolean
+purple_hash_digest_to_str(hash, digest_s)
+	Purple::Hash hash
+	SV *digest_s
+	PREINIT:
+		gchar *buff = NULL;
+		size_t digest_size, str_len;
+	CODE:
+		digest_size = purple_hash_get_digest_size(hash);
+		str_len = 2 * digest_size;
+		SvUPGRADE(digest_s, SVt_PV);
+		buff = SvGROW(digest_s, str_len + 1);
+		if (purple_hash_digest_to_str(hash, buff, str_len + 1)) {
+			SvCUR_set(digest_s, str_len);
+			SvPOK_only(digest_s);
+			RETVAL = 1;
+		} else {
+			SvSetSV_nosteal(digest_s, &PL_sv_undef);
+			RETVAL = 0;
+		}
+	OUTPUT:
+		RETVAL
+
+size_t
+purple_hash_get_block_size(hash)
+	Purple::Hash hash
+
+MODULE = Purple::Hash  PACKAGE = Purple::MD4Hash  PREFIX = purple_md4_hash_
+PROTOTYPES: ENABLE
+
+Purple::Hash
+purple_md4_hash_new()
+
+MODULE = Purple::Hash  PACKAGE = Purple::MD5Hash  PREFIX = purple_md5_hash_
+PROTOTYPES: ENABLE
+
+Purple::Hash
+purple_md5_hash_new()
+
+MODULE = Purple::Hash  PACKAGE = Purple::SHA1Hash  PREFIX = purple_sha1_hash_
+PROTOTYPES: ENABLE
+
+Purple::Hash
+purple_sha1_hash_new()
+
+MODULE = Purple::Hash  PACKAGE = Purple::SHA256Hash  PREFIX = purple_sha256_hash_
+PROTOTYPES: ENABLE
+
+Purple::Hash
+purple_sha256_hash_new()
--- a/libpurple/plugins/perl/common/MANIFEST	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/perl/common/MANIFEST	Sun Jun 23 13:35:53 2013 +0530
@@ -8,6 +8,7 @@
 Conversation.xs
 Debug.xs
 FT.xs
+Hash.xs
 ImgStore.xs
 Log.xs
 Makefile.PL
@@ -17,7 +18,6 @@
 PluginPref.xs
 Pounce.xs
 Prefs.xs
-Privacy.xs
 Proxy.xs
 Prpl.xs
 Purple.pm
--- a/libpurple/plugins/perl/common/Makefile.mingw	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/perl/common/Makefile.mingw	Sun Jun 23 13:35:53 2013 +0530
@@ -48,6 +48,7 @@
 				Core.xs \
 				Debug.xs \
 				FT.xs \
+				Hash.xs \
 				Idle.xs \
 				Purple.xs \
 				ImgStore.xs \
@@ -58,7 +59,6 @@
 				PluginPref.xs \
 				Pounce.xs \
 				Prefs.xs \
-				Privacy.xs \
 				Proxy.xs \
 				Prpl.xs \
 				Request.xs \
--- a/libpurple/plugins/perl/common/Privacy.xs	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#include "module.h"
-
-MODULE = Purple::Privacy  PACKAGE = Purple::Privacy  PREFIX = purple_privacy_
-PROTOTYPES: ENABLE
-
-gboolean
-purple_privacy_permit_add(account, name, local_only)
-	Purple::Account account
-	const char * name
-	gboolean local_only
-
-gboolean
-purple_privacy_permit_remove(account, name, local_only)
-	Purple::Account account
-	const char * name
-	gboolean local_only
-
-gboolean
-purple_privacy_deny_add(account, name, local_only)
-	Purple::Account account
-	const char * name
-	gboolean local_only
-
-gboolean
-purple_privacy_deny_remove(account, name, local_only)
-	Purple::Account account
-	const char * name
-	gboolean local_only
-
-gboolean
-purple_privacy_check(account, who)
-	Purple::Account account
-	const char * who
--- a/libpurple/plugins/perl/common/Server.xs	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/perl/common/Server.xs	Sun Jun 23 13:35:53 2013 +0530
@@ -35,7 +35,7 @@
 	Purple::Connection con 
 	int a
 	const char * b
-	Purple::MessageFlags flags
+	Purple::Conversation::MessageFlags flags
 
 void 
 serv_chat_whisper(con, a, b, c)
@@ -60,7 +60,7 @@
 	Purple::Connection g
 	int id
 	const char *who
-	Purple::MessageFlags chatflags
+	Purple::Conversation::MessageFlags chatflags
 	const char *message
 	time_t mtime
 
@@ -101,7 +101,7 @@
 	Purple::Connection gc
 	const char *who
 	const char *msg
-	Purple::MessageFlags imflags
+	Purple::Conversation::MessageFlags imflags
 	time_t mtime
 
 Purple::Conversation
@@ -115,7 +115,7 @@
 	Purple::Connection gc
 	const char *name
 	int timeout
-	Purple::TypingState state
+	Purple::IMConversation::TypingState state
 
 void 
 serv_got_typing_stopped(gc, name)
@@ -197,13 +197,13 @@
 	Purple::Connection con
 	const char * a
 	const char * b
-	Purple::MessageFlags flags
+	Purple::Conversation::MessageFlags flags
 
 int  
 serv_send_typing(con, a, state)
 	Purple::Connection con
 	const char * a
-	Purple::TypingState state
+	Purple::IMConversation::TypingState state
 
 void 
 serv_set_info(con, a)
--- a/libpurple/plugins/perl/common/module.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/perl/common/module.h	Sun Jun 23 13:35:53 2013 +0530
@@ -19,15 +19,26 @@
 
 #include "../perl-common.h"
 
-#include "account.h"
+#include "accounts.h"
 #include "accountopt.h"
 #include "blist.h"
 #include "buddyicon.h"
 #include "certificate.h"
 #include "cipher.h"
+#include "ciphers/aescipher.h"
+#include "ciphers/des3cipher.h"
+#include "ciphers/descipher.h"
+#include "ciphers/hmaccipher.h"
+#include "ciphers/pbkdf2cipher.h"
+#include "ciphers/rc4cipher.h"
+#include "hash.h"
+#include "ciphers/md4hash.h"
+#include "ciphers/md5hash.h"
+#include "ciphers/sha1hash.h"
+#include "ciphers/sha256hash.h"
 #include "cmds.h"
 #include "connection.h"
-#include "conversation.h"
+#include "conversations.h"
 #include "core.h"
 #include "debug.h"
 #include "desktopitem.h"
@@ -48,7 +59,6 @@
 #include "pluginpref.h"
 #include "pounce.h"
 #include "prefs.h"
-#include "privacy.h"
 #include "prpl.h"
 #include "proxy.h"
 #include "request.h"
@@ -71,6 +81,7 @@
 typedef PurpleAccount *			Purple__Account;
 typedef PurpleAccountOption *		Purple__Account__Option;
 typedef PurpleAccountUserSplit *		Purple__Account__UserSplit;
+typedef PurpleAccountPrivacyType		Purple__Account__PrivacyType;
 
 /* blist.h */
 typedef PurpleBlistNode *			Purple__BuddyList__Node;
@@ -95,9 +106,6 @@
 
 /* cipher.h */
 typedef PurpleCipher *			Purple__Cipher;
-typedef PurpleCipherCaps			Purple__CipherCaps;
-typedef PurpleCipherContext *		Purple__Cipher__Context;
-typedef PurpleCipherOps *			Purple__Cipher__Ops;
 typedef PurpleCipherBatchMode		Purple__Cipher__BatchMode;
 
 /* cmds.h */
@@ -111,16 +119,15 @@
 typedef PurpleConnectionFlags		Purple__ConnectionFlags;
 typedef PurpleConnectionState		Purple__ConnectionState;
 
-/* conversation.h */
-typedef PurpleConversationType		Purple__ConversationType;
-typedef PurpleConvUpdateType		Purple__ConvUpdateType;
-typedef PurpleTypingState			Purple__TypingState;
-typedef PurpleMessageFlags		Purple__MessageFlags;
-typedef PurpleConvChatBuddyFlags		Purple__ConvChatBuddyFlags;
+/* conversations.h */
+typedef PurpleConversationUpdateType		Purple__Conversation__UpdateType;
+typedef PurpleIMConversationTypingState		Purple__IMConversation__TypingState;
+typedef PurpleConversationMessageFlags		Purple__Conversation__MessageFlags;
+typedef PurpleChatConversationBuddyFlags	Purple__ChatConversation__Buddy__Flags;
 typedef PurpleConversation *		Purple__Conversation;
-typedef PurpleConvIm *			Purple__Conversation__IM;
-typedef PurpleConvChat *			Purple__Conversation__Chat;
-typedef PurpleConvChatBuddy *		Purple__Conversation__ChatBuddy;
+typedef PurpleIMConversation *			Purple__IMConversation;
+typedef PurpleChatConversation *		Purple__ChatConversation;
+typedef PurpleChatConversationBuddy *	Purple__ChatConversation__Buddy;
 
 /* core.h */
 
@@ -168,6 +175,9 @@
 /* gtkconn.h */
 #endif
 
+/* hash.h */
+typedef PurpleHash *			Purple__Hash;
+
 /* imgstore.h */
 typedef PurpleStoredImage *		Purple__StoredImage;
 
@@ -215,9 +225,6 @@
 /* prefs.h */
 typedef PurplePrefType			Purple__PrefType;
 
-/* privacy.h */
-typedef PurplePrivacyType			Purple__PrivacyType;
-
 /* proxy.h */
 typedef PurpleProxyInfo *			Purple__ProxyInfo;
 typedef PurpleProxyType			Purple__ProxyType;
--- a/libpurple/plugins/perl/common/typemap	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/perl/common/typemap	Sun Jun 23 13:35:53 2013 +0530
@@ -37,10 +37,12 @@
 const xmlnode *				T_PTR
 gssize					T_IV
 const void *				T_PTR
+GType					T_IV
 
 Purple::Account				T_PurpleObj
 Purple::Account::Option			T_PurpleObj
 Purple::Account::UserSplit		T_PurpleObj
+Purple::Account::PrivacyType			T_IV
 
 Purple::Buddy::Icon			T_PurpleObj
 Purple::Buddy::Icon::Spec			T_PurpleObj
@@ -54,18 +56,12 @@
 Purple::BuddyList::NodeType		T_IV
 
 Purple::Cipher				T_PurpleObj
-Purple::CipherCaps			T_IV
-Purple::Cipher::Ops			T_PurpleObj
-Purple::Cipher::Context			T_PurpleObj
+Purple::Hash				T_PurpleObj
 Purple::Cmd::Flag				T_IV
 Purple::Cmd::Id				T_IV
 Purple::Cmd::Priority			T_IV
 Purple::Cmd::Ret				T_IV
 Purple::Connection			T_PurpleObj
-Purple::Conversation			T_PurpleObj
-Purple::Conversation::Chat		T_PurpleObj
-Purple::Conversation::ChatBuddy		T_PurpleObj
-Purple::Conversation::IM			T_PurpleObj
 Purple::Core				T_PurpleObj
 
 Purple::Desktop::Item			T_PurpleObj
@@ -111,7 +107,6 @@
 Purple::Pounce				T_PurpleObj
 Purple::PounceEvent			T_IV
 Purple::Presence				T_PurpleObj
-Purple::PrivacyType			T_IV
 Purple::ProtocolOptions			T_IV
 Purple::ProxyInfo				T_PurpleObj
 Purple::ProxyType				T_IV
@@ -180,12 +175,15 @@
 /* debug.h */
 Purple::DebugLevel			T_IV
 
-/* conversation.h */
-Purple::ConvChatBuddyFlags		T_IV
-Purple::ConvUpdateType			T_IV
-Purple::ConversationType		T_IV
-Purple::MessageFlags			T_IV
-Purple::TypingState			T_IV
+/* conversations.h */
+Purple::Conversation			T_PurpleObj
+Purple::ChatConversation		T_PurpleObj
+Purple::ChatConversation::Buddy		T_PurpleObj
+Purple::IMConversation			T_PurpleObj
+Purple::ChatConversation::Buddy::Flags	T_IV
+Purple::Conversation::UpdateType	T_IV
+Purple::Conversation::MessageFlags	T_IV
+Purple::IMConversation::TypingState	T_IV
 Purple::UnseenState			T_IV
 
 /* connection.h */
--- a/libpurple/plugins/psychic.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/psychic.c	Sun Jun 23 13:35:53 2013 +0530
@@ -9,7 +9,6 @@
 #include "signals.h"
 #include "status.h"
 #include "version.h"
-#include "privacy.h"
 
 #include "plugin.h"
 #include "pluginpref.h"
@@ -48,7 +47,7 @@
     return;
   }
 
-  if(FALSE == purple_privacy_check(acct, name)) {
+  if(FALSE == purple_account_privacy_check(acct, name)) {
     purple_debug_info("psychic", "user %s is blocked\n", name);
     return;
   }
--- a/libpurple/plugins/signals-test.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/signals-test.c	Sun Jun 23 13:35:53 2013 +0530
@@ -24,7 +24,6 @@
 
 #include <stdio.h>
 
-#include "cipher.h"
 #include "connection.h"
 #include "conversation.h"
 #include "core.h"
@@ -74,7 +73,7 @@
 {
 	purple_debug_misc("signals test", "account-alias-changed (%s, %s, %s)\n",
 					purple_account_get_username(account),
-					old, purple_account_get_alias(account));
+					old, purple_account_get_private_alias(account));
 }
 
 static int
@@ -524,21 +523,6 @@
 					(who) ? who : "unknown");
 }
 /**************************************************************************
- * Ciphers signal callbacks
- **************************************************************************/
-static void
-cipher_added_cb(PurpleCipher *cipher, void *data) {
-	purple_debug_misc("signals test", "cipher %s added\n",
-					purple_cipher_get_name(cipher));
-}
-
-static void
-cipher_removed_cb(PurpleCipher *cipher, void *data) {
-	purple_debug_misc("signals test", "cipher %s removed\n",
-					purple_cipher_get_name(cipher));
-}
-
-/**************************************************************************
  * Core signal callbacks
  **************************************************************************/
 static void
@@ -719,7 +703,6 @@
 	void *conn_handle     = purple_connections_get_handle();
 	void *conv_handle     = purple_conversations_get_handle();
 	void *accounts_handle = purple_accounts_get_handle();
-	void *ciphers_handle  = purple_ciphers_get_handle();
 	void *ft_handle       = purple_xfers_get_handle();
 	void *sound_handle    = purple_sounds_get_handle();
 	void *notify_handle   = purple_notify_get_handle();
@@ -831,12 +814,6 @@
 	purple_signal_connect(conv_handle, "chat-topic-changed",
 						plugin, PURPLE_CALLBACK(chat_topic_changed_cb), NULL);
 
-	/* Ciphers signals */
-	purple_signal_connect(ciphers_handle, "cipher-added",
-						plugin, PURPLE_CALLBACK(cipher_added_cb), NULL);
-	purple_signal_connect(ciphers_handle, "cipher-removed",
-						plugin, PURPLE_CALLBACK(cipher_removed_cb), NULL);
-
 	/* Core signals */
 	purple_signal_connect(core_handle, "quitting",
 						plugin, PURPLE_CALLBACK(quitting_cb), NULL);
--- a/libpurple/plugins/tcl/tcl_cmds.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/plugins/tcl/tcl_cmds.c	Sun Jun 23 13:35:53 2013 +0530
@@ -70,7 +70,7 @@
 	if (convo == NULL)
 		return NULL;
 
-	for (cur = purple_get_conversations(); cur != NULL; cur = g_list_next(cur)) {
+	for (cur = purple_conversations_get(); cur != NULL; cur = g_list_next(cur)) {
 		if (convo == cur->data)
 			return convo;
 	}
@@ -139,7 +139,7 @@
 		}
 		if ((account = tcl_validate_account(objv[2], interp)) == NULL)
 			return TCL_ERROR;
-		alias = purple_account_get_alias(account);
+		alias = purple_account_get_private_alias(account);
 		Tcl_SetObjResult(interp, Tcl_NewStringObj(alias ? (char *)alias : "", -1));
 		break;
 	case CMD_ACCOUNT_CONNECT:
@@ -775,7 +775,7 @@
 	enum { CMD_CONV_NEW_CHAT, CMD_CONV_NEW_IM } newopt;
 	PurpleConversation *convo;
 	PurpleAccount *account;
-	PurpleConversationType type;
+	gboolean is_chat = FALSE;
 	GList *cur;
 	char *opt, *from, *what;
 	int error, argsused, flags = 0;
@@ -797,8 +797,7 @@
 		account = NULL;
 		if ((account = tcl_validate_account(objv[2], interp)) == NULL)
 			return TCL_ERROR;
-		convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY,
-							    Tcl_GetString(objv[3]),
+		convo = purple_conversations_find_with_account(Tcl_GetString(objv[3]),
 							    account);
 		Tcl_SetObjResult(interp, purple_tcl_ref_new(PurpleTclRefConversation, convo));
 		break;
@@ -813,7 +812,7 @@
 		break;
 	case CMD_CONV_LIST:
 		list = Tcl_NewListObj(0, NULL);
-		for (cur = purple_get_conversations(); cur != NULL; cur = g_list_next(cur)) {
+		for (cur = purple_conversations_get(); cur != NULL; cur = g_list_next(cur)) {
 			elem = purple_tcl_ref_new(PurpleTclRefConversation, cur->data);
 			Tcl_ListObjAppendElement(interp, list, elem);
 		}
@@ -825,7 +824,7 @@
 			return TCL_ERROR;
 		}
 		argsused = 2;
-		type = PURPLE_CONV_TYPE_IM;
+		is_chat = FALSE;
 		while (argsused < objc) {
 			opt = Tcl_GetString(objv[argsused]);
 			if (*opt == '-') {
@@ -835,10 +834,10 @@
 				argsused++;
 				switch (newopt) {
 				case CMD_CONV_NEW_CHAT:
-					type = PURPLE_CONV_TYPE_CHAT;
+					is_chat = TRUE;
 					break;
 				case CMD_CONV_NEW_IM:
-					type = PURPLE_CONV_TYPE_IM;
+					is_chat = FALSE;
 					break;
 				}
 			} else {
@@ -851,7 +850,10 @@
 		}
 		if ((account = tcl_validate_account(objv[argsused++], interp)) == NULL)
 			return TCL_ERROR;
-		convo = purple_conversation_new(type, account, Tcl_GetString(objv[argsused]));
+		if (is_chat)
+			convo = purple_chat_conversation_new(account, Tcl_GetString(objv[argsused]));
+		else
+			convo = purple_im_conversation_new(account, Tcl_GetString(objv[argsused]));
 		Tcl_SetObjResult(interp, purple_tcl_ref_new(PurpleTclRefConversation, convo));
 		break;
 	case CMD_CONV_WRITE:
@@ -868,20 +870,16 @@
 
 		switch (style) {
 		case CMD_CONV_WRITE_SEND:
-			flags = PURPLE_MESSAGE_SEND;
+			flags = PURPLE_CONVERSATION_MESSAGE_SEND;
 			break;
 		case CMD_CONV_WRITE_RECV:
-			flags = PURPLE_MESSAGE_RECV;
+			flags = PURPLE_CONVERSATION_MESSAGE_RECV;
 			break;
 		case CMD_CONV_WRITE_SYSTEM:
-			flags = PURPLE_MESSAGE_SYSTEM;
+			flags = PURPLE_CONVERSATION_MESSAGE_SYSTEM;
 			break;
 		}
-		if (purple_conversation_get_type(convo) == PURPLE_CONV_TYPE_CHAT)
-			purple_conv_chat_write(PURPLE_CONV_CHAT(convo), from, what, flags, time(NULL));
-		else
-			purple_conv_im_write(PURPLE_CONV_IM(convo), from, what, flags, time(NULL));
-		break;
+		purple_conversation_write_message(convo, from, what, flags, time(NULL));
 	case CMD_CONV_NAME:
 		if (objc != 3) {
 			Tcl_WrongNumArgs(interp, 2, objv, "conversation");
@@ -912,10 +910,7 @@
 		if ((convo = tcl_validate_conversation(objv[2], interp)) == NULL)
 			return TCL_ERROR;
 		what = Tcl_GetString(objv[3]);
-		if (purple_conversation_get_type(convo) == PURPLE_CONV_TYPE_CHAT)
-			purple_conv_chat_send(PURPLE_CONV_CHAT(convo), what);
-		else
-			purple_conv_im_send(PURPLE_CONV_IM(convo), what);
+		purple_conversation_send(convo, what);
 		break;
 	}
 
--- a/libpurple/privacy.c	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,411 +0,0 @@
-/**
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#include "internal.h"
-
-#include "account.h"
-#include "privacy.h"
-#include "server.h"
-#include "util.h"
-
-static PurplePrivacyUiOps *privacy_ops = NULL;
-
-gboolean
-purple_privacy_permit_add(PurpleAccount *account, const char *who,
-						gboolean local_only)
-{
-	GSList *l;
-	char *name;
-	PurpleBuddy *buddy;
-	PurpleBlistUiOps *blist_ops;
-
-	g_return_val_if_fail(account != NULL, FALSE);
-	g_return_val_if_fail(who     != NULL, FALSE);
-
-	name = g_strdup(purple_normalize(account, who));
-
-	for (l = account->permit; l != NULL; l = l->next) {
-		if (g_str_equal(name, l->data))
-			/* This buddy already exists */
-			break;
-	}
-
-	if (l != NULL)
-	{
-		/* This buddy already exists, so bail out */
-		g_free(name);
-		return FALSE;
-	}
-
-	account->permit = g_slist_append(account->permit, name);
-
-	if (!local_only && purple_account_is_connected(account))
-		serv_add_permit(purple_account_get_connection(account), who);
-
-	if (privacy_ops != NULL && privacy_ops->permit_added != NULL)
-		privacy_ops->permit_added(account, who);
-
-	blist_ops = purple_blist_get_ui_ops();
-	if (blist_ops != NULL && blist_ops->save_account != NULL)
-		blist_ops->save_account(account);
-
-	/* This lets the UI know a buddy has had its privacy setting changed */
-	buddy = purple_find_buddy(account, name);
-	if (buddy != NULL) {
-		purple_signal_emit(purple_blist_get_handle(),
-                "buddy-privacy-changed", buddy);
-	}
-	return TRUE;
-}
-
-gboolean
-purple_privacy_permit_remove(PurpleAccount *account, const char *who,
-						   gboolean local_only)
-{
-	GSList *l;
-	const char *name;
-	PurpleBuddy *buddy;
-	char *del;
-	PurpleBlistUiOps *blist_ops;
-
-	g_return_val_if_fail(account != NULL, FALSE);
-	g_return_val_if_fail(who     != NULL, FALSE);
-
-	name = purple_normalize(account, who);
-
-	for (l = account->permit; l != NULL; l = l->next) {
-		if (g_str_equal(name, l->data))
-			/* We found the buddy we were looking for */
-			break;
-	}
-
-	if (l == NULL)
-		/* We didn't find the buddy we were looking for, so bail out */
-		return FALSE;
-
-	/* We should not free l->data just yet. There can be occasions where
-	 * l->data == who. In such cases, freeing l->data here can cause crashes
-	 * later when who is used. */
-	del = l->data;
-	account->permit = g_slist_delete_link(account->permit, l);
-
-	if (!local_only && purple_account_is_connected(account))
-		serv_rem_permit(purple_account_get_connection(account), who);
-
-	if (privacy_ops != NULL && privacy_ops->permit_removed != NULL)
-		privacy_ops->permit_removed(account, who);
-
-	blist_ops = purple_blist_get_ui_ops();
-	if (blist_ops != NULL && blist_ops->save_account != NULL)
-		blist_ops->save_account(account);
-
-	buddy = purple_find_buddy(account, name);
-	if (buddy != NULL) {
-		purple_signal_emit(purple_blist_get_handle(),
-                "buddy-privacy-changed", buddy);
-	}
-	g_free(del);
-	return TRUE;
-}
-
-gboolean
-purple_privacy_deny_add(PurpleAccount *account, const char *who,
-					  gboolean local_only)
-{
-	GSList *l;
-	char *name;
-	PurpleBuddy *buddy;
-	PurpleBlistUiOps *blist_ops;
-
-	g_return_val_if_fail(account != NULL, FALSE);
-	g_return_val_if_fail(who     != NULL, FALSE);
-
-	name = g_strdup(purple_normalize(account, who));
-
-	for (l = account->deny; l != NULL; l = l->next) {
-		if (g_str_equal(name, l->data))
-			/* This buddy already exists */
-			break;
-	}
-
-	if (l != NULL)
-	{
-		/* This buddy already exists, so bail out */
-		g_free(name);
-		return FALSE;
-	}
-
-	account->deny = g_slist_append(account->deny, name);
-
-	if (!local_only && purple_account_is_connected(account))
-		serv_add_deny(purple_account_get_connection(account), who);
-
-	if (privacy_ops != NULL && privacy_ops->deny_added != NULL)
-		privacy_ops->deny_added(account, who);
-
-	blist_ops = purple_blist_get_ui_ops();
-	if (blist_ops != NULL && blist_ops->save_account != NULL)
-		blist_ops->save_account(account);
-
-	buddy = purple_find_buddy(account, name);
-	if (buddy != NULL) {
-		purple_signal_emit(purple_blist_get_handle(),
-                "buddy-privacy-changed", buddy);
-	}
-	return TRUE;
-}
-
-gboolean
-purple_privacy_deny_remove(PurpleAccount *account, const char *who,
-						 gboolean local_only)
-{
-	GSList *l;
-	const char *normalized;
-	char *name;
-	PurpleBuddy *buddy;
-	PurpleBlistUiOps *blist_ops;
-
-	g_return_val_if_fail(account != NULL, FALSE);
-	g_return_val_if_fail(who     != NULL, FALSE);
-
-	normalized = purple_normalize(account, who);
-
-	for (l = account->deny; l != NULL; l = l->next) {
-		if (g_str_equal(normalized, l->data))
-			/* We found the buddy we were looking for */
-			break;
-	}
-
-	if (l == NULL)
-		/* We didn't find the buddy we were looking for, so bail out */
-		return FALSE;
-
-	buddy = purple_find_buddy(account, normalized);
-
-	name = l->data;
-	account->deny = g_slist_delete_link(account->deny, l);
-
-	if (!local_only && purple_account_is_connected(account))
-		serv_rem_deny(purple_account_get_connection(account), name);
-
-	if (privacy_ops != NULL && privacy_ops->deny_removed != NULL)
-		privacy_ops->deny_removed(account, who);
-
-	if (buddy != NULL) {
-		purple_signal_emit(purple_blist_get_handle(),
-                "buddy-privacy-changed", buddy);
-	}
-
-	g_free(name);
-
-	blist_ops = purple_blist_get_ui_ops();
-	if (blist_ops != NULL && blist_ops->save_account != NULL)
-		blist_ops->save_account(account);
-
-	return TRUE;
-}
-
-/**
- * This makes sure your permit list contains all buddies from your
- * buddy list and ONLY buddies from your buddy list.
- */
-static void
-add_all_buddies_to_permit_list(PurpleAccount *account, gboolean local)
-{
-	GSList *list;
-
-	/* Remove anyone in the permit list who is not in the buddylist */
-	for (list = account->permit; list != NULL; ) {
-		char *person = list->data;
-		list = list->next;
-		if (!purple_find_buddy(account, person))
-			purple_privacy_permit_remove(account, person, local);
-	}
-
-	/* Now make sure everyone in the buddylist is in the permit list */
-	list = purple_find_buddies(account, NULL);
-	while (list != NULL)
-	{
-		PurpleBuddy *buddy = list->data;
-		const gchar *name = purple_buddy_get_name(buddy);
-
-		if (!g_slist_find_custom(account->permit, name, (GCompareFunc)g_utf8_collate))
-			purple_privacy_permit_add(account, name, local);
-		list = g_slist_delete_link(list, list);
-	}
-}
-
-/*
- * TODO: All callers of this function pass in FALSE for local and
- *       restore and I don't understand when you would ever want to
- *       use TRUE for either of them.  I think both parameters could
- *       safely be removed in the next major version bump.
- */
-void
-purple_privacy_allow(PurpleAccount *account, const char *who, gboolean local,
-						gboolean restore)
-{
-	GSList *list;
-	PurplePrivacyType type = purple_account_get_privacy_type(account);
-
-	switch (type) {
-		case PURPLE_PRIVACY_ALLOW_ALL:
-			return;
-		case PURPLE_PRIVACY_ALLOW_USERS:
-			purple_privacy_permit_add(account, who, local);
-			break;
-		case PURPLE_PRIVACY_DENY_USERS:
-			purple_privacy_deny_remove(account, who, local);
-			break;
-		case PURPLE_PRIVACY_DENY_ALL:
-			if (!restore) {
-				/* Empty the allow-list. */
-				const char *norm = purple_normalize(account, who);
-				for (list = account->permit; list != NULL;) {
-					char *person = list->data;
-					list = list->next;
-					if (!purple_strequal(norm, person))
-						purple_privacy_permit_remove(account, person, local);
-				}
-			}
-			purple_privacy_permit_add(account, who, local);
-			purple_account_set_privacy_type(account, PURPLE_PRIVACY_ALLOW_USERS);
-			break;
-		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
-			if (!purple_find_buddy(account, who)) {
-				add_all_buddies_to_permit_list(account, local);
-				purple_privacy_permit_add(account, who, local);
-				purple_account_set_privacy_type(account, PURPLE_PRIVACY_ALLOW_USERS);
-			}
-			break;
-		default:
-			g_return_if_reached();
-	}
-
-	/* Notify the server if the privacy setting was changed */
-	if (type != purple_account_get_privacy_type(account) && purple_account_is_connected(account))
-		serv_set_permit_deny(purple_account_get_connection(account));
-}
-
-/*
- * TODO: All callers of this function pass in FALSE for local and
- *       restore and I don't understand when you would ever want to
- *       use TRUE for either of them.  I think both parameters could
- *       safely be removed in the next major version bump.
- */
-void
-purple_privacy_deny(PurpleAccount *account, const char *who, gboolean local,
-					gboolean restore)
-{
-	GSList *list;
-	PurplePrivacyType type = purple_account_get_privacy_type(account);
-
-	switch (type) {
-		case PURPLE_PRIVACY_ALLOW_ALL:
-			if (!restore) {
-				/* Empty the deny-list. */
-				const char *norm = purple_normalize(account, who);
-				for (list = account->deny; list != NULL; ) {
-					char *person = list->data;
-					list = list->next;
-					if (!purple_strequal(norm, person))
-						purple_privacy_deny_remove(account, person, local);
-				}
-			}
-			purple_privacy_deny_add(account, who, local);
-			purple_account_set_privacy_type(account, PURPLE_PRIVACY_DENY_USERS);
-			break;
-		case PURPLE_PRIVACY_ALLOW_USERS:
-			purple_privacy_permit_remove(account, who, local);
-			break;
-		case PURPLE_PRIVACY_DENY_USERS:
-			purple_privacy_deny_add(account, who, local);
-			break;
-		case PURPLE_PRIVACY_DENY_ALL:
-			break;
-		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
-			if (purple_find_buddy(account, who)) {
-				add_all_buddies_to_permit_list(account, local);
-				purple_privacy_permit_remove(account, who, local);
-				purple_account_set_privacy_type(account, PURPLE_PRIVACY_ALLOW_USERS);
-			}
-			break;
-		default:
-			g_return_if_reached();
-	}
-
-	/* Notify the server if the privacy setting was changed */
-	if (type != purple_account_get_privacy_type(account) && purple_account_is_connected(account))
-		serv_set_permit_deny(purple_account_get_connection(account));
-}
-
-gboolean
-purple_privacy_check(PurpleAccount *account, const char *who)
-{
-	GSList *list;
-
-	switch (purple_account_get_privacy_type(account)) {
-		case PURPLE_PRIVACY_ALLOW_ALL:
-			return TRUE;
-
-		case PURPLE_PRIVACY_DENY_ALL:
-			return FALSE;
-
-		case PURPLE_PRIVACY_ALLOW_USERS:
-			who = purple_normalize(account, who);
-			for (list=account->permit; list!=NULL; list=list->next) {
-				if (g_str_equal(who, list->data))
-					return TRUE;
-			}
-			return FALSE;
-
-		case PURPLE_PRIVACY_DENY_USERS:
-			who = purple_normalize(account, who);
-			for (list=account->deny; list!=NULL; list=list->next) {
-				if (g_str_equal(who, list->data))
-					return FALSE;
-			}
-			return TRUE;
-
-		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
-			return (purple_find_buddy(account, who) != NULL);
-
-		default:
-			g_return_val_if_reached(TRUE);
-	}
-}
-
-void
-purple_privacy_set_ui_ops(PurplePrivacyUiOps *ops)
-{
-	privacy_ops = ops;
-}
-
-PurplePrivacyUiOps *
-purple_privacy_get_ui_ops(void)
-{
-	return privacy_ops;
-}
-
-void
-purple_privacy_init(void)
-{
-}
--- a/libpurple/privacy.h	Sun Jun 23 02:43:06 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
-/**
- * @file privacy.h Privacy API
- * @ingroup core
- */
-
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#ifndef _PURPLE_PRIVACY_H_
-#define _PURPLE_PRIVACY_H_
-
-/**
- * Privacy data types.
- */
-typedef enum
-{
-	PURPLE_PRIVACY_ALLOW_ALL = 1,
-	PURPLE_PRIVACY_DENY_ALL,
-	PURPLE_PRIVACY_ALLOW_USERS,
-	PURPLE_PRIVACY_DENY_USERS,
-	PURPLE_PRIVACY_ALLOW_BUDDYLIST
-} PurplePrivacyType;
-
-#include "account.h"
-
-/**
- * Privacy core/UI operations.
- */
-typedef struct
-{
-	void (*permit_added)(PurpleAccount *account, const char *name);
-	void (*permit_removed)(PurpleAccount *account, const char *name);
-	void (*deny_added)(PurpleAccount *account, const char *name);
-	void (*deny_removed)(PurpleAccount *account, const char *name);
-
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-} PurplePrivacyUiOps;
-
-G_BEGIN_DECLS
-
-/**
- * Adds a user to the account's permit list.
- *
- * @param account    The account.
- * @param name       The name of the user to add to the list.
- * @param local_only If TRUE, only the local list is updated, and not
- *                   the server.
- *
- * @return TRUE if the user was added successfully, or @c FALSE otherwise.
- */
-gboolean purple_privacy_permit_add(PurpleAccount *account, const char *name,
-								 gboolean local_only);
-
-/**
- * Removes a user from the account's permit list.
- *
- * @param account    The account.
- * @param name       The name of the user to add to the list.
- * @param local_only If TRUE, only the local list is updated, and not
- *                   the server.
- *
- * @return TRUE if the user was removed successfully, or @c FALSE otherwise.
- */
-gboolean purple_privacy_permit_remove(PurpleAccount *account, const char *name,
-									gboolean local_only);
-
-/**
- * Adds a user to the account's deny list.
- *
- * @param account    The account.
- * @param name       The name of the user to add to the list.
- * @param local_only If TRUE, only the local list is updated, and not
- *                   the server.
- *
- * @return TRUE if the user was added successfully, or @c FALSE otherwise.
- */
-gboolean purple_privacy_deny_add(PurpleAccount *account, const char *name,
-							   gboolean local_only);
-
-/**
- * Removes a user from the account's deny list.
- *
- * @param account    The account.
- * @param name       The name of the user to add to the list.
- * @param local_only If TRUE, only the local list is updated, and not
- *                   the server.
- *
- * @return TRUE if the user was removed successfully, or @c FALSE otherwise.
- */
-gboolean purple_privacy_deny_remove(PurpleAccount *account, const char *name,
-								  gboolean local_only);
-
-/**
- * Allow a user to send messages. If current privacy setting for the account is:
- *		PURPLE_PRIVACY_ALLOW_USERS:	The user is added to the allow-list.
- *		PURPLE_PRIVACY_DENY_USERS	:	The user is removed from the deny-list.
- *		PURPLE_PRIVACY_ALLOW_ALL	:	No changes made.
- *		PURPLE_PRIVACY_DENY_ALL	:	The privacy setting is changed to
- *									PURPLE_PRIVACY_ALLOW_USERS and the user
- *									is added to the allow-list.
- *		PURPLE_PRIVACY_ALLOW_BUDDYLIST: No changes made if the user is already in
- *									the buddy-list. Otherwise the setting is
- *									changed to PURPLE_PRIVACY_ALLOW_USERS, all the
- *									buddies are added to the allow-list, and the
- *									user is also added to the allow-list.
- *
- * @param account	The account.
- * @param who		The name of the user.
- * @param local		Whether the change is local-only.
- * @param restore	Should the previous allow/deny list be restored if the
- *					privacy setting is changed.
- */
-void purple_privacy_allow(PurpleAccount *account, const char *who, gboolean local,
-						gboolean restore);
-
-/**
- * Block messages from a user. If current privacy setting for the account is:
- *		PURPLE_PRIVACY_ALLOW_USERS:	The user is removed from the allow-list.
- *		PURPLE_PRIVACY_DENY_USERS	:	The user is added to the deny-list.
- *		PURPLE_PRIVACY_DENY_ALL	:	No changes made.
- *		PURPLE_PRIVACY_ALLOW_ALL	:	The privacy setting is changed to
- *									PURPLE_PRIVACY_DENY_USERS and the user is
- *									added to the deny-list.
- *		PURPLE_PRIVACY_ALLOW_BUDDYLIST: If the user is not in the buddy-list,
- *									then no changes made. Otherwise, the setting
- *									is changed to PURPLE_PRIVACY_ALLOW_USERS, all
- *									the buddies are added to the allow-list, and
- *									this user is removed from the list.
- *
- * @param account	The account.
- * @param who		The name of the user.
- * @param local		Whether the change is local-only.
- * @param restore	Should the previous allow/deny list be restored if the
- *					privacy setting is changed.
- */
-void purple_privacy_deny(PurpleAccount *account, const char *who, gboolean local,
-						gboolean restore);
-
-/**
- * Check the privacy-setting for a user.
- *
- * @param account	The account.
- * @param who		The name of the user.
- *
- * @return @c FALSE if the specified account's privacy settings block the user or @c TRUE otherwise. The meaning of "block" is protocol-dependent and generally relates to status and/or sending of messages.
- */
-gboolean purple_privacy_check(PurpleAccount *account, const char *who);
-
-/**
- * Sets the UI operations structure for the privacy subsystem.
- *
- * @param ops The UI operations structure.
- */
-void purple_privacy_set_ui_ops(PurplePrivacyUiOps *ops);
-
-/**
- * Returns the UI operations structure for the privacy subsystem.
- *
- * @return The UI operations structure.
- */
-PurplePrivacyUiOps *purple_privacy_get_ui_ops(void);
-
-/**
- * Initializes the privacy subsystem.
- */
-void purple_privacy_init(void);
-
-G_END_DECLS
-
-#endif /* _PURPLE_PRIVACY_H_ */
--- a/libpurple/protocols/bonjour/bonjour_ft.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Sun Jun 23 13:35:53 2013 +0530
@@ -28,7 +28,7 @@
 #include "buddy.h"
 #include "bonjour.h"
 #include "bonjour_ft.h"
-#include "cipher.h"
+#include "ciphers/sha1hash.h"
 
 static void
 bonjour_bytestreams_init(PurpleXfer *xfer);
@@ -1018,6 +1018,7 @@
 {
 	PurpleBuddy *pb;
 	PurpleAccount *account = NULL;
+	PurpleHash *hash;
 	XepXfer *xf;
 	char dstaddr[41];
 	const gchar *name = NULL;
@@ -1039,8 +1040,12 @@
 	account = purple_buddy_get_account(pb);
 
 	p = g_strdup_printf("%s%s%s", xf->sid, name, bonjour_get_jid(account));
-	purple_cipher_digest_region("sha1", (guchar *)p, strlen(p), hashval,
-		sizeof(hashval));
+
+	hash = purple_sha1_hash_new();
+	purple_hash_append(hash, (guchar *)p, strlen(p));
+	purple_hash_digest(hash, hashval, sizeof(hashval));
+	g_object_unref(G_OBJECT(hash));
+
 	g_free(p);
 
 	memset(dstaddr, 0, 41);
--- a/libpurple/protocols/bonjour/jabber.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/bonjour/jabber.c	Sun Jun 23 13:35:53 2013 +0530
@@ -89,7 +89,7 @@
 
 	BonjourJabberConversation *bconv = g_new0(BonjourJabberConversation, 1);
 	bconv->socket = -1;
-	bconv->tx_buf = purple_circ_buffer_new(512);
+	bconv->tx_buf = purple_circular_buffer_new(512);
 	bconv->tx_handler = 0;
 	bconv->rx_handler = 0;
 	bconv->pb = pb;
@@ -280,7 +280,7 @@
 	BonjourJabberConversation *bconv = bb->conversation;
 	int ret, writelen;
 
-	writelen = purple_circ_buffer_get_max_read(bconv->tx_buf);
+	writelen = purple_circular_buffer_get_max_read(bconv->tx_buf);
 
 	if (writelen == 0) {
 		purple_input_remove(bconv->tx_handler);
@@ -288,7 +288,7 @@
 		return;
 	}
 
-	ret = send(bconv->socket, bconv->tx_buf->outptr, writelen, 0);
+	ret = send(bconv->socket, purple_circular_buffer_get_output(bconv->tx_buf), writelen, 0);
 
 	if (ret < 0 && errno == EAGAIN)
 		return;
@@ -313,7 +313,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(bconv->tx_buf, ret);
+	purple_circular_buffer_mark_read(bconv->tx_buf, ret);
 }
 
 static gint
@@ -329,7 +329,7 @@
 			|| bconv->connect_data != NULL
 			|| bconv->sent_stream_start != FULLY_SENT
 			|| !bconv->recv_stream_start
-			|| purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) {
+			|| purple_circular_buffer_get_max_read(bconv->tx_buf) > 0) {
 		ret = -1;
 		errno = EAGAIN;
 	} else {
@@ -364,7 +364,7 @@
 		if (bconv->sent_stream_start == FULLY_SENT && bconv->recv_stream_start && bconv->tx_handler == 0)
 			bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE,
 				_send_data_write_cb, pb);
-		purple_circ_buffer_append(bconv->tx_buf, message + ret, len - ret);
+		purple_circular_buffer_append(bconv->tx_buf, message + ret, len - ret);
 	}
 
 	return ret;
@@ -616,7 +616,7 @@
 	/* If the stream has been completely started and we know who we're talking to, we can start doing stuff. */
 	/* I don't think the circ_buffer can actually contain anything without a buddy being associated, but lets be explicit. */
 	if (bconv->sent_stream_start == FULLY_SENT && bconv->recv_stream_start
-			&& bconv->pb && purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) {
+			&& bconv->pb && purple_circular_buffer_get_max_read(bconv->tx_buf) > 0) {
 		/* Watch for when we can write the buffered messages */
 		bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE,
 			_send_data_write_cb, bconv->pb);
@@ -1189,7 +1189,7 @@
 			purple_input_remove(bconv->tx_handler);
 
 		/* Free all the data related to the conversation */
-		purple_circ_buffer_destroy(bconv->tx_buf);
+		g_object_unref(G_OBJECT(bconv->tx_buf));
 		if (bconv->connect_data != NULL)
 			purple_proxy_connect_cancel(bconv->connect_data);
 		if (bconv->stream_data != NULL) {
@@ -1303,7 +1303,7 @@
 
 	acc = purple_buddy_get_account(pb);
 
-	for(l = acc->deny; l != NULL; l = l->next) {
+	for(l = purple_account_privacy_get_denied(acc); l != NULL; l = l->next) {
 		const gchar *name = purple_buddy_get_name(pb);
 		const gchar *username = bonjour_get_jid(acc);
 
--- a/libpurple/protocols/bonjour/jabber.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/bonjour/jabber.h	Sun Jun 23 13:35:53 2013 +0530
@@ -31,7 +31,7 @@
 #include "xmlnode.h"
 
 #include "account.h"
-#include "circbuffer.h"
+#include "circularbuffer.h"
 
 typedef struct _BonjourJabber
 {
@@ -50,7 +50,7 @@
 	guint rx_handler;
 	guint tx_handler;
 	guint close_timeout;
-	PurpleCircBuffer *tx_buf;
+	PurpleCircularBuffer *tx_buf;
 	int sent_stream_start; /* 0 = Unsent, 1 = Partial, 2 = Complete */
 	gboolean recv_stream_start;
 	PurpleProxyConnectData *connect_data;
--- a/libpurple/protocols/gg/oauth/oauth.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/gg/oauth/oauth.c	Sun Jun 23 13:35:53 2013 +0530
@@ -26,7 +26,8 @@
 #include "oauth.h"
 
 #include "oauth-parameter.h"
-#include <cipher.h>
+#include "ciphers/hmaccipher.h"
+#include "ciphers/sha1hash.h"
 
 char *gg_oauth_static_nonce;		/* dla unit testów */
 char *gg_oauth_static_timestamp;	/* dla unit testów */
@@ -48,15 +49,19 @@
 
 static gchar *gg_hmac_sha1(const char *key, const char *message)
 {
-	PurpleCipherContext *context;
+	PurpleCipher *cipher;
+	PurpleHash *hash;
 	guchar digest[20];
-	
-	context = purple_cipher_context_new_by_name("hmac", NULL);
-	purple_cipher_context_set_option(context, "hash", "sha1");
-	purple_cipher_context_set_key(context, (guchar *)key, strlen(key));
-	purple_cipher_context_append(context, (guchar *)message, strlen(message));
-	purple_cipher_context_digest(context, digest, sizeof(digest));
-	purple_cipher_context_destroy(context);
+
+	hash = purple_sha1_hash_new();
+	cipher = purple_hmac_cipher_new(hash);
+
+	purple_cipher_set_key(cipher, (guchar *)key, strlen(key));
+	purple_cipher_append(cipher, (guchar *)message, strlen(message));
+	purple_cipher_digest(cipher, digest, sizeof(digest));
+
+	g_object_unref(cipher);
+	g_object_unref(hash);
 	
 	return purple_base64_encode(digest, sizeof(digest));
 }
--- a/libpurple/protocols/irc/irc.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/irc/irc.c	Sun Jun 23 13:35:53 2013 +0530
@@ -111,8 +111,9 @@
 {
 	struct irc_conn *irc = data;
 	int ret, writelen;
+	const gchar *buffer = NULL;
 
-	writelen = purple_circ_buffer_get_max_read(irc->outbuf);
+	writelen = purple_circular_buffer_get_max_read(irc->outbuf);
 
 	if (writelen == 0) {
 		purple_input_remove(irc->writeh);
@@ -120,7 +121,9 @@
 		return;
 	}
 
-	ret = do_send(irc, irc->outbuf->outptr, writelen);
+	buffer = purple_circular_buffer_get_output(irc->outbuf);
+
+	ret = do_send(irc, buffer, writelen);
 
 	if (ret < 0 && errno == EAGAIN)
 		return;
@@ -134,7 +137,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(irc->outbuf, ret);
+	purple_circular_buffer_mark_read(irc->outbuf, ret);
 
 #if 0
 	/* We *could* try to write more if we wrote it all */
@@ -183,7 +186,7 @@
 			irc->writeh = purple_input_add(
 				irc->gsc ? irc->gsc->fd : irc->fd,
 				PURPLE_INPUT_WRITE, irc_send_cb, irc);
-		purple_circ_buffer_append(irc->outbuf, tosend + ret,
+		purple_circular_buffer_append(irc->outbuf, tosend + ret,
 			buflen - ret);
 	}
 	g_free(tosend);
@@ -345,7 +348,7 @@
 	purple_connection_set_protocol_data(gc, irc);
 	irc->fd = -1;
 	irc->account = account;
-	irc->outbuf = purple_circ_buffer_new(512);
+	irc->outbuf = purple_circular_buffer_new(512);
 
 	userparts = g_strsplit(username, "@", 2);
 	purple_connection_set_display_name(gc, userparts[0]);
@@ -533,7 +536,7 @@
 	if (irc->writeh)
 		purple_input_remove(irc->writeh);
 
-	purple_circ_buffer_destroy(irc->outbuf);
+	g_object_unref(G_OBJECT(irc->outbuf));
 
 	g_free(irc->mode_chars);
 	g_free(irc->reqnick);
--- a/libpurple/protocols/irc/irc.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/irc/irc.h	Sun Jun 23 13:35:53 2013 +0530
@@ -29,7 +29,7 @@
 #include <sasl/sasl.h>
 #endif
 
-#include "circbuffer.h"
+#include "circularbuffer.h"
 #include "ft.h"
 #include "roomlist.h"
 #include "sslconn.h"
@@ -89,7 +89,7 @@
 
 	gboolean quitting;
 
-	PurpleCircBuffer *outbuf;
+	PurpleCircularBuffer *outbuf;
 	guint writeh;
 
 	time_t recv_time;
--- a/libpurple/protocols/jabber/auth.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/auth.c	Sun Jun 23 13:35:53 2013 +0530
@@ -24,7 +24,6 @@
 
 #include "account.h"
 #include "debug.h"
-#include "cipher.h"
 #include "core.h"
 #include "conversation.h"
 #include "request.h"
@@ -39,6 +38,9 @@
 #include "iq.h"
 #include "notify.h"
 
+#include "ciphers/hmaccipher.h"
+#include "ciphers/md5hash.h"
+
 static GSList *auth_mechs = NULL;
 
 static void auth_old_result_cb(JabberStream *js, const char *from,
@@ -276,16 +278,18 @@
 			 */
 			const char *challenge;
 			gchar digest[33];
-			PurpleCipherContext *hmac;
+			PurpleCipher *hmac;
+			PurpleHash *md5;
 
 			/* Calculate the MHAC-MD5 digest */
+			md5 = purple_md5_hash_new();
+			hmac = purple_hmac_cipher_new(md5);
 			challenge = xmlnode_get_attrib(x, "challenge");
-			hmac = purple_cipher_context_new_by_name("hmac", NULL);
-			purple_cipher_context_set_option(hmac, "hash", "md5");
-			purple_cipher_context_set_key(hmac, (guchar *)pw, strlen(pw));
-			purple_cipher_context_append(hmac, (guchar *)challenge, strlen(challenge));
-			purple_cipher_context_digest_to_str(hmac, digest, 33);
-			purple_cipher_context_destroy(hmac);
+			purple_cipher_set_key(hmac, (guchar *)pw, strlen(pw));
+			purple_cipher_append(hmac, (guchar *)challenge, strlen(challenge));
+			purple_cipher_digest_to_str(hmac, digest, 33);
+			g_object_unref(hmac);
+			g_object_unref(md5);
 
 			/* Create the response query */
 			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
--- a/libpurple/protocols/jabber/auth_digest_md5.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/auth_digest_md5.c	Sun Jun 23 13:35:53 2013 +0530
@@ -23,7 +23,7 @@
 #include "internal.h"
 
 #include "debug.h"
-#include "cipher.h"
+#include "ciphers/md5hash.h"
 #include "util.h"
 #include "xmlnode.h"
 
@@ -106,8 +106,7 @@
 generate_response_value(JabberID *jid, const char *passwd, const char *nonce,
 		const char *cnonce, const char *a2, const char *realm)
 {
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
+	PurpleHash *hash;
 	guchar result[16];
 	size_t a1len;
 
@@ -122,35 +121,34 @@
 		convpasswd = g_strdup(passwd);
 	}
 
-	cipher = purple_ciphers_find_cipher("md5");
-	context = purple_cipher_context_new(cipher, NULL);
+	hash = purple_md5_hash_new();
 
 	x = g_strdup_printf("%s:%s:%s", convnode, realm, convpasswd ? convpasswd : "");
-	purple_cipher_context_append(context, (const guchar *)x, strlen(x));
-	purple_cipher_context_digest(context, result, sizeof(result));
+	purple_hash_append(hash, (const guchar *)x, strlen(x));
+	purple_hash_digest(hash, result, sizeof(result));
 
 	a1 = g_strdup_printf("xxxxxxxxxxxxxxxx:%s:%s", nonce, cnonce);
 	a1len = strlen(a1);
 	g_memmove(a1, result, 16);
 
-	purple_cipher_context_reset(context, NULL);
-	purple_cipher_context_append(context, (const guchar *)a1, a1len);
-	purple_cipher_context_digest(context, result, sizeof(result));
+	purple_hash_reset(hash);
+	purple_hash_append(hash, (const guchar *)a1, a1len);
+	purple_hash_digest(hash, result, sizeof(result));
 
 	ha1 = purple_base16_encode(result, 16);
 
-	purple_cipher_context_reset(context, NULL);
-	purple_cipher_context_append(context, (const guchar *)a2, strlen(a2));
-	purple_cipher_context_digest(context, result, sizeof(result));
+	purple_hash_reset(hash);
+	purple_hash_append(hash, (const guchar *)a2, strlen(a2));
+	purple_hash_digest(hash, result, sizeof(result));
 
 	ha2 = purple_base16_encode(result, 16);
 
 	kd = g_strdup_printf("%s:%s:00000001:%s:auth:%s", ha1, nonce, cnonce, ha2);
 
-	purple_cipher_context_reset(context, NULL);
-	purple_cipher_context_append(context, (const guchar *)kd, strlen(kd));
-	purple_cipher_context_digest(context, result, sizeof(result));
-	purple_cipher_context_destroy(context);
+	purple_hash_reset(hash);
+	purple_hash_append(hash, (const guchar *)kd, strlen(kd));
+	purple_hash_digest(hash, result, sizeof(result));
+	g_object_unref(hash);
 
 	z = purple_base16_encode(result, 16);
 
--- a/libpurple/protocols/jabber/auth_scram.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/auth_scram.c	Sun Jun 23 13:35:53 2013 +0530
@@ -25,11 +25,12 @@
 #include "auth.h"
 #include "auth_scram.h"
 
-#include "cipher.h"
+#include "ciphers/hmaccipher.h"
+#include "ciphers/sha1hash.h"
 #include "debug.h"
 
 static const JabberScramHash hashes[] = {
-	{ "-SHA-1", "sha1", 20 },
+	{ "-SHA-1", purple_sha1_hash_new, 20 },
 };
 
 static const JabberScramHash *mech_to_hash(const char *mech)
@@ -76,7 +77,8 @@
 guchar *jabber_scram_hi(const JabberScramHash *hash, const GString *str,
                         GString *salt, guint iterations)
 {
-	PurpleCipherContext *context;
+	PurpleHash *hasher;
+	PurpleCipher *cipher;
 	guchar *result;
 	guint i;
 	guchar *prev, *tmp;
@@ -90,27 +92,28 @@
 	tmp    = g_new0(guint8, hash->size);
 	result = g_new0(guint8, hash->size);
 
-	context = purple_cipher_context_new_by_name("hmac", NULL);
+	hasher = hash->new_cipher();
+	cipher = purple_hmac_cipher_new(hasher);
+	g_object_unref(G_OBJECT(hasher));
 
 	/* Append INT(1), a four-octet encoding of the integer 1, most significant
 	 * octet first. */
 	g_string_append_len(salt, "\0\0\0\1", 4);
 
 	/* Compute U0 */
-	purple_cipher_context_set_option(context, "hash", (gpointer)hash->name);
-	purple_cipher_context_set_key(context, (guchar *)str->str, str->len);
-	purple_cipher_context_append(context, (guchar *)salt->str, salt->len);
-	purple_cipher_context_digest(context, result, hash->size);
+	purple_cipher_set_key(cipher, (guchar *)str->str, str->len);
+	purple_cipher_append(cipher, (guchar *)salt->str, salt->len);
+	purple_cipher_digest(cipher, result, hash->size);
 
 	memcpy(prev, result, hash->size);
 
 	/* Compute U1...Ui */
 	for (i = 1; i < iterations; ++i) {
 		guint j;
-		purple_cipher_context_set_option(context, "hash", (gpointer)hash->name);
-		purple_cipher_context_set_key(context, (guchar *)str->str, str->len);
-		purple_cipher_context_append(context, prev, hash->size);
-		purple_cipher_context_digest(context, tmp, hash->size);
+		purple_cipher_reset(cipher);
+		purple_cipher_set_key(cipher, (guchar *)str->str, str->len);
+		purple_cipher_append(cipher, prev, hash->size);
+		purple_cipher_digest(cipher, tmp, hash->size);
 
 		for (j = 0; j < hash->size; ++j)
 			result[j] ^= tmp[j];
@@ -118,7 +121,7 @@
 		memcpy(prev, tmp, hash->size);
 	}
 
-	purple_cipher_context_destroy(context);
+	g_object_unref(G_OBJECT(cipher));
 	g_free(tmp);
 	g_free(prev);
 	return result;
@@ -136,25 +139,27 @@
 static void
 hmac(const JabberScramHash *hash, guchar *out, const guchar *key, const gchar *str)
 {
-	PurpleCipherContext *context;
+	PurpleHash *hasher;
+	PurpleCipher *cipher;
 
-	context = purple_cipher_context_new_by_name("hmac", NULL);
-	purple_cipher_context_set_option(context, "hash", (gpointer)hash->name);
-	purple_cipher_context_set_key(context, key, hash->size);
-	purple_cipher_context_append(context, (guchar *)str, strlen(str));
-	purple_cipher_context_digest(context, out, hash->size);
-	purple_cipher_context_destroy(context);
+	hasher = hash->new_cipher();
+	cipher = purple_hmac_cipher_new(hasher);
+	g_object_unref(G_OBJECT(hasher));
+	purple_cipher_set_key(cipher, key, hash->size);
+	purple_cipher_append(cipher, (guchar *)str, strlen(str));
+	purple_cipher_digest(cipher, out, hash->size);
+	g_object_unref(G_OBJECT(cipher));
 }
 
 static void
 hash(const JabberScramHash *hash, guchar *out, const guchar *data)
 {
-	PurpleCipherContext *context;
+	PurpleHash *hasher;
 
-	context = purple_cipher_context_new_by_name(hash->name, NULL);
-	purple_cipher_context_append(context, data, hash->size);
-	purple_cipher_context_digest(context, out, hash->size);
-	purple_cipher_context_destroy(context);
+	hasher = hash->new_cipher();
+	purple_hash_append(hasher, data, hash->size);
+	purple_hash_digest(hasher, out, hash->size);
+	g_object_unref(G_OBJECT(hasher));
 }
 
 gboolean
--- a/libpurple/protocols/jabber/auth_scram.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/auth_scram.h	Sun Jun 23 13:35:53 2013 +0530
@@ -29,12 +29,14 @@
  * DO NOT USE ANYTHING HERE OR YOU WILL BE SENT TO THE PIT OF DESPAIR.
  */
 
+#include "hash.h"
+
 /* Per-connection state stored between messages.
  * This is stored in js->auth_data_mech.
  */
 typedef struct {
 	const char *mech_substr;
-	const char *name;
+	PurpleHash *(*new_cipher)(void);
 	guint size;
 } JabberScramHash;
 
--- a/libpurple/protocols/jabber/bosh.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/bosh.c	Sun Jun 23 13:35:53 2013 +0530
@@ -21,7 +21,7 @@
  *
  */
 #include "internal.h"
-#include "circbuffer.h"
+#include "circularbuffer.h"
 #include "core.h"
 #include "cipher.h"
 #include "debug.h"
@@ -56,7 +56,7 @@
 	JabberStream *js;
 	PurpleHTTPConnection *connections[NUM_HTTP_CONNECTIONS];
 
-	PurpleCircBuffer *pending;
+	PurpleCircularBuffer *pending;
 	PurpleBOSHConnectionConnectFunction connect_cb;
 	PurpleBOSHConnectionReceiveFunction receive_cb;
 
@@ -91,7 +91,7 @@
 	PurpleBOSHConnection *bosh;
 	PurpleSslConnection *psc;
 
-	PurpleCircBuffer *write_buf;
+	PurpleCircularBuffer *write_buf;
 	GString *read_buf;
 
 	gsize handled_len;
@@ -169,7 +169,7 @@
 	conn->fd = -1;
 	conn->state = HTTP_CONN_OFFLINE;
 
-	conn->write_buf = purple_circ_buffer_new(0 /* default grow size */);
+	conn->write_buf = purple_circular_buffer_new(0 /* default grow size */);
 
 	return conn;
 }
@@ -181,7 +181,7 @@
 		g_string_free(conn->read_buf, TRUE);
 
 	if (conn->write_buf)
-		purple_circ_buffer_destroy(conn->write_buf);
+		g_object_unref(G_OBJECT(conn->write_buf));
 	if (conn->readh)
 		purple_input_remove(conn->readh);
 	if (conn->writeh)
@@ -239,7 +239,7 @@
 	conn->rid = ((guint64)g_random_int() << 32) | g_random_int();
 	conn->rid &= 0xFFFFFFFFFFFFFLL;
 
-	conn->pending = purple_circ_buffer_new(0 /* default grow size */);
+	conn->pending = purple_circular_buffer_new(0 /* default grow size */);
 
 	conn->state = BOSH_CONN_OFFLINE;
 	if (purple_strcasestr(url, "https://") != NULL)
@@ -263,7 +263,7 @@
 	if (conn->send_timer)
 		purple_timeout_remove(conn->send_timer);
 
-	purple_circ_buffer_destroy(conn->pending);
+	g_object_unref(G_OBJECT(conn->pending));
 
 	for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) {
 		if (conn->connections[i])
@@ -350,11 +350,14 @@
 		 * the buffer.
 		 */
 		if (data)
-			purple_circ_buffer_append(conn->pending, data, strlen(data));
+			purple_circular_buffer_append(conn->pending, data, strlen(data));
 
-		if (purple_debug_is_verbose())
+		if (purple_debug_is_verbose()) {
+			gsize bufused = purple_circular_buffer_get_used(conn->pending);
 			purple_debug_misc("jabber", "bosh: %p has %" G_GSIZE_FORMAT " bytes in "
-			                  "the buffer.\n", conn, conn->pending->bufused);
+			                  "the buffer.\n", conn, bufused);
+		}
+
 		if (conn->send_timer == 0)
 			conn->send_timer = purple_timeout_add_seconds(BUFFER_SEND_IN_SECS,
 					send_timer_cb, conn);
@@ -409,9 +412,10 @@
 
 		packet = g_string_append_c(packet, '>');
 
-		while ((read_amt = purple_circ_buffer_get_max_read(conn->pending)) > 0) {
-			packet = g_string_append_len(packet, conn->pending->outptr, read_amt);
-			purple_circ_buffer_mark_read(conn->pending, read_amt);
+		while ((read_amt = purple_circular_buffer_get_max_read(conn->pending)) > 0) {
+			const gchar *output = purple_circular_buffer_get_output(conn->pending);
+			packet = g_string_append_len(packet, output, read_amt);
+			purple_circular_buffer_mark_read(conn->pending, read_amt);
 		}
 
 		if (data)
@@ -678,7 +682,7 @@
 		jabber_bosh_connection_send(conn->bosh, PACKET_NORMAL, NULL);
 	else if (conn->bosh->state == BOSH_CONN_ONLINE) {
 		purple_debug_info("jabber", "BOSH session already exists. Trying to reuse it.\n");
-		if (conn->bosh->requests == 0 || conn->bosh->pending->bufused > 0) {
+		if (conn->bosh->requests == 0 || purple_circular_buffer_get_used(conn->bosh->pending) > 0) {
 			/* Send the pending data */
 			jabber_bosh_connection_send(conn->bosh, PACKET_FLUSH, NULL);
 		}
@@ -832,7 +836,9 @@
 	}
 
 	if (conn->bosh->state == BOSH_CONN_ONLINE &&
-			(conn->bosh->requests == 0 || conn->bosh->pending->bufused > 0)) {
+			(conn->bosh->requests == 0 ||
+			purple_circular_buffer_get_used(conn->bosh->pending) > 0))
+	{
 		purple_debug_misc("jabber", "BOSH: Sending an empty request\n");
 		jabber_bosh_connection_send(conn->bosh, PACKET_NORMAL, NULL);
 	}
@@ -1001,8 +1007,9 @@
 http_connection_send_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
 	PurpleHTTPConnection *conn = data;
+	const gchar *output = NULL;
 	int ret;
-	int writelen = purple_circ_buffer_get_max_read(conn->write_buf);
+	int writelen = purple_circular_buffer_get_max_read(conn->write_buf);
 
 	if (writelen == 0) {
 		purple_input_remove(conn->writeh);
@@ -1010,7 +1017,8 @@
 		return;
 	}
 
-	ret = http_connection_do_send(conn, conn->write_buf->outptr, writelen);
+	output = purple_circular_buffer_get_output(conn->write_buf);
+	ret = http_connection_do_send(conn, output, writelen);
 
 	if (ret < 0 && errno == EAGAIN)
 		return;
@@ -1029,7 +1037,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(conn->write_buf, ret);
+	purple_circular_buffer_mark_read(conn->write_buf, ret);
 }
 
 static void
@@ -1089,7 +1097,7 @@
 		if (conn->writeh == 0)
 			conn->writeh = purple_input_add(conn->psc ? conn->psc->fd : conn->fd,
 					PURPLE_INPUT_WRITE, http_connection_send_cb, conn);
-		purple_circ_buffer_append(conn->write_buf, data + ret, len - ret);
+		purple_circular_buffer_append(conn->write_buf, data + ret, len - ret);
 	}
 }
 
--- a/libpurple/protocols/jabber/caps.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/caps.c	Sun Jun 23 13:35:53 2013 +0530
@@ -25,12 +25,14 @@
 
 #include "debug.h"
 #include "caps.h"
-#include "cipher.h"
 #include "iq.h"
 #include "presence.h"
 #include "util.h"
 #include "xdata.h"
 
+#include "ciphers/md5hash.h"
+#include "ciphers/sha1hash.h"
+
 #define JABBER_CAPS_FILENAME "xmpp-caps.xml"
 
 typedef struct _JabberDataFormField {
@@ -455,16 +457,18 @@
 	/* Only validate if these are v1.5 capabilities */
 	if (userdata->hash) {
 		gchar *hash = NULL;
+		PurpleHash *hasher = NULL;
 		/*
 		 * TODO: If you add *any* hash here, make sure the checksum buffer
 		 * size in jabber_caps_calculate_hash is large enough. The cipher API
 		 * doesn't seem to offer a "Get the hash size" function(?).
 		 */
 		if (g_str_equal(userdata->hash, "sha-1")) {
-			hash = jabber_caps_calculate_hash(info, "sha1");
+			hasher = purple_sha1_hash_new();
 		} else if (g_str_equal(userdata->hash, "md5")) {
-			hash = jabber_caps_calculate_hash(info, "md5");
+			hasher = purple_md5_hash_new();
 		}
+		hash = jabber_caps_calculate_hash(info, hasher);
 
 		if (!hash || !g_str_equal(hash, userdata->ver)) {
 			purple_debug_warning("jabber", "Could not validate caps info from "
@@ -480,6 +484,7 @@
 		}
 
 		g_free(hash);
+		g_object_unref(hasher);
 	}
 
 	if (!userdata->hash && userdata->node_exts) {
@@ -806,28 +811,33 @@
 }
 
 static void
-append_escaped_string(PurpleCipherContext *context, const gchar *str)
+append_escaped_string(PurpleHash *hash, const gchar *str)
 {
+	g_return_if_fail(hash != NULL);
+	g_object_ref(hash);
+
 	if (str && *str) {
 		char *tmp = g_markup_escape_text(str, -1);
-		purple_cipher_context_append(context, (const guchar *)tmp, strlen(tmp));
+		purple_hash_append(hash, (const guchar *)tmp, strlen(tmp));
 		g_free(tmp);
 	}
 
-	purple_cipher_context_append(context, (const guchar *)"<", 1);
+	purple_hash_append(hash, (const guchar *)"<", 1);
+	g_object_unref(hash);
 }
 
-gchar *jabber_caps_calculate_hash(JabberCapsClientInfo *info, const char *hash)
+gchar *jabber_caps_calculate_hash(JabberCapsClientInfo *info, PurpleHash *hash)
 {
 	GList *node;
-	PurpleCipherContext *context;
 	guint8 checksum[20];
 	gsize checksum_size = 20;
 	gboolean success;
 
-	if (!info || !(context = purple_cipher_context_new_by_name(hash, NULL)))
+	if (!info || !hash)
 		return NULL;
 
+	g_object_ref(hash);
+
 	/* sort identities, features and x-data forms */
 	info->identities = g_list_sort(info->identities, jabber_identity_compare);
 	info->features = g_list_sort(info->features, (GCompareFunc)strcmp);
@@ -850,7 +860,7 @@
 		tmp = g_strconcat(category, "/", type, "/", lang ? lang : "",
 		                  "/", name ? name : "", "<", NULL);
 
-		purple_cipher_context_append(context, (const guchar *)tmp, strlen(tmp));
+		purple_hash_append(hash, (const guchar *)tmp, strlen(tmp));
 
 		g_free(tmp);
 		g_free(category);
@@ -861,7 +871,7 @@
 
 	/* concat features to the verification string */
 	for (node = info->features; node; node = node->next) {
-		append_escaped_string(context, node->data);
+		append_escaped_string(hash, node->data);
 	}
 
 	/* concat x-data forms to the verification string */
@@ -871,7 +881,7 @@
 		GList *fields = jabber_caps_xdata_get_fields(data);
 
 		/* append FORM_TYPE's field value to the verification string */
-		append_escaped_string(context, formtype);
+		append_escaped_string(hash, formtype);
 		g_free(formtype);
 
 		while (fields) {
@@ -879,10 +889,10 @@
 
 			if (!g_str_equal(field->var, "FORM_TYPE")) {
 				/* Append the "var" attribute */
-				append_escaped_string(context, field->var);
+				append_escaped_string(hash, field->var);
 				/* Append <value/> elements' cdata */
 				while (field->values) {
-					append_escaped_string(context, field->values->data);
+					append_escaped_string(hash, field->values->data);
 					g_free(field->values->data);
 					field->values = g_list_delete_link(field->values,
 					                                   field->values);
@@ -900,16 +910,17 @@
 	}
 
 	/* generate hash */
-	success = purple_cipher_context_digest(context, checksum, checksum_size);
-	checksum_size = purple_cipher_context_get_digest_size(context);
+	success = purple_hash_digest(hash, checksum, checksum_size);
+	checksum_size = purple_hash_get_digest_size(hash);
 
-	purple_cipher_context_destroy(context);
+	g_object_unref(hash);
 
 	return (success ? purple_base64_encode(checksum, checksum_size) : NULL);
 }
 
 void jabber_caps_calculate_own_hash(JabberStream *js) {
 	JabberCapsClientInfo info;
+	PurpleHash *hasher;
 	GList *iter = 0;
 	GList *features = 0;
 
@@ -940,7 +951,9 @@
 	info.forms = NULL;
 
 	g_free(js->caps_hash);
-	js->caps_hash = jabber_caps_calculate_hash(&info, "sha1");
+	hasher = purple_sha1_hash_new();
+	js->caps_hash = jabber_caps_calculate_hash(&info, hasher);
+	g_object_unref(hasher);
 	g_list_free(info.identities);
 	g_list_free(info.features);
 }
--- a/libpurple/protocols/jabber/caps.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/caps.h	Sun Jun 23 13:35:53 2013 +0530
@@ -27,6 +27,7 @@
 typedef struct _JabberCapsClientInfo JabberCapsClientInfo;
 
 #include "jabber.h"
+#include "hash.h"
 
 /* Implementation of XEP-0115 - Entity Capabilities */
 
@@ -98,7 +99,7 @@
  *	@param hash Hash cipher to be used. Either sha-1 or md5.
  *	@return		The base64 encoded SHA-1 hash; must be freed by caller
  */
-gchar *jabber_caps_calculate_hash(JabberCapsClientInfo *info, const char *hash);
+gchar *jabber_caps_calculate_hash(JabberCapsClientInfo *info, PurpleHash *hash);
 
 /**
  *  Calculate SHA1 hash for own featureset.
--- a/libpurple/protocols/jabber/google/google_roster.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/google/google_roster.c	Sun Jun 23 13:35:53 2013 +0530
@@ -28,7 +28,7 @@
 void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item)
 {
 	PurpleAccount *account = purple_connection_get_account(js->gc);
-	GSList *list = account->deny;
+	GSList *list = purple_account_privacy_get_denied(account);
 	const char *jid = xmlnode_get_attrib(item, "jid");
 	char *jid_norm = (char *)jabber_normalize(account, jid);
 
@@ -64,8 +64,8 @@
 
 	jid_norm = g_strdup(jabber_normalize(account, jid));
 
-	on_block_list = NULL != g_slist_find_custom(account->deny, jid_norm,
-	                                            (GCompareFunc)strcmp);
+	on_block_list = NULL != g_slist_find_custom(purple_account_privacy_get_denied(account),
+	                                            jid_norm, (GCompareFunc)strcmp);
 
 	if (grt && (*grt == 'H' || *grt == 'h')) {
 		/* Hidden; don't show this buddy. */
@@ -86,10 +86,10 @@
 
 	if (!on_block_list && (grt && (*grt == 'B' || *grt == 'b'))) {
 		purple_debug_info("jabber", "Blocking %s\n", jid_norm);
-		purple_privacy_deny_add(account, jid_norm, TRUE);
+		purple_account_privacy_deny_add(account, jid_norm, TRUE);
 	} else if (on_block_list && (!grt || (*grt != 'B' && *grt != 'b' ))){
 		purple_debug_info("jabber", "Unblocking %s\n", jid_norm);
-		purple_privacy_deny_remove(account, jid_norm, TRUE);
+		purple_account_privacy_deny_remove(account, jid_norm, TRUE);
 	}
 
 	g_free(jid_norm);
--- a/libpurple/protocols/jabber/jabber.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/jabber.c	Sun Jun 23 13:35:53 2013 +0530
@@ -35,7 +35,6 @@
 #include "message.h"
 #include "notify.h"
 #include "pluginpref.h"
-#include "privacy.h"
 #include "proxy.h"
 #include "prpl.h"
 #include "request.h"
@@ -392,8 +391,11 @@
 static void jabber_send_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
 	JabberStream *js = data;
+	const gchar *output = NULL;
 	int ret, writelen;
-	writelen = purple_circ_buffer_get_max_read(js->write_buffer);
+
+	writelen = purple_circular_buffer_get_max_read(js->write_buffer);
+	output = purple_circular_buffer_get_output(js->write_buffer);
 
 	if (writelen == 0) {
 		purple_input_remove(js->writeh);
@@ -401,7 +403,7 @@
 		return;
 	}
 
-	ret = jabber_do_send(js, js->write_buffer->outptr, writelen);
+	ret = jabber_do_send(js, output, writelen);
 
 	if (ret < 0 && errno == EAGAIN)
 		return;
@@ -414,7 +416,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(js->write_buffer, ret);
+	purple_circular_buffer_mark_read(js->write_buffer, ret);
 }
 
 static gboolean do_jabber_send_raw(JabberStream *js, const char *data, int len)
@@ -457,7 +459,7 @@
 			js->writeh = purple_input_add(
 				js->gsc ? js->gsc->fd : js->fd,
 				PURPLE_INPUT_WRITE, jabber_send_cb, js);
-		purple_circ_buffer_append(js->write_buffer,
+		purple_circular_buffer_append(js->write_buffer,
 			data + ret, len - ret);
 	}
 
@@ -994,7 +996,7 @@
 	js->chats = g_hash_table_new_full(g_str_hash, g_str_equal,
 			g_free, (GDestroyNotify)jabber_chat_free);
 	js->next_id = g_random_int();
-	js->write_buffer = purple_circ_buffer_new(512);
+	js->write_buffer = purple_circular_buffer_new(512);
 	js->old_length = 0;
 	js->keepalive_timeout = 0;
 	js->max_inactivity = DEFAULT_INACTIVITY_TIME;
@@ -1419,7 +1421,7 @@
 	if((node = xmlnode_get_child(query, "name"))) {
 		if(js->registration)
 			field = purple_request_field_string_new("name", _("Name"),
-													purple_account_get_alias(purple_connection_get_account(js->gc)), FALSE);
+													purple_account_get_private_alias(purple_connection_get_account(js->gc)), FALSE);
 		else {
 			char *data = xmlnode_get_data(node);
 			field = purple_request_field_string_new("name", _("Name"), data, FALSE);
@@ -1653,7 +1655,7 @@
 	g_free(js->caps_hash);
 
 	if (js->write_buffer)
-		purple_circ_buffer_destroy(js->write_buffer);
+		g_object_unref(G_OBJECT(js->write_buffer));
 	if(js->writeh)
 		purple_input_remove(js->writeh);
 	if (js->auth_mech && js->auth_mech->dispose)
@@ -1796,6 +1798,7 @@
 	xmlnode *item;
 	PurpleAccount *account;
 	gboolean is_block;
+	GSList *deny;
 
 	if (!jabber_is_own_account(js, from)) {
 		xmlnode *error, *x;
@@ -1821,8 +1824,8 @@
 		/* Unblock everyone */
 		purple_debug_info("jabber", "Received unblock push. Unblocking everyone.\n");
 
-		while (account->deny != NULL) {
-			purple_privacy_deny_remove(account, account->deny->data, TRUE);
+		while ((deny = purple_account_privacy_get_denied(account)) != NULL) {
+			purple_account_privacy_deny_remove(account, deny->data, TRUE);
 		}
 	} else if (item == NULL) {
 		/* An empty <block/> is bogus */
@@ -1844,9 +1847,9 @@
 				continue;
 
 			if (is_block)
-				purple_privacy_deny_add(account, jid, TRUE);
+				purple_account_privacy_deny_add(account, jid, TRUE);
 			else
-				purple_privacy_deny_remove(account, jid, TRUE);
+				purple_account_privacy_deny_remove(account, jid, TRUE);
 		}
 	}
 
@@ -1861,6 +1864,7 @@
 {
 	xmlnode *blocklist, *item;
 	PurpleAccount *account;
+	GSList *deny;
 
 	blocklist = xmlnode_get_child_with_namespace(packet,
 			"blocklist", NS_SIMPLE_BLOCKING);
@@ -1870,19 +1874,19 @@
 		return;
 
 	/* This is the only privacy method supported by XEP-0191 */
-	purple_account_set_privacy_type(account, PURPLE_PRIVACY_DENY_USERS);
+	purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_DENY_USERS);
 
 	/*
 	 * TODO: When account->deny is something more than a hash table, this can
 	 * be re-written to find the set intersection and difference.
 	 */
-	while (account->deny)
-		purple_privacy_deny_remove(account, account->deny->data, TRUE);
+	while ((deny = purple_account_privacy_get_denied(account)))
+		purple_account_privacy_deny_remove(account, deny->data, TRUE);
 
 	item = xmlnode_get_child(blocklist, "item");
 	while (item != NULL) {
 		const char *jid = xmlnode_get_attrib(item, "jid");
-		purple_privacy_deny_add(account, jid, TRUE);
+		purple_account_privacy_deny_add(account, jid, TRUE);
 		item = xmlnode_get_next_twin(item);
 	}
 }
--- a/libpurple/protocols/jabber/jabber.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/jabber.h	Sun Jun 23 13:35:53 2013 +0530
@@ -56,7 +56,7 @@
 
 #include <libxml/parser.h>
 #include <glib.h>
-#include "circbuffer.h"
+#include "circularbuffer.h"
 #include "connection.h"
 #include "dnsquery.h"
 #include "dnssrv.h"
@@ -190,7 +190,7 @@
 
 	GSList *pending_buddy_info_requests;
 
-	PurpleCircBuffer *write_buffer;
+	PurpleCircularBuffer *write_buffer;
 	guint writeh;
 
 	gboolean reinit;
--- a/libpurple/protocols/jabber/jutil.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/jutil.c	Sun Jun 23 13:35:53 2013 +0530
@@ -22,7 +22,6 @@
  */
 #include "internal.h"
 #include "account.h"
-#include "cipher.h"
 #include "conversation.h"
 #include "debug.h"
 #include "server.h"
@@ -33,6 +32,10 @@
 #include "presence.h"
 #include "jutil.h"
 
+#include "ciphers/md4hash.h"
+#include "ciphers/md5hash.h"
+#include "ciphers/sha1hash.h"
+
 #ifdef USE_IDN
 #include <idna.h>
 #include <stringprep.h>
@@ -736,25 +739,31 @@
 jabber_calculate_data_hash(gconstpointer data, size_t len,
     const gchar *hash_algo)
 {
-	PurpleCipherContext *context;
+	PurpleHash *hash = NULL;
 	static gchar digest[129]; /* 512 bits hex + \0 */
 
-	context = purple_cipher_context_new_by_name(hash_algo, NULL);
-	if (context == NULL)
+	/* FIXME: Check the source of this change and what we need here... */
+	if (g_str_equal(hash_algo, "sha1"))
+		hash = purple_sha1_hash_new();
+	else if (g_str_equal(hash_algo, "md4"))
+		hash = purple_md4_hash_new();
+	else if (g_str_equal(hash_algo, "md5"))
+		hash = purple_md5_hash_new();
+	if (hash == NULL)
 	{
 		purple_debug_error("jabber", "Could not find %s cipher\n", hash_algo);
 		g_return_val_if_reached(NULL);
 	}
 
 	/* Hash the data */
-	purple_cipher_context_append(context, data, len);
-	if (!purple_cipher_context_digest_to_str(context, digest, sizeof(digest)))
+	purple_hash_append(hash, data, len);
+	if (!purple_hash_digest_to_str(hash, digest, sizeof(digest)))
 	{
 		purple_debug_error("jabber", "Failed to get digest for %s cipher.\n",
 		    hash_algo);
 		g_return_val_if_reached(NULL);
 	}
-	purple_cipher_context_destroy(context);
+	g_object_unref(G_OBJECT(hash));
 
 	return g_strdup(digest);
 }
--- a/libpurple/protocols/jabber/si.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/jabber/si.c	Sun Jun 23 13:35:53 2013 +0530
@@ -71,7 +71,7 @@
 
 	JabberIBBSession *ibb_session;
 	guint ibb_timeout_handle;
-	PurpleCircBuffer *ibb_buffer;
+	PurpleCircularBuffer *ibb_buffer;
 } JabberSIXfer;
 
 /* some forward declarations */
@@ -1011,7 +1011,7 @@
 	if (size <= purple_xfer_get_bytes_remaining(xfer)) {
 		purple_debug_info("jabber", "about to write %" G_GSIZE_FORMAT " bytes from IBB stream\n",
 			size);
-		purple_circ_buffer_append(jsx->ibb_buffer, data, size);
+		purple_circular_buffer_append(jsx->ibb_buffer, data, size);
 		purple_xfer_prpl_ready(xfer);
 	} else {
 		/* trying to write past size of file transfers negotiated size,
@@ -1028,15 +1028,15 @@
 {
 	JabberSIXfer *jsx = purple_xfer_get_protocol_data(xfer);
 	guchar *buffer;
-	gsize size;
+	gsize size = purple_circular_buffer_get_used(jsx->ibb_buffer);
 	gsize tmp;
 
-	size = jsx->ibb_buffer->bufused;
 	*out_buffer = buffer = g_malloc(size);
-	while ((tmp = purple_circ_buffer_get_max_read(jsx->ibb_buffer))) {
-		memcpy(buffer, jsx->ibb_buffer->outptr, tmp);
+	while ((tmp = purple_circular_buffer_get_max_read(jsx->ibb_buffer))) {
+		const gchar *output = purple_circular_buffer_get_output(jsx->ibb_buffer);
+		memcpy(buffer, output, tmp);
 		buffer += tmp;
-		purple_circ_buffer_mark_read(jsx->ibb_buffer, tmp);
+		purple_circular_buffer_mark_read(jsx->ibb_buffer, tmp);
 	}
 
 	return size;
@@ -1069,7 +1069,7 @@
 			 clients interpreting the block-size attribute as that
 			 (see also remark in ibb.c) */
 			jsx->ibb_buffer =
-				purple_circ_buffer_new(jabber_ibb_session_get_block_size(sess));
+				purple_circular_buffer_new(jabber_ibb_session_get_block_size(sess));
 
 			/* set up read function */
 			purple_xfer_set_read_fnc(xfer, jabber_si_xfer_ibb_read);
@@ -1157,7 +1157,7 @@
 		purple_xfer_set_write_fnc(xfer, jabber_si_xfer_ibb_write);
 
 		jsx->ibb_buffer =
-			purple_circ_buffer_new(jabber_ibb_session_get_max_data_size(jsx->ibb_session));
+			purple_circular_buffer_new(jabber_ibb_session_get_max_data_size(jsx->ibb_session));
 
 		/* open the IBB session */
 		jabber_ibb_session_open(jsx->ibb_session);
@@ -1334,7 +1334,7 @@
 		}
 
 		if (jsx->ibb_buffer) {
-			purple_circ_buffer_destroy(jsx->ibb_buffer);
+			g_object_unref(G_OBJECT(jsx->ibb_buffer));
 		}
 
 		purple_debug_info("jabber", "jabber_si_xfer_free(): freeing jsx %p\n", jsx);
--- a/libpurple/protocols/msn/contact.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/contact.c	Sun Jun 23 13:35:53 2013 +0530
@@ -1664,10 +1664,10 @@
 		msn_add_contact_to_list(session, new_state, state->who, MSN_LIST_RL);
 		return;
 	} else if (state->list_id == MSN_LIST_AL) {
-		purple_privacy_permit_remove(session->account, state->who, TRUE);
+		purple_account_privacy_permit_remove(session->account, state->who, TRUE);
 		msn_add_contact_to_list(session, NULL, state->who, MSN_LIST_BL);
 	} else if (state->list_id == MSN_LIST_BL) {
-		purple_privacy_deny_remove(session->account, state->who, TRUE);
+		purple_account_privacy_deny_remove(session->account, state->who, TRUE);
 		msn_add_contact_to_list(session, NULL, state->who, MSN_LIST_AL);
 	}
 
@@ -1764,9 +1764,9 @@
 		if (state->action & MSN_DENIED_BUDDY) {
 			msn_add_contact_to_list(state->session, NULL, state->who, MSN_LIST_BL);
 		} else if (state->list_id == MSN_LIST_AL) {
-			purple_privacy_permit_add(state->session->account, state->who, TRUE);
+			purple_account_privacy_permit_add(state->session->account, state->who, TRUE);
 		} else if (state->list_id == MSN_LIST_BL) {
-			purple_privacy_deny_add(state->session->account, state->who, TRUE);
+			purple_account_privacy_deny_add(state->session->account, state->who, TRUE);
 		}
 	}
 }
--- a/libpurple/protocols/msn/directconn.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/directconn.c	Sun Jun 23 13:35:53 2013 +0530
@@ -23,7 +23,7 @@
  */
 
 #include "internal.h"
-#include "cipher.h"
+#include "ciphers/sha1hash.h"
 #include "debug.h"
 
 #include "msn.h"
@@ -44,11 +44,10 @@
 	guchar digest[20];
 
 	if (type == DC_NONCE_SHA1) {
-		PurpleCipher *cipher = purple_ciphers_find_cipher("sha1");
-		PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL);
-		purple_cipher_context_append(context, nonce, nonce_len);
-		purple_cipher_context_digest(context, digest, sizeof(digest));
-		purple_cipher_context_destroy(context);
+		PurpleHash *hash = purple_sha1_hash_new();
+		purple_hash_append(hash, nonce, nonce_len);
+		purple_hash_digest(hash, digest, sizeof(digest));
+		g_object_unref(hash);
 	} else if (type == DC_NONCE_PLAIN) {
 		memcpy(digest, nonce, nonce_len);
 	} else {
--- a/libpurple/protocols/msn/directconn.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/directconn.h	Sun Jun 23 13:35:53 2013 +0530
@@ -28,7 +28,7 @@
 
 #include "network.h"
 #include "proxy.h"
-#include "circbuffer.h"
+#include "circularbuffer.h"
 
 #include "slp.h"
 #include "slplink.h"
--- a/libpurple/protocols/msn/httpconn.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/httpconn.c	Sun Jun 23 13:35:53 2013 +0530
@@ -353,9 +353,11 @@
 	MsnHttpConn *httpconn;
 	gssize ret;
 	int writelen;
+	const gchar *output = NULL;
 
 	httpconn = data;
-	writelen = purple_circ_buffer_get_max_read(httpconn->tx_buf);
+	writelen = purple_circular_buffer_get_max_read(httpconn->tx_buf);
+	output = purple_circular_buffer_get_output(httpconn->tx_buf);
 
 	if (writelen == 0)
 	{
@@ -364,7 +366,7 @@
 		return;
 	}
 
-	ret = write(httpconn->fd, httpconn->tx_buf->outptr, writelen);
+	ret = write(httpconn->fd, output, writelen);
 	if (ret <= 0)
 	{
 		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
@@ -376,7 +378,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(httpconn->tx_buf, ret);
+	purple_circular_buffer_mark_read(httpconn->tx_buf, ret);
 
 	/* TODO: I don't think these 2 lines are needed.  Remove them? */
 	if (ret == writelen)
@@ -409,7 +411,7 @@
 		if (httpconn->tx_handler == 0 && httpconn->fd)
 			httpconn->tx_handler = purple_input_add(httpconn->fd,
 				PURPLE_INPUT_WRITE, httpconn_write_cb, httpconn);
-		purple_circ_buffer_append(httpconn->tx_buf, data + res,
+		purple_circular_buffer_append(httpconn->tx_buf, data + res,
 			data_len - res);
 	}
 
@@ -612,7 +614,7 @@
 
 	httpconn->servconn = servconn;
 
-	httpconn->tx_buf = purple_circ_buffer_new(MSN_BUF_LEN);
+	httpconn->tx_buf = purple_circular_buffer_new(MSN_BUF_LEN);
 	httpconn->tx_handler = 0;
 
 	httpconn->fd = -1;
@@ -647,7 +649,7 @@
 		g_free(queue_data);
 	}
 
-	purple_circ_buffer_destroy(httpconn->tx_buf);
+	g_object_unref(G_OBJECT(httpconn->tx_buf));
 	if (httpconn->tx_handler > 0)
 		purple_input_remove(httpconn->tx_handler);
 
--- a/libpurple/protocols/msn/httpconn.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/httpconn.h	Sun Jun 23 13:35:53 2013 +0530
@@ -26,7 +26,7 @@
 
 typedef struct _MsnHttpConn MsnHttpConn;
 
-#include "circbuffer.h"
+#include "circularbuffer.h"
 #include "servconn.h"
 #include "session.h"
 
@@ -61,7 +61,7 @@
 	char *rx_buf; /**< The receive buffer. */
 	int rx_len; /**< The receive buffer length. */
 
-	PurpleCircBuffer *tx_buf;
+	PurpleCircularBuffer *tx_buf;
 	guint tx_handler;
 };
 
--- a/libpurple/protocols/msn/msn.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/msn.c	Sun Jun 23 13:35:53 2013 +0530
@@ -814,8 +814,8 @@
 	session = purple_connection_get_protocol_data(gc);
 	cmdproc = session->notification->cmdproc;
 
-	if (purple_account_get_privacy_type(account) == PURPLE_PRIVACY_ALLOW_ALL ||
-	    purple_account_get_privacy_type(account) == PURPLE_PRIVACY_DENY_USERS)
+	if (purple_account_get_privacy_type(account) == PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL ||
+	    purple_account_get_privacy_type(account) == PURPLE_ACCOUNT_PRIVACY_DENY_USERS)
 		trans = msn_transaction_new(cmdproc, "BLP", "%s", "AL");
 	else
 		trans = msn_transaction_new(cmdproc, "BLP", "%s", "BL");
@@ -853,7 +853,7 @@
 	swboard->flag = MSN_SB_FLAG_IM;
 
 	/* Local alias > Display name > Username */
-	if ((alias = purple_account_get_alias(account)) == NULL)
+	if ((alias = purple_account_get_private_alias(account)) == NULL)
 		if ((alias = purple_connection_get_display_name(gc)) == NULL)
 			alias = purple_account_get_username(account);
 
--- a/libpurple/protocols/msn/msnutils.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/msnutils.c	Sun Jun 23 13:35:53 2013 +0530
@@ -27,7 +27,7 @@
 #include "msn.h"
 #include "msnutils.h"
 
-#include "cipher.h"
+#include "ciphers/md5hash.h"
 
 /**************************************************************************
  * Util
@@ -542,8 +542,7 @@
 void
 msn_handle_chl(char *input, char *output)
 {
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
+	PurpleHash *hash;
 	const guchar productKey[] = MSNP15_WLM_PRODUCT_KEY;
 	const guchar productID[]  = MSNP15_WLM_PRODUCT_ID;
 	const char hexChars[]     = "0123456789abcdef";
@@ -560,13 +559,12 @@
 	int i;
 
 	/* Create the MD5 hash by using Purple MD5 algorithm */
-	cipher = purple_ciphers_find_cipher("md5");
-	context = purple_cipher_context_new(cipher, NULL);
+	hash = purple_md5_hash_new();
 
-	purple_cipher_context_append(context, (guchar *)input, strlen(input));
-	purple_cipher_context_append(context, productKey, sizeof(productKey) - 1);
-	purple_cipher_context_digest(context, md5Hash, sizeof(md5Hash));
-	purple_cipher_context_destroy(context);
+	purple_hash_append(hash, (guchar *)input, strlen(input));
+	purple_hash_append(hash, productKey, sizeof(productKey) - 1);
+	purple_hash_digest(hash, md5Hash, sizeof(md5Hash));
+	g_object_unref(hash);
 
 	/* Split it into four integers */
 	md5Parts = (unsigned int *)md5Hash;
--- a/libpurple/protocols/msn/nexus.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/nexus.c	Sun Jun 23 13:35:53 2013 +0530
@@ -23,7 +23,6 @@
  */
 
 #include "internal.h"
-#include "cipher.h"
 #include "debug.h"
 
 #include "msnutils.h"
@@ -31,6 +30,10 @@
 #include "nexus.h"
 #include "notification.h"
 
+#include "ciphers/des3cipher.h"
+#include "ciphers/hmaccipher.h"
+#include "ciphers/sha1hash.h"
+
 /**************************************************************************
  * Valid Ticket Tokens
  **************************************************************************/
@@ -99,35 +102,37 @@
 	const guchar magic[] = "WS-SecureConversation";
 	const int magic_len = sizeof(magic) - 1;
 
-	PurpleCipherContext *hmac;
+	PurpleCipher *hmac;
+	PurpleHash *hash;
 	guchar hash1[20], hash2[20], hash3[20], hash4[20];
 	char *result;
 
-	hmac = purple_cipher_context_new_by_name("hmac", NULL);
-	purple_cipher_context_set_option(hmac, "hash", "sha1");
-	purple_cipher_context_set_key(hmac, (guchar *)key, key_len);
+	hash = purple_sha1_hash_new();
+	hmac = purple_hmac_cipher_new(hash);
+	purple_cipher_set_key(hmac, (guchar *)key, key_len);
 
-	purple_cipher_context_append(hmac, magic, magic_len);
-	purple_cipher_context_append(hmac, (guchar *)data, data_len);
-	purple_cipher_context_digest(hmac, hash1, sizeof(hash1));
+	purple_cipher_append(hmac, magic, magic_len);
+	purple_cipher_append(hmac, (guchar *)data, data_len);
+	purple_cipher_digest(hmac, hash1, sizeof(hash1));
 
-	purple_cipher_context_reset_state(hmac, NULL);
-	purple_cipher_context_append(hmac, hash1, 20);
-	purple_cipher_context_append(hmac, magic, magic_len);
-	purple_cipher_context_append(hmac, (guchar *)data, data_len);
-	purple_cipher_context_digest(hmac, hash2, sizeof(hash2));
+	purple_cipher_reset_state(hmac);
+	purple_cipher_append(hmac, hash1, 20);
+	purple_cipher_append(hmac, magic, magic_len);
+	purple_cipher_append(hmac, (guchar *)data, data_len);
+	purple_cipher_digest(hmac, hash2, sizeof(hash2));
 
-	purple_cipher_context_reset_state(hmac, NULL);
-	purple_cipher_context_append(hmac, hash1, 20);
-	purple_cipher_context_digest(hmac, hash3, sizeof(hash3));
+	purple_cipher_reset_state(hmac);
+	purple_cipher_append(hmac, hash1, 20);
+	purple_cipher_digest(hmac, hash3, sizeof(hash3));
 
-	purple_cipher_context_reset_state(hmac, NULL);
-	purple_cipher_context_append(hmac, hash3, sizeof(hash3));
-	purple_cipher_context_append(hmac, magic, magic_len);
-	purple_cipher_context_append(hmac, (guchar *)data, data_len);
-	purple_cipher_context_digest(hmac, hash4, sizeof(hash4));
+	purple_cipher_reset_state(hmac);
+	purple_cipher_append(hmac, hash3, sizeof(hash3));
+	purple_cipher_append(hmac, magic, magic_len);
+	purple_cipher_append(hmac, (guchar *)data, data_len);
+	purple_cipher_digest(hmac, hash4, sizeof(hash4));
 
-	purple_cipher_context_destroy(hmac);
+	g_object_unref(hmac);
+	g_object_unref(hash);
 
 	result = g_malloc(24);
 	memcpy(result, hash2, sizeof(hash2));
@@ -139,21 +144,21 @@
 static char *
 des3_cbc(const char *key, const char *iv, const char *data, int len, gboolean decrypt)
 {
-	PurpleCipherContext *des3;
+	PurpleCipher *des3;
 	char *out;
 
-	des3 = purple_cipher_context_new_by_name("des3", NULL);
-	purple_cipher_context_set_key(des3, (guchar *)key, 24);
-	purple_cipher_context_set_batch_mode(des3, PURPLE_CIPHER_BATCH_MODE_CBC);
-	purple_cipher_context_set_iv(des3, (guchar *)iv, 8);
+	des3 = purple_des3_cipher_new();
+	purple_cipher_set_key(des3, (guchar *)key, 24);
+	purple_cipher_set_batch_mode(des3, PURPLE_CIPHER_BATCH_MODE_CBC);
+	purple_cipher_set_iv(des3, (guchar *)iv, 8);
 
 	out = g_malloc(len);
 	if (decrypt)
-		purple_cipher_context_decrypt(des3, (guchar *)data, len, (guchar *)out, len);
+		purple_cipher_decrypt(des3, (guchar *)data, len, (guchar *)out, len);
 	else
-		purple_cipher_context_encrypt(des3, (guchar *)data, len, (guchar *)out, len);
+		purple_cipher_encrypt(des3, (guchar *)data, len, (guchar *)out, len);
 
-	purple_cipher_context_destroy(des3);
+	g_object_unref(des3);
 
 	return out;
 }
@@ -168,7 +173,8 @@
 	char usr_key_base[MSN_USER_KEY_SIZE], *usr_key;
 	const char magic1[] = "SESSION KEY HASH";
 	const char magic2[] = "SESSION KEY ENCRYPTION";
-	PurpleCipherContext *hmac;
+	PurpleCipher *hmac;
+	PurpleHash *hasher;
 	size_t len;
 	guchar *hash;
 	char *key1, *key2, *key3;
@@ -199,12 +205,13 @@
 	key3 = rps_create_key(key1, key1_len, magic2, sizeof(magic2) - 1);
 
 	len = strlen(nexus->nonce);
-	hmac = purple_cipher_context_new_by_name("hmac", NULL);
-	purple_cipher_context_set_option(hmac, "hash", "sha1");
-	purple_cipher_context_set_key(hmac, (guchar *)key2, 24);
-	purple_cipher_context_append(hmac, (guchar *)nexus->nonce, len);
-	purple_cipher_context_digest(hmac, hash, 20);
-	purple_cipher_context_destroy(hmac);
+	hasher = purple_sha1_hash_new();
+	hmac = purple_hmac_cipher_new(hasher);
+	purple_cipher_set_key(hmac, (guchar *)key2, 24);
+	purple_cipher_append(hmac, (guchar *)nexus->nonce, len);
+	purple_cipher_digest(hmac, hash, 20);
+	g_object_unref(hmac);
+	g_object_unref(hasher);
 
 	/* We need to pad this to 72 bytes, apparently */
 	nonce_fixed = g_malloc(len + 8);
@@ -508,8 +515,8 @@
 	MsnSession *session = nexus->session;
 	MsnNexusUpdateData *ud;
 	MsnNexusUpdateCallback *update;
-	PurpleCipherContext *sha1;
-	PurpleCipherContext *hmac;
+	PurpleHash *sha1;
+	PurpleCipher *hmac;
 
 	char *key;
 
@@ -560,7 +567,7 @@
 	ud->nexus = nexus;
 	ud->id = id;
 
-	sha1 = purple_cipher_context_new_by_name("sha1", NULL);
+	sha1 = purple_sha1_hash_new();
 
 	domain = g_strdup_printf(MSN_SSO_RST_TEMPLATE,
 	                         id,
@@ -568,8 +575,8 @@
 	                         ticket_domains[id][SSO_VALID_TICKET_POLICY] != NULL ?
 	                             ticket_domains[id][SSO_VALID_TICKET_POLICY] :
 	                             nexus->policy);
-	purple_cipher_context_append(sha1, (guchar *)domain, strlen(domain));
-	purple_cipher_context_digest(sha1, digest, 20);
+	purple_hash_append(sha1, (guchar *)domain, strlen(domain));
+	purple_hash_digest(sha1, digest, 20);
 	domain_b64 = purple_base64_encode(digest, 20);
 
 	now = time(NULL);
@@ -580,13 +587,13 @@
 	timestamp = g_strdup_printf(MSN_SSO_TIMESTAMP_TEMPLATE,
 	                            now_str,
 	                            purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm));
-	purple_cipher_context_reset(sha1, NULL);
-	purple_cipher_context_append(sha1, (guchar *)timestamp, strlen(timestamp));
-	purple_cipher_context_digest(sha1, digest, 20);
+	purple_hash_reset(sha1);
+	purple_hash_append(sha1, (guchar *)timestamp, strlen(timestamp));
+	purple_hash_digest(sha1, digest, 20);
 	timestamp_b64 = purple_base64_encode(digest, 20);
 	g_free(now_str);
 
-	purple_cipher_context_destroy(sha1);
+	purple_hash_reset(sha1);
 
 	signedinfo = g_strdup_printf(MSN_SSO_SIGNEDINFO_TEMPLATE,
 	                             id,
@@ -598,12 +605,14 @@
 	nonce_b64 = purple_base64_encode((guchar *)&nonce, sizeof(nonce));
 
 	key = rps_create_key(nexus->secret, 24, (char *)nonce, sizeof(nonce));
-	hmac = purple_cipher_context_new_by_name("hmac", NULL);
-	purple_cipher_context_set_option(hmac, "hash", "sha1");
-	purple_cipher_context_set_key(hmac, (guchar *)key, 24);
-	purple_cipher_context_append(hmac, (guchar *)signedinfo, strlen(signedinfo));
-	purple_cipher_context_digest(hmac, signature, 20);
-	purple_cipher_context_destroy(hmac);
+	hmac = purple_hmac_cipher_new(sha1);
+	purple_cipher_set_key(hmac, (guchar *)key, 24);
+	purple_cipher_append(hmac, (guchar *)signedinfo, strlen(signedinfo));
+	purple_cipher_digest(hmac, signature, 20);
+
+	g_object_unref(hmac);
+	g_object_unref(sha1);
+
 	signature_b64 = purple_base64_encode(signature, 20);
 
 	request = g_strdup_printf(MSN_SSO_TOKEN_UPDATE_TEMPLATE,
--- a/libpurple/protocols/msn/notification.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/notification.c	Sun Jun 23 13:35:53 2013 +0530
@@ -23,7 +23,7 @@
  */
 
 #include "internal.h"
-#include "cipher.h"
+#include "ciphers/md5hash.h"
 #include "core.h"
 #include "debug.h"
 
@@ -1394,7 +1394,7 @@
 	PurpleAccount *account;
 	const char *rru;
 	const char *url;
-	PurpleCipherContext *cipher;
+	PurpleHash *hash;
 	gchar creds[33];
 	char *buf;
 
@@ -1415,10 +1415,10 @@
 	                      tmp_timestamp,
 	                      purple_connection_get_password(gc));
 
-	cipher = purple_cipher_context_new_by_name("md5", NULL);
-	purple_cipher_context_append(cipher, (const guchar *)buf, strlen(buf));
-	purple_cipher_context_digest_to_str(cipher, creds, sizeof(creds));
-	purple_cipher_context_destroy(cipher);
+	hash = purple_md5_hash_new();
+	purple_hash_append(hash, (const guchar *)buf, strlen(buf));
+	purple_hash_digest_to_str(hash, creds, sizeof(creds));
+	g_object_unref(hash);
 	g_free(buf);
 
 	g_free(session->passport_info.mail_url);
--- a/libpurple/protocols/msn/object.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/object.c	Sun Jun 23 13:35:53 2013 +0530
@@ -26,7 +26,7 @@
 #include "object.h"
 #include "debug.h"
 /* Sha1 stuff */
-#include "cipher.h"
+#include "ciphers/sha1hash.h"
 /* Base64 stuff */
 #include "util.h"
 
@@ -130,7 +130,7 @@
 {
 	MsnObject *msnobj;
 
-	PurpleCipherContext *ctx;
+	PurpleHash *hash;
 	char *buf;
 	gconstpointer data;
 	size_t size;
@@ -157,9 +157,9 @@
 	/* Compute the SHA1D field. */
 	memset(digest, 0, sizeof(digest));
 
-	ctx = purple_cipher_context_new_by_name("sha1", NULL);
-	purple_cipher_context_append(ctx, data, size);
-	purple_cipher_context_digest(ctx, digest, sizeof(digest));
+	hash = purple_sha1_hash_new();
+	purple_hash_append(hash, data, size);
+	purple_hash_digest(hash, digest, sizeof(digest));
 
 	base64 = purple_base64_encode(digest, sizeof(digest));
 	msn_object_set_sha1d(msnobj, base64);
@@ -179,10 +179,10 @@
 
 	memset(digest, 0, sizeof(digest));
 
-	purple_cipher_context_reset(ctx, NULL);
-	purple_cipher_context_append(ctx, (const guchar *)buf, strlen(buf));
-	purple_cipher_context_digest(ctx, digest, sizeof(digest));
-	purple_cipher_context_destroy(ctx);
+	purple_hash_reset(hash);
+	purple_hash_append(hash, (const guchar *)buf, strlen(buf));
+	purple_hash_digest(hash, digest, sizeof(digest));
+	g_object_unref(hash);
 	g_free(buf);
 
 	base64 = purple_base64_encode(digest, sizeof(digest));
--- a/libpurple/protocols/msn/servconn.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/servconn.c	Sun Jun 23 13:35:53 2013 +0530
@@ -53,7 +53,7 @@
 
 	servconn->num = session->servconns_count++;
 
-	servconn->tx_buf = purple_circ_buffer_new(MSN_BUF_LEN);
+	servconn->tx_buf = purple_circular_buffer_new(MSN_BUF_LEN);
 	servconn->tx_handler = 0;
 	servconn->timeout_sec = 0;
 	servconn->timeout_handle = 0;
@@ -84,7 +84,7 @@
 
 	g_free(servconn->host);
 
-	purple_circ_buffer_destroy(servconn->tx_buf);
+	g_object_unref(G_OBJECT(servconn->tx_buf));
 	if (servconn->tx_handler > 0)
 		purple_input_remove(servconn->tx_handler);
 	if (servconn->timeout_handle > 0)
@@ -334,8 +334,10 @@
 	MsnServConn *servconn = data;
 	gssize ret;
 	int writelen;
+	const gchar *output = NULL;
 
-	writelen = purple_circ_buffer_get_max_read(servconn->tx_buf);
+	writelen = purple_circular_buffer_get_max_read(servconn->tx_buf);
+	output = purple_circular_buffer_get_output(servconn->tx_buf);
 
 	if (writelen == 0) {
 		purple_input_remove(servconn->tx_handler);
@@ -343,7 +345,7 @@
 		return;
 	}
 
-	ret = write(servconn->fd, servconn->tx_buf->outptr, writelen);
+	ret = write(servconn->fd, output, writelen);
 
 	if (ret < 0 && errno == EAGAIN)
 		return;
@@ -352,7 +354,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(servconn->tx_buf, ret);
+	purple_circular_buffer_mark_read(servconn->tx_buf, ret);
 	servconn_timeout_renew(servconn);
 }
 
@@ -394,7 +396,7 @@
 				servconn->tx_handler = purple_input_add(
 					servconn->fd, PURPLE_INPUT_WRITE,
 					servconn_write_cb, servconn);
-			purple_circ_buffer_append(servconn->tx_buf, buf + ret,
+			purple_circular_buffer_append(servconn->tx_buf, buf + ret,
 				len - ret);
 		}
 	}
--- a/libpurple/protocols/msn/servconn.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/servconn.h	Sun Jun 23 13:35:53 2013 +0530
@@ -85,7 +85,7 @@
 						  It's only set when we've received a command that
 						  has a payload. */
 
-	PurpleCircBuffer *tx_buf;
+	PurpleCircularBuffer *tx_buf;
 	guint tx_handler;
 	guint timeout_sec;
 	guint timeout_handle;
--- a/libpurple/protocols/msn/userlist.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/msn/userlist.c	Sun Jun 23 13:35:53 2013 +0530
@@ -59,8 +59,8 @@
 		PurpleAccount *account = purple_connection_get_account(pa->gc);
 
 		msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_AL);
-		purple_privacy_deny_remove(account, pa->who, TRUE);
-		purple_privacy_permit_add(account, pa->who, TRUE);
+		purple_account_privacy_deny_remove(account, pa->who, TRUE);
+		purple_account_privacy_permit_add(account, pa->who, TRUE);
 
 		msn_del_contact_from_list(session, NULL, pa->who, MSN_LIST_PL);
 	}
@@ -152,15 +152,15 @@
 	if (list_op & MSN_LIST_AL_OP)
 	{
 		/* These are users who are allowed to see our status. */
-		purple_privacy_deny_remove(account, passport, TRUE);
-		purple_privacy_permit_add(account, passport, TRUE);
+		purple_account_privacy_deny_remove(account, passport, TRUE);
+		purple_account_privacy_permit_add(account, passport, TRUE);
 	}
 
 	if (list_op & MSN_LIST_BL_OP)
 	{
 		/* These are users who are not allowed to see our status. */
-		purple_privacy_permit_remove(account, passport, TRUE);
-		purple_privacy_deny_add(account, passport, TRUE);
+		purple_account_privacy_permit_remove(account, passport, TRUE);
+		purple_account_privacy_deny_add(account, passport, TRUE);
 	}
 
 	if (list_op & MSN_LIST_RL_OP)
@@ -742,13 +742,13 @@
 		purple_buddy_set_protocol_data(buddy, user);
 		msn_user_set_op(user, MSN_LIST_FL_OP);
 	}
-	for (l = session->account->permit; l != NULL; l = l->next)
+	for (l = purple_account_privacy_get_permitted(session->account); l != NULL; l = l->next)
 	{
 		user = msn_userlist_find_add_user(session->userlist,
 						(char *)l->data,NULL);
 		msn_user_set_op(user, MSN_LIST_AL_OP);
 	}
-	for (l = session->account->deny; l != NULL; l = l->next)
+	for (l = purple_account_privacy_get_denied(session->account); l != NULL; l = l->next)
 	{
 		user = msn_userlist_find_add_user(session->userlist,
 						(char *)l->data,NULL);
--- a/libpurple/protocols/mxit/multimx.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/mxit/multimx.c	Sun Jun 23 13:35:53 2013 +0530
@@ -638,7 +638,7 @@
 	if (multimx->nickname)
 		nickname = multimx->nickname;
 	else
-		nickname = purple_account_get_alias(purple_connection_get_account(gc));		/* local alias */
+		nickname = purple_account_get_private_alias(purple_connection_get_account(gc));		/* local alias */
 
 	/* Display message in chat window */
 	serv_got_chat_in(gc, id, nickname, flags, message, time(NULL));
--- a/libpurple/protocols/myspace/myspace.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/myspace/myspace.c	Sun Jun 23 13:35:53 2013 +0530
@@ -36,8 +36,6 @@
 
 #include "myspace.h"
 
-#include "privacy.h"
-
 static void msim_set_status(PurpleAccount *account, PurpleStatus *status);
 static void msim_set_idle(PurpleConnection *gc, int time);
 
@@ -532,9 +530,8 @@
 msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE],
 		const gchar *email, const gchar *password, guint *response_len)
 {
-	PurpleCipherContext *key_context;
-	PurpleCipher *sha1;
-	PurpleCipherContext *rc4;
+	PurpleHash *sha1;
+	PurpleCipher *rc4;
 
 	guchar hash_pw[HASH_SIZE];
 	guchar key[HASH_SIZE];
@@ -583,8 +580,11 @@
 	}
 
 	/* Compute password hash */
-	purple_cipher_digest_region("sha1", (guchar *)password_utf16le,
-			conv_bytes_written, hash_pw, sizeof(hash_pw));
+	sha1 = purple_sha1_hash_new();
+	purple_hash_append(sha1, (guchar *)password_utf16le,
+					   conv_bytes_written);
+	purple_hash_digest(sha1, hash_pw, sizeof(hash_pw));
+	purple_hash_reset(sha1);
 	g_free(password_utf16le);
 
 #ifdef MSIM_DEBUG_LOGIN_CHALLENGE
@@ -595,12 +595,10 @@
 #endif
 
 	/* key = sha1(sha1(pw) + nonce2) */
-	sha1 = purple_ciphers_find_cipher("sha1");
-	key_context = purple_cipher_context_new(sha1, NULL);
-	purple_cipher_context_append(key_context, hash_pw, HASH_SIZE);
-	purple_cipher_context_append(key_context, (guchar *)(nonce + NONCE_SIZE), NONCE_SIZE);
-	purple_cipher_context_digest(key_context, key, sizeof(key));
-	purple_cipher_context_destroy(key_context);
+	purple_hash_append(sha1, hash_pw, HASH_SIZE);
+	purple_hash_append(sha1, (guchar *)(nonce + NONCE_SIZE), NONCE_SIZE);
+	purple_hash_digest(sha1, key, sizeof(key));
+	g_object_unref(sha1);
 
 #ifdef MSIM_DEBUG_LOGIN_CHALLENGE
 	purple_debug_info("msim", "key = ");
@@ -610,11 +608,11 @@
 	purple_debug_info("msim", "\n");
 #endif
 
-	rc4 = purple_cipher_context_new_by_name("rc4", NULL);
+	rc4 = purple_rc4_cipher_new();
 
 	/* Note: 'key' variable is 0x14 bytes (from SHA-1 hash),
 	 * but only first 0x10 used for the RC4 key. */
-	purple_cipher_context_set_key(rc4, key, 0x10);
+	purple_cipher_set_key(rc4, key, 0x10);
 
 	/* rc4 encrypt:
 	 * nonce1+email+IP list */
@@ -640,9 +638,9 @@
 
 	data_out = g_new0(guchar, data->len);
 
-	data_out_len = purple_cipher_context_encrypt(rc4,
+	data_out_len = purple_cipher_encrypt(rc4,
 		(const guchar *)data->str, data->len, data_out, data->len);
-	purple_cipher_context_destroy(rc4);
+	g_object_unref(rc4);
 
 	if (data_out_len != data->len) {
 		purple_debug_info("msim", "msim_compute_login_response: "
@@ -1019,7 +1017,7 @@
 	visibility = msim_msg_get_integer(contact_info, "Visibility");
 	if (visibility == 2) {
 		/* This buddy is blocked (and therefore not on our buddy list */
-		purple_privacy_deny_add(session->account, username, TRUE);
+		purple_account_privacy_deny_add(session->account, username, TRUE);
 		msim_msg_free(contact_info);
 		g_free(username);
 		g_free(display_name);
@@ -2179,6 +2177,7 @@
 {
 	PurpleConnection *gc;
 	const gchar *host;
+	GSList *deny;
 	int port;
 
 	g_return_if_fail(acct != NULL);
@@ -2195,8 +2194,8 @@
 	 * list of all blocked buddies from the server, and we shouldn't
 	 * have stuff in the local list that isn't on the server list.
 	 */
-	while (acct->deny != NULL)
-		purple_privacy_deny_remove(acct, acct->deny->data, TRUE);
+	while ((deny = purple_account_privacy_get_denied(acct)) != NULL)
+		purple_account_privacy_deny_remove(acct, deny->data, TRUE);
 
 	/* 1. connect to server */
 	purple_connection_update_progress(gc, _("Connecting"),
@@ -3089,16 +3088,6 @@
 static gboolean
 msim_load(PurplePlugin *plugin)
 {
-	/* If compiled to use RC4 from libpurple, check if it is really there. */
-	if (!purple_ciphers_find_cipher("rc4")) {
-		purple_debug_error("msim", "rc4 not in libpurple, but it is required - not loading MySpaceIM plugin!\n");
-		purple_notify_error(plugin, _("Missing Cipher"),
-				_("The RC4 cipher could not be found"),
-				_("Upgrade "
-					"to a libpurple with RC4 support (>= 2.0.1). MySpaceIM "
-					"plugin will not be loaded."));
-		return FALSE;
-	}
 	return TRUE;
 }
 
--- a/libpurple/protocols/myspace/myspace.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/myspace/myspace.h	Sun Jun 23 13:35:53 2013 +0530
@@ -42,7 +42,6 @@
 #include "plugin.h"
 #include "accountopt.h"
 #include "version.h"
-#include "cipher.h"     /* for SHA-1 */
 #include "util.h"       /* for base64 */
 #include "debug.h"      /* for purple_debug_info */
 #include "request.h"    /* For dialogs used in setting the username */
@@ -50,6 +49,10 @@
 #include "core.h"
 #include "conversation.h" /* For late normalization */
 
+/* Ciphers */
+#include "ciphers/rc4cipher.h"
+#include "ciphers/sha1hash.h"
+
 /* MySpaceIM includes */
 #include "persist.h"
 #include "message.h"
--- a/libpurple/protocols/novell/novell.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/novell/novell.c	Sun Jun 23 13:35:53 2013 +0530
@@ -29,7 +29,6 @@
 #include "sslconn.h"
 #include "request.h"
 #include "network.h"
-#include "privacy.h"
 #include "status.h"
 #include "version.h"
 
@@ -102,12 +101,12 @@
 	if (ret_code == NM_OK) {
 
 		/* Set alias for user if not set (use Full Name) */
-		alias = purple_account_get_alias(user->client_data);
+		alias = purple_account_get_private_alias(user->client_data);
 		if (alias == NULL || *alias == '\0') {
 			alias = nm_user_record_get_full_name(user->user_record);
 
 			if (alias)
-				purple_account_set_alias(user->client_data, alias);
+				purple_account_set_private_alias(user->client_data, alias);
 		}
 
 		/* Tell Purple that we are connected */
@@ -726,6 +725,7 @@
 								   gpointer resp_data, gpointer user_data)
 {
 	PurpleConnection *gc;
+	PurpleAccount *account;
 	NMUserRecord *user_record = resp_data;
 	char *err;
 	gboolean allowed = GPOINTER_TO_INT(user_data);
@@ -736,21 +736,22 @@
 
 	gc = purple_account_get_connection(user->client_data);
 	display_id = nm_user_record_get_display_id(user_record);
+	account = purple_connection_get_account(gc);
 
 	if (ret_code == NM_OK) {
 
 		if (allowed) {
 
-			if (!g_slist_find_custom(purple_connection_get_account(gc)->permit,
+			if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
 									 display_id, (GCompareFunc)purple_utf8_strcasecmp)) {
-				purple_privacy_permit_add(purple_connection_get_account(gc), display_id, TRUE);
+				purple_account_privacy_permit_add(account, display_id, TRUE);
 			}
 
 		} else {
 
-			if (!g_slist_find_custom(purple_connection_get_account(gc)->permit,
+			if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
 									 display_id, (GCompareFunc)purple_utf8_strcasecmp)) {
-				purple_privacy_deny_add(purple_connection_get_account(gc), display_id, TRUE);
+				purple_account_privacy_deny_add(account, display_id, TRUE);
 			}
 		}
 
@@ -770,6 +771,7 @@
 								  gpointer resp_data, gpointer user_data)
 {
 	PurpleConnection *gc;
+	PurpleAccount *account;
 	NMUserRecord *user_record;
 	char *who = user_data;
 	char *err;
@@ -780,6 +782,7 @@
 		return;
 
 	gc = purple_account_get_connection(user->client_data);
+	account = purple_connection_get_account(gc);
 
 	if (ret_code == NM_OK) {
 
@@ -789,10 +792,10 @@
 
 		if (display_id) {
 
-			if (!g_slist_find_custom(purple_connection_get_account(gc)->deny,
+			if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
 									 display_id, (GCompareFunc)purple_utf8_strcasecmp)) {
 
-				purple_privacy_deny_add(purple_connection_get_account(gc), display_id, TRUE);
+				purple_account_privacy_deny_add(account, display_id, TRUE);
 			}
 
 		} else {
@@ -821,6 +824,7 @@
 									gpointer resp_data, gpointer user_data)
 {
 	PurpleConnection *gc;
+	PurpleAccount *account;
 	NMUserRecord *user_record;
 	char *who = user_data;
 	char *err;
@@ -831,6 +835,7 @@
 		return;
 
 	gc = purple_account_get_connection(user->client_data);
+	account = purple_connection_get_account(gc);
 
 	if (ret_code == NM_OK) {
 
@@ -840,11 +845,11 @@
 
 		if (display_id) {
 
-			if (!g_slist_find_custom(purple_connection_get_account(gc)->permit,
+			if (!g_slist_find_custom(purple_account_privacy_get_permitted(account),
 									 display_id,
 									 (GCompareFunc)purple_utf8_strcasecmp)) {
 
-				purple_privacy_permit_add(purple_connection_get_account(gc), display_id, TRUE);
+				purple_account_privacy_permit_add(account, display_id, TRUE);
 			}
 
 		} else {
@@ -1386,6 +1391,7 @@
 {
 	GSList *node = NULL, *rem_list = NULL;
 	PurpleConnection *gc;
+	PurpleAccount *account;
 	const char *name, *dn;
 	NMUserRecord *user_record;
 
@@ -1396,18 +1402,20 @@
 	if (gc == NULL)
 		return;
 
+	account = purple_connection_get_account(gc);
+
 	/* Set the Purple privacy setting */
 	if (user->default_deny) {
 		if (user->allow_list == NULL) {
-			purple_account_set_privacy_type(purple_connection_get_account(gc), PURPLE_PRIVACY_DENY_ALL);
+			purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_DENY_ALL);
 		} else {
-			purple_account_set_privacy_type(purple_connection_get_account(gc), PURPLE_PRIVACY_ALLOW_USERS);
+			purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS);
 		}
 	} else {
 		if (user->deny_list == NULL) {
-			purple_account_set_privacy_type(purple_connection_get_account(gc), PURPLE_PRIVACY_ALLOW_ALL);
+			purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL);
 		} else {
-			purple_account_set_privacy_type(purple_connection_get_account(gc), PURPLE_PRIVACY_DENY_USERS);
+			purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_DENY_USERS);
 		}
 	}
 
@@ -1419,9 +1427,9 @@
 		else
 			name =(char *)node->data;
 
-		if (!g_slist_find_custom(purple_connection_get_account(gc)->permit,
+		if (!g_slist_find_custom(purple_account_privacy_get_permitted(account),
 								 name, (GCompareFunc)purple_utf8_strcasecmp)) {
-			purple_privacy_permit_add(purple_connection_get_account(gc), name , TRUE);
+			purple_account_privacy_permit_add(account, name , TRUE);
 		}
 	}
 
@@ -1432,15 +1440,15 @@
 		else
 			name =(char *)node->data;
 
-		if (!g_slist_find_custom(purple_connection_get_account(gc)->deny,
+		if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
 								 name, (GCompareFunc)purple_utf8_strcasecmp)) {
-			purple_privacy_deny_add(purple_connection_get_account(gc), name, TRUE);
+			purple_account_privacy_deny_add(account, name, TRUE);
 		}
 	}
 
 
 	/*  Remove stuff */
-	for (node = purple_connection_get_account(gc)->permit; node; node = node->next) {
+	for (node = purple_account_privacy_get_permitted(account); node; node = node->next) {
 		dn = nm_lookup_dn(user, (char *)node->data);
 		if (dn != NULL &&
 			!g_slist_find_custom(user->allow_list,
@@ -1451,13 +1459,13 @@
 
 	if (rem_list) {
 		for (node = rem_list; node; node = node->next) {
-			purple_privacy_permit_remove(purple_connection_get_account(gc), (char *)node->data, TRUE);
+			purple_account_privacy_permit_remove(account, (char *)node->data, TRUE);
 		}
 		g_slist_free(rem_list);
 		rem_list = NULL;
 	}
 
-	for (node = purple_connection_get_account(gc)->deny; node; node = node->next) {
+	for (node = purple_account_privacy_get_denied(account); node; node = node->next) {
 		dn = nm_lookup_dn(user, (char *)node->data);
 		if (dn != NULL &&
 			!g_slist_find_custom(user->deny_list,
@@ -1468,7 +1476,7 @@
 
 	if (rem_list) {
 		for (node = rem_list; node; node = node->next) {
-			purple_privacy_deny_remove(purple_connection_get_account(gc), (char *)node->data, TRUE);
+			purple_account_privacy_deny_remove(account, (char *)node->data, TRUE);
 		}
 		g_slist_free(rem_list);
 	}
@@ -2502,7 +2510,7 @@
 				if (!_check_for_disconnect(user, rc)) {
 
 					/* Use the account alias if it is set */
-					name = purple_account_get_alias(user->client_data);
+					name = purple_account_get_private_alias(user->client_data);
 					if (name == NULL || *name == '\0') {
 
 						/* If there is no account alias, try full name */
@@ -3086,7 +3094,7 @@
 	/* Remove first -- we will add it back in when we get
 	 * the okay from the server
 	 */
-	purple_privacy_permit_remove(purple_connection_get_account(gc), who, TRUE);
+	purple_account_privacy_permit_remove(purple_connection_get_account(gc), who, TRUE);
 
 	if (nm_user_is_privacy_locked(user)) {
 		_show_privacy_locked_error(gc, user);
@@ -3130,7 +3138,7 @@
 	/* Remove first -- we will add it back in when we get
 	 * the okay from the server
 	 */
-	purple_privacy_deny_remove(purple_connection_get_account(gc), who, TRUE);
+	purple_account_privacy_deny_remove(purple_connection_get_account(gc), who, TRUE);
 
 	if (nm_user_is_privacy_locked(user)) {
 		_show_privacy_locked_error(gc, user);
@@ -3228,10 +3236,13 @@
 	int i, j, num_contacts, num_folders;
 	NMContact *contact;
 	NMFolder *folder = NULL;
+	PurpleAccount *account;
 
 	if (gc == NULL)
 		return;
 
+	account = purple_connection_get_account(gc);
+
 	user = purple_connection_get_protocol_data(gc);
 	if (user == NULL)
 		return;
@@ -3248,9 +3259,9 @@
 		return;
 	}
 
-	switch (purple_account_get_privacy_type(purple_connection_get_account(gc))) {
-
-		case PURPLE_PRIVACY_ALLOW_ALL:
+	switch (purple_account_get_privacy_type(account)) {
+
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
 			rc = nm_send_set_privacy_default(user, FALSE,
 											 _set_privacy_default_resp_cb, NULL);
 			_check_for_disconnect(user, rc);
@@ -3270,7 +3281,7 @@
 			}
 			break;
 
-		case PURPLE_PRIVACY_DENY_ALL:
+		case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
 			rc = nm_send_set_privacy_default(user, TRUE,
 											 _set_privacy_default_resp_cb, NULL);
 			_check_for_disconnect(user, rc);
@@ -3290,7 +3301,7 @@
 			}
 			break;
 
-		case PURPLE_PRIVACY_ALLOW_USERS:
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
 
 			rc = nm_send_set_privacy_default(user, TRUE,
 											 _set_privacy_default_resp_cb, NULL);
@@ -3304,14 +3315,14 @@
 					if (user_record) {
 						name = nm_user_record_get_display_id(user_record);
 
-						if (!g_slist_find_custom(purple_connection_get_account(gc)->permit,
+						if (!g_slist_find_custom(purple_account_privacy_get_permitted(account),
 												 name, (GCompareFunc)purple_utf8_strcasecmp)) {
-							purple_privacy_permit_add(purple_connection_get_account(gc), name , TRUE);
+							purple_account_privacy_permit_add(account, name , TRUE);
 						}
 					}
 				}
 
-				for (node = purple_connection_get_account(gc)->permit; node; node = node->next) {
+				for (node = purple_account_privacy_get_permitted(account); node; node = node->next) {
 					dn = nm_lookup_dn(user, (char *)node->data);
 					if (dn) {
 
@@ -3322,13 +3333,13 @@
 															 g_strdup(dn));
 						}
 					} else {
-						purple_privacy_permit_remove(purple_connection_get_account(gc), (char *)node->data, TRUE);
+						purple_account_privacy_permit_remove(account, (char *)node->data, TRUE);
 					}
 				}
 			}
 			break;
 
-		case PURPLE_PRIVACY_DENY_USERS:
+		case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
 
 			/* set to default allow */
 			rc = nm_send_set_privacy_default(user, FALSE,
@@ -3343,14 +3354,14 @@
 					if (user_record) {
 						name = nm_user_record_get_display_id(user_record);
 
-						if (!g_slist_find_custom(purple_connection_get_account(gc)->deny,
+						if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
 												 name, (GCompareFunc)purple_utf8_strcasecmp)) {
-							purple_privacy_deny_add(purple_connection_get_account(gc), name , TRUE);
+							purple_account_privacy_deny_add(account, name , TRUE);
 						}
 					}
 				}
 
-				for (node = purple_connection_get_account(gc)->deny; node; node = node->next) {
+				for (node = purple_account_privacy_get_denied(account); node; node = node->next) {
 
 					name = NULL;
 					dn = nm_lookup_dn(user, (char *)node->data);
@@ -3365,14 +3376,14 @@
 															 g_strdup(name));
 						}
 					} else {
-						purple_privacy_deny_remove(purple_connection_get_account(gc), (char *)node->data, TRUE);
+						purple_account_privacy_deny_remove(account, (char *)node->data, TRUE);
 					}
 				}
 
 			}
 			break;
 
-		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST:
 
 			/* remove users from allow list that are not in buddy list */
 			copy = g_slist_copy(user->allow_list);
--- a/libpurple/protocols/oscar/clientlogin.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/oscar/clientlogin.c	Sun Jun 23 13:35:53 2013 +0530
@@ -38,9 +38,10 @@
 
 #include "oscar.h"
 #include "oscarcommon.h"
+#include "core.h"
 
-#include "cipher.h"
-#include "core.h"
+#include "ciphers/hmaccipher.h"
+#include "ciphers/sha256hash.h"
 
 #define AIM_LOGIN_HOST "api.screenname.aol.com"
 #define ICQ_LOGIN_HOST "api.login.icq.net"
@@ -128,15 +129,17 @@
  */
 static gchar *hmac_sha256(const char *key, const char *message)
 {
-	PurpleCipherContext *context;
+	PurpleCipher *cipher;
+	PurpleHash *hash;
 	guchar digest[32];
 
-	context = purple_cipher_context_new_by_name("hmac", NULL);
-	purple_cipher_context_set_option(context, "hash", "sha256");
-	purple_cipher_context_set_key(context, (guchar *)key, strlen(key));
-	purple_cipher_context_append(context, (guchar *)message, strlen(message));
-	purple_cipher_context_digest(context, digest, sizeof(digest));
-	purple_cipher_context_destroy(context);
+	hash = purple_sha256_hash_new();
+	cipher = purple_hmac_cipher_new(hash);
+	purple_cipher_set_key(cipher, (guchar *)key, strlen(key));
+	purple_cipher_append(cipher, (guchar *)message, strlen(message));
+	purple_cipher_digest(cipher, digest, sizeof(digest));
+	g_object_unref(cipher);
+	g_object_unref(hash);
 
 	return purple_base64_encode(digest, sizeof(digest));
 }
--- a/libpurple/protocols/oscar/family_auth.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/oscar/family_auth.c	Sun Jun 23 13:35:53 2013 +0530
@@ -31,7 +31,7 @@
 
 #include <ctype.h>
 
-#include "cipher.h"
+#include "ciphers/md5hash.h"
 
 /* #define USE_XOR_FOR_ICQ */
 
@@ -75,14 +75,14 @@
 static int
 aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest)
 {
-	PurpleCipherContext *context;
+	PurpleHash *hash;
 
-	context = purple_cipher_context_new_by_name("md5", NULL);
-	purple_cipher_context_append(context, (const guchar *)key, strlen(key));
-	purple_cipher_context_append(context, (const guchar *)password, password_len);
-	purple_cipher_context_append(context, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
-	purple_cipher_context_digest(context, 16, digest, NULL);
-	purple_cipher_context_destroy(context);
+	hash = purple_md5_hash_new();
+	purple_hash_append(hash, (const guchar *)key, strlen(key));
+	purple_hash_append(hash, (const guchar *)password, password_len);
+	purple_hash_append(hash, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
+	purple_hash_digest(hash, 16, digest, NULL);
+	g_object_unref(hash);
 
 	return 0;
 }
@@ -90,23 +90,19 @@
 static int
 aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest)
 {
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
+	PurpleHash *hash;
 	guchar passdigest[16];
 
-	cipher = purple_ciphers_find_cipher("md5");
-
-	context = purple_cipher_context_new(cipher, NULL);
-	purple_cipher_context_append(context, (const guchar *)password, password_len);
-	purple_cipher_context_digest(context, passdigest, sizeof(passdigest));
-	purple_cipher_context_destroy(context);
+	hash = purple_md5_hash_new();
+	purple_hash_append(hash, (const guchar *)password, password_len);
+	purple_hash_digest(hash, passdigest, sizeof(passdigest));
+	purple_hash_reset(hash);
 
-	context = purple_cipher_context_new(cipher, NULL);
-	purple_cipher_context_append(context, (const guchar *)key, strlen(key));
-	purple_cipher_context_append(context, passdigest, 16);
-	purple_cipher_context_append(context, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
-	purple_cipher_context_digest(context, digest, 16);
-	purple_cipher_context_destroy(context);
+	purple_hash_append(hash, (const guchar *)key, strlen(key));
+	purple_hash_append(hash, passdigest, 16);
+	purple_hash_append(hash, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
+	purple_hash_digest(hash, digest, 16);
+	g_object_unref(hash);
 
 	return 0;
 }
--- a/libpurple/protocols/oscar/family_oservice.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/oscar/family_oservice.c	Sun Jun 23 13:35:53 2013 +0530
@@ -25,7 +25,7 @@
 
 #include "oscar.h"
 
-#include "cipher.h"
+#include "ciphers/md5hash.h"
 
 /*
  * Each time we make a FLAP connection to an oscar server the server gives
@@ -972,18 +972,18 @@
 		byte_stream_putraw(&bs, buf, 0x10);
 
 	} else if (buf && (len > 0)) { /* use input buffer */
-		PurpleCipherContext *context;
+		PurpleHash *hash;
 		guchar digest[16];
 
-		context = purple_cipher_context_new_by_name("md5", NULL);
-		purple_cipher_context_append(context, buf, len);
-		purple_cipher_context_digest(context, digest, sizeof(digest));
-		purple_cipher_context_destroy(context);
+		hash = purple_md5_hash_new();
+		purple_hash_append(hash, buf, len);
+		purple_hash_digest(hash, digest, sizeof(digest));
+		g_object_unref(hash);
 
 		byte_stream_putraw(&bs, digest, 0x10);
 
 	} else if (len == 0) { /* no length, just hash NULL (buf is optional) */
-		PurpleCipherContext *context;
+		PurpleHash *hash;
 		guchar digest[16];
 		guint8 nil = '\0';
 
@@ -991,10 +991,10 @@
 		 * I'm not sure if we really need the empty append with the
 		 * new MD5 functions, so I'll leave it in, just in case.
 		 */
-		context = purple_cipher_context_new_by_name("md5", NULL);
-		purple_cipher_context_append(context, &nil, 0);
-		purple_cipher_context_digest(context, digest, sizeof(digest));
-		purple_cipher_context_destroy(context);
+		hash = purple_md5_hash_new();
+		purple_hash_append(hash, &nil, 0);
+		purple_hash_digest(hash, digest, sizeof(digest));
+		g_object_unref(hash);
 
 		byte_stream_putraw(&bs, digest, 0x10);
 
--- a/libpurple/protocols/oscar/flap_connection.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/oscar/flap_connection.c	Sun Jun 23 13:35:53 2013 +0530
@@ -336,7 +336,7 @@
 
 	conn = g_new0(FlapConnection, 1);
 	conn->od = od;
-	conn->buffer_outgoing = purple_circ_buffer_new(0);
+	conn->buffer_outgoing = purple_circular_buffer_new(0);
 	conn->fd = -1;
 	conn->subtype = -1;
 	conn->type = type;
@@ -410,7 +410,7 @@
 	g_free(conn->buffer_incoming.data.data);
 	conn->buffer_incoming.data.data = NULL;
 
-	purple_circ_buffer_destroy(conn->buffer_outgoing);
+	g_object_unref(G_OBJECT(conn->buffer_outgoing));
 	conn->buffer_outgoing = NULL;
 }
 
@@ -1020,9 +1020,11 @@
 {
 	FlapConnection *conn;
 	int writelen, ret;
+	const gchar *output = NULL;
 
 	conn = data;
-	writelen = purple_circ_buffer_get_max_read(conn->buffer_outgoing);
+	writelen = purple_circular_buffer_get_max_read(conn->buffer_outgoing);
+	output = purple_circular_buffer_get_output(conn->buffer_outgoing);
 
 	if (writelen == 0)
 	{
@@ -1032,10 +1034,9 @@
 	}
 
 	if (conn->gsc)
-		ret = purple_ssl_write(conn->gsc, conn->buffer_outgoing->outptr,
-				writelen);
+		ret = purple_ssl_write(conn->gsc, output, writelen);
 	else
-		ret = send(conn->fd, conn->buffer_outgoing->outptr, writelen, 0);
+		ret = send(conn->fd, output, writelen, 0);
 	if (ret <= 0)
 	{
 		if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
@@ -1057,7 +1058,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(conn->buffer_outgoing, ret);
+	purple_circular_buffer_mark_read(conn->buffer_outgoing, ret);
 }
 
 static void
@@ -1074,7 +1075,7 @@
 		return;
 
 	/* Add everything to our outgoing buffer */
-	purple_circ_buffer_append(conn->buffer_outgoing, bs->data, count);
+	purple_circular_buffer_append(conn->buffer_outgoing, bs->data, count);
 
 	/* If we haven't already started writing stuff, then start the cycle */
 	if (conn->watcher_outgoing == 0)
--- a/libpurple/protocols/oscar/oft.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/oscar/oft.c	Sun Jun 23 13:35:53 2013 +0530
@@ -360,7 +360,7 @@
 
 	conn = data;
 
-	if (purple_circ_buffer_get_max_read(conn->buffer_outgoing) == 0)
+	if (purple_circular_buffer_get_max_read(conn->buffer_outgoing) == 0)
 	{
 		int fd = conn->fd;
 		conn->sending_data_timer = 0;
@@ -385,7 +385,7 @@
 
 	conn = data;
 
-	if (purple_circ_buffer_get_max_read(conn->buffer_outgoing) == 0)
+	if (purple_circular_buffer_get_max_read(conn->buffer_outgoing) == 0)
 	{
 		conn->sending_data_timer = 0;
 		peer_connection_destroy(conn, conn->disconnect_reason, NULL);
--- a/libpurple/protocols/oscar/oscar.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/oscar/oscar.c	Sun Jun 23 13:35:53 2013 +0530
@@ -33,7 +33,7 @@
 #include "account.h"
 #include "accountopt.h"
 #include "buddyicon.h"
-#include "cipher.h"
+#include "ciphers/md5hash.h"
 #include "conversation.h"
 #include "core.h"
 #include "debug.h"
@@ -41,7 +41,6 @@
 #include "imgstore.h"
 #include "network.h"
 #include "notify.h"
-#include "privacy.h"
 #include "prpl.h"
 #include "proxy.h"
 #include "request.h"
@@ -3118,10 +3117,12 @@
 	}
 	else {
 		/* Don't send if this turkey is in our deny list */
+		PurpleAccount *account = purple_connection_get_account(gc);
 		GSList *list;
-		for (list=purple_connection_get_account(gc)->deny; (list && oscar_util_name_compare(name, list->data)); list=list->next);
+
+		for (list=purple_account_privacy_get_denied(account); (list && oscar_util_name_compare(name, list->data)); list=list->next);
 		if (!list) {
-			struct buddyinfo *bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(purple_connection_get_account(gc), name));
+			struct buddyinfo *bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, name));
 			if (bi && bi->typingnot) {
 				if (state == PURPLE_TYPING)
 					aim_im_sendmtn(od, 0x0001, name, 0x0002);
@@ -3599,12 +3600,12 @@
 
 	/*
 	 * For ICQ the permit/deny setting controls who can see you
-	 * online. Mimicking the official client's behavior, we use PURPLE_PRIVACY_ALLOW_USERS
-	 * when our status is "invisible" and PURPLE_PRIVACY_DENY_USERS otherwise.
+	 * online. Mimicking the official client's behavior, we use PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS
+	 * when our status is "invisible" and PURPLE_ACCOUNT_PRIVACY_DENY_USERS otherwise.
 	 * In the former case, we are visible only to buddies on our "permanently visible" list.
 	 * In the latter, we are invisible only to buddies on our "permanently invisible" list.
 	 */
-	aim_ssi_setpermdeny(od, invisible ? PURPLE_PRIVACY_ALLOW_USERS : PURPLE_PRIVACY_DENY_USERS);
+	aim_ssi_setpermdeny(od, invisible ? PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS : PURPLE_ACCOUNT_PRIVACY_DENY_USERS);
 }
 
 void
@@ -3909,27 +3910,27 @@
 
 	/* Permit list (ICQ doesn't have one) */
 	if (!od->icq) {
-		next = account->permit;
+		next = purple_account_privacy_get_permitted(account);
 		while (next != NULL) {
 			cur = next;
 			next = next->next;
 			if (!aim_ssi_itemlist_finditem(&od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
 				purple_debug_info("oscar",
 						"ssi: removing permit %s from local list\n", (const char *)cur->data);
-				purple_privacy_permit_remove(account, cur->data, TRUE);
+				purple_account_privacy_permit_remove(account, cur->data, TRUE);
 			}
 		}
 	}
 
 	/* Deny list */
-	next = account->deny;
+	next = purple_account_privacy_get_denied(account);
 	while (next != NULL) {
 		cur = next;
 		next = next->next;
 		if (!aim_ssi_itemlist_finditem(&od->ssi.local, NULL, cur->data, deny_entry_type)) {
 			purple_debug_info("oscar",
 					"ssi: removing deny %s from local list\n", (const char *)cur->data);
-			purple_privacy_deny_remove(account, cur->data, TRUE);
+			purple_account_privacy_deny_remove(account, cur->data, TRUE);
 		}
 	}
 
@@ -4016,11 +4017,11 @@
 
 			case AIM_SSI_TYPE_PERMIT: { /* Permit buddy (unless we're on ICQ) */
 				if (!od->icq && curitem->name) {
-					for (cur = account->permit; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
+					for (cur = purple_account_privacy_get_permitted(account); (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
 					if (!cur) {
 						purple_debug_info("oscar",
 								   "ssi: adding permit buddy %s to local list\n", curitem->name);
-						purple_privacy_permit_add(account, curitem->name, TRUE);
+						purple_account_privacy_permit_add(account, curitem->name, TRUE);
 					}
 				}
 			} break;
@@ -4028,11 +4029,11 @@
 			case AIM_SSI_TYPE_ICQDENY:
 			case AIM_SSI_TYPE_DENY: { /* Deny buddy */
 				if (curitem->type == deny_entry_type && curitem->name) {
-					for (cur = account->deny; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
+					for (cur = purple_account_privacy_get_denied(account); (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
 					if (!cur) {
 						purple_debug_info("oscar",
 								   "ssi: adding deny buddy %s to local list\n", curitem->name);
-						purple_privacy_deny_add(account, curitem->name, TRUE);
+						purple_account_privacy_deny_add(account, curitem->name, TRUE);
 					}
 				}
 			} break;
@@ -5336,15 +5337,15 @@
 	if (img == NULL) {
 		aim_ssi_delicon(od);
 	} else {
-		PurpleCipherContext *context;
+		PurpleHash *hash;
 		guchar md5[16];
 		gconstpointer data = purple_imgstore_get_data(img);
 		size_t len = purple_imgstore_get_size(img);
 
-		context = purple_cipher_context_new_by_name("md5", NULL);
-		purple_cipher_context_append(context, data, len);
-		purple_cipher_context_digest(context, md5, sizeof(md5));
-		purple_cipher_context_destroy(context);
+		hash = purple_md5_hash_new();
+		purple_hash_append(hash, data, len);
+		purple_hash_digest(hash, md5, sizeof(md5));
+		g_object_unref(hash);
 
 		aim_ssi_seticon(od, md5, 16);
 	}
--- a/libpurple/protocols/oscar/oscar.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/oscar/oscar.h	Sun Jun 23 13:35:53 2013 +0530
@@ -30,7 +30,7 @@
 #define _OSCAR_H_
 
 #include "internal.h"
-#include "circbuffer.h"
+#include "circularbuffer.h"
 #include "debug.h"
 #include "eventloop.h"
 #include "proxy.h"
@@ -280,7 +280,7 @@
 	guint8 header[6];
 	gssize header_received;
 	FlapFrame buffer_incoming;
-	PurpleCircBuffer *buffer_outgoing;
+	PurpleCircularBuffer *buffer_outgoing;
 	guint watcher_incoming;
 	guint watcher_outgoing;
 
--- a/libpurple/protocols/oscar/peer.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/oscar/peer.c	Sun Jun 23 13:35:53 2013 +0530
@@ -115,7 +115,7 @@
 	conn->od = od;
 	conn->type = type;
 	conn->bn = g_strdup(bn);
-	conn->buffer_outgoing = purple_circ_buffer_new(0);
+	conn->buffer_outgoing = purple_circular_buffer_new(0);
 	conn->listenerfd = -1;
 	conn->fd = -1;
 	conn->lastactivity = time(NULL);
@@ -189,8 +189,8 @@
 	conn->buffer_incoming.len = 0;
 	conn->buffer_incoming.offset = 0;
 
-	purple_circ_buffer_destroy(conn->buffer_outgoing);
-	conn->buffer_outgoing = purple_circ_buffer_new(0);
+	g_object_unref(G_OBJECT(conn->buffer_outgoing));
+	conn->buffer_outgoing = purple_circular_buffer_new(0);
 
 	conn->flags &= ~PEER_CONNECTION_FLAG_IS_INCOMING;
 }
@@ -234,7 +234,7 @@
 	g_free(conn->clientip);
 	g_free(conn->verifiedip);
 	g_free(conn->xferdata.name);
-	purple_circ_buffer_destroy(conn->buffer_outgoing);
+	g_object_unref(G_OBJECT(conn->buffer_outgoing));
 
 	conn->od->peer_connections = g_slist_remove(conn->od->peer_connections, conn);
 
@@ -408,9 +408,10 @@
 	PeerConnection *conn;
 	gsize writelen;
 	gssize wrotelen;
+	const gchar *output = NULL;
 
 	conn = data;
-	writelen = purple_circ_buffer_get_max_read(conn->buffer_outgoing);
+	writelen = purple_circular_buffer_get_max_read(conn->buffer_outgoing);
 
 	if (writelen == 0)
 	{
@@ -433,12 +434,13 @@
 		 * file transfer.  Somebody should teach those guys how to
 		 * write good TCP code.
 		 */
-		conn->buffer_outgoing->inptr = conn->buffer_outgoing->buffer;
-		conn->buffer_outgoing->outptr = conn->buffer_outgoing->buffer;
+		purple_circular_buffer_reset(conn->buffer_outgoing);
 		return;
 	}
 
-	wrotelen = send(conn->fd, conn->buffer_outgoing->outptr, writelen, 0);
+	output = purple_circular_buffer_get_output(conn->buffer_outgoing);
+
+	wrotelen = send(conn->fd, output, writelen, 0);
 	if (wrotelen <= 0)
 	{
 		if (wrotelen < 0 && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
@@ -465,7 +467,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(conn->buffer_outgoing, wrotelen);
+	purple_circular_buffer_mark_read(conn->buffer_outgoing, wrotelen);
 	conn->lastactivity = time(NULL);
 }
 
@@ -478,7 +480,7 @@
 peer_connection_send(PeerConnection *conn, ByteStream *bs)
 {
 	/* Add everything to our outgoing buffer */
-	purple_circ_buffer_append(conn->buffer_outgoing, bs->data, bs->len);
+	purple_circular_buffer_append(conn->buffer_outgoing, bs->data, bs->len);
 
 	/* If we haven't already started writing stuff, then start the cycle */
 	if ((conn->watcher_outgoing == 0) && (conn->fd >= 0))
--- a/libpurple/protocols/oscar/peer.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/oscar/peer.h	Sun Jun 23 13:35:53 2013 +0530
@@ -184,7 +184,7 @@
 	guint8 proxy_header[12];
 	gssize proxy_header_received;
 	ByteStream buffer_incoming;
-	PurpleCircBuffer *buffer_outgoing;
+	PurpleCircularBuffer *buffer_outgoing;
 	guint watcher_incoming;
 	guint watcher_outgoing;
 
--- a/libpurple/protocols/sametime/sametime.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/sametime/sametime.c	Sun Jun 23 13:35:53 2013 +0530
@@ -33,7 +33,7 @@
 /* purple includes */
 #include "account.h"
 #include "accountopt.h"
-#include "circbuffer.h"
+#include "circularbuffer.h"
 #include "conversation.h"
 #include "debug.h"
 #include "ft.h"
@@ -41,7 +41,6 @@
 #include "mime.h"
 #include "notify.h"
 #include "plugin.h"
-#include "privacy.h"
 #include "prpl.h"
 #include "request.h"
 #include "util.h"
@@ -221,7 +220,7 @@
   gint outpa;  /* like inpa, but the other way */
 
   /** circular buffer for outgoing data */
-  PurpleCircBuffer *sock_buf;
+  PurpleCircularBuffer *sock_buf;
 
   PurpleConnection *gc;
 };
@@ -343,7 +342,7 @@
 
 static void write_cb(gpointer data, gint source, PurpleInputCondition cond) {
   struct mwPurplePluginData *pd = data;
-  PurpleCircBuffer *circ = pd->sock_buf;
+  PurpleCircularBuffer *circ = pd->sock_buf;
   gsize avail;
   int ret;
 
@@ -351,17 +350,17 @@
 
   g_return_if_fail(circ != NULL);
 
-  avail = purple_circ_buffer_get_max_read(circ);
+  avail = purple_circular_buffer_get_max_read(circ);
   if(BUF_LONG < avail) avail = BUF_LONG;
 
   while(avail) {
-    ret = write(pd->socket, circ->outptr, avail);
+    ret = write(pd->socket, purple_circular_buffer_get_output(circ), avail);
 
     if(ret <= 0)
       break;
 
-    purple_circ_buffer_mark_read(circ, ret);
-    avail = purple_circ_buffer_get_max_read(circ);
+    purple_circular_buffer_mark_read(circ, ret);
+    avail = purple_circular_buffer_get_max_read(circ);
     if(BUF_LONG < avail) avail = BUF_LONG;
   }
 
@@ -386,7 +385,7 @@
 
   if(pd->outpa) {
     DEBUG_INFO("already pending INPUT_WRITE, buffering\n");
-    purple_circ_buffer_append(pd->sock_buf, buf, len);
+    purple_circular_buffer_append(pd->sock_buf, buf, len);
     return 0;
   }
 
@@ -406,7 +405,7 @@
   if(err == EAGAIN) {
     /* append remainder to circular buffer */
     DEBUG_INFO("EAGAIN\n");
-    purple_circ_buffer_append(pd->sock_buf, buf, len);
+    purple_circular_buffer_append(pd->sock_buf, buf, len);
     pd->outpa = purple_input_add(pd->socket, PURPLE_INPUT_WRITE, write_cb, pd);
 
   } else if(len > 0) {
@@ -1634,7 +1633,7 @@
   PurpleConnection *gc;
   PurpleAccount *acct;
   struct mwPrivacyInfo *privacy;
-  GSList *l, **ll;
+  GSList *list;
   guint count;
 
   DEBUG_INFO("privacy information set from server\n");
@@ -1653,16 +1652,25 @@
   privacy = mwSession_getPrivacyInfo(session);
   count = privacy->count;
 
-  ll = (privacy->deny)? &acct->deny: &acct->permit;
-  for(l = *ll; l; l = l->next) g_free(l->data);
-  g_slist_free(*ll);
-  l = *ll = NULL;
-
-  while(count--) {
-    struct mwUserItem *u = privacy->users + count;
-    l = g_slist_prepend(l, g_strdup(u->id));
+  if (privacy->deny) {
+    while ((list = purple_account_privacy_get_denied(acct))) {
+      g_free(list->data);
+      purple_account_privacy_deny_remove(acct, list->data, TRUE);
+    }
+    while (count--) {
+      struct mwUserItem *u = privacy->users + count;
+      purple_account_privacy_deny_add(acct, u->id, TRUE);
+    }
+  } else {
+    while ((list = purple_account_privacy_get_permitted(acct))) {
+      g_free(list->data);
+      purple_account_privacy_permit_remove(acct, list->data, TRUE);
+    }
+    while (count--) {
+      struct mwUserItem *u = privacy->users + count;
+      purple_account_privacy_permit_add(acct, u->id, TRUE);
+    }
   }
-  *ll = l;
 }
 
 
@@ -3150,7 +3158,7 @@
   pd->srvc_resolve = mw_srvc_resolve_new(pd->session);
   pd->srvc_store = mw_srvc_store_new(pd->session);
   pd->group_list_map = g_hash_table_new(g_direct_hash, g_direct_equal);
-  pd->sock_buf = purple_circ_buffer_new(0);
+  pd->sock_buf = purple_circular_buffer_new(0);
 
   mwSession_addService(pd->session, MW_SERVICE(pd->srvc_aware));
   mwSession_addService(pd->session, MW_SERVICE(pd->srvc_conf));
@@ -3197,7 +3205,7 @@
   mwSession_free(pd->session);
 
   g_hash_table_destroy(pd->group_list_map);
-  purple_circ_buffer_destroy(pd->sock_buf);
+  g_object_unref(G_OBJECT(pd->sock_buf));
 
   g_free(pd);
 }
@@ -4604,25 +4612,25 @@
   g_return_if_fail(session != NULL);
 
   switch(purple_account_get_privacy_type(acct)) {
-  case PURPLE_PRIVACY_DENY_USERS:
-    DEBUG_INFO("PURPLE_PRIVACY_DENY_USERS\n");
-    privacy_fill(&privacy, acct->deny);
+  case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
+    DEBUG_INFO("PURPLE_ACCOUNT_PRIVACY_DENY_USERS\n");
+    privacy_fill(&privacy, purple_account_privacy_get_denied(acct));
     privacy.deny = TRUE;
     break;
 
-  case PURPLE_PRIVACY_ALLOW_ALL:
-    DEBUG_INFO("PURPLE_PRIVACY_ALLOW_ALL\n");
+  case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
+    DEBUG_INFO("PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL\n");
     privacy.deny = TRUE;
     break;
 
-  case PURPLE_PRIVACY_ALLOW_USERS:
-    DEBUG_INFO("PURPLE_PRIVACY_ALLOW_USERS\n");
-    privacy_fill(&privacy, acct->permit);
+  case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
+    DEBUG_INFO("PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS\n");
+    privacy_fill(&privacy, purple_account_privacy_get_permitted(acct));
     privacy.deny = FALSE;
     break;
 
-  case PURPLE_PRIVACY_DENY_ALL:
-    DEBUG_INFO("PURPLE_PRIVACY_DENY_ALL\n");
+  case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
+    DEBUG_INFO("PURPLE_ACCOUNT_PRIVACY_DENY_ALL\n");
     privacy.deny = FALSE;
     break;
 
--- a/libpurple/protocols/simple/simple.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/simple/simple.c	Sun Jun 23 13:35:53 2013 +0530
@@ -32,7 +32,6 @@
 #include "dnsquery.h"
 #include "debug.h"
 #include "notify.h"
-#include "privacy.h"
 #include "prpl.h"
 #include "plugin.h"
 #include "util.h"
@@ -274,7 +273,7 @@
 
 	if(auth->type == 1) { /* Digest */
 		sprintf(noncecount, "%08d", auth->nc++);
-		response = purple_cipher_http_digest_calculate_response(
+		response = purple_http_digest_calculate_response(
 							"md5", method, target, NULL, NULL,
 							auth->nonce, noncecount, NULL, auth->digest_session_key);
 		purple_debug(PURPLE_DEBUG_MISC, "simple", "response %s\n", response);
@@ -295,7 +294,7 @@
 	}
 
 	sprintf(noncecount, "%08d", auth->nc++);
-	response = purple_cipher_http_digest_calculate_response(
+	response = purple_http_digest_calculate_response(
 						"md5", method, target, NULL, NULL,
 						auth->nonce, noncecount, NULL, auth->digest_session_key);
 	purple_debug(PURPLE_DEBUG_MISC, "simple", "response %s\n", response);
@@ -399,7 +398,7 @@
 					 auth->realm ? auth->realm : "(null)");
 
 		if(auth->realm) {
-			auth->digest_session_key = purple_cipher_http_digest_calculate_session_key(
+			auth->digest_session_key = purple_http_digest_calculate_session_key(
 				"md5", authuser, auth->realm, sip->password, auth->nonce, NULL);
 
 			auth->nc = 1;
@@ -416,8 +415,9 @@
 	struct simple_account_data *sip = purple_connection_get_protocol_data(gc);
 	gsize max_write;
 	gssize written;
+	const gchar *output = NULL;
 
-	max_write = purple_circ_buffer_get_max_read(sip->txbuf);
+	max_write = purple_circular_buffer_get_max_read(sip->txbuf);
 
 	if(max_write == 0) {
 		purple_input_remove(sip->tx_handler);
@@ -425,7 +425,9 @@
 		return;
 	}
 
-	written = write(sip->fd, sip->txbuf->outptr, max_write);
+	output = purple_circular_buffer_get_output(sip->txbuf);
+
+	written = write(sip->fd, output, max_write);
 
 	if(written < 0 && errno == EAGAIN)
 		written = 0;
@@ -439,7 +441,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(sip->txbuf, written);
+	purple_circular_buffer_mark_read(sip->txbuf, written);
 }
 
 static void simple_input_cb(gpointer data, gint source, PurpleInputCondition cond);
@@ -465,7 +467,7 @@
 	simple_canwrite_cb(gc, sip->fd, PURPLE_INPUT_WRITE);
 
 	/* If there is more to write now, we need to register a handler */
-	if(sip->txbuf->bufused > 0)
+	if(purple_circular_buffer_get_used(sip->txbuf) > 0)
 		sip->tx_handler = purple_input_add(sip->fd, PURPLE_INPUT_WRITE,
 			simple_canwrite_cb, gc);
 
@@ -485,10 +487,10 @@
 		sip->connecting = TRUE;
 	}
 
-	if(purple_circ_buffer_get_max_read(sip->txbuf) > 0)
-		purple_circ_buffer_append(sip->txbuf, "\r\n", 2);
+	if(purple_circular_buffer_get_max_read(sip->txbuf) > 0)
+		purple_circular_buffer_append(sip->txbuf, "\r\n", 2);
 
-	purple_circ_buffer_append(sip->txbuf, buf, strlen(buf));
+	purple_circular_buffer_append(sip->txbuf, buf, strlen(buf));
 }
 
 static void sendout_pkt(PurpleConnection *gc, const char *buf) {
@@ -529,10 +531,10 @@
 
 			/* XXX: is it OK to do this? You might get part of a request sent
 			   with part of another. */
-			if(sip->txbuf->bufused > 0)
-				purple_circ_buffer_append(sip->txbuf, "\r\n", 2);
+			if(purple_circular_buffer_get_used(sip->txbuf) > 0)
+				purple_circular_buffer_append(sip->txbuf, "\r\n", 2);
 
-			purple_circ_buffer_append(sip->txbuf, buf + ret,
+			purple_circular_buffer_append(sip->txbuf, buf + ret,
 				writelen - ret);
 		}
 	}
@@ -1452,7 +1454,7 @@
 	if(!watcher) { /* new subscription */
 		const gchar *acceptheader = sipmsg_find_header(msg, "Accept");
 		gboolean needsxpidf = FALSE;
-		if(!purple_privacy_check(sip->account, from)) {
+		if(!purple_account_privacy_check(sip->account, from)) {
 			send_sip_response(sip->gc, msg, 202, "Ok", NULL);
 			goto privend;
 		}
@@ -1941,7 +1943,7 @@
 	sip->udp = purple_account_get_bool(account, "udp", FALSE);
 	/* TODO: is there a good default grow size? */
 	if(!sip->udp)
-		sip->txbuf = purple_circ_buffer_new(0);
+		sip->txbuf = purple_circular_buffer_new(0);
 
 	userserver = g_strsplit(username, "@", 2);
 	if (userserver[1] == NULL || userserver[1][0] == '\0') {
@@ -2037,7 +2039,7 @@
 		transactions_remove(sip, sip->transactions->data);
 	g_free(sip->publish_etag);
 	if (sip->txbuf)
-		purple_circ_buffer_destroy(sip->txbuf);
+		g_object_unref(G_OBJECT(sip->txbuf));
 	g_free(sip->realhostname);
 
 	g_free(sip);
--- a/libpurple/protocols/simple/simple.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/simple/simple.h	Sun Jun 23 13:35:53 2013 +0530
@@ -27,7 +27,7 @@
 #include <time.h>
 
 #include "cipher.h"
-#include "circbuffer.h"
+#include "circularbuffer.h"
 #include "dnsquery.h"
 #include "dnssrv.h"
 #include "network.h"
@@ -101,7 +101,7 @@
 	guint resendtimeout;
 	gboolean connecting;
 	PurpleAccount *account;
-	PurpleCircBuffer *txbuf;
+	PurpleCircularBuffer *txbuf;
 	guint tx_handler;
 	gchar *regcallid;
 	GSList *transactions;
--- a/libpurple/protocols/yahoo/libymsg.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/yahoo/libymsg.c	Sun Jun 23 13:35:53 2013 +0530
@@ -27,13 +27,12 @@
 #include "account.h"
 #include "accountopt.h"
 #include "blist.h"
-#include "cipher.h"
+#include "ciphers/md5hash.h"
 #include "cmds.h"
 #include "core.h"
 #include "debug.h"
 #include "network.h"
 #include "notify.h"
-#include "privacy.h"
 #include "prpl.h"
 #include "proxy.h"
 #include "request.h"
@@ -575,7 +574,7 @@
 				} else {
 					/* This buddy is on the ignore list (and therefore in no group) */
 					purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n", purple_account_get_username(account), norm_bud);
-					purple_privacy_deny_add(account, norm_bud, 1);
+					purple_account_privacy_deny_add(account, norm_bud, 1);
 				}
 
 				g_free(norm_bud);
@@ -738,7 +737,7 @@
 		for (bud = buddies; bud && *bud; bud++) {
 			/* The server is already ignoring the user */
 			got_serv_list = TRUE;
-			purple_privacy_deny_add(account, *bud, 1);
+			purple_account_privacy_deny_add(account, *bud, 1);
 		}
 		g_strfreev(buddies);
 
@@ -747,12 +746,12 @@
 	}
 
 	if (got_serv_list &&
-		((purple_account_get_privacy_type(account) != PURPLE_PRIVACY_ALLOW_BUDDYLIST) &&
-		(purple_account_get_privacy_type(account) != PURPLE_PRIVACY_DENY_ALL) &&
-		(purple_account_get_privacy_type(account) != PURPLE_PRIVACY_ALLOW_USERS)))
+		((purple_account_get_privacy_type(account) != PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST) &&
+		(purple_account_get_privacy_type(account) != PURPLE_ACCOUNT_PRIVACY_DENY_ALL) &&
+		(purple_account_get_privacy_type(account) != PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS)))
 	{
-		purple_account_set_privacy_type(account, PURPLE_PRIVACY_DENY_USERS);
-		purple_debug_info("yahoo", "%s privacy defaulting to PURPLE_PRIVACY_DENY_USERS.\n",
+		purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_DENY_USERS);
+		purple_debug_info("yahoo", "%s privacy defaulting to PURPLE_ACCOUNT_PRIVACY_DENY_USERS.\n",
 				purple_account_get_username(account));
 	}
 
@@ -820,7 +819,7 @@
 	}
 
 	if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING"))
-		&& (purple_privacy_check(account, from)))
+		&& (purple_account_privacy_check(account, from)))
 	{
 		char *fed_from = from;
 		switch (fed) {
@@ -1044,7 +1043,7 @@
 					{
 						PurpleWhiteboard *wb;
 
-						if (!purple_privacy_check(account, im->from)) {
+						if (!purple_account_privacy_check(account, im->from)) {
 							purple_debug_info("yahoo", "Doodle request from %s dropped.\n",
 												im->from);
 							g_free(im->fed_from);
@@ -1090,7 +1089,7 @@
 			continue;
 		}
 
-		if (!purple_privacy_check(account, im->fed_from)) {
+		if (!purple_account_privacy_check(account, im->fed_from)) {
 			purple_debug_info("yahoo", "Message from %s dropped.\n", im->fed_from);
 			return;
 		}
@@ -1409,7 +1408,7 @@
 		if (add_req->id && add_req->who) {
 			char *alias = NULL, *dec_msg = NULL;
 
-			if (!purple_privacy_check(account, add_req->who))
+			if (!purple_account_privacy_check(account, add_req->who))
 			{
 				purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
 						  add_req->who);
@@ -1482,7 +1481,7 @@
 	if (add_req->id && add_req->who) {
 		char *dec_msg = NULL;
 
-		if (!purple_privacy_check(account, add_req->who)) {
+		if (!purple_account_privacy_check(account, add_req->who)) {
 			purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
 					  add_req->who);
 			yahoo_buddy_add_deny_cb(NULL, add_req);
@@ -1692,18 +1691,16 @@
 	YahooData *yd = purple_connection_get_protocol_data(gc);
 	PurpleAccount *account = purple_connection_get_account(gc);
 	const char *name = purple_normalize(account, purple_account_get_username(account));
-	PurpleCipher *md5_cipher;
-	PurpleCipherContext *md5_ctx;
+	PurpleHash *md5_hash;
 	guchar md5_digest[16];
 	gchar base64_string[25];
 	struct yahoo_packet *pkt;
 
 	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage3\n");
 
-	md5_cipher = purple_ciphers_find_cipher("md5");
-	md5_ctx = purple_cipher_context_new(md5_cipher, NULL);
-	purple_cipher_context_append(md5_ctx, (guchar *)crypt, strlen(crypt));
-	purple_cipher_context_digest(md5_ctx, md5_digest, sizeof(md5_digest));
+	md5_hash = purple_md5_hash_new();
+	purple_hash_append(md5_hash, (guchar *)crypt, strlen(crypt));
+	purple_hash_digest(md5_hash, md5_digest, sizeof(md5_digest));
 
 	to_y64(base64_string, md5_digest, 16);
 
@@ -1741,7 +1738,7 @@
 		yahoo_packet_hash_int(pkt, 192, yd->picture_checksum);
 	yahoo_packet_send_and_free(pkt, yd);
 
-	purple_cipher_context_destroy(md5_ctx);
+	g_object_unref(md5_hash);
 }
 
 static gchar *yahoo_auth16_get_cookie_b(gchar *headers)
@@ -2112,7 +2109,7 @@
 
 static void keep_buddy(PurpleBuddy *b)
 {
-	purple_privacy_deny_remove(purple_buddy_get_account(b),
+	purple_account_privacy_deny_remove(purple_buddy_get_account(b),
 			purple_buddy_get_name(b), 1);
 }
 
@@ -2946,7 +2943,7 @@
 		purple_debug_misc("yahoo", "Warning, nonutf8 audible, ignoring!\n");
 		return;
 	}
-	if (!purple_privacy_check(account, who)) {
+	if (!purple_account_privacy_check(account, who)) {
 		purple_debug_misc("yahoo", "Audible message from %s for %s dropped!\n",
 				purple_account_get_username(account), who);
 		return;
@@ -3668,7 +3665,7 @@
 	yd->fd = -1;
 	yd->txhandler = 0;
 	/* TODO: Is there a good grow size for the buffer? */
-	yd->txbuf = purple_circ_buffer_new(0);
+	yd->txbuf = purple_circular_buffer_new(0);
 	yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free);
 	yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 	yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
@@ -3762,7 +3759,7 @@
 	if (yd->txhandler)
 		purple_input_remove(yd->txhandler);
 
-	purple_circ_buffer_destroy(yd->txbuf);
+	g_object_unref(G_OBJECT(yd->txbuf));
 
 	if (yd->fd >= 0)
 		close(yd->fd);
@@ -4543,7 +4540,7 @@
 			return -1;
 		}
 
-		alias = purple_account_get_alias(account);
+		alias = purple_account_get_private_alias(account);
 		pkt = yahoo_packet_new(YAHOO_SERVICE_SMS_MSG, YAHOO_STATUS_AVAILABLE, yd->session_id);
 		yahoo_packet_hash(pkt, "sssss",
 			1, purple_connection_get_display_name(gc),
@@ -4939,7 +4936,7 @@
 		return;
 
 	fed_bname = bname = purple_buddy_get_name(buddy);
-	if (!purple_privacy_check(purple_connection_get_account(gc), bname))
+	if (!purple_account_privacy_check(purple_connection_get_account(gc), bname))
 		return;
 
 	fed = yahoo_get_federation_from_name(bname);
@@ -5099,16 +5096,16 @@
 
 	switch (purple_account_get_privacy_type(account))
 	{
-		case PURPLE_PRIVACY_ALLOW_ALL:
-			for (deny = account->deny; deny; deny = deny->next)
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
+			for (deny = purple_account_privacy_get_denied(account); deny; deny = deny->next)
 				yahoo_rem_deny(gc, deny->data);
 			break;
 
-		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
-		case PURPLE_PRIVACY_ALLOW_USERS:
-		case PURPLE_PRIVACY_DENY_USERS:
-		case PURPLE_PRIVACY_DENY_ALL:
-			for (deny = account->deny; deny; deny = deny->next)
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST:
+		case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
+		case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
+		case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
+			for (deny = purple_account_privacy_get_denied(account); deny; deny = deny->next)
 				yahoo_add_deny(gc, deny->data);
 			break;
 	}
--- a/libpurple/protocols/yahoo/libymsg.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/yahoo/libymsg.h	Sun Jun 23 13:35:53 2013 +0530
@@ -25,7 +25,7 @@
 #ifndef _LIBYMSG_H_
 #define _LIBYMSG_H_
 
-#include "circbuffer.h"
+#include "circularbuffer.h"
 #include "cmds.h"
 #include "prpl.h"
 #include "network.h"
@@ -192,7 +192,7 @@
 	guint inpa;
 	guchar *rxqueue;
 	int rxlen;
-	PurpleCircBuffer *txbuf;
+	PurpleCircularBuffer *txbuf;
 	guint txhandler;
 	GHashTable *friends;
 
--- a/libpurple/protocols/yahoo/yahoo_doodle.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/yahoo/yahoo_doodle.c	Sun Jun 23 13:35:53 2013 +0530
@@ -33,7 +33,6 @@
 #include "cmds.h"
 #include "debug.h"
 #include "notify.h"
-#include "privacy.h"
 #include "prpl.h"
 #include "proxy.h"
 #include "request.h"
--- a/libpurple/protocols/yahoo/yahoo_packet.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/yahoo/yahoo_packet.c	Sun Jun 23 13:35:53 2013 +0530
@@ -287,8 +287,9 @@
 {
 	YahooData *yd = data;
 	int ret, writelen;
+	const gchar *output = NULL;
 
-	writelen = purple_circ_buffer_get_max_read(yd->txbuf);
+	writelen = purple_circular_buffer_get_max_read(yd->txbuf);
 
 	if (writelen == 0) {
 		purple_input_remove(yd->txhandler);
@@ -296,7 +297,9 @@
 		return;
 	}
 
-	ret = write(yd->fd, yd->txbuf->outptr, writelen);
+	output = purple_circular_buffer_get_output(yd->txbuf);
+
+	ret = write(yd->fd, output, writelen);
 
 	if (ret < 0 && errno == EAGAIN)
 		return;
@@ -307,7 +310,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(yd->txbuf, ret);
+	purple_circular_buffer_mark_read(yd->txbuf, ret);
 }
 
 
@@ -374,7 +377,7 @@
 		if (yd->txhandler == 0)
 			yd->txhandler = purple_input_add(yd->fd, PURPLE_INPUT_WRITE,
 				yahoo_packet_send_can_write, yd);
-		purple_circ_buffer_append(yd->txbuf, data + ret, len - ret);
+		purple_circular_buffer_append(yd->txbuf, data + ret, len - ret);
 	}
 
 	g_free(data);
--- a/libpurple/protocols/yahoo/yahoo_picture.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/yahoo/yahoo_picture.c	Sun Jun 23 13:35:53 2013 +0530
@@ -28,7 +28,6 @@
 #include "accountopt.h"
 #include "blist.h"
 #include "debug.h"
-#include "privacy.h"
 #include "prpl.h"
 #include "proxy.h"
 #include "util.h"
@@ -113,7 +112,7 @@
 	if (!who)
 		return;
 
-	if (!purple_privacy_check(purple_connection_get_account(gc), who)) {
+	if (!purple_account_privacy_check(purple_connection_get_account(gc), who)) {
 		purple_debug_info("yahoo", "Picture packet from %s dropped.\n", who);
 		return;
 	}
--- a/libpurple/protocols/yahoo/yahoochat.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/yahoo/yahoochat.c	Sun Jun 23 13:35:53 2013 +0530
@@ -34,7 +34,6 @@
 
 #include "debug.h"
 #include "http.h"
-#include "privacy.h"
 #include "prpl.h"
 
 #include "conversation.h"
@@ -182,7 +181,7 @@
 		return;
 	}
 
-	if (!purple_privacy_check(account, who) ||
+	if (!purple_account_privacy_check(account, who) ||
 			(purple_account_get_bool(account, "ignore_invites", FALSE)))
 	{
 		purple_debug_info("yahoo",
@@ -232,7 +231,7 @@
 			break;
 		}
 	}
-	if (!purple_privacy_check(purple_connection_get_account(gc), who))
+	if (!purple_account_privacy_check(purple_connection_get_account(gc), who))
 	{
 		g_free(room);
 		g_free(msg);
@@ -590,9 +589,9 @@
 		yahoo_chat_add_users(PURPLE_CONV_CHAT(c), members);
 	}
 
-	if (account->deny && c) {
+	if (purple_account_privacy_get_denied(account) && c) {
 		PurpleConversationUiOps *ops = purple_conversation_get_ui_ops(c);
-		for (l = account->deny; l != NULL; l = l->next) {
+		for (l = purple_account_privacy_get_denied(account); l != NULL; l = l->next) {
 			for (roomies = members; roomies; roomies = roomies->next) {
 				if (!purple_utf8_strcasecmp((char *)l->data, roomies->data)) {
 					purple_debug_info("yahoo", "Ignoring room member %s in room %s\n" , (char *)roomies->data, room ? room : "");
@@ -730,7 +729,7 @@
 	if (room && who) {
 		GHashTable *components;
 
-		if (!purple_privacy_check(account, who) ||
+		if (!purple_account_privacy_check(account, who) ||
 				(purple_account_get_bool(account, "ignore_invites", FALSE)))
 		{
 			purple_debug_info("yahoo", "Invite to room %s from %s has been dropped.\n", room, who);
--- a/libpurple/protocols/yahoo/ycht.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/yahoo/ycht.c	Sun Jun 23 13:35:53 2013 +0530
@@ -267,8 +267,9 @@
 {
 	YchtConn *ycht = data;
 	int ret, writelen;
+	const gchar *output = NULL;
 
-	writelen = purple_circ_buffer_get_max_read(ycht->txbuf);
+	writelen = purple_circular_buffer_get_max_read(ycht->txbuf);
 
 	if (writelen == 0) {
 		purple_input_remove(ycht->tx_handler);
@@ -276,7 +277,9 @@
 		return;
 	}
 
-	ret = write(ycht->fd, ycht->txbuf->outptr, writelen);
+	output = purple_circular_buffer_get_output(ycht->txbuf);
+
+	ret = write(ycht->fd, output, writelen);
 
 	if (ret < 0 && errno == EAGAIN)
 		return;
@@ -292,7 +295,7 @@
 		return;
 	}
 
-	purple_circ_buffer_mark_read(ycht->txbuf, ret);
+	purple_circular_buffer_mark_read(ycht->txbuf, ret);
 
 }
 
@@ -345,7 +348,7 @@
 			ycht->tx_handler = purple_input_add(ycht->fd,
 				PURPLE_INPUT_WRITE, ycht_packet_send_write_cb,
 				ycht);
-		purple_circ_buffer_append(ycht->txbuf, buf + written,
+		purple_circular_buffer_append(ycht->txbuf, buf + written,
 			len - written);
 	}
 
@@ -444,7 +447,7 @@
 	if (ycht->tx_handler)
 		purple_input_remove(ycht->tx_handler);
 
-	purple_circ_buffer_destroy(ycht->txbuf);
+	g_object_unref(G_OBJECT(ycht->txbuf));
 
 	g_free(ycht->rxqueue);
 
--- a/libpurple/protocols/yahoo/ycht.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/yahoo/ycht.h	Sun Jun 23 13:35:53 2013 +0530
@@ -73,7 +73,7 @@
 	gboolean changing_rooms;
 	guchar *rxqueue;
 	guint rxlen;
-	PurpleCircBuffer *txbuf;
+	PurpleCircularBuffer *txbuf;
 	guint tx_handler;
 } YchtConn;
 
--- a/libpurple/protocols/zephyr/zephyr.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/protocols/zephyr/zephyr.c	Sun Jun 23 13:35:53 2013 +0530
@@ -35,7 +35,6 @@
 #include "server.h"
 #include "util.h"
 #include "cmds.h"
-#include "privacy.h"
 #include "version.h"
 
 #include "internal.h"
--- a/libpurple/proxy.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/proxy.c	Sun Jun 23 13:35:53 2013 +0530
@@ -32,7 +32,7 @@
 #define _PURPLE_PROXY_C_
 
 #include "internal.h"
-#include "cipher.h"
+#include "ciphers/md5hash.h"
 #include "debug.h"
 #include "dnsquery.h"
 #include "http.h"
@@ -1682,23 +1682,21 @@
 static void
 hmacmd5_chap(const unsigned char * challenge, int challen, const char * passwd, unsigned char * response)
 {
-	PurpleCipher *cipher;
-	PurpleCipherContext *ctx;
+	PurpleHash *hash;
 	int i;
 	unsigned char Kxoripad[65];
 	unsigned char Kxoropad[65];
 	size_t pwlen;
 
-	cipher = purple_ciphers_find_cipher("md5");
-	ctx = purple_cipher_context_new(cipher, NULL);
+	hash = purple_md5_hash_new();
 
 	memset(Kxoripad,0,sizeof(Kxoripad));
 	memset(Kxoropad,0,sizeof(Kxoropad));
 
 	pwlen=strlen(passwd);
 	if (pwlen>64) {
-		purple_cipher_context_append(ctx, (const guchar *)passwd, strlen(passwd));
-		purple_cipher_context_digest(ctx, Kxoripad, sizeof(Kxoripad));
+		purple_hash_append(hash, (const guchar *)passwd, strlen(passwd));
+		purple_hash_digest(hash, Kxoripad, sizeof(Kxoripad));
 		pwlen=16;
 	} else {
 		memcpy(Kxoripad, passwd, pwlen);
@@ -1710,17 +1708,17 @@
 		Kxoropad[i]^=0x5c;
 	}
 
-	purple_cipher_context_reset(ctx, NULL);
-	purple_cipher_context_append(ctx, Kxoripad, 64);
-	purple_cipher_context_append(ctx, challenge, challen);
-	purple_cipher_context_digest(ctx, Kxoripad, sizeof(Kxoripad));
-
-	purple_cipher_context_reset(ctx, NULL);
-	purple_cipher_context_append(ctx, Kxoropad, 64);
-	purple_cipher_context_append(ctx, Kxoripad, 16);
-	purple_cipher_context_digest(ctx, response, 16);
-
-	purple_cipher_context_destroy(ctx);
+	purple_hash_reset(hash);
+	purple_hash_append(hash, Kxoripad, 64);
+	purple_hash_append(hash, challenge, challen);
+	purple_hash_digest(hash, Kxoripad, sizeof(Kxoripad));
+
+	purple_hash_reset(hash);
+	purple_hash_append(hash, Kxoropad, 64);
+	purple_hash_append(hash, Kxoripad, 16);
+	purple_hash_digest(hash, response, 16);
+
+	g_object_unref(hash);
 }
 
 static void
--- a/libpurple/prpl.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/prpl.h	Sun Jun 23 13:35:53 2013 +0530
@@ -72,7 +72,7 @@
 #endif
 
 #include "blist.h"
-#include "conversation.h"
+#include "conversations.h"
 #include "ft.h"
 #include "imgstore.h"
 #include "media.h"
@@ -327,7 +327,7 @@
 	 */
 	int  (*send_im)(PurpleConnection *, const char *who,
 					const char *message,
-					PurpleMessageFlags flags);
+					PurpleConversationMessageFlags flags);
 
 	void (*set_info)(PurpleConnection *, const char *info);
 
@@ -338,7 +338,7 @@
 	 *         seconds to wait before sending a subsequent notification.
 	 *         Otherwise the PRPL should return 0.
 	 */
-	unsigned int (*send_typing)(PurpleConnection *, const char *name, PurpleTypingState state);
+	unsigned int (*send_typing)(PurpleConnection *, const char *name, PurpleIMConversationTypingState state);
 
 	/**
 	 * Should arrange for purple_notify_userinfo() to be called with
@@ -438,12 +438,12 @@
 	 *
 	 * @param id      The id of the chat to send the message to.
 	 * @param message The message to send to the chat.
-	 * @param flags   A bitwise OR of #PurpleMessageFlags representing
+	 * @param flags   A bitwise OR of #PurpleConversationMessageFlags representing
 	 *                message flags.
 	 * @return 	  A positive number or 0 in case of success,
 	 *                a negative error number in case of failure.
 	 */
-	int  (*chat_send)(PurpleConnection *, int id, const char *message, PurpleMessageFlags flags);
+	int  (*chat_send)(PurpleConnection *, int id, const char *message, PurpleConversationMessageFlags flags);
 
 	/** If implemented, this will be called regularly for this prpl's
 	 *  active connections.  You'd want to do this if you need to repeatedly
--- a/libpurple/purple.h.in	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/purple.h.in	Sun Jun 23 13:35:53 2013 +0530
@@ -44,16 +44,16 @@
 
 @PLUGINS_DEFINE@
 
-#include <account.h>
+#include <accounts.h>
 #include <accountopt.h>
 #include <blist.h>
 #include <buddyicon.h>
 #include <certificate.h>
 #include <cipher.h>
-#include <circbuffer.h>
+#include <circularbuffer.h>
 #include <cmds.h>
 #include <connection.h>
-#include <conversation.h>
+#include <conversations.h>
 #include <core.h>
 #include <debug.h>
 #include <desktopitem.h>
@@ -75,7 +75,6 @@
 #include <pluginpref.h>
 #include <pounce.h>
 #include <prefs.h>
-#include <privacy.h>
 #include <proxy.h>
 #include <prpl.h>
 #include <request.h>
--- a/libpurple/server.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/server.c	Sun Jun 23 13:35:53 2013 +0530
@@ -30,7 +30,6 @@
 #include "log.h"
 #include "notify.h"
 #include "prefs.h"
-#include "privacy.h"
 #include "prpl.h"
 #include "request.h"
 #include "signals.h"
@@ -560,7 +559,7 @@
 	 */
 	flags |= PURPLE_MESSAGE_RECV;
 
-	if (!purple_privacy_check(account, who)) {
+	if (!purple_account_privacy_check(account, who)) {
 		purple_signal_emit(purple_conversations_get_handle(), "blocked-im-msg",
 				account, who, msg, flags, (unsigned int)mtime);
 		return;
@@ -778,7 +777,7 @@
 	g_return_if_fail(who != NULL);
 
 	account = purple_connection_get_account(gc);
-	if (!purple_privacy_check(account, who)) {
+	if (!purple_account_privacy_check(account, who)) {
 		purple_signal_emit(purple_conversations_get_handle(), "chat-invite-blocked",
 				account, who, name, message, data);
 		return;
--- a/libpurple/server.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/server.h	Sun Jun 23 13:35:53 2013 +0530
@@ -26,8 +26,8 @@
 #ifndef _PURPLE_SERVER_H_
 #define _PURPLE_SERVER_H_
 
-#include "account.h"
-#include "conversation.h"
+#include "accounts.h"
+#include "conversations.h"
 #include "prpl.h"
 
 G_BEGIN_DECLS
@@ -48,10 +48,10 @@
  *         user is still typing then Purple will send another PURPLE_TYPING
  *         message.
  */
-unsigned int serv_send_typing(PurpleConnection *gc, const char *name, PurpleTypingState state);
+unsigned int serv_send_typing(PurpleConnection *gc, const char *name, PurpleIMConversationTypingState state);
 
 void serv_move_buddy(PurpleBuddy *, PurpleGroup *, PurpleGroup *);
-int  serv_send_im(PurpleConnection *, const char *, const char *, PurpleMessageFlags flags);
+int  serv_send_im(PurpleConnection *, const char *, const char *, PurpleConversationMessageFlags flags);
 
 /** Get information about an account's attention commands, from the prpl.
  *
@@ -70,7 +70,7 @@
 void serv_chat_invite(PurpleConnection *, int, const char *, const char *);
 void serv_chat_leave(PurpleConnection *, int);
 void serv_chat_whisper(PurpleConnection *, int, const char *, const char *);
-int  serv_chat_send(PurpleConnection *, int, const char *, PurpleMessageFlags flags);
+int  serv_chat_send(PurpleConnection *, int, const char *, PurpleConversationMessageFlags flags);
 void serv_alias_buddy(PurpleBuddy *);
 void serv_got_alias(PurpleConnection *gc, const char *who, const char *alias);
 
@@ -103,7 +103,7 @@
  * @param state   The typing state received
  */
 void serv_got_typing(PurpleConnection *gc, const char *name, int timeout,
-					 PurpleTypingState state);
+					 PurpleIMConversationTypingState state);
 
 /**
  * TODO: Could probably move this into the conversation API.
@@ -111,7 +111,7 @@
 void serv_got_typing_stopped(PurpleConnection *gc, const char *name);
 
 void serv_got_im(PurpleConnection *gc, const char *who, const char *msg,
-				 PurpleMessageFlags flags, time_t mtime);
+				 PurpleConversationMessageFlags flags, time_t mtime);
 
 /**
  * @param data The hash function should be g_str_hash() and the equal
@@ -180,7 +180,7 @@
  * @param mtime   The time when the message was received.
  */
 void serv_got_chat_in(PurpleConnection *g, int id, const char *who,
-					  PurpleMessageFlags flags, const char *message, time_t mtime);
+					  PurpleConversationMessageFlags flags, const char *message, time_t mtime);
 void serv_send_file(PurpleConnection *gc, const char *who, const char *file);
 
 G_END_DECLS
--- a/libpurple/smiley.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/smiley.c	Sun Jun 23 13:35:53 2013 +0530
@@ -32,25 +32,21 @@
 #include "util.h"
 #include "xmlnode.h"
 
+#define PURPLE_SMILEY_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_SMILEY, PurpleSmileyPrivate))
+
 /**************************************************************************/
-/* Main structures, members and constants                                 */
+/* Structs                                                                */
 /**************************************************************************/
 
-struct _PurpleSmiley
-{
-	GObject parent;
+typedef struct {
 	PurpleStoredImage *img;        /**< The id of the stored image with the
 	                                    the smiley data.        */
 	char *shortcut;                /**< Shortcut associated with the custom
 	                                    smiley. This field will work as a
 	                                    unique key by this API. */
 	char *checksum;                /**< The smiley checksum.        */
-};
-
-struct _PurpleSmileyClass
-{
-	GObjectClass parent_class;
-};
+} PurpleSmileyPrivate;
 
 static GHashTable *smiley_shortcut_index = NULL; /* shortcut (char *) => smiley (PurpleSmiley*) */
 static GHashTable *smiley_checksum_index = NULL; /* checksum (char *) => smiley (PurpleSmiley*) */
@@ -134,6 +130,7 @@
 static xmlnode *
 smiley_to_xmlnode(PurpleSmiley *smiley)
 {
+	PurpleSmileyPrivate *priv = NULL;
 	xmlnode *smiley_node = NULL;
 
 	smiley_node = xmlnode_new(XML_SMILEY_TAG);
@@ -141,14 +138,16 @@
 	if (!smiley_node)
 		return NULL;
 
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
 	xmlnode_set_attrib(smiley_node, XML_SHORTCUT_ATTRIB_TAG,
-			smiley->shortcut);
+			priv->shortcut);
 
 	xmlnode_set_attrib(smiley_node, XML_CHECKSUM_ATRIB_TAG,
-			smiley->checksum);
+			priv->checksum);
 
 	xmlnode_set_attrib(smiley_node, XML_FILENAME_ATRIB_TAG,
-			purple_imgstore_get_filename(smiley->img));
+			purple_imgstore_get_filename(priv->img));
 
 	return smiley_node;
 }
@@ -310,12 +309,14 @@
 		GParamSpec *spec)
 {
 	PurpleSmiley *smiley = PURPLE_SMILEY(object);
+	PurpleSmileyPrivate *priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
 	switch (param_id) {
 		case PROP_SHORTCUT:
-			g_value_set_string(value, smiley->shortcut);
+			g_value_set_string(value, priv->shortcut);
 			break;
 		case PROP_IMGSTORE:
-			g_value_set_pointer(value, smiley->img);
+			g_value_set_pointer(value, priv->img);
 			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, spec);
@@ -328,6 +329,8 @@
 		GParamSpec *spec)
 {
 	PurpleSmiley *smiley = PURPLE_SMILEY(object);
+	PurpleSmileyPrivate *priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
 	switch (param_id) {
 		case PROP_SHORTCUT:
 			{
@@ -339,18 +342,18 @@
 			{
 				PurpleStoredImage *img = g_value_get_pointer(value);
 
-				purple_imgstore_unref(smiley->img);
-				g_free(smiley->checksum);
+				purple_imgstore_unref(priv->img);
+				g_free(priv->checksum);
 
-				smiley->img = img;
+				priv->img = img;
 				if (img) {
-					smiley->checksum = g_compute_checksum_for_data(
+					priv->checksum = g_compute_checksum_for_data(
 							G_CHECKSUM_SHA1,
 							purple_imgstore_get_data(img),
 							purple_imgstore_get_size(img));
 					purple_smiley_data_store(img);
 				} else {
-					smiley->checksum = NULL;
+					priv->checksum = NULL;
 				}
 
 				g_object_notify(object, PROP_IMGSTORE_S);
@@ -366,17 +369,18 @@
 purple_smiley_finalize(GObject *obj)
 {
 	PurpleSmiley *smiley = PURPLE_SMILEY(obj);
+	PurpleSmileyPrivate *priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
 
-	if (g_hash_table_lookup(smiley_shortcut_index, smiley->shortcut)) {
-		g_hash_table_remove(smiley_shortcut_index, smiley->shortcut);
-		g_hash_table_remove(smiley_checksum_index, smiley->checksum);
+	if (g_hash_table_lookup(smiley_shortcut_index, priv->shortcut)) {
+		g_hash_table_remove(smiley_shortcut_index, priv->shortcut);
+		g_hash_table_remove(smiley_checksum_index, priv->checksum);
 	}
 
-	g_free(smiley->shortcut);
-	g_free(smiley->checksum);
-	if (smiley->img)
-		purple_smiley_data_unstore(purple_imgstore_get_filename(smiley->img));
-	purple_imgstore_unref(smiley->img);
+	g_free(priv->shortcut);
+	g_free(priv->checksum);
+	if (priv->img)
+		purple_smiley_data_unstore(purple_imgstore_get_filename(priv->img));
+	purple_imgstore_unref(priv->img);
 
 	PURPLE_DBUS_UNREGISTER_POINTER(smiley);
 
@@ -398,6 +402,8 @@
 
 	parent_class = g_type_class_peek_parent(klass);
 
+	g_type_class_add_private(klass, sizeof(PurpleSmileyPrivate));
+
 	gobj_class->get_property = purple_smiley_get_property;
 	gobj_class->set_property = purple_smiley_set_property;
 	gobj_class->finalize = purple_smiley_finalize;
@@ -473,6 +479,7 @@
 purple_smiley_load_file(const char *shortcut, const char *checksum, const char *filename)
 {
 	PurpleSmiley *smiley = NULL;
+	PurpleSmileyPrivate *priv = NULL;
 	guchar *smiley_data;
 	size_t smiley_data_len;
 	char *fullpath = NULL;
@@ -493,7 +500,9 @@
 		return;
 	}
 
-	smiley->checksum = g_strdup(checksum);
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
+	priv->checksum = g_strdup(checksum);
 
 	if (read_smiley_file(fullpath, &smiley_data, &smiley_data_len))
 		purple_smiley_set_data_impl(smiley, smiley_data,
@@ -616,6 +625,7 @@
 purple_smiley_set_data_impl(PurpleSmiley *smiley, guchar *smiley_data,
 				size_t smiley_data_len)
 {
+	PurpleSmileyPrivate *priv = NULL;
 	PurpleStoredImage *old_img, *new_img;
 	const char *old_filename = NULL;
 	const char *new_filename = NULL;
@@ -624,7 +634,9 @@
 	g_return_if_fail(smiley_data != NULL);
 	g_return_if_fail(smiley_data_len > 0);
 
-	old_img = smiley->img;
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
+	old_img = priv->img;
 
 	new_img = purple_smiley_data_new(smiley_data, smiley_data_len);
 
@@ -636,7 +648,7 @@
 		return;
 
 	old_filename = purple_imgstore_get_filename(old_img);
-	new_filename = purple_imgstore_get_filename(smiley->img);
+	new_filename = purple_imgstore_get_filename(priv->img);
 
 	if (g_ascii_strcasecmp(old_filename, new_filename))
 		purple_smiley_data_unstore(old_filename);
@@ -683,7 +695,8 @@
 purple_smiley_new_from_stream(const char *shortcut, guchar *smiley_data,
 			size_t smiley_data_len)
 {
-	PurpleSmiley *smiley;
+	PurpleSmiley *smiley = NULL;
+	PurpleSmileyPrivate *priv = NULL;
 
 	g_return_val_if_fail(shortcut  != NULL,    NULL);
 	g_return_val_if_fail(smiley_data != NULL,  NULL);
@@ -698,9 +711,10 @@
 	if (!smiley)
 		return NULL;
 
-	purple_smiley_set_data_impl(smiley, smiley_data, smiley_data_len);
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
 
-	purple_smiley_data_store(smiley->img);
+	purple_smiley_set_data_impl(smiley, smiley_data, smiley_data_len);
+	purple_smiley_data_store(priv->img);
 
 	return smiley;
 }
@@ -734,6 +748,8 @@
 gboolean
 purple_smiley_set_shortcut(PurpleSmiley *smiley, const char *shortcut)
 {
+	PurpleSmileyPrivate *priv = NULL;
+
 	g_return_val_if_fail(smiley  != NULL, FALSE);
 	g_return_val_if_fail(shortcut != NULL, FALSE);
 
@@ -741,15 +757,17 @@
 	if (g_hash_table_lookup(smiley_shortcut_index, shortcut))
 		return FALSE;
 
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
 	/* Remove the old shortcut. */
-	if (smiley->shortcut)
-		g_hash_table_remove(smiley_shortcut_index, smiley->shortcut);
+	if (priv->shortcut)
+		g_hash_table_remove(smiley_shortcut_index, priv->shortcut);
 
 	/* Insert the new shortcut. */
 	g_hash_table_insert(smiley_shortcut_index, g_strdup(shortcut), smiley);
 
-	g_free(smiley->shortcut);
-	smiley->shortcut = g_strdup(shortcut);
+	g_free(priv->shortcut);
+	priv->shortcut = g_strdup(shortcut);
 
 	g_object_notify(G_OBJECT(smiley), PROP_SHORTCUT_S);
 
@@ -762,18 +780,22 @@
 purple_smiley_set_data(PurpleSmiley *smiley, guchar *smiley_data,
 			   size_t smiley_data_len)
 {
+	PurpleSmileyPrivate *priv = NULL;
+
 	g_return_if_fail(smiley     != NULL);
 	g_return_if_fail(smiley_data != NULL);
 	g_return_if_fail(smiley_data_len > 0);
 
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
 	/* Remove the previous entry */
-	g_hash_table_remove(smiley_checksum_index, smiley->checksum);
+	g_hash_table_remove(smiley_checksum_index, priv->checksum);
 
 	/* Update the file data. This also updates the checksum. */
 	purple_smiley_set_data_impl(smiley, smiley_data, smiley_data_len);
 
 	/* Reinsert the index item. */
-	g_hash_table_insert(smiley_checksum_index, g_strdup(smiley->checksum), smiley);
+	g_hash_table_insert(smiley_checksum_index, g_strdup(priv->checksum), smiley);
 
 	purple_smileys_save();
 }
@@ -781,34 +803,45 @@
 PurpleStoredImage *
 purple_smiley_get_stored_image(const PurpleSmiley *smiley)
 {
-	return purple_imgstore_ref(smiley->img);
+	PurpleSmileyPrivate *priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+	return purple_imgstore_ref(priv->img);
 }
 
 const char *purple_smiley_get_shortcut(const PurpleSmiley *smiley)
 {
+	PurpleSmileyPrivate *priv = NULL;
+
 	g_return_val_if_fail(smiley != NULL, NULL);
 
-	return smiley->shortcut;
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+	return priv->shortcut;
 }
 
 const char *
 purple_smiley_get_checksum(const PurpleSmiley *smiley)
 {
+	PurpleSmileyPrivate *priv = NULL;
+
 	g_return_val_if_fail(smiley != NULL, NULL);
 
-	return smiley->checksum;
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+	return priv->checksum;
 }
 
 gconstpointer
 purple_smiley_get_data(const PurpleSmiley *smiley, size_t *len)
 {
+	PurpleSmileyPrivate *priv = NULL;
+
 	g_return_val_if_fail(smiley != NULL, NULL);
 
-	if (smiley->img) {
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
+	if (priv->img) {
 		if (len != NULL)
-			*len = purple_imgstore_get_size(smiley->img);
+			*len = purple_imgstore_get_size(priv->img);
 
-		return purple_imgstore_get_data(smiley->img);
+		return purple_imgstore_get_data(priv->img);
 	}
 
 	return NULL;
@@ -817,20 +850,26 @@
 const char *
 purple_smiley_get_extension(const PurpleSmiley *smiley)
 {
-	if (smiley->img != NULL)
-		return purple_imgstore_get_extension(smiley->img);
+	PurpleSmileyPrivate *priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
+	if (priv->img != NULL)
+		return purple_imgstore_get_extension(priv->img);
 
 	return NULL;
 }
 
 char *purple_smiley_get_full_path(PurpleSmiley *smiley)
 {
+	PurpleSmileyPrivate *priv = NULL;
+
 	g_return_val_if_fail(smiley != NULL, NULL);
 
-	if (smiley->img == NULL)
+	priv = PURPLE_SMILEY_GET_PRIVATE(smiley);
+
+	if (priv->img == NULL)
 		return NULL;
 
-	return get_file_full_path(purple_imgstore_get_filename(smiley->img));
+	return get_file_full_path(purple_imgstore_get_filename(priv->img));
 }
 
 static void add_smiley_to_list(gpointer key, gpointer value, gpointer user_data)
--- a/libpurple/smiley.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/smiley.h	Sun Jun 23 13:35:53 2013 +0530
@@ -50,6 +50,26 @@
 #define PURPLE_IS_SMILEY_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_SMILEY))
 #define PURPLE_SMILEY_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_SMILEY, PurpleSmileyClass))
 
+struct _PurpleSmiley
+{
+	GObject parent;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
+};
+
+struct _PurpleSmileyClass
+{
+	GObjectClass parent_class;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
+};
+
 G_BEGIN_DECLS
 
 /**************************************************************************/
--- a/libpurple/sound-theme-loader.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/sound-theme-loader.h	Sun Jun 23 13:35:53 2013 +0530
@@ -49,11 +49,21 @@
 struct _PurpleSoundThemeLoader
 {
 	PurpleThemeLoader parent;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 struct _PurpleSoundThemeLoaderClass
 {
 	PurpleThemeLoaderClass parent_class;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 /**************************************************************************/
--- a/libpurple/sound-theme.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/sound-theme.h	Sun Jun 23 13:35:53 2013 +0530
@@ -51,11 +51,21 @@
 struct _PurpleSoundTheme
 {
 	PurpleTheme parent;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 struct _PurpleSoundThemeClass
 {
 	PurpleThemeClass parent_class;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 /**************************************************************************/
--- a/libpurple/tests/test_cipher.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/tests/test_cipher.c	Sun Jun 23 13:35:53 2013 +0530
@@ -7,28 +7,32 @@
 
 #include "tests.h"
 
-#include "../cipher.h"
+#include "../ciphers/des3cipher.h"
+#include "../ciphers/descipher.h"
+#include "../ciphers/hmaccipher.h"
+#include "../ciphers/md4hash.h"
+#include "../ciphers/md5hash.h"
+#include "../ciphers/sha1hash.h"
+#include "../ciphers/sha256hash.h"
 
 /******************************************************************************
  * MD4 Tests
  *****************************************************************************/
 #define MD4_TEST(data, digest) { \
-	PurpleCipher *cipher = NULL; \
-	PurpleCipherContext *context = NULL; \
+	PurpleHash *hash = NULL; \
 	gchar cdigest[33]; \
 	gboolean ret = FALSE; \
 	\
-	cipher = purple_ciphers_find_cipher("md4"); \
-	context = purple_cipher_context_new(cipher, NULL); \
-	purple_cipher_context_append(context, (guchar *)(data), strlen((data))); \
+	hash = purple_md4_hash_new(); \
+	purple_hash_append(hash, (guchar *)(data), strlen((data))); \
 	\
-	ret = purple_cipher_context_digest_to_str(context, cdigest, sizeof(cdigest)); \
+	ret = purple_hash_digest_to_str(hash, cdigest, sizeof(cdigest)); \
 	\
 	fail_unless(ret == TRUE, NULL); \
 	\
 	fail_unless(strcmp((digest), cdigest) == 0, NULL); \
 	\
-	purple_cipher_context_destroy(context); \
+	g_object_unref(hash); \
 }
 
 START_TEST(test_md4_empty_string) {
@@ -75,22 +79,20 @@
  * MD5 Tests
  *****************************************************************************/
 #define MD5_TEST(data, digest) { \
-	PurpleCipher *cipher = NULL; \
-	PurpleCipherContext *context = NULL; \
+	PurpleHash *hash = NULL; \
 	gchar cdigest[33]; \
 	gboolean ret = FALSE; \
 	\
-	cipher = purple_ciphers_find_cipher("md5"); \
-	context = purple_cipher_context_new(cipher, NULL); \
-	purple_cipher_context_append(context, (guchar *)(data), strlen((data))); \
+	hash = purple_md5_hash_new(); \
+	purple_hash_append(hash, (guchar *)(data), strlen((data))); \
 	\
-	ret = purple_cipher_context_digest_to_str(context, cdigest, sizeof(cdigest)); \
+	ret = purple_hash_digest_to_str(hash, cdigest, sizeof(cdigest)); \
 	\
 	fail_unless(ret == TRUE, NULL); \
 	\
 	fail_unless(strcmp((digest), cdigest) == 0, NULL); \
 	\
-	purple_cipher_context_destroy(context); \
+	g_object_unref(hash); \
 }
 
 START_TEST(test_md5_empty_string) {
@@ -136,17 +138,15 @@
  * SHA-1 Tests
  *****************************************************************************/
 #define SHA1_TEST(data, digest) { \
-	PurpleCipher *cipher = NULL; \
-	PurpleCipherContext *context = NULL; \
+	PurpleHash *hash = NULL; \
 	gchar cdigest[41]; \
 	gboolean ret = FALSE; \
 	gchar *input = data; \
 	\
-	cipher = purple_ciphers_find_cipher("sha1"); \
-	context = purple_cipher_context_new(cipher, NULL); \
+	hash = purple_sha1_hash_new(); \
 	\
 	if (input) { \
-		purple_cipher_context_append(context, (guchar *)input, strlen(input)); \
+		purple_hash_append(hash, (guchar *)input, strlen(input)); \
 	} else { \
 		gint j; \
 		guchar buff[1000]; \
@@ -154,16 +154,16 @@
 		memset(buff, 'a', 1000); \
 		\
 		for(j = 0; j < 1000; j++) \
-			purple_cipher_context_append(context, buff, 1000); \
+			purple_hash_append(hash, buff, 1000); \
 	} \
 	\
-	ret = purple_cipher_context_digest_to_str(context, cdigest, sizeof(cdigest)); \
+	ret = purple_hash_digest_to_str(hash, cdigest, sizeof(cdigest)); \
 	\
 	fail_unless(ret == TRUE, NULL); \
 	\
 	fail_unless(strcmp((digest), cdigest) == 0, NULL); \
 	\
-	purple_cipher_context_destroy(context); \
+	g_object_unref(hash); \
 }
 
 START_TEST(test_sha1_empty_string) {
@@ -196,17 +196,15 @@
  * SHA-256 Tests
  *****************************************************************************/
 #define SHA256_TEST(data, digest) { \
-	PurpleCipher *cipher = NULL; \
-	PurpleCipherContext *context = NULL; \
+	PurpleHash *hash = NULL; \
 	gchar cdigest[65]; \
 	gboolean ret = FALSE; \
 	gchar *input = data; \
 	\
-	cipher = purple_ciphers_find_cipher("sha256"); \
-	context = purple_cipher_context_new(cipher, NULL); \
+	hash = purple_sha256_hash_new(); \
 	\
 	if (input) { \
-		purple_cipher_context_append(context, (guchar *)input, strlen(input)); \
+		purple_hash_append(hash, (guchar *)input, strlen(input)); \
 	} else { \
 		gint j; \
 		guchar buff[1000]; \
@@ -214,16 +212,16 @@
 		memset(buff, 'a', 1000); \
 		\
 		for(j = 0; j < 1000; j++) \
-			purple_cipher_context_append(context, buff, 1000); \
+			purple_hash_append(hash, buff, 1000); \
 	} \
 	\
-	ret = purple_cipher_context_digest_to_str(context, cdigest, sizeof(cdigest)); \
+	ret = purple_hash_digest_to_str(hash, cdigest, sizeof(cdigest)); \
 	\
 	fail_unless(ret == TRUE, NULL); \
 	\
 	fail_unless(strcmp((digest), cdigest) == 0, NULL); \
 	\
-	purple_cipher_context_destroy(context); \
+	g_object_unref(hash); \
 }
 
 START_TEST(test_sha256_empty_string) {
@@ -257,26 +255,24 @@
  *****************************************************************************/
 #define DES_TEST(in, keyz, out, len) { \
 	PurpleCipher *cipher = NULL; \
-	PurpleCipherContext *context = NULL; \
 	guchar answer[len+1]; \
 	gint ret = 0; \
 	guchar decrypt[len+1] = in; \
 	guchar key[8+1] = keyz;\
 	guchar encrypt[len+1] = out;\
 	\
-	cipher = purple_ciphers_find_cipher("des"); \
-	context = purple_cipher_context_new(cipher, NULL); \
-	purple_cipher_context_set_key(context, key, 8); \
+	cipher = purple_des_cipher_new(); \
+	purple_cipher_set_key(cipher, key, 8); \
 	\
-	ret = purple_cipher_context_encrypt(context, decrypt, len, answer, len); \
+	ret = purple_cipher_encrypt(cipher, decrypt, len, answer, len); \
 	fail_unless(ret == len, NULL); \
 	fail_unless(memcmp(encrypt, answer, len) == 0, NULL); \
 	\
-	ret = purple_cipher_context_decrypt(context, encrypt, len, answer, len); \
+	ret = purple_cipher_decrypt(cipher, encrypt, len, answer, len); \
 	fail_unless(ret == len, NULL); \
 	fail_unless(memcmp(decrypt, answer, len) == 0, NULL); \
 	\
-	purple_cipher_context_destroy(context); \
+	g_object_unref(cipher); \
 }
 
 START_TEST(test_des_12345678) {
@@ -303,28 +299,25 @@
 
 #define DES3_TEST(in, key, iv, out, len, mode) { \
 	PurpleCipher *cipher = NULL; \
-	PurpleCipherContext *context = NULL; \
 	guchar answer[len+1]; \
 	guchar decrypt[len+1] = in; \
 	guchar encrypt[len+1] = out; \
 	gint ret = 0; \
 	\
-	cipher = purple_ciphers_find_cipher("des3"); \
-	context = purple_cipher_context_new(cipher, NULL); \
-	purple_cipher_context_set_key(context, (guchar *)key, 24); \
-	purple_cipher_context_set_batch_mode(context, (mode)); \
-	purple_cipher_context_set_iv(context, (guchar *)iv, 8); \
+	cipher = purple_des3_cipher_new(); \
+	purple_cipher_set_key(cipher, (guchar *)key, 24); \
+	purple_cipher_set_batch_mode(cipher, (mode)); \
+	purple_cipher_set_iv(cipher, (guchar *)iv, 8); \
 	\
-	fprintf(stderr, "len: %lu\n", len); \
-	ret = purple_cipher_context_encrypt(context, decrypt, len, answer, len); \
+	ret = purple_cipher_encrypt(cipher, decrypt, len, answer, len); \
 	fail_unless(ret == len, NULL); \
 	fail_unless(memcmp(encrypt, answer, len) == 0, NULL); \
 	\
-	ret = purple_cipher_context_decrypt(context, encrypt, len, answer, len); \
+	ret = purple_cipher_decrypt(cipher, encrypt, len, answer, len); \
 	fail_unless(ret == len, NULL); \
 	fail_unless(memcmp(decrypt, answer, len) == 0, NULL); \
 	\
-	purple_cipher_context_destroy(context); \
+	g_object_unref(cipher); \
 }
 
 START_TEST(test_des3_ecb_nist1) {
@@ -472,22 +465,22 @@
 
 #define HMAC_TEST(data, data_len, key, key_len, type, digest) { \
 	PurpleCipher *cipher = NULL; \
-	PurpleCipherContext *context = NULL; \
+	PurpleHash *hash = NULL; \
 	gchar cdigest[41]; \
 	gboolean ret = FALSE; \
 	\
-	cipher = purple_ciphers_find_cipher("hmac"); \
-	context = purple_cipher_context_new(cipher, NULL); \
-	purple_cipher_context_set_option(context, "hash", type); \
-	purple_cipher_context_set_key(context, (guchar *)key, (key_len)); \
+	hash = purple_##type##_hash_new(); \
+	cipher = purple_hmac_cipher_new(hash); \
+	purple_cipher_set_key(cipher, (guchar *)key, (key_len)); \
 	\
-	purple_cipher_context_append(context, (guchar *)(data), (data_len)); \
-	ret = purple_cipher_context_digest_to_str(context, cdigest, sizeof(cdigest)); \
+	purple_cipher_append(cipher, (guchar *)(data), (data_len)); \
+	ret = purple_cipher_digest_to_str(cipher, cdigest, sizeof(cdigest)); \
 	\
 	fail_unless(ret == TRUE, NULL); \
 	fail_unless(strcmp((digest), cdigest) == 0, NULL); \
 	\
-	purple_cipher_context_destroy(context); \
+	g_object_unref(cipher); \
+	g_object_unref(hash); \
 }
 
 /* HMAC MD5 */
@@ -497,7 +490,7 @@
 	          8,
 	          "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
 	          16,
-	          "md5",
+	          md5,
 	          "9294727a3638bb1c13f48ef8158bfc9d");
 }
 END_TEST
@@ -507,7 +500,7 @@
 	          28,
 	          "Jefe",
 	          4,
-	          "md5",
+	          md5,
 	          "750c783e6ab0b503eaa86e310a5db738");
 }
 END_TEST
@@ -521,7 +514,7 @@
 	          50,
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
 	          16,
-	          "md5",
+	          md5,
 	          "56be34521d144c88dbb8c733f0e8b3f6");
 }
 END_TEST
@@ -537,7 +530,7 @@
 	          "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
 	          "\x15\x16\x17\x18\x19",
 	          25,
-	          "md5",
+	          md5,
 	          "697eaf0aca3a3aea3a75164746ffaa79");
 }
 END_TEST
@@ -547,7 +540,7 @@
 	          20,
 	          "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
 	          16,
-	          "md5",
+	          md5,
 	          "56461ef2342edc00f9bab995690efd4c");
 }
 END_TEST
@@ -564,7 +557,7 @@
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
 	          80,
-	          "md5",
+	          md5,
 	          "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd");
 }
 END_TEST
@@ -581,7 +574,7 @@
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
 	          80,
-	          "md5",
+	          md5,
 	          "6f630fad67cda0ee1fb1f562db3aa53e");
 }
 END_TEST
@@ -592,7 +585,7 @@
 	          "\x0a\x0b\x00\x0d\x0e\x0f\x1a\x2f\x0b\x0b"
 	          "\x0b\x00\x00\x0b\x0b\x49\x5f\x6e\x0b\x0b",
 	          20,
-	          "md5",
+	          md5,
 	          "597bfd644b797a985561eeb03a169e59");
 }
 END_TEST
@@ -603,7 +596,7 @@
 	          "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
 	          "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
 	          20,
-	          "md5",
+	          md5,
 	          "70be8e1b7b50dfcc335d6cd7992c564f");
 }
 END_TEST
@@ -614,7 +607,7 @@
 	          "\x0c\x0d\x00\x0f\x10\x1a\x3a\x3a\xe6\x34"
 	          "\x0b\x00\x00\x0b\x0b\x49\x5f\x6e\x0b\x0b",
 	          20,
-	          "md5",
+	          md5,
 	          "b31bcbba35a33a067cbba9131cba4889");
 }
 END_TEST
@@ -627,7 +620,7 @@
 	          "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
 	          "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
 	          20,
-	          "sha1",
+	          sha1,
 	          "b617318655057264e28bc0b6fb378c8ef146be00");
 }
 END_TEST
@@ -637,7 +630,7 @@
 	          28,
 	          "Jefe",
 	          4,
-	          "sha1",
+	          sha1,
 	          "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79");
 }
 END_TEST
@@ -652,7 +645,7 @@
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
 	          20,
-	          "sha1",
+	          sha1,
 	          "125d7342b9ac11cd91a39af48aa17b4f63f175d3");
 }
 END_TEST
@@ -668,7 +661,7 @@
 	          "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
 	          "\x15\x16\x17\x18\x19",
 	          25,
-	          "sha1",
+	          sha1,
 	          "4c9007f4026250c6bc8414f9bf50c86c2d7235da");
 }
 END_TEST
@@ -679,7 +672,7 @@
 	          "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
 	          "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
 	          20,
-	          "sha1",
+	          sha1,
 	          "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04");
 }
 END_TEST
@@ -696,7 +689,7 @@
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
 	          80,
-	          "sha1",
+	          sha1,
 	          "aa4ae5e15272d00e95705637ce8a3b55ed402112");
 }
 END_TEST
@@ -713,7 +706,7 @@
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
 	          "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
 	          80,
-	          "sha1",
+	          sha1,
 	          "e8e99d0f45237d786d6bbaa7965c7808bbff1a91");
 }
 END_TEST
@@ -724,7 +717,7 @@
 	          "\x0a\x0b\x00\x0d\x0e\x0f\x1a\x2f\x0b\x0b"
 	          "\x0b\x00\x00\x0b\x0b\x49\x5f\x6e\x0b\x0b",
 	          20,
-	          "sha1",
+	          sha1,
 	          "eb62a2e0e33d300be669c52aab3f591bc960aac5");
 }
 END_TEST
@@ -735,7 +728,7 @@
 	          "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
 	          "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
 	          20,
-	          "sha1",
+	          sha1,
 	          "31ca58d849e971e418e3439de2c6f83144b6abb7");
 }
 END_TEST
@@ -746,7 +739,7 @@
 	          "\x0c\x0d\x00\x0f\x10\x1a\x3a\x3a\xe6\x34"
 	          "\x0b\x00\x00\x0b\x0b\x49\x5f\x6e\x0b\x0b",
 	          20,
-	          "sha1",
+	          sha1,
 	          "e6b8e2fede87aa09dcb13e554df1435e056eae36");
 }
 END_TEST
--- a/libpurple/tests/test_jabber_caps.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/tests/test_jabber_caps.c	Sun Jun 23 13:35:53 2013 +0530
@@ -3,6 +3,8 @@
 #include "tests.h"
 #include "../xmlnode.h"
 #include "../protocols/jabber/caps.h"
+#include "../ciphers/md5hash.h"
+#include "../ciphers/sha1hash.h"
 
 START_TEST(test_parse_invalid)
 {
@@ -25,14 +27,22 @@
 
 #define assert_caps_calculate_match(hash_func, hash, str) { \
 	xmlnode *query = xmlnode_from_str((str), -1); \
+	PurpleHash *hasher = NULL; \
 	JabberCapsClientInfo *info = jabber_caps_parse_client_info(query); \
-	gchar *got_hash = jabber_caps_calculate_hash(info, (hash_func)); \
+	gchar *got_hash; \
+	if (g_str_equal(hash_func, "sha-1")) { \
+		hasher = purple_sha1_hash_new(); \
+	} else if (g_str_equal(hash_func, "md5")) { \
+		hasher = purple_md5_hash_new(); \
+	} \
+	got_hash = jabber_caps_calculate_hash(info, hasher); \
+	g_object_unref(hasher); \
 	assert_string_equal_free((hash), got_hash); \
 }
 
 START_TEST(test_calculate_caps)
 {
-	assert_caps_calculate_match("sha1", "GNjxthSckUNvAIoCCJFttjl6VL8=",
+	assert_caps_calculate_match("sha-1", "GNjxthSckUNvAIoCCJFttjl6VL8=",
 	"<query xmlns='http://jabber.org/protocol/disco#info' node='http://tkabber.jabber.ru/#GNjxthSckUNvAIoCCJFttjl6VL8='><identity category='client' type='pc' name='Tkabber'/><x xmlns='jabber:x:data' type='result'><field var='FORM_TYPE' type='hidden'><value>urn:xmpp:dataforms:softwareinfo</value></field><field var='software'><value>Tkabber</value></field><field var='software_version'><value> ( 8.5.5 )</value></field><field var='os'><value>ATmega640-16AU</value></field><field var='os_version'><value/></field></x><feature var='games:board'/><feature var='google:mail:notify'/><feature var='http://jabber.org/protocol/activity'/><feature var='http://jabber.org/protocol/bytestreams'/><feature var='http://jabber.org/protocol/chatstates'/><feature var='http://jabber.org/protocol/commands'/><feature var='http://jabber.org/protocol/commands'/><feature var='http://jabber.org/protocol/disco#info'/><feature var='http://jabber.org/protocol/disco#items'/><feature var='http://jabber.org/protocol/feature-neg'/><feature var='http://jabber.org/protocol/geoloc'/><feature var='http://jabber.org/protocol/ibb'/><feature var='http://jabber.org/protocol/iqibb'/><feature var='http://jabber.org/protocol/mood'/><feature var='http://jabber.org/protocol/muc'/><feature var='http://jabber.org/protocol/mute#ancestor'/><feature var='http://jabber.org/protocol/mute#editor'/><feature var='http://jabber.org/protocol/rosterx'/><feature var='http://jabber.org/protocol/si'/><feature var='http://jabber.org/protocol/si/profile/file-transfer'/><feature var='http://jabber.org/protocol/tune'/><feature var='jabber:iq:avatar'/><feature var='jabber:iq:browse'/><feature var='jabber:iq:dtcp'/><feature var='jabber:iq:filexfer'/><feature var='jabber:iq:ibb'/><feature var='jabber:iq:inband'/><feature var='jabber:iq:jidlink'/><feature var='jabber:iq:last'/><feature var='jabber:iq:oob'/><feature var='jabber:iq:privacy'/><feature var='jabber:iq:time'/><feature var='jabber:iq:version'/><feature var='jabber:x:data'/><feature var='jabber:x:event'/><feature var='jabber:x:oob'/><feature var='urn:xmpp:ping'/><feature var='urn:xmpp:receipts'/><feature var='urn:xmpp:time'/></query>");
 }
 END_TEST
--- a/libpurple/tests/test_jabber_scram.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/tests/test_jabber_scram.c	Sun Jun 23 13:35:53 2013 +0530
@@ -4,8 +4,9 @@
 #include "../util.h"
 #include "../protocols/jabber/auth_scram.h"
 #include "../protocols/jabber/jutil.h"
+#include "../ciphers/sha1hash.h"
 
-static JabberScramHash sha1_mech = { "-SHA-1", "sha1", 20 };
+static JabberScramHash sha1_mech = { "-SHA-1", purple_sha1_hash_new, 20 };
 
 #define assert_pbkdf2_equal(password, salt, count, expected) { \
 	GString *p = g_string_new(password); \
--- a/libpurple/theme-loader.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/theme-loader.h	Sun Jun 23 13:35:53 2013 +0530
@@ -50,6 +50,11 @@
 struct _PurpleThemeLoader
 {
 	GObject parent;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 struct _PurpleThemeLoaderClass
@@ -57,6 +62,11 @@
 	GObjectClass parent_class;
 	PurpleTheme *((*purple_theme_loader_build)(const gchar*));
 	gboolean (*probe_directory)(const gchar *);
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 /**************************************************************************/
--- a/libpurple/theme-manager.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/theme-manager.h	Sun Jun 23 13:35:53 2013 +0530
@@ -46,10 +46,20 @@
 
 struct _PurpleThemeManager {
 	GObject parent;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 struct _PurpleThemeManagerClass {
 	GObjectClass parent_class;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 /**************************************************************************/
--- a/libpurple/theme.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/theme.h	Sun Jun 23 13:35:53 2013 +0530
@@ -49,11 +49,21 @@
 struct _PurpleTheme
 {
 	GObject parent;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 struct _PurpleThemeClass
 {
 	GObjectClass parent_class;
+
+	void (*purple_reserved1)(void);
+	void (*purple_reserved2)(void);
+	void (*purple_reserved3)(void);
+	void (*purple_reserved4)(void);
 };
 
 /**************************************************************************/
--- a/libpurple/util.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/util.c	Sun Jun 23 13:35:53 2013 +0530
@@ -23,7 +23,7 @@
  */
 #include "internal.h"
 
-#include "cipher.h"
+#include "ciphers/md5hash.h"
 #include "conversation.h"
 #include "core.h"
 #include "debug.h"
@@ -4743,3 +4743,161 @@
 			b,
 			(tmp >> 16) & 0xFFFF, g_random_int());
 }
+
+gchar *purple_http_digest_calculate_session_key(
+		const gchar *algorithm,
+		const gchar *username,
+		const gchar *realm,
+		const gchar *password,
+		const gchar *nonce,
+		const gchar *client_nonce)
+{
+	PurpleHash *hasher;
+	gchar hash[33]; /* We only support MD5. */
+
+	g_return_val_if_fail(username != NULL, NULL);
+	g_return_val_if_fail(realm    != NULL, NULL);
+	g_return_val_if_fail(password != NULL, NULL);
+	g_return_val_if_fail(nonce    != NULL, NULL);
+
+	/* Check for a supported algorithm. */
+	g_return_val_if_fail(algorithm == NULL ||
+						 *algorithm == '\0' ||
+						 g_ascii_strcasecmp(algorithm, "MD5") ||
+						 g_ascii_strcasecmp(algorithm, "MD5-sess"), NULL);
+
+	hasher = purple_md5_hash_new();
+	g_return_val_if_fail(hash != NULL, NULL);
+
+	purple_hash_append(hasher, (guchar *)username, strlen(username));
+	purple_hash_append(hasher, (guchar *)":", 1);
+	purple_hash_append(hasher, (guchar *)realm, strlen(realm));
+	purple_hash_append(hasher, (guchar *)":", 1);
+	purple_hash_append(hasher, (guchar *)password, strlen(password));
+
+	if (algorithm != NULL && !g_ascii_strcasecmp(algorithm, "MD5-sess"))
+	{
+		guchar digest[16];
+
+		if (client_nonce == NULL)
+		{
+			g_object_unref(hasher);
+			purple_debug_error("hash", "Required client_nonce missing for MD5-sess digest calculation.\n");
+			return NULL;
+		}
+
+		purple_hash_digest(hasher, digest, sizeof(digest));
+
+		purple_hash_reset(hasher);
+		purple_hash_append(hasher, digest, sizeof(digest));
+		purple_hash_append(hasher, (guchar *)":", 1);
+		purple_hash_append(hasher, (guchar *)nonce, strlen(nonce));
+		purple_hash_append(hasher, (guchar *)":", 1);
+		purple_hash_append(hasher, (guchar *)client_nonce, strlen(client_nonce));
+	}
+
+	purple_hash_digest_to_str(hasher, hash, sizeof(hash));
+	g_object_unref(hasher);
+
+	return g_strdup(hash);
+}
+
+gchar *purple_http_digest_calculate_response(
+		const gchar *algorithm,
+		const gchar *method,
+		const gchar *digest_uri,
+		const gchar *qop,
+		const gchar *entity,
+		const gchar *nonce,
+		const gchar *nonce_count,
+		const gchar *client_nonce,
+		const gchar *session_key)
+{
+	PurpleHash *hash;
+	static gchar hash2[33]; /* We only support MD5. */
+
+	g_return_val_if_fail(method      != NULL, NULL);
+	g_return_val_if_fail(digest_uri  != NULL, NULL);
+	g_return_val_if_fail(nonce       != NULL, NULL);
+	g_return_val_if_fail(session_key != NULL, NULL);
+
+	/* Check for a supported algorithm. */
+	g_return_val_if_fail(algorithm == NULL ||
+						 *algorithm == '\0' ||
+						 g_ascii_strcasecmp(algorithm, "MD5") ||
+						 g_ascii_strcasecmp(algorithm, "MD5-sess"), NULL);
+
+	/* Check for a supported "quality of protection". */
+	g_return_val_if_fail(qop == NULL ||
+						 *qop == '\0' ||
+						 g_ascii_strcasecmp(qop, "auth") ||
+						 g_ascii_strcasecmp(qop, "auth-int"), NULL);
+
+	hash = purple_md5_hash_new();
+	g_return_val_if_fail(hash != NULL, NULL);
+
+	purple_hash_append(hash, (guchar *)method, strlen(method));
+	purple_hash_append(hash, (guchar *)":", 1);
+	purple_hash_append(hash, (guchar *)digest_uri, strlen(digest_uri));
+
+	if (qop != NULL && !g_ascii_strcasecmp(qop, "auth-int"))
+	{
+		PurpleHash *hash2;
+		gchar entity_hash[33];
+
+		if (entity == NULL)
+		{
+			g_object_unref(hash);
+			purple_debug_error("hash", "Required entity missing for auth-int digest calculation.\n");
+			return NULL;
+		}
+
+		hash2 = purple_md5_hash_new();
+		purple_hash_append(hash2, (guchar *)entity, strlen(entity));
+		purple_hash_digest_to_str(hash2, entity_hash, sizeof(entity_hash));
+		g_object_unref(hash2);
+
+		purple_hash_append(hash, (guchar *)":", 1);
+		purple_hash_append(hash, (guchar *)entity_hash, strlen(entity_hash));
+	}
+
+	purple_hash_digest_to_str(hash, hash2, sizeof(hash2));
+	purple_hash_reset(hash);
+
+	purple_hash_append(hash, (guchar *)session_key, strlen(session_key));
+	purple_hash_append(hash, (guchar *)":", 1);
+	purple_hash_append(hash, (guchar *)nonce, strlen(nonce));
+	purple_hash_append(hash, (guchar *)":", 1);
+
+	if (qop != NULL && *qop != '\0')
+	{
+		if (nonce_count == NULL)
+		{
+			g_object_unref(hash);
+			purple_debug_error("hash", "Required nonce_count missing for digest calculation.\n");
+			return NULL;
+		}
+
+		if (client_nonce == NULL)
+		{
+			g_object_unref(hash);
+			purple_debug_error("hash", "Required client_nonce missing for digest calculation.\n");
+			return NULL;
+		}
+
+		purple_hash_append(hash, (guchar *)nonce_count, strlen(nonce_count));
+		purple_hash_append(hash, (guchar *)":", 1);
+		purple_hash_append(hash, (guchar *)client_nonce, strlen(client_nonce));
+		purple_hash_append(hash, (guchar *)":", 1);
+
+		purple_hash_append(hash, (guchar *)qop, strlen(qop));
+
+		purple_hash_append(hash, (guchar *)":", 1);
+	}
+
+	purple_hash_append(hash, (guchar *)hash2, strlen(hash2));
+	purple_hash_digest_to_str(hash, hash2, sizeof(hash2));
+	g_object_unref(hash);
+
+	return g_strdup(hash2);
+}
--- a/libpurple/util.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/libpurple/util.h	Sun Jun 23 13:35:53 2013 +0530
@@ -1431,6 +1431,48 @@
  */
 gchar *purple_uuid_random(void);
 
+/**
+ * Calculates a session key for HTTP Digest authentation
+ *
+ * See RFC 2617 for more information.
+ *
+ * @param algorithm    The hash algorithm to use
+ * @param username     The username provided by the user
+ * @param realm        The authentication realm provided by the server
+ * @param password     The password provided by the user
+ * @param nonce        The nonce provided by the server
+ * @param client_nonce The nonce provided by the client
+ *
+ * @return The session key, or @c NULL if an error occurred.
+ */
+gchar *purple_http_digest_calculate_session_key(
+		const gchar *algorithm, const gchar *username,
+		const gchar *realm, const gchar *password,
+		const gchar *nonce, const gchar *client_nonce);
+
+/** Calculate a response for HTTP Digest authentication
+ *
+ * See RFC 2617 for more information.
+ *
+ * @param algorithm         The hash algorithm to use
+ * @param method            The HTTP method in use
+ * @param digest_uri        The URI from the initial request
+ * @param qop               The "quality of protection"
+ * @param entity            The entity body
+ * @param nonce             The nonce provided by the server
+ * @param nonce_count       The nonce count
+ * @param client_nonce      The nonce provided by the client
+ * @param session_key       The session key from purple_cipher_http_digest_calculate_session_key()
+ *
+ * @return The hashed response, or @c NULL if an error occurred.
+ */
+gchar *purple_http_digest_calculate_response(
+		const gchar *algorithm, const gchar *method,
+		const gchar *digest_uri, const gchar *qop,
+		const gchar *entity, const gchar *nonce,
+		const gchar *nonce_count, const gchar *client_nonce,
+		const gchar *session_key);
+
 G_END_DECLS
 
 #endif /* _PURPLE_UTIL_H_ */
--- a/pidgin/gtkaccount.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/gtkaccount.c	Sun Jun 23 13:35:53 2013 +0530
@@ -165,6 +165,10 @@
 static void set_account(GtkListStore *store, GtkTreeIter *iter,
 						  PurpleAccount *account, GdkPixbuf *global_buddyicon);
 
+/* privacy UI ops */
+void pidgin_permit_added_removed(PurpleAccount *account, const char *name);
+void pidgin_deny_added_removed(PurpleAccount *account, const char *name);
+
 /**************************************************************************
  * Add/Modify Account dialog
  **************************************************************************/
@@ -859,9 +863,9 @@
 		gpointer data = NULL;
 		size_t len = 0;
 
-		if (purple_account_get_alias(dialog->account))
+		if (purple_account_get_private_alias(dialog->account))
 			gtk_entry_set_text(GTK_ENTRY(dialog->alias_entry),
-							   purple_account_get_alias(dialog->account));
+							   purple_account_get_private_alias(dialog->account));
 
 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->new_mail_check),
 					     purple_account_get_check_mail(dialog->account));
@@ -1401,7 +1405,7 @@
 	if (succeeded)
 	{
 		const PurpleSavedStatus *saved_status = purple_savedstatus_get_current();
-		purple_signal_emit(pidgin_account_get_handle(), "account-modified", account);
+		purple_signal_emit(pidgin_accounts_get_handle(), "account-modified", account);
 
 		if (saved_status != NULL && purple_account_get_remember_password(account)) {
 			purple_savedstatus_activate_for_account(saved_status, account);
@@ -1485,9 +1489,9 @@
 	value = gtk_entry_get_text(GTK_ENTRY(dialog->alias_entry));
 
 	if (*value != '\0')
-		purple_account_set_alias(account, value);
+		purple_account_set_private_alias(account, value);
 	else
-		purple_account_set_alias(account, NULL);
+		purple_account_set_private_alias(account, NULL);
 
 	/* Buddy Icon */
 	if (dialog->prpl_info != NULL && dialog->prpl_info->icon_spec.format != NULL)
@@ -1668,7 +1672,7 @@
 	if (new_acct)
 		purple_accounts_add(account);
 	else
-		purple_signal_emit(pidgin_account_get_handle(), "account-modified", account);
+		purple_signal_emit(pidgin_accounts_get_handle(), "account-modified", account);
 
 	/* If this is a new account, then sign on! */
 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->register_button))) {
@@ -2555,7 +2559,7 @@
 	/* Close button */
 	pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_CLOSE, G_CALLBACK(close_accounts_cb), dialog);
 
-	purple_signal_connect(pidgin_account_get_handle(), "account-modified",
+	purple_signal_connect(pidgin_accounts_get_handle(), "account-modified",
 	                    accounts_window,
 	                    PURPLE_CALLBACK(account_modified_cb), accounts_window);
 	purple_prefs_connect_callback(accounts_window,
@@ -2901,10 +2905,11 @@
 	pidgin_accounts_request_add,
 	pidgin_accounts_request_authorization,
 	pidgin_accounts_request_close,
-	NULL,
-	NULL,
-	NULL,
-	NULL
+	pidgin_permit_added_removed,
+	pidgin_permit_added_removed,
+	pidgin_deny_added_removed,
+	pidgin_deny_added_removed,
+	NULL, NULL, NULL, NULL
 };
 
 PurpleAccountUiOps *
@@ -2914,14 +2919,14 @@
 }
 
 void *
-pidgin_account_get_handle(void) {
+pidgin_accounts_get_handle(void) {
 	static int handle;
 
 	return &handle;
 }
 
 void
-pidgin_account_init(void)
+pidgin_accounts_init(void)
 {
 	char *default_avatar = NULL;
 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/accounts");
@@ -2941,29 +2946,29 @@
 	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon", default_avatar);
 	g_free(default_avatar);
 
-	purple_signal_register(pidgin_account_get_handle(), "account-modified",
+	purple_signal_register(pidgin_accounts_get_handle(), "account-modified",
 						 purple_marshal_VOID__POINTER, NULL, 1,
 						 purple_value_new(PURPLE_TYPE_SUBTYPE,
 										PURPLE_SUBTYPE_ACCOUNT));
 
 	/* Setup some purple signal handlers. */
 	purple_signal_connect(purple_connections_get_handle(), "signed-on",
-						pidgin_account_get_handle(),
+						pidgin_accounts_get_handle(),
 						PURPLE_CALLBACK(signed_on_off_cb), NULL);
 	purple_signal_connect(purple_connections_get_handle(), "signed-off",
-						pidgin_account_get_handle(),
+						pidgin_accounts_get_handle(),
 						PURPLE_CALLBACK(signed_on_off_cb), NULL);
 	purple_signal_connect(purple_accounts_get_handle(), "account-added",
-						pidgin_account_get_handle(),
+						pidgin_accounts_get_handle(),
 						PURPLE_CALLBACK(add_account_to_liststore), NULL);
 	purple_signal_connect(purple_accounts_get_handle(), "account-removed",
-						pidgin_account_get_handle(),
+						pidgin_accounts_get_handle(),
 						PURPLE_CALLBACK(account_removed_cb), NULL);
 	purple_signal_connect(purple_accounts_get_handle(), "account-disabled",
-						pidgin_account_get_handle(),
+						pidgin_accounts_get_handle(),
 						PURPLE_CALLBACK(account_abled_cb), GINT_TO_POINTER(FALSE));
 	purple_signal_connect(purple_accounts_get_handle(), "account-enabled",
-						pidgin_account_get_handle(),
+						pidgin_accounts_get_handle(),
 						PURPLE_CALLBACK(account_abled_cb), GINT_TO_POINTER(TRUE));
 
 	account_pref_wins =
@@ -2971,7 +2976,7 @@
 }
 
 void
-pidgin_account_uninit(void)
+pidgin_accounts_uninit(void)
 {
 	/*
 	 * TODO: Need to free all the dialogs in here.  Could probably create
@@ -2980,7 +2985,7 @@
 	 */
 	g_hash_table_destroy(account_pref_wins);
 
-	purple_signals_disconnect_by_handle(pidgin_account_get_handle());
-	purple_signals_unregister_by_instance(pidgin_account_get_handle());
+	purple_signals_disconnect_by_handle(pidgin_accounts_get_handle());
+	purple_signals_unregister_by_instance(pidgin_accounts_get_handle());
 }
 
--- a/pidgin/gtkaccount.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/gtkaccount.h	Sun Jun 23 13:35:53 2013 +0530
@@ -27,7 +27,7 @@
 #ifndef _PIDGINACCOUNT_H_
 #define _PIDGINACCOUNT_H_
 
-#include "account.h"
+#include "accounts.h"
 
 typedef enum
 {
@@ -70,17 +70,17 @@
  *
  * @return The handle to the GTK+ account system
  */
-void *pidgin_account_get_handle(void);
+void *pidgin_accounts_get_handle(void);
 
 /**
  * Initializes the GTK+ account system
  */
-void pidgin_account_init(void);
+void pidgin_accounts_init(void);
 
 /**
  * Uninitializes the GTK+ account system
  */
-void pidgin_account_uninit(void);
+void pidgin_accounts_uninit(void);
 
 G_END_DECLS
 
--- a/pidgin/gtkblist.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/gtkblist.c	Sun Jun 23 13:35:53 2013 +0530
@@ -1416,14 +1416,14 @@
 	account = purple_buddy_get_account(buddy);
 	name = purple_buddy_get_name(buddy);
 
-	permitted = purple_privacy_check(account, name);
+	permitted = purple_account_privacy_check(account, name);
 
 	/* XXX: Perhaps ask whether to restore the previous lists where appropirate? */
 
 	if (permitted)
-		purple_privacy_deny(account, name, FALSE, FALSE);
+		purple_account_privacy_deny(account, name);
 	else
-		purple_privacy_allow(account, name, FALSE, FALSE);
+		purple_account_privacy_allow(account, name);
 
 	pidgin_blist_update(purple_get_blist(), node);
 }
@@ -1435,7 +1435,7 @@
 	gboolean permitted;
 
 	account = purple_buddy_get_account(buddy);
-	permitted = purple_privacy_check(account, purple_buddy_get_name(buddy));
+	permitted = purple_account_privacy_check(account, purple_buddy_get_name(buddy));
 
 	pidgin_new_item_from_stock(menu, permitted ? _("_Block") : _("Un_block"),
 						permitted ? PIDGIN_STOCK_TOOLBAR_BLOCK : PIDGIN_STOCK_TOOLBAR_UNBLOCK, G_CALLBACK(toggle_privacy),
@@ -4159,7 +4159,7 @@
 
 	g_return_val_if_fail(buddy != NULL, NULL);
 
-	if (!purple_privacy_check(purple_buddy_get_account(buddy), purple_buddy_get_name(buddy))) {
+	if (!purple_account_privacy_check(purple_buddy_get_account(buddy), purple_buddy_get_name(buddy))) {
 		path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "blocked.png", NULL);
 		return _pidgin_blist_get_cached_emblem(path);
 	}
@@ -6309,7 +6309,7 @@
 	purple_signal_connect(handle, "account-actions-changed", gtkblist,
 	                      PURPLE_CALLBACK(account_actions_changed), NULL);
 
-	handle = pidgin_account_get_handle();
+	handle = pidgin_accounts_get_handle();
 	purple_signal_connect(handle, "account-modified", gtkblist,
 	                      PURPLE_CALLBACK(account_modified), gtkblist);
 
--- a/pidgin/gtkconv.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/gtkconv.c	Sun Jun 23 13:35:53 2013 +0530
@@ -5140,7 +5140,7 @@
 			replace = purple_conversation_get_name(conv);
 
 		} else if (g_str_has_prefix(cur, "%sourceName%")) {
-			replace = purple_account_get_alias(account);
+			replace = purple_account_get_private_alias(account);
 			if (replace == NULL)
 				replace = purple_account_get_username(account);
 
@@ -7205,7 +7205,7 @@
 		gtk_action_set_visible(win->menu.get_info, TRUE);
 		gtk_action_set_visible(win->menu.invite, FALSE);
 		gtk_action_set_visible(win->menu.alias, TRUE);
-		if (purple_privacy_check(account, purple_conversation_get_name(conv))) {
+		if (purple_account_privacy_check(account, purple_conversation_get_name(conv))) {
 			gtk_action_set_visible(win->menu.unblock, FALSE);
 			gtk_action_set_visible(win->menu.block, TRUE);
 		} else {
--- a/pidgin/gtkmain.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/gtkmain.c	Sun Jun 23 13:35:53 2013 +0530
@@ -257,7 +257,6 @@
 	purple_xfers_set_ui_ops(pidgin_xfers_get_ui_ops());
 	purple_blist_set_ui_ops(pidgin_blist_get_ui_ops());
 	purple_notify_set_ui_ops(pidgin_notify_get_ui_ops());
-	purple_privacy_set_ui_ops(pidgin_privacy_get_ui_ops());
 	purple_request_set_ui_ops(pidgin_request_get_ui_ops());
 	purple_sound_set_ui_ops(pidgin_sound_get_ui_ops());
 	purple_connections_set_ui_ops(pidgin_connections_get_ui_ops());
@@ -266,7 +265,7 @@
 	purple_idle_set_ui_ops(pidgin_idle_get_ui_ops());
 #endif
 
-	pidgin_account_init();
+	pidgin_accounts_init();
 	pidgin_connection_init();
 	pidgin_blist_init();
 	pidgin_status_init();
@@ -302,7 +301,7 @@
 	pidgin_docklet_uninit();
 	pidgin_blist_uninit();
 	pidgin_connection_uninit();
-	pidgin_account_uninit();
+	pidgin_accounts_uninit();
 	pidgin_xfers_uninit();
 	pidgin_debug_uninit();
 
--- a/pidgin/gtkprivacy.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/gtkprivacy.c	Sun Jun 23 13:35:53 2013 +0530
@@ -28,7 +28,6 @@
 
 #include "connection.h"
 #include "debug.h"
-#include "privacy.h"
 #include "request.h"
 #include "util.h"
 
@@ -80,17 +79,20 @@
 
 } const menu_entries[] =
 {
-	{ N_("Allow all users to contact me"),         PURPLE_PRIVACY_ALLOW_ALL },
-	{ N_("Allow only the users on my buddy list"), PURPLE_PRIVACY_ALLOW_BUDDYLIST },
-	{ N_("Allow only the users below"),            PURPLE_PRIVACY_ALLOW_USERS },
-	{ N_("Block all users"),                       PURPLE_PRIVACY_DENY_ALL },
-	{ N_("Block only the users below"),            PURPLE_PRIVACY_DENY_USERS }
+	{ N_("Allow all users to contact me"),         PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL },
+	{ N_("Allow only the users on my buddy list"), PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST },
+	{ N_("Allow only the users below"),            PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS },
+	{ N_("Block all users"),                       PURPLE_ACCOUNT_PRIVACY_DENY_ALL },
+	{ N_("Block only the users below"),            PURPLE_ACCOUNT_PRIVACY_DENY_USERS }
 };
 
 static const size_t menu_entry_count = sizeof(menu_entries) / sizeof(*menu_entries);
 
 static PidginPrivacyDialog *privacy_dialog = NULL;
 
+void pidgin_permit_added_removed(PurpleAccount *account, const char *name);
+void pidgin_deny_added_removed(PurpleAccount *account, const char *name);
+
 static void
 rebuild_allow_list(PidginPrivacyDialog *dialog)
 {
@@ -99,7 +101,7 @@
 
 	gtk_list_store_clear(dialog->allow_store);
 
-	for (l = dialog->account->permit; l != NULL; l = l->next) {
+	for (l = purple_account_privacy_get_permitted(dialog->account); l != NULL; l = l->next) {
 		gtk_list_store_append(dialog->allow_store, &iter);
 		gtk_list_store_set(dialog->allow_store, &iter, 0, l->data, -1);
 	}
@@ -113,7 +115,7 @@
 
 	gtk_list_store_clear(dialog->block_store);
 
-	for (l = dialog->account->deny; l != NULL; l = l->next) {
+	for (l = purple_account_privacy_get_denied(dialog->account); l != NULL; l = l->next) {
 		gtk_list_store_append(dialog->block_store, &iter);
 		gtk_list_store_set(dialog->block_store, &iter, 0, l->data, -1);
 	}
@@ -239,12 +241,12 @@
 	gtk_widget_hide(dialog->block_widget);
 	gtk_widget_hide(dialog->button_box);
 
-	if (new_type == PURPLE_PRIVACY_ALLOW_USERS) {
+	if (new_type == PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS) {
 		gtk_widget_show(dialog->allow_widget);
 		gtk_widget_show_all(dialog->button_box);
 		dialog->in_allow_list = TRUE;
 	}
-	else if (new_type == PURPLE_PRIVACY_DENY_USERS) {
+	else if (new_type == PURPLE_ACCOUNT_PRIVACY_DENY_USERS) {
 		gtk_widget_show(dialog->block_widget);
 		gtk_widget_show_all(dialog->button_box);
 		dialog->in_allow_list = FALSE;
@@ -295,9 +297,9 @@
 		return;
 
 	if (dialog->in_allow_list)
-		purple_privacy_permit_remove(dialog->account, name, FALSE);
+		purple_account_privacy_permit_remove(dialog->account, name, FALSE);
 	else
-		purple_privacy_deny_remove(dialog->account, name, FALSE);
+		purple_account_privacy_deny_remove(dialog->account, name, FALSE);
 
 	g_free(name);
 }
@@ -307,17 +309,17 @@
 {
 	GSList *l;
 	if (dialog->in_allow_list)
-		l = dialog->account->permit;
+		l = purple_account_privacy_get_permitted(dialog->account);
 	else
-		l = dialog->account->deny;
+		l = purple_account_privacy_get_denied(dialog->account);
 	while (l) {
 		char *user;
 		user = l->data;
 		l = l->next;
 		if (dialog->in_allow_list)
-			purple_privacy_permit_remove(dialog->account, user, FALSE);
+			purple_account_privacy_permit_remove(dialog->account, user, FALSE);
 		else
-			purple_privacy_deny_remove(dialog->account, user, FALSE);
+			purple_account_privacy_deny_remove(dialog->account, user, FALSE);
 	}
 }
 
@@ -413,12 +415,12 @@
 
 	type_changed_cb(GTK_COMBO_BOX(dialog->type_menu), dialog);
 #if 0
-	if (purple_account_get_privacy_type(dialog->account) == PURPLE_PRIVACY_ALLOW_USERS) {
+	if (purple_account_get_privacy_type(dialog->account) == PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS) {
 		gtk_widget_show(dialog->allow_widget);
 		gtk_widget_show(dialog->button_box);
 		dialog->in_allow_list = TRUE;
 	}
-	else if (purple_account_get_privacy_type(dialog->account) == PURPLE_PRIVACY_DENY_USERS) {
+	else if (purple_account_get_privacy_type(dialog->account) == PURPLE_ACCOUNT_PRIVACY_DENY_USERS) {
 		gtk_widget_show(dialog->block_widget);
 		gtk_widget_show(dialog->button_box);
 		dialog->in_allow_list = FALSE;
@@ -462,9 +464,9 @@
 confirm_permit_block_cb(PidginPrivacyRequestData *data, int option)
 {
 	if (data->block)
-		purple_privacy_deny(data->account, data->name, FALSE, FALSE);
+		purple_account_privacy_deny(data->account, data->name);
 	else
-		purple_privacy_allow(data->account, data->name, FALSE, FALSE);
+		purple_account_privacy_allow(data->account, data->name);
 
 	destroy_request_data(data);
 }
@@ -558,38 +560,20 @@
 	}
 }
 
-static void
+void
 pidgin_permit_added_removed(PurpleAccount *account, const char *name)
 {
 	if (privacy_dialog != NULL)
 		rebuild_allow_list(privacy_dialog);
 }
 
-static void
+void
 pidgin_deny_added_removed(PurpleAccount *account, const char *name)
 {
 	if (privacy_dialog != NULL)
 		rebuild_block_list(privacy_dialog);
 }
 
-static PurplePrivacyUiOps privacy_ops =
-{
-	pidgin_permit_added_removed,
-	pidgin_permit_added_removed,
-	pidgin_deny_added_removed,
-	pidgin_deny_added_removed,
-	NULL,
-	NULL,
-	NULL,
-	NULL
-};
-
-PurplePrivacyUiOps *
-pidgin_privacy_get_ui_ops(void)
-{
-	return &privacy_ops;
-}
-
 void
 pidgin_privacy_init(void)
 {
--- a/pidgin/gtkprivacy.h	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/gtkprivacy.h	Sun Jun 23 13:35:53 2013 +0530
@@ -26,7 +26,7 @@
 #ifndef _PIDGINPRIVACY_H_
 #define _PIDGINPRIVACY_H_
 
-#include "privacy.h"
+#include "account.h"
 
 G_BEGIN_DECLS
 
@@ -67,13 +67,6 @@
  */
 void pidgin_request_add_block(PurpleAccount *account, const char *name);
 
-/**
- * Returns the UI operations structure for the GTK+ privacy subsystem.
- *
- * @return The GTK+ UI privacy operations structure.
- */
-PurplePrivacyUiOps *pidgin_privacy_get_ui_ops(void);
-
 G_END_DECLS
 
 #endif /* _PIDGINPRIVACY_H_ */
--- a/pidgin/gtksession.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/gtksession.c	Sun Jun 23 13:35:53 2013 +0530
@@ -366,7 +366,7 @@
 	g_free(tmp);
 
 	session_set_gchar(session, SmRestartStyleHint, (gchar) SmRestartIfRunning);
-	session_set_string(session, SmProgram, g_get_prgname());
+	session_set_string(session, SmProgram, (gchar *) g_get_prgname());
 
 	myself = g_strdup(argv0);
 	purple_debug(PURPLE_DEBUG_MISC, "Session Management",
--- a/pidgin/gtkutils.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/gtkutils.c	Sun Jun 23 13:35:53 2013 +0530
@@ -733,10 +733,10 @@
 				gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE);
 		}
 
-		if (purple_account_get_alias(account)) {
+		if (purple_account_get_private_alias(account)) {
 			g_snprintf(buf, sizeof(buf), "%s (%s) (%s)",
 					   purple_account_get_username(account),
-					   purple_account_get_alias(account),
+					   purple_account_get_private_alias(account),
 					   purple_account_get_protocol_name(account));
 		} else {
 			g_snprintf(buf, sizeof(buf), "%s (%s)",
--- a/pidgin/plugins/gtk-signals-test.c	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/plugins/gtk-signals-test.c	Sun Jun 23 13:35:53 2013 +0530
@@ -110,7 +110,7 @@
 static gboolean
 plugin_load(PurplePlugin *plugin)
 {
-	void *accounts_handle = pidgin_account_get_handle();
+	void *accounts_handle = pidgin_accounts_get_handle();
 	void *blist_handle = pidgin_blist_get_handle();
 	void *conv_handle = pidgin_conversations_get_handle();
 
--- a/pidgin/plugins/perl/common/GtkAccount.xs	Sun Jun 23 02:43:06 2013 -0500
+++ b/pidgin/plugins/perl/common/GtkAccount.xs	Sun Jun 23 13:35:53 2013 +0530
@@ -4,7 +4,7 @@
 PROTOTYPES: ENABLE
 
 Purple::Handle
-pidgin_account_get_handle()
+pidgin_accounts_get_handle()
 
 MODULE = Pidgin::Account  PACKAGE = Pidgin::Account::Dialog  PREFIX = pidgin_account_dialog_
 PROTOTYPES: ENABLE
--- a/po/POTFILES.in	Sun Jun 23 02:43:06 2013 -0500
+++ b/po/POTFILES.in	Sun Jun 23 13:35:53 2013 +0530
@@ -18,20 +18,6 @@
 finch/gntsound.c
 finch/gntstatus.c
 finch/gntui.c
-finch/libgnt/gntbox.c
-finch/libgnt/gntbutton.c
-finch/libgnt/gntcheckbox.c
-finch/libgnt/gntcolors.c
-finch/libgnt/gntcombobox.c
-finch/libgnt/gntentry.c
-finch/libgnt/gntkeys.c
-finch/libgnt/gntlabel.c
-finch/libgnt/gntline.c
-finch/libgnt/gntstyle.c
-finch/libgnt/gnttextview.c
-finch/libgnt/gnttree.c
-finch/libgnt/gntutils.c
-finch/libgnt/gntwidget.c
 finch/plugins/gntclipboard.c
 finch/plugins/gntgf.c
 finch/plugins/gnthistory.c
@@ -44,14 +30,15 @@
 libpurple/connection.c
 libpurple/conversation.c
 libpurple/dbus-server.c
-libpurple/dbus-server.h
 libpurple/desktopitem.c
 libpurple/dnsquery.c
 libpurple/ft.c
 libpurple/gconf/purple.schemas.in
+libpurple/http.c
 libpurple/keyring.c
 libpurple/log.c
 libpurple/media/backend-fs2.c
+libpurple/obsolete.c
 libpurple/plugin.c
 libpurple/plugins/autoaccept.c
 libpurple/plugins/buddynote.c
@@ -82,10 +69,16 @@
 libpurple/plugins/statenotify.c
 libpurple/plugins/tcl/tcl.c
 libpurple/protocols/bonjour/bonjour.c
-libpurple/protocols/bonjour/bonjour.h
 libpurple/protocols/bonjour/jabber.c
 libpurple/protocols/bonjour/mdns_win32.c
+libpurple/protocols/gg/account.c
+libpurple/protocols/gg/deprecated.c
 libpurple/protocols/gg/gg.c
+libpurple/protocols/gg/image.c
+libpurple/protocols/gg/pubdir-prpl.c
+libpurple/protocols/gg/purplew.c
+libpurple/protocols/gg/status.c
+libpurple/protocols/gg/validator.c
 libpurple/protocols/irc/cmds.c
 libpurple/protocols/irc/dcc_send.c
 libpurple/protocols/irc/irc.c
@@ -102,6 +95,8 @@
 libpurple/protocols/jabber/chat.c
 libpurple/protocols/jabber/jabber.c
 libpurple/protocols/jabber/jutil.c
+libpurple/protocols/jabber/libfacebook.c
+libpurple/protocols/jabber/libgtalk.c
 libpurple/protocols/jabber/libxmpp.c
 libpurple/protocols/jabber/message.c
 libpurple/protocols/jabber/parser.c
@@ -113,7 +108,6 @@
 libpurple/protocols/jabber/xdata.c
 libpurple/protocols/msn/contact.c
 libpurple/protocols/msn/error.c
-libpurple/protocols/msn/group.h
 libpurple/protocols/msn/msg.c
 libpurple/protocols/msn/msn.c
 libpurple/protocols/msn/nexus.c
@@ -121,20 +115,11 @@
 libpurple/protocols/msn/oim.c
 libpurple/protocols/msn/servconn.c
 libpurple/protocols/msn/session.c
-libpurple/protocols/msn/slp.c
 libpurple/protocols/msn/slpcall.c
 libpurple/protocols/msn/state.c
 libpurple/protocols/msn/switchboard.c
 libpurple/protocols/msn/userlist.c
-libpurple/protocols/mxit/actions.c
-libpurple/protocols/mxit/filexfer.c
-libpurple/protocols/mxit/http.c
-libpurple/protocols/mxit/login.c
 libpurple/protocols/mxit/multimx.c
-libpurple/protocols/mxit/mxit.c
-libpurple/protocols/mxit/profile.c
-libpurple/protocols/mxit/protocol.c
-libpurple/protocols/mxit/roster.c
 libpurple/protocols/mxit/splashscreen.c
 libpurple/protocols/myspace/myspace.c
 libpurple/protocols/myspace/user.c
@@ -144,7 +129,9 @@
 libpurple/protocols/oscar/authorization.c
 libpurple/protocols/oscar/clientlogin.c
 libpurple/protocols/oscar/encoding.c
+libpurple/protocols/oscar/family_auth.c
 libpurple/protocols/oscar/family_chatnav.c
+libpurple/protocols/oscar/family_feedbag.c
 libpurple/protocols/oscar/family_icbm.c
 libpurple/protocols/oscar/family_locate.c
 libpurple/protocols/oscar/flap_connection.c
@@ -180,7 +167,7 @@
 libpurple/protocols/zephyr/zephyr.c
 libpurple/proxy.c
 libpurple/prpl.c
-libpurple/request.h
+libpurple/request.c
 libpurple/savedstatuses.c
 libpurple/server.c
 libpurple/smiley.c
@@ -194,7 +181,6 @@
 pidgin/gtkblist-theme.c
 pidgin/gtkblist.c
 pidgin/gtkcertmgr.c
-pidgin/gtkconn.c
 pidgin/gtkconv.c
 pidgin/gtkdebug.c
 pidgin/gtkdialogs.c
@@ -217,8 +203,9 @@
 pidgin/gtksound.c
 pidgin/gtkstatusbox.c
 pidgin/gtkutils.c
+pidgin/gtkwebview.c
+pidgin/gtkwebviewtoolbar.c
 pidgin/gtkwhiteboard.c
-pidgin/pidgin.h
 pidgin/pidginstock.c
 pidgin/pidgintooltip.c
 pidgin/pixmaps/emotes/default/24/default.theme.in
@@ -254,9 +241,7 @@
 pidgin/plugins/themeedit-icon.c
 pidgin/plugins/themeedit.c
 pidgin/plugins/ticker/ticker.c
-pidgin/plugins/timestamp.c
-pidgin/plugins/timestamp_format.c
-pidgin/plugins/vvconfig.c
+pidgin/plugins/webkit.c
 pidgin/plugins/win32/transparency/win2ktrans.c
 pidgin/plugins/win32/winprefs/winprefs.c
 pidgin/plugins/xmppconsole.c

mercurial