Merged pidgin/main into default

Mon, 05 Jun 2017 16:36:29 +0300

author
Arkadiy Illarionov <qarkai@gmail.com>
date
Mon, 05 Jun 2017 16:36:29 +0300
changeset 38887
826f5da7b56c
parent 38886
c1fb4e53da4e (current diff)
parent 38341
3da74e727e78 (diff)
child 38888
8bcae3a0b165

Merged pidgin/main into default

libpurple/ciphers/hmaccipher.c file | annotate | diff | comparison | revisions
libpurple/ciphers/hmaccipher.h file | annotate | diff | comparison | revisions
libpurple/ciphers/md5hash.c file | annotate | diff | comparison | revisions
libpurple/ciphers/md5hash.h file | annotate | diff | comparison | revisions
libpurple/ciphers/sha1hash.c file | annotate | diff | comparison | revisions
libpurple/ciphers/sha1hash.h file | annotate | diff | comparison | revisions
libpurple/ciphers/sha256hash.c file | annotate | diff | comparison | revisions
libpurple/ciphers/sha256hash.h file | annotate | diff | comparison | revisions
libpurple/protocols/msn/ft.c file | annotate | diff | comparison | revisions
libpurple/protocols/msn/ft.h file | annotate | diff | comparison | revisions
libpurple/protocols/mxit/cipher-mxit.c file | annotate | diff | comparison | revisions
libpurple/protocols/mxit/cipher-mxit.h file | annotate | diff | comparison | revisions
libpurple/protocols/mxit/client.c file | annotate | diff | comparison | revisions
libpurple/protocols/mxit/client.h file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/tests/.hgignore file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/tests/Makefile.am file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/tests/test_yahoo_util.c file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoo.c file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoo.h file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoojp.c file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/yahoojp.h file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/ymsg.c file | annotate | diff | comparison | revisions
libpurple/protocols/yahoo/ymsg.h file | annotate | diff | comparison | revisions
libpurple/tests/test_hmac.c file | annotate | diff | comparison | revisions
libpurple/tests/test_md5.c file | annotate | diff | comparison | revisions
libpurple/tests/test_sha1.c file | annotate | diff | comparison | revisions
libpurple/tests/test_sha256.c file | annotate | diff | comparison | revisions
libpurple/util.c file | annotate | diff | comparison | revisions
libpurple/util.h file | annotate | diff | comparison | revisions
pidgin/plugins/perl/Makefile.am file | annotate | diff | comparison | revisions
pidgin/plugins/perl/Makefile.mingw file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkAccount.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkBlist.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkConn.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkConv.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkConvWin.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkDebug.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkDialogs.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkFt.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkLog.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkMenuTray.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkPlugin.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkPluginPref.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkPounce.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkPrefs.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkPrivacy.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkRoomlist.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkSavedStatuses.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkSession.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkSound.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkStatusBox.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/GtkUtils.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/MANIFEST file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/Makefile.PL.in file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/Makefile.mingw file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/Pidgin.pm file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/Pidgin.xs file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/gtkmodule.h file | annotate | diff | comparison | revisions
pidgin/plugins/perl/common/typemap file | annotate | diff | comparison | revisions
--- a/.hgignore	Sun May 28 13:26:27 2017 +0300
+++ b/.hgignore	Mon Jun 05 16:36:29 2017 +0300
@@ -11,10 +11,6 @@
 .*/?.*\.pc$
 .*/?Makefile(\.in)?$
 .*/?Makefile\.am\.mingw$
-.*/perl/common/[^/]+\.c$
-.*/perl/common/blib.*
-.*/perl/common/pm_to_blib$
-.*/perl/common/MYMETA\.(json|yml)
 .*~$
 .*\.a$
 .*\.asc$
@@ -81,11 +77,6 @@
 libpurple/data/purple-url-handler.desktop.in$
 libpurple/marshallers.[ch]
 libpurple/plugins/dbus-example-bindings.c
-libpurple/plugins/perl/common/Makefile.PL$
-libpurple/plugins/perl/common/Makefile.old
-libpurple/plugins/perl/common/const-c.inc
-libpurple/plugins/perl/common/const-xs.inc
-libpurple/plugins/perl/common/lib
 libpurple/protocols/facebook/marshal.[ch]
 libpurple/purple-client-bindings.[ch]
 libpurple/purple-client-example
@@ -126,8 +117,6 @@
 pidgin/pixmaps/emotes/none/theme
 pidgin/pixmaps/emotes/small/16/theme
 pidgin/plugins/musicmessaging/music-messaging-bindings.c
-pidgin/plugins/perl/common/Makefile.PL$
-pidgin/plugins/perl/common/Makefile.old
 pidgin/win32/nsis/gtk-runtime-*.*.*.*.zip
 pidgin/win32/nsis/gtk_runtime_stage$
 pidgin/win32/nsis/cacert.pem
--- a/ChangeLog.API	Sun May 28 13:26:27 2017 +0300
+++ b/ChangeLog.API	Mon Jun 05 16:36:29 2017 +0300
@@ -417,6 +417,7 @@
 		* purple_account_add_buddies_with_invite
 		* purple_account_add_buddy_with_invite
 		* purple_account_set_current_error
+		* purple_base64_*. Use g_base64_* instead
 		* purple_blist_load
 		* purple_blist_new
 		* purple_set_blist
--- a/Makefile.am	Sun May 28 13:26:27 2017 +0300
+++ b/Makefile.am	Mon Jun 05 16:36:29 2017 +0300
@@ -138,12 +138,5 @@
 
 SUBDIRS = . m4macros libpurple $(GNT_DIR) $(GTK_DIR) $(PO_DIR) share/ca-certs share/sounds doc
 
-# perl's MakeMaker uninstall foo doesn't work well with DESTDIR set, which
-# breaks "make distcheck" unless we ignore perl things
-# TODO drop it when we drop perl wrapper
-
-distuninstallcheck_listfiles = \
-	find . -type f -print | grep -v perl | grep -v Purple.3pm | grep -v Pidgin.3pm
-
 DISTCLEANFILES= intltool-extract intltool-merge intltool-update \
 			package_revision_raw.txt
--- a/config.h.mingw	Sun May 28 13:26:27 2017 +0300
+++ b/config.h.mingw	Mon Jun 05 16:36:29 2017 +0300
@@ -180,18 +180,6 @@
 /* Define to 1 if you have the <paths.h> header file. */
 /* #define HAVE_PATHS_H 1 */
 
-/* Compile with support for perl */
-#define HAVE_PERL 1
-
-/* Define to 1 if you have the `Perl_eval_pv' function. */
-/* #undef HAVE_PERL_EVAL_PV */
-
-/* Define to 1 if you have the <perl.h> header file. */
-#define HAVE_PERL_H 1
-
-/* Define to 1 if you have the `perl_run' function. */
-/* #define HAVE_PERL_RUN 1 */
-
 /* Define to 1 if you have the <prio.h> header file. */
 /* #undef HAVE_PRIO_H */
 
@@ -273,9 +261,6 @@
 /* Define to 1 if you have the <sys/wait.h> header file. */
 /* #define HAVE_SYS_WAIT_H 1 */
 
-/* Compile with support for the Tcl toolkit */
-/* #define HAVE_TCL 1 */
-
 /* Define to 1 if you have the <termios.h> header file. */
 /* #define HAVE_TERMIOS_H 1 */
 
@@ -285,9 +270,6 @@
 /* Define if you have the external 'timezone' variable. */
 #define HAVE_TIMEZONE 1
 
-/* Compile with support for the Tk toolkit */
-#define HAVE_TK 1
-
 /* Define if you have a tm_gmtoff member in struct tm */
 /* #define HAVE_TM_GMTOFF 1 */
 
@@ -321,9 +303,6 @@
 /* Define to 1 if you don't have wide-character support. */
 /* #undef NO_WIDECHAR */
 
-/* Define if old perl is installed. */
-/* #undef OLD_PERL */
-
 /* Name of package */
 #define PACKAGE "pidgin"
 
--- a/doc/pidgin.1.in	Sun May 28 13:26:27 2017 +0300
+++ b/doc/pidgin.1.in	Mon Jun 05 16:36:29 2017 +0300
@@ -520,15 +520,6 @@
 configuration options, the \fIConfigure Plugin\fR button will present the
 plugin's preferences dialog.
 
-.SH PERL
-Pidgin allows for plugins to be written in the perl scripting language.  See
-\fIPerl Scripting HOWTO\fR in the Pidgin documentation for more information
-about perl scripting.
-
-.SH TCL
-Pidgin allows for plugins to be written in the Tcl scripting language. See
-\fIplugins/tcl/TCL-HOWTO\fR for more information about Tcl scripting.
-
 .SH D-Bus
 Pidgin allows for interaction via D-Bus.  Currently very little documentation
 about this interaction exists.
--- a/doc/reference/finch/Makefile.am	Sun May 28 13:26:27 2017 +0300
+++ b/doc/reference/finch/Makefile.am	Mon Jun 05 16:36:29 2017 +0300
@@ -103,6 +103,7 @@
 
 GTKDOC_LIBS = \
 	$(top_builddir)/finch/libfinch.la \
+	$(top_builddir)/libpurple/libpurple.la \
 	$(DBUS_LIBS) \
 	$(INTLLIBS) \
 	$(GLIB_LIBS) \
--- a/doc/reference/libpurple/libpurple-docs.xml	Sun May 28 13:26:27 2017 +0300
+++ b/doc/reference/libpurple/libpurple-docs.xml	Mon Jun 05 16:36:29 2017 +0300
@@ -111,13 +111,9 @@
         <xi:include href="xml/aescipher.xml" />
         <xi:include href="xml/descipher.xml" />
         <xi:include href="xml/des3cipher.xml" />
-        <xi:include href="xml/hmaccipher.xml" />
         <xi:include href="xml/pbkdf2cipher.xml" />
         <xi:include href="xml/rc4cipher.xml" />
         <xi:include href="xml/md4hash.xml" />
-        <xi:include href="xml/md5hash.xml" />
-        <xi:include href="xml/sha1hash.xml" />
-        <xi:include href="xml/sha256hash.xml" />
     </chapter>
 
     <chapter id="smiley">
--- a/doc/reference/pidgin/Makefile.am	Sun May 28 13:26:27 2017 +0300
+++ b/doc/reference/pidgin/Makefile.am	Mon Jun 05 16:36:29 2017 +0300
@@ -111,6 +111,7 @@
 
 GTKDOC_LIBS = \
 	$(top_builddir)/pidgin/libpidgin.la \
+	$(top_builddir)/libpurple/libpurple.la \
 	$(GLIB_LIBS) \
 	$(GPLUGIN_LIBS) \
 	$(GCR_LIBS) \
--- a/libpurple/Makefile.am	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/Makefile.am	Mon Jun 05 16:36:29 2017 +0300
@@ -44,13 +44,9 @@
 	ciphers/aescipher.c \
 	ciphers/descipher.c \
 	ciphers/des3cipher.c \
-	ciphers/hmaccipher.c \
 	ciphers/md4hash.c \
-	ciphers/md5hash.c \
 	ciphers/pbkdf2cipher.c \
 	ciphers/rc4cipher.c \
-	ciphers/sha1hash.c \
-	ciphers/sha256hash.c \
 	cipher.c \
 	circularbuffer.c \
 	cmds.c \
@@ -245,13 +241,9 @@
 	aescipher.h \
 	descipher.h \
 	des3cipher.h \
-	hmaccipher.h \
 	md4hash.h \
-	md5hash.h \
 	pbkdf2cipher.h \
-	rc4cipher.h \
-	sha1hash.h \
-	sha256hash.h
+	rc4cipher.h
 
 purple_builtheaders = purple.h version.h enums.h marshallers.h
 
--- a/libpurple/Makefile.mingw	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/Makefile.mingw	Mon Jun 05 16:36:29 2017 +0300
@@ -71,13 +71,9 @@
 			ciphers/aescipher.c \
 			ciphers/descipher.c \
 			ciphers/des3cipher.c \
-			ciphers/hmaccipher.c \
 			ciphers/md4hash.c \
-			ciphers/md5hash.c \
 			ciphers/pbkdf2cipher.c \
 			ciphers/rc4cipher.c \
-			ciphers/sha1hash.c \
-			ciphers/sha256hash.c \
 			cipher.c \
 			circularbuffer.c \
 			cmds.c \
--- a/libpurple/ciphers/hmaccipher.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,341 +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 "glibcompat.h"
-
-#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;
-static GParamSpec *properties[PROP_LAST];
-
-/*******************************************************************************
- * 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_by_pspec(G_OBJECT(cipher), properties[PROP_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);
-
-	g_free(priv->ipad);
-	priv->ipad = NULL;
-	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);
-	gsize 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);
-}
-
-/******************************************************************************
- * 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);
-
-	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;
-
-	properties[PROP_HASH] = g_param_spec_object("hash", "hash", "hash",
-								PURPLE_TYPE_HASH,
-								G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-								G_PARAM_STATIC_STRINGS);
-
-	g_object_class_install_properties(obj_class, PROP_LAST, properties);
-}
-
-/******************************************************************************
- * PurpleHMACCipher API
- *****************************************************************************/
-GType
-purple_hmac_cipher_get_type(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;
-}
-
--- a/libpurple/ciphers/hmaccipher.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#ifndef PURPLE_HMAC_CIPHER_H
-#define PURPLE_HMAC_CIPHER_H
-/**
- * SECTION:hmaccipher
- * @section_id: libpurple-hmaccipher
- * @short_description: <filename>ciphers/hmaccipher.h</filename>
- * @title: HMAC Cipher
- */
-
-#include "cipher.h"
-
-#define PURPLE_TYPE_HMAC_CIPHER				(purple_hmac_cipher_get_type())
-#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;
-};
-
-struct _PurpleHMACCipherClass {
-	PurpleCipherClass gparent;
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-GType purple_hmac_cipher_get_type(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/md5hash.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +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 "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(required_len >= 0, FALSE);
-	g_return_val_if_fail(buff_len >= (gsize)required_len, FALSE);
-
-	g_checksum_get_digest(priv->checksum, digest, &digest_len);
-
-	if (digest_len != (gsize)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);
-}
-
-/******************************************************************************
- * 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;
-
-	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_type(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);
-}
--- a/libpurple/ciphers/md5hash.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#ifndef PURPLE_MD5_HASH_H
-#define PURPLE_MD5_HASH_H
-/**
- * SECTION:md5hash
- * @section_id: libpurple-md5hash
- * @short_description: <filename>ciphers/md5hash.h</filename>
- * @title: MD5 Hash
- */
-
-#include "cipher.h"
-
-#define PURPLE_TYPE_MD5_HASH				(purple_md5_hash_get_type())
-#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;
-};
-
-struct _PurpleMD5HashClass {
-	PurpleHashClass gparent;
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-GType purple_md5_hash_get_type(void);
-
-PurpleHash *purple_md5_hash_new(void);
-
-G_END_DECLS
-
-#endif /* PURPLE_MD5_HASH_H */
--- a/libpurple/ciphers/pbkdf2cipher.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/ciphers/pbkdf2cipher.c	Mon Jun 05 16:36:29 2017 +0300
@@ -25,7 +25,6 @@
 #include "glibcompat.h"
 
 #include "pbkdf2cipher.h"
-#include "hmaccipher.h"
 #include "debug.h"
 
 /* 1024bit */
@@ -38,7 +37,7 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_PBKDF2_CIPHER, PurplePBKDF2CipherPrivate))
 
 typedef struct {
-	PurpleHash *hash;
+	GChecksumType hash_type;
 	guint iter_count;
 	size_t out_len;
 
@@ -53,7 +52,7 @@
  *****************************************************************************/
 enum {
 	PROP_NONE,
-	PROP_HASH,
+	PROP_HASH_TYPE,
 	PROP_ITER_COUNT,
 	PROP_OUT_LEN,
 	PROP_LAST,
@@ -65,20 +64,6 @@
 static GObjectClass *parent_class = NULL;
 static GParamSpec *properties[PROP_LAST];
 
-/*******************************************************************************
- * 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_by_pspec(G_OBJECT(cipher), properties[PROP_HASH]);
-}
-
 /******************************************************************************
  * Cipher Stuff
  *****************************************************************************/
@@ -89,8 +74,6 @@
 
 	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;
 
@@ -167,17 +150,16 @@
 	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;
+	guint halfkey_count, halfkey_pad, halfkey_no;
+	gsize halfkey_len;
 	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);
@@ -188,19 +170,10 @@
 
 	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);
+	halfkey_len = g_checksum_type_get_length(priv->hash_type);
 	if (halfkey_len <= 0 || halfkey_len > PBKDF2_HASH_MAX_LEN) {
 		purple_debug_error("pbkdf2", "Unsupported hash function. "
-			"(digest size: %d)\n", halfkey_len);
+			"(digest size: %" G_GSIZE_FORMAT ")\n", halfkey_len);
 		return FALSE;
 	}
 
@@ -215,9 +188,18 @@
 		memset(halfkey, 0, halfkey_len);
 
 		for (iter_no = 1; iter_no <= priv->iter_count; iter_no++) {
+			GHmac *hmac;
 			guint i;
 
-			purple_cipher_reset_state(hash);
+			hmac = g_hmac_new(priv->hash_type,
+				(const guchar*)priv->passphrase,
+				priv->passphrase_len);
+			if (hmac == NULL) {
+				purple_debug_error("pbkdf2",
+					"Couldn't create new hmac cipher\n");
+				g_free(salt_ext);
+				return FALSE;
+			}
 
 			if (iter_no == 1) {
 				salt_ext[salt_ext_len - 4] =
@@ -229,21 +211,13 @@
 				salt_ext[salt_ext_len - 1] =
 					(halfkey_no & 0x000000ff) >> 0;
 
-				purple_cipher_append(hash, salt_ext,
-					salt_ext_len);
+				g_hmac_update(hmac, salt_ext, salt_ext_len);
 			}
 			else
-				purple_cipher_append(hash, halfkey_hash,
-					halfkey_len);
+				g_hmac_update(hmac, 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;
-			}
+			g_hmac_get_digest(hmac, halfkey_hash, &halfkey_len);
+			g_hmac_unref(hmac);
 
 			for (i = 0; i < halfkey_len; i++)
 				halfkey[i] ^= halfkey_hash[i];
@@ -255,7 +229,6 @@
 	}
 
 	g_free(salt_ext);
-	g_object_unref(hash);
 
 	return TRUE;
 }
@@ -271,8 +244,8 @@
 	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));
+		case PROP_HASH_TYPE:
+			g_value_set_int(value, priv->hash_type);
 			break;
 		case PROP_ITER_COUNT:
 			g_value_set_uint(value, priv->iter_count);
@@ -294,8 +267,8 @@
 	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));
+		case PROP_HASH_TYPE:
+			priv->hash_type = g_value_get_int(value);
 			break;
 		case PROP_ITER_COUNT:
 			priv->iter_count = g_value_get_uint(value);
@@ -313,13 +286,9 @@
 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);
 }
 
@@ -343,8 +312,8 @@
 
 	g_type_class_add_private(klass, sizeof(PurplePBKDF2CipherPrivate));
 
-	properties[PROP_HASH] = g_param_spec_object("hash", "hash", "hash",
-								PURPLE_TYPE_HASH,
+	properties[PROP_HASH_TYPE] = g_param_spec_int("hash-type", "hash-type", "hash-type",
+								G_MININT, G_MAXINT, -1,
 								G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 								G_PARAM_STATIC_STRINGS);
 
@@ -364,6 +333,11 @@
 static void
 purple_pbkdf2_cipher_init(PurpleCipher *cipher)
 {
+	PurplePBKDF2CipherPrivate *priv =
+		PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
+
+	priv->hash_type = -1;
+
 	purple_cipher_reset(cipher);
 }
 
@@ -397,24 +371,22 @@
 }
 
 PurpleCipher *
-purple_pbkdf2_cipher_new(PurpleHash *hash) {
-	g_return_val_if_fail(PURPLE_IS_HASH(hash), NULL);
-
+purple_pbkdf2_cipher_new(GChecksumType hash_type) {
 	return g_object_new(PURPLE_TYPE_PBKDF2_CIPHER,
-						"hash", hash,
+						"hash-type", hash_type,
 						NULL);
 }
 
-PurpleHash *
-purple_pbkdf2_cipher_get_hash(const PurplePBKDF2Cipher *cipher) {
+GChecksumType
+purple_pbkdf2_cipher_get_hash_type(const PurplePBKDF2Cipher *cipher) {
 	PurplePBKDF2CipherPrivate *priv = NULL;
 
-	g_return_val_if_fail(PURPLE_IS_PBKDF2_CIPHER(cipher), NULL);
+	g_return_val_if_fail(PURPLE_IS_PBKDF2_CIPHER(cipher), -1);
 
 	priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
 
-	if(priv && priv->hash)
-		return priv->hash;
+	if(priv)
+		return priv->hash_type;
 
-	return NULL;
+	return -1;
 }
--- a/libpurple/ciphers/pbkdf2cipher.h	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/ciphers/pbkdf2cipher.h	Mon Jun 05 16:36:29 2017 +0300
@@ -58,9 +58,9 @@
 
 GType purple_pbkdf2_cipher_get_type(void);
 
-PurpleCipher *purple_pbkdf2_cipher_new(PurpleHash *hash);
+PurpleCipher *purple_pbkdf2_cipher_new(GChecksumType hash_type);
 
-PurpleHash *purple_pbkdf2_cipher_get_hash(const PurplePBKDF2Cipher *cipher);
+GChecksumType purple_pbkdf2_cipher_get_hash_type(const PurplePBKDF2Cipher *cipher);
 
 G_END_DECLS
 
--- a/libpurple/ciphers/sha1hash.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +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 "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(required_len >= 0, FALSE);
-	g_return_val_if_fail(buff_len >= (gsize)required_len, FALSE);
-
-	g_checksum_get_digest(priv->checksum, digest, &digest_len);
-
-	if (digest_len != (gsize)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);
-}
-
-/******************************************************************************
- * 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;
-
-	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_type(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);
-}
--- a/libpurple/ciphers/sha1hash.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#ifndef PURPLE_SHA1_HASH_H
-#define PURPLE_SHA1_HASH_H
-/**
- * SECTION:sha1hash
- * @section_id: libpurple-sha1hash
- * @short_description: <filename>ciphers/sha1hash.h</filename>
- * @title: SHA1 Hash
- */
-
-#include "cipher.h"
-
-#define PURPLE_TYPE_SHA1_HASH				(purple_sha1_hash_get_type())
-#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;
-};
-
-struct _PurpleSHA1HashClass {
-	PurpleHashClass gparent;
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-GType purple_sha1_hash_get_type(void);
-
-PurpleHash *purple_sha1_hash_new(void);
-
-G_END_DECLS
-
-#endif /* PURPLE_SHA1_HASH_H */
--- a/libpurple/ciphers/sha256hash.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +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 "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(required_len >= 0, FALSE);
-	g_return_val_if_fail(buff_len >= (gsize)required_len, FALSE);
-
-	g_checksum_get_digest(priv->checksum, digest, &digest_len);
-
-	if (digest_len != (gsize)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);
-}
-
-/******************************************************************************
- * 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;
-
-	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_type(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);
-}
--- a/libpurple/ciphers/sha256hash.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#ifndef PURPLE_SHA256_HASH_H
-#define PURPLE_SHA256_HASH_H
-/**
- * SECTION:sha256hash
- * @section_id: libpurple-sha256hash
- * @short_description: <filename>ciphers/sha256hash.h</filename>
- * @title: SHA256 Hash
- */
-
-#include "cipher.h"
-
-#define PURPLE_TYPE_SHA256_HASH				(purple_sha256_hash_get_type())
-#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;
-};
-
-struct _PurpleSHA256HashClass {
-	PurpleHashClass gparent;
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-GType purple_sha256_hash_get_type(void);
-
-PurpleHash *purple_sha256_hash_new(void);
-
-G_END_DECLS
-
-#endif /* PURPLE_SHA256_HASH_H */
--- a/libpurple/http.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/http.c	Mon Jun 05 16:36:29 2017 +0300
@@ -859,7 +859,7 @@
 
 		tmp = g_strdup_printf("%s:%s", proxy_username, proxy_password);
 		len = strlen(tmp);
-		proxy_auth = purple_base64_encode((const guchar *)tmp, len);
+		proxy_auth = g_base64_encode((const guchar *)tmp, len);
 		memset(tmp, 0, len);
 		g_free(tmp);
 
--- a/libpurple/mime.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/mime.c	Mon Jun 05 16:36:29 2017 +0300
@@ -345,7 +345,7 @@
 		*data = purple_base16_decode(part->data->str, len);
 
 	} else if(! g_ascii_strcasecmp(enc, "base64")) {
-		*data = purple_base64_decode(part->data->str, len);
+		*data = g_base64_decode(part->data->str, len);
 
 	} else if(! g_ascii_strcasecmp(enc, "quoted-printable")) {
 		*data = purple_quotedp_decode(part->data->str, len);
--- a/libpurple/ntlm.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/ntlm.c	Mon Jun 05 16:36:29 2017 +0300
@@ -139,7 +139,7 @@
 	memcpy(msg + host_off, hostname, hostnamelen);
 	memcpy(msg + dom_off, domain, domainlen);
 
-	tmp = purple_base64_encode(msg, sizeof(struct type1_message) + hostnamelen + domainlen);
+	tmp = g_base64_encode(msg, sizeof(struct type1_message) + hostnamelen + domainlen);
 	g_free(msg);
 
 	return tmp;
@@ -153,7 +153,7 @@
 	struct type2_message tmsg;
 	static guint8 nonce[8];
 
-	buff = purple_base64_decode(type2, &retlen);
+	buff = g_base64_decode(type2, &retlen);
 
 	if (buff != NULL && retlen >= (sizeof(struct type2_message) - 1)) {
 		memcpy(&tmsg, buff, MIN(retlen, sizeof(tmsg)));
@@ -397,7 +397,7 @@
 	/*tmsg->flags2 = 0x0a280105;
 	tmsg->flags3 = 0x0f000000;*/
 
-	tmp = purple_base64_encode((guchar *)tmsg, msglen);
+	tmp = g_base64_encode((guchar *)tmsg, msglen);
 	g_free(tmsg);
 
 	return tmp;
--- a/libpurple/plugins/Makefile.mingw	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/plugins/Makefile.mingw	Mon Jun 05 16:36:29 2017 +0300
@@ -7,8 +7,6 @@
 PIDGIN_TREE_TOP := ../..
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
-PERL_PLUGIN := ./perl
-SSL_PLUGIN := ./ssl
 KEYRING_PLUGIN := ./keyrings
 
 .SUFFIXES:
@@ -45,13 +43,9 @@
 .PHONY: all clean plugins install
 
 all: $(PURPLE_DLL).a plugins
-	$(MAKE_at) $(MAKE) -C $(PERL_PLUGIN) -f $(MINGW_MAKEFILE)
-	$(MAKE_at) $(MAKE) -C $(SSL_PLUGIN) -f $(MINGW_MAKEFILE)
 	$(MAKE_at) $(MAKE) -C $(KEYRING_PLUGIN) -f $(MINGW_MAKEFILE)
 
 install: all $(PURPLE_INSTALL_PLUGINS_DIR)
-	$(MAKE_at) $(MAKE) -C $(PERL_PLUGIN) -f $(MINGW_MAKEFILE) install
-	$(MAKE_at) $(MAKE) -C $(SSL_PLUGIN) -f $(MINGW_MAKEFILE) install
 	$(MAKE_at) $(MAKE) -C $(KEYRING_PLUGIN) -f $(MINGW_MAKEFILE) install
 	cp *.dll $(PURPLE_INSTALL_PLUGINS_DIR)
 
@@ -74,8 +68,6 @@
 ##
 clean:
 	rm -f *.o *.dll
-	$(MAKE_at) $(MAKE) -C $(PERL_PLUGIN) -f $(MINGW_MAKEFILE) clean
-	$(MAKE_at) $(MAKE) -C $(SSL_PLUGIN) -f $(MINGW_MAKEFILE) clean
 	$(MAKE_at) $(MAKE) -C $(KEYRING_PLUGIN) -f $(MINGW_MAKEFILE) clean
 
 include $(PIDGIN_COMMON_TARGETS)
--- a/libpurple/plugins/keyrings/internalkeyring.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/plugins/keyrings/internalkeyring.c	Mon Jun 05 16:36:29 2017 +0300
@@ -33,7 +33,6 @@
 
 #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 " \
@@ -139,7 +138,7 @@
 	guchar *data;
 	gsize len;
 
-	data = purple_base64_decode(base64, &len);
+	data = g_base64_decode(base64, &len);
 
 	return intkeyring_buff_new(data, len);
 }
@@ -152,14 +151,12 @@
 intkeyring_derive_key(const gchar *passphrase, intkeyring_buff_t *salt)
 {
 	PurpleCipher *cipher;
-	PurpleHash *hash;
 	gboolean succ;
 	intkeyring_buff_t *ret;
 
 	g_return_val_if_fail(passphrase != NULL, NULL);
 
-	hash = purple_sha256_hash_new();
-	cipher = purple_pbkdf2_cipher_new(hash);
+	cipher = purple_pbkdf2_cipher_new(G_CHECKSUM_SHA256);
 
 	g_object_set(G_OBJECT(cipher), "iter_count",
 		GUINT_TO_POINTER(purple_prefs_get_int(INTKEYRING_PREFS
@@ -175,7 +172,6 @@
 	succ = purple_cipher_digest(cipher, ret->data, ret->len);
 
 	g_object_unref(cipher);
-	g_object_unref(hash);
 
 	if (!succ) {
 		intkeyring_buff_free(ret);
@@ -282,7 +278,7 @@
 	if (encrypted_size < 0)
 		return NULL;
 
-	return purple_base64_encode(encrypted_raw, encrypted_size);
+	return g_base64_encode(encrypted_raw, encrypted_size);
 
 }
 
@@ -304,7 +300,7 @@
 	cipher = purple_aes_cipher_new();
 	g_return_val_if_fail(cipher != NULL, NULL);
 
-	encrypted_raw = purple_base64_decode(str, &encrypted_size);
+	encrypted_raw = g_base64_decode(str, &encrypted_size);
 	g_return_val_if_fail(encrypted_raw != NULL, NULL);
 
 	iv_len = purple_cipher_get_block_size(cipher);
@@ -378,7 +374,7 @@
 		 * but it's not a problem.
 		 */
 		verifier = intkeyring_encrypt(key, INTKEYRING_VERIFY_STR);
-		salt_b64 = purple_base64_encode(salt->data, salt->len);
+		salt_b64 = g_base64_encode(salt->data, salt->len);
 	}
 
 	if (!verifier || !salt_b64) {
--- a/libpurple/protocols/bonjour/bonjour_ft.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Mon Jun 05 16:36:29 2017 +0300
@@ -28,7 +28,6 @@
 #include "buddy.h"
 #include "bonjour.h"
 #include "bonjour_ft.h"
-#include "ciphers/sha1hash.h"
 
 static void
 bonjour_bytestreams_init(PurpleXfer *xfer);
@@ -1014,11 +1013,12 @@
 {
 	PurpleBuddy *pb;
 	PurpleAccount *account = NULL;
-	PurpleHash *hash;
+	GChecksum *hash;
 	XepXfer *xf;
 	char dstaddr[41];
 	const gchar *name = NULL;
 	unsigned char hashval[20];
+	gsize digest_len = 20;
 	char *p;
 	int i;
 
@@ -1037,10 +1037,10 @@
 
 	p = g_strdup_printf("%s%s%s", xf->sid, name, bonjour_get_jid(account));
 
-	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));
+	hash = g_checksum_new(G_CHECKSUM_SHA1);
+	g_checksum_update(hash, (guchar *)p, -1);
+	g_checksum_get_digest(hash, hashval, &digest_len);
+	g_checksum_free(hash);
 
 	g_free(p);
 
--- a/libpurple/protocols/gg/avatar.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/gg/avatar.c	Mon Jun 05 16:36:29 2017 +0300
@@ -353,7 +353,7 @@
 	}
 	own_data->img = NULL;
 
-	img_data = purple_base64_encode(purple_image_get_data(img),
+	img_data = g_base64_encode(purple_image_get_data(img),
 		purple_image_get_data_size(img));
 	img_data_e = g_uri_escape_string(img_data, NULL, FALSE);
 	g_free(img_data);
--- a/libpurple/protocols/gg/oauth/oauth.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/gg/oauth/oauth.c	Mon Jun 05 16:36:29 2017 +0300
@@ -26,8 +26,6 @@
 #include "oauth.h"
 
 #include "oauth-parameter.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 */
@@ -49,21 +47,16 @@
 
 static gchar *gg_hmac_sha1(const char *key, const char *message)
 {
-	PurpleCipher *cipher;
-	PurpleHash *hash;
+	GHmac *hmac;
 	guchar digest[20];
-
-	hash = purple_sha1_hash_new();
-	cipher = purple_hmac_cipher_new(hash);
+	gsize digest_len = 20;
 
-	purple_cipher_set_key(cipher, (guchar *)key, strlen(key));
-	purple_cipher_append(cipher, (guchar *)message, strlen(message));
-	purple_cipher_digest(cipher, digest, sizeof(digest));
+	hmac = g_hmac_new(G_CHECKSUM_SHA1, (guchar *)key, strlen(key));
+	g_hmac_update(hmac, (guchar *)message, -1);
+	g_hmac_get_digest(hmac, digest, &digest_len);
+	g_hmac_unref(hmac);
 
-	g_object_unref(cipher);
-	g_object_unref(hash);
-
-	return purple_base64_encode(digest, sizeof(digest));
+	return g_base64_encode(digest, sizeof(digest));
 }
 
 static char *
--- a/libpurple/protocols/irc/msgs.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/irc/msgs.c	Mon Jun 05 16:36:29 2017 +0300
@@ -1660,7 +1660,7 @@
 		return;
 
 	if (arg[0] != '+')
-		serverin = (char *)purple_base64_decode(arg, &serverinlen);
+		serverin = (char *)g_base64_decode(arg, &serverinlen);
 
 	ret = sasl_client_step(irc->sasl_conn, serverin, serverinlen,
 		NULL, &c_out, &clen);
@@ -1678,7 +1678,7 @@
 	}
 
 	if (clen > 0)
-		authinfo = purple_base64_encode((const guchar*)c_out, clen);
+		authinfo = g_base64_encode((const guchar*)c_out, clen);
 	else
 		authinfo = g_strdup("+");
 
--- a/libpurple/protocols/jabber/auth.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/auth.c	Mon Jun 05 16:36:29 2017 +0300
@@ -38,9 +38,6 @@
 #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,
@@ -266,7 +263,8 @@
 
 			x = purple_xmlnode_new_child(query, "digest");
 			s = g_strdup_printf("%s%s", js->stream_id, pw);
-			hash = jabber_calculate_data_hash(s, strlen(s), "sha1");
+			hash = g_compute_checksum_for_string(G_CHECKSUM_SHA1,
+					s, -1);
 			purple_xmlnode_insert_data(x, hash, -1);
 			g_free(hash);
 			g_free(s);
@@ -277,22 +275,15 @@
 			 * to non-SASL authentication.
 			 */
 			const char *challenge;
-			gchar digest[33];
-			PurpleCipher *hmac;
-			PurpleHash *md5;
-			gssize diglen;
+			gchar *digest;
 
 			/* Calculate the MHAC-MD5 digest */
-			md5 = purple_md5_hash_new();
-			hmac = purple_hmac_cipher_new(md5);
 			challenge = purple_xmlnode_get_attrib(x, "challenge");
-			purple_cipher_set_key(hmac, (guchar *)pw, strlen(pw));
-			purple_cipher_append(hmac, (guchar *)challenge, strlen(challenge));
-			diglen = purple_cipher_digest_to_str(hmac, digest, 33);
-			g_object_unref(hmac);
-			g_object_unref(md5);
+			digest = g_compute_hmac_for_string(G_CHECKSUM_MD5,
+					(guchar *)pw, strlen(pw),
+					challenge, -1);
 
-			g_return_if_fail(diglen > 0);
+			g_return_if_fail(digest != NULL);
 
 			/* Create the response query */
 			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
@@ -306,6 +297,7 @@
 			x = purple_xmlnode_new_child(query, "crammd5");
 
 			purple_xmlnode_insert_data(x, digest, 32);
+			g_free(digest);
 
 			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
 			jabber_iq_send(iq);
--- a/libpurple/protocols/jabber/auth_cyrus.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/auth_cyrus.c	Mon Jun 05 16:36:29 2017 +0300
@@ -336,7 +336,7 @@
 			if (coutlen == 0) {
 				purple_xmlnode_insert_data(auth, "=", -1);
 			} else {
-				enc_out = purple_base64_encode((unsigned char*)clientout, coutlen);
+				enc_out = g_base64_encode((unsigned char*)clientout, coutlen);
 				purple_xmlnode_insert_data(auth, enc_out, -1);
 				g_free(enc_out);
 			}
@@ -458,7 +458,7 @@
 	unsigned int clen;
 	gsize declen;
 
-	dec_in = purple_base64_decode(enc_in, &declen);
+	dec_in = g_base64_decode(enc_in, &declen);
 
 	js->sasl_state = sasl_client_step(js->sasl, (char*)dec_in, declen,
 					  NULL, &c_out, &clen);
@@ -486,10 +486,10 @@
 			if (!purple_strequal(js->current_mech, "DIGEST-MD5") ||
 					strstr(c_out, ",charset="))
 				/* If we're not using DIGEST-MD5 or Cyrus SASL is fixed */
-				enc_out = purple_base64_encode((unsigned char*)c_out, clen);
+				enc_out = g_base64_encode((unsigned char*)c_out, clen);
 			else {
 				char *tmp = g_strdup_printf("%s,charset=utf-8", c_out);
-				enc_out = purple_base64_encode((unsigned char*)tmp, clen + 14);
+				enc_out = g_base64_encode((unsigned char*)tmp, clen + 14);
 				g_free(tmp);
 			}
 
@@ -519,7 +519,7 @@
 		gsize declen = 0;
 
 		if(enc_in != NULL)
-			dec_in = purple_base64_decode(enc_in, &declen);
+			dec_in = g_base64_decode(enc_in, &declen);
 
 		js->sasl_state = sasl_client_step(js->sasl, (char*)dec_in, declen, NULL, &c_out, &clen);
 
--- a/libpurple/protocols/jabber/auth_digest_md5.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/auth_digest_md5.c	Mon Jun 05 16:36:29 2017 +0300
@@ -23,7 +23,6 @@
 #include "internal.h"
 
 #include "debug.h"
-#include "ciphers/md5hash.h"
 #include "util.h"
 #include "xmlnode.h"
 
@@ -106,9 +105,8 @@
 generate_response_value(JabberID *jid, const char *passwd, const char *nonce,
 		const char *cnonce, const char *a2, const char *realm)
 {
-	PurpleHash *hash;
-	guchar result[16];
-	size_t a1len;
+	GChecksum *hash;
+	gsize digest_len = 16;
 
 	gchar *a1, *convnode=NULL, *convpasswd = NULL, *ha1, *ha2, *kd, *x, *z;
 
@@ -121,36 +119,22 @@
 		convpasswd = g_strdup(passwd);
 	}
 
-	hash = purple_md5_hash_new();
+	hash = g_checksum_new(G_CHECKSUM_MD5);
 
 	x = g_strdup_printf("%s:%s:%s", convnode, realm, convpasswd ? convpasswd : "");
-	purple_hash_append(hash, (const guchar *)x, strlen(x));
-	purple_hash_digest(hash, result, sizeof(result));
+	g_checksum_update(hash, (const guchar *)x, -1);
 
 	a1 = g_strdup_printf("xxxxxxxxxxxxxxxx:%s:%s", nonce, cnonce);
-	a1len = strlen(a1);
-	g_memmove(a1, result, 16);
-
-	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);
+	g_checksum_get_digest(hash, (guint8 *)a1, &digest_len);
+	g_checksum_free(hash);
 
-	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);
+	ha1 = g_compute_checksum_for_string(G_CHECKSUM_MD5, a1, -1);
+	ha2 = g_compute_checksum_for_string(G_CHECKSUM_MD5, a2, -1);
 
 	kd = g_strdup_printf("%s:%s:00000001:%s:auth:%s", ha1, nonce, cnonce, ha2);
 
-	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);
+	z = g_compute_checksum_for_string(G_CHECKSUM_MD5, kd, -1);
 
 	g_free(convnode);
 	g_free(convpasswd);
@@ -171,6 +155,7 @@
 	char *enc_in = purple_xmlnode_get_data(packet);
 	char *dec_in;
 	char *enc_out;
+	gsize size = 0;
 	GHashTable *parts;
 	JabberSaslState state = JABBER_SASL_STATE_CONTINUE;
 
@@ -179,10 +164,10 @@
 		return JABBER_SASL_STATE_FAIL;
 	}
 
-	dec_in = (char *)purple_base64_decode(enc_in, NULL);
+	dec_in = (char *)g_base64_decode(enc_in, &size);
 	purple_debug_misc("jabber", "decoded challenge (%"
 			G_GSIZE_FORMAT "): %s\n",
-			strlen(dec_in),
+			size,
 			dec_in);
 
 	parts = jabber_auth_digest_md5_parse(dec_in);
@@ -254,7 +239,7 @@
 			g_free(auth_resp);
 			g_free(cnonce);
 
-			enc_out = purple_base64_encode((guchar *)response->str, response->len);
+			enc_out = g_base64_encode((guchar *)response->str, response->len);
 
 			purple_debug_misc("jabber", "decoded response (%"
 					G_GSIZE_FORMAT "): %s\n",
--- a/libpurple/protocols/jabber/auth_plain.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/auth_plain.c	Mon Jun 05 16:36:29 2017 +0300
@@ -50,7 +50,7 @@
 	response = g_string_append(response,
 			purple_connection_get_password(js->gc));
 
-	enc_out = purple_base64_encode((guchar *)response->str, response->len);
+	enc_out = g_base64_encode((guchar *)response->str, response->len);
 
 	purple_xmlnode_set_attrib(auth, "mechanism", "PLAIN");
 	purple_xmlnode_insert_data(auth, enc_out, -1);
--- a/libpurple/protocols/jabber/auth_scram.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/auth_scram.c	Mon Jun 05 16:36:29 2017 +0300
@@ -25,12 +25,10 @@
 #include "auth.h"
 #include "auth_scram.h"
 
-#include "ciphers/hmaccipher.h"
-#include "ciphers/sha1hash.h"
 #include "debug.h"
 
 static const JabberScramHash hashes[] = {
-	{ "-SHA-1", purple_sha1_hash_new, 20 },
+	{ "-SHA-1", G_CHECKSUM_SHA1 },
 };
 
 static const JabberScramHash *mech_to_hash(const char *mech)
@@ -80,8 +78,8 @@
 guchar *jabber_scram_hi(const JabberScramHash *hash, const GString *str,
                         GString *salt, guint iterations)
 {
-	PurpleHash *hasher;
-	PurpleCipher *cipher;
+	GHmac *hmac;
+	gsize digest_len;
 	guchar *result;
 	guint i;
 	guchar *prev, *tmp;
@@ -91,40 +89,38 @@
 	g_return_val_if_fail(salt != NULL && salt->len > 0, NULL);
 	g_return_val_if_fail(iterations > 0, NULL);
 
-	prev   = g_new0(guint8, hash->size);
-	tmp    = g_new0(guint8, hash->size);
-	result = g_new0(guint8, hash->size);
+	digest_len = g_checksum_type_get_length(hash->type);
+	prev   = g_new0(guchar, digest_len);
+	tmp    = g_new0(guchar, digest_len);
+	result = g_new0(guchar, digest_len);
 
-	hasher = hash->new_cipher();
-	cipher = purple_hmac_cipher_new(hasher);
-	g_object_unref(G_OBJECT(hasher));
+	hmac = g_hmac_new(hash->type, (guchar *)str->str, str->len);
 
 	/* 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_set_key(cipher, (guchar *)str->str, str->len);
-	purple_cipher_append(cipher, (guchar *)salt->str, salt->len);
-	purple_cipher_digest(cipher, result, hash->size);
+	g_hmac_update(hmac, (guchar *)salt->str, salt->len);
+	g_hmac_get_digest(hmac, result, &digest_len);
+	g_hmac_unref(hmac);
 
-	memcpy(prev, result, hash->size);
+	memcpy(prev, result, digest_len);
 
 	/* Compute U1...Ui */
 	for (i = 1; i < iterations; ++i) {
 		guint j;
-		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);
+		hmac = g_hmac_new(hash->type, (guchar *)str->str, str->len);
+		g_hmac_update(hmac, prev, digest_len);
+		g_hmac_get_digest(hmac, tmp, &digest_len);
+		g_hmac_unref(hmac);
 
-		for (j = 0; j < hash->size; ++j)
+		for (j = 0; j < digest_len; ++j)
 			result[j] ^= tmp[j];
 
-		memcpy(prev, tmp, hash->size);
+		memcpy(prev, tmp, digest_len);
 	}
 
-	g_object_unref(G_OBJECT(cipher));
 	g_free(tmp);
 	g_free(prev);
 	return result;
@@ -142,33 +138,31 @@
 static void
 hmac(const JabberScramHash *hash, guchar *out, const guchar *key, const gchar *str)
 {
-	PurpleHash *hasher;
-	PurpleCipher *cipher;
+	GHmac *hmac;
+	gsize digest_len = g_checksum_type_get_length(hash->type);
 
-	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));
+	hmac = g_hmac_new(hash->type, key, digest_len);
+	g_hmac_update(hmac, (guchar *)str, -1);
+	g_hmac_get_digest(hmac, out, &digest_len);
+	g_hmac_unref(hmac);
 }
 
 static void
 hash(const JabberScramHash *hash, guchar *out, const guchar *data)
 {
-	PurpleHash *hasher;
+	GChecksum *checksum;
+	gsize digest_len = g_checksum_type_get_length(hash->type);
 
-	hasher = hash->new_cipher();
-	purple_hash_append(hasher, data, hash->size);
-	purple_hash_digest(hasher, out, hash->size);
-	g_object_unref(G_OBJECT(hasher));
+	checksum = g_checksum_new(hash->type);
+	g_checksum_update(checksum, data, digest_len);
+	g_checksum_get_digest(checksum, out, &digest_len);
+	g_checksum_free(checksum);
 }
 
 gboolean
 jabber_scram_calc_proofs(JabberScramData *data, GString *salt, guint iterations)
 {
-	guint hash_len = data->hash->size;
+	guint hash_len = g_checksum_type_get_length(data->hash->type);
 	guint i;
 
 	GString *pass = g_string_new(data->password);
@@ -252,7 +246,7 @@
 	if (token[0] != 's' || token[1] != '=')
 		goto err;
 
-	decoded = (gchar *)purple_base64_decode(token + 2, &len);
+	decoded = (gchar *)g_base64_decode(token + 2, &len);
 	if (!decoded || *decoded == '\0') {
 		g_free(decoded);
 		goto err;
@@ -343,7 +337,7 @@
 			return FALSE;
 		}
 
-		proof = purple_base64_encode((guchar *)data->client_proof->str, data->client_proof->len);
+		proof = g_base64_encode((guchar *)data->client_proof->str, data->client_proof->len);
 		*out = g_strdup_printf("c=%s,r=%s,p=%s", "biws", nonce, proof);
 		g_free(nonce);
 		g_free(proof);
@@ -355,7 +349,7 @@
 		if (!ret)
 			return FALSE;
 
-		server_sig = (gchar *)purple_base64_decode(enc_server_sig, &len);
+		server_sig = (gchar *)g_base64_decode(enc_server_sig, &len);
 		g_free(enc_server_sig);
 
 		if (server_sig == NULL || len != data->server_signature->len) {
@@ -427,7 +421,7 @@
 		data->channel_binding = TRUE;
 #endif
 	cnonce = ((guint64)g_random_int() << 32) | g_random_int();
-	data->cnonce = purple_base64_encode((guchar *)&cnonce, sizeof(cnonce));
+	data->cnonce = g_base64_encode((guchar *)&cnonce, sizeof(cnonce));
 
 	data->auth_message = g_string_new(NULL);
 	g_string_printf(data->auth_message, "n=%s,r=%s",
@@ -442,7 +436,7 @@
 
 	/* TODO: Channel binding */
 	dec_out = g_strdup_printf("%c,,%s", 'n', data->auth_message->str);
-	enc_out = purple_base64_encode((guchar *)dec_out, strlen(dec_out));
+	enc_out = g_base64_encode((guchar *)dec_out, strlen(dec_out));
 	purple_debug_misc("jabber", "initial SCRAM message '%s'\n", dec_out);
 
 	purple_xmlnode_insert_data(reply, enc_out, -1);
@@ -473,7 +467,7 @@
 		goto out;
 	}
 
-	dec_in = (gchar *)purple_base64_decode(enc_in, &len);
+	dec_in = (gchar *)g_base64_decode(enc_in, &len);
 	if (!dec_in || len != strlen(dec_in)) {
 		/* Danger afoot; SCRAM shouldn't contain NUL bytes */
 		reply = purple_xmlnode_new("abort");
@@ -500,7 +494,7 @@
 
 	purple_debug_misc("jabber", "decoded response: %s\n", dec_out ? dec_out : "(null)");
 	if (dec_out) {
-		enc_out = purple_base64_encode((guchar *)dec_out, strlen(dec_out));
+		enc_out = g_base64_encode((guchar *)dec_out, strlen(dec_out));
 		purple_xmlnode_insert_data(reply, enc_out, -1);
 	}
 
@@ -546,7 +540,7 @@
 		return JABBER_SASL_STATE_FAIL;
 	}
 
-	dec_in = (gchar *)purple_base64_decode(enc_in, &len);
+	dec_in = (gchar *)g_base64_decode(enc_in, &len);
 	g_free(enc_in);
 	if (!dec_in || len != strlen(dec_in)) {
 		/* Danger afoot; SCRAM shouldn't contain NUL bytes */
--- a/libpurple/protocols/jabber/auth_scram.h	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/auth_scram.h	Mon Jun 05 16:36:29 2017 +0300
@@ -29,15 +29,12 @@
  * DO NOT USE ANYTHING HERE OR YOU WILL BE SENT TO THE PIT OF DESPAIR.
  */
 
-#include "cipher.h"
-
 /* Per-connection state stored between messages.
  * This is stored in js->auth_data_mech.
  */
 typedef struct {
 	const char *mech_substr;
-	PurpleHash *(*new_cipher)(void);
-	guint size;
+	GChecksumType type;
 } JabberScramHash;
 
 typedef struct {
--- a/libpurple/protocols/jabber/buddy.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/buddy.c	Mon Jun 05 16:36:29 2017 +0300
@@ -472,10 +472,10 @@
 		g_free(js->initial_avatar_hash);
 		image = purple_buddy_icons_find_account_icon(purple_connection_get_account(gc));
 		if (image != NULL) {
-			js->initial_avatar_hash = jabber_calculate_data_hash(
+			js->initial_avatar_hash = g_compute_checksum_for_data(
+				G_CHECKSUM_SHA1,
 				purple_image_get_data(image),
-				purple_image_get_data_size(image),
-				"sha1"
+				purple_image_get_data_size(image)
 			);
 			g_object_unref(image);
 		} else {
@@ -528,10 +528,10 @@
 		type = purple_xmlnode_new_child(photo, "TYPE");
 		purple_xmlnode_insert_data(type, "image/png", -1);
 		binval = purple_xmlnode_new_child(photo, "BINVAL");
-		enc = purple_base64_encode(avatar_data, avatar_len);
+		enc = g_base64_encode(avatar_data, avatar_len);
 
-		js->avatar_hash =
-			jabber_calculate_data_hash(avatar_data, avatar_len, "sha1");
+		js->avatar_hash = g_compute_checksum_for_data(G_CHECKSUM_SHA1,
+			avatar_data, avatar_len);
 
 		purple_xmlnode_insert_data(binval, enc, -1);
 		g_free(enc);
@@ -957,11 +957,12 @@
 		gsize size;
 		char *bintext = purple_xmlnode_get_data(binval);
 		if (bintext) {
-			guchar *data = purple_base64_decode(bintext, &size);
+			guchar *data = g_base64_decode(bintext, &size);
 			g_free(bintext);
 
 			if (data) {
-				vcard_hash = jabber_calculate_data_hash(data, size, "sha1");
+				vcard_hash = g_compute_checksum_for_data(
+					G_CHECKSUM_SHA1, data, size);
 				g_free(data);
 			}
 		}
@@ -1200,7 +1201,7 @@
 					guchar *data;
 					gboolean photo = (strcmp(child->name, "PHOTO") == 0);
 
-					data = purple_base64_decode(bintext, &size);
+					data = g_base64_decode(bintext, &size);
 					if (data) {
 						PurpleImage *img;
 						guint img_id;
@@ -1216,7 +1217,7 @@
 
 						purple_notify_user_info_add_pair_html(user_info, (photo ? _("Photo") : _("Logo")), img_text);
 
-						hash = jabber_calculate_data_hash(data, size, "sha1");
+						hash = g_compute_checksum_for_data(G_CHECKSUM_SHA1, data, size);
 						purple_buddy_icons_set_for_user(account, bare_jid, data, size, hash);
 						g_free(hash);
 						g_free(img_text);
--- a/libpurple/protocols/jabber/caps.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/caps.c	Mon Jun 05 16:36:29 2017 +0300
@@ -30,9 +30,6 @@
 #include "util.h"
 #include "xdata.h"
 
-#include "ciphers/md5hash.h"
-#include "ciphers/sha1hash.h"
-
 #define JABBER_CAPS_FILENAME "xmpp-caps.xml"
 
 typedef struct _JabberDataFormField {
@@ -457,19 +454,20 @@
 	/* 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(?).
-		 */
+		GChecksumType hash_type;
+		gboolean supported_hash = TRUE;
+
 		if (g_str_equal(userdata->hash, "sha-1")) {
-			hasher = purple_sha1_hash_new();
+			hash_type = G_CHECKSUM_SHA1;
 		} else if (g_str_equal(userdata->hash, "md5")) {
-			hasher = purple_md5_hash_new();
+			hash_type = G_CHECKSUM_MD5;
+		} else {
+			supported_hash = FALSE;
 		}
-		hash = jabber_caps_calculate_hash(info, hasher);
-		g_object_unref(hasher);
+
+		if (supported_hash) {
+			hash = jabber_caps_calculate_hash(info, hash_type);
+		}
 
 		if (!hash || !g_str_equal(hash, userdata->ver)) {
 			purple_debug_warning("jabber", "Could not validate caps info from "
@@ -818,27 +816,29 @@
 }
 
 static void
-append_escaped_string(PurpleHash *hash, const gchar *str)
+append_escaped_string(GChecksum *hash, const gchar *str)
 {
 	g_return_if_fail(hash != NULL);
 
 	if (str && *str) {
 		char *tmp = g_markup_escape_text(str, -1);
-		purple_hash_append(hash, (const guchar *)tmp, strlen(tmp));
+		g_checksum_update(hash, (const guchar *)tmp, -1);
 		g_free(tmp);
 	}
 
-	purple_hash_append(hash, (const guchar *)"<", 1);
+	g_checksum_update(hash, (const guchar *)"<", -1);
 }
 
-gchar *jabber_caps_calculate_hash(JabberCapsClientInfo *info, PurpleHash *hash)
+gchar *jabber_caps_calculate_hash(JabberCapsClientInfo *info,
+	GChecksumType hash_type)
 {
+	GChecksum *hash;
 	GList *node;
-	guint8 checksum[20];
-	gsize checksum_size = 20;
-	gboolean success;
+	guint8 *checksum;
+	gsize checksum_size;
+	gchar *ret;
 
-	if (!info || !hash)
+	if (!info)
 		return NULL;
 
 	/* sort identities, features and x-data forms */
@@ -846,6 +846,12 @@
 	info->features = g_list_sort(info->features, (GCompareFunc)strcmp);
 	info->forms = g_list_sort(info->forms, jabber_xdata_compare);
 
+	hash = g_checksum_new(hash_type);
+
+	if (hash == NULL) {
+		return NULL;
+	}
+
 	/* Add identities to the hash data */
 	for (node = info->identities; node; node = node->next) {
 		JabberIdentity *id = (JabberIdentity*)node->data;
@@ -863,7 +869,7 @@
 		tmp = g_strconcat(category, "/", type, "/", lang ? lang : "",
 		                  "/", name ? name : "", "<", NULL);
 
-		purple_hash_append(hash, (const guchar *)tmp, strlen(tmp));
+		g_checksum_update(hash, (const guchar *)tmp, -1);
 
 		g_free(tmp);
 		g_free(category);
@@ -912,16 +918,20 @@
 		}
 	}
 
+	checksum_size = g_checksum_type_get_length(hash_type);
+	checksum = g_new(guint8, checksum_size);
+
 	/* generate hash */
-	success = purple_hash_digest(hash, checksum, checksum_size);
-	checksum_size = purple_hash_get_digest_size(hash);
+	g_checksum_get_digest(hash, checksum, &checksum_size);
 
-	return (success ? purple_base64_encode(checksum, checksum_size) : NULL);
+	ret = g_base64_encode(checksum, checksum_size);
+	g_free(checksum);
+
+	return ret;
 }
 
 void jabber_caps_calculate_own_hash(JabberStream *js) {
 	JabberCapsClientInfo info;
-	PurpleHash *hasher;
 	GList *iter = NULL;
 	GList *features = NULL;
 
@@ -952,9 +962,7 @@
 	info.forms = NULL;
 
 	g_free(js->caps_hash);
-	hasher = purple_sha1_hash_new();
-	js->caps_hash = jabber_caps_calculate_hash(&info, hasher);
-	g_object_unref(hasher);
+	js->caps_hash = jabber_caps_calculate_hash(&info, G_CHECKSUM_SHA1);
 	g_list_free(info.identities);
 	g_list_free(info.features);
 }
--- a/libpurple/protocols/jabber/caps.h	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/caps.h	Mon Jun 05 16:36:29 2017 +0300
@@ -27,7 +27,6 @@
 typedef struct _JabberCapsClientInfo JabberCapsClientInfo;
 
 #include "jabber.h"
-#include "cipher.h"
 
 /* Implementation of XEP-0115 - Entity Capabilities */
 
@@ -96,10 +95,11 @@
  *	XEP-0115 Version 1.5.
  *
  *	@param info A JabberCapsClientInfo pointer.
- *	@param hash Hash cipher to be used. Either sha-1 or md5.
+ *	@param hash_type GChecksumType 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, PurpleHash *hash);
+gchar *jabber_caps_calculate_hash(JabberCapsClientInfo *info,
+                                  GChecksumType hash_type);
 
 /**
  *  Calculate SHA1 hash for own featureset.
--- a/libpurple/protocols/jabber/data.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/data.c	Mon Jun 05 16:36:29 2017 +0300
@@ -50,7 +50,7 @@
 	g_return_val_if_fail(type != NULL, NULL);
 
 	data = g_new0(JabberData, 1);
-	checksum = jabber_calculate_data_hash(rawdata, size, "sha1");
+	checksum = g_compute_checksum_for_data(G_CHECKSUM_SHA1, rawdata, size);
 
 	g_snprintf(cid, sizeof(cid), "sha1+%s@bob.xmpp.org", checksum);
 	g_free(checksum);
@@ -109,7 +109,7 @@
 	}
 
 	data = g_new0(JabberData, 1);
-	data->data = purple_base64_decode(raw_data, &data->size);
+	data->data = g_base64_decode(raw_data, &data->size);
 	g_free(raw_data);
 
 	if (data->data == NULL) {
@@ -174,7 +174,7 @@
 	g_return_val_if_fail(data != NULL, NULL);
 
 	tag = purple_xmlnode_new("data");
-	base64data = purple_base64_encode(data->data, data->size);
+	base64data = g_base64_encode(data->data, data->size);
 
 	purple_xmlnode_set_namespace(tag, NS_BOB);
 	purple_xmlnode_set_attrib(tag, "cid", data->cid);
@@ -238,11 +238,25 @@
 		if (num_sub_parts == 2) {
 			const gchar *hash_algo = sub_parts[0];
 			const gchar *hash_value = sub_parts[1];
-			gchar *digest =
-				jabber_calculate_data_hash(jabber_data_get_data(data),
-				    jabber_data_get_size(data), hash_algo);
+			GChecksumType hash_type;
+			gboolean valid_hash_type = TRUE;
 
-			if (digest) {
+			if (purple_strequal(hash_algo, "sha1"))
+				hash_type = G_CHECKSUM_SHA1;
+			else if (purple_strequal(hash_algo, "sha256"))
+				hash_type = G_CHECKSUM_SHA256;
+			else if (purple_strequal(hash_algo, "sha512"))
+				hash_type = G_CHECKSUM_SHA512;
+			else if (purple_strequal(hash_algo, "md5"))
+				hash_type = G_CHECKSUM_MD5;
+			else
+				valid_hash_type = FALSE;
+
+			if (valid_hash_type) {
+				gchar *digest = g_compute_checksum_for_data(
+					hash_type, jabber_data_get_data(data),
+					jabber_data_get_size(data));
+
 				ret = purple_strequal(digest, hash_value);
 
 				if (!ret)
--- a/libpurple/protocols/jabber/ibb.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/ibb.c	Mon Jun 05 16:36:29 2017 +0300
@@ -335,7 +335,7 @@
 		JabberIq *set = jabber_iq_new(jabber_ibb_session_get_js(sess),
 			JABBER_IQ_SET);
 		PurpleXmlNode *data_element = purple_xmlnode_new("data");
-		char *base64 = purple_base64_encode(data, size);
+		char *base64 = g_base64_encode(data, size);
 		char seq[10];
 		g_snprintf(seq, sizeof(seq), "%u", jabber_ibb_session_get_send_seq(sess));
 
@@ -415,7 +415,7 @@
 				if (sess->data_received_cb) {
 					gchar *base64 = purple_xmlnode_get_data(child);
 					gsize size;
-					gpointer rawdata = purple_base64_decode(base64, &size);
+					gpointer rawdata = g_base64_decode(base64, &size);
 
 					g_free(base64);
 
--- a/libpurple/protocols/jabber/jabber.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/jabber.c	Mon Jun 05 16:36:29 2017 +0300
@@ -1135,10 +1135,10 @@
 	 */
 	image = purple_buddy_icons_find_account_icon(account);
 	if (image != NULL) {
-		js->initial_avatar_hash = jabber_calculate_data_hash(
+		js->initial_avatar_hash = g_compute_checksum_for_data(
+			G_CHECKSUM_SHA1,
 			purple_image_get_data(image),
-			purple_image_get_data_size(image),
-			"sha1"
+			purple_image_get_data_size(image)
 		);
 		g_object_unref(image);
 	}
--- a/libpurple/protocols/jabber/jutil.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/jutil.c	Mon Jun 05 16:36:29 2017 +0300
@@ -32,10 +32,6 @@
 #include "presence.h"
 #include "jutil.h"
 
-#include "ciphers/sha1hash.h"
-#include "ciphers/sha256hash.h"
-#include "ciphers/md5hash.h"
-
 #ifdef USE_IDN
 #include <idna.h>
 #include <stringprep.h>
@@ -780,36 +776,3 @@
 	return NULL;
 }
 
-char *
-jabber_calculate_data_hash(gconstpointer data, size_t len,
-    const gchar *hash_algo)
-{
-	PurpleHash *hash = NULL;
-	static gchar digest[129]; /* 512 bits hex + \0 */
-
-	if (g_str_equal(hash_algo, "sha1"))
-		hash = purple_sha1_hash_new();
-	else if (g_str_equal(hash_algo, "sha256"))
-		hash = purple_sha256_hash_new();
-	else if (g_str_equal(hash_algo, "md5"))
-		hash = purple_md5_hash_new();
-
-	if (hash == NULL)
-	{
-		purple_debug_error("jabber", "Unexpected hashing algorithm %s requested\n", hash_algo);
-		g_return_val_if_reached(NULL);
-	}
-
-	/* Hash the data */
-	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);
-	}
-	g_object_unref(G_OBJECT(hash));
-
-	return g_strdup(digest);
-}
-
--- a/libpurple/protocols/jabber/jutil.h	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/jutil.h	Mon Jun 05 16:36:29 2017 +0300
@@ -94,6 +94,4 @@
 /* show attr (presence stanza) -> state */
 JabberBuddyState jabber_buddy_show_get_state(const char *id);
 
-char *jabber_calculate_data_hash(gconstpointer data, size_t len,
-    const gchar *hash_algo);
 #endif /* PURPLE_JABBER_JUTIL_H_ */
--- a/libpurple/protocols/jabber/presence.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/presence.c	Mon Jun 05 16:36:29 2017 +0300
@@ -458,11 +458,12 @@
 
 			if ((binval = purple_xmlnode_get_child(photo, "BINVAL")) &&
 					(text = purple_xmlnode_get_data(binval))) {
-				data = purple_base64_decode(text, &size);
+				data = g_base64_decode(text, &size);
 				g_free(text);
 
 				if (data)
-					hash = jabber_calculate_data_hash(data, size, "sha1");
+					g_compute_checksum_for_data(
+						G_CHECKSUM_SHA1, data, size);
 			}
 
 			purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, data, size, hash);
--- a/libpurple/protocols/jabber/si.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/si.c	Mon Jun 05 16:36:29 2017 +0300
@@ -301,7 +301,8 @@
 				jsx->js->user->node, jsx->js->user->domain, jsx->js->user->resource);
 
 		/* Per XEP-0065, the 'host' must be SHA1(SID + from JID + to JID) */
-		hash = jabber_calculate_data_hash(dstaddr, strlen(dstaddr), "sha1");
+		hash = g_compute_checksum_for_string(G_CHECKSUM_SHA1,
+				dstaddr, -1);
 
 		account = purple_connection_get_account(jsx->js->gc);
 		jsx->connect_data = purple_proxy_connect_socks5_account(NULL, account,
@@ -478,7 +479,7 @@
 			jsx->js->user->resource, purple_xfer_get_remote_user(xfer));
 
 	/* Per XEP-0065, the 'host' must be SHA1(SID + from JID + to JID) */
-	hash = jabber_calculate_data_hash(dstaddr, strlen(dstaddr), "sha1");
+	hash = g_compute_checksum_for_string(G_CHECKSUM_SHA1, dstaddr, -1);
 
 	if(strncmp(hash, jsx->rxqueue + 5, 40) ||
 			jsx->rxqueue[45] != 0x00 || jsx->rxqueue[46] != 0x00) {
--- a/libpurple/protocols/jabber/tests/test_jabber_caps.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/tests/test_jabber_caps.c	Mon Jun 05 16:36:29 2017 +0300
@@ -1,7 +1,6 @@
 #include <glib.h>
 
 #include "xmlnode.h"
-#include "ciphers/sha1hash.h"
 #include "protocols/jabber/caps.h"
 
 static void
@@ -24,13 +23,12 @@
 }
 
 static void
-_test_jabber_caps_match(PurpleHash *hash, const gchar *in, const gchar *expected) {
+_test_jabber_caps_match(GChecksumType hash_type, const gchar *in, const gchar *expected) {
 	PurpleXmlNode *query = purple_xmlnode_from_str(in, -1);
 	JabberCapsClientInfo *info = jabber_caps_parse_client_info(query);
 	gchar *got = NULL;
 
-	got = jabber_caps_calculate_hash(info, hash);
-	g_object_unref(G_OBJECT(hash));
+	got = jabber_caps_calculate_hash(info, hash_type);
 
 	g_assert_cmpstr(expected, ==, got);
 	g_free(got);
@@ -39,7 +37,7 @@
 static void
 test_jabber_caps_calculate_from_xmlnode(void) {
 	_test_jabber_caps_match(
-		purple_sha1_hash_new(),
+		G_CHECKSUM_SHA1,
 		"<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>",
 		"GNjxthSckUNvAIoCCJFttjl6VL8="
 	);
--- a/libpurple/protocols/jabber/tests/test_jabber_scram.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/tests/test_jabber_scram.c	Mon Jun 05 16:36:29 2017 +0300
@@ -4,9 +4,8 @@
 #include "util.h"
 #include "protocols/jabber/auth_scram.h"
 #include "protocols/jabber/jutil.h"
-#include "ciphers/sha1hash.h"
 
-static JabberScramHash sha1_mech = { "-SHA-1", purple_sha1_hash_new, 20 };
+static JabberScramHash sha1_mech = { "-SHA-1", G_CHECKSUM_SHA1 };
 
 #define assert_pbkdf2_equal(password, salt, count, expected) { \
 	GString *p = g_string_new(password); \
--- a/libpurple/protocols/jabber/useravatar.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/jabber/useravatar.c	Mon Jun 05 16:36:29 2017 +0300
@@ -154,10 +154,11 @@
 			char *lengthstring, *widthstring, *heightstring;
 
 			/* compute the sha1 hash */
-			char *hash = jabber_calculate_data_hash(
+			char *hash = g_compute_checksum_for_data(
+				G_CHECKSUM_SHA1,
 				purple_image_get_data(img),
-				purple_image_get_data_size(img), "sha1");
-			char *base64avatar = purple_base64_encode(
+				purple_image_get_data_size(img));
+			char *base64avatar = g_base64_encode(
 				purple_image_get_data(img),
 				purple_image_get_data_size(img));
 
@@ -314,7 +315,7 @@
 	if(!b64data)
 		return;
 
-	img = purple_base64_decode(b64data, &size);
+	img = g_base64_decode(b64data, &size);
 	if(!img) {
 		g_free(b64data);
 		return;
--- a/libpurple/protocols/msn/ft.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,256 +0,0 @@
-/**
- * @file ft.c MSN File Transfer functions
- *
- * 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 "debug.h"
-
-#include "msnutils.h"
-#include "sbconn.h"
-#include "ft.h"
-
-/**************************************************************************
- * Xfer
- **************************************************************************/
-
-void
-msn_xfer_init(PurpleXfer *xfer)
-{
-	MsnSlpCall *slpcall;
-	/* MsnSlpLink *slplink; */
-	char *content;
-
-	purple_debug_info("msn", "xfer_init\n");
-
-	slpcall = purple_xfer_get_protocol_data(xfer);
-
-	/* Send Ok */
-	content = g_strdup_printf("SessionID: %lu\r\n\r\n",
-							  slpcall->session_id);
-
-	msn_slp_send_ok(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody",
-			content);
-
-	g_free(content);
-	msn_slplink_send_queued_slpmsgs(slpcall->slplink);
-}
-
-void
-msn_xfer_cancel(PurpleXfer *xfer)
-{
-	MsnSlpCall *slpcall;
-	char *content;
-
-	g_return_if_fail(xfer != NULL);
-
-	slpcall = purple_xfer_get_protocol_data(xfer);
-	g_return_if_fail(slpcall != NULL);
-
-	if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL)
-	{
-		if (slpcall->started)
-		{
-			msn_slpcall_close(slpcall);
-		}
-		else
-		{
-			content = g_strdup_printf("SessionID: %lu\r\n\r\n",
-									slpcall->session_id);
-
-			msn_slp_send_decline(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody",
-						content);
-
-			g_free(content);
-			msn_slplink_send_queued_slpmsgs(slpcall->slplink);
-
-			if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_SEND)
-				slpcall->wasted = TRUE;
-			else
-				msn_slpcall_destroy(slpcall);
-		}
-	}
-}
-
-gssize
-msn_xfer_write(const guchar *data, gsize len, PurpleXfer *xfer)
-{
-	MsnSlpCall *slpcall;
-
-	g_return_val_if_fail(xfer != NULL, -1);
-	g_return_val_if_fail(data != NULL, -1);
-	g_return_val_if_fail(len > 0, -1);
-
-	g_return_val_if_fail(purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_SEND, -1);
-
-	slpcall = purple_xfer_get_protocol_data(xfer);
-	/* Not sure I trust it'll be there */
-	g_return_val_if_fail(slpcall != NULL, -1);
-
-	g_return_val_if_fail(slpcall->xfer_msg != NULL, -1);
-
-	slpcall->u.outgoing.len = len;
-	slpcall->u.outgoing.data = data;
-	msn_slplink_send_msgpart(slpcall->slplink, slpcall->xfer_msg);
-
-	return MIN(MSN_SBCONN_MAX_SIZE, len);
-}
-
-gssize
-msn_xfer_read(guchar **data, gsize size, PurpleXfer *xfer)
-{
-	MsnSlpCall *slpcall;
-	gsize len;
-
-	g_return_val_if_fail(xfer != NULL, -1);
-	g_return_val_if_fail(data != NULL, -1);
-
-	g_return_val_if_fail(purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE, -1);
-
-	slpcall = purple_xfer_get_protocol_data(xfer);
-	/* Not sure I trust it'll be there */
-	g_return_val_if_fail(slpcall != NULL, -1);
-
-	/* Just pass up the whole GByteArray. We'll make another. */
-	*data = slpcall->u.incoming_data->data;
-	len = slpcall->u.incoming_data->len;
-
-	g_byte_array_free(slpcall->u.incoming_data, FALSE);
-	slpcall->u.incoming_data = g_byte_array_new();
-
-	return len;
-}
-
-void
-msn_xfer_end_cb(MsnSlpCall *slpcall, MsnSession *session)
-{
-	if ((purple_xfer_get_status(slpcall->xfer) != PURPLE_XFER_STATUS_DONE) &&
-		(purple_xfer_get_status(slpcall->xfer) != PURPLE_XFER_STATUS_CANCEL_REMOTE) &&
-		(purple_xfer_get_status(slpcall->xfer) != PURPLE_XFER_STATUS_CANCEL_LOCAL))
-	{
-		purple_xfer_cancel_remote(slpcall->xfer);
-	}
-}
-
-void
-msn_xfer_completed_cb(MsnSlpCall *slpcall, const guchar *body,
-					  gsize size)
-{
-	PurpleXfer *xfer = slpcall->xfer;
-
-	purple_xfer_set_completed(xfer, TRUE);
-	purple_xfer_end(xfer);
-}
-
-gchar *
-msn_file_context_to_wire(MsnFileContext *context)
-{
-	gchar *ret, *tmp;
-
-	tmp = ret = g_new(gchar, MSN_FILE_CONTEXT_SIZE_V2 + context->preview_len + 1);
-
-	msn_push32le(tmp, context->length);
-	msn_push32le(tmp, context->version);
-	msn_push64le(tmp, context->file_size);
-	msn_push32le(tmp, context->type);
-	memcpy(tmp, context->file_name, MAX_FILE_NAME_LEN * 2);
-	tmp += MAX_FILE_NAME_LEN * 2;
-#if 0
-	memcpy(tmp, context->unknown1, sizeof(context->unknown1));
-	tmp += sizeof(context->unknown1);
-	msn_push32le(tmp, context->unknown2);
-#else
-	memset(tmp, 0, sizeof(gchar[30]));
-	tmp += sizeof(gchar[30]);
-	msn_push32le(tmp, 0xffffffff);
-#endif
-	if (context->preview) {
-		memcpy(tmp, context->preview, context->preview_len);
-	}
-	tmp[context->preview_len] = '\0';
-
-	return ret;
-}
-
-MsnFileContext *
-msn_file_context_from_wire(const char *buf, gsize len)
-{
-	MsnFileContext *context;
-
-	if (!buf || len < MSN_FILE_CONTEXT_SIZE_V0)
-		return NULL;
-
-	context = g_new(MsnFileContext, 1);
-
-	context->length = msn_pop32le(buf);
-	context->version = msn_pop32le(buf);
-	if (context->version == 0) {
-		if (context->length != MSN_FILE_CONTEXT_SIZE_V0) {
-			g_free(context);
-			return NULL;
-		}
-	} else if (context->version == 2) {
-		/* The length field is broken for this version. No check. */
-		context->length = MSN_FILE_CONTEXT_SIZE_V2;
-		if (len < MSN_FILE_CONTEXT_SIZE_V2) {
-			g_free(context);
-			return NULL;
-		}
-	} else if (context->version == 3) {
-		if (context->length != MSN_FILE_CONTEXT_SIZE_V3) {
-			g_free(context);
-			return NULL;
-		} else if (len < MSN_FILE_CONTEXT_SIZE_V3) {
-			g_free(context);
-			return NULL;
-		}
-	} else {
-		purple_debug_warning("msn", "Received MsnFileContext with unknown version: %d\n", context->version);
-		g_free(context);
-		return NULL;
-	}
-
-	context->file_size = msn_pop64le(buf);
-	context->type = msn_pop32le(buf);
-	memcpy(context->file_name, buf, MAX_FILE_NAME_LEN * 2);
-	buf += MAX_FILE_NAME_LEN * 2;
-	if (context->version > 0) {
-#if 0
-		memcpy(context->unknown1, buf, sizeof(context->unknown1));
-		buf += sizeof(context->unknown1);
-		context->unknown2 = msn_pop32le(buf);
-#else
-		buf += sizeof(gchar[30]) + sizeof(guint32);
-#endif
-	}
-
-	if (context->type == 0 && len > context->length) {
-		context->preview_len = len - context->length;
-		context->preview = g_memdup(buf, context->preview_len);
-	} else {
-		context->preview_len = 0;
-		context->preview = NULL;
-	}
-
-	return context;
-}
-
--- a/libpurple/protocols/msn/ft.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/**
- * @file ft.h MSN File Transfer functions
- *
- * 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 MSN_FT_H
-#define MSN_FT_H
-
-#include "slpcall.h"
-
-#define MAX_FILE_NAME_LEN 260 /* MAX_PATH in Windows */
-
-/**
- * The context data for a file transfer request
- */
-typedef struct
-{
-	guint32   length;       /*< Length of header */
-	guint32   version;      /*< MSN version */
-	guint64   file_size;    /*< Size of file */
-	guint32   type;         /*< Transfer type */
-	gunichar2 file_name[MAX_FILE_NAME_LEN]; /*< Self-explanatory */
-#if 0
-	gchar     unknown1[30]; /*< Used somehow for background sharing */
-	guint32   unknown2;     /*< Possibly for background sharing as well */
-#endif
-	gchar     *preview;     /*< File preview data, 96x96 PNG */
-	gsize     preview_len;
-} MsnFileContext;
-
-#define MSN_FILE_CONTEXT_SIZE_V0 (4*3 + 1*8 + 2*MAX_FILE_NAME_LEN)
-#define MSN_FILE_CONTEXT_SIZE_V2 (MSN_FILE_CONTEXT_SIZE_V0 + 4*1 + 30)
-#define MSN_FILE_CONTEXT_SIZE_V3 (MSN_FILE_CONTEXT_SIZE_V2 + 63)
-
-void msn_xfer_init(PurpleXfer *xfer);
-void msn_xfer_cancel(PurpleXfer *xfer);
-
-gssize msn_xfer_write(const guchar *data, gsize len, PurpleXfer *xfer);
-gssize msn_xfer_read(guchar **data, gsize size, PurpleXfer *xfer);
-
-void msn_xfer_completed_cb(MsnSlpCall *slpcall,
-						   const guchar *body, gsize size);
-void msn_xfer_end_cb(MsnSlpCall *slpcall, MsnSession *session);
-
-gchar *
-msn_file_context_to_wire(MsnFileContext *context);
-
-MsnFileContext *
-msn_file_context_from_wire(const char *buf, gsize len);
-
-#endif /* MSN_FT_H */
-
--- a/libpurple/protocols/mxit/cipher-mxit.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +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 "cipher-mxit.h"
-
-#include "cipher.h"
-#include "ciphers/aescipher.h"
-#include "debug.h"
-#include "internal.h"
-
-#define INITIAL_KEY "6170383452343567"
-#define SECRET_HEADER "<mxit/>"
-
-/**
- * Encrypt the user's cleartext password using the AES 128-bit (ECB)
- * encryption algorithm.
- *
- * @param session The MXit session object
- *
- * @return The encrypted & encoded password. Must be g_free'd when
- *         no longer needed.
- */
-gchar *
-mxit_encrypt_password(struct MXitSession* session)
-{
-	guchar key[16];
-	size_t clientkey_len, header_len, pass_len, plaintext_len;
-	const gchar *plaintext_passwd;
-	guchar *plaintext;
-	guchar encrypted[64]; /* shouldn't be longer than 17 */
-	PurpleCipher *cipher;
-	ssize_t encrypted_size;
-
-	purple_debug_info(MXIT_PLUGIN_ID, "mxit_encrypt_password");
-
-	/* build the AES encryption key */
-	g_assert(strlen(INITIAL_KEY) == sizeof(key));
-	memcpy(key, INITIAL_KEY, sizeof(key));
-	clientkey_len = strlen(session->clientkey);
-	if (clientkey_len > sizeof(key))
-		clientkey_len = sizeof(key);
-	memcpy(key, session->clientkey, clientkey_len);
-
-	/* build the secret data to be encrypted: SECRET_HEADER + password */
-	plaintext_passwd = purple_connection_get_password(session->con);
-	g_return_val_if_fail(plaintext_passwd, NULL);
-	pass_len = strlen(plaintext_passwd);
-	header_len = strlen(SECRET_HEADER);
-	/* Trailing NUL, just to be safe. But PKCS#7 seems to be enough. */
-	plaintext_len = header_len + pass_len + 1;
-	plaintext = g_new0(guchar, plaintext_len);
-	memcpy(plaintext, SECRET_HEADER, header_len);
-	memcpy(plaintext + header_len, plaintext_passwd, pass_len);
-
-	/* encrypt */
-	cipher = purple_aes_cipher_new();
-	purple_cipher_set_key(cipher, key, sizeof(key));
-	purple_cipher_set_batch_mode(cipher, PURPLE_CIPHER_BATCH_MODE_ECB);
-	encrypted_size = purple_cipher_encrypt(cipher,
-		plaintext, plaintext_len, encrypted, sizeof(encrypted));
-	g_return_val_if_fail(encrypted_size > 0, NULL);
-
-	return purple_base64_encode(encrypted, encrypted_size);
-}
--- a/libpurple/protocols/mxit/cipher-mxit.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- */
-
-#ifndef _MXIT_CIPHER_H_
-#define _MXIT_CIPHER_H_
-
-#include "mxit.h"
-
-gchar *
-mxit_encrypt_password(struct MXitSession* session);
-
-#endif /* _MXIT_CIPHER_H_ */
--- a/libpurple/protocols/mxit/client.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2968 +0,0 @@
-/*
- *					MXit Protocol libPurple Plugin
- *
- *			-- MXit client protocol implementation --
- *
- *				Pieter Loubser	<libpurple@mxit.com>
- *
- *			(C) Copyright 2009	MXit Lifestyle (Pty) Ltd.
- *				<http://www.mxitlifestyle.com>
- *
- * 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	"debug.h"
-#include	"version.h"
-
-#include	"client.h"
-#include	"mxit.h"
-#include	"roster.h"
-#include	"chunk.h"
-#include	"filexfer.h"
-#include	"markup.h"
-#include	"multimx.h"
-#include	"splashscreen.h"
-#include	"login.h"
-#include	"formcmds.h"
-#include	"http.h"
-#include	"cipher.h"
-
-
-#define		MXIT_MS_OFFSET		3
-
-/* configure the right record terminator char to use */
-#define		CP_REC_TERM			( ( session->http ) ? CP_HTTP_REC_TERM : CP_SOCK_REC_TERM )
-
-
-/*------------------------------------------------------------------------
- * return the current timestamp in milliseconds
- */
-gint64 mxit_now_milli( void )
-{
-	GTimeVal	now;
-
-	g_get_current_time( &now );
-
-	return ( ( now.tv_sec * 1000 ) + ( now.tv_usec / 1000 ) );
-}
-
-
-/*------------------------------------------------------------------------
- * Display a notification popup message to the user.
- *
- *  @param type			The type of notification:
- *		- info:		PURPLE_NOTIFY_MSG_INFO
- *		- warning:	PURPLE_NOTIFY_MSG_WARNING
- *		- error:	PURPLE_NOTIFY_MSG_ERROR
- *  @param heading		Heading text
- *  @param message		Message text
- */
-void mxit_popup( int type, const char* heading, const char* message )
-{
-	/* (reference: "libpurple/notify.h") */
-	purple_notify_message( NULL, type, _( MXIT_POPUP_WIN_NAME ), heading, message, NULL, NULL, NULL );
-}
-
-
-/*------------------------------------------------------------------------
- * For compatibility with legacy clients, all usernames are sent from MXit with a domain
- *  appended.  For MXit contacts, this domain is set to "@m".  This function strips
- *  those fake domains.
- *
- *  @param username		The username of the contact
- */
-void mxit_strip_domain( char* username )
-{
-	if ( g_str_has_suffix( username, "@m" ) )
-		username[ strlen( username ) - 2 ] = '\0';
-}
-
-
-/*------------------------------------------------------------------------
- * Dump a byte buffer to the console for debugging purposes.
- *
- *  @param buf			The data
- *  @param len			The data length
- */
-void dump_bytes( struct MXitSession* session, const char* buf, int len )
-{
-	char*	msg	= g_malloc0( len + 1 );
-	int		i;
-
-	for ( i = 0; i < len; i++ ) {
-		char ch	= buf[i];
-
-		if ( ch == CP_REC_TERM )		/* record terminator */
-			msg[i] = '!';
-		else if ( ch == CP_FLD_TERM )	/* field terminator */
-			msg[i] = '^';
-		else if ( ch == CP_PKT_TERM )	/* packet terminator */
-			msg[i] = '@';
-		else if ( ( ch < 0x20 ) || ( ch > 0x7E ) )		/* non-printable character */
-			msg[i] = '_';
-		else
-			msg[i] = ch;
-	}
-
-	purple_debug_info( MXIT_PLUGIN_ID, "DUMP: '%s'\n", msg );
-
-	g_free( msg );
-}
-
-
-/*------------------------------------------------------------------------
- * Determine if we have an active chat with a specific contact
- *
- *  @param session		The MXit session object
- *  @param who			The contact name
- *  @return				Return true if we have an active chat with the contact
- */
-gboolean find_active_chat( const GList* chats, const char* who )
-{
-	const GList*	list	= chats;
-	const char*		chat	= NULL;
-
-	while ( list ) {
-		chat = (const char*) list->data;
-
-		if ( strcmp( chat, who ) == 0 )
-			return TRUE;
-
-		list = g_list_next( list );
-	}
-
-	return FALSE;
-}
-
-
-/*------------------------------------------------------------------------
- * scnprintf
- *
- *	@param string		The destination buffer.
- *	@param size			The maximum size of the destination buffer.
- * 	@param format		The format string
- *	@param ...			The parameters to the format string.
- *	@return				The number of characters actually stored in the buffer.
- */
-static int scnprintf( gchar* string, size_t size, const char *format, ... )
-{
-	va_list args;
-	guint i;
-
-	va_start( args, format );
-	i = g_vsnprintf( string, size, format, args );
-	va_end( args );
-
-	if ( i < size )
-		return i;
-	else if ( size > 0 )		/* destination buffer too short - return number of characters actually inserted */
-		return size - 1;
-	else
-		return 0;
-}
-
-
-
-/*========================================================================================================================
- * Low-level Packet transmission
- */
-
-/*------------------------------------------------------------------------
- * Remove next packet from transmission queue.
- *
- *  @param session		The MXit session object
- *  @return				The next packet for transmission (or NULL)
- */
-static struct tx_packet* pop_tx_packet( struct MXitSession* session )
-{
-	struct tx_packet*	packet	= NULL;
-
-	if ( session->queue.count > 0 ) {
-		/* dequeue the next packet */
-		packet = session->queue.packets[session->queue.rd_i];
-		session->queue.packets[session->queue.rd_i] = NULL;
-		session->queue.rd_i = ( session->queue.rd_i + 1 ) % MAX_QUEUE_SIZE;
-		session->queue.count--;
-	}
-
-	return packet;
-}
-
-
-/*------------------------------------------------------------------------
- * Add packet to transmission queue.
- *
- *  @param session		The MXit session object
- *  @param packet		The packet to transmit
- *  @return				Return TRUE if packet was enqueue, or FALSE if queue is full.
- */
-static gboolean push_tx_packet( struct MXitSession* session, struct tx_packet* packet )
-{
-	if ( session->queue.count < MAX_QUEUE_SIZE ) {
-		/* enqueue packet */
-		session->queue.packets[session->queue.wr_i] = packet;
-		session->queue.wr_i = ( session->queue.wr_i + 1 ) % MAX_QUEUE_SIZE;
-		session->queue.count++;
-		return TRUE;
-	}
-	else
-		return FALSE;		/* queue is full */
-}
-
-
-/*------------------------------------------------------------------------
- * Deallocate transmission packet.
- *
- *  @param packet		The packet to deallocate.
- */
-static void free_tx_packet( struct tx_packet* packet )
-{
-	g_free( packet->data );
-	g_free( packet );
-	packet = NULL;
-}
-
-
-/*------------------------------------------------------------------------
- * Flush all the packets from the tx queue and release the resources.
- *
- *  @param session		The MXit session object
- */
-static void flush_queue( struct MXitSession* session )
-{
-	struct tx_packet*	packet;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "flushing the tx queue\n" );
-
-	while ( (packet = pop_tx_packet( session ) ) != NULL )
-		free_tx_packet( packet );
-}
-
-
-/*------------------------------------------------------------------------
- * TX Step 3: Write the packet data to the TCP connection.
- *
- *  @param fd			The file descriptor
- *  @param pktdata		The packet data
- *  @param pktlen		The length of the packet data
- *  @return				Return -1 on error, otherwise 0
- */
-static int mxit_write_sock_packet( int fd, const char* pktdata, int pktlen )
-{
-	int		written;
-	int		res;
-
-	written = 0;
-	while ( written < pktlen ) {
-		res = write( fd, &pktdata[written], pktlen - written );
-		if ( res <= 0 ) {
-			/* error on socket */
-			if ( errno == EAGAIN )
-				continue;
-
-			purple_debug_error( MXIT_PLUGIN_ID, "Error while writing packet to MXit server (%i)\n", res );
-			return -1;
-		}
-		written += res;
-	}
-
-	return 0;
-}
-
-
-/**
- * Callback called for handling a HTTP GET response
- *
- * @param http_conn http api object (see http.h)
- * @param response  http api object (see http.h)
- * @param _session  The MXit session object
- */
-static void
-mxit_cb_http_rx(PurpleHttpConnection *http_conn, PurpleHttpResponse *response,
-	gpointer _session)
-{
-	struct MXitSession *session = _session;
-	const gchar *got_data;
-	size_t got_len;
-
-	if (!purple_http_response_is_successful(response)) {
-		purple_debug_error(MXIT_PLUGIN_ID, "HTTP response error (%s)\n",
-			purple_http_response_get_error(response));
-		return;
-	}
-
-	/* convert the HTTP result */
-	got_data = purple_http_response_get_data(response, &got_len);
-	memcpy(session->rx_dbuf, got_data, got_len);
-	session->rx_i = got_len;
-
-	mxit_parse_packet(session);
-}
-
-
-/**
- * TX Step 3: Write the packet data to the HTTP connection (GET style).
- *
- * @param session The MXit session object
- * @param packet  The packet data
- */
-static void
-mxit_write_http_get(struct MXitSession* session, struct tx_packet* packet)
-{
-	PurpleHttpRequest *req;
-	char *part = NULL;
-
-	if (packet->datalen > 0) {
-		char *tmp;
-
-		tmp = g_strndup(packet->data, packet->datalen);
-		part = g_strdup(purple_url_encode(tmp));
-		g_free(tmp);
-	}
-
-	req = purple_http_request_new(NULL);
-	purple_http_request_set_url_printf(req, "%s?%s%s", session->http_server,
-		purple_url_encode(packet->header), part ? part : "");
-	purple_http_request_header_set(req, "User-Agent", MXIT_HTTP_USERAGENT);
-	purple_http_connection_set_add(session->async_http_reqs,
-		purple_http_request(session->con, req, mxit_cb_http_rx,
-			session));
-	purple_http_request_unref(req);
-
-	g_free(part);
-}
-
-
-/**
- * TX Step 3: Write the packet data to the HTTP connection (POST style).
- *
- * @param session The MXit session object
- * @param packet  The packet data
- */
-static void
-mxit_write_http_post(struct MXitSession* session, struct tx_packet* packet)
-{
-	PurpleHttpRequest *req;
-
-	/* strip off the last '&' from the header */
-	packet->header[packet->headerlen - 1] = '\0';
-	packet->headerlen--;
-
-	req = purple_http_request_new(NULL);
-	purple_http_request_set_url_printf(req, "%s?%s", session->http_server,
-		purple_url_encode(packet->header));
-	purple_http_request_set_method(req, "POST");
-	purple_http_request_header_set(req, "User-Agent", MXIT_HTTP_USERAGENT);
-	purple_http_request_header_set(req, "Content-Type",
-		"application/octet-stream");
-	purple_http_request_set_contents(req, packet->data + MXIT_MS_OFFSET,
-		packet->datalen - MXIT_MS_OFFSET);
-	purple_http_connection_set_add(session->async_http_reqs,
-		purple_http_request(session->con, req, mxit_cb_http_rx,
-			session));
-	purple_http_request_unref(req);
-}
-
-
-/*------------------------------------------------------------------------
- * TX Step 2: Handle the transmission of the packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param packet		The packet to transmit
- */
-static void mxit_send_packet( struct MXitSession* session, struct tx_packet* packet )
-{
-	int		res;
-
-	if ( !( session->flags & MXIT_FLAG_CONNECTED ) ) {
-		/* we are not connected so ignore all packets to be send */
-		purple_debug_error( MXIT_PLUGIN_ID, "Dropping TX packet (we are not connected)\n" );
-		return;
-	}
-
-	purple_debug_info( MXIT_PLUGIN_ID, "Packet send CMD:%i (%i)\n", packet->cmd, packet->headerlen + packet->datalen );
-#ifdef	DEBUG_PROTOCOL
-	dump_bytes( session, packet->header, packet->headerlen );
-	dump_bytes( session, packet->data, packet->datalen );
-#endif
-
-	if ( !session->http ) {
-		/* socket connection */
-		char		data[packet->datalen + packet->headerlen];
-		int			datalen;
-
-		/* create raw data buffer */
-		memcpy( data, packet->header, packet->headerlen );
-		memcpy( data + packet->headerlen, packet->data, packet->datalen );
-		datalen = packet->headerlen + packet->datalen;
-
-		res = mxit_write_sock_packet( session->fd, data, datalen );
-		if ( res < 0 ) {
-			/* we must have lost the connection, so terminate it so that we can reconnect */
-			purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "We have lost the connection to MXit. Please reconnect." ) );
-		}
-	}
-	else {
-		/* http connection */
-
-		if ( packet->cmd == CP_CMD_MEDIA ) {
-			/* multimedia packets must be send with a HTTP POST */
-			mxit_write_http_post( session, packet );
-		}
-		else {
-			mxit_write_http_get( session, packet );
-		}
-	}
-
-	/* update the timestamp of the last-transmitted packet */
-	session->last_tx = mxit_now_milli();
-
-	/*
-	 * we need to remember that we are still waiting for the ACK from
-	 * the server on this request
-	 */
-	session->outack = packet->cmd;
-
-	/* free up the packet resources */
-	free_tx_packet( packet );
-}
-
-
-/*------------------------------------------------------------------------
- * TX Step 1: Create a new Tx packet and queue it for sending.
- *
- *  @param session		The MXit session object
- *  @param data			The packet data (payload)
- *  @param datalen		The length of the packet data
- *  @param cmd			The MXit command for this packet
- */
-static void mxit_queue_packet( struct MXitSession* session, const char* data, int datalen, int cmd )
-{
-	struct tx_packet*	packet;
-	char				header[256];
-	int					hlen;
-
-	/* create a packet for sending */
-	packet = g_new0( struct tx_packet, 1 );
-	packet->data = g_malloc0( datalen );
-	packet->cmd = cmd;
-	packet->headerlen = 0;
-
-	/* create generic packet header */
-	hlen = scnprintf( header, sizeof( header ), "id=%s%c", purple_account_get_username( session->acc ), CP_REC_TERM );	/* client mxitid */
-
-	if ( session->http ) {
-		/* http connection only */
-		hlen += scnprintf( header + hlen, sizeof( header ) - hlen, "s=" );
-		if ( session->http_sesid > 0 ) {
-			hlen += scnprintf( header + hlen, sizeof( header ) - hlen, "%u%c", session->http_sesid, CP_FLD_TERM );	/* http session id */
-		}
-		session->http_seqno++;
-		hlen += scnprintf( header + hlen, sizeof( header ) - hlen, "%u%c", session->http_seqno, CP_REC_TERM );		/* http request sequence id */
-	}
-
-	hlen += scnprintf( header + hlen, sizeof( header ) - hlen, "cm=%i%c", cmd, CP_REC_TERM ); 						/* packet command */
-
-	if ( !session->http ) {
-		/* socket connection only */
-		packet->headerlen = scnprintf( packet->header, sizeof( packet->header ), "ln=%i%c", ( datalen + hlen ), CP_REC_TERM );		/* packet length */
-	}
-
-	/* copy the header to packet */
-	memcpy( packet->header + packet->headerlen, header, hlen );
-	packet->headerlen += hlen;
-
-	/* copy payload to packet */
-	if ( datalen > 0 )
-		memcpy( packet->data, data, datalen );
-	packet->datalen = datalen;
-
-
-	/* shortcut */
-	if ( ( session->queue.count == 0 ) && ( session->outack == 0 ) ) {
-		/* the queue is empty and there are no outstanding acks so we can write it directly */
-		mxit_send_packet( session, packet );
-	}
-	else {
-		/* we need to queue this packet */
-
-		if ( ( packet->cmd == CP_CMD_PING ) || ( packet->cmd == CP_CMD_POLL ) ) {
-			/* we do NOT queue HTTP poll nor socket ping packets */
-			free_tx_packet( packet );
-			return;
-		}
-
-		purple_debug_info( MXIT_PLUGIN_ID, "queueing packet for later sending cmd=%i\n", cmd );
-		if ( !push_tx_packet( session, packet ) ) {
-			/* packet could not be queued for transmission */
-			mxit_popup( PURPLE_NOTIFY_MSG_ERROR, _( "Message Send Error" ), _( "Unable to process your request at this time" ) );
-			free_tx_packet( packet );
-		}
-	}
-}
-
-
-/*------------------------------------------------------------------------
- * Manage the packet send queue (send next packet, timeout's, etc).
- *
- *  @param session		The MXit session object
- */
-static void mxit_manage_queue( struct MXitSession* session )
-{
-	struct tx_packet*	packet		= NULL;
-	gint64				now			= mxit_now_milli();
-
-	if ( !( session->flags & MXIT_FLAG_CONNECTED ) ) {
-		/* we are not connected, so ignore the queue */
-		return;
-	}
-	else if ( session->outack > 0 ) {
-		/* we are still waiting for an outstanding ACK from the MXit server */
-		if ( session->last_tx <= mxit_now_milli() - ( MXIT_ACK_TIMEOUT * 1000 ) ) {
-			/* ack timeout! so we close the connection here */
-			purple_debug_info( MXIT_PLUGIN_ID, "mxit_manage_queue: Timeout awaiting ACK for command '%i'\n", session->outack );
-			purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "Timeout while waiting for a response from the MXit server." ) );
-		}
-		return;
-	}
-
-	/*
-	 * the mxit server has flood detection and it prevents you from sending messages to fast.
-	 * this is a self defense mechanism, a very annoying feature. so the client must ensure that
-	 * it does not send messages too fast otherwise mxit will ignore the user for 30 seconds.
-	 * this is what we are trying to avoid here..
-	 */
-	if ( session->q_fast_timer_id == 0 ) {
-		/* the fast timer has not been set yet */
-		if ( session->last_tx > ( now - MXIT_TX_DELAY ) ) {
-			/* we need to wait a little before sending the next packet, so schedule a wakeup call */
-			gint64 tdiff = now - ( session->last_tx );
-			guint delay = ( MXIT_TX_DELAY - tdiff ) + 9;
-			if ( delay <= 0 )
-				delay = MXIT_TX_DELAY;
-			session->q_fast_timer_id = purple_timeout_add( delay, mxit_manage_queue_fast, session );
-		}
-		else {
-			/* get the next packet from the queue to send */
-			packet = pop_tx_packet( session );
-			if ( packet != NULL ) {
-				/* there was a packet waiting to be sent to the server, now is the time to do something about it */
-
-				/* send the packet to MXit server */
-				mxit_send_packet( session, packet );
-			}
-		}
-	}
-}
-
-
-/*------------------------------------------------------------------------
- * Slow callback to manage the packet send queue.
- *
- *  @param session		The MXit session object
- */
-gboolean mxit_manage_queue_slow( gpointer user_data )
-{
-	struct MXitSession* session		= (struct MXitSession*) user_data;
-
-	mxit_manage_queue( session );
-
-	/* continue running */
-	return TRUE;
-}
-
-
-/*------------------------------------------------------------------------
- * Fast callback to manage the packet send queue.
- *
- *  @param session		The MXit session object
- */
-gboolean mxit_manage_queue_fast( gpointer user_data )
-{
-	struct MXitSession* session		= (struct MXitSession*) user_data;
-
-	session->q_fast_timer_id = 0;
-	mxit_manage_queue( session );
-
-	/* stop running */
-	return FALSE;
-}
-
-
-/*------------------------------------------------------------------------
- * Callback to manage HTTP server polling (HTTP connections ONLY)
- *
- *  @param session		The MXit session object
- */
-gboolean mxit_manage_polling( gpointer user_data )
-{
-	struct MXitSession* session		= (struct MXitSession*) user_data;
-	gboolean			poll		= FALSE;
-	gint64				now			= mxit_now_milli();
-	gint64				rxdiff;
-
-	if ( !( session->flags & MXIT_FLAG_LOGGEDIN ) ) {
-		/* we only poll if we are actually logged in */
-		return TRUE;
-	}
-
-	/* calculate the time differences */
-	rxdiff = now - session->last_rx;
-
-	if ( rxdiff < MXIT_HTTP_POLL_MIN ) {
-		/* we received some reply a few moments ago, so reset the poll interval */
-		session->http_interval = MXIT_HTTP_POLL_MIN;
-	}
-	else if ( session->http_last_poll < ( now - session->http_interval ) ) {
-		/* time to poll again */
-		poll = TRUE;
-
-		/* back-off some more with the polling */
-		session->http_interval = session->http_interval + ( session->http_interval / 2 );
-		if ( session->http_interval > MXIT_HTTP_POLL_MAX )
-			session->http_interval = MXIT_HTTP_POLL_MAX;
-	}
-
-	/* debugging */
-	//purple_debug_info( MXIT_PLUGIN_ID, "POLL TIMER: %i (%i)\n", session->http_interval, rxdiff );
-
-	if ( poll ) {
-		/* send poll request */
-		session->http_last_poll = mxit_now_milli();
-		mxit_send_poll( session );
-	}
-
-	return TRUE;
-}
-
-
-/*========================================================================================================================
- * Send MXit operations.
- */
-
-/*------------------------------------------------------------------------
- * Send a ping/keepalive packet to MXit server.
- *
- *  @param session		The MXit session object
- */
-void mxit_send_ping( struct MXitSession* session )
-{
-	/* queue packet for transmission */
-	mxit_queue_packet( session, NULL, 0, CP_CMD_PING );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a poll request to the HTTP server (HTTP connections ONLY).
- *
- *  @param session		The MXit session object
- */
-void mxit_send_poll( struct MXitSession* session )
-{
-	/* queue packet for transmission */
-	mxit_queue_packet( session, NULL, 0, CP_CMD_POLL );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a logout packet to the MXit server.
- *
- *  @param session		The MXit session object
- */
-void mxit_send_logout( struct MXitSession* session )
-{
-	/* queue packet for transmission */
-	mxit_queue_packet( session, NULL, 0, CP_CMD_LOGOUT );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a register packet to the MXit server.
- *
- *  @param session		The MXit session object
- */
-void mxit_send_register( struct MXitSession* session )
-{
-	struct MXitProfile*	profile		= session->profile;
-	const char*			locale;
-	char				data[CP_MAX_PACKET];
-	int					datalen;
-	char*				clientVersion;
-	unsigned int		features	= MXIT_CP_FEATURES;
-
-	locale = purple_account_get_string( session->acc, MXIT_CONFIG_LOCALE, MXIT_DEFAULT_LOCALE );
-
-	/* generate client version string (eg, P-2.7.10-Y-PURPLE) */
-	clientVersion = g_strdup_printf( "%c-%i.%i.%i-%s-%s", MXIT_CP_DISTCODE, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CP_ARCH, MXIT_CP_PLATFORM );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%s%c%i%c%s%c"		/* "ms"=password\1version\1maxreplyLen\1name\1 */
-								"%s%c%i%c%s%c%s%c"			/* dateOfBirth\1gender\1location\1capabilities\1 */
-								"%s%c%i%c%s%c%s"			/* dc\1features\1dialingcode\1locale */
-								"%c%i%c%i",					/* \1protocolVer\1lastRosterUpdate */
-								session->encpwd, CP_FLD_TERM, clientVersion, CP_FLD_TERM, CP_MAX_FILESIZE, CP_FLD_TERM, profile->nickname, CP_FLD_TERM,
-								profile->birthday, CP_FLD_TERM, ( profile->male ) ? 1 : 0, CP_FLD_TERM, MXIT_DEFAULT_LOC, CP_FLD_TERM, MXIT_CP_CAP, CP_FLD_TERM,
-								session->distcode, CP_FLD_TERM, features, CP_FLD_TERM, session->dialcode, CP_FLD_TERM, locale,
-								CP_FLD_TERM, MXIT_CP_PROTO_VESION, CP_FLD_TERM, 0
-	);
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_REGISTER );
-
-	g_free( clientVersion );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a login packet to the MXit server.
- *
- *  @param session		The MXit session object
- */
-void mxit_send_login( struct MXitSession* session )
-{
-	const char*		splashId;
-	const char*		locale;
-	char			data[CP_MAX_PACKET];
-	int				datalen;
-	char*			clientVersion;
-	unsigned int	features	= MXIT_CP_FEATURES;
-
-	locale = purple_account_get_string( session->acc, MXIT_CONFIG_LOCALE, MXIT_DEFAULT_LOCALE );
-
-	/* generate client version string (eg, P-2.7.10-Y-PURPLE) */
-	clientVersion = g_strdup_printf( "%c-%i.%i.%i-%s-%s", MXIT_CP_DISTCODE, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CP_ARCH, MXIT_CP_PLATFORM );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%s%c%i%c"			/* "ms"=password\1version\1getContacts\1 */
-								"%s%c%s%c%i%c"				/* capabilities\1dc\1features\1 */
-								"%s%c%s%c"					/* dialingcode\1locale\1 */
-								"%i%c%i%c%i",				/* maxReplyLen\1protocolVer\1lastRosterUpdate */
-								session->encpwd, CP_FLD_TERM, clientVersion, CP_FLD_TERM, 1, CP_FLD_TERM,
-								MXIT_CP_CAP, CP_FLD_TERM, session->distcode, CP_FLD_TERM, features, CP_FLD_TERM,
-								session->dialcode, CP_FLD_TERM, locale, CP_FLD_TERM,
-								CP_MAX_FILESIZE, CP_FLD_TERM, MXIT_CP_PROTO_VESION, CP_FLD_TERM, 0
-	);
-
-	/* include "custom resource" information */
-	splashId = splash_current( session );
-	if ( splashId != NULL )
-		datalen += scnprintf( data + datalen, sizeof( data ) - datalen, "%ccr=%s", CP_REC_TERM, splashId );
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_LOGIN );
-
-	g_free( clientVersion );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a chat message packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param to			The username of the recipient
- *  @param msg			The message text
- */
-void mxit_send_message( struct MXitSession* session, const char* to, const char* msg, gboolean parse_markup, gboolean is_command )
-{
-	char		data[CP_MAX_PACKET];
-	char*		markuped_msg;
-	int			datalen;
-	int			msgtype = ( is_command ? CP_MSGTYPE_COMMAND : CP_MSGTYPE_NORMAL );
-
-	/* first we need to convert the markup from libPurple to MXit format */
-	if ( parse_markup )
-		markuped_msg = mxit_convert_markup_tx( msg, &msgtype );
-	else
-		markuped_msg = g_strdup( msg );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%s%c%i%c%i",		/* "ms"=jid\1msg\1type\1flags */
-								to, CP_FLD_TERM, markuped_msg, CP_FLD_TERM, msgtype, CP_FLD_TERM, CP_MSG_MARKUP | CP_MSG_EMOTICON
-	);
-
-	/* free the resources */
-	g_free( markuped_msg );
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_TX_MSG );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a extended profile request packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param username		Username who's profile is being requested (NULL = our own)
- *  @param nr_attribs	Number of attributes being requested
- *  @param attribute	The names of the attributes
- */
-void mxit_send_extprofile_request( struct MXitSession* session, const char* username, unsigned int nr_attrib, const char* attribute[] )
-{
-	char			data[CP_MAX_PACKET];
-	int				datalen;
-	unsigned int	i;
-
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%i",		/* "ms="mxitid\1nr_attributes */
-								( username ? username : "" ), CP_FLD_TERM, nr_attrib
-	);
-
-	/* add attributes */
-	for ( i = 0; i < nr_attrib; i++ )
-		datalen += scnprintf( data + datalen, sizeof( data ) - datalen, "%c%s", CP_FLD_TERM, attribute[i] );
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_EXTPROFILE_GET );
-}
-
-
-/*------------------------------------------------------------------------
- * Send an update profile packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param password		The new password to be used for logging in (optional)
- *	@param nr_attrib	The number of attributes
- *	@param attributes	String containing the attribute-name, attribute-type and value (seperated by '\01')
- */
-void mxit_send_extprofile_update( struct MXitSession* session, const char* password, unsigned int nr_attrib, const char* attributes )
-{
-	char			data[CP_MAX_PACKET];
-	gchar**			parts					= NULL;
-	int				datalen;
-	unsigned int	i;
-
-	if ( attributes )
-		parts = g_strsplit( attributes, "\01", 1 + ( nr_attrib * 3 ) );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%i",	/* "ms"=password\1nr_attibutes  */
-								( password ) ? password : "", CP_FLD_TERM, nr_attrib
-	);
-
-	/* add attributes */
-	for ( i = 1; i < nr_attrib * 3; i+=3 ) {
-		if ( parts == NULL || parts[i] == NULL || parts[i + 1] == NULL || parts[i + 2] == NULL ) {
-			purple_debug_error( MXIT_PLUGIN_ID, "Invalid profile update attributes = '%s' - nbr=%u\n", attributes, nr_attrib );
-			g_strfreev( parts );
-			return;
-		}
-		datalen += scnprintf( data + datalen, sizeof( data ) - datalen,
-								"%c%s%c%s%c%s",		/* \1name\1type\1value  */
-								CP_FLD_TERM, parts[i], CP_FLD_TERM, parts[i + 1], CP_FLD_TERM, parts[i + 2] );
-	}
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_EXTPROFILE_SET );
-
-	/* freeup the memory */
-	g_strfreev( parts );
-}
-
-
-/*------------------------------------------------------------------------
- * Send packet to request list of suggested friends.
- *
- *  @param session		The MXit session object
- *  @param max			Maximum number of results to return
- *  @param nr_attribs	Number of attributes being requested
- *  @param attribute	The names of the attributes
- */
-void mxit_send_suggest_friends( struct MXitSession* session, int max, unsigned int nr_attrib, const char* attribute[] )
-{
-	char			data[CP_MAX_PACKET];
-	int				datalen;
-	unsigned int	i;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%i%c%s%c%i%c%i%c%i",	/* inputType \1 input \1 maxSuggestions \1 startIndex \1 numAttributes \1 name0 \1 name1 ... \1 nameN */
-								CP_SUGGEST_FRIENDS, CP_FLD_TERM, "", CP_FLD_TERM, max, CP_FLD_TERM, 0, CP_FLD_TERM, nr_attrib );
-
-	/* add attributes */
-	for ( i = 0; i < nr_attrib; i++ )
-		datalen += scnprintf( data + datalen, sizeof( data ) - datalen, "%c%s", CP_FLD_TERM, attribute[i] );
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_SUGGESTCONTACTS );
-}
-
-
-/*------------------------------------------------------------------------
- * Send packet to perform a search for users.
- *
- *  @param session		The MXit session object
- *  @param max			Maximum number of results to return
- *  @param text			The search text
- *  @param nr_attribs	Number of attributes being requested
- *  @param attribute	The names of the attributes
- */
-void mxit_send_suggest_search( struct MXitSession* session, int max, const char* text, unsigned int nr_attrib, const char* attribute[] )
-{
-	char			data[CP_MAX_PACKET];
-	int				datalen;
-	unsigned int	i;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%i%c%s%c%i%c%i%c%i",	/* inputType \1 input \1 maxSuggestions \1 startIndex \1 numAttributes \1 name0 \1 name1 ... \1 nameN */
-								CP_SUGGEST_SEARCH, CP_FLD_TERM, text, CP_FLD_TERM, max, CP_FLD_TERM, 0, CP_FLD_TERM, nr_attrib );
-
-	/* add attributes */
-	for ( i = 0; i < nr_attrib; i++ )
-		datalen += scnprintf( data + datalen, sizeof( data ) - datalen, "%c%s", CP_FLD_TERM, attribute[i] );
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_SUGGESTCONTACTS );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a presence update packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param presence		The presence (as per MXit types)
- *  @param statusmsg	The status message (can be NULL)
- */
-void mxit_send_presence( struct MXitSession* session, int presence, const char* statusmsg )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%i%c",					/* "ms"=show\1status */
-								presence, CP_FLD_TERM
-	);
-
-	/* append status message (if one is set) */
-	if ( statusmsg )
-		datalen += scnprintf( data + datalen, sizeof( data ) - datalen, "%s", statusmsg );
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_STATUS );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a mood update packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param mood			The mood (as per MXit types)
- */
-void mxit_send_mood( struct MXitSession* session, int mood )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%i",	/* "ms"=mood */
-								mood
-	);
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_MOOD );
-}
-
-
-/*------------------------------------------------------------------------
- * Send an invite contact packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param username		The username of the contact being invited
- *  @param mxitid		Indicates the username is a MXitId.
- *  @param alias		Our alias for the contact
- *  @param groupname	Group in which contact should be stored.
- *  @param message		Invite message
- */
-void mxit_send_invite( struct MXitSession* session, const char* username, gboolean mxitid, const char* alias, const char* groupname, const char* message )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%s%c%s%c%i%c%s%c%i",	/* "ms"=group \1 username \1 alias \1 type \1 msg \1 isuserid */
-								groupname, CP_FLD_TERM, username, CP_FLD_TERM, alias,
-								CP_FLD_TERM, MXIT_TYPE_MXIT, CP_FLD_TERM,
-								( message ? message : "" ), CP_FLD_TERM,
-								( mxitid ? 0 : 1 )
-	);
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_INVITE );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a remove contact packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param username		The username of the contact being removed
- */
-void mxit_send_remove( struct MXitSession* session, const char* username )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s",	/* "ms"=username */
-								username
-	);
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_REMOVE );
-}
-
-
-/*------------------------------------------------------------------------
- * Send an accept subscription (invite) packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param username		The username of the contact being accepted
- *  @param alias		Our alias for the contact
- */
-void mxit_send_allow_sub( struct MXitSession* session, const char* username, const char* alias )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%s%c%s",	/* "ms"=username\1group\1alias */
-								username, CP_FLD_TERM, "", CP_FLD_TERM, alias
-	);
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_ALLOW );
-}
-
-
-/*------------------------------------------------------------------------
- * Send an deny subscription (invite) packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param username		The username of the contact being denied
- *  @param reason		The message describing the reason for the rejection (can be NULL).
- */
-void mxit_send_deny_sub( struct MXitSession* session, const char* username, const char* reason )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s",	/* "ms"=username */
-								username
-	);
-
-	/* append reason (if one is set) */
-	if ( reason )
-		datalen += scnprintf( data + datalen, sizeof( data ) - datalen, "%c%s", CP_FLD_TERM, reason );
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_DENY );
-}
-
-
-/*------------------------------------------------------------------------
- * Send an update contact packet to the MXit server.
- *
- *  @param session		The MXit session object
- *  @param username		The username of the contact being denied
- *  @param alias		Our alias for the contact
- *  @param groupname	Group in which contact should be stored.
- */
-void mxit_send_update_contact( struct MXitSession* session, const char* username, const char* alias, const char* groupname )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%s%c%s",	/* "ms"=groupname\1username\1alias */
-								groupname, CP_FLD_TERM, username, CP_FLD_TERM, alias
-	);
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_UPDATE );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a splash-screen click event packet.
- *
- *  @param session		The MXit session object
- *  @param splashid		The identifier of the splash-screen
- */
-void mxit_send_splashclick( struct MXitSession* session, const char* splashid )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s",	/* "ms"=splashId */
-								splashid
-	);
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_SPLASHCLICK );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a message event packet.
- *
- *  @param session		The MXit session object
- *  @param to           The username of the original sender (ie, recipient of the event)
- *  @param id			The identifier of the event (received in message)
- *  @param event		Identified the type of event
- */
-void mxit_send_msgevent( struct MXitSession* session, const char* to, const char* id, int event )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_send_msgevent: to=%s id=%s event=%i\n", to, id, event );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%s%c%i",		/* "ms"=contactAddress \1 id \1 event */
-								to, CP_FLD_TERM, id, CP_FLD_TERM, event
-	);
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_MSGEVENT );
-}
-
-
-/*------------------------------------------------------------------------
- * Send packet to create a MultiMX room.
- *
- *  @param session		The MXit session object
- *  @param groupname	Name of the room to create
- *  @param nr_usernames	Number of users in initial invite
- *  @param usernames	The usernames of the users in the initial invite
- */
-void mxit_send_groupchat_create( struct MXitSession* session, const char* groupname, int nr_usernames, const char* usernames[] )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-	int			i;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%i",	/* "ms"=roomname\1nr_jids\1jid0\1..\1jidN */
-								groupname, CP_FLD_TERM, nr_usernames
-	);
-
-	/* add usernames */
-	for ( i = 0; i < nr_usernames; i++ )
-		datalen += scnprintf( data + datalen, sizeof( data ) - datalen, "%c%s", CP_FLD_TERM, usernames[i] );
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_GRPCHAT_CREATE );
-}
-
-
-/*------------------------------------------------------------------------
- * Send packet to invite users to existing MultiMX room.
- *
- *  @param session		The MXit session object
- *  @param roomid		The unique RoomID for the MultiMx room.
- *  @param nr_usernames	Number of users being invited
- *  @param usernames	The usernames of the users being invited
- */
-void mxit_send_groupchat_invite( struct MXitSession* session, const char* roomid, int nr_usernames, const char* usernames[] )
-{
-	char		data[CP_MAX_PACKET];
-	int			datalen;
-	int			i;
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ),
-								"ms=%s%c%i",	/* "ms"=roomid\1nr_jids\1jid0\1..\1jidN */
-								roomid, CP_FLD_TERM, nr_usernames
-	);
-
-	/* add usernames */
-	for ( i = 0; i < nr_usernames; i++ )
-		datalen += scnprintf( data + datalen, sizeof( data ) - datalen, "%c%s", CP_FLD_TERM, usernames[i] );
-
-	/* queue packet for transmission */
-	mxit_queue_packet( session, data, datalen, CP_CMD_GRPCHAT_INVITE );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a "send file direct" multimedia packet.
- *
- *  @param session		The MXit session object
- *  @param username		The username of the recipient
- *  @param filename		The name of the file being sent
- *  @param buf			The content of the file
- *  @param buflen		The length of the file contents
- */
-void mxit_send_file( struct MXitSession* session, const char* username, const char* filename, const unsigned char* buf, size_t buflen )
-{
-	char				data[CP_MAX_PACKET];
-	int					datalen		= 0;
-	gchar*				chunk;
-	size_t				chunksize;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "SENDING FILE '%s' of %zu bytes to user '%s'\n", filename, buflen, username );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ), "ms=" );
-
-	/* map chunk header over data buffer */
-	chunk = &data[datalen];
-
-	/* encode chunk */
-	chunksize = mxit_chunk_create_senddirect( chunk_data( chunk ), username, filename, buf, buflen );
-	set_chunk_type( chunk, CP_CHUNK_DIRECT_SND );
-	set_chunk_length( chunk, chunksize );
-	datalen += MXIT_CHUNK_HEADER_SIZE + chunksize;
-
-	/* send the byte stream to the mxit server */
-	mxit_queue_packet( session, data, datalen, CP_CMD_MEDIA );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a "reject file" multimedia packet.
- *
- *  @param session		The MXit session object
- *  @param fileid		A unique ID that identifies this file
- */
-void mxit_send_file_reject( struct MXitSession* session, const char* fileid )
-{
-	char				data[CP_MAX_PACKET];
-	int					datalen		= 0;
-	gchar*				chunk;
-	size_t				chunksize;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_send_file_reject\n" );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ), "ms=" );
-
-	/* map chunk header over data buffer */
-	chunk = &data[datalen];
-
-	/* encode chunk */
-	chunksize = mxit_chunk_create_reject( chunk_data( chunk ), fileid );
-	set_chunk_type( chunk, CP_CHUNK_REJECT );
-	set_chunk_length( chunk, chunksize );
-	datalen += MXIT_CHUNK_HEADER_SIZE + chunksize;
-
-	/* send the byte stream to the mxit server */
-	mxit_queue_packet( session, data, datalen, CP_CMD_MEDIA );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a "get file" multimedia packet.
- *
- *  @param session		The MXit session object
- *  @param fileid		A unique ID that identifies this file
- *  @param filesize		The number of bytes to retrieve
- *  @param offset		Offset in file at which to start retrieving
- */
-void mxit_send_file_accept( struct MXitSession* session, const char* fileid, size_t filesize, size_t offset )
-{
-	char				data[CP_MAX_PACKET];
-	int					datalen		= 0;
-	gchar*				chunk;
-	size_t				chunksize;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_send_file_accept\n" );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ), "ms=" );
-
-	/* map chunk header over data buffer */
-	chunk = &data[datalen];
-
-	/* encode chunk */
-	chunksize = mxit_chunk_create_get( chunk_data(chunk), fileid, filesize, offset );
-	set_chunk_type( chunk, CP_CHUNK_GET );
-	set_chunk_length( chunk, chunksize );
-	datalen += MXIT_CHUNK_HEADER_SIZE + chunksize;
-
-	/* send the byte stream to the mxit server */
-	mxit_queue_packet( session, data, datalen, CP_CMD_MEDIA );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a "received file" multimedia packet.
- *
- *  @param session		The MXit session object
- *  @param status		The status of the file-transfer
- */
-void mxit_send_file_received( struct MXitSession* session, const char* fileid, short status )
-{
-	char				data[CP_MAX_PACKET];
-	int					datalen		= 0;
-	gchar*				chunk;
-	size_t				chunksize;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_send_file_received\n" );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ), "ms=" );
-
-	/* map chunk header over data buffer */
-	chunk = &data[datalen];
-
-	/* encode chunk */
-	chunksize = mxit_chunk_create_received( chunk_data(chunk), fileid, status );
-	set_chunk_type( chunk, CP_CHUNK_RECEIVED );
-	set_chunk_length( chunk, chunksize );
-	datalen += MXIT_CHUNK_HEADER_SIZE + chunksize;
-
-	/* send the byte stream to the mxit server */
-	mxit_queue_packet( session, data, datalen, CP_CMD_MEDIA );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a "set avatar" multimedia packet.
- *
- *  @param session		The MXit session object
- *  @param data			The avatar data
- *  @param buflen		The length of the avatar data
- */
-void mxit_set_avatar( struct MXitSession* session, const unsigned char* avatar, size_t avatarlen )
-{
-	char				data[CP_MAX_PACKET];
-	int					datalen		= 0;
-	gchar*				chunk;
-	size_t				chunksize;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_set_avatar: %zu bytes\n", avatarlen );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ), "ms=" );
-
-	/* map chunk header over data buffer */
-	chunk = &data[datalen];
-
-	/* encode chunk */
-	chunksize = mxit_chunk_create_set_avatar( chunk_data(chunk), avatar, avatarlen );
-	set_chunk_type( chunk, CP_CHUNK_SET_AVATAR );
-	set_chunk_length( chunk, chunksize );
-	datalen += MXIT_CHUNK_HEADER_SIZE + chunksize;
-
-	/* send the byte stream to the mxit server */
-	mxit_queue_packet( session, data, datalen, CP_CMD_MEDIA );
-}
-
-
-/*------------------------------------------------------------------------
- * Send a "get avatar" multimedia packet.
- *
- *  @param session		The MXit session object
- *  @param mxitId		The username who's avatar to request
- *  @param avatarId		The id of the avatar image (as string)
- *  @param data			The avatar data
- *  @param buflen		The length of the avatar data
- */
-void mxit_get_avatar( struct MXitSession* session, const char* mxitId, const char* avatarId )
-{
-	char				data[CP_MAX_PACKET];
-	int					datalen		= 0;
-	gchar*				chunk;
-	size_t				chunksize;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_get_avatar: %s\n", mxitId );
-
-	/* convert the packet to a byte stream */
-	datalen = scnprintf( data, sizeof( data ), "ms=" );
-
-	/* map chunk header over data buffer */
-	chunk = &data[datalen];
-
-	/* encode chunk */
-	chunksize = mxit_chunk_create_get_avatar( chunk_data(chunk), mxitId, avatarId );
-	set_chunk_type( chunk, CP_CHUNK_GET_AVATAR );
-	set_chunk_length( chunk, chunksize );
-	datalen += MXIT_CHUNK_HEADER_SIZE + chunksize;
-
-	/* send the byte stream to the mxit server */
-	mxit_queue_packet( session, data, datalen, CP_CMD_MEDIA );
-}
-
-
-/*------------------------------------------------------------------------
- * Process a login message packet.
- *
- *  @param session		The MXit session object
- *  @param records		The packet's data records
- *  @param rcount		The number of data records
- */
-static void mxit_parse_cmd_login( struct MXitSession* session, struct record** records, int rcount )
-{
-	PurpleStatus*	status;
-	int				presence;
-	const char*		statusmsg;
-	const char*		profilelist[] = { CP_PROFILE_BIRTHDATE, CP_PROFILE_GENDER, CP_PROFILE_FULLNAME,
-									CP_PROFILE_TITLE, CP_PROFILE_FIRSTNAME, CP_PROFILE_LASTNAME, CP_PROFILE_EMAIL,
-									CP_PROFILE_MOBILENR, CP_PROFILE_WHEREAMI, CP_PROFILE_ABOUTME, CP_PROFILE_RELATIONSHIP, CP_PROFILE_FLAGS };
-
-	purple_account_set_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN );
-
-	/* we were not yet logged in so we need to complete the login sequence here */
-	session->flags |= MXIT_FLAG_LOGGEDIN;
-	purple_connection_update_progress( session->con, _( "Successfully Logged In..." ), 3, 4 );
-	purple_connection_set_state( session->con, PURPLE_CONNECTION_CONNECTED );
-
-	/* save extra info if this is a HTTP connection */
-	if ( session->http ) {
-		/* save the http server to use for this session */
-		g_strlcpy( session->http_server, records[1]->fields[3]->data, sizeof( session->http_server ) );
-
-		/* save the session id */
-		session->http_sesid = atoi( records[0]->fields[0]->data );
-	}
-
-	/* extract UserId (from protocol 5.9) */
-	if ( records[1]->fcount >= 9 )
-		session->uid = g_strdup( records[1]->fields[8]->data );
-
-	/* display the current splash-screen */
-	if ( splash_popup_enabled( session ) )
-		splash_display( session );
-
-	/* update presence status */
-	status = purple_account_get_active_status( session->acc );
-	presence = mxit_convert_presence( purple_status_get_id( status ) );
-	statusmsg = purple_status_get_attr_string( status, "message" );
-
-	if ( ( presence != MXIT_PRESENCE_ONLINE ) || ( statusmsg ) ) {
-		/* when logging into MXit, your default presence is online. but with the UI, one can change
-		 * the presence to whatever. in the case where its changed to a different presence setting
-		 * we need to send an update to the server, otherwise the user's presence will be out of
-		 * sync between the UI and MXit.
-		 */
-		char* statusmsg1 = purple_markup_strip_html( statusmsg );
-		char* statusmsg2 = g_strndup( statusmsg1, CP_MAX_STATUS_MSG );
-
-		mxit_send_presence( session, presence, statusmsg2 );
-
-		g_free( statusmsg1 );
-		g_free( statusmsg2 );
-	}
-
-	/* retrieve our MXit profile */
-	mxit_send_extprofile_request( session, NULL, ARRAY_SIZE( profilelist ), profilelist );
-}
-
-
-/*------------------------------------------------------------------------
- * Process a received message packet.
- *
- *  @param session		The MXit session object
- *  @param records		The packet's data records
- *  @param rcount		The number of data records
- */
-static void mxit_parse_cmd_message( struct MXitSession* session, struct record** records, int rcount )
-{
-	struct RXMsgData*	mx			= NULL;
-	char*				message		= NULL;
-	char*				sender		= NULL;
-	int					msglen		= 0;
-	int					msgflags	= 0;
-	int					msgtype		= 0;
-
-	if ( ( rcount == 1 ) || ( records[0]->fcount < 2 ) || ( records[1]->fcount == 0 ) || ( records[1]->fields[0]->len == 0 ) ) {
-		/* packet contains no message or an empty message */
-		return;
-	}
-
-	message = records[1]->fields[0]->data;
-	msglen = strlen( message );
-
-	/* strip off dummy domain */
-	sender = records[0]->fields[0]->data;
-	mxit_strip_domain( sender );
-
-#ifdef	DEBUG_PROTOCOL
-	purple_debug_info( MXIT_PLUGIN_ID, "Message received from '%s'\n", sender );
-#endif
-
-	/* decode message flags (if any) */
-	if ( records[0]->fcount >= 5 )
-		msgflags = atoi( records[0]->fields[4]->data );
-	msgtype = atoi( records[0]->fields[2]->data );
-
-	if ( msgflags & CP_MSG_PWD_ENCRYPTED ) {
-		/* this is a password encrypted message. we do not currently support those so ignore it */
-		PurpleBuddy*	buddy;
-		const char*		name;
-		char			msg[128];
-
-		buddy = purple_blist_find_buddy( session->acc, sender );
-		if ( buddy )
-			name = purple_buddy_get_alias( buddy );
-		else
-			name = sender;
-		g_snprintf( msg, sizeof( msg ), _( "%s sent you an encrypted message, but it is not supported on this client." ), name );
-		mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Message Error" ), msg );
-		return;
-	}
-	else if ( msgflags & CP_MSG_TL_ENCRYPTED ) {
-		/* This is a transport-layer encrypted message. We don't support
-		 * it anymore, because original client doesn't look like it was. */
-		purple_serv_got_im(session->con, sender,
-			_("An encrypted message was received which could not be decrypted."),
-			PURPLE_MESSAGE_ERROR, time(NULL));
-		return;
-	}
-
-	if ( msgflags & CP_MSG_NOTIFY_DELIVERY ) {
-		/* delivery notification is requested */
-		if ( records[0]->fcount >= 4 )
-			mxit_send_msgevent( session, sender, records[0]->fields[3]->data, CP_MSGEVENT_DELIVERED );
-	}
-
-	/* create and initialise new markup struct */
-	mx = g_new0( struct RXMsgData, 1 );
-	mx->msg = g_string_sized_new( msglen );
-	mx->session = session;
-	mx->from = g_strdup( sender );
-	mx->timestamp = atoi( records[0]->fields[1]->data );
-	mx->got_img = FALSE;
-	mx->chatid = -1;
-	mx->img_count = 0;
-
-	/* update list of active chats */
-	if ( !find_active_chat( session->active_chats, mx->from ) ) {
-		session->active_chats = g_list_append( session->active_chats, g_strdup( mx->from ) );
-	}
-
-	if ( is_multimx_contact( session, mx->from ) ) {
-		/* this is a MultiMx chatroom message */
-		multimx_message_received( mx, message, msglen, msgtype, msgflags );
-	}
-	else {
-		mxit_parse_markup( mx, message, msglen, msgtype, msgflags );
-	}
-
-	/* we are now done parsing the message */
-	mx->converted = TRUE;
-	if ( mx->img_count == 0 ) {
-		/* we have all the data we need for this message to be displayed now. */
-		mxit_show_message( mx );
-	}
-	else {
-		/* this means there are still images outstanding for this message and
-		 * still need to wait for them before we can display the message.
-		 * so the image received callback function will eventually display
-		 * the message. */
-	}
-
-	/* cleanup */
-	if ( msgflags & CP_MSG_TL_ENCRYPTED )
-		g_free( message );
-}
-
-
-/*------------------------------------------------------------------------
- * Process a received subscription request packet.
- *
- *  @param session		The MXit session object
- *  @param records		The packet's data records
- *  @param rcount		The number of data records
- */
-static void mxit_parse_cmd_new_sub( struct MXitSession* session, struct record** records, int rcount )
-{
-	struct contact*		contact;
-	struct record*		rec;
-	int					i;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_new_sub (%i recs)\n", rcount );
-
-	for ( i = 0; i < rcount; i++ ) {
-		rec = records[i];
-
-		if ( rec->fcount < 4 ) {
-			purple_debug_error( MXIT_PLUGIN_ID, "BAD SUBSCRIPTION RECORD! %i fields\n", rec->fcount );
-			break;
-		}
-
-		/* build up a new contact info struct */
-		contact = g_new0( struct contact, 1 );
-
-		g_strlcpy( contact->username, rec->fields[0]->data, sizeof( contact->username ) );
-		mxit_strip_domain( contact->username );				/* remove dummy domain */
-		g_strlcpy( contact->alias, rec->fields[1]->data, sizeof( contact->alias ) );
-		contact->type = atoi( rec->fields[2]->data );
-
-		if ( rec->fcount >= 5 ) {
-			/* there is a personal invite message attached */
-			if ( ( rec->fields[4]->data ) && ( *rec->fields[4]->data ) )
-				contact->msg = strdup( rec->fields[4]->data );
-		}
-
-		/* handle the subscription */
-		if ( contact-> type == MXIT_TYPE_MULTIMX ) {		/* subscription to a MultiMX room */
-			char* creator = NULL;
-
-			if ( rec->fcount >= 6 )
-				creator = rec->fields[5]->data;
-
-			multimx_invite( session, contact, creator );
-		}
-		else
-			mxit_new_subscription( session, contact );
-	}
-}
-
-
-/*------------------------------------------------------------------------
- * Parse the received presence value, and ensure that it is supported.
- *
- *  @param value		The received presence value.
- *  @return				A valid presence value.
- */
-static short mxit_parse_presence( const char* value )
-{
-	short presence = atoi( value );
-
-	/* ensure that the presence value is valid */
-	switch ( presence ) {
-		case MXIT_PRESENCE_OFFLINE :
-		case MXIT_PRESENCE_ONLINE :
-		case MXIT_PRESENCE_AWAY :
-		case MXIT_PRESENCE_DND :
-			return presence;
-
-		default :
-			return MXIT_PRESENCE_ONLINE;
-	}
-}
-
-
-/*------------------------------------------------------------------------
- * Parse the received mood value, and ensure that it is supported.
- *
- *  @param value		The received mood value.
- *  @return				A valid mood value.
- */
-static short mxit_parse_mood( const char* value )
-{
-	short mood = atoi( value );
-
-	/* ensure that the mood value is valid */
-	if ( ( mood >= MXIT_MOOD_NONE ) && ( mood <= MXIT_MOOD_STRESSED ) )
-		return mood;
-
-	return MXIT_MOOD_NONE;
-}
-
-
-/*------------------------------------------------------------------------
- * Process a received contact update packet.
- *
- *  @param session		The MXit session object
- *  @param records		The packet's data records
- *  @param rcount		The number of data records
- */
-static void mxit_parse_cmd_contact( struct MXitSession* session, struct record** records, int rcount )
-{
-	struct contact*		contact	= NULL;
-	struct record*		rec;
-	int					i;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_contact (%i recs)\n", rcount );
-
-	for ( i = 0; i < rcount; i++ ) {
-		rec = records[i];
-
-		if ( rec->fcount < 6 ) {
-			purple_debug_error( MXIT_PLUGIN_ID, "BAD CONTACT RECORD! %i fields\n", rec->fcount );
-			break;
-		}
-
-		/* build up a new contact info struct */
-		contact = g_new0( struct contact, 1 );
-
-		g_strlcpy( contact->groupname, rec->fields[0]->data, sizeof( contact->groupname ) );
-		g_strlcpy( contact->username, rec->fields[1]->data, sizeof( contact->username ) );
-		mxit_strip_domain( contact->username );				/* remove dummy domain */
-		g_strlcpy( contact->alias, rec->fields[2]->data, sizeof( contact->alias ) );
-
-		contact->presence = mxit_parse_presence( rec->fields[3]->data );
-		contact->type = atoi( rec->fields[4]->data );
-		contact->mood = mxit_parse_mood( rec->fields[5]->data );
-
-		if ( rec->fcount > 6 ) {
-			/* added in protocol 5.9 - flags & subtype */
-			contact->flags = atoi( rec->fields[6]->data );
-			contact->subtype = rec->fields[7]->data[0];
-		}
-		if ( rec->fcount > 8 ) {
-			/* added in protocol 6.0 - reject message */
-			contact->msg = g_strdup( rec->fields[8]->data );
-		}
-
-		/* add the contact to the buddy list */
-		if ( contact-> type == MXIT_TYPE_MULTIMX )			/* contact is a MultiMX room */
-			multimx_created( session, contact );
-		else
-			mxit_update_contact( session, contact );
-	}
-
-	if ( !( session->flags & MXIT_FLAG_FIRSTROSTER ) ) {
-		session->flags |= MXIT_FLAG_FIRSTROSTER;
-		mxit_update_blist( session );
-	}
-}
-
-
-/*------------------------------------------------------------------------
- * Process a received presence update packet.
- *
- *  @param session		The MXit session object
- *  @param records		The packet's data records
- *  @param rcount		The number of data records
- */
-static void mxit_parse_cmd_presence( struct MXitSession* session, struct record** records, int rcount )
-{
-	int					i;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_presence (%i recs)\n", rcount );
-
-	for ( i = 0; i < rcount; i++ ) {
-		struct record*	rec		= records[i];
-		int				flags	= 0;
-
-		if ( rec->fcount < 6 ) {
-			purple_debug_error( MXIT_PLUGIN_ID, "BAD PRESENCE RECORD! %i fields\n", rec->fcount );
-			break;
-		}
-
-		/*
-		 * The format of the record is:
-		 * contactAddressN \1 presenceN \1 moodN \1 customMoodN \1 statusMsgN \1 avatarIdN [ \1 flagsN ]
-		 */
-		mxit_strip_domain( rec->fields[0]->data );		/* contactAddress */
-
-		if ( rec->fcount >= 7 )		/* flags field is included */
-			flags = atoi( rec->fields[6]->data );
-
-		mxit_update_buddy_presence( session, rec->fields[0]->data, mxit_parse_presence( rec->fields[1]->data ), mxit_parse_mood( rec->fields[2]->data ),
-				rec->fields[3]->data, rec->fields[4]->data, flags );
-		mxit_update_buddy_avatar( session, rec->fields[0]->data, rec->fields[5]->data );
-	}
-}
-
-
-/*------------------------------------------------------------------------
- * Process a received extended profile packet.
- *
- *  @param session		The MXit session object
- *  @param records		The packet's data records
- *  @param rcount		The number of data records
- */
-static void mxit_parse_cmd_extprofile( struct MXitSession* session, struct record** records, int rcount )
-{
-	const char*				mxitId		= records[0]->fields[0]->data;
-	struct MXitProfile*		profile		= NULL;
-	int						count;
-	int						i;
-	const char*				avatarId	= NULL;
-	char*					statusMsg	= NULL;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_extprofile: profile for '%s'\n", mxitId );
-
-	if ( ( records[0]->fields[0]->len == 0 ) || ( session->uid && ( strcmp( session->uid, records[0]->fields[0]->data ) == 0 ) ) ) {
-		/* No UserId or Our UserId provided, so this must be our own profile information */
-		if ( session->profile == NULL )
-			session->profile = g_new0( struct MXitProfile, 1 );
-		profile = session->profile;
-	}
-	else {
-		/* is a buddy's profile */
-		profile = g_new0( struct MXitProfile, 1 );
-	}
-
-	/* set the count for attributes */
-	count = atoi( records[0]->fields[1]->data );
-
-	/* ensure the packet has the correct number of fields */
-	if ( records[0]->fcount < ( 2 + ( count * 3 ) ) ) {
-		purple_debug_error( MXIT_PLUGIN_ID, "Insufficient number of fields in extprofile response. fields=%i records=%i", records[0]->fcount, count );
-		return;
-	}
-
-	for ( i = 0; i < count; i++ ) {
-		char* fname;
-		char* fvalue;
-		char* fstatus;
-		int f = ( i * 3 ) + 2;
-
-		fname = records[0]->fields[f]->data;		/* field name */
-		fvalue = records[0]->fields[f + 1]->data;	/* field value */
-		fstatus = records[0]->fields[f + 2]->data;	/* field status */
-
-		/* first check the status on the returned attribute */
-		if ( fstatus[0] != '0' ) {
-			/* error: attribute requested was NOT found */
-			purple_debug_error( MXIT_PLUGIN_ID, "Bad profile status on attribute '%s' \n", fname );
-			continue;
-		}
-
-		if ( strcmp( CP_PROFILE_BIRTHDATE, fname ) == 0 ) {
-			/* birthdate */
-			if ( records[0]->fields[f + 1]->len > 10 ) {
-				fvalue[10] = '\0';
-				records[0]->fields[f + 1]->len = 10;
-			}
-			memcpy( profile->birthday, fvalue, records[0]->fields[f + 1]->len );
-		}
-		else if ( strcmp( CP_PROFILE_GENDER, fname ) == 0 ) {
-			/* gender */
-			profile->male = ( fvalue[0] == '1' );
-		}
-		else if ( strcmp( CP_PROFILE_FULLNAME, fname ) == 0 ) {
-			/* nickname */
-			g_strlcpy( profile->nickname, fvalue, sizeof( profile->nickname ) );
-		}
-		else if ( strcmp( CP_PROFILE_STATUS, fname ) == 0 ) {
-			/* status message - just keep a reference to the value */
-			statusMsg = g_markup_escape_text( fvalue, -1 );
-		}
-		else if ( strcmp( CP_PROFILE_AVATAR, fname ) == 0 ) {
-			/* avatar id - just keep a reference to the value */
-			avatarId = fvalue;
-		}
-		else if ( strcmp( CP_PROFILE_TITLE, fname ) == 0 ) {
-			/* title */
-			g_strlcpy( profile->title, fvalue, sizeof( profile->title ) );
-		}
-		else if ( strcmp( CP_PROFILE_FIRSTNAME, fname ) == 0 ) {
-			/* first name */
-			g_strlcpy( profile->firstname, fvalue, sizeof( profile->firstname ) );
-		}
-		else if ( strcmp( CP_PROFILE_LASTNAME, fname ) == 0 ) {
-			/* last name */
-			g_strlcpy( profile->lastname, fvalue, sizeof( profile->lastname ) );
-		}
-		else if ( strcmp( CP_PROFILE_EMAIL, fname ) == 0 ) {
-			/* email address */
-			g_strlcpy( profile->email, fvalue, sizeof( profile->email ) );
-		}
-		else if ( strcmp( CP_PROFILE_MOBILENR, fname ) == 0 ) {
-			/* mobile number */
-			g_strlcpy( profile->mobilenr, fvalue, sizeof( profile->mobilenr ) );
-		}
-		else if ( strcmp( CP_PROFILE_REGCOUNTRY, fname ) == 0 ) {
-			/* registered country */
-			g_strlcpy( profile->regcountry, fvalue, sizeof( profile->regcountry ) );
-		}
-		else if ( strcmp( CP_PROFILE_FLAGS, fname ) == 0 ) {
-			/* profile flags */
-			profile->flags = g_ascii_strtoll( fvalue, NULL, 10 );
-		}
-		else if ( strcmp( CP_PROFILE_LASTSEEN, fname ) == 0 ) {
-			/* last seen online */
-			profile->lastonline = g_ascii_strtoll( fvalue, NULL, 10 );
-		}
-		else if ( strcmp( CP_PROFILE_WHEREAMI, fname ) == 0 ) {
-			/* where am I */
-			g_strlcpy( profile->whereami, fvalue, sizeof( profile->whereami ) );
-		}
-		else if ( strcmp( CP_PROFILE_ABOUTME, fname ) == 0) {
-			/* about me */
-			g_strlcpy( profile->aboutme, fvalue, sizeof( profile->aboutme ) );
-		}
-		else if ( strcmp( CP_PROFILE_RELATIONSHIP, fname ) == 0) {
-			/* relatinship status */
-			profile->relationship = strtol( fvalue, NULL, 10 );
-		}
-		else {
-			/* invalid profile attribute */
-			purple_debug_error( MXIT_PLUGIN_ID, "Invalid profile attribute received '%s' \n", fname );
-		}
-	}
-
-	if ( profile != session->profile ) {
-		/* not our own profile */
-		struct contact*		contact		= NULL;
-
-		contact = get_mxit_invite_contact( session, mxitId );
-		if ( contact ) {
-			/* this is an invite, so update its profile info */
-			if ( ( statusMsg ) && ( *statusMsg ) ) {
-				/* update the status message */
-				g_free(contact->statusMsg);
-				contact->statusMsg = strdup( statusMsg );
-			}
-			else
-				contact->statusMsg = NULL;
-			g_free(contact->profile);
-			contact->profile = profile;
-			if ( ( avatarId ) && ( *avatarId ) ) {
-				/* avatar must be requested for this invite before we can display it */
-				mxit_get_avatar( session, mxitId, avatarId );
-				g_free(contact->avatarId);
-				contact->avatarId = strdup( avatarId );
-			}
-			else {
-				/* display what we have */
-				contact->avatarId = NULL;
-				mxit_show_profile( session, mxitId, profile );
-			}
-		}
-		else {
-			/* this is a contact */
-			if ( avatarId )
-				mxit_update_buddy_avatar( session, mxitId, avatarId );
-
-			if ( ( statusMsg ) && ( *statusMsg ) ) {
-				/* update the status message */
-				PurpleBuddy*		buddy	= NULL;
-
-				buddy = purple_blist_find_buddy( session->acc, mxitId );
-				if ( buddy ) {
-					contact = purple_buddy_get_protocol_data( buddy );
-					if ( contact ) {
-						g_free(contact->statusMsg);
-						contact->statusMsg = strdup( statusMsg );
-					}
-				}
-			}
-
-			/* show the profile */
-			mxit_show_profile( session, mxitId, profile );
-			g_free( profile );
-		}
-	}
-
-	g_free( statusMsg );
-}
-
-
-/*------------------------------------------------------------------------
- * Process a received suggest-contacts packet.
- *
- *  @param session		The MXit session object
- *  @param records		The packet's data records
- *  @param rcount		The number of data records
- */
-static void mxit_parse_cmd_suggestcontacts( struct MXitSession* session, struct record** records, int rcount )
-{
-	GList* entries = NULL;
-	int searchType;
-	int maxResults;
-	int count;
-	int i;
-
-	/*
-	 * searchType \1 numSuggestions \1 total \1 numAttributes \1 name0 \1 name1 \1 ... \1 nameN \0
-	 * userid \1 contactType \1 value0 \1 value1 ... valueN \0
-	 * ...
-	 * userid \1 contactType \1 value0 \1 value1 ... valueN
-	 */
-
-	/* ensure that record[0] contacts the minumum number of fields */
-	if ( records[0]->fcount < 4 ) {
-		purple_debug_error( MXIT_PLUGIN_ID, "Insufficient number of fields in suggest contacts response. fields=%i", records[0]->fcount );
-		return;
-	}
-
-	/* the type of results */
-	searchType = atoi( records[0]->fields[0]->data );
-
-	/* the maximum number of results */
-	maxResults = atoi( records[0]->fields[2]->data );
-
-	/* set the count for attributes */
-	count = atoi( records[0]->fields[3]->data );
-
-	/* ensure that record[0] contains the specified number of attributes */
-	if ( records[0]->fcount < ( 4 + count ) ) {
-		purple_debug_error( MXIT_PLUGIN_ID, "Insufficient number of fields in suggest contacts response. fields=%i attributes=%i", records[0]->fcount, count );
-		return;
-	}
-
-	for ( i = 1; i < rcount; i ++ ) {
-		struct record*		rec		= records[i];
-		struct MXitProfile*	profile	= g_new0( struct MXitProfile, 1 );
-		int j;
-
-		/* ensure that each result contains the specified number of attributes */
-		if ( rec->fcount != ( 2 + count ) ) {
-			purple_debug_error( MXIT_PLUGIN_ID, "Insufficient number of fields in suggest contacts response. fields=%i attributes=%i", rec->fcount, count );
-			g_free( profile );
-			continue;
-		}
-
-		g_strlcpy( profile->userid, rec->fields[0]->data, sizeof( profile->userid ) );
-		// TODO: ContactType - User or Service
-
-		for ( j = 0; j < count; j++ ) {
-			char* fname;
-			char* fvalue = "";
-
-			fname = records[0]->fields[4 + j]->data;		/* field name */
-			if ( records[i]->fcount > ( 2 + j ) )
-				fvalue = records[i]->fields[2 + j]->data;	/* field value */
-
-			purple_debug_info( MXIT_PLUGIN_ID, " %s: field='%s' value='%s'\n", profile->userid, fname, fvalue );
-
-			if ( strcmp( CP_PROFILE_BIRTHDATE, fname ) == 0 ) {
-				/* birthdate */
-				g_strlcpy( profile->birthday, fvalue, sizeof( profile->birthday ) );
-			}
-			else if ( strcmp( CP_PROFILE_FIRSTNAME, fname ) == 0 ) {
-				/* first name */
-				g_strlcpy( profile->firstname, fvalue, sizeof( profile->firstname ) );
-			}
-			else if ( strcmp( CP_PROFILE_LASTNAME, fname ) == 0 ) {
-				/* last name */
-				g_strlcpy( profile->lastname, fvalue, sizeof( profile->lastname ) );
-			}
-			else if ( strcmp( CP_PROFILE_GENDER, fname ) == 0 ) {
-				/* gender */
-				profile->male = ( fvalue[0] == '1' );
-			}
-			else if ( strcmp( CP_PROFILE_FULLNAME, fname ) == 0 ) {
-				/* nickname */
-				g_strlcpy( profile->nickname, fvalue, sizeof( profile->nickname ) );
-			}
-			else if ( strcmp( CP_PROFILE_WHEREAMI, fname ) == 0 ) {
-				/* where am I */
-				g_strlcpy( profile->whereami, fvalue, sizeof( profile->whereami ) );
-			}
-			/* ignore other attibutes */
-		}
-
-		entries = g_list_append( entries, profile );
-	}
-
-	/* display */
-	mxit_show_search_results( session, searchType, maxResults, entries );
-
-	/* cleanup */
-	g_list_foreach( entries, (GFunc)g_free, NULL );
-}
-
-/*------------------------------------------------------------------------
- * Process a received message event packet.
- *
- *  @param session		The MXit session object
- *  @param records		The packet's data records
- *  @param rcount		The number of data records
- */
-static void mxit_parse_cmd_msgevent( struct MXitSession* session, struct record** records, int rcount )
-{
-	int event;
-
-	/*
-	 * contactAddress \1 dateTime \1 id \1 event
-	 */
-
-	/* strip off dummy domain */
-	mxit_strip_domain( records[0]->fields[0]->data );
-
-	event = atoi( records[0]->fields[3]->data );
-
-	switch ( event ) {
-		case CP_MSGEVENT_TYPING :							/* user is typing */
-		case CP_MSGEVENT_ANGRY :							/* user is typing angrily */
-			purple_serv_got_typing( session->con, records[0]->fields[0]->data, 0, PURPLE_IM_TYPING );
-			break;
-
-		case CP_MSGEVENT_STOPPED :							/* user has stopped typing */
-			purple_serv_got_typing_stopped( session->con, records[0]->fields[0]->data );
-			break;
-
-		case CP_MSGEVENT_ERASING :							/* user is erasing text */
-		case CP_MSGEVENT_DELIVERED :						/* message was delivered */
-		case CP_MSGEVENT_DISPLAYED :						/* message was viewed */
-			/* these are currently not supported by libPurple */
-			break;
-
-		default:
-			purple_debug_error( MXIT_PLUGIN_ID, "Unknown message event received (%i)\n", event );
-	}
-}
-
-
-/*------------------------------------------------------------------------
- * Process a received multimedia packet.
- *
- *  @param session		The MXit session object
- *  @param records		The packet's data records
- *  @param rcount		The number of data records
- */
-static void mxit_parse_cmd_media( struct MXitSession* session, struct record** records, int rcount )
-{
-	guint	chunktype;
-	guint32	chunksize;
-	gchar*	chunkdata;
-
-	/* received packet is too short to even contain a chunk header */
-	if ( records[0]->fields[0]->len < MXIT_CHUNK_HEADER_SIZE )
-		return;
-
-	/* decode the chunk header */
-	chunktype = chunk_type( records[0]->fields[0]->data );
-	chunksize = chunk_length( records[0]->fields[0]->data );
-	chunkdata = chunk_data( records[0]->fields[0]->data );
-
-	/* check chunk size against length of received data */
-	if ( MXIT_CHUNK_HEADER_SIZE + chunksize > records[0]->fields[0]->len )
-		return;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_media (%i records) (%i type) (%i bytes)\n", rcount, chunktype, chunksize );
-
-	/* supported chunked data types */
-	switch ( chunktype ) {
-		case CP_CHUNK_CUSTOM :				/* custom resource */
-			{
-				struct cr_chunk chunk;
-
-				/* decode the chunked data */
-				if ( mxit_chunk_parse_cr( chunkdata, chunksize, &chunk ) ) {
-
-					purple_debug_info( MXIT_PLUGIN_ID, "chunk info id=%s handle=%s op=%i\n", chunk.id, chunk.handle, chunk.operation );
-
-					/* this is a splash-screen operation */
-					if ( strcmp( chunk.handle, HANDLE_SPLASH2 ) == 0 ) {
-						if ( chunk.operation == CR_OP_UPDATE ) {		/* update the splash-screen */
-							struct splash_chunk *splash = chunk.resources->data;			// TODO: Fix - assuming 1st resource is splash
-							gboolean clickable = ( g_list_length( chunk.resources ) > 1 );	// TODO: Fix - if 2 resources, then is clickable
-
-							if ( splash != NULL )
-								splash_update( session, chunk.id, splash->data, splash->datalen, clickable );
-						}
-						else if ( chunk.operation == CR_OP_REMOVE )		/* remove the splash-screen */
-							splash_remove( session );
-					}
-
-					/* cleanup custom resources */
-					g_list_foreach( chunk.resources, (GFunc)g_free, NULL );
-				}
-			}
-			break;
-
-		case CP_CHUNK_OFFER :				/* file offer */
-			{
-				struct offerfile_chunk chunk;
-
-				/* decode the chunked data */
-				if ( mxit_chunk_parse_offer( chunkdata, chunksize, &chunk ) ) {
-					/* process the offer */
-					mxit_xfer_rx_offer( session, chunk.username, chunk.filename, chunk.filesize, chunk.fileid );
-				}
-			}
-			break;
-
-		case CP_CHUNK_GET :					/* get file response */
-			{
-				struct getfile_chunk chunk;
-
-				/* decode the chunked data */
-				if ( mxit_chunk_parse_get( chunkdata, chunksize, &chunk ) ) {
-					/* process the getfile */
-					mxit_xfer_rx_file( session, chunk.fileid, chunk.data, chunk.length );
-				}
-			}
-			break;
-
-		case CP_CHUNK_GET_AVATAR :			/* get avatars */
-			{
-				struct getavatar_chunk chunk;
-				struct contact* contact = NULL;
-
-				/* decode the chunked data */
-				if ( mxit_chunk_parse_get_avatar( chunkdata, chunksize, &chunk ) ) {
-					/* update avatar image */
-					purple_debug_info( MXIT_PLUGIN_ID, "updating avatar for contact '%s'\n", chunk.mxitid );
-
-					contact = get_mxit_invite_contact( session, chunk.mxitid );
-					if ( contact ) {
-						/* this is an invite (add image to the internal image store) */
-						if (contact->image)
-							g_object_unref(contact->image);
-						contact->image = purple_image_new_from_data(
-							g_memdup(chunk.data, chunk.length), chunk.length);
-						/* show the profile */
-						mxit_show_profile( session, chunk.mxitid, contact->profile );
-					}
-					else {
-						/* this is a contact's avatar, so update it */
-						purple_buddy_icons_set_for_user( session->acc, chunk.mxitid, g_memdup( chunk.data, chunk.length ), chunk.length, chunk.avatarid );
-					}
-				}
-			}
-			break;
-
-		case CP_CHUNK_SET_AVATAR :
-			/* this is a reply packet to a set avatar request. no action is required */
-			break;
-
-		case CP_CHUNK_REJECT :
-			/* this is a reply packet to a reject file request. no action is required */
-			break;
-
-		case CP_CHUNK_DIRECT_SND :
-			/* this is a ack for a file send. */
-			{
-				struct sendfile_chunk chunk;
-
-				if ( mxit_chunk_parse_sendfile( chunkdata, chunksize, &chunk ) ) {
-					purple_debug_info( MXIT_PLUGIN_ID, "file-send send to '%s' [status=%i message='%s']\n", chunk.username, chunk.status, chunk.statusmsg );
-
-					if ( chunk.status != 0 )	/* not success */
-						mxit_popup( PURPLE_NOTIFY_MSG_ERROR, _( "File Send Failed" ), chunk.statusmsg );
-				}
-			}
-			break;
-
-		case CP_CHUNK_RECEIVED :
-			/* this is a ack for a file received. no action is required */
-			break;
-
-		default :
-			purple_debug_error( MXIT_PLUGIN_ID, "Unsupported chunked data packet type received (%i)\n", chunktype );
-			break;
-	}
-}
-
-
-/*------------------------------------------------------------------------
- * Handle a redirect sent from the MXit server.
- *
- *  @param session		The MXit session object
- *  @param url			The redirect information
- */
-static void mxit_perform_redirect( struct MXitSession* session, const char* url )
-{
-	gchar**		parts;
-	gchar**		host;
-	int			type;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_perform_redirect: %s\n", url );
-
-	/* tokenize the URL string */
-	parts = g_strsplit( url, ";", 0 );
-
-	/* Part 1: protocol://host:port */
-	host = g_strsplit( parts[0], ":", 4 );
-	if ( strcmp( host[0], "socket" ) == 0 ) {
-		/* redirect to a MXit socket proxy */
-		g_strlcpy( session->server, &host[1][2], sizeof( session->server ) );
-		session->port = atoi( host[2] );
-	}
-	else {
-		purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "Cannot perform redirect using the specified protocol" ) );
-		goto redirect_fail;
-	}
-
-	/* Part 2: type of redirect */
-	type = atoi( parts[1] );
-	if ( type == CP_REDIRECT_PERMANENT ) {
-		/* permanent redirect, so save new MXit server and port */
-		purple_account_set_string( session->acc, MXIT_CONFIG_SERVER_ADDR, session->server );
-		purple_account_set_int( session->acc, MXIT_CONFIG_SERVER_PORT, session->port );
-	}
-
-	/* Part 3: message (optional) */
-	if ( parts[2] != NULL )
-		purple_connection_notice( session->con, parts[2] );
-
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_perform_redirect: %s redirect to %s:%i\n",
-			( type == CP_REDIRECT_PERMANENT ) ? "Permanent" : "Temporary", session->server, session->port );
-
-	/* perform the re-connect to the new MXit server */
-	mxit_reconnect( session );
-
-redirect_fail:
-	g_strfreev( parts );
-	g_strfreev( host );
-}
-
-
-/*------------------------------------------------------------------------
- * Process a success response received from the MXit server.
- *
- *  @param session		The MXit session object
- *  @param packet		The received packet
- */
-static int process_success_response( struct MXitSession* session, struct rx_packet* packet )
-{
-	/* ignore ping/poll packets */
-	if ( ( packet->cmd != CP_CMD_PING ) && ( packet->cmd != CP_CMD_POLL ) )
-		session->last_rx = mxit_now_milli();
-
-	/*
-	 * when we pass the packet records to the next level for parsing
-	 * we minus 3 records because 1) the first record is the packet
-	 * type 2) packet reply status 3) the last record is bogus
-	 */
-
-	/* packet command */
-	switch ( packet->cmd ) {
-
-		case CP_CMD_REGISTER :
-				/* fall through, when registeration successful, MXit will auto login */
-		case CP_CMD_LOGIN :
-				/* login response */
-				if ( !( session->flags & MXIT_FLAG_LOGGEDIN ) ) {
-					mxit_parse_cmd_login( session, &packet->records[2], packet->rcount - 3 );
-				}
-				break;
-
-		case CP_CMD_LOGOUT :
-				/* logout response */
-				session->flags &= ~MXIT_FLAG_LOGGEDIN;
-				purple_account_disconnect( session->acc );
-
-				/* note:
-				 * we do not prompt the user here for a reconnect, because this could be the user
-				 * logging in with his phone. so we just disconnect the account otherwise
-				 * mxit will start to bounce between the phone and pidgin. also could be a valid
-				 * disconnect selected by the user.
-				 */
-				return -1;
-
-		case CP_CMD_CONTACT :
-				/* contact update */
-				mxit_parse_cmd_contact( session, &packet->records[2], packet->rcount - 3 );
-				break;
-
-		case CP_CMD_PRESENCE :
-				/* presence update */
-				mxit_parse_cmd_presence( session, &packet->records[2], packet->rcount - 3 );
-				break;
-
-		case CP_CMD_RX_MSG :
-				/* incoming message (no bogus record) */
-				mxit_parse_cmd_message( session, &packet->records[2], packet->rcount - 2 );
-				break;
-
-		case CP_CMD_NEW_SUB :
-				/* new subscription request */
-				mxit_parse_cmd_new_sub( session, &packet->records[2], packet->rcount - 3 );
-				break;
-
-		case CP_CMD_MEDIA :
-				/* multi-media message */
-				mxit_parse_cmd_media( session, &packet->records[2], packet->rcount - 2 );
-				break;
-
-		case CP_CMD_EXTPROFILE_GET :
-				/* profile update */
-				mxit_parse_cmd_extprofile( session, &packet->records[2], packet->rcount - 2 );
-				break;
-
-		case CP_CMD_SUGGESTCONTACTS :
-				/* suggest contacts */
-				mxit_parse_cmd_suggestcontacts( session, &packet->records[2], packet->rcount - 2 );
-				break;
-
-		case CP_CMD_GOT_MSGEVENT :
-				/* received message event */
-				mxit_parse_cmd_msgevent( session, &packet->records[2], packet->rcount - 2 );
-				break;
-
-		case CP_CMD_MOOD :
-				/* mood update */
-		case CP_CMD_UPDATE :
-				/* update contact information */
-		case CP_CMD_ALLOW :
-				/* allow subscription ack */
-		case CP_CMD_DENY :
-				/* deny subscription ack */
-		case CP_CMD_INVITE :
-				/* invite contact ack */
-		case CP_CMD_REMOVE :
-				/* remove contact ack */
-		case CP_CMD_TX_MSG :
-				/* outgoing message ack */
-		case CP_CMD_STATUS :
-				/* presence update ack */
-		case CP_CMD_GRPCHAT_CREATE :
-				/* create groupchat */
-		case CP_CMD_GRPCHAT_INVITE :
-				/* groupchat invite */
-		case CP_CMD_PING :
-				/* ping reply */
-		case CP_CMD_POLL :
-				/* HTTP poll reply */
-		case CP_CMD_EXTPROFILE_SET :
-				/* profile update */
-				// TODO: Protocol 6.2 indicates status for each attribute, and current value.
-		case CP_CMD_SPLASHCLICK :
-				/* splash-screen clickthrough */
-		case CP_CMD_MSGEVENT :
-				/* event message */
-				break;
-
-		default :
-			/* unknown packet */
-			purple_debug_error( MXIT_PLUGIN_ID, "Received unknown client packet (cmd = %i)\n", packet->cmd );
-	}
-
-	return 0;
-}
-
-
-/*------------------------------------------------------------------------
- * Process an error response received from the MXit server.
- *
- *  @param session		The MXit session object
- *  @param packet		The received packet
- */
-static int process_error_response( struct MXitSession* session, struct rx_packet* packet )
-{
-	char			errmsg[256];
-	const char*		errdesc;
-
-	/* set the error description to be shown to the user */
-	if ( packet->errmsg )
-		errdesc = packet->errmsg;
-	else
-		errdesc = _( "An internal MXit server error occurred." );
-
-	purple_debug_info( MXIT_PLUGIN_ID, "Error Reply %i:%s\n", packet->errcode, errdesc );
-
-	if ( packet->errcode == MXIT_ERRCODE_LOGGEDOUT ) {
-		/* we are not currently logged in, so we need to reconnect */
-		purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( errdesc ) );
-	}
-
-	/* packet command */
-	switch ( packet->cmd ) {
-
-		case CP_CMD_REGISTER :
-		case CP_CMD_LOGIN :
-				if ( packet->errcode == MXIT_ERRCODE_REDIRECT ) {
-					mxit_perform_redirect( session, packet->errmsg );
-					return 0;
-				}
-				else {
-					g_snprintf( errmsg, sizeof( errmsg ), _( "Login error: %s (%i)" ), errdesc, packet->errcode );
-					purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, errmsg );
-					return -1;
-				}
-		case CP_CMD_LOGOUT :
-				g_snprintf( errmsg, sizeof( errmsg ), _( "Logout error: %s (%i)" ), errdesc, packet->errcode );
-				purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NAME_IN_USE, _( errmsg ) );
-				return -1;
-		case CP_CMD_CONTACT :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Contact Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_RX_MSG :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Message Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_TX_MSG :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Message Sending Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_STATUS :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Status Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_MOOD :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Mood Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_KICK :
-				/*
-				 * the MXit server sends this packet if we were idle for too long.
-				 * to stop the server from closing this connection we need to resend
-				 * the login packet.
-				 */
-				mxit_send_login( session );
-				break;
-		case CP_CMD_INVITE :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Invitation Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_REMOVE :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Contact Removal Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_ALLOW :
-		case CP_CMD_DENY :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Subscription Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_UPDATE :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Contact Update Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_MEDIA :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "File Transfer Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_GRPCHAT_CREATE :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Cannot create MultiMx room" ), _( errdesc ) );
-				break;
-		case CP_CMD_GRPCHAT_INVITE :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "MultiMx Invitation Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_EXTPROFILE_GET :
-		case CP_CMD_EXTPROFILE_SET :
-				mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Profile Error" ), _( errdesc ) );
-				break;
-		case CP_CMD_SPLASHCLICK :
-		case CP_CMD_MSGEVENT :
-				/* ignore error */
-				break;
-		case CP_CMD_PING :
-		case CP_CMD_POLL :
-				break;
-		default :
-				mxit_popup( PURPLE_NOTIFY_MSG_ERROR, _( "Error" ), _( errdesc ) );
-				break;
-	}
-
-	return 0;
-}
-
-
-/*========================================================================================================================
- * Low-level Packet receive
- */
-
-#ifdef	DEBUG_PROTOCOL
-/*------------------------------------------------------------------------
- * Dump a received packet structure.
- *
- *  @param p			The received packet
- */
-static void dump_packet( struct rx_packet* p )
-{
-	struct record*		r	= NULL;
-	struct field*		f	= NULL;
-	int					i;
-	int					j;
-
-	purple_debug_info( MXIT_PLUGIN_ID, "PACKET DUMP: (%i records)\n", p->rcount );
-
-	for ( i = 0; i < p->rcount; i++ ) {
-		r = p->records[i];
-		purple_debug_info( MXIT_PLUGIN_ID, "RECORD: (%i fields)\n", r->fcount );
-
-		for ( j = 0; j < r->fcount; j++ ) {
-			f = r->fields[j];
-			purple_debug_info( MXIT_PLUGIN_ID, "\tFIELD: (len=%zu) '%s' \n", f->len, f->data );
-		}
-	}
-}
-#endif
-
-
-/*------------------------------------------------------------------------
- * Free up memory used by a packet structure.
- *
- *  @param p			The received packet
- */
-static void free_rx_packet( struct rx_packet* p )
-{
-	struct record*		r	= NULL;
-	struct field*		f	= NULL;
-	int					i;
-	int					j;
-
-	for ( i = 0; i < p->rcount; i++ ) {
-		r = p->records[i];
-
-		for ( j = 0; j < r->fcount; j++ ) {
-			g_free( f );
-		}
-		g_free( r->fields );
-		g_free( r );
-	}
-	g_free( p->records );
-}
-
-
-/*------------------------------------------------------------------------
- * Add a new field to a record.
- *
- *  @param r			Parent record object
- *  @return				The newly created field
- */
-static struct field* add_field( struct record* r )
-{
-	struct field*	field;
-
-	field = g_new0( struct field, 1 );
-
-	r->fields = g_realloc( r->fields, sizeof( struct field* ) * ( r->fcount + 1 ) );
-	r->fields[r->fcount] = field;
-	r->fcount++;
-
-	return field;
-}
-
-
-/*------------------------------------------------------------------------
- * Add a new record to a packet.
- *
- *  @param p			The packet object
- *  @return				The newly created record
- */
-static struct record* add_record( struct rx_packet* p )
-{
-	struct record*	rec;
-
-	rec = g_new0( struct record, 1 );
-
-	p->records = g_realloc( p->records, sizeof( struct record* ) * ( p->rcount + 1 ) );
-	p->records[p->rcount] = rec;
-	p->rcount++;
-
-	return rec;
-}
-
-
-/*------------------------------------------------------------------------
- * Parse the received byte stream into a proper client protocol packet.
- *
- *  @param session		The MXit session object
- *  @return				Success (0) or Failure (!0)
- */
-int mxit_parse_packet( struct MXitSession* session )
-{
-	struct rx_packet	packet;
-	struct record*		rec;
-	struct field*		field;
-	gboolean			pbreak;
-	unsigned int		i;
-	int					res	= 0;
-
-#ifdef	DEBUG_PROTOCOL
-	purple_debug_info( MXIT_PLUGIN_ID, "Received packet (%i bytes)\n", session->rx_i );
-	dump_bytes( session, session->rx_dbuf, session->rx_i );
-#endif
-
-	i = 0;
-	while ( i < session->rx_i ) {
-
-		/* create first record and field */
-		rec = NULL;
-		field = NULL;
-		memset( &packet, 0x00, sizeof( struct rx_packet ) );
-		rec = add_record( &packet );
-		pbreak = FALSE;
-
-		/* break up the received packet into fields and records for easy parsing */
-		while ( ( i < session->rx_i ) && ( !pbreak ) ) {
-
-			switch ( session->rx_dbuf[i] ) {
-				case CP_SOCK_REC_TERM :
-						/* new record */
-						if ( packet.rcount == 1 ) {
-							/* packet command */
-							if ( packet.records[0]->fcount > 0 )
-								packet.cmd = atoi( packet.records[0]->fields[0]->data );
-						}
-						else if ( packet.rcount == 2 ) {
-							/* special case: binary multimedia packets should not be parsed here */
-							if ( packet.cmd == CP_CMD_MEDIA ) {
-								/* add the chunked to new record */
-								rec = add_record( &packet );
-								field = add_field( rec );
-								field->data = &session->rx_dbuf[i + 1];
-								field->len = session->rx_i - i;
-								/* now skip the binary data */
-								res = chunk_length( field->data );
-								/* determine if we have more packets */
-								if ( res + 6 + i < session->rx_i ) {
-									/* we have more than one packet in this stream */
-									i += res + 6;
-									pbreak = TRUE;
-								}
-								else {
-									i = session->rx_i;
-								}
-							}
-						}
-						else if ( !field ) {
-							field = add_field( rec );
-							field->data = &session->rx_dbuf[i];
-						}
-						session->rx_dbuf[i] = '\0';
-						rec = add_record( &packet );
-						field = NULL;
-
-						break;
-				case CP_FLD_TERM :
-						/* new field */
-						session->rx_dbuf[i] = '\0';
-						if ( !field ) {
-							field = add_field( rec );
-							field->data = &session->rx_dbuf[i];
-						}
-						field = NULL;
-						break;
-				case CP_PKT_TERM :
-						/* packet is done! */
-						session->rx_dbuf[i] = '\0';
-						pbreak = TRUE;
-						break;
-				default :
-						/* skip non special characters */
-						if ( !field ) {
-							field = add_field( rec );
-							field->data = &session->rx_dbuf[i];
-						}
-						field->len++;
-						break;
-			}
-
-			i++;
-		}
-
-		if ( packet.rcount < 2 ) {
-			/* bad packet */
-			purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "Invalid packet received from MXit." ) );
-			free_rx_packet( &packet );
-			continue;
-		}
-
-		session->rx_dbuf[session->rx_i] = '\0';
-		packet.errcode = atoi( packet.records[1]->fields[0]->data );
-
-		purple_debug_info( MXIT_PLUGIN_ID, "Packet received CMD:%i (%i)\n", packet.cmd, packet.errcode );
-#ifdef	DEBUG_PROTOCOL
-		/* debug */
-		dump_packet( &packet );
-#endif
-
-		/* reset the out ack */
-		if ( session->outack == packet.cmd ) {
-			/* outstanding ack received from mxit server */
-			session->outack = 0;
-		}
-
-		/* check packet status */
-		if ( packet.errcode != MXIT_ERRCODE_SUCCESS ) {
-			/* error reply! */
-			if ( ( packet.records[1]->fcount > 1 ) && ( packet.records[1]->fields[1]->data ) )
-				packet.errmsg = packet.records[1]->fields[1]->data;
-			else
-				packet.errmsg = NULL;
-
-			res = process_error_response( session, &packet );
-		}
-		else {
-			/* success reply! */
-			res = process_success_response( session, &packet );
-		}
-
-		/* free up the packet resources */
-		free_rx_packet( &packet );
-	}
-
-	if ( session->outack == 0 )
-			mxit_manage_queue( session );
-
-	return res;
-}
-
-
-/*------------------------------------------------------------------------
- * Callback when data is received from the MXit server.
- *
- *  @param user_data		The MXit session object
- *  @param source			The file-descriptor on which data was received
- *  @param cond				Condition which caused the callback (PURPLE_INPUT_READ)
- */
-void mxit_cb_rx( gpointer user_data, gint source, PurpleInputCondition cond )
-{
-	struct MXitSession*	session		= (struct MXitSession*) user_data;
-	char				ch;
-	int					res;
-	int					len;
-
-	if ( session->rx_state == RX_STATE_RLEN ) {
-		/* we are reading in the packet length */
-		len = read( session->fd, &ch, 1 );
-		if ( len < 0 ) {
-			/* connection error */
-			purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "A connection error occurred to MXit. (read stage 0x01)" ) );
-			return;
-		}
-		else if ( len == 0 ) {
-			/* connection closed */
-			purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "A connection error occurred to MXit. (read stage 0x02)" ) );
-			return;
-		}
-		else {
-			/* byte read */
-			if ( ch == CP_REC_TERM ) {
-				/* the end of the length record found */
-				session->rx_lbuf[session->rx_i] = '\0';
-				session->rx_res = atoi( &session->rx_lbuf[3] );
-				if ( ( session->rx_res <= 0 ) || ( session->rx_res > CP_MAX_PACKET ) ) {
-					purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "A connection error occurred to MXit. (read stage 0x03)" ) );
-					return;
-				}
-				session->rx_state = RX_STATE_DATA;
-				session->rx_i = 0;
-			}
-			else {
-				/* still part of the packet length record */
-				session->rx_lbuf[session->rx_i] = ch;
-				session->rx_i++;
-				if ( session->rx_i >= sizeof( session->rx_lbuf ) ) {
-					/* malformed packet length record (too long) */
-					purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "A connection error occurred to MXit. (read stage 0x04)" ) );
-					return;
-				}
-			}
-		}
-	}
-	else if ( session->rx_state == RX_STATE_DATA ) {
-		/* we are reading in the packet data */
-		len = read( session->fd, &session->rx_dbuf[session->rx_i], session->rx_res );
-		if ( len < 0 ) {
-			/* connection error */
-			purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "A connection error occurred to MXit. (read stage 0x05)" ) );
-			return;
-		}
-		else if ( len == 0 ) {
-			/* connection closed */
-			purple_connection_error( session->con, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _( "A connection error occurred to MXit. (read stage 0x06)" ) );
-			return;
-		}
-		else {
-			/* data read */
-			session->rx_i += len;
-			session->rx_res -= len;
-
-			if ( session->rx_res == 0 ) {
-				/* ok, so now we have read in the whole packet */
-				session->rx_state = RX_STATE_PROC;
-			}
-		}
-	}
-
-	if ( session->rx_state == RX_STATE_PROC ) {
-		/* we have a full packet, which we now need to process */
-		res = mxit_parse_packet( session );
-
-		if ( res == 0 ) {
-			/* we are still logged in */
-			session->rx_state = RX_STATE_RLEN;
-			session->rx_res = 0;
-			session->rx_i = 0;
-		}
-	}
-}
-
-
-/*------------------------------------------------------------------------
- * Log the user off MXit and close the connection
- *
- *  @param session		The MXit session object
- */
-void mxit_close_connection( struct MXitSession* session )
-{
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_close_connection\n" );
-
-	if ( !( session->flags & MXIT_FLAG_CONNECTED ) ) {
-		/* we are already closed */
-		return;
-	}
-	else if ( session->flags & MXIT_FLAG_LOGGEDIN ) {
-		/* we are currently logged in so we need to send a logout packet */
-		if ( !session->http ) {
-			mxit_send_logout( session );
-		}
-		session->flags &= ~MXIT_FLAG_LOGGEDIN;
-	}
-	session->flags &= ~MXIT_FLAG_CONNECTED;
-
-	/* cancel all outstanding async calls */
-	purple_http_connection_set_destroy(session->async_http_reqs);
-	session->async_http_reqs = NULL;
-
-	/* remove the input cb function */
-	if ( session->inpa ) {
-		purple_input_remove( session->inpa );
-		session->inpa = 0;
-	}
-
-	/* remove HTTP poll timer */
-	if ( session->http_timer_id > 0 )
-		purple_timeout_remove( session->http_timer_id );
-
-	/* remove slow queue manager timer */
-	if ( session->q_slow_timer_id > 0 )
-		purple_timeout_remove( session->q_slow_timer_id );
-
-	/* remove fast queue manager timer */
-	if ( session->q_fast_timer_id > 0 )
-		purple_timeout_remove( session->q_fast_timer_id );
-
-	/* remove all groupchat rooms */
-	while ( session->rooms != NULL ) {
-		struct multimx* multimx = (struct multimx *) session->rooms->data;
-
-		session->rooms = g_list_remove( session->rooms, multimx );
-
-		free( multimx );
-	}
-	g_list_free( session->rooms );
-	session->rooms = NULL;
-
-	/* remove all rx chats names */
-	while ( session->active_chats != NULL ) {
-		char* chat = (char*) session->active_chats->data;
-
-		session->active_chats = g_list_remove( session->active_chats, chat );
-
-		g_free( chat );
-	}
-	g_list_free( session->active_chats );
-	session->active_chats = NULL;
-
-	/* clear the internal invites */
-	while ( session->invites != NULL ) {
-		struct contact* contact = (struct contact*) session->invites->data;
-
-		session->invites = g_list_remove( session->invites, contact );
-
-		g_free(contact->msg);
-		g_free(contact->statusMsg);
-		g_free(contact->profile);
-		if (contact->image)
-			g_object_unref(contact->image);
-		g_free( contact );
-	}
-	g_list_free( session->invites );
-	session->invites = NULL;
-
-	free( session->profile );
-	mxit_free_emoticon_cache( session );
-	g_free( session->uid );
-	g_free( session->encpwd );
-	session->encpwd = NULL;
-
-	/* flush all the commands still in the queue */
-	flush_queue( session );
-}
-
--- a/libpurple/protocols/mxit/client.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,352 +0,0 @@
-/*
- *					MXit Protocol libPurple Plugin
- *
- *			-- MXit client protocol implementation --
- *
- *				Pieter Loubser	<libpurple@mxit.com>
- *
- *			(C) Copyright 2009	MXit Lifestyle (Pty) Ltd.
- *				<http://www.mxitlifestyle.com>
- *
- * 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		_MXIT_PROTO_H_
-#define		_MXIT_PROTO_H_
-
-
-/* Client protocol constants */
-#define		CP_SOCK_REC_TERM		'\x00'				/* socket record terminator */
-#define		CP_HTTP_REC_TERM		'\x26'				/* http record terminator '&' */
-#define		CP_FLD_TERM				'\x01'				/* field terminator */
-#define		CP_PKT_TERM				'\x02'				/* packet terminator */
-
-
-#define		CP_MAX_PACKET			( 1 * 1000 * 1000 )	/* maximum client protocol packet size (1 MB) */
-#define		CP_MAX_FILESIZE			( CP_MAX_PACKET - 1000 )	/* maximum file size (reserve some space for packet headers) */
-#define		MXIT_EMOTICON_SIZE		18					/* icon size for custom emoticons */
-#define		CP_MAX_STATUS_MSG		250					/* maximum status message length (in characters) */
-
-/* Avatars */
-#define		MXIT_AVATAR_SIZE		96					/* default avatar image size 96x96 */
-#define		MXIT_AVATAR_TYPE		"PNG"				/* request avatars in this file type (only a suggestion) */
-#define		MXIT_AVATAR_BITDEPT		24					/* request avatars with this bit depth (only a suggestion) */
-
-/* Protocol error codes */
-#define		MXIT_ERRCODE_SUCCESS	0
-#define		MXIT_ERRCODE_REDIRECT	16
-#define		MXIT_ERRCODE_LOGGEDOUT	42
-
-/* MXit client features */
-#define		MXIT_CF_NONE			0x000000
-#define		MXIT_CF_FORMS			0x000001
-#define		MXIT_CF_FILE_TRANSFER	0x000002
-#define		MXIT_CF_CAMERA			0x000004
-#define		MXIT_CF_COMMANDS		0x000008
-#define		MXIT_CF_SMS				0x000010
-#define		MXIT_CF_FILE_ACCESS		0x000020
-#define		MXIT_CF_MIDP2			0x000040
-#define		MXIT_CF_SKINS			0x000080
-#define		MXIT_CF_AUDIO			0x000100
-#define		MXIT_CF_ENCRYPTION		0x000200
-#define		MXIT_CF_VOICE_REC		0x000400
-#define		MXIT_CF_VECTOR_GFX		0x000800
-#define		MXIT_CF_IMAGES			0x001000
-#define		MXIT_CF_MARKUP			0x002000
-#define		MXIT_CF_VIBES			0x004000
-#define		MXIT_CF_SELECT_CONTACT	0x008000
-#define		MXIT_CF_CUSTOM_EMO		0x010000
-#define		MXIT_CF_ALERT_PROFILES	0x020000
-#define		MXIT_CF_EXT_MARKUP		0x040000
-#define		MXIT_CF_PLAIN_PWD		0x080000
-#define		MXIT_CF_NO_GATEWAYS		0x100000
-#define		MXIT_CF_NO_AVATARS		0x200000
-#define		MXIT_CF_GAMING			0x400000
-#define		MXIT_CF_GAMING_UPDATE	0x800000
-#define		MXIT_CF_VOICE			0x1000000
-#define		MXIT_CF_VIDEO			0x2000000
-#define		MXIT_CF_TOUCHSCREEN		0x4000000
-#define		MXIT_CF_SVC_CONNECTION	0x8000000
-#define		MXIT_CF_MXML			0x10000000
-#define		MXIT_CF_TYPING_NOTIFY	0x20000000
-
-/* Client features supported by this implementation */
-#define		MXIT_CP_FEATURES		( MXIT_CF_FILE_TRANSFER | MXIT_CF_FILE_ACCESS | MXIT_CF_AUDIO | MXIT_CF_MARKUP | MXIT_CF_EXT_MARKUP | MXIT_CF_NO_GATEWAYS | MXIT_CF_IMAGES | MXIT_CF_COMMANDS | MXIT_CF_VIBES | MXIT_CF_MIDP2 | MXIT_CF_TYPING_NOTIFY )
-
-
-#define		MXIT_PING_INTERVAL		( 5 * 60 )				/* ping the server after X seconds of being idle (5 minutes) */
-#define		MXIT_ACK_TIMEOUT		( 30 )					/* timeout after waiting X seconds for an ack from the server (30 seconds) */
-#define		MXIT_TX_DELAY			( 100 )					/* delay between sending consecutive packets (100 ms) */
-
-/* MXit client version */
-#define		MXIT_CP_DISTCODE		'P'						/* client distribution code (magic, do not touch!) */
-#define		MXIT_CP_ARCH			"Y"						/* client architecture series (Y not for Yoda but for PC-client) */
-#define		MXIT_CLIENT_ID			"LP"					/* client ID as specified by MXit */
-#define		MXIT_CP_PLATFORM		"PURPLE"				/* client platform */
-#define		MXIT_CP_PROTO_VESION	63						/* client protocol version */
-
-/* set operating system name */
-#if defined( __APPLE__ )
-#define		MXIT_CP_OS				"apple"
-#elif defined( _WIN32 )
-#define		MXIT_CP_OS				"windows"
-#elif defined( __linux__ )
-#define		MXIT_CP_OS				"linux"
-#else
-#define		MXIT_CP_OS				"unknown"
-#endif
-
-/* Client capabilities */
-#define		MXIT_CP_CAP				"utf8=true;cid="MXIT_CLIENT_ID
-
-/* Client settings */
-#define		MAX_QUEUE_SIZE			( 1 << 5 )				/* tx queue size (32 packets) */
-#define		MXIT_POPUP_WIN_NAME		"MXit Notification"		/* popup window name */
-#define		MXIT_DEFAULT_LOCALE		"en"					/* default locale setting */
-#define		MXIT_DEFAULT_LOC		"planetpurple"			/* the default location for registration */
-
-/* Client protocol commands */
-#define		CP_CMD_LOGIN			0x0001					/* (1) login */
-#define		CP_CMD_LOGOUT			0x0002					/* (2) logout */
-#define		CP_CMD_CONTACT			0x0003					/* (3) get contacts */
-#define		CP_CMD_UPDATE			0x0005					/* (5) update contact information */
-#define		CP_CMD_INVITE			0x0006					/* (6) subscribe to new contact */
-#define		CP_CMD_PRESENCE			0x0007					/* (7) get presence */
-#define		CP_CMD_REMOVE			0x0008					/* (8) remove contact */
-#define		CP_CMD_RX_MSG			0x0009					/* (9) get new messages */
-#define		CP_CMD_TX_MSG			0x000A					/* (10) send new message */
-#define		CP_CMD_REGISTER			0x000B					/* (11) register */
-//#define	CP_CMD_PROFILE_SET		0x000C					/* (12) set profile (DEPRECATED see CP_CMD_EXTPROFILE_SET) */
-#define		CP_CMD_SUGGESTCONTACTS	0x000D					/* (13) suggest contacts */
-#define		CP_CMD_POLL				0x0011					/* (17) poll the HTTP server for an update */
-//#define	CP_CMD_PROFILE_GET		0x001A					/* (26) get profile (DEPRECATED see CP_CMD_EXTPROFILE_GET) */
-#define		CP_CMD_MEDIA			0x001B					/* (27) get multimedia message */
-#define		CP_CMD_SPLASHCLICK		0x001F					/* (31) splash-screen clickthrough */
-#define		CP_CMD_STATUS			0x0020					/* (32) set shown presence & status */
-#define		CP_CMD_MSGEVENT			0x0023					/* (35) Raise message event */
-#define		CP_CMD_GOT_MSGEVENT		0x0024					/* (36) Get message event */
-#define		CP_CMD_MOOD				0x0029					/* (41) set mood */
-#define		CP_CMD_KICK				0x002B					/* (43) login kick */
-#define		CP_CMD_GRPCHAT_CREATE	0x002C					/* (44) create new groupchat */
-#define		CP_CMD_GRPCHAT_INVITE	0x002D					/* (45) add new groupchat member */
-#define		CP_CMD_NEW_SUB			0x0033					/* (51) get new subscription */
-#define		CP_CMD_ALLOW			0x0034					/* (52) allow subscription */
-#define		CP_CMD_DENY				0x0037					/* (55) deny subscription */
-#define		CP_CMD_EXTPROFILE_GET	0x0039					/* (57) get extended profile */
-#define		CP_CMD_EXTPROFILE_SET	0x003A					/* (58) set extended profile */
-#define		CP_CMD_PING				0x03E8					/* (1000) ping (keepalive) */
-
-/* HTTP connection */
-#define		MXIT_HTTP_POLL_MIN		7						/* minimum time between HTTP polls (seconds) */
-#define		MXIT_HTTP_POLL_MAX		( 10 * 60 )				/* maximum time between HTTP polls (seconds) */
-
-/* receiver states */
-#define		RX_STATE_RLEN			0x01					/* reading packet length section */
-#define		RX_STATE_DATA			0x02					/* reading packet data section */
-#define		RX_STATE_PROC			0x03					/* process read data */
-
-/* message flags */
-#define		CP_MSG_NOTIFY_DELIVERY	0x0002					/* request delivery notification */
-#define		CP_MSG_NOTIFY_READ		0x0004					/* request read notification */
-#define		CP_MSG_PWD_ENCRYPTED	0x0010					/* message is password encrypted */
-#define		CP_MSG_TL_ENCRYPTED		0x0020					/* message is transport encrypted */
-#define		CP_MSG_RPLY_PWD_ENCRYPT	0x0040					/* reply should be password encrypted */
-#define		CP_MSG_RPLY_TL_ENCRYPT	0x0080					/* reply should be transport encrypted */
-#define		CP_MSG_MARKUP			0x0200					/* message may contain markup */
-#define		CP_MSG_EMOTICON			0x0400					/* message may contain custom emoticons */
-#define		CP_MSG_FAREWELL			0x0800					/* this is a farewell message */
-
-/* redirect types */
-#define		CP_REDIRECT_PERMANENT	1						/* permanent redirect */
-#define		CP_REDIRECT_TEMPORARY	2						/* temporary redirect */
-
-/* message tx types */
-#define		CP_MSGTYPE_NORMAL		0x01					/* normal message */
-#define		CP_MSGTYPE_CHAT			0x02					/* chat message */
-#define		CP_MSGTYPE_HEADLINE		0x03					/* headline message */
-#define		CP_MSGTYPE_ERROR		0x04					/* error message */
-#define		CP_MSGTYPE_GROUPCHAT	0x05					/* groupchat message */
-#define		CP_MSGTYPE_FORM			0x06					/* mxit custom form */
-#define		CP_MSGTYPE_COMMAND		0x07					/* mxit command */
-
-/* message event types */
-#define		CP_MSGEVENT_DELIVERED	0x02					/* message was delivered */
-#define		CP_MSGEVENT_DISPLAYED	0x04					/* message was viewed */
-#define		CP_MSGEVENT_TYPING		0x10					/* user is typing */
-#define		CP_MSGEVENT_STOPPED		0x20					/* user has stopped typing */
-#define		CP_MSGEVENT_ANGRY		0x40					/* user is typing angrily */
-#define		CP_MSGEVENT_ERASING		0x80					/* user is erasing text */
-
-/* extended profile attribute fields */
-#define		CP_PROFILE_BIRTHDATE	"birthdate"				/* Birthdate (String - ISO 8601 format) */
-#define		CP_PROFILE_GENDER		"gender"				/* Gender (Boolean - 0=female, 1=male) */
-// #define		CP_PROFILE_HIDENUMBER	"hidenumber"			/* Hide Number (Boolean - 0=false, 1=true) (DEPRECATED) */
-#define		CP_PROFILE_FULLNAME		"fullname"				/* Fullname (UTF8 String) */
-#define		CP_PROFILE_STATUS		"statusmsg"				/* Status Message (UTF8 String) */
-#define		CP_PROFILE_PREVSTATUS	"prevstatusmsgs"		/* Previous Status Messages (UTF8 String) */
-#define		CP_PROFILE_AVATAR		"avatarid"				/* Avatar ID (String) */
-#define		CP_PROFILE_MODIFIED		"lastmodified"			/* Last-Modified timestamp */
-#define		CP_PROFILE_TITLE		"title"					/* Title (UTF8 String) */
-#define		CP_PROFILE_FIRSTNAME	"firstname"				/* First name (UTF8 String) */
-#define		CP_PROFILE_LASTNAME		"lastname"				/* Last name (UTF8 String) */
-#define		CP_PROFILE_EMAIL		"email"					/* Email address (UTF8 String) */
-#define		CP_PROFILE_MOBILENR		"mobilenumber"			/* Mobile Number (UTF8 String) */
-#define		CP_PROFILE_REGCOUNTRY	"registeredcountry"		/* Registered Country Code (UTF8 String) */
-#define		CP_PROFILE_FLAGS		"flags"					/* Profile flags (Bitset) */
-#define		CP_PROFILE_LASTSEEN		"lastseen"				/* Last-Online timestamp */
-#define		CP_PROFILE_WHEREAMI		"whereami"				/* Where am I / Where I live */
-#define		CP_PROFILE_ABOUTME		"aboutme"				/* About me */
-#define		CP_PROFILE_RELATIONSHIP	"relationship"			/* Relationship Status */
-
-/* extended profile field types */
-#define		CP_PROFILE_TYPE_BOOL	0x02					/* boolean (0 or 1) */
-#define		CP_PROFILE_TYPE_SHORT	0x04					/* short (16-bit) */
-#define		CP_PROFILE_TYPE_INT		0x05					/* integer (32-bit) */
-#define		CP_PROFILE_TYPE_LONG	0x06					/* long (64-bit) */
-#define		CP_PROFILE_TYPE_UTF8	0x0A					/* UTF8 string */
-#define		CP_PROFILE_TYPE_DATE	0x0B					/* date-time (ISO 8601 format) */
-
-/* profile flags */
-#define		CP_PROF_NOT_SEARCHABLE	0x02					/* user cannot be searched for */
-#define		CP_PROF_NOT_SUGGESTABLE	0x08					/* user cannot be suggested as friend */
-#define		CP_PROF_DOBLOCKED		0x40					/* date-of-birth cannot be changed */
-
-/* suggestion types */
-#define		CP_SUGGEST_ADDRESSBOOK	0						/* address book search */
-#define		CP_SUGGEST_FRIENDS		1						/* suggested friends */
-#define		CP_SUGGEST_SEARCH		2						/* free-text search */
-#define		CP_SUGGEST_MXITID		3						/* MXitId search */
-
-/* define this to enable protocol debugging (very verbose logging) */
-#define		DEBUG_PROTOCOL
-
-
-/* ======================================================================================= */
-
-struct MXitSession;
-
-/*------------------------------------------*/
-
-struct field {
-	char*				data;
-	size_t				len;
-};
-
-struct record {
-	struct field**		fields;
-	int					fcount;
-};
-
-struct rx_packet {
-	int					cmd;
-	int					errcode;
-	char*				errmsg;
-	struct record**		records;
-	int					rcount;
-};
-
-struct tx_packet {
-	int					cmd;
-	char				header[256];
-	int					headerlen;
-	char*				data;
-	int					datalen;
-};
-
-/*------------------------------------------*/
-
-
-/*
- * A received message data object
- */
-struct RXMsgData {
-	struct MXitSession*		session;					/* MXit session object */
-	char*					from;						/* the sender's name */
-	time_t					timestamp;					/* time at which the message was sent */
-	GString*				msg;						/* newly created message converted to libPurple formatting */
-	gboolean				got_img;					/* flag to say if this message got any images/emoticons embedded */
-	short					img_count;					/* the amount of images/emoticons still outstanding for the message */
-	int						chatid;						/* multimx chatroom id */
-	int						flags;						/* libPurple conversation flags */
-	gboolean				converted;					/* true if the message has been completely parsed and converted to libPurple markup */
-	gboolean				processed;					/* the message has been processed completely and should be freed up */
-};
-
-
-
-/*
- * The packet transmission queue.
- */
-struct tx_queue {
-	struct tx_packet*	packets[MAX_QUEUE_SIZE];		/* array of packet pointers */
-	int					count;							/* number of packets queued */
-	int					rd_i;							/* queue current read index (queue offset for reading a packet) */
-	int					wr_i;							/* queue current write index (queue offset for adding new packet) */
-};
-
-
-/* ======================================================================================= */
-
-void mxit_popup( int type, const char* heading, const char* message );
-void mxit_strip_domain( char* username );
-gboolean find_active_chat( const GList* chats, const char* who );
-
-void mxit_cb_rx( gpointer data, gint source, PurpleInputCondition cond );
-gboolean mxit_manage_queue_slow( gpointer user_data );
-gboolean mxit_manage_queue_fast( gpointer user_data );
-gboolean mxit_manage_polling( gpointer user_data );
-
-void mxit_send_register( struct MXitSession* session );
-void mxit_send_login( struct MXitSession* session );
-void mxit_send_logout( struct MXitSession* session );
-void mxit_send_ping( struct MXitSession* session );
-void mxit_send_poll( struct MXitSession* session );
-
-void mxit_send_presence( struct MXitSession* session, int presence, const char* statusmsg );
-void mxit_send_mood( struct MXitSession* session, int mood );
-void mxit_send_message( struct MXitSession* session, const char* to, const char* msg, gboolean parse_markup, gboolean is_command );
-
-void mxit_send_extprofile_update( struct MXitSession* session, const char* password, unsigned int nr_attrib, const char* attributes );
-void mxit_send_extprofile_request( struct MXitSession* session, const char* username, unsigned int nr_attrib, const char* attribute[] );
-
-void mxit_send_suggest_friends( struct MXitSession* session, int max, unsigned int nr_attrib, const char* attribute[] );
-void mxit_send_suggest_search( struct MXitSession* session, int max, const char* text, unsigned int nr_attrib, const char* attribute[] );
-
-void mxit_send_invite( struct MXitSession* session, const char* username, gboolean mxitid, const char* alias, const char* groupname, const char* message );
-void mxit_send_remove( struct MXitSession* session, const char* username );
-void mxit_send_allow_sub( struct MXitSession* session, const char* username, const char* alias );
-void mxit_send_deny_sub( struct MXitSession* session, const char* username, const char* reason );
-void mxit_send_update_contact( struct MXitSession* session, const char* username, const char* alias, const char* groupname );
-void mxit_send_splashclick( struct MXitSession* session, const char* splashid );
-void mxit_send_msgevent( struct MXitSession* session, const char* to, const char* id, int event);
-
-void mxit_send_file( struct MXitSession* session, const char* username, const char* filename, const unsigned char* buf, size_t buflen );
-void mxit_send_file_reject( struct MXitSession* session, const char* fileid );
-void mxit_send_file_accept( struct MXitSession* session, const char* fileid, size_t filesize, size_t offset );
-void mxit_send_file_received( struct MXitSession* session, const char* fileid, short status );
-void mxit_set_avatar( struct MXitSession* session, const unsigned char* avatar, size_t avatarlen );
-void mxit_get_avatar( struct MXitSession* session, const char* mxitId, const char* avatarId );
-
-void mxit_send_groupchat_create( struct MXitSession* session, const char* groupname, int nr_usernames, const char* usernames[] );
-void mxit_send_groupchat_invite( struct MXitSession* session, const char* roomid, int nr_usernames, const char* usernames[] );
-
-int mxit_parse_packet( struct MXitSession* session );
-void dump_bytes( struct MXitSession* session, const char* buf, int len );
-void mxit_close_connection( struct MXitSession* session );
-gint64 mxit_now_milli( void );
-
-
-#endif		/* _MXIT_PROTO_H_ */
-
--- a/libpurple/protocols/oscar/clientlogin.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/oscar/clientlogin.c	Mon Jun 05 16:36:29 2017 +0300
@@ -40,9 +40,6 @@
 #include "oscarcommon.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"
 
@@ -122,19 +119,16 @@
  */
 static gchar *hmac_sha256(const char *key, const char *message)
 {
-	PurpleCipher *cipher;
-	PurpleHash *hash;
+	GHmac *hmac;
 	guchar digest[32];
+	gsize digest_len = 32;
 
-	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);
+	hmac = g_hmac_new(G_CHECKSUM_SHA256, (guchar *)key, strlen(key));
+	g_hmac_update(hmac, (guchar *)message, -1);
+	g_hmac_get_digest(hmac, digest, &digest_len);
+	g_hmac_unref(hmac);
 
-	return purple_base64_encode(digest, sizeof(digest));
+	return g_base64_encode(digest, sizeof(digest));
 }
 
 /**
@@ -345,7 +339,7 @@
 	if (!parse_start_oscar_session_response(gc, got_data, got_len, &host, &port, &cookie, &tls_certname))
 		return;
 
-	cookiedata = purple_base64_decode(cookie, &cookiedata_len);
+	cookiedata = g_base64_decode(cookie, &cookiedata_len);
 	oscar_connect_to_bos(gc, od, host, port, cookiedata, cookiedata_len, tls_certname);
 	g_free(cookiedata);
 
--- a/libpurple/protocols/oscar/family_auth.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/oscar/family_auth.c	Mon Jun 05 16:36:29 2017 +0300
@@ -31,8 +31,6 @@
 
 #include <ctype.h>
 
-#include "ciphers/md5hash.h"
-
 /* #define USE_XOR_FOR_ICQ */
 
 #ifdef USE_XOR_FOR_ICQ
@@ -75,14 +73,15 @@
 static int
 aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest)
 {
-	PurpleHash *hash;
+	GChecksum *hash;
+	gsize digest_len = 16;
 
-	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);
+	hash = g_checksum_new(G_CHECKSUM_MD5);
+	g_checksum_update(hash, (const guchar *)key, -1);
+	g_checksum_update(hash, (const guchar *)password, password_len);
+	g_checksum_update(hash, (const guchar *)AIM_MD5_STRING, -1);
+	g_checksum_get_digest(hash, digest, &digest_len);
+	g_checksum_free(hash);
 
 	return 0;
 }
@@ -90,19 +89,20 @@
 static int
 aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest)
 {
-	PurpleHash *hash;
+	GChecksum *hash;
 	guchar passdigest[16];
+	gsize digest_len = 16;
 
-	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);
+	hash = g_checksum_new(G_CHECKSUM_MD5);
+	g_checksum_update(hash, (const guchar *)password, password_len);
+	g_checksum_get_digest(hash, passdigest, &digest_len);
+	g_checksum_reset(hash);
 
-	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);
+	g_checksum_update(hash, (const guchar *)key, -1);
+	g_checksum_update(hash, passdigest, digest_len);
+	g_checksum_update(hash, (const guchar *)AIM_MD5_STRING, -1);
+	g_checksum_get_digest(hash, digest, &digest_len);
+	g_checksum_free(hash);
 
 	return 0;
 }
--- a/libpurple/protocols/oscar/oscar.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/oscar/oscar.c	Mon Jun 05 16:36:29 2017 +0300
@@ -33,7 +33,6 @@
 #include "account.h"
 #include "accountopt.h"
 #include "buddyicon.h"
-#include "ciphers/md5hash.h"
 #include "conversation.h"
 #include "core.h"
 #include "debug.h"
@@ -5238,15 +5237,16 @@
 	if (img == NULL) {
 		aim_ssi_delicon(od);
 	} else {
-		PurpleHash *hash;
+		GChecksum *hash;
 		guchar md5[16];
+		gsize digest_len = 16;
 		gconstpointer data = purple_image_get_data(img);
 		size_t len = purple_image_get_data_size(img);
 
-		hash = purple_md5_hash_new();
-		purple_hash_append(hash, data, len);
-		purple_hash_digest(hash, md5, sizeof(md5));
-		g_object_unref(hash);
+		hash = g_checksum_new(G_CHECKSUM_MD5);
+		g_checksum_update(hash, data, len);
+		g_checksum_get_digest(hash, md5, &digest_len);
+		g_checksum_free(hash);
 
 		aim_ssi_seticon(od, md5, 16);
 	}
--- a/libpurple/protocols/sametime/sametime.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/protocols/sametime/sametime.c	Mon Jun 05 16:36:29 2017 +0300
@@ -3879,7 +3879,7 @@
       /* obtain and base64 encode the image data, and put it in the
 	 mime part */
       size = purple_image_get_data_size(img);
-      data = purple_base64_encode(purple_image_get_data(img), size);
+      data = g_base64_encode(purple_image_get_data(img), size);
       purple_mime_part_set_data(part, data);
       g_free(data);
 
--- a/libpurple/protocols/yahoo/tests/.hgignore	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-syntax: regexp
-^test_yahoo_util$
-
-syntax: glob
-*.log
-*.trs
-
--- a/libpurple/protocols/yahoo/tests/Makefile.am	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-include $(top_srcdir)/glib-tap.mk
-
-COMMON_LIBS=\
-	$(top_builddir)/libpurple/libpurple.la \
-	$(top_builddir)/libpurple/protocols/yahoo/libyahoo.la \
-	$(GLIB_LIBS) \
-	$(GPLUGIN_LIBS)
-
-test_programs=\
-	test_yahoo_util
-
-test_yahoo_util_SOURCES=test_yahoo_util.c
-test_yahoo_util_LDADD=$(COMMON_LIBS)
-
-AM_CPPFLAGS = \
-	-I$(top_srcdir)/libpurple \
-	-I$(top_builddir)/libpurple \
-	$(DEBUG_CFLAGS) \
-	$(GLIB_CFLAGS) \
-	$(GPLUGIN_CFLAGS) \
-	$(PLUGIN_CFLAGS) \
-	$(DBUS_CFLAGS) \
-	$(NSS_CFLAGS)
--- a/libpurple/protocols/yahoo/tests/test_yahoo_util.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,250 +0,0 @@
-#include <glib.h>
-
-#include "../ymsg.h"
-
-typedef struct {
-	gchar *input;
-	gchar *output;
-} YahooStringTestData;
-
-static void
-test_codes_to_html(void) {
-	YahooStringTestData data[] = {
-		{
-			"",
-			"",
-		}, {
-			"\x1B[12345m",
-			"",
-		}, {
-			"plain",
-			"plain",
-		}, {
-			"unknown \x1B[12345m ansi code",
-			"unknown  ansi code",
-		}, {
-			"plain <peanut>",
-			"plain &lt;peanut&gt;",
-		}, {
-			"plain <peanut",
-			"plain &lt;peanut",
-		}, {
-			"plain> peanut",
-			"plain&gt; peanut",
-		}, {
-			"<font face='inva>lid'>test",
-			"<font face='inva&gt;lid'>test</font>",
-		}, {
-			"<font face='inva>lid",
-			"&lt;font face=&apos;inva&gt;lid",
-		}, {
-			"\x1B[1mbold",
-			"<b>bold</b>",
-		}, {
-			"\x1B[2mitalic",
-			"<i>italic</i>",
-		}, {
-			"\x1B[4munderline",
-			"<u>underline</u>",
-		}, {
-			"no\x1B[x4m markup",
-			"no markup",
-		}, {
-			/* bold italic underline */
-			"\x1B[1mbold\x1B[x1m \x1B[2mitalic\x1B[x2m \x1B[4munderline",
-			"<b>bold</b> <i>italic</i> <u>underline</u>",
-		}, {
-			"\x1B[1mbold \x1B[2mbolditalic\x1B[x1m italic",
-			"<b>bold <i>bolditalic</i></b><i> italic</i>",
-		}, {
-			"\x1B[1mbold \x1B[2mbolditalic\x1B[x1m \x1B[4mitalicunderline",
-			"<b>bold <i>bolditalic</i></b><i> <u>italicunderline</u></i>",
-		}, {
-			"\x1B[1mbold \x1B[2mbolditalic \x1B[4mbolditalicunderline\x1B[x2m boldunderline",
-			"<b>bold <i>bolditalic <u>bolditalicunderline</u></i><u> boldunderline</u></b>",
-		}, {
-			"\x1B[1mbold \x1B[2mbolditalic \x1B[4mbolditalicunderline\x1B[x1m italicunderline",
-			"<b>bold <i>bolditalic <u>bolditalicunderline</u></i></b><i><u> italicunderline</u></i>",
-		}, {
-			/* links */
-			"\x1B[lmhttps://pidgin.im/\x1B[xlm",
-			"https://pidgin.im/",
-		}, {
-			/* font color */
-			"\x1B[31mblue",
-			"<font color='#0000FF'>blue</font>",
-		}, {
-			"\x1B[#70ea15mcustom color",
-			"<font color='#70ea15'>custom color</font>",
-		}, {
-			"<ALT #ff0000,#00ff00,#0000ff>test</ALT>",
-			"test",
-		}, {
-			/* font face */
-			"<font face='Georgia'>test",
-			"<font face='Georgia'>test</font>",
-		}, {
-			/* font size */
-			"<font size='15'>test",
-			"<font size='4' absz='15'>test</font>",
-		}, {
-			"<font size='32'>size 32",
-			"<font size='6' absz='32'>size 32</font>",
-		}, {
-			/* combinations */
-			"<font face='Georgia' size='32'>test",
-			"<font face='Georgia' size='6' absz='32'>test</font>",
-		}, {
-			"\x1B[35m<font size='15'>test",
-			"<font color='#FF0080'><font size='4' absz='15'>test</font></font>",
-		}, {
-			"<FADE #ff0000,#00ff00,#0000ff>:<</FADE>",
-			":&lt;",
-		}, {
-			NULL,
-			NULL,
-		}
-	};
-	gint i;
-
-	yahoo_init_colorht();
-
-	for(i = 0; data[i].input; i++) {
-		gchar *result = yahoo_codes_to_html(data[i].input);
-
-		g_assert_cmpstr(result, ==, data[i].output);
-
-		g_free(result);
-	}
-
-	yahoo_dest_colorht();
-}
-
-static void
-test_html_to_codes(void) {
-	YahooStringTestData data[] = {
-		{
-			"plain",
-			"plain",
-		}, {
-			"plain &lt;peanut&gt;",
-			"plain <peanut>",
-		}, {
-			"plain &lt;peanut",
-			"plain <peanut",
-		}, {
-			"plain&gt; peanut",
-			"plain> peanut",
-		}, {
-			"plain &gt;",
-			"plain >",
-		}, {
-			"plain &gt; ",
-			"plain > ",
-		}, {
-			"plain &lt;",
-			"plain <",
-		}, {
-			"plain &lt; ",
-			"plain < ",
-		}, {
-			"plain &lt",
-			"plain &lt",
-		}, {
-			"plain &amp;",
-			"plain &",
-		}, {
-			/* bold/italic/underline */
-			"<b>bold</b>",
-			"\x1B[1mbold\x1B[x1m",
-		}, {
-			"<i>italic</i>",
-			"\x1B[2mitalic\x1B[x2m",
-		}, {
-			"<u>underline</u>",
-			"\x1B[4munderline\x1B[x4m",
-		}, {
-			"no</u> markup",
-			"no markup",
-		}, {
-			"<b>bold</b> <i>italic</i> <u>underline</u>",
-			"\x1B[1mbold\x1B[x1m \x1B[2mitalic\x1B[x2m \x1B[4munderline\x1B[x4m",
-		}, {
-			"<b>bold <i>bolditalic</i></b><i> italic</i>",
-			"\x1B[1mbold \x1B[2mbolditalic\x1B[x2m\x1B[x1m\x1B[2m italic\x1B[x2m",
-		}, {
-			"<b>bold <i>bolditalic</i></b><i> <u>italicunderline</u></i>",
-			"\x1B[1mbold \x1B[2mbolditalic\x1B[x2m\x1B[x1m\x1B[2m \x1B[4mitalicunderline\x1B[x4m\x1B[x2m",
-		}, {
-			/* link */
-			"<A HREF=\"https://pidgin.im/\">https://pidgin.im/</A>",
-			"https://pidgin.im/",
-		}, {
-			"<A HREF=\"mailto:mark@example.com\">mark@example.com</A>",
-			"mark@example.com",
-		}, {
-			/* font nothing */
-			"<font>nothing</font>",
-			"nothing",
-		}, {
-			/* font color */
-			"<font color=\"#E71414\">red</font>",
-			"\x1B[#E71414mred\x1B[#000000m",
-		}, {
-			"<font color=\"#FF0000\">red</font> <font color=\"#0000FF\">blue</font> black",
-			"\x1B[#FF0000mred\x1B[#000000m \x1B[#0000FFmblue\x1B[#000000m black",
-		}, {
-			/* font size */
-			"<font size=\"2\">test</font>",
-			"<font size=\"10\">test</font>",
-		}, {
-			"<font size=\"6\">test</font>",
-			"<font size=\"30\">test</font>",
-		}, {
-			/* combinations */
-			"<font color=\"#FF0000\"><font size=\"1\">redsmall</font> rednormal</font>",
-			"\x1B[#FF0000m<font size=\"8\">redsmall</font> rednormal\x1B[#000000m",
-		}, {
-			"<font color=\"#FF0000\"><font size=\"1\">redsmall</font> <font color=\"#00FF00\">greennormal</font> rednormal</font>",
-			"\x1B[#FF0000m<font size=\"8\">redsmall</font> \x1B[#00FF00mgreennormal\x1B[#FF0000m rednormal\x1B[#000000m",
-		}, {
-			"<b>bold <font color=\"#FF0000\">red <font face=\"Comic Sans MS\" size=\"5\">larger <font color=\"#000000\">backtoblack <font size=\"3\">normalsize</font></font></font></font></b>",
-			"\x1B[1mbold \x1B[#FF0000mred <font face=\"Comic Sans MS\" size=\"20\">larger \x1B[#000000mbacktoblack <font size=\"12\">normalsize</font>\x1B[#FF0000m</font>\x1B[#000000m\x1B[x1m",
-		}, {
-			/* buzz/unknown tags */
-			"<ding>",
-			"<ding>",
-		}, {
-			"Unknown <tags>",
-			"Unknown <tags>",
-		}, {
-			NULL,
-			NULL,
-		}
-	};
-	gint i;
-
-	yahoo_init_colorht();
-
-	for(i = 0; data[i].input; i++) {
-		gchar *result = yahoo_html_to_codes(data[i].input);
-
-		g_assert_cmpstr(result, ==, data[i].output);
-
-		g_free(result);
-	}
-
-	yahoo_dest_colorht();
-}
-
-gint
-main(gint argc, gchar **argv) {
-	g_test_init(&argc, &argv, NULL);
-
-	g_test_add_func("/yahoo/format/network to html",
-	                test_codes_to_html);
-	g_test_add_func("/yahoo/format/html to network",
-	                test_html_to_codes);
-
-	return g_test_run();
-}
--- a/libpurple/protocols/yahoo/yahoo.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,415 +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 <core.h>
-#include <plugins.h>
-
-#include "ymsg.h"
-#include "yahoo.h"
-#include "yahoochat.h"
-#include "yahoo_aliases.h"
-#include "yahoo_doodle.h"
-#include "yahoo_filexfer.h"
-#include "yahoo_picture.h"
-
-static PurpleProtocol *yahoo_protocol = NULL;
-
-static GSList *cmds = NULL;
-
-static void yahoo_register_commands(void)
-{
-	PurpleCmdId id;
-
-	id = purple_cmd_register("join", "s", PURPLE_CMD_P_PROTOCOL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
-	                  PURPLE_CMD_FLAG_PROTOCOL_ONLY,
-	                  "prpl-yahoo", yahoopurple_cmd_chat_join,
-	                  _("join &lt;room&gt;:  Join a chat room on the Yahoo network"), NULL);
-	cmds = g_slist_prepend(cmds, GUINT_TO_POINTER(id));
-
-	id = purple_cmd_register("list", "", PURPLE_CMD_P_PROTOCOL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
-	                  PURPLE_CMD_FLAG_PROTOCOL_ONLY,
-	                  "prpl-yahoo", yahoopurple_cmd_chat_list,
-	                  _("list: List rooms on the Yahoo network"), NULL);
-	cmds = g_slist_prepend(cmds, GUINT_TO_POINTER(id));
-
-	id = purple_cmd_register("buzz", "", PURPLE_CMD_P_PROTOCOL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PROTOCOL_ONLY,
-	                  "prpl-yahoo", yahoopurple_cmd_buzz,
-	                  _("buzz: Buzz a user to get their attention"), NULL);
-	cmds = g_slist_prepend(cmds, GUINT_TO_POINTER(id));
-
-	id = purple_cmd_register("doodle", "", PURPLE_CMD_P_PROTOCOL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PROTOCOL_ONLY,
-	                  "prpl-yahoo", yahoo_doodle_purple_cmd_start,
-	                 _("doodle: Request user to start a Doodle session"), NULL);
-	cmds = g_slist_prepend(cmds, GUINT_TO_POINTER(id));
-}
-
-static void yahoo_unregister_commands(void)
-{
-	while (cmds) {
-		PurpleCmdId id = GPOINTER_TO_UINT(cmds->data);
-		purple_cmd_unregister(id);
-		cmds = g_slist_delete_link(cmds, cmds);
-	}
-}
-
-static PurpleAccount *find_acct(const char *protocol, const char *acct_id)
-{
-	PurpleAccount *acct = NULL;
-
-	/* If we have a specific acct, use it */
-	if (acct_id) {
-		acct = purple_accounts_find(acct_id, protocol);
-		if (acct && !purple_account_is_connected(acct))
-			acct = NULL;
-	} else { /* Otherwise find an active account for the protocol */
-		GList *l = purple_accounts_get_all();
-		while (l) {
-			if (!strcmp(protocol, purple_account_get_protocol_id(l->data))
-					&& purple_account_is_connected(l->data)) {
-				acct = l->data;
-				break;
-			}
-			l = l->next;
-		}
-	}
-
-	return acct;
-}
-
-/* This may not be the best way to do this, but we find the first key w/o a value
- * and assume it is the buddy name */
-static void yahoo_find_uri_novalue_param(gpointer key, gpointer value, gpointer user_data)
-{
-	char **retval = user_data;
-
-	if (value == NULL && *retval == NULL) {
-		*retval = key;
-	}
-}
-
-static gboolean yahoo_uri_handler(const char *proto, const char *cmd, GHashTable *params)
-{
-	char *acct_id = g_hash_table_lookup(params, "account");
-	PurpleAccount *acct;
-
-	if (g_ascii_strcasecmp(proto, "ymsgr"))
-		return FALSE;
-
-	acct = find_acct(purple_protocol_get_id(yahoo_protocol), acct_id);
-
-	if (!acct)
-		return FALSE;
-
-	/* ymsgr:SendIM?screename&m=The+Message */
-	if (!g_ascii_strcasecmp(cmd, "SendIM")) {
-		char *sname = NULL;
-		g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &sname);
-		if (sname) {
-			char *message = g_hash_table_lookup(params, "m");
-
-			PurpleIMConversation *im = purple_conversations_find_im_with_account(
-				sname, acct);
-			if (im == NULL)
-				im = purple_im_conversation_new(acct, sname);
-			purple_conversation_present(PURPLE_CONVERSATION(im));
-
-			if (message) {
-				/* Spaces are encoded as '+' */
-				g_strdelimit(message, "+", ' ');
-				purple_conversation_send_confirm(PURPLE_CONVERSATION(im), message);
-			}
-		}
-		/* else
-			**If pidgindialogs_im() was in the core, we could use it here.
-			 * It is all purple_request_* based, but I'm not sure it really belongs in the core
-			pidgindialogs_im(); */
-
-		return TRUE;
-	}
-	/* ymsgr:Chat?roomname */
-	else if (!g_ascii_strcasecmp(cmd, "Chat")) {
-		char *rname = NULL;
-		g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &rname);
-		if (rname) {
-			/* This is somewhat hacky, but the params aren't useful after this command */
-			g_hash_table_insert(params, g_strdup("room"), g_strdup(rname));
-			g_hash_table_insert(params, g_strdup("type"), g_strdup("Chat"));
-			purple_serv_join_chat(purple_account_get_connection(acct), params);
-		}
-		/* else
-			** Same as above (except that this would have to be re-written using purple_request_*)
-			pidgin_blist_joinchat_show(); */
-
-		return TRUE;
-	}
-	/* ymsgr:AddFriend?name */
-	else if (!g_ascii_strcasecmp(cmd, "AddFriend")) {
-		char *name = NULL;
-		g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &name);
-		purple_blist_request_add_buddy(acct, name, NULL, NULL);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-static GHashTable *
-yahoo_get_account_text_table(PurpleAccount *account)
-{
-	GHashTable *table;
-	table = g_hash_table_new(g_str_hash, g_str_equal);
-	g_hash_table_insert(table, "login_label", (gpointer)_("Yahoo ID..."));
-	return table;
-}
-
-static PurpleWhiteboardOps yahoo_whiteboard_ops =
-{
-	yahoo_doodle_start,
-	yahoo_doodle_end,
-	yahoo_doodle_get_dimensions,
-	NULL,
-	yahoo_doodle_get_brush,
-	yahoo_doodle_set_brush,
-	yahoo_doodle_send_draw_list,
-	yahoo_doodle_clear,
-
-	/* padding */
-	NULL,
-	NULL,
-	NULL,
-	NULL
-};
-
-static void
-yahoo_protocol_init(PurpleProtocol *protocol)
-{
-	PurpleAccountOption *option;
-
-	protocol->id        = "prpl-yahoo";
-	protocol->name      = "Yahoo";
-	protocol->options   = OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC |
-	                      OPT_PROTO_AUTHORIZATION_DENIED_MESSAGE;
-	protocol->icon_spec = purple_buddy_icon_spec_new("png,gif,jpeg",
-	                                                    96, 96, 96, 96, 0,
-	                                                    PURPLE_ICON_SCALE_SEND);
-
-	protocol->whiteboard_ops = &yahoo_whiteboard_ops;
-
-	option = purple_account_option_int_new(_("Pager port"), "port", YAHOO_PAGER_PORT);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_string_new(_("File transfer server"), "xfer_host", YAHOO_XFER_HOST);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_string_new(_("Chat room locale"), "room_list_locale", YAHOO_ROOMLIST_LOCALE);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_string_new(_("Encoding"), "local_charset", "UTF-8");
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_bool_new(_("Ignore conference and chatroom invitations"), "ignore_invites", FALSE);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-#if 0
-	option = purple_account_option_bool_new(_("Use account proxy for HTTP and HTTPS connections"), "proxy_ssl", FALSE);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_string_new(_("Chat room list URL"), "room_list", YAHOO_ROOMLIST_URL);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-#endif
-}
-
-static void
-yahoo_protocol_class_init(PurpleProtocolClass *klass)
-{
-	klass->login        = yahoo_login;
-	klass->close        = yahoo_close;
-	klass->status_types = yahoo_status_types;
-	klass->list_icon    = yahoo_list_icon;
-}
-
-static void
-yahoo_protocol_client_iface_init(PurpleProtocolClientIface *client_iface)
-{
-	client_iface->get_actions            = yahoo_get_actions;
-	client_iface->list_emblem            = yahoo_list_emblem;
-	client_iface->status_text            = yahoo_status_text;
-	client_iface->tooltip_text           = yahoo_tooltip_text;
-	client_iface->blist_node_menu        = yahoo_blist_node_menu;
-	client_iface->normalize              = purple_normalize_nocase;
-	client_iface->offline_message        = yahoo_offline_message;
-	client_iface->get_account_text_table = yahoo_get_account_text_table;
-	client_iface->get_max_message_size   = yahoo_get_max_message_size;
-}
-
-static void
-yahoo_protocol_server_iface_init(PurpleProtocolServerIface *server_iface)
-{
-	server_iface->get_info       = yahoo_get_info;
-	server_iface->set_status     = yahoo_set_status;
-	server_iface->set_idle       = yahoo_set_idle;
-	server_iface->add_buddy      = yahoo_add_buddy;
-	server_iface->remove_buddy   = yahoo_remove_buddy;
-	server_iface->keepalive      = yahoo_keepalive;
-	server_iface->alias_buddy    = yahoo_update_alias;
-	server_iface->group_buddy    = yahoo_change_buddys_group;
-	server_iface->rename_group   = yahoo_rename_group;
-	server_iface->set_buddy_icon = yahoo_set_buddy_icon;
-}
-
-static void
-yahoo_protocol_im_iface_init(PurpleProtocolIMIface *im_iface)
-{
-	im_iface->send        = yahoo_send_im;
-	im_iface->send_typing = yahoo_send_typing;
-}
-
-static void
-yahoo_protocol_chat_iface_init(PurpleProtocolChatIface *chat_iface)
-{
-	chat_iface->info          = yahoo_c_info;
-	chat_iface->info_defaults = yahoo_c_info_defaults;
-	chat_iface->join          = yahoo_c_join;
-	chat_iface->get_name      = yahoo_get_chat_name;
-	chat_iface->invite        = yahoo_c_invite;
-	chat_iface->leave         = yahoo_c_leave;
-	chat_iface->send          = yahoo_c_send;
-}
-
-static void
-yahoo_protocol_privacy_iface_init(PurpleProtocolPrivacyIface *privacy_iface)
-{
-	privacy_iface->add_deny        = yahoo_add_deny;
-	privacy_iface->rem_deny        = yahoo_rem_deny;
-	privacy_iface->set_permit_deny = yahoo_set_permit_deny;
-}
-
-static void
-yahoo_protocol_roomlist_iface_init(PurpleProtocolRoomlistIface *roomlist_iface)
-{
-	roomlist_iface->get_list        = yahoo_roomlist_get_list;
-	roomlist_iface->cancel          = yahoo_roomlist_cancel;
-	roomlist_iface->expand_category = yahoo_roomlist_expand_category;
-}
-
-static void
-yahoo_protocol_attention_iface_init(PurpleProtocolAttentionIface *attention_iface)
-{
-	attention_iface->send      = yahoo_send_attention;
-	attention_iface->get_types = yahoo_attention_types;
-}
-
-static void
-yahoo_protocol_xfer_iface_init(PurpleProtocolXferIface *xfer_iface)
-{
-	xfer_iface->can_receive = yahoo_can_receive_file;
-	xfer_iface->send        = yahoo_send_file;
-	xfer_iface->new_xfer    = yahoo_new_xfer;
-}
-
-PURPLE_DEFINE_TYPE_EXTENDED(
-	YahooProtocol, yahoo_protocol, PURPLE_TYPE_PROTOCOL, 0,
-
-	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CLIENT_IFACE,
-	                                  yahoo_protocol_client_iface_init)
-
-	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_SERVER_IFACE,
-	                                  yahoo_protocol_server_iface_init)
-
-	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_IM_IFACE,
-	                                  yahoo_protocol_im_iface_init)
-
-	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CHAT_IFACE,
-	                                  yahoo_protocol_chat_iface_init)
-
-	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_PRIVACY_IFACE,
-	                                  yahoo_protocol_privacy_iface_init)
-
-	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_ROOMLIST_IFACE,
-	                                  yahoo_protocol_roomlist_iface_init)
-
-	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_ATTENTION_IFACE,
-	                                  yahoo_protocol_attention_iface_init)
-
-	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_XFER_IFACE,
-	                                  yahoo_protocol_xfer_iface_init)
-);
-
-static PurplePluginInfo *
-plugin_query(GError **error)
-{
-	return purple_plugin_info_new(
-		"id",           "prpl-yahoo",
-		"name",         "Yahoo Protocols",
-		"version",      DISPLAY_VERSION,
-		"category",     N_("Protocol"),
-		"summary",      N_("Yahoo! and Yahoo! JAPAN Protocols Plugin"),
-		"description",  N_("Yahoo! and Yahoo! JAPAN Protocols Plugin"),
-		"website",      PURPLE_WEBSITE,
-		"abi-version",  PURPLE_ABI_VERSION,
-		"flags",        PURPLE_PLUGIN_INFO_FLAGS_INTERNAL |
-		                PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD,
-		NULL
-	);
-}
-
-static gboolean
-plugin_load(PurplePlugin *plugin, GError **error)
-{
-	yahoo_protocol_register_type(plugin);
-
-	yahoo_protocol = purple_protocols_add(YAHOO_TYPE_PROTOCOL, error);
-	if (!yahoo_protocol)
-		return FALSE;
-
-	yahoo_init_colorht();
-
-	yahoo_register_commands();
-
-	purple_signal_connect(purple_get_core(), "uri-handler", yahoo_protocol,
-		PURPLE_CALLBACK(yahoo_uri_handler), NULL);
-
-	return TRUE;
-}
-
-static gboolean
-plugin_unload(PurplePlugin *plugin, GError **error)
-{
-	yahoo_unregister_commands();
-
-	yahoo_dest_colorht();
-
-	if (!purple_protocols_remove(yahoo_protocol, error))
-		return FALSE;
-
-	return TRUE;
-}
-
-PURPLE_PLUGIN_INIT(yahoo, plugin_query, plugin_load, plugin_unload);
--- a/libpurple/protocols/yahoo/yahoo.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-#ifndef _YAHOO_H_
-#define _YAHOO_H_
-
-#include <gmodule.h>
-
-#include "protocol.h"
-
-#define YAHOO_TYPE_PROTOCOL             (yahoo_protocol_get_type())
-#define YAHOO_PROTOCOL(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), YAHOO_TYPE_PROTOCOL, YahooProtocol))
-#define YAHOO_PROTOCOL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), YAHOO_TYPE_PROTOCOL, YahooProtocolClass))
-#define YAHOO_IS_PROTOCOL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), YAHOO_TYPE_PROTOCOL))
-#define YAHOO_IS_PROTOCOL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), YAHOO_TYPE_PROTOCOL))
-#define YAHOO_PROTOCOL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), YAHOO_TYPE_PROTOCOL, YahooProtocolClass))
-
-typedef struct _YahooProtocol
-{
-	PurpleProtocol parent;
-} YahooProtocol;
-
-typedef struct _YahooProtocolClass
-{
-	PurpleProtocolClass parent_class;
-} YahooProtocolClass;
-
-/**
- * Returns the GType for the YahooProtocol object.
- */
-G_MODULE_EXPORT GType yahoo_protocol_get_type(void);
-
-#endif /* _YAHOO_H_ */
--- a/libpurple/protocols/yahoo/yahoojp.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +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 <plugins.h>
-
-#include "yahoojp.h"
-#include "ymsg.h"
-#include "yahoochat.h"
-#include "yahoo_aliases.h"
-#include "yahoo_doodle.h"
-#include "yahoo_filexfer.h"
-#include "yahoo_picture.h"
-
-static GSList *cmds = NULL;
-
-void yahoojp_register_commands(void)
-{
-	PurpleCmdId id;
-
-	id = purple_cmd_register("join", "s", PURPLE_CMD_P_PROTOCOL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
-	                  PURPLE_CMD_FLAG_PROTOCOL_ONLY,
-	                  "prpl-yahoojp", yahoopurple_cmd_chat_join,
-	                  _("join &lt;room&gt;:  Join a chat room on the Yahoo network"), NULL);
-	cmds = g_slist_prepend(cmds, GUINT_TO_POINTER(id));
-
-	id = purple_cmd_register("list", "", PURPLE_CMD_P_PROTOCOL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
-	                  PURPLE_CMD_FLAG_PROTOCOL_ONLY,
-	                  "prpl-yahoojp", yahoopurple_cmd_chat_list,
-	                  _("list: List rooms on the Yahoo network"), NULL);
-	cmds = g_slist_prepend(cmds, GUINT_TO_POINTER(id));
-
-	id = purple_cmd_register("buzz", "", PURPLE_CMD_P_PROTOCOL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PROTOCOL_ONLY,
-	                  "prpl-yahoojp", yahoopurple_cmd_buzz,
-	                  _("buzz: Buzz a user to get their attention"), NULL);
-	cmds = g_slist_prepend(cmds, GUINT_TO_POINTER(id));
-
-	id = purple_cmd_register("doodle", "", PURPLE_CMD_P_PROTOCOL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PROTOCOL_ONLY,
-	                  "prpl-yahoojp", yahoo_doodle_purple_cmd_start,
-	                 _("doodle: Request user to start a Doodle session"), NULL);
-	cmds = g_slist_prepend(cmds, GUINT_TO_POINTER(id));
-}
-
-void yahoojp_unregister_commands(void)
-{
-	while (cmds) {
-		PurpleCmdId id = GPOINTER_TO_UINT(cmds->data);
-		purple_cmd_unregister(id);
-		cmds = g_slist_delete_link(cmds, cmds);
-	}
-}
-
-static GHashTable *
-yahoojp_get_account_text_table(PurpleAccount *account)
-{
-	GHashTable *table;
-	table = g_hash_table_new(g_str_hash, g_str_equal);
-	g_hash_table_insert(table, "login_label", (gpointer)_("Yahoo JAPAN ID..."));
-	return table;
-}
-
-static void
-yahoojp_protocol_init(PurpleProtocol *protocol)
-{
-	PurpleAccountOption *option;
-
-	protocol->id   = "prpl-yahoojp";
-	protocol->name = "Yahoo JAPAN";
-
-	/* delete yahoo's protocol options */
-	purple_protocol_override(protocol, PURPLE_PROTOCOL_OVERRIDE_PROTOCOL_OPTIONS);
-
-	option = purple_account_option_int_new(_("Pager port"), "port", YAHOO_PAGER_PORT);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_string_new(_("File transfer server"), "xfer_host", YAHOOJP_XFER_HOST);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_string_new(_("Chat room locale"), "room_list_locale", YAHOOJP_ROOMLIST_LOCALE);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_string_new(_("Encoding"), "local_charset", "UTF-8");
-	protocol->account_options = g_list_append(protocol->account_options, option);
-
-	option = purple_account_option_bool_new(_("Ignore conference and chatroom invitations"), "ignore_invites", FALSE);
-	protocol->account_options = g_list_append(protocol->account_options, option);
-}
-
-static void
-yahoojp_protocol_class_init(PurpleProtocolClass *klass)
-{
-}
-
-static void
-yahoojp_protocol_client_iface_init(PurpleProtocolClientIface *client_iface)
-{
-	client_iface->get_account_text_table = yahoojp_get_account_text_table;
-}
-
-PURPLE_DEFINE_TYPE_EXTENDED(
-	YahooJPProtocol, yahoojp_protocol, YAHOO_TYPE_PROTOCOL, 0,
-
-	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CLIENT_IFACE,
-	                                  yahoojp_protocol_client_iface_init)
-);
--- a/libpurple/protocols/yahoo/yahoojp.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-#ifndef _YAHOOJP_H_
-#define _YAHOOJP_H_
-
-#include "yahoo.h"
-
-#define YAHOOJP_TYPE_PROTOCOL             (yahoojp_protocol_get_type())
-#define YAHOOJP_PROTOCOL(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), YAHOOJP_TYPE_PROTOCOL, YahooJPProtocol))
-#define YAHOOJP_PROTOCOL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), YAHOOJP_TYPE_PROTOCOL, YahooJPProtocolClass))
-#define YAHOOJP_IS_PROTOCOL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), YAHOOJP_TYPE_PROTOCOL))
-#define YAHOOJP_IS_PROTOCOL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), YAHOOJP_TYPE_PROTOCOL))
-#define YAHOOJP_PROTOCOL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), YAHOOJP_TYPE_PROTOCOL, YahooJPProtocolClass))
-
-typedef struct _YahooJPProtocol
-{
-	YahooProtocol parent;
-} YahooJPProtocol;
-
-typedef struct _YahooJPProtocolClass
-{
-	YahooProtocolClass parent_class;
-} YahooJPProtocolClass;
-
-/**
- * Registers the YahooJPProtocol type in the type system.
- */
-void yahoojp_protocol_register_type(PurplePlugin *plugin);
-
-/**
- * Returns the GType for the YahooJPProtocol object.
- */
-G_MODULE_EXPORT GType yahoojp_protocol_get_type(void);
-
-void yahoojp_register_commands(void);
-void yahoojp_unregister_commands(void);
-
-#endif /* _YAHOOJP_H_ */
--- a/libpurple/protocols/yahoo/ymsg.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4989 +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
- *
- */
-
-/*
- * Note: When handling the list of struct yahoo_pair's from an incoming
- * packet the value might not be UTF-8. You should either validate that
- * it is UTF-8 using g_utf8_validate() or use yahoo_string_decode().
- */
-
-#include "internal.h"
-
-#include "account.h"
-#include "accountopt.h"
-#include "buddylist.h"
-#include "ciphers/md5hash.h"
-#include "cmds.h"
-#include "core.h"
-#include "debug.h"
-#include "http.h"
-#include "network.h"
-#include "notify.h"
-#include "protocol.h"
-#include "proxy.h"
-#include "request.h"
-#include "server.h"
-#include "util.h"
-#include "version.h"
-#include "xmlnode.h"
-
-#include "ymsg.h"
-#include "yahoochat.h"
-#include "yahoo_aliases.h"
-#include "yahoo_doodle.h"
-#include "yahoo_filexfer.h"
-#include "yahoo_friend.h"
-#include "yahoo_packet.h"
-#include "yahoo_picture.h"
-#include "ycht.h"
-
-/* #define YAHOO_DEBUG */
-
-/* It doesn't look like it is working (the previously used host is down, another
- * one doesn't send us back cookies).
- */
-#define TRY_WEBMESSENGER_LOGIN 0
-
-/* One hour */
-#define PING_TIMEOUT 3600
-
-/* One minute */
-#define KEEPALIVE_TIMEOUT 60
-
-#if TRY_WEBMESSENGER_LOGIN
-static void
-yahoo_login_page_cb(PurpleHttpConnection *http_conn,
-	PurpleHttpResponse *response, gpointer _unused);
-#endif /* TRY_WEBMESSENGER_LOGIN */
-
-static void yahoo_update_status(PurpleConnection *gc, const char *name, YahooFriend *f)
-{
-	char *status = NULL;
-
-	if (!gc || !name || !f || !purple_blist_find_buddy(purple_connection_get_account(gc), name))
-		return;
-
-	switch (f->status) {
-	case YAHOO_STATUS_OFFLINE:
-		status = YAHOO_STATUS_TYPE_OFFLINE;
-		break;
-	case YAHOO_STATUS_AVAILABLE:
-		status = YAHOO_STATUS_TYPE_AVAILABLE;
-		break;
-	case YAHOO_STATUS_BRB:
-		status = YAHOO_STATUS_TYPE_BRB;
-		break;
-	case YAHOO_STATUS_BUSY:
-		status = YAHOO_STATUS_TYPE_BUSY;
-		break;
-	case YAHOO_STATUS_NOTATHOME:
-		status = YAHOO_STATUS_TYPE_NOTATHOME;
-		break;
-	case YAHOO_STATUS_NOTATDESK:
-		status = YAHOO_STATUS_TYPE_NOTATDESK;
-		break;
-	case YAHOO_STATUS_NOTINOFFICE:
-		status = YAHOO_STATUS_TYPE_NOTINOFFICE;
-		break;
-	case YAHOO_STATUS_ONPHONE:
-		status = YAHOO_STATUS_TYPE_ONPHONE;
-		break;
-	case YAHOO_STATUS_ONVACATION:
-		status = YAHOO_STATUS_TYPE_ONVACATION;
-		break;
-	case YAHOO_STATUS_OUTTOLUNCH:
-		status = YAHOO_STATUS_TYPE_OUTTOLUNCH;
-		break;
-	case YAHOO_STATUS_STEPPEDOUT:
-		status = YAHOO_STATUS_TYPE_STEPPEDOUT;
-		break;
-	case YAHOO_STATUS_INVISIBLE: /* this should never happen? */
-		status = YAHOO_STATUS_TYPE_INVISIBLE;
-		break;
-	case YAHOO_STATUS_CUSTOM:
-	case YAHOO_STATUS_IDLE:
-		if (!f->away)
-			status = YAHOO_STATUS_TYPE_AVAILABLE;
-		else
-			status = YAHOO_STATUS_TYPE_AWAY;
-		break;
-	default:
-		purple_debug_warning("yahoo", "Warning, unknown status %d\n", f->status);
-		break;
-	}
-
-	if (status) {
-		if (f->status == YAHOO_STATUS_CUSTOM)
-			purple_protocol_got_user_status(purple_connection_get_account(gc), name, status, "message",
-			                          yahoo_friend_get_status_message(f), NULL);
-		else
-			purple_protocol_got_user_status(purple_connection_get_account(gc), name, status, NULL);
-	}
-
-	if (f->idle != 0)
-		purple_protocol_got_user_idle(purple_connection_get_account(gc), name, TRUE, f->idle);
-	else
-		purple_protocol_got_user_idle(purple_connection_get_account(gc), name, FALSE, 0);
-
-	if (f->sms)
-		purple_protocol_got_user_status(purple_connection_get_account(gc), name, YAHOO_STATUS_TYPE_MOBILE, NULL);
-	else
-		purple_protocol_got_user_status_deactive(purple_connection_get_account(gc), name, YAHOO_STATUS_TYPE_MOBILE);
-}
-
-static void yahoo_process_status(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	PurpleAccount *account = purple_connection_get_account(gc);
-	GSList *l = pkt->hash;
-	YahooFriend *f = NULL;
-	char *name = NULL;
-	gboolean unicode = FALSE;
-	char *message = NULL;
-
-	if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
-		if (!purple_account_get_remember_password(account))
-			purple_account_set_password(account, NULL, NULL, NULL);
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NAME_IN_USE,
-			_("You have signed on from another location"));
-		return;
-	}
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 0: /* we won't actually do anything with this */
-		case 1: /* we won't actually do anything with this */
-			break;
-		case 8: /* how many online buddies we have */
-			break;
-		case 7: /* the current buddy */
-			/* update the previous buddy before changing the variables */
-			if (f) {
-				if (message)
-					yahoo_friend_set_status_message(f, yahoo_string_decode(gc, message, unicode));
-				if (name)
-					yahoo_update_status(gc, name, f);
-			}
-			name = message = NULL;
-			f = NULL;
-			if (pair->value && g_utf8_validate(pair->value, -1, NULL)) {
-				name = pair->value;
-				f = yahoo_friend_find_or_new(gc, name);
-			}
-			break;
-		case 10: /* state */
-			if (!f)
-				break;
-
-			f->status = strtol(pair->value, NULL, 10);
-			if ((f->status >= YAHOO_STATUS_BRB) && (f->status <= YAHOO_STATUS_STEPPEDOUT))
-				f->away = 1;
-			else
-				f->away = 0;
-
-			if (f->status == YAHOO_STATUS_IDLE) {
-				/* Idle may have already been set in a more precise way in case 137 */
-				if (f->idle == 0)
-				{
-					if(pkt->service == YAHOO_SERVICE_STATUS_15)
-						f->idle = -1;
-					else
-						f->idle = time(NULL);
-				}
-			} else
-				f->idle = 0;
-
-			if (f->status != YAHOO_STATUS_CUSTOM)
-				yahoo_friend_set_status_message(f, NULL);
-
-			f->sms = 0;
-			break;
-		case 19: /* custom message */
-			if (f)
-				message = pair->value;
-			break;
-		case 11: /* this is the buddy's session id */
-			if (f)
-				f->session_id = strtol(pair->value, NULL, 10);
-			break;
-		case 17: /* in chat? */
-			break;
-		case 47: /* is custom status away or not? 2=idle*/
-			if (!f)
-				break;
-
-			/* I have no idea what it means when this is
-			 * set when someone's available, but it doesn't
-			 * mean idle. */
-			if (f->status == YAHOO_STATUS_AVAILABLE)
-				break;
-
-			f->away = strtol(pair->value, NULL, 10);
-			if (f->away == 2) {
-				/* Idle may have already been set in a more precise way in case 137 */
-				if (f->idle == 0)
-				{
-					if(pkt->service == YAHOO_SERVICE_STATUS_15)
-						f->idle = -1;
-					else
-						f->idle = time(NULL);
-				}
-			}
-
-			break;
-		case 138: /* when value is 1, either we're not idle, or we are but won't say how long */
-			if (!f)
-				break;
-
-			if( (strtol(pair->value, NULL, 10) == 1) && (f->idle) )
-				f->idle = -1;
-			break;
-		case 137: /* usually idle time in seconds, sometimes login time */
-			if (!f)
-				break;
-
-			if (f->status != YAHOO_STATUS_AVAILABLE)
-				f->idle = time(NULL) - strtol(pair->value, NULL, 10);
-			break;
-		case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
-			if (strtol(pair->value, NULL, 10) == 0) {
-				if (f)
-					f->status = YAHOO_STATUS_OFFLINE;
-				if (name) {
-					purple_protocol_got_user_status(account, name, "offline", NULL);
-					purple_protocol_got_user_status_deactive(account, name, YAHOO_STATUS_TYPE_MOBILE);
-				}
-				break;
-			}
-			break;
-		case 60: /* SMS */
-			if (f) {
-				f->sms = strtol(pair->value, NULL, 10);
-				yahoo_update_status(gc, name, f);
-			}
-			break;
-		case 197: /* Avatars */
-		{
-			guchar *decoded;
-			char *tmp;
-			gsize len;
-
-			if (pair->value) {
-				decoded = purple_base64_decode(pair->value, &len);
-				if (decoded && len > 0) {
-					tmp = purple_str_binary_to_ascii(decoded, len);
-					purple_debug_info("yahoo", "Got key 197, value = %s\n", tmp);
-					g_free(tmp);
-				}
-				g_free(decoded);
-			}
-			break;
-		}
-		case 192: /* Pictures, aka Buddy Icons, checksum */
-		{
-			/* FIXME: Please, if you know this protocol,
-			 * FIXME: fix up the strtol() stuff if possible. */
-			int cksum = strtol(pair->value, NULL, 10);
-			const char *locksum = NULL;
-			PurpleBuddy *b;
-
-			if (!name)
-				break;
-
-			b = purple_blist_find_buddy(purple_connection_get_account(gc), name);
-
-			if (!cksum || (cksum == -1)) {
-				if (f)
-					yahoo_friend_set_buddy_icon_need_request(f, TRUE);
-				purple_buddy_icons_set_for_user(purple_connection_get_account(gc), name, NULL, 0, NULL);
-				break;
-			}
-
-			if (!f)
-				break;
-
-			yahoo_friend_set_buddy_icon_need_request(f, FALSE);
-			if (b) {
-				locksum = purple_buddy_icons_get_checksum_for_user(b);
-				if (!locksum || (cksum != strtol(locksum, NULL, 10)))
-					yahoo_send_picture_request(gc, name);
-			}
-
-			break;
-		}
-		case 16: /* Custom error message */
-			{
-				char *tmp = yahoo_string_decode(gc, pair->value, TRUE);
-				purple_notify_error(gc, NULL, tmp, NULL,
-					purple_request_cpar_from_connection(gc));
-				g_free(tmp);
-			}
-			break;
-		case 97: /* Unicode status message */
-			unicode = !strcmp(pair->value, "1");
-			break;
-		case 244: /* client version number. Yahoo Client Detection */
-			if(f && strtol(pair->value, NULL, 10))
-				f->version_id = strtol(pair->value, NULL, 10);
-			break;
-		default:
-			purple_debug_warning("yahoo",
-					   "Unknown status key %d\n", pair->key);
-			break;
-		}
-
-		l = l->next;
-	}
-
-	if (f) {
-		if (pkt->service == YAHOO_SERVICE_LOGOFF)
-			f->status = YAHOO_STATUS_OFFLINE;
-		if (message)
-			yahoo_friend_set_status_message(f, yahoo_string_decode(gc, message, unicode));
-
-		if (name) /* update the last buddy */
-			yahoo_update_status(gc, name, f);
-	}
-}
-
-static void yahoo_do_group_check(PurpleAccount *account, GHashTable *ht, const char *name, const char *group)
-{
-	PurpleBuddy *b;
-	PurpleGroup *g;
-	GSList *list, *i;
-	gboolean onlist = FALSE;
-	char *oname = NULL;
-
-	if (g_hash_table_lookup_extended(ht, name, (gpointer *)&oname, (gpointer *)&list))
-		g_hash_table_steal(ht, oname);
-	else
-		list = purple_blist_find_buddies(account, name);
-
-	for (i = list; i; i = i->next) {
-		b = i->data;
-		g = purple_buddy_get_group(b);
-		if (!purple_utf8_strcasecmp(group, purple_group_get_name(g))) {
-			purple_debug_misc("yahoo",
-				"Oh good, %s is in the right group (%s).\n", name, group);
-			list = g_slist_delete_link(list, i);
-			onlist = TRUE;
-			break;
-		}
-	}
-
-	if (!onlist) {
-		purple_debug_misc("yahoo",
-			"Uhoh, %s isn't on the list (or not in this group), adding him to group %s.\n", name, group);
-		if (!(g = purple_blist_find_group(group))) {
-			g = purple_group_new(group);
-			purple_blist_add_group(g, NULL);
-		}
-		b = purple_buddy_new(account, name, NULL);
-		purple_blist_add_buddy(b, NULL, g, NULL);
-	}
-
-	if (list) {
-		if (!oname)
-			oname = g_strdup(name);
-		g_hash_table_insert(ht, oname, list);
-	} else
-		g_free(oname);
-}
-
-static void yahoo_do_group_cleanup(gpointer key, gpointer value, gpointer user_data)
-{
-	char *name = key;
-	GSList *list = value, *i;
-	PurpleBuddy *b;
-	PurpleGroup *g;
-
-	for (i = list; i; i = i->next) {
-		b = i->data;
-		g = purple_buddy_get_group(b);
-		purple_debug_misc("yahoo", "Deleting Buddy %s from group %s.\n", name,
-				purple_group_get_name(g));
-		purple_blist_remove_buddy(b);
-	}
-}
-
-static char *_getcookie(char *rawcookie)
-{
-	char *cookie = NULL;
-	char *tmpcookie;
-	char *cookieend;
-
-	if (strlen(rawcookie) < 2)
-		return NULL;
-	tmpcookie = g_strdup(rawcookie+2);
-	cookieend = strchr(tmpcookie, ';');
-
-	if (cookieend)
-		*cookieend = '\0';
-
-	cookie = g_strdup(tmpcookie);
-	g_free(tmpcookie);
-
-	return cookie;
-}
-
-static void yahoo_process_cookie(YahooData *yd, char *c)
-{
-	if (c[0] == 'Y') {
-		g_free(yd->cookie_y);
-		yd->cookie_y = _getcookie(c);
-	} else if (c[0] == 'T') {
-		g_free(yd->cookie_t);
-		yd->cookie_t = _getcookie(c);
-	} else
-		purple_debug_info("yahoo", "Unrecognized cookie '%c'\n", c[0]);
-	yd->cookies = g_slist_prepend(yd->cookies, g_strdup(c));
-}
-
-static void yahoo_process_list_15(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	GSList *l = pkt->hash;
-
-	PurpleAccount *account = purple_connection_get_account(gc);
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	GHashTable *ht;
-	char *norm_bud = NULL;
-	char *temp = NULL;
-	YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */
-	                       /* But what if you had no friends? */
-	int stealth = 0;
-
-	ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free);
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-		l = l->next;
-
-		switch (pair->key) {
-		case 302:
-			/* This is always 318 before a group, 319 before the first s/n in a group, 320 before any ignored s/n.
-			 * It is not sent for s/n's in a group after the first.
-			 * All ignored s/n's are listed last, so when we see a 320 we clear the group and begin marking the
-			 * s/n's as ignored.  It is always followed by an identical 300 key.
-			 */
-			if (pair->value && !strcmp(pair->value, "320")) {
-				/* No longer in any group; this indicates the start of the ignore list. */
-				g_free(yd->current_list15_grp);
-				yd->current_list15_grp = NULL;
-			}
-
-			break;
-		case 301: /* This is 319 before all s/n's in a group after the first. It is followed by an identical 300. */
-			if(temp != NULL) {
-				norm_bud = g_strdup(temp);
-
-				if (yd->current_list15_grp) {
-					/* This buddy is in a group */
-					f = yahoo_friend_find_or_new(gc, norm_bud);
-					if (!purple_blist_find_buddy(account, norm_bud)) {
-						PurpleBuddy *b;
-						PurpleGroup *g;
-						if (!(g = purple_blist_find_group(yd->current_list15_grp))) {
-							g = purple_group_new(yd->current_list15_grp);
-							purple_blist_add_group(g, NULL);
-						}
-						b = purple_buddy_new(account, norm_bud, NULL);
-						purple_blist_add_buddy(b, NULL, g, NULL);
-					}
-					yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp);
-
-					if(stealth == 2)
-						f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
-
-					yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
-					f->p2p_packet_sent = 0;
-				} 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_account_privacy_deny_add(account, norm_bud, 1);
-				}
-
-				g_free(norm_bud);
-				norm_bud=NULL;
-				stealth = 0;
-				g_free(temp);
-				temp = NULL;
-			}
-			break;
-		case 300: /* This is 318 before a group, 319 before any s/n in a group, and 320 before any ignored s/n. */
-			break;
-		case 65: /* This is the group */
-			g_free(yd->current_list15_grp);
-			yd->current_list15_grp = yahoo_string_decode(gc, pair->value, FALSE);
-			break;
-		case 7: /* buddy's s/n */
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				g_free(temp);
-				temp = g_strdup(purple_normalize(account, pair->value));
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_list_15 "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 59: /* somebody told cookies come here too, but im not sure */
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				yahoo_process_cookie(yd, pair->value);
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_list_15 "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 317: /* Stealth Setting */
-			stealth = strtol(pair->value, NULL, 10);
-			break;
-		}
-	}
-
-	g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL);
-
-	/* The reporter of ticket #9745 determined that we weren't retrieving the
-	 * aliases during buddy list retrieval, so we never updated aliases that
-	 * changed while we were signed off. */
-	yahoo_fetch_aliases(gc);
-
-	/* Now that we have processed the buddy list, we can say yahoo has connected */
-	purple_connection_set_display_name(gc, purple_normalize(account, purple_account_get_username(account)));
-	yd->logged_in = TRUE;
-	purple_debug_info("yahoo","Authentication: Connection established\n");
-	purple_connection_set_state(gc, PURPLE_CONNECTION_CONNECTED);
-	if (yd->picture_upload_todo) {
-		yahoo_buddy_icon_upload(gc, yd->picture_upload_todo);
-		yd->picture_upload_todo = NULL;
-	}
-	yahoo_set_status(account, purple_account_get_active_status(account));
-
-	g_hash_table_destroy(ht);
-	g_free(temp);
-}
-
-static void yahoo_process_list(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	GSList *l = pkt->hash;
-	gboolean got_serv_list = FALSE;
-	YahooFriend *f = NULL;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	GHashTable *ht;
-
-	char **lines;
-	char **split;
-	char **buddies;
-	char **tmp, **bud, *norm_bud;
-	char *grp = NULL;
-
-	if (pkt->id)
-		yd->session_id = pkt->id;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-		l = l->next;
-
-		switch (pair->key) {
-		case 87:
-			if (!yd->tmp_serv_blist)
-				yd->tmp_serv_blist = g_string_new(pair->value);
-			else
-				g_string_append(yd->tmp_serv_blist, pair->value);
-			break;
-		case 88:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				if (!yd->tmp_serv_ilist)
-					yd->tmp_serv_ilist = g_string_new(pair->value);
-				else
-					g_string_append(yd->tmp_serv_ilist, pair->value);
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_list "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 89:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				yd->profiles = g_strsplit(pair->value, ",", -1);
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_list "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 59: /* cookies, yum */
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				yahoo_process_cookie(yd, pair->value);
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_list "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case YAHOO_SERVICE_PRESENCE_PERM:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				if (!yd->tmp_serv_plist)
-					yd->tmp_serv_plist = g_string_new(pair->value);
-				else
-					g_string_append(yd->tmp_serv_plist, pair->value);
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_list "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		}
-	}
-
-	if (pkt->status != 0)
-		return;
-
-	if (yd->tmp_serv_blist) {
-		ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free);
-
-		lines = g_strsplit(yd->tmp_serv_blist->str, "\n", -1);
-		for (tmp = lines; *tmp; tmp++) {
-			split = g_strsplit(*tmp, ":", 2);
-			if (!split)
-				continue;
-			if (!split[0] || !split[1]) {
-				g_strfreev(split);
-				continue;
-			}
-			grp = yahoo_string_decode(gc, split[0], FALSE);
-			buddies = g_strsplit(split[1], ",", -1);
-			for (bud = buddies; bud && *bud; bud++) {
-				if (!g_utf8_validate(*bud, -1, NULL)) {
-					purple_debug_warning("yahoo", "yahoo_process_list "
-							"got non-UTF-8 string for bud\n");
-					continue;
-				}
-
-				norm_bud = g_strdup(purple_normalize(account, *bud));
-				f = yahoo_friend_find_or_new(gc, norm_bud);
-
-				if (!purple_blist_find_buddy(account, norm_bud)) {
-					PurpleBuddy *b;
-					PurpleGroup *g;
-					if (!(g = purple_blist_find_group(grp))) {
-						g = purple_group_new(grp);
-						purple_blist_add_group(g, NULL);
-					}
-					b = purple_buddy_new(account, norm_bud, NULL);
-					purple_blist_add_buddy(b, NULL, g, NULL);
-				}
-
-				yahoo_do_group_check(account, ht, norm_bud, grp);
-				/* set p2p status not connected and no p2p packet sent */
-				yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
-				f->p2p_packet_sent = 0;
-
-				g_free(norm_bud);
-			}
-			g_strfreev(buddies);
-			g_strfreev(split);
-			g_free(grp);
-		}
-		g_strfreev(lines);
-
-		g_string_free(yd->tmp_serv_blist, TRUE);
-		yd->tmp_serv_blist = NULL;
-		g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL);
-		g_hash_table_destroy(ht);
-	}
-
-	if (yd->tmp_serv_ilist) {
-		buddies = g_strsplit(yd->tmp_serv_ilist->str, ",", -1);
-		for (bud = buddies; bud && *bud; bud++) {
-			/* The server is already ignoring the user */
-			got_serv_list = TRUE;
-			purple_account_privacy_deny_add(account, *bud, 1);
-		}
-		g_strfreev(buddies);
-
-		g_string_free(yd->tmp_serv_ilist, TRUE);
-		yd->tmp_serv_ilist = NULL;
-	}
-
-	if (got_serv_list &&
-		((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_ACCOUNT_PRIVACY_DENY_USERS);
-		purple_debug_info("yahoo", "%s privacy defaulting to PURPLE_ACCOUNT_PRIVACY_DENY_USERS.\n",
-				purple_account_get_username(account));
-	}
-
-	if (yd->tmp_serv_plist) {
-		buddies = g_strsplit(yd->tmp_serv_plist->str, ",", -1);
-		for (bud = buddies; bud && *bud; bud++) {
-			f = yahoo_friend_find(gc, *bud);
-			if (f) {
-				purple_debug_info("yahoo", "%s setting presence for %s to PERM_OFFLINE\n",
-						purple_account_get_username(account), *bud);
-				f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
-			}
-		}
-		g_strfreev(buddies);
-		g_string_free(yd->tmp_serv_plist, TRUE);
-		yd->tmp_serv_plist = NULL;
-
-	}
-	/* Now that we've got the list, request aliases */
-	yahoo_fetch_aliases(gc);
-}
-
-/* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
-static void yahoo_process_notify(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type)
-{
-	PurpleAccount *account;
-	char *msg = NULL;
-	char *from = NULL;
-	char *stat = NULL;
-	char *game = NULL;
-	YahooFriend *f = NULL;
-	GSList *l = pkt->hash;
-	gint val_11 = 0;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-
-	account = purple_connection_get_account(gc);
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-		if (pair->key == 4 || pair->key == 1) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				from = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_notify "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		} else if (pair->key == 49) {
-			msg = pair->value;
-		} else if (pair->key == 13) {
-			stat = pair->value;
-		} else if (pair->key == 14) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				game = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_notify "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		} else if (pair->key == 11) {
-			val_11 = strtol(pair->value, NULL, 10);
-		}
-		l = l->next;
-	}
-
-	if (!from || !msg)
-		return;
-
-	/* disconnect the peer if connected through p2p and sends wrong value for session id */
-	if ((pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id)) {
-		purple_debug_warning("yahoo","p2p: %s sent us notify with wrong session id. Disconnecting p2p connection to peer\n", from);
-		/* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
-		g_hash_table_remove(yd->peers, from);
-		return;
-	}
-
-	if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING"))
-		&& (purple_account_privacy_check(account, from)))
-	{
-
-		if (stat && *stat == '1')
-			purple_serv_got_typing(gc, from, 0, PURPLE_IM_TYPING);
-		else
-			purple_serv_got_typing_stopped(gc, from);
-
-	} else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) {
-		PurpleBuddy *bud = purple_blist_find_buddy(account, from);
-
-		if (!bud) {
-			purple_debug_warning("yahoo",
-					   "%s is playing a game, and doesn't want you to know.\n", from);
-		}
-
-		f = yahoo_friend_find(gc, from);
-		if (!f)
-			return; /* if they're not on the list, don't bother */
-
-		yahoo_friend_set_game(f, NULL);
-
-		if (stat && *stat == '1') {
-			yahoo_friend_set_game(f, game);
-			if (bud)
-				yahoo_update_status(gc, from, f);
-		}
-	} else if (!g_ascii_strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) {
-		PurpleIMConversation *im = purple_conversations_find_im_with_account(from, account);
-		char *buf = g_strdup_printf(_("%s has sent you a webcam invite, which is not yet supported."), from);
-		purple_conversation_write_system_message(PURPLE_CONVERSATION(im),
-			buf, PURPLE_MESSAGE_NOTIFY);
-		g_free(buf);
-	}
-}
-
-
-struct _yahoo_im {
-	char *from;
-	char *active_id;
-	int time;
-	int utf8;
-	int buddy_icon;
-	char *id;
-	char *msg;
-};
-
-static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	PurpleAccount *account;
-	GSList *l = pkt->hash;
-	struct _yahoo_im *sms = NULL;
-	YahooData *yd;
-	char *server_msg = NULL;
-	char *m;
-
-	yd = purple_connection_get_protocol_data(gc);
-	account = purple_connection_get_account(gc);
-
-	while (l != NULL) {
-		struct yahoo_pair *pair = l->data;
-		if (pair->key == 4) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				sms = g_new0(struct _yahoo_im, 1);
-				sms->from = g_strdup_printf("+%s", pair->value);
-				sms->time = time(NULL);
-				sms->utf8 = TRUE;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_sms_message "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		} else if (pair->key == 14) {
-			if (sms)
-				sms->msg = pair->value;
-		} else if (pair->key == 68) {
-			if(sms)
-				g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value));
-		} else if (pair->key == 16) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				server_msg = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_sms_message "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		}
-		l = l->next;
-	}
-
-	if(!sms) {
-		purple_debug_info("yahoo", "Received a malformed SMS packet!\n");
-		return;
-	}
-
-	if ((int)pkt->status < 0)
-		pkt->status = YAHOO_STATUS_DISCONNECTED;
-	if (pkt->status == YAHOO_STATUS_DISCONNECTED) {
-		if (server_msg) {
-			PurpleIMConversation *im;
-			im = purple_conversations_find_im_with_account(sms->from, account);
-			if (im == NULL)
-				im = purple_im_conversation_new(account, sms->from);
-			purple_conversation_write_system_message(PURPLE_CONVERSATION(im),
-				server_msg, 0);
-		}
-		else {
-			purple_notify_error(gc, NULL,
-				_("Your SMS was not delivered"), NULL,
-				purple_request_cpar_from_connection(gc));
-		}
-
-		g_free(sms->from);
-		g_free(sms);
-		return ;
-	}
-
-	if (!sms->from || !sms->msg) {
-		g_free(sms);
-		return;
-	}
-
-	m = yahoo_string_decode(gc, sms->msg, sms->utf8);
-	purple_serv_got_im(gc, sms->from, m, 0, sms->time);
-
-	g_free(m);
-	g_free(sms->from);
-	g_free(sms);
-}
-
-/* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
-static void yahoo_process_message(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type)
-{
-	PurpleAccount *account;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	GSList *l = pkt->hash;
-	GSList *list = NULL;
-	struct _yahoo_im *im = NULL;
-
-	account = purple_connection_get_account(gc);
-
-	if (pkt->status <= 1 || pkt->status == 5 || pkt->status == YAHOO_STATUS_OFFLINE) {
-	/* messages are received with status YAHOO_STATUS_OFFLINE in case of p2p */
-		while (l != NULL) {
-			struct yahoo_pair *pair = l->data;
-			if (pair->key == 4 || pair->key == 1) {
-				if (g_utf8_validate(pair->value, -1, NULL)) {
-					im = g_new0(struct _yahoo_im, 1);
-					list = g_slist_append(list, im);
-					im->from = pair->value;
-					im->time = time(NULL);
-					im->utf8 = TRUE;
-				} else {
-					purple_debug_warning("yahoo", "yahoo_process_message "
-							"got non-UTF-8 string for key %d\n", pair->key);
-				}
-			} else if (im && pair->key == 5) {
-				im->active_id = pair->value;
-			} else if (pair->key == 97) {
-				if (im)
-					im->utf8 = strtol(pair->value, NULL, 10);
-			} else if (pair->key == 15) {
-				if (im)
-					im->time = strtol(pair->value, NULL, 10);
-			} else if (pair->key == 206) {
-				if (im)
-					im->buddy_icon = strtol(pair->value, NULL, 10);
-			} else if (pair->key == 14) {
-				if (im)
-					im->msg = pair->value;
-			} else if (im && (pair->key == 11)) {
-				/* peer session id */
-				/* disconnect the peer if connected through p2p and sends wrong value for session id */
-				if( (pkt_type == YAHOO_PKT_TYPE_P2P)
-						&& (yd->session_id != strtol(pair->value, NULL, 10)) )
-				{
-					purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im->from);
-					/* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
-					g_hash_table_remove(yd->peers, im->from);
-					g_free(im);
-					return; /* Not sure whether we should process remaining IMs in this packet */
-				}
-
-			} else if (im && pair->key == 63 && g_utf8_validate(pair->value, -1, NULL)) {
-				/* IMV key */
-				/* Check for the Doodle IMV */
-				if (im->from != NULL)
-				{
-					g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(pair->value));
-
-					if (strstr(pair->value, "doodle;") != NULL)
-					{
-						PurpleWhiteboard *wb;
-
-						if (!purple_account_privacy_check(account, im->from)) {
-							purple_debug_info("yahoo", "Doodle request from %s dropped.\n",
-												im->from);
-							g_free(im);
-							return;
-						}
-						/* I'm not sure the following ever happens -DAA */
-						wb = purple_whiteboard_get_session(account, im->from);
-
-						/* If a Doodle session doesn't exist between this user */
-						if(wb == NULL)
-						{
-							doodle_session *ds;
-							wb = purple_whiteboard_new(account, im->from,
-											DOODLE_STATE_REQUESTED);
-							ds = purple_whiteboard_get_protocol_data(wb);
-							ds->imv_key = g_strdup(pair->value);
-
-							yahoo_doodle_command_send_request(gc, im->from, pair->value);
-							yahoo_doodle_command_send_ready(gc, im->from, pair->value);
-						}
-					}
-				}
-			} else if (pair->key == 429) {
-				if (im)
-					im->id = pair->value;
-			}
-			l = l->next;
-		}
-	} else if (pkt->status == 2) {
-		purple_notify_error(gc, NULL,
-			_("Your Yahoo! message did not get sent."), NULL,
-			purple_request_cpar_from_connection(gc));
-	}
-
-	for (l = list; l; l = l->next) {
-		char *m, *m2;
-		im = l->data;
-
-		if (!im->msg) {
-			g_free(im);
-			continue;
-		}
-
-		if (!purple_account_privacy_check(account, im->from)) {
-			purple_debug_info("yahoo", "Message from %s dropped.\n", im->from);
-			return;
-		}
-
-		/*
-		 * TODO: Is there anything else we should check when determining whether
-		 *       we should send an acknowledgement?
-		 */
-		if (im->id != NULL) {
-			/* Send acknowledgement.  If we don't do this then the official
-			 * Yahoo Messenger client for Windows will send us the same
-			 * message 7 seconds later as an offline message.  This is true
-			 * for at least version 9.0.0.2162 on Windows XP. */
-			struct yahoo_packet *pkt2;
-			pkt2 = yahoo_packet_new(YAHOO_SERVICE_MESSAGE_ACK,
-					YAHOO_STATUS_AVAILABLE, pkt->id);
-			yahoo_packet_hash(pkt2, "ssisii",
-					1, im->active_id,  /* May not always be the connection's display name */
-					5, im->from,
-					302, 430,
-					430, im->id,
-					303, 430,
-					450, 0);
-			yahoo_packet_send_and_free(pkt2, yd);
-		}
-
-		m = yahoo_string_decode(gc, im->msg, im->utf8);
-		/* This may actually not be necessary, but it appears
-		 * that at least at one point some clients were sending
-		 * "\r\n" as line delimiters, so we want to avoid double
-		 * lines. */
-		m2 = purple_strreplace(m, "\r\n", "\n");
-		g_free(m);
-		m = m2;
-		purple_util_chrreplace(m, '\r', '\n');
-		if (!strcmp(m, "<ding>")) {
-			char *username;
-
-			username = g_markup_escape_text(im->from, -1);
-			purple_protocol_got_attention(gc, username, YAHOO_BUZZ);
-			g_free(username);
-			g_free(m);
-			g_free(im);
-			continue;
-		}
-
-		m2 = yahoo_codes_to_html(m);
-		g_free(m);
-
-		purple_serv_got_im(gc, im->from, m2, 0, im->time);
-		g_free(m2);
-		g_free(im);
-	}
-
-	g_slist_free(list);
-}
-
-static void yahoo_process_sysmessage(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	GSList *l = pkt->hash;
-	char *prim, *me = NULL, *msg = NULL;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		if (pair->key == 5) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				me = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_sysmessage "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		} else if (pair->key == 14) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				msg = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_sysmessage "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		}
-
-		l = l->next;
-	}
-
-	if (!msg || !g_utf8_validate(msg, -1, NULL))
-		return;
-
-	prim = g_strdup_printf(_("Yahoo! system message for %s:"),
-	                       me?me:purple_connection_get_display_name(gc));
-	purple_notify_info(NULL, NULL, prim, msg,
-		purple_request_cpar_from_connection(gc));
-	g_free(prim);
-}
-
-struct yahoo_add_request {
-	PurpleConnection *gc;
-	char *id;
-	char *who;
-};
-
-static void
-yahoo_buddy_add_authorize_cb(const char *message, gpointer data)
-{
-	struct yahoo_add_request *add_req = data;
-	struct yahoo_packet *pkt;
-	YahooData *yd = purple_connection_get_protocol_data(add_req->gc);
-	const char *who = add_req->who;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash(pkt, "ssii",
-					  1, add_req->id,
-					  5, who,
-					  13, 1,
-					  334, 0);
-
-	yahoo_packet_send_and_free(pkt, yd);
-
-	g_free(add_req->id);
-	g_free(add_req->who);
-	g_free(add_req);
-}
-
-static void
-yahoo_buddy_add_deny_cb(const char *msg, gpointer data)
-{
-	struct yahoo_add_request *add_req = data;
-	YahooData *yd = purple_connection_get_protocol_data(add_req->gc);
-	struct yahoo_packet *pkt;
-	char *encoded_msg = NULL;
-	const char *who = add_req->who;
-
-	if (msg && *msg)
-		encoded_msg = yahoo_string_encode(add_req->gc, msg, FALSE);
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15,
-			YAHOO_STATUS_AVAILABLE, yd->session_id);
-
-	yahoo_packet_hash(pkt, "ssiiis",
-					  1, add_req->id,
-					  5, who,
-					  13, 2,
-					  334, 0,
-					  97, 1, /* UTF-8 */
-					  14, encoded_msg ? encoded_msg : "");
-
-
-	yahoo_packet_send_and_free(pkt, yd);
-
-	g_free(encoded_msg);
-
-	g_free(add_req->id);
-	g_free(add_req->who);
-	g_free(add_req);
-}
-
-static void yahoo_buddy_denied_our_add(PurpleConnection *gc, const char *who, const char *reason)
-{
-	char *notify_msg;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-
-	if (who == NULL)
-		return;
-
-	if (reason != NULL) {
-		char *msg2 = yahoo_string_decode(gc, reason, FALSE);
-		notify_msg = g_strdup_printf(_("%s has (retroactively) denied your request to add them to your list for the following reason: %s."), who, msg2);
-		g_free(msg2);
-	} else
-		notify_msg = g_strdup_printf(_("%s has (retroactively) denied your request to add them to your list."), who);
-
-	purple_notify_info(gc, NULL, _("Add buddy rejected"), notify_msg,
-		purple_request_cpar_from_connection(gc));
-	g_free(notify_msg);
-
-	g_hash_table_remove(yd->friends, who);
-	purple_protocol_got_user_status(purple_connection_get_account(gc), who, "offline", NULL); /* FIXME: make this set not on list status instead */
-	/* TODO: Shouldn't we remove the buddy from our local list? */
-}
-
-static void yahoo_buddy_auth_req_15(PurpleConnection *gc, struct yahoo_packet *pkt) {
-	PurpleAccount *account;
-	GSList *l = pkt->hash;
-	const char *msg = NULL;
-
-	account = purple_connection_get_account(gc);
-
-	/* Buddy authorized/declined our addition */
-	if (pkt->status == 1) {
-		char *who = NULL;
-		int response = 0;
-
-		while (l) {
-			struct yahoo_pair *pair = l->data;
-
-			switch (pair->key) {
-			case 4:
-				break;
-			case 13:
-				response = strtol(pair->value, NULL, 10);
-				break;
-			case 14:
-				msg = pair->value;
-				break;
-			}
-			l = l->next;
-		}
-
-		if (response == 1) /* Authorized */
-			purple_debug_info("yahoo", "Received authorization from buddy '%s'.\n", who ? who : "(Unknown Buddy)");
-		else if (response == 2) { /* Declined */
-			purple_debug_info("yahoo", "Received authorization decline from buddy '%s'.\n", who ? who : "(Unknown Buddy)");
-			yahoo_buddy_denied_our_add(gc, who, msg);
-		} else
-			purple_debug_error("yahoo", "Received unknown authorization response of %d from buddy '%s'.\n", response, who ? who : "(Unknown Buddy)");
-		g_free(who);
-	}
-	/* Buddy requested authorization to add us. */
-	else if (pkt->status == 3) {
-		struct yahoo_add_request *add_req;
-		const char *firstname = NULL, *lastname = NULL;
-
-		add_req = g_new0(struct yahoo_add_request, 1);
-		add_req->gc = gc;
-
-		while (l) {
-			struct yahoo_pair *pair = l->data;
-
-			switch (pair->key) {
-			case 4:
-				break;
-			case 5:
-				if (g_utf8_validate(pair->value, -1, NULL)) {
-					add_req->id = g_strdup(pair->value);
-				} else {
-					purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
-							"got non-UTF-8 string for key %d\n", pair->key);
-				}
-				break;
-			case 14:
-				msg = pair->value;
-				break;
-			case 216:
-				if (g_utf8_validate(pair->value, -1, NULL)) {
-					firstname = pair->value;
-				} else {
-					purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
-							"got non-UTF-8 string for key %d\n", pair->key);
-				}
-				break;
-			case 254:
-				if (g_utf8_validate(pair->value, -1, NULL)) {
-					lastname = pair->value;
-				} else {
-					purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
-							"got non-UTF-8 string for key %d\n", pair->key);
-				}
-				break;
-
-			}
-			l = l->next;
-		}
-
-		if (add_req->id && add_req->who) {
-			char *alias = NULL, *dec_msg = NULL;
-
-			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);
-				return;
-			}
-
-			if (msg)
-				dec_msg = yahoo_string_decode(gc, msg, FALSE);
-
-			if (firstname && lastname)
-				alias = g_strdup_printf("%s %s", firstname, lastname);
-			else if (firstname)
-				alias = g_strdup(firstname);
-			else if (lastname)
-				alias = g_strdup(lastname);
-
-			/* DONE! this is almost exactly the same as what MSN does,
-			 * this should probably be moved to the core.
-			 */
-			 purple_account_request_authorization(account, add_req->who, add_req->id,
-					alias, dec_msg,
-					purple_blist_find_buddy(account, add_req->who) != NULL,
-					yahoo_buddy_add_authorize_cb,
-					yahoo_buddy_add_deny_cb,
-					add_req);
-			g_free(alias);
-			g_free(dec_msg);
-		} else {
-			g_free(add_req->id);
-			g_free(add_req->who);
-			g_free(add_req);
-		}
-	} else {
-		purple_debug_error("yahoo", "Received authorization of unknown status (%d).\n", pkt->status);
-	}
-}
-
-/* I don't think this happens anymore in Version 15 */
-static void yahoo_buddy_added_us(PurpleConnection *gc, struct yahoo_packet *pkt) {
-	PurpleAccount *account;
-	struct yahoo_add_request *add_req;
-	char *msg = NULL;
-	GSList *l = pkt->hash;
-
-	account = purple_connection_get_account(gc);
-
-	add_req = g_new0(struct yahoo_add_request, 1);
-	add_req->gc = gc;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 1:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				add_req->id = g_strdup(pair->value);
-			} else {
-					purple_debug_warning("yahoo", "yahoo_buddy_added_us "
-							"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 3:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				add_req->who = g_strdup(pair->value);
-			} else {
-					purple_debug_warning("yahoo", "yahoo_buddy_added_us "
-							"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 15: /* time, for when they add us and we're offline */
-			break;
-		case 14:
-			msg = pair->value;
-			break;
-		}
-		l = l->next;
-	}
-
-	if (add_req->id && add_req->who) {
-		char *dec_msg = NULL;
-
-		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);
-			return;
-		}
-
-		if (msg)
-			dec_msg = yahoo_string_decode(gc, msg, FALSE);
-
-		/* DONE! this is almost exactly the same as what MSN does,
-		 * this should probably be moved to the core.
-		 */
-		 purple_account_request_authorization(account, add_req->who, add_req->id,
-				NULL, dec_msg,
-				purple_blist_find_buddy(account,add_req->who) != NULL,
-						yahoo_buddy_add_authorize_cb,
-						yahoo_buddy_add_deny_cb, add_req);
-		g_free(dec_msg);
-	} else {
-		g_free(add_req->id);
-		g_free(add_req->who);
-		g_free(add_req);
-	}
-}
-
-/* I have no idea if this every gets called in version 15 */
-static void yahoo_buddy_denied_our_add_old(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	char *who = NULL;
-	char *msg = NULL;
-	GSList *l = pkt->hash;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 3:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				who = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 14:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				msg = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		}
-		l = l->next;
-	}
-
-	yahoo_buddy_denied_our_add(gc, who, msg);
-}
-
-static void yahoo_process_contact(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	switch (pkt->status) {
-	case 1:
-		yahoo_process_status(gc, pkt);
-		return;
-	case 3:
-		yahoo_buddy_added_us(gc, pkt);
-		break;
-	case 7:
-		yahoo_buddy_denied_our_add_old(gc, pkt);
-		break;
-	default:
-		break;
-	}
-}
-
-#define OUT_CHARSET "utf-8"
-
-static char *yahoo_decode(const char *text)
-{
-	char *converted = NULL;
-	char *n, *new;
-	const char *end, *p;
-	int i, k;
-
-	n = new = g_malloc(strlen (text) + 1);
-	end = text + strlen(text);
-
-	for (p = text; p < end; p++, n++) {
-		if (*p == '\\') {
-			if (p[1] >= '0' && p[1] <= '7') {
-				p += 1;
-				for (i = 0, k = 0; k < 3; k += 1) {
-					char c = p[k];
-					if (c < '0' || c > '7') break;
-					i *= 8;
-					i += c - '0';
-				}
-				*n = i;
-				p += k - 1;
-			} else { /* bug 959248 */
-				/* If we see a \ not followed by an octal number,
-				 * it means that it is actually a \\ with one \
-				 * already eaten by some unknown function.
-				 * This is arguably broken.
-				 *
-				 * I think wing is wrong here, there is no function
-				 * called that I see that could have done it. I guess
-				 * it is just really sending single \'s. That's yahoo
-				 * for you.
-				 */
-				*n = *p;
-			}
-		}
-		else
-			*n = *p;
-	}
-
-	*n = '\0';
-
-	/* XXX: Is this related to Yahoo! Japan? If so, it should be removed. -mmcco */
-	if (strstr(text, "\033$B"))
-		converted = g_convert(new, n - new, OUT_CHARSET, "iso-2022-jp", NULL, NULL, NULL);
-	if (!converted)
-		converted = g_convert(new, n - new, OUT_CHARSET, "iso-8859-1", NULL, NULL, NULL);
-	g_free(new);
-
-	return converted;
-}
-
-static void yahoo_process_mail(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	PurpleAccount *account = purple_connection_get_account(gc);
-	const char *who = NULL;
-	const char *email = NULL;
-	const char *subj = NULL;
-	const char *yahoo_mail_url = YAHOO_MAIL_URL;
-	int count = 0;
-	GSList *l = pkt->hash;
-
-	if (!purple_account_get_check_mail(account))
-		return;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-		if (pair->key == 9) {
-			count = strtol(pair->value, NULL, 10);
-		} else if (pair->key == 43) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				who = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_mail "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		} else if (pair->key == 42) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				email = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_mail "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		} else if (pair->key == 18) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				subj = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_mail "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		}
-		l = l->next;
-	}
-
-	if (who && subj && email && *email) {
-		char *dec_who = yahoo_decode(who);
-		char *dec_subj = yahoo_decode(subj);
-		char *from = g_strdup_printf("%s (%s)", dec_who, email);
-
-		purple_notify_email(gc, dec_subj, from, purple_account_get_username(account),
-						  yahoo_mail_url, NULL, NULL);
-
-		g_free(dec_who);
-		g_free(dec_subj);
-		g_free(from);
-	} else if (count > 0) {
-		const char *tos[2] = { purple_account_get_username(account) };
-		const char *urls[2] = { yahoo_mail_url };
-
-		purple_notify_emails(gc, count, FALSE, NULL, NULL, tos, urls,
-						   NULL, NULL);
-	}
-}
-
-/* We use this structure once while we authenticate */
-struct yahoo_auth_data
-{
-	PurpleConnection *gc;
-	char *seed;
-};
-
-/* This is the y64 alphabet... it's like base64, but has a . and a _ */
-static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
-
-/* This is taken from Sylpheed by Hiroyuki Yamamoto. We have our own tobase64 function
- * in util.c, but it is different from the one yahoo uses */
-static void to_y64(char *out, const unsigned char *in, gsize inlen)
-     /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
-{
-	for (; inlen >= 3; inlen -= 3)
-		{
-			*out++ = base64digits[in[0] >> 2];
-			*out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
-			*out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
-			*out++ = base64digits[in[2] & 0x3f];
-			in += 3;
-		}
-	if (inlen > 0)
-		{
-			unsigned char fragment;
-
-			*out++ = base64digits[in[0] >> 2];
-			fragment = (in[0] << 4) & 0x30;
-			if (inlen > 1)
-				fragment |= in[1] >> 4;
-			*out++ = base64digits[fragment];
-			*out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c];
-			*out++ = '-';
-		}
-	*out = '\0';
-}
-
-static void yahoo_auth16_stage3(PurpleConnection *gc, const char *crypt)
-{
-	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));
-	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");
-
-	g_return_if_fail(crypt != NULL);
-
-	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);
-
-	purple_debug_info("yahoo", "yahoo status: %d\n", yd->current_status);
-	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->current_status, yd->session_id);
-
-	if(yd->cookie_b) { /* send B cookie if we have it */
-		yahoo_packet_hash(pkt, "ssssssssss",
-					1, name,
-					0, name,
-					277, yd->cookie_y,
-					278, yd->cookie_t,
-					307, base64_string,
-					244, YAHOO_CLIENT_VERSION_ID,
-					2, name,
-					2, "1",
-					59, yd->cookie_b,
-					98, purple_account_get_string(account, "room_list_locale", "us"),
-					135, YAHOO_CLIENT_VERSION);
-	} else { /* don't try to send an empty B cookie - the server will be mad */
-		yahoo_packet_hash(pkt, "sssssssss",
-					1, name,
-					0, name,
-					277, yd->cookie_y,
-					278, yd->cookie_t,
-					307, base64_string,
-					244, YAHOO_CLIENT_VERSION_ID,
-					2, name,
-					2, "1",
-					98, purple_account_get_string(account, "room_list_locale", "us"),
-					135, YAHOO_CLIENT_VERSION);
-	}
-
-	if (yd->picture_checksum)
-		yahoo_packet_hash_int(pkt, 192, yd->picture_checksum);
-	yahoo_packet_send_and_free(pkt, yd);
-
-	g_object_unref(md5_hash);
-}
-
-static void yahoo_auth16_stage2(PurpleHttpConnection *http_conn,
-	PurpleHttpResponse *response, gpointer _auth_data)
-{
-	struct yahoo_auth_data *auth_data = _auth_data;
-	PurpleConnection *gc = auth_data->gc;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-
-	int i;
-	gchar **splits;
-	int response_no = -1;
-	char *crumb = NULL;
-	char *crypt = NULL;
-	PurpleHttpCookieJar *cookiejar;
-
-	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage2\n");
-
-	if (!purple_http_response_is_successful(response)) {
-		const gchar *error_message = purple_http_response_get_error(response);
-		purple_debug_error("yahoo", "Login Failed, unable to retrieve stage 2 url: %s\n", error_message);
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
-		g_free(auth_data->seed);
-		g_free(auth_data);
-		return;
-	}
-
-	splits = g_strsplit(purple_http_response_get_data(response, NULL),
-		"\r\n", -1);
-
-	cookiejar = purple_http_conn_get_cookie_jar(http_conn);
-	yd->cookie_b = purple_http_cookie_jar_get(cookiejar, "B");
-	yd->cookie_t = purple_http_cookie_jar_get(cookiejar, "T");
-	yd->cookie_y = purple_http_cookie_jar_get(cookiejar, "Y");
-
-	i = 0;
-	while (splits[i]) {
-		/* I'm not exactly a fan of the magic numbers, but it's obvious,
-		 * so no sense in wasting a bajillion vars or calls to strlen */
-
-		if (i == 0 && g_ascii_isdigit(splits[i][0])) {
-			response_no = strtol(splits[i], NULL, 10);
-			purple_debug_info("yahoo", "Got auth16 stage 2 response code: %d\n",
-				response_no);
-		} else if (strncmp(splits[i], "crumb=", 6) == 0) {
-			crumb = g_strdup(&splits[i][6]);
-
-			if (purple_debug_is_unsafe())
-				purple_debug_info("yahoo", "Got crumb: %s\n", crumb);
-		}
-		i++;
-	}
-
-	g_strfreev(splits);
-
-	if (crumb == NULL)
-		response_no = -1;
-
-	if(response_no != 0) {
-		/* Some error in the login process */
-		PurpleConnectionError error;
-		char *error_reason = NULL;
-
-		switch (response_no) {
-			case -1:
-				/* Some error in the received stream */
-				error_reason = g_strdup(_("Received invalid data"));
-				error = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
-				break;
-			case 100:
-				/* Unknown error */
-				error_reason = g_strdup(_("Unknown error"));
-				error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-				break;
-			default:
-				/* if we have everything we need, why not try to login irrespective of response */
-				if ((crumb != NULL) && (yd->cookie_y != NULL) && (yd->cookie_t != NULL)) {
-#if 0
-					try_login_on_error = TRUE;
-#endif
-					break;
-				}
-				error_reason = g_strdup(_("Unknown error"));
-				error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-				break;
-		}
-		if (error_reason) {
-			purple_debug_error("yahoo", "Authentication error: %s. "
-				"Code %d\n", error_reason, response_no);
-			purple_connection_error(gc, error, error_reason);
-			g_free(error_reason);
-			g_free(crumb);
-			g_free(auth_data->seed);
-			g_free(auth_data);
-			return;
-		}
-	}
-
-	crypt = g_strconcat(crumb, auth_data->seed, NULL);
-	yahoo_auth16_stage3(gc, crypt);
-	g_free(crypt);
-	g_free(crumb);
-	g_free(auth_data->seed);
-	g_free(auth_data);
-}
-
-static void yahoo_auth16_stage1_cb(PurpleHttpConnection *http_conn,
-	PurpleHttpResponse *response, gpointer _auth_data)
-{
-	struct yahoo_auth_data *auth_data = _auth_data;
-	PurpleConnection *gc = auth_data->gc;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-
-	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage1_cb\n");
-
-	if (!purple_http_response_is_successful(response)) {
-		const gchar *error_message = purple_http_response_get_error(response);
-		purple_debug_error("yahoo", "Login Failed, unable to retrieve login url: %s\n", error_message);
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
-		g_free(auth_data->seed);
-		g_free(auth_data);
-		return;
-	} else {
-		PurpleAccount *account = purple_connection_get_account(gc);
-		gchar **split_data = g_strsplit(purple_http_response_get_data(
-			response, NULL), "\r\n", -1);
-		int totalelements = 0;
-		int response_no = -1;
-		char *token = NULL;
-
-		totalelements = g_strv_length(split_data);
-
-		if(totalelements == 1) { /* Received an error code */
-			response_no = strtol(split_data[0], NULL, 10);
-		} else if(totalelements == 2 || totalelements == 3 ) { /* received valid data */
-			response_no = strtol(split_data[0], NULL, 10);
-			token = g_strdup(split_data[1] + strlen("ymsgr="));
-		} else { /* It looks like a transparent proxy has returned a document we don't want */
-			response_no = -1;
-		}
-
-		g_strfreev(split_data);
-
-		if(response_no != 0) {
-			/* Some error in the login process */
-			PurpleConnectionError error;
-			char *error_reason;
-
-			switch(response_no) {
-				case -1:
-					/* Some error in the received stream */
-					error_reason = g_strdup(_("Received invalid data"));
-					error = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
-					break;
-				case 1212:
-					/* Password incorrect */
-					/* Set password to NULL. Avoids account locking. Brings dialog to enter password if clicked on Re-enable account */
-					if (!purple_account_get_remember_password(account))
-						purple_account_set_password(account, NULL, NULL, NULL);
-					error_reason = g_strdup(_("Incorrect password"));
-					error = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
-					break;
-				case 1213:
-					/* security lock from too many failed login attempts */
-					error_reason = g_strdup(_("Account locked: Too many failed login "
-								"attempts.  Logging into the Yahoo! website may fix this."));
-					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-					break;
-				case 1235:
-					/* the username does not exist */
-					error_reason = g_strdup(_("Username does not exist"));
-					error = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
-					break;
-				case 1214:
-					/* indicates a lock of some description */
-					error_reason = g_strdup(_("Account locked: Unknown reason.  Logging "
-								"into the Yahoo! website may fix this."));
-					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-					break;
-				case 1236:
-					/* indicates a lock due to logging in too frequently */
-					error_reason = g_strdup(_("Account locked: You have been logging in too "
-								"frequently.  Wait a few minutes before trying to connect "
-								"again.  Logging into the Yahoo! website may help."));
-					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-					break;
-				case 100:
-					/* username or password missing */
-					error_reason = g_strdup(_("Username or password missing"));
-					error = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
-					break;
-				default:
-					/* Unknown error! */
-					error_reason = g_strdup_printf(_("Unknown error (%d)"), response_no);
-					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-					break;
-			}
-			purple_debug_error("yahoo", "Authentication error: %s. Code %d\n",
-			                   error_reason, response_no);
-			purple_connection_error(gc, error, error_reason);
-			g_free(error_reason);
-			g_free(auth_data->seed);
-			g_free(auth_data);
-			g_free(token);
-		}
-		else {
-			PurpleHttpRequest *req;
-
-			req = purple_http_request_new(NULL);
-			purple_http_request_set_url_printf(req, YAHOO_LOGIN_URL, token);
-			purple_http_request_header_set(req, "User-Agent",
-				YAHOO_CLIENT_USERAGENT);
-			purple_http_connection_set_add(yd->http_reqs,
-				purple_http_request(gc, req,
-					yahoo_auth16_stage2, auth_data));
-			purple_http_request_unref(req);
-
-			g_free(token);
-		}
-	}
-}
-
-static void yahoo_auth16_stage1(PurpleConnection *gc, const char *seed)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	PurpleHttpRequest *req;
-	struct yahoo_auth_data *auth_data = NULL;
-	char *encoded_username;
-	char *encoded_password;
-
-	purple_debug_info("yahoo", "Authentication: In yahoo_auth16_stage1\n");
-
-	auth_data = g_new0(struct yahoo_auth_data, 1);
-	auth_data->gc = gc;
-	auth_data->seed = g_strdup(seed);
-
-	encoded_username = g_strdup(purple_url_encode(purple_account_get_username(purple_connection_get_account(gc))));
-	encoded_password = g_strdup(purple_url_encode(purple_connection_get_password(gc)));
-
-	req = purple_http_request_new(NULL);
-	purple_http_request_set_url_printf(req, YAHOO_TOKEN_URL,
-		encoded_username, encoded_password, purple_url_encode(seed));
-	purple_http_request_header_set(req, "User-Agent", YAHOO_CLIENT_USERAGENT);
-	purple_http_connection_set_add(yd->http_reqs, purple_http_request(gc,
-		req, yahoo_auth16_stage1_cb, auth_data));
-	purple_http_request_unref(req);
-
-	purple_str_wipe(encoded_password);
-	g_free(encoded_username);
-}
-
-static void yahoo_process_auth(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	char *seed = NULL;
-	GSList *l = pkt->hash;
-	int m = 0;
-	gchar *buf;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-		/* (pair->key == 1) -> sn */
-		if (pair->key == 94) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				seed = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_auth "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		} else if (pair->key == 13) {
-			m = atoi(pair->value);
-		}
-		l = l->next;
-	}
-
-	if (seed) {
-		switch (m) {
-		case 0:
-			/* used to be for really old auth routine, dont support now */
-		case 1:
-		case 2: /* Yahoo ver 16 authentication */
-			yahoo_auth16_stage1(gc, seed);
-			break;
-		default:
-			{
-				GHashTable *ui_info = purple_core_get_ui_info();
-
-				buf = g_strdup_printf(_("The Yahoo server has requested the use of an unrecognized "
-							"authentication method.  You will probably not be able "
-							"to successfully sign on to Yahoo.  Check %s for updates."),
-							((ui_info && g_hash_table_lookup(ui_info, "website")) ? (char *)g_hash_table_lookup(ui_info, "website") : PURPLE_WEBSITE));
-				purple_notify_error(gc, "",
-					_("Failed Yahoo! Authentication"), buf,
-					purple_request_cpar_from_connection(gc));
-				g_free(buf);
-				yahoo_auth16_stage1(gc, seed); /* Can't hurt to try it anyway. */
-				break;
-			}
-		}
-	}
-}
-
-static void ignore_buddy(PurpleBuddy *buddy) {
-	PurpleGroup *group;
-	PurpleAccount *account;
-	gchar *name;
-
-	if (!buddy)
-		return;
-
-	group = purple_buddy_get_group(buddy);
-	name = g_strdup(purple_buddy_get_name(buddy));
-	account = purple_buddy_get_account(buddy);
-
-	purple_debug_info("yahoo", "blist: Removing '%s' from buddy list.\n", name);
-	purple_account_remove_buddy(account, buddy, group);
-	purple_blist_remove_buddy(buddy);
-
-	purple_serv_add_deny(purple_account_get_connection(account), name);
-
-	g_free(name);
-}
-
-static void keep_buddy(PurpleBuddy *b)
-{
-	purple_account_privacy_deny_remove(purple_buddy_get_account(b),
-			purple_buddy_get_name(b), 1);
-}
-
-static void yahoo_process_ignore(PurpleConnection *gc, struct yahoo_packet *pkt) {
-	PurpleBuddy *b;
-	GSList *l;
-	gchar *who = NULL;
-	gchar buf[BUF_LONG];
-	gboolean ignore = TRUE;
-	gint status = 0;
-
-	for (l = pkt->hash; l; l = l->next) {
-		struct yahoo_pair *pair = l->data;
-		switch (pair->key) {
-		case 0:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				who = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_ignore "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		/* 1 -> me */
-		case 13:
-			/* 1 == ignore, 2 == unignore */
-			ignore = (strtol(pair->value, NULL, 10) == 1);
-			break;
-		case 66:
-			status = strtol(pair->value, NULL, 10);
-			break;
-		default:
-			break;
-		}
-	}
-
-	/*
-	 * status
-	 * 0  - ok
-	 * 2  - already in ignore list, could not add
-	 * 3  - not in ignore list, could not delete
-	 * 12 - is a buddy, could not add (and possibly also a not-in-ignore list condition?)
-	 */
-	switch (status) {
-		case 12:
-			purple_debug_info("yahoo", "Server reported \"is a buddy\" for %s while %s",
-							  who, (ignore ? "ignoring" : "unignoring"));
-
-			if (ignore) {
-				b = purple_blist_find_buddy(purple_connection_get_account(gc), who);
-				g_snprintf(buf, sizeof(buf), _("You have tried to ignore %s, but the "
-											   "user is on your buddy list.  Clicking \"Yes\" "
-											   "will remove and ignore the buddy."), who);
-				purple_request_yes_no(gc, NULL,
-					_("Ignore buddy?"), buf, 0,
-					purple_request_cpar_from_connection(gc),
-					b, G_CALLBACK(ignore_buddy),
-					G_CALLBACK(keep_buddy));
-				break;
-			}
-		case 2:
-			purple_debug_info("yahoo", "Server reported that %s is already in the ignore list.\n",
-							  who);
-			break;
-		case 3:
-			purple_debug_info("yahoo", "Server reported that %s is not in the ignore list; could not delete\n",
-							  who);
-		case 0:
-		default:
-			break;
-	}
-}
-
-#if TRY_WEBMESSENGER_LOGIN
-
-static gboolean
-yahoo_try_webmessenger_login(PurpleConnection *gc)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	PurpleHttpRequest *req;
-
-	if (yd->wm)
-		return FALSE;
-
-	yd->wm = TRUE;
-	if (yd->fd >= 0)
-		close(yd->fd);
-	if (yd->inpa) {
-		purple_input_remove(yd->inpa);
-		yd->inpa = 0;
-	}
-
-	req = purple_http_request_new(WEBMESSENGER_URL);
-	purple_http_request_header_set(req, "User-Agent", "Purple/" VERSION);
-	purple_http_connection_set_add(yd->http_reqs, purple_http_request(gc,
-		req, yahoo_login_page_cb, NULL));
-	purple_http_request_unref(req);
-
-	return TRUE;
-}
-
-#endif /* TRY_WEBMESSENGER_LOGIN */
-
-static void yahoo_process_authresp(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	GSList *l = pkt->hash;
-	int err = 0;
-	char *msg;
-	char *url = NULL;
-	char *fullmsg;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		if (pair->key == 66) {
-			err = strtol(pair->value, NULL, 10);
-		} else if (pair->key == 20) {
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				url = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_authresp "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-		}
-
-		l = l->next;
-	}
-
-	switch (err) {
-	case 0:
-		msg = g_strdup(_("Unknown error"));
-		reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
-		break;
-	case 3:
-		msg = g_strdup(_("Username does not exist"));
-		reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
-		break;
-	case 13:
-#if TRY_WEBMESSENGER_LOGIN
-		if (yahoo_try_webmessenger_login(gc))
-			return;
-#else
-		purple_debug_info("yahoo", "Web messenger login is disabled\n");
-#endif /* TRY_WEBMESSENGER_LOGIN */
-		if (!purple_account_get_remember_password(account))
-			purple_account_set_password(account, NULL, NULL, NULL);
-
-		msg = g_strdup(_("Invalid username or password"));
-		reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
-		break;
-	case 14:
-		msg = g_strdup(_("Your account has been locked due to too many failed login attempts."
-					"  Please try logging into the Yahoo! website."));
-		reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
-		break;
-	case 52:
-		/* See #9660. As much as we know, reconnecting shouldn't hurt */
-		purple_debug_info("yahoo", "Got error 52, Set to autoreconnect\n");
-		msg = g_strdup(_("Unknown error 52.  Reconnecting should fix this."));
-		reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
-		break;
-	case 1013:
-		msg = g_strdup(_("Error 1013: The username you have entered is invalid."
-					"  The most common cause of this error is entering your email"
-					" address instead of your Yahoo! ID."));
-		reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
-		break;
-	default:
-		msg = g_strdup_printf(_("Unknown error number %d. Logging into the Yahoo! website may fix this."), err);
-	}
-
-	if (url)
-		fullmsg = g_strdup_printf("%s\n%s", msg, url);
-	else
-		fullmsg = g_strdup(msg);
-
-	purple_connection_error(gc, reason, fullmsg);
-	g_free(msg);
-	g_free(fullmsg);
-}
-
-static void yahoo_process_addbuddy(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	int err = 0;
-	char *who = NULL;
-	char *temp = NULL;
-	char *group = NULL;
-	char *decoded_group;
-	char *buf;
-	YahooFriend *f;
-	GSList *l = pkt->hash;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 66:
-			err = strtol(pair->value, NULL, 10);
-			break;
-		case 7:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				temp = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_addbuddy "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 65:
-			group = pair->value;
-			break;
-		}
-
-		l = l->next;
-	}
-
-	if (!temp)
-		return;
-	if (!group)
-		group = "";
-
-	who = g_strdup(temp);
-
-	if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */
-		f = yahoo_friend_find_or_new(gc, who);
-		yahoo_update_status(gc, who, f);
-
-		if( !g_hash_table_lookup(yd->peers, who) ) {
-			/* we are not connected as client, so set friend to not connected */
-			yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
-			f->p2p_packet_sent = 0;
-		}
-		else	/* we are already connected. set friend to YAHOO_P2PSTATUS_WE_ARE_CLIENT */
-			yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT);
-		g_free(who);
-		return;
-	}
-
-	decoded_group = yahoo_string_decode(gc, group, FALSE);
-	buf = g_strdup_printf(_("Unable to add buddy %s to group %s to the server list on account %s."),
-				who, decoded_group, purple_connection_get_display_name(gc));
-	if (!purple_conversation_present_error(who, purple_connection_get_account(gc), buf))
-		purple_notify_error(gc, NULL, _("Unable to add buddy to server list"), buf,
-			purple_request_cpar_from_connection(gc));
-	g_free(buf);
-	g_free(decoded_group);
-	g_free(who);
-}
-
-/* write pkt to the source */
-static void yahoo_p2p_write_pkt(gint source, struct yahoo_packet *pkt)
-{
-	size_t pkt_len;
-	gssize written;
-	guchar *raw_packet;
-
-	/*build the raw packet and send it to the host*/
-	pkt_len = yahoo_packet_build(pkt, 0, 0, &raw_packet);
-	written = write(source, raw_packet, pkt_len);
-	if (written < 0 || (gsize)written != pkt_len)
-		purple_debug_warning("yahoo","p2p: couldn't write to the source\n");
-	g_free(raw_packet);
-}
-
-static void yahoo_p2p_keepalive_cb(gpointer key, gpointer value, gpointer user_data)
-{
-	struct yahoo_p2p_data *p2p_data = value;
-	PurpleConnection *gc = user_data;
-	struct yahoo_packet *pkt_to_send;
-	PurpleAccount *account;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-
-	account = purple_connection_get_account(gc);
-
-	pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash(pkt_to_send, "ssisi",
-		4, purple_normalize(account, purple_account_get_username(account)),
-		5, p2p_data->host_username,
-		241, 0,		/* Protocol identifier */
-		49, "PEERTOPEER",
-		13, 7);
-	yahoo_p2p_write_pkt(p2p_data->source, pkt_to_send);
-
-	yahoo_packet_free(pkt_to_send);
-}
-
-static gboolean yahoo_p2p_keepalive(gpointer data)
-{
-	PurpleConnection *gc = data;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-
-	g_hash_table_foreach(yd->peers, yahoo_p2p_keepalive_cb, gc);
-
-	return TRUE;
-}
-
-/* destroy p2p_data associated with a peer and close p2p connection.
- * g_hash_table_remove() calls this function to destroy p2p_data associated with the peer,
- * call g_hash_table_remove() instead of this fucntion if peer has an entry in the table */
-static void yahoo_p2p_disconnect_destroy_data(gpointer data)
-{
-	struct yahoo_p2p_data *p2p_data;
-	YahooFriend *f;
-
-	if(!(p2p_data = data))
-		return ;
-
-	/* If friend, set him not connected */
-	f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username);
-	if (f)
-		yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
-
-	if(p2p_data->source >= 0)
-		close(p2p_data->source);
-	if (p2p_data->input_event > 0)
-		purple_input_remove(p2p_data->input_event);
-	g_free(p2p_data->host_ip);
-	g_free(p2p_data->host_username);
-	g_free(p2p_data);
-}
-
-/* exchange of initial p2pfilexfer packets, service type YAHOO_SERVICE_P2PFILEXFER */
-static void yahoo_p2p_process_p2pfilexfer(gpointer data, gint source, struct yahoo_packet *pkt)
-{
-	struct yahoo_p2p_data *p2p_data;
-	char *who = NULL;
-	GSList *l = pkt->hash;
-	struct yahoo_packet *pkt_to_send;
-	PurpleAccount *account;
-	int val_13_to_send = 0;
-	YahooData *yd;
-	YahooFriend *f;
-
-	if(!(p2p_data = data))
-		return ;
-
-	yd = purple_connection_get_protocol_data(p2p_data->gc);
-
-	/* lets see whats in the packet */
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 4:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				who = pair->value;
-				if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) {
-					/* from whom are we receiving the packets ?? */
-					purple_debug_warning("yahoo","p2p: received data from wrong user\n");
-					return;
-				}
-			} else {
-				purple_debug_warning("yahoo", "yahoo_p2p_process_p2pfilexfer "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 13:
-			p2p_data->val_13 = strtol(pair->value, NULL, 10);	/* Value should be 5-7 */
-			break;
-		/* case 5, 49 look laters, no use right now */
-		}
-		l = l->next;
-	}
-
-	account = purple_connection_get_account(p2p_data->gc);
-
-	/* key_13: sort of a counter.
-	 * WHEN WE ARE CLIENT: yahoo server sends val_13 = 0, we send to peer val_13 = 1, receive back val_13 = 5,
-	 * we send val_13=6, receive val_13=7, we send val_13=7, HALT. Keep sending val_13 = 7 as keep alive.
-	 * WHEN WE ARE SERVER: we send val_13 = 0 to yahoo server, peer sends us val_13 = 1, we send val_13 = 5,
-	 * receive val_13 = 6, send val_13 = 7, receive val_13 = 7. HALT. Keep sending val_13 = 7 as keep alive. */
-
-	switch(p2p_data->val_13) {
-		case 1 : val_13_to_send = 5; break;
-		case 5 : val_13_to_send = 6; break;
-		case 6 : val_13_to_send = 7; break;
-		case 7 : if( g_hash_table_lookup(yd->peers, p2p_data->host_username) )
-				return;
-			 val_13_to_send = 7; break;
-		default: purple_debug_warning("yahoo","p2p:Unknown value for key 13\n");
-			 return;
-		}
-
-	/* Build the yahoo packet */
-	pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash(pkt_to_send, "ssisi",
-		4, purple_normalize(account, purple_account_get_username(account)),
-		5, p2p_data->host_username,
-		241, 0,		/* Protocol identifier */
-		49, "PEERTOPEER",
-		13, val_13_to_send);
-
-	/* build the raw packet and send it to the host */
-	yahoo_p2p_write_pkt(source, pkt_to_send);
-	yahoo_packet_free(pkt_to_send);
-
-	if( val_13_to_send == 7 )
-		if( !g_hash_table_lookup(yd->peers, p2p_data->host_username) ) {
-			g_hash_table_insert(yd->peers, g_strdup(p2p_data->host_username), p2p_data);
-			/* If the peer is a friend, set him connected */
-			f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username);
-			if (f) {
-				if(p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER) {
-					p2p_data->session_id = f->session_id;
-					yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_SERVER);
-				}
-				else
-					yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT);
-			}
-		}
-}
-
-/* callback function associated with receiving of data, not considering receipt of multiple YMSG packets in a single TCP packet */
-static void yahoo_p2p_read_pkt_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	guchar buf[1024];	/* is it safe to assume a fixed array length of 1024 ?? */
-	int len;
-	int pos = 0;
-	int pktlen;
-	struct yahoo_packet *pkt;
-	guchar *start;
-	struct yahoo_p2p_data *p2p_data;
-	YahooData *yd;
-
-	if(!(p2p_data = data))
-		return ;
-	yd = purple_connection_get_protocol_data(p2p_data->gc);
-
-	len = read(source, buf, sizeof(buf));
-	if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
-		return ; /* No Worries*/
-	else if (len <= 0)
-	{
-		purple_debug_warning("yahoo","p2p: Error in connection, or host disconnected\n");
-		/* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
-		if( g_hash_table_lookup(yd->peers, p2p_data->host_username) )
-			g_hash_table_remove(yd->peers,p2p_data->host_username);
-		else
-			yahoo_p2p_disconnect_destroy_data(data);
-		return;
-	}
-
-	/* TODO: It looks like there's a bug here (and above) where an incorrect
-	 * assumtion is being made that the buffer will be added to when this
-	 * is next called, but that's not really the case! */
-	if(len < YAHOO_PACKET_HDRLEN)
-		return;
-
-	if(strncmp((char *)buf, "YMSG", 4) != 0) {
-		/* Not a YMSG packet */
-		purple_debug_warning("yahoo", "p2p: Got something other than YMSG packet\n");
-
-		start = (guchar *) g_strstr_len((char *) buf + 1, len - 1 ,"YMSG");
-		if (start == NULL) {
-			/* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
-			if (g_hash_table_lookup(yd->peers, p2p_data->host_username))
-				g_hash_table_remove(yd->peers, p2p_data->host_username);
-			else
-				yahoo_p2p_disconnect_destroy_data(data);
-			return;
-		}
-		purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
-
-		len -= (start - buf);
-		g_memmove(buf, start, len);
-	}
-
-	pos += 4;	/* YMSG */
-	pos += 2;
-	pos += 2;
-
-	pktlen = yahoo_get16(buf + pos); pos += 2;
-	if (len < (YAHOO_PACKET_HDRLEN + pktlen)) {
-		purple_debug_error("yahoo", "p2p: packet length(%d) > buffer length(%d)\n",
-				pktlen, (len - pos)); 
-		/* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
-		if (g_hash_table_lookup(yd->peers, p2p_data->host_username))
-			g_hash_table_remove(yd->peers, p2p_data->host_username);
-		else
-			yahoo_p2p_disconnect_destroy_data(data);
-		return;
-	} else
-		purple_debug_misc("yahoo", "p2p: %d bytes to read\n", pktlen);
-
-	pkt = yahoo_packet_new(0, 0, 0);
-	pkt->service = yahoo_get16(buf + pos); pos += 2;
-	pkt->status = yahoo_get32(buf + pos); pos += 4;
-	pkt->id = yahoo_get32(buf + pos); pos += 4;
-
-	purple_debug_misc("yahoo", "p2p: Yahoo Service: 0x%02x Status: %d\n",pkt->service, pkt->status);
-	yahoo_packet_read(pkt, buf + pos, pktlen);
-
-	/* packet processing */
-	switch(pkt->service) {
-		case YAHOO_SERVICE_P2PFILEXFER:
-			yahoo_p2p_process_p2pfilexfer(data, source, pkt);
-			break;
-		case YAHOO_SERVICE_MESSAGE:
-			yahoo_process_message(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P);
-			break;
-		case YAHOO_SERVICE_NOTIFY:
-			yahoo_process_notify(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P);
-			break;
-		default:
-			purple_debug_warning("yahoo","p2p: p2p service %d Unhandled\n",pkt->service);
-	}
-
-	yahoo_packet_free(pkt);
-}
-
-static void yahoo_p2p_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	int acceptfd;
-	struct yahoo_p2p_data *p2p_data;
-	YahooData *yd;
-
-	if(!(p2p_data = data))
-		return ;
-	yd = purple_connection_get_protocol_data(p2p_data->gc);
-
-	acceptfd = accept(source, NULL, 0);
-	if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
-		return;
-	else if(acceptfd == -1) {
-		purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno));
-		yahoo_p2p_disconnect_destroy_data(data);
-		return;
-	}
-
-	/* remove timeout */
-	if (yd->yahoo_p2p_server_timeout_handle) {
-		purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle);
-		yd->yahoo_p2p_server_timeout_handle = 0;
-	}
-
-	/* remove watcher and close p2p server */
-	if (yd->yahoo_p2p_server_watcher) {
-		purple_input_remove(yd->yahoo_p2p_server_watcher);
-		yd->yahoo_p2p_server_watcher = 0;
-	}
-	if (yd->yahoo_local_p2p_server_fd >= 0) {
-		close(yd->yahoo_local_p2p_server_fd);
-		yd->yahoo_local_p2p_server_fd = -1;
-	}
-
-	/* Add an Input Read event to the file descriptor */
-	p2p_data->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data);
-	p2p_data->source = acceptfd;
-}
-
-static gboolean yahoo_cancel_p2p_server_listen_cb(gpointer data)
-{
-	struct yahoo_p2p_data *p2p_data;
-	YahooData *yd;
-
-	if(!(p2p_data = data))
-		return FALSE;
-
-	yd = purple_connection_get_protocol_data(p2p_data->gc);
-
-	purple_debug_warning("yahoo","yahoo p2p server timeout, peer failed to connect\n");
-	yahoo_p2p_disconnect_destroy_data(data);
-	purple_input_remove(yd->yahoo_p2p_server_watcher);
-	yd->yahoo_p2p_server_watcher = 0;
-	close(yd->yahoo_local_p2p_server_fd);
-	yd->yahoo_local_p2p_server_fd = -1;
-	yd->yahoo_p2p_server_timeout_handle = 0;
-
-	return FALSE;
-}
-
-static void yahoo_p2p_server_listen_cb(int listenfd, gpointer data)
-{
-	struct yahoo_p2p_data *p2p_data;
-	YahooData *yd;
-
-	if(!(p2p_data = data))
-		return ;
-
-	yd = purple_connection_get_protocol_data(p2p_data->gc);
-	yd->listen_data = NULL;
-
-	if(listenfd == -1) {
-		purple_debug_warning("yahoo","p2p: error starting p2p server\n");
-		yahoo_p2p_disconnect_destroy_data(data);
-		return;
-	}
-
-	/* Add an Input Read event to the file descriptor */
-	yd->yahoo_local_p2p_server_fd = listenfd;
-	yd->yahoo_p2p_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_server_send_connected_cb,data);
-
-	/* add timeout */
-	yd->yahoo_p2p_server_timeout_handle = purple_timeout_add_seconds(YAHOO_P2P_SERVER_TIMEOUT, yahoo_cancel_p2p_server_listen_cb, data);
-}
-
-/* send p2p pkt containing our encoded ip, asking peer to connect to us */
-void yahoo_send_p2p_pkt(PurpleConnection *gc, const char *who, int val_13)
-{
-	const char *public_ip;
-	guint32 temp[4];
-	guint32 ip;
-	char temp_str[100];
-	gchar *base64_ip = NULL;
-	YahooFriend *f;
-	struct yahoo_packet *pkt;
-	PurpleAccount *account;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_p2p_data *p2p_data;
-	const char *norm_username;
-
-	f = yahoo_friend_find(gc, who);
-	account = purple_connection_get_account(gc);
-
-	/* Do not send invitation if already listening for other connection */
-	if(yd->yahoo_local_p2p_server_fd >= 0)
-		return;
-
-	/* One shouldn't try to connect to self */
-	if( strcmp(purple_normalize(account, purple_account_get_username(account)), who) == 0)
-		return;
-
-	/* send packet to only those friends who arent p2p connected and to whom we havent already sent. Do not send if this condition doesn't hold good */
-	if( !( f && (yahoo_friend_get_p2p_status(f) == YAHOO_P2PSTATUS_NOT_CONNECTED) && (f->p2p_packet_sent == 0)) )
-		return;
-
-	/* Finally, don't try to connect to buddies not online or on sms */
-	if( (f->status == YAHOO_STATUS_OFFLINE) || f->sms )
-		return;
-
-	public_ip = purple_network_get_public_ip();
-	if( (sscanf(public_ip, "%u.%u.%u.%u", &temp[0], &temp[1], &temp[2], &temp[3])) !=4 )
-		return ;
-
-	ip = (temp[3] << 24) | (temp[2] <<16) | (temp[1] << 8) | temp[0];
-	sprintf(temp_str, "%d", ip);
-	base64_ip = purple_base64_encode( (guchar *)temp_str, strlen(temp_str) );
-
-	norm_username = purple_normalize(account, purple_account_get_username(account));
-	pkt = yahoo_packet_new(YAHOO_SERVICE_PEERTOPEER, YAHOO_STATUS_AVAILABLE, 0);
-	yahoo_packet_hash(pkt, "sssissis",
-		1, norm_username,
-		4, norm_username,
-		12, base64_ip,	/* base64 encode ip */
-		61, 0,		/* To-do : figure out what is 61 for?? */
-		2, "",
-		5, who,
-		13, val_13,
-		49, "PEERTOPEER");
-	yahoo_packet_send_and_free(pkt, yd);
-
-	f->p2p_packet_sent = 1;	/* set p2p_packet_sent to sent */
-
-	p2p_data = g_new0(struct yahoo_p2p_data, 1);
-
-	p2p_data->gc = gc;
-	p2p_data->host_ip = NULL;
-	p2p_data->host_username = g_strdup(who);
-	p2p_data->val_13 = val_13;
-	p2p_data->connection_type = YAHOO_P2P_WE_ARE_SERVER;
-	p2p_data->source = -1;
-
-	/* FIXME: If the port is already used, purple_network_listener returns NULL and old listener won't be canceled
-	 * in yahoo_close function. */
-	if (yd->listen_data)
-		purple_debug_warning("yahoo","p2p: Failed to create p2p server - server already exists\n");
-	else {
-		yd->listen_data = purple_network_listen(YAHOO_PAGER_PORT_P2P, AF_UNSPEC, SOCK_STREAM, TRUE, yahoo_p2p_server_listen_cb, p2p_data);
-		if (yd->listen_data == NULL)
-			purple_debug_warning("yahoo","p2p: Failed to created p2p server\n");
-	}
-
-	g_free(base64_ip);
-}
-
-/* function called when connection to p2p host is setup */
-static void yahoo_p2p_init_cb(gpointer data, gint source, const gchar *error_message)
-{
-	struct yahoo_p2p_data *p2p_data;
-	struct yahoo_packet *pkt_to_send;
-	PurpleAccount *account;
-	YahooData *yd;
-
-	p2p_data = data;
-	yd = purple_connection_get_protocol_data(p2p_data->gc);
-
-	if(error_message != NULL) {
-		purple_debug_warning("yahoo","p2p: %s\n",error_message);
-		yahoo_send_p2p_pkt(p2p_data->gc, p2p_data->host_username, 2);/* send p2p init packet with val_13=2 */
-
-		yahoo_p2p_disconnect_destroy_data(p2p_data);
-		return;
-	}
-
-	/* Add an Input Read event to the file descriptor */
-	p2p_data->input_event = purple_input_add(source, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data);
-	p2p_data->source = source;
-
-	account = purple_connection_get_account(p2p_data->gc);
-
-	/* Build the yahoo packet */
-	pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash(pkt_to_send, "ssisi",
-		4, purple_normalize(account, purple_account_get_username(account)),
-		5, p2p_data->host_username,
-		241, 0,		/* Protocol identifier */
-		49, "PEERTOPEER",
-		13, 1);		/* we receive key13= 0 or 2, we send key13=1 */
-
-	yahoo_p2p_write_pkt(source, pkt_to_send);	/* build raw packet and send */
-	yahoo_packet_free(pkt_to_send);
-}
-
-static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	GSList *l = pkt->hash;
-	char *who = NULL;
-	char *base64 = NULL;
-	guchar *decoded;
-	gsize len;
-	gint val_13 = 0;
-	gint val_11 = 0;
-	PurpleAccount *account;
-	YahooFriend *f;
-
-	/* if status is not YAHOO_STATUS_BRB or YAHOO_STATUS_P2P, the packet bounced back,
-	 * so it contains our own ip */
-	if(pkt->status != YAHOO_STATUS_BRB && pkt->status != YAHOO_STATUS_P2P)
-		return ;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 5:
-			/* our identity */
-			break;
-		case 4:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				who = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_p2p "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 1:
-			/* who again, the master identity this time? */
-			break;
-		case 12:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				base64 = pair->value;
-				/* so, this is an ip address. in base64. decoded it's in ascii.
-				   after strtol, it's in reversed byte order. Who thought this up?*/
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_p2p "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 13:
-			val_13 = strtol(pair->value, NULL, 10);
-			break;
-		case 11:
-			val_11 = strtol(pair->value, NULL, 10);		/* session id of peer */
-			if( (f = yahoo_friend_find(gc, who)) )
-				f->session_id = val_11;
-			break;
-		/*
-			TODO: figure these out
-			yahoo: Key: 61          Value: 0
-			yahoo: Key: 2   Value:
-			yahoo: Key: 13          Value: 0	packet count ??
-			yahoo: Key: 49          Value: PEERTOPEER
-			yahoo: Key: 140         Value: 1
-		*/
-
-		}
-
-		l = l->next;
-	}
-
-	if (base64) {
-		guint32 ip;
-		YahooFriend *f;
-		char *host_ip, *tmp;
-		struct yahoo_p2p_data *p2p_data;
-
-		decoded = purple_base64_decode(base64, &len);
-		if (decoded == NULL) {
-			purple_debug_info("yahoo","p2p: Unable to decode base64 IP (%s) \n", base64);
-			return;
-		}
-		tmp = purple_str_binary_to_ascii(decoded, len);
-		purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp);
-		g_free(tmp);
-
-		ip = strtol((gchar *)decoded, NULL, 10);
-		g_free(decoded);
-		host_ip = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff,
-		                       (ip >> 24) & 0xff);
-		f = yahoo_friend_find(gc, who);
-		if (f)
-			yahoo_friend_set_ip(f, host_ip);
-		purple_debug_info("yahoo", "IP : %s\n", host_ip);
-
-		account = purple_connection_get_account(gc);
-
-		if(val_11==0) {
-			if(!f)
-				return;
-			else
-				val_11 = f->session_id;
-		}
-
-		p2p_data = g_new0(struct yahoo_p2p_data, 1);
-		p2p_data->host_username = g_strdup(who);
-		p2p_data->val_13 = val_13;
-		p2p_data->session_id = val_11;
-		p2p_data->host_ip = host_ip;
-		p2p_data->gc = gc;
-		p2p_data->connection_type = YAHOO_P2P_WE_ARE_CLIENT;
-		p2p_data->source = -1;
-
-		/* connect to host */
-		if((purple_proxy_connect(gc, account, host_ip, YAHOO_PAGER_PORT_P2P, yahoo_p2p_init_cb, p2p_data))==NULL) {
-			purple_debug_info("yahoo","p2p: Connection to %s failed\n", host_ip);
-			g_free(p2p_data->host_ip);
-			g_free(p2p_data->host_username);
-			g_free(p2p_data);
-		}
-	}
-}
-
-static void yahoo_process_audible(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	PurpleAccount *account;
-	char *who = NULL, *msg = NULL, *id = NULL;
-	GSList *l = pkt->hash;
-
-	account = purple_connection_get_account(gc);
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 4:
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				who = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_audible "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 5:
-			/* us */
-			break;
-		case 230:
-			/* the audible, in foo.locale.bar.baz format
-			   eg: base.tw.smiley.smiley43 */
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				id = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_audible "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 231:
-			/* the text of the audible */
-			if (g_utf8_validate(pair->value, -1, NULL)) {
-				msg = pair->value;
-			} else {
-				purple_debug_warning("yahoo", "yahoo_process_audible "
-						"got non-UTF-8 string for key %d\n", pair->key);
-			}
-			break;
-		case 232:
-			/* SHA-1 hash of audible SWF file (eg: 4e8691499d9c0fb8374478ff9720f4a9ea4a4915) */
-			break;
-		}
-
-		l = l->next;
-	}
-
-	if (!msg)
-		msg = id;
-	if (!who || !msg)
-		return;
-	if (!g_utf8_validate(msg, -1, NULL)) {
-		purple_debug_misc("yahoo", "Warning, nonutf8 audible, ignoring!\n");
-		return;
-	}
-	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;
-	}
-	if (id) {
-		/* "http://l.yimg.com/pu/dl/aud/"+locale+"/"+id+".swf" */
-		char **audible_locale = g_strsplit(id, ".", 0);
-		char *buf = g_strdup_printf(_("[ Audible %s/%s/%s.swf ] %s"), YAHOO_AUDIBLE_URL, audible_locale[1], id, msg);
-		g_strfreev(audible_locale);
-
-		purple_serv_got_im(gc, who, buf, 0, time(NULL));
-		g_free(buf);
-	} else
-		purple_serv_got_im(gc, who, msg, 0, time(NULL));
-}
-
-static void yahoo_packet_process(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	switch (pkt->service) {
-	case YAHOO_SERVICE_LOGON:
-	case YAHOO_SERVICE_LOGOFF:
-	case YAHOO_SERVICE_ISAWAY:
-	case YAHOO_SERVICE_ISBACK:
-	case YAHOO_SERVICE_GAMELOGON:
-	case YAHOO_SERVICE_GAMELOGOFF:
-	case YAHOO_SERVICE_CHATLOGON:
-	case YAHOO_SERVICE_CHATLOGOFF:
-	case YAHOO_SERVICE_Y6_STATUS_UPDATE:
-	case YAHOO_SERVICE_STATUS_15:
-		yahoo_process_status(gc, pkt);
-		break;
-	case YAHOO_SERVICE_NOTIFY:
-		yahoo_process_notify(gc, pkt, YAHOO_PKT_TYPE_SERVER);
-		break;
-	case YAHOO_SERVICE_MESSAGE:
-	case YAHOO_SERVICE_GAMEMSG:
-	case YAHOO_SERVICE_CHATMSG:
-		yahoo_process_message(gc, pkt, YAHOO_PKT_TYPE_SERVER);
-		break;
-	case YAHOO_SERVICE_SYSMESSAGE:
-		yahoo_process_sysmessage(gc, pkt);
-			break;
-	case YAHOO_SERVICE_NEWMAIL:
-		yahoo_process_mail(gc, pkt);
-		break;
-	case YAHOO_SERVICE_NEWCONTACT:
-		yahoo_process_contact(gc, pkt);
-		break;
-	case YAHOO_SERVICE_AUTHRESP:
-		yahoo_process_authresp(gc, pkt);
-		break;
-	case YAHOO_SERVICE_LIST:
-		yahoo_process_list(gc, pkt);
-		break;
-	case YAHOO_SERVICE_LIST_15:
-		yahoo_process_list_15(gc, pkt);
-		break;
-	case YAHOO_SERVICE_AUTH:
-		yahoo_process_auth(gc, pkt);
-		break;
-	case YAHOO_SERVICE_AUTH_REQ_15:
-		yahoo_buddy_auth_req_15(gc, pkt);
-		break;
-	case YAHOO_SERVICE_ADDBUDDY:
-		yahoo_process_addbuddy(gc, pkt);
-		break;
-	case YAHOO_SERVICE_IGNORECONTACT:
-		yahoo_process_ignore(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CONFINVITE:
-	case YAHOO_SERVICE_CONFADDINVITE:
-		yahoo_process_conference_invite(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CONFDECLINE:
-		yahoo_process_conference_decline(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CONFLOGON:
-		yahoo_process_conference_logon(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CONFLOGOFF:
-		yahoo_process_conference_logoff(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CONFMSG:
-		yahoo_process_conference_message(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CHATONLINE:
-		yahoo_process_chat_online(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CHATLOGOUT:
-		yahoo_process_chat_logout(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CHATGOTO:
-		yahoo_process_chat_goto(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CHATJOIN:
-		yahoo_process_chat_join(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CHATLEAVE: /* XXX is this right? */
-	case YAHOO_SERVICE_CHATEXIT:
-		yahoo_process_chat_exit(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CHATINVITE: /* XXX never seen this one, might not do it right */
-	case YAHOO_SERVICE_CHATADDINVITE:
-		yahoo_process_chat_addinvite(gc, pkt);
-		break;
-	case YAHOO_SERVICE_COMMENT:
-		yahoo_process_chat_message(gc, pkt);
-		break;
-	case YAHOO_SERVICE_PRESENCE_PERM:
-	case YAHOO_SERVICE_PRESENCE_SESSION:
-		yahoo_process_presence(gc, pkt);
-		break;
-	case YAHOO_SERVICE_P2PFILEXFER:
-		/* This case had no break and continued; thus keeping it this way.*/
-		yahoo_process_p2p(gc, pkt);	/* P2PFILEXFER handled the same way as process_p2p */
-		yahoo_process_p2pfilexfer(gc, pkt);	/* redundant ??, need to have a break now */
-	case YAHOO_SERVICE_FILETRANSFER:
-		purple_debug_error("yahoo", "Legacy file transfers are not "
-			"supported anymore.\n");
-		break;
-	case YAHOO_SERVICE_PEERTOPEER:
-		yahoo_process_p2p(gc, pkt);
-		break;
-	case YAHOO_SERVICE_PICTURE:
-		yahoo_process_picture(gc, pkt);
-		break;
-	case YAHOO_SERVICE_PICTURE_CHECKSUM:
-		yahoo_process_picture_checksum(gc, pkt);
-		break;
-	case YAHOO_SERVICE_PICTURE_UPLOAD:
-		yahoo_process_picture_upload(gc, pkt);
-		break;
-	case YAHOO_SERVICE_PICTURE_UPDATE:
-	case YAHOO_SERVICE_AVATAR_UPDATE:
-		yahoo_process_avatar_update(gc, pkt);
-		break;
-	case YAHOO_SERVICE_AUDIBLE:
-		yahoo_process_audible(gc, pkt);
-		break;
-	case YAHOO_SERVICE_CONTACT_DETAILS:
-		yahoo_process_contact_details(gc, pkt);
-		break;
-	case YAHOO_SERVICE_FILETRANS_15:
-		yahoo_process_filetrans_15(gc, pkt);
-		break;
-	case YAHOO_SERVICE_FILETRANS_INFO_15:
-		yahoo_process_filetrans_info_15(gc, pkt);
-		break;
-	case YAHOO_SERVICE_FILETRANS_ACC_15:
-		yahoo_process_filetrans_acc_15(gc, pkt);
-		break;
-	case YAHOO_SERVICE_SMS_MSG:
-		yahoo_process_sms_message(gc, pkt);
-		break;
-
-	default:
-		purple_debug_error("yahoo", "Unhandled service 0x%02x\n", pkt->service);
-		break;
-	}
-}
-
-static void yahoo_pending(gpointer data, gint source, PurpleInputCondition cond)
-{
-	PurpleConnection *gc = data;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	char buf[1024];
-	int len;
-
-	len = read(yd->fd, buf, sizeof(buf));
-
-	if (len < 0) {
-		gchar *tmp;
-
-		if (errno == EAGAIN)
-			/* No worries */
-			return;
-
-		tmp = g_strdup_printf(_("Lost connection with server: %s"),
-				g_strerror(errno));
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	} else if (len == 0) {
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Server closed the connection"));
-		return;
-	}
-	purple_connection_update_last_received(gc);
-	yd->rxqueue = g_realloc(yd->rxqueue, len + yd->rxlen);
-	memcpy(yd->rxqueue + yd->rxlen, buf, len);
-	yd->rxlen += len;
-
-	while (1) {
-		struct yahoo_packet *pkt;
-		int pos = 0;
-		int pktlen;
-
-		if (yd->rxlen < YAHOO_PACKET_HDRLEN)
-			return;
-
-		if (strncmp((char *)yd->rxqueue, "YMSG", MIN(4, yd->rxlen)) != 0) {
-			/* HEY! This isn't even a YMSG packet. What
-			 * are you trying to pull? */
-			guchar *start;
-
-			purple_debug_warning("yahoo", "Error in YMSG stream, got something not a YMSG packet!\n");
-
-			start = memchr(yd->rxqueue + 1, 'Y', yd->rxlen - 1);
-			if (start) {
-				g_memmove(yd->rxqueue, start, yd->rxlen - (start - yd->rxqueue));
-				yd->rxlen -= start - yd->rxqueue;
-				continue;
-			} else {
-				g_free(yd->rxqueue);
-				yd->rxqueue = NULL;
-				yd->rxlen = 0;
-				return;
-			}
-		}
-
-		pos += 4; /* YMSG */
-		pos += 2;
-		pos += 2;
-
-		pktlen = yahoo_get16(yd->rxqueue + pos); pos += 2;
-		purple_debug_misc("yahoo", "%d bytes to read, rxlen is %d\n", pktlen, yd->rxlen);
-
-		if (yd->rxlen < (YAHOO_PACKET_HDRLEN + pktlen))
-			return;
-
-		yahoo_packet_dump(yd->rxqueue, YAHOO_PACKET_HDRLEN + pktlen);
-
-		pkt = yahoo_packet_new(0, 0, 0);
-
-		pkt->service = yahoo_get16(yd->rxqueue + pos); pos += 2;
-		pkt->status = yahoo_get32(yd->rxqueue + pos); pos += 4;
-		purple_debug_misc("yahoo", "Yahoo Service: 0x%02x Status: %d\n",
-				   pkt->service, pkt->status);
-		pkt->id = yahoo_get32(yd->rxqueue + pos); pos += 4;
-
-		yahoo_packet_read(pkt, yd->rxqueue + pos, pktlen);
-
-		yd->rxlen -= YAHOO_PACKET_HDRLEN + pktlen;
-		if (yd->rxlen) {
-			guchar *tmp = g_memdup(yd->rxqueue + YAHOO_PACKET_HDRLEN + pktlen, yd->rxlen);
-			g_free(yd->rxqueue);
-			yd->rxqueue = tmp;
-		} else {
-			g_free(yd->rxqueue);
-			yd->rxqueue = NULL;
-		}
-
-		yahoo_packet_process(gc, pkt);
-
-		yahoo_packet_free(pkt);
-	}
-}
-
-static void yahoo_got_connected(gpointer data, gint source, const gchar *error_message)
-{
-	PurpleConnection *gc = data;
-	YahooData *yd;
-	struct yahoo_packet *pkt;
-
-	if (source < 0) {
-		gchar *tmp;
-		tmp = g_strdup_printf(_("Unable to connect: %s"), error_message);
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	}
-
-	yd = purple_connection_get_protocol_data(gc);
-	yd->fd = source;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, yd->current_status, yd->session_id);
-
-	yahoo_packet_hash_str(pkt, 1, purple_normalize(purple_connection_get_account(gc), purple_account_get_username(purple_connection_get_account(gc))));
-	yahoo_packet_send_and_free(pkt, yd);
-
-	yd->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc);
-}
-
-#if TRY_WEBMESSENGER_LOGIN
-
-static void yahoo_got_web_connected(gpointer data, gint source, const gchar *error_message)
-{
-	PurpleConnection *gc = data;
-	YahooData *yd;
-	struct yahoo_packet *pkt;
-
-	if (source < 0) {
-		gchar *tmp;
-		tmp = g_strdup_printf(_("Unable to connect: %s"), error_message);
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	}
-
-	yd = purple_connection_get_protocol_data(gc);
-	yd->fd = source;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_WEBLOGIN, YAHOO_STATUS_WEBLOGIN, yd->session_id);
-
-	yahoo_packet_hash(pkt, "sss", 0,
-	                  purple_normalize(purple_connection_get_account(gc), purple_account_get_username(purple_connection_get_account(gc))),
-	                  1, purple_normalize(purple_connection_get_account(gc), purple_account_get_username(purple_connection_get_account(gc))),
-	                  6, yd->auth);
-	yahoo_packet_send_and_free(pkt, yd);
-
-	g_free(yd->auth);
-	yd->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc);
-}
-
-static void
-yahoo_login_page_got(PurpleHttpConnection *hc, PurpleHttpResponse *resp,
-	gpointer _unused)
-{
-	PurpleConnection *gc = purple_http_conn_get_purple_connection(hc);
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleHttpCookieJar *cjar;
-	GString *auth_s;
-	gchar *cookie;
-
-	if (purple_http_response_get_code(resp) != 302) {
-		purple_connection_error(gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Unable to connect"));
-		return;
-	}
-
-	auth_s = g_string_new(NULL);
-	cjar = purple_http_conn_get_cookie_jar(hc);
-	cookie = purple_http_cookie_jar_get(cjar, "B");
-	if (cookie) {
-		g_string_append_printf(auth_s, "B=%s; ", cookie);
-		g_free(cookie);
-	}
-	cookie = purple_http_cookie_jar_get(cjar, "T");
-	if (cookie) {
-		g_string_append_printf(auth_s, "T=%s; ", cookie);
-		g_free(cookie);
-	}
-	cookie = purple_http_cookie_jar_get(cjar, "Y");
-	if (cookie) {
-		g_string_append_printf(auth_s, "Y=%s; ", cookie);
-		g_free(cookie);
-	}
-
-	yd->auth = g_string_free(auth_s, FALSE);
-	/* Now we have our cookies to login with.  I'll go get the milk. */
-
-	/* XXX: wcs2.msg.dcn.yahoo.com is down, so I used
-	 * YAHOO_PAGER_HOST_FALLBACK, but I'm not sure, if it is the correct
-	 * host.
-	 */
-	if (purple_proxy_connect(gc, account, YAHOO_PAGER_HOST_FALLBACK,
-		purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
-		yahoo_got_web_connected, gc) == NULL)
-	{
-		purple_connection_error(gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Unable to connect"));
-		return;
-	}
-}
-
-static void yahoo_login_page_hash_iter(const char *key, const char *val, GString *url)
-{
-	if (!strcmp(key, "passwd") || !strcmp(key, "login"))
-		return;
-	g_string_append_c(url, '&');
-	g_string_append(url, key);
-	g_string_append_c(url, '=');
-	if (!strcmp(key, ".save") || !strcmp(key, ".js"))
-		g_string_append_c(url, '1');
-	else if (!strcmp(key, ".challenge"))
-		g_string_append(url, val);
-	else
-		g_string_append(url, purple_url_encode(val));
-}
-
-static GHashTable *yahoo_login_page_hash(const char *buf, size_t len)
-{
-	GHashTable *hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-	const char *c = buf;
-	char *d;
-	char name[64], value[64];
-	int count;
-	int input_len = strlen("<input ");
-	int name_len = strlen("name=\"");
-	int value_len = strlen("value=\"");
-	while ((len > ((c - buf) + input_len))
-			&& (c = strstr(c, "<input "))) {
-		if (!(c = g_strstr_len(c, len - (c - buf), "name=\"")))
-			continue;
-		c += name_len;
-		count = sizeof(name)-1;
-		for (d = name; (len > ((c - buf) + 1)) && *c!='"'
-				&& count; c++, d++, count--)
-			*d = *c;
-		*d = '\0';
-		count = sizeof(value)-1;
-		if (!(d = g_strstr_len(c, len - (c - buf), "value=\"")))
-			continue;
-		d += value_len;
-		if (strchr(c, '>') < d)
-			break;
-		for (c = d, d = value; (len > ((c - buf) + 1))
-				&& *c!='"' && count; c++, d++, count--)
-			*d = *c;
-		*d = '\0';
-		g_hash_table_insert(hash, g_strdup(name), g_strdup(value));
-	}
-	return hash;
-}
-
-static void
-yahoo_login_page_cb(PurpleHttpConnection *http_conn,
-	PurpleHttpResponse *response, gpointer _unused)
-{
-	PurpleConnection *gc = purple_http_conn_get_purple_connection(http_conn);
-	PurpleAccount *account = purple_connection_get_account(gc);
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	const char *pass = purple_connection_get_password(gc);
-	size_t len;
-	const gchar *got_data;
-	GHashTable *hash;
-	GString *url;
-	char md5[33], *hashp = md5, *chal;
-	int i;
-	PurpleCipher *cipher;
-	guchar digest[16];
-	PurpleHttpRequest *req;
-
-	if (!purple_http_response_is_successful(response))
-	{
-		purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			purple_http_response_get_error(response));
-		return;
-	}
-
-	got_data = purple_http_response_get_data(response, &len);
-	hash = yahoo_login_page_hash(got_data, len);
-
-	cipher = purple_md5_cipher_new();
-
-	purple_cipher_append(cipher, (const guchar *)pass, strlen(pass));
-	purple_cipher_digest(cipher, digest, sizeof(digest));
-	for (i = 0; i < 16; ++i) {
-		g_snprintf(hashp, 3, "%02x", digest[i]);
-		hashp += 2;
-	}
-
-	chal = g_strconcat(md5, g_hash_table_lookup(hash, ".challenge"), NULL);
-	purple_cipher_reset(cipher);
-	purple_cipher_append(cipher, (const guchar *)chal, strlen(chal));
-	purple_cipher_digest(cipher, digest, sizeof(digest));
-	hashp = md5;
-	for (i = 0; i < 16; ++i) {
-		g_snprintf(hashp, 3, "%02x", digest[i]);
-		hashp += 2;
-	}
-	/*
-	 * I dunno why this is here and commented out.. but in case it's needed
-	 * I updated it..
-
-	purple_cipher_reset(cipher);
-	purple_cipher_append(cipher, md5, strlen(md5));
-	purple_cipher_digest(cipher, sizeof(digest), digest, NULL);
-	hashp = md5;
-	for (i = 0; i < 16; ++i) {
-		g_snprintf(hashp, 3, "%02x", digest[i]);
-		hashp += 2;
-	}
-	*/
-	g_free(chal);
-
-	url = g_string_new(NULL);
-	g_string_printf(url, "http://login.yahoo.com/config/login?login=%s&passwd=%s", purple_account_get_username(account), md5);
-	g_hash_table_foreach(hash, (GHFunc)yahoo_login_page_hash_iter, url);
-	url = g_string_append(url, "&.hash=1&.md5=1");
-
-	g_hash_table_destroy(hash);
-	g_object_unref(cipher);
-
-	req = purple_http_request_new(g_string_free(url, FALSE));
-	purple_http_request_set_max_redirects(req, 0);
-	purple_http_connection_set_add(yd->http_reqs,
-		purple_http_request(gc, req, yahoo_login_page_got, NULL));
-	purple_http_request_unref(req);
-}
-
-#endif /* TRY_WEBMESSENGER_LOGIN */
-
-static void yahoo_picture_check(PurpleAccount *account)
-{
-	PurpleConnection *gc = purple_account_get_connection(account);
-	PurpleImage *img = purple_buddy_icons_find_account_icon(account);
-
-	yahoo_set_buddy_icon(gc, img);
-
-	if (img)
-		g_object_unref(img);
-}
-
-static int get_yahoo_status_from_purple_status(PurpleStatus *status)
-{
-	PurplePresence *presence;
-	const char *status_id;
-	const char *msg;
-
-	presence = purple_status_get_presence(status);
-	status_id = purple_status_get_id(status);
-	msg = purple_status_get_attr_string(status, "message");
-
-	if ((msg != NULL) && (*msg != '\0')) {
-		return YAHOO_STATUS_CUSTOM;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_AVAILABLE)) {
-		return YAHOO_STATUS_AVAILABLE;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_BRB)) {
-		return YAHOO_STATUS_BRB;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_BUSY)) {
-		return YAHOO_STATUS_BUSY;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTATHOME)) {
-		return YAHOO_STATUS_NOTATHOME;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTATDESK)) {
-		return YAHOO_STATUS_NOTATDESK;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTINOFFICE)) {
-		return YAHOO_STATUS_NOTINOFFICE;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_ONPHONE)) {
-		return YAHOO_STATUS_ONPHONE;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_ONVACATION)) {
-		return YAHOO_STATUS_ONVACATION;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_OUTTOLUNCH)) {
-		return YAHOO_STATUS_OUTTOLUNCH;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_STEPPEDOUT)) {
-		return YAHOO_STATUS_STEPPEDOUT;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_INVISIBLE)) {
-		return YAHOO_STATUS_INVISIBLE;
-	} else if (!strcmp(status_id, YAHOO_STATUS_TYPE_AWAY)) {
-		return YAHOO_STATUS_CUSTOM;
-	} else if (purple_presence_is_idle(presence)) {
-		return YAHOO_STATUS_IDLE;
-	} else {
-		purple_debug_error("yahoo", "Unexpected PurpleStatus!\n");
-		return YAHOO_STATUS_AVAILABLE;
-	}
-}
-
-static void yahoo_got_pager_server(PurpleHttpConnection *http_conn,
-	PurpleHttpResponse *response, gpointer _yd)
-{
-	YahooData *yd = _yd;
-	PurpleConnection *gc = yd->gc;
-	PurpleAccount *a = purple_connection_get_account(gc);
-	gchar **strings = NULL, *cs_server = NULL;
-	int port = purple_account_get_int(a, "port", YAHOO_PAGER_PORT);
-	int stringslen = 0;
-	const gchar *got_data;
-
-	if (!purple_http_response_is_successful(response)) {
-		purple_debug_error("yahoo", "Unable to retrieve server info: %s\n",
-			purple_http_response_get_error(response));
-
-		if(purple_proxy_connect(gc, a, YAHOO_PAGER_HOST_FALLBACK, port,
-				yahoo_got_connected, gc) == NULL) {
-			purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-					_("Unable to connect"));
-		}
-	} else {
-		got_data = purple_http_response_get_data(response, NULL);
-		strings = g_strsplit(got_data, "\r\n", -1);
-
-		if((stringslen = g_strv_length(strings)) > 1) {
-			int i;
-
-			for(i = 0; i < stringslen; i++) {
-				if(g_ascii_strncasecmp(strings[i], "COLO_CAPACITY=", 14) == 0) {
-					purple_debug_info("yahoo", "Got COLO Capacity: %s\n", &(strings[i][14]));
-				} else if(g_ascii_strncasecmp(strings[i], "CS_IP_ADDRESS=", 14) == 0) {
-					cs_server = g_strdup(&strings[i][14]);
-					purple_debug_info("yahoo", "Got CS IP address: %s\n", cs_server);
-				}
-			}
-		}
-
-		if(cs_server) { /* got an address; get on with connecting */
-			if(purple_proxy_connect(gc, a, cs_server, port, yahoo_got_connected, gc) == NULL)
-				purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-								_("Unable to connect"));
-		} else {
-			purple_debug_error("yahoo", "No CS address retrieved!  Server "
-					"response:\n%s\n", got_data);
-
-			if(purple_proxy_connect(gc, a, YAHOO_PAGER_HOST_FALLBACK, port,
-					yahoo_got_connected, gc) == NULL) {
-				purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-						_("Unable to connect"));
-			}
-		}
-	}
-
-	g_strfreev(strings);
-	g_free(cs_server);
-}
-
-void yahoo_login(PurpleAccount *account) {
-	PurpleConnection *gc = purple_account_get_connection(account);
-	PurpleHttpRequest *req;
-	YahooData *yd = g_new0(YahooData, 1);
-	PurpleStatus *status = purple_account_get_active_status(account);
-
-	purple_connection_set_protocol_data(gc, yd);
-	purple_connection_set_flags(gc, PURPLE_CONNECTION_FLAG_HTML |
-		PURPLE_CONNECTION_FLAG_NO_BGCOLOR |
-		PURPLE_CONNECTION_FLAG_NO_URLDESC |
-		PURPLE_CONNECTION_FLAG_NO_IMAGES);
-
-	purple_connection_update_progress(gc, _("Connecting"), 1, 2);
-
-	purple_connection_set_display_name(gc, purple_account_get_username(account));
-
-	yd->gc = gc;
-	yd->yahoo_local_p2p_server_fd = -1;
-	yd->fd = -1;
-	yd->txhandler = 0;
-	/* TODO: Is there a good grow size for the buffer? */
-	yd->txbuf = purple_circular_buffer_new(0);
-	yd->http_reqs = purple_http_connection_set_new();
-	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);
-	yd->peers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
-					yahoo_p2p_disconnect_destroy_data);
-	yd->sms_carrier = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-	yd->yahoo_p2p_timer = purple_timeout_add_seconds(YAHOO_P2P_KEEPALIVE_SECS,
-					yahoo_p2p_keepalive, gc);
-	yd->confs = NULL;
-	yd->conf_id = 2;
-	yd->last_keepalive = yd->last_ping = time(NULL);
-
-	yd->current_status = get_yahoo_status_from_purple_status(status);
-
-	yahoo_picture_check(account);
-
-	/* Get the pager server.  Actually start connecting in the callback since we
-	 * must have the contents of the HTTP response to proceed. */
-	req = purple_http_request_new(YAHOO_PAGER_HOST_REQ_URL);
-	purple_http_request_header_set(req, "User-Agent", YAHOO_CLIENT_USERAGENT);
-	purple_http_connection_set_add(yd->http_reqs, purple_http_request(gc,
-		req, yahoo_got_pager_server, yd));
-	purple_http_request_unref(req);
-
-	return;
-}
-
-void yahoo_close(PurpleConnection *gc) {
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	GSList *l;
-
-	if (yd->inpa) {
-		purple_input_remove(yd->inpa);
-		yd->inpa = 0;
-	}
-
-	purple_http_connection_set_destroy(yd->http_reqs);
-	yd->http_reqs = NULL;
-
-	for (l = yd->confs; l; l = l->next) {
-		PurpleChatConversation *conv = l->data;
-		GList *users;
-
-		users = purple_chat_conversation_get_users(conv);
-		yahoo_conf_leave(yd,
-			purple_conversation_get_name(PURPLE_CONVERSATION(conv)),
-			purple_connection_get_display_name(gc), users);
-		g_list_free(users);
-	}
-	g_slist_free(yd->confs);
-
-	g_slist_free_full(yd->cookies, g_free);
-
-	yd->chat_online = FALSE;
-	if (yd->in_chat)
-		yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */
-
-	purple_timeout_remove(yd->yahoo_p2p_timer);
-	if(yd->yahoo_p2p_server_timeout_handle != 0) {
-		purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle);
-		yd->yahoo_p2p_server_timeout_handle = 0;
-	}
-
-	/* close p2p server if it is waiting for a peer to connect */
-	if (yd->yahoo_p2p_server_watcher) {
-		purple_input_remove(yd->yahoo_p2p_server_watcher);
-		yd->yahoo_p2p_server_watcher = 0;
-	}
-	if (yd->yahoo_local_p2p_server_fd >= 0) {
-		close(yd->yahoo_local_p2p_server_fd);
-		yd->yahoo_local_p2p_server_fd = -1;
-	}
-
-	g_hash_table_destroy(yd->sms_carrier);
-	g_hash_table_destroy(yd->peers);
-	g_hash_table_destroy(yd->friends);
-	g_hash_table_destroy(yd->imvironments);
-	g_hash_table_destroy(yd->xfer_peer_idstring_map);
-	g_free(yd->chat_name);
-
-	g_free(yd->cookie_y);
-	g_free(yd->cookie_t);
-	g_free(yd->cookie_b);
-
-	if (yd->txhandler)
-		purple_input_remove(yd->txhandler);
-
-	g_object_unref(G_OBJECT(yd->txbuf));
-
-	if (yd->fd >= 0)
-		close(yd->fd);
-
-	g_free(yd->rxqueue);
-	yd->rxlen = 0;
-	g_free(yd->picture_url);
-
-	purple_http_conn_cancel(yd->picture_upload_hc);
-	if (yd->picture_upload_todo)
-		yahoo_buddy_icon_upload_data_free(yd->picture_upload_todo);
-	if (yd->ycht)
-		ycht_connection_close(yd->ycht);
-	if (yd->listen_data != NULL)
-		purple_network_listen_cancel(yd->listen_data);
-
-	g_free(yd->pending_chat_room);
-	g_free(yd->pending_chat_id);
-	g_free(yd->pending_chat_topic);
-	g_free(yd->pending_chat_goto);
-	g_strfreev(yd->profiles);
-
-	yahoo_personal_details_reset(&yd->ypd, TRUE);
-
-	g_free(yd->current_list15_grp);
-
-	g_free(yd);
-	purple_connection_set_protocol_data(gc, NULL);
-}
-
-const char *yahoo_list_icon(PurpleAccount *a, PurpleBuddy *b)
-{
-	return "yahoo";
-}
-
-const char *yahoo_list_emblem(PurpleBuddy *b)
-{
-	PurpleAccount *account;
-	PurpleConnection *gc;
-	YahooFriend *f;
-	PurplePresence *presence;
-
-	if (!b || !(account = purple_buddy_get_account(b)) ||
-			!(gc = purple_account_get_connection(account)) ||
-			!purple_connection_get_protocol_data(gc))
-		return NULL;
-
-	f = yahoo_friend_find(gc, purple_buddy_get_name(b));
-	if (!f) {
-		return "not-authorized";
-	}
-
-	presence = purple_buddy_get_presence(b);
-
-	if (purple_presence_is_online(presence)) {
-		if (yahoo_friend_get_game(f))
-			return "game";
-	}
-	return NULL;
-}
-
-static const char *yahoo_get_status_string(enum yahoo_status a)
-{
-	switch (a) {
-	case YAHOO_STATUS_BRB:
-		return _("Be Right Back");
-	case YAHOO_STATUS_BUSY:
-		return _("Busy");
-	case YAHOO_STATUS_NOTATHOME:
-		return _("Not at Home");
-	case YAHOO_STATUS_NOTATDESK:
-		return _("Not at Desk");
-	case YAHOO_STATUS_NOTINOFFICE:
-		return _("Not in Office");
-	case YAHOO_STATUS_ONPHONE:
-		return _("On the Phone");
-	case YAHOO_STATUS_ONVACATION:
-		return _("On Vacation");
-	case YAHOO_STATUS_OUTTOLUNCH:
-		return _("Out to Lunch");
-	case YAHOO_STATUS_STEPPEDOUT:
-		return _("Stepped Out");
-	case YAHOO_STATUS_INVISIBLE:
-		return _("Invisible");
-	case YAHOO_STATUS_IDLE:
-		return _("Idle");
-	case YAHOO_STATUS_OFFLINE:
-		return _("Offline");
-	default:
-		return _("Available");
-	}
-}
-
-static void yahoo_initiate_conference(PurpleBlistNode *node, gpointer data) {
-
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-
-	GHashTable *components;
-	YahooData *yd;
-	int id;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-	yd = purple_connection_get_protocol_data(gc);
-	id = yd->conf_id;
-
-	components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-	g_hash_table_replace(components, g_strdup("room"),
-		g_strdup_printf("%s-%d", purple_connection_get_display_name(gc), id));
-	g_hash_table_replace(components, g_strdup("topic"), g_strdup("Join my conference..."));
-	g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference"));
-	yahoo_c_join(gc, components);
-	g_hash_table_destroy(components);
-
-	yahoo_c_invite(gc, id, "Join my conference...", purple_buddy_get_name(buddy));
-}
-
-static void yahoo_presence_settings(PurpleBlistNode *node, gpointer data) {
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-	int presence_val = GPOINTER_TO_INT(data);
-
-	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-
-	yahoo_friend_update_presence(gc, purple_buddy_get_name(buddy), presence_val);
-}
-
-static void yahoo_game(PurpleBlistNode *node, gpointer data) {
-
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-
-	const char *game;
-	char *game2;
-	char *t;
-	char url[256];
-	YahooFriend *f;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-
-	f = yahoo_friend_find(gc, purple_buddy_get_name(buddy));
-	if (!f)
-		return;
-
-	game = yahoo_friend_get_game(f);
-	if (!game)
-		return;
-
-	t = game2 = g_strdup(strstr(game, "ante?room="));
-	while (*t && *t != '\t')
-		t++;
-	*t = 0;
-	g_snprintf(url, sizeof url, "http://games.yahoo.com/games/%s", game2);
-	purple_notify_uri(gc, url);
-	g_free(game2);
-}
-
-char *yahoo_status_text(PurpleBuddy *b)
-{
-	YahooFriend *f = NULL;
-	const char *msg;
-	char *msg2;
-	PurpleAccount *account;
-	PurpleConnection *gc;
-
-	account = purple_buddy_get_account(b);
-	gc = purple_account_get_connection(account);
-	if (!gc || !purple_connection_get_protocol_data(gc))
-		return NULL;
-
-	f = yahoo_friend_find(gc, purple_buddy_get_name(b));
-	if (!f)
-		return g_strdup(_("Not on server list"));
-
-	switch (f->status) {
-	case YAHOO_STATUS_AVAILABLE:
-		return NULL;
-	case YAHOO_STATUS_IDLE:
-		if (f->idle == -1)
-			return g_strdup(yahoo_get_status_string(f->status));
-		return NULL;
-	case YAHOO_STATUS_CUSTOM:
-		if (!(msg = yahoo_friend_get_status_message(f)))
-			return NULL;
-		msg2 = g_markup_escape_text(msg, strlen(msg));
-		purple_util_chrreplace(msg2, '\n', ' ');
-		return msg2;
-
-	default:
-		return g_strdup(yahoo_get_status_string(f->status));
-	}
-}
-
-void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
-{
-	YahooFriend *f;
-	char *status = NULL;
-	const char *presence = NULL;
-	PurpleAccount *account;
-
-	account = purple_buddy_get_account(b);
-	f = yahoo_friend_find(purple_account_get_connection(account), purple_buddy_get_name(b));
-	if (!f)
-		status = g_strdup_printf("\n%s", _("Not on server list"));
-	else {
-		switch (f->status) {
-		case YAHOO_STATUS_CUSTOM:
-			if (!yahoo_friend_get_status_message(f))
-				return;
-			status = g_strdup(yahoo_friend_get_status_message(f));
-			break;
-		case YAHOO_STATUS_OFFLINE:
-			break;
-		default:
-			status = g_strdup(yahoo_get_status_string(f->status));
-			break;
-		}
-
-		switch (f->presence) {
-			case YAHOO_PRESENCE_ONLINE:
-				presence = _("Appear Online");
-				break;
-			case YAHOO_PRESENCE_PERM_OFFLINE:
-				presence = _("Appear Permanently Offline");
-				break;
-			case YAHOO_PRESENCE_DEFAULT:
-				break;
-			default:
-				purple_debug_error("yahoo", "Unknown presence in yahoo_tooltip_text\n");
-				break;
-		}
-	}
-
-	if (status != NULL) {
-		purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), status);
-		g_free(status);
-	}
-
-	if (presence != NULL)
-		purple_notify_user_info_add_pair_plaintext(user_info, _("Presence"), presence);
-
-	if (f && full) {
-		YahooPersonalDetails *ypd = &f->ypd;
-		if (ypd->phone.home && *ypd->phone.home)
-			purple_notify_user_info_add_pair_plaintext(user_info, _("Home Phone Number"), ypd->phone.home);
-		if (ypd->phone.work && *ypd->phone.work)
-			purple_notify_user_info_add_pair_plaintext(user_info, _("Work Phone Number"), ypd->phone.work);
-		if (ypd->phone.mobile && *ypd->phone.mobile)
-			purple_notify_user_info_add_pair_plaintext(user_info, _("Mobile Phone Number"), ypd->phone.mobile);
-	}
-}
-
-static void yahoo_addbuddyfrommenu_cb(PurpleBlistNode *node, gpointer data)
-{
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-
-	yahoo_add_buddy(gc, buddy, NULL, NULL);
-}
-
-
-static void yahoo_chat_goto_menu(PurpleBlistNode *node, gpointer data)
-{
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-
-	g_return_if_fail(PURPLE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-
-	yahoo_chat_goto(gc, purple_buddy_get_name(buddy));
-}
-
-static GList *build_presence_submenu(YahooFriend *f, PurpleConnection *gc) {
-	GList *m = NULL;
-	PurpleMenuAction *act;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-
-	if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
-		if (f->presence != YAHOO_PRESENCE_ONLINE) {
-			act = purple_menu_action_new(_("Appear Online"),
-			                           PURPLE_CALLBACK(yahoo_presence_settings),
-			                           GINT_TO_POINTER(YAHOO_PRESENCE_ONLINE),
-			                           NULL);
-			m = g_list_append(m, act);
-		} else if (f->presence != YAHOO_PRESENCE_DEFAULT) {
-			act = purple_menu_action_new(_("Appear Offline"),
-			                           PURPLE_CALLBACK(yahoo_presence_settings),
-			                           GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT),
-			                           NULL);
-			m = g_list_append(m, act);
-		}
-	}
-
-	if (f->presence == YAHOO_PRESENCE_PERM_OFFLINE) {
-		act = purple_menu_action_new(_("Don't Appear Permanently Offline"),
-		                           PURPLE_CALLBACK(yahoo_presence_settings),
-		                           GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT),
-		                           NULL);
-		m = g_list_append(m, act);
-	} else {
-		act = purple_menu_action_new(_("Appear Permanently Offline"),
-		                           PURPLE_CALLBACK(yahoo_presence_settings),
-		                           GINT_TO_POINTER(YAHOO_PRESENCE_PERM_OFFLINE),
-		                           NULL);
-		m = g_list_append(m, act);
-	}
-
-	return m;
-}
-
-static void yahoo_doodle_blist_node(PurpleBlistNode *node, gpointer data)
-{
-	PurpleBuddy *b = (PurpleBuddy *)node;
-	PurpleAccount *account = purple_buddy_get_account(b);
-	PurpleConnection *gc = purple_account_get_connection(account);
-
-	yahoo_doodle_initiate(gc, purple_buddy_get_name(b));
-}
-
-#if 0
-/* XXX: it doesn't seems to work */
-static void
-yahoo_userinfo_blist_node(PurpleBlistNode *node, gpointer data)
-{
-	PurpleBuddy *b = (PurpleBuddy *)node;
-	PurpleAccount *account = purple_buddy_get_account(b);
-	PurpleConnection *gc = purple_account_get_connection(account);
-
-	yahoo_set_userinfo_for_buddy(gc, b);
-}
-#endif
-
-static GList *yahoo_buddy_menu(PurpleBuddy *buddy)
-{
-	GList *m = NULL;
-	PurpleMenuAction *act;
-
-	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	static char buf2[1024];
-	YahooFriend *f;
-
-	f = yahoo_friend_find(gc, purple_buddy_get_name(buddy));
-
-	if (!f && !yd->wm) {
-		act = purple_menu_action_new(_("Add Buddy"),
-		                           PURPLE_CALLBACK(yahoo_addbuddyfrommenu_cb),
-		                           NULL, NULL);
-		m = g_list_append(m, act);
-
-		return m;
-
-	}
-
-	if (f && f->status != YAHOO_STATUS_OFFLINE) {
-		if (!yd->wm) {
-			act = purple_menu_action_new(_("Join in Chat"),
-			                           PURPLE_CALLBACK(yahoo_chat_goto_menu),
-			                           NULL, NULL);
-			m = g_list_append(m, act);
-		}
-
-		act = purple_menu_action_new(_("Initiate Conference"),
-		                           PURPLE_CALLBACK(yahoo_initiate_conference),
-		                           NULL, NULL);
-		m = g_list_append(m, act);
-
-		if (yahoo_friend_get_game(f)) {
-			const char *game = yahoo_friend_get_game(f);
-			char *room;
-			char *t;
-
-			if ((room = strstr(game, "&follow="))) {/* skip ahead to the url */
-				while (*room && *room != '\t')          /* skip to the tab */
-					room++;
-				t = room++;                             /* room as now at the name */
-				while (*t != '\n')
-					t++;                            /* replace the \n with a space */
-				*t = ' ';
-				g_snprintf(buf2, sizeof buf2, "%s", room);
-
-				act = purple_menu_action_new(buf2,
-				                           PURPLE_CALLBACK(yahoo_game),
-				                           NULL, NULL);
-				m = g_list_append(m, act);
-			}
-		}
-	}
-
-	if (f) {
-		act = purple_menu_action_new(_("Presence Settings"), NULL, NULL,
-		                           build_presence_submenu(f, gc));
-		m = g_list_append(m, act);
-
-		act = purple_menu_action_new(_("Start Doodling"),
-				PURPLE_CALLBACK(yahoo_doodle_blist_node),
-				NULL, NULL);
-		m = g_list_append(m, act);
-
-#if 0
-		/* XXX: it doesn't seems to work */
-		act = purple_menu_action_new(_("Set User Info..."),
-		                           PURPLE_CALLBACK(yahoo_userinfo_blist_node),
-		                           NULL, NULL);
-		m = g_list_append(m, act);
-#endif
-	}
-
-	return m;
-}
-
-GList *yahoo_blist_node_menu(PurpleBlistNode *node)
-{
-	if(PURPLE_IS_BUDDY(node)) {
-		return yahoo_buddy_menu((PurpleBuddy *) node);
-	} else {
-		return NULL;
-	}
-}
-
-static void yahoo_act_id(PurpleConnection *gc, PurpleRequestFields *fields)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	const char *name = yd->profiles[GPOINTER_TO_INT(purple_request_fields_get_choice(fields, "id"))];
-
-	struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_IDACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash_str(pkt, 3, name);
-	yahoo_packet_send_and_free(pkt, yd);
-
-	purple_connection_set_display_name(gc, name);
-}
-
-static void
-yahoo_get_inbox_token_cb(PurpleHttpConnection *http_conn,
-	PurpleHttpResponse *response, gpointer _unused)
-{
-	PurpleConnection *gc =
-		purple_http_conn_get_purple_connection(http_conn);
-	gchar *url;
-
-	PURPLE_ASSERT_CONNECTION_IS_VALID(gc);
-
-	if (!purple_http_response_is_successful(response)) {
-		purple_debug_error("yahoo",
-			"Requesting mail login token failed: %s\n",
-			purple_http_response_get_error(response));
-		url = g_strdup(YAHOO_MAIL_URL);
-	} else {
-		/* Should we not be hardcoding the rd url? */
-		gchar *token;
-		token = g_strdup(purple_http_response_get_data(response, NULL));
-		g_strstrip(token);
-		url = g_strdup_printf(
-			"http://login.yahoo.com/config/reset_cookies_token?"
-			".token=%s"
-			"&.done=http://us.rd.yahoo.com/messenger/client/%%3f"
-			"http://mail.yahoo.com/", token);
-		purple_str_wipe(token);
-	}
-
-	/* Open the mailbox with the parsed url data */
-	purple_notify_uri(gc, url);
-
-	g_free(url);
-}
-
-
-static void yahoo_show_inbox(PurpleProtocolAction *action)
-{
-	/* Setup a cookie that can be used by the browser */
-
-	PurpleConnection *gc = action->connection;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	PurpleHttpRequest *req;
-	PurpleHttpCookieJar *cookiejar;
-
-	req = purple_http_request_new(
-		"https://login.yahoo.com/config/cookie_token");
-	purple_http_request_set_method(req, "POST");
-	purple_http_request_header_set(req, "User-Agent",
-		YAHOO_CLIENT_USERAGENT);
-	cookiejar = purple_http_request_get_cookie_jar(req);
-	purple_http_cookie_jar_set(cookiejar, "T", yd->cookie_t);
-	purple_http_cookie_jar_set(cookiejar, "Y", yd->cookie_y);
-	purple_http_connection_set_add(yd->http_reqs, purple_http_request(gc,
-		req, yahoo_get_inbox_token_cb, NULL));
-	purple_http_request_unref(req);
-}
-
-#if 0
-/* XXX: it doesn't seems to work */
-static void
-yahoo_set_userinfo_fn(PurpleProtocolAction *action)
-{
-	yahoo_set_userinfo(action->connection);
-}
-#endif
-
-static void yahoo_show_act_id(PurpleProtocolAction *action)
-{
-	PurpleRequestFields *fields;
-	PurpleRequestFieldGroup *group;
-	PurpleRequestField *field;
-	PurpleConnection *gc = (PurpleConnection *) action->connection;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	const char *name = purple_connection_get_display_name(gc);
-	int iter;
-
-	fields = purple_request_fields_new();
-	group = purple_request_field_group_new(NULL);
-	purple_request_fields_add_group(fields, group);
-	field = purple_request_field_choice_new("id", _("Activate which ID?"), 0);
-	purple_request_field_group_add_field(group, field);
-
-	for (iter = 0; yd->profiles[iter]; iter++) {
-		purple_request_field_choice_add(field, yd->profiles[iter], GINT_TO_POINTER(iter));
-		if (purple_strequal(yd->profiles[iter], name))
-			purple_request_field_choice_set_default_value(field, GINT_TO_POINTER(iter));
-	}
-
-	purple_request_fields(gc, NULL, _("Select the ID you want to activate"), NULL,
-					   fields,
-					   _("OK"), G_CALLBACK(yahoo_act_id),
-					   _("Cancel"), NULL,
-					   purple_request_cpar_from_connection(gc), gc);
-}
-
-static void yahoo_show_chat_goto(PurpleProtocolAction *action)
-{
-	PurpleConnection *gc = action->connection;
-	purple_request_input(gc, NULL, _("Join whom in chat?"), NULL,
-					   "", FALSE, FALSE, NULL,
-					   _("OK"), G_CALLBACK(yahoo_chat_goto),
-					   _("Cancel"), NULL,
-					   purple_request_cpar_from_connection(gc),
-					   gc);
-}
-
-GList *yahoo_get_actions(PurpleConnection *gc) {
-	GList *m = NULL;
-	PurpleProtocolAction *act;
-
-#if 0
-	/* XXX: it doesn't seems to work */
-	act = purple_protocol_action_new(_("Set User Info..."),
-			yahoo_set_userinfo_fn);
-	m = g_list_append(m, act);
-#endif
-
-	act = purple_protocol_action_new(_("Activate ID..."),
-			yahoo_show_act_id);
-	m = g_list_append(m, act);
-
-	act = purple_protocol_action_new(_("Join User in Chat..."),
-			yahoo_show_chat_goto);
-	m = g_list_append(m, act);
-
-	m = g_list_append(m, NULL);
-	act = purple_protocol_action_new(_("Open Inbox"),
-			yahoo_show_inbox);
-	m = g_list_append(m, act);
-
-	return m;
-}
-
-struct yahoo_sms_carrier_cb_data	{
-	PurpleConnection *gc;
-	char *who;
-	char *what;
-};
-
-static void yahoo_get_sms_carrier_cb(PurpleHttpConnection *http_conn,
-	PurpleHttpResponse *response, gpointer _sms_cb_data)
-{
-	struct yahoo_sms_carrier_cb_data *sms_cb_data = _sms_cb_data;
-	PurpleConnection *gc = sms_cb_data->gc;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	char *status = NULL;
-	char *carrier = NULL;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleIMConversation *im = purple_conversations_find_im_with_account(sms_cb_data->who, account);
-
-	if (!purple_http_response_is_successful(response)) {
-		purple_conversation_write_system_message(PURPLE_CONVERSATION(im),
-			_("Can't send SMS. Unable to obtain mobile carrier."), 0);
-
-		g_free(sms_cb_data->who);
-		g_free(sms_cb_data->what);
-		g_free(sms_cb_data);
-		return ;
-	} else {
-		const gchar *got_data = purple_http_response_get_data(response, NULL);
-		PurpleXmlNode *validate_data_root = purple_xmlnode_from_str(got_data, -1);
-		PurpleXmlNode *validate_data_child = purple_xmlnode_get_child(validate_data_root, "mobile_no");
-		const char *mobile_no = purple_xmlnode_get_attrib(validate_data_child, "msisdn");
-
-		validate_data_root = purple_xmlnode_copy(validate_data_child);
-		validate_data_child = purple_xmlnode_get_child(validate_data_root, "status");
-		status = purple_xmlnode_get_data(validate_data_child);
-
-		validate_data_child = purple_xmlnode_get_child(validate_data_root, "carrier");
-		carrier = purple_xmlnode_get_data(validate_data_child);
-
-		purple_debug_info("yahoo", "SMS validate data: %s\n", got_data);
-
-		if (status && g_str_equal(status, "Valid")) {
-			g_hash_table_insert(yd->sms_carrier,
-					g_strdup_printf("+%s", mobile_no), g_strdup(carrier));
-			yahoo_send_im(sms_cb_data->gc, purple_message_new_outgoing(
-				sms_cb_data->who, sms_cb_data->what, 0));
-		} else {
-			g_hash_table_insert(yd->sms_carrier,
-					g_strdup_printf("+%s", mobile_no), g_strdup("Unknown"));
-			purple_conversation_write_system_message(PURPLE_CONVERSATION(im),
-				_("Can't send SMS. Unknown mobile carrier."), 0);
-		}
-
-		purple_xmlnode_free(validate_data_child);
-		purple_xmlnode_free(validate_data_root);
-		g_free(sms_cb_data->who);
-		g_free(sms_cb_data->what);
-		g_free(sms_cb_data);
-		g_free(status);
-		g_free(carrier);
-	}
-}
-
-static void yahoo_get_sms_carrier(PurpleConnection *gc, gpointer data)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	PurpleHttpRequest *req;
-	PurpleHttpCookieJar *cookiejar;
-	struct yahoo_sms_carrier_cb_data *sms_cb_data;
-	char *validate_request_str = NULL;
-	PurpleXmlNode *validate_request_root = NULL;
-	PurpleXmlNode *validate_request_child = NULL;
-
-	if(!(sms_cb_data = data))
-		return;
-
-	validate_request_root = purple_xmlnode_new("validate");
-	purple_xmlnode_set_attrib(validate_request_root, "intl", "us");
-	purple_xmlnode_set_attrib(validate_request_root, "version", YAHOO_CLIENT_VERSION);
-	purple_xmlnode_set_attrib(validate_request_root, "qos", "0");
-
-	validate_request_child = purple_xmlnode_new_child(validate_request_root, "mobile_no");
-	purple_xmlnode_set_attrib(validate_request_child, "msisdn", sms_cb_data->who + 1);
-
-	validate_request_str = purple_xmlnode_to_str(validate_request_root, NULL);
-
-	purple_xmlnode_free(validate_request_child);
-	purple_xmlnode_free(validate_request_root);
-
-	req = purple_http_request_new(NULL);
-	purple_http_request_set_url_printf(req, "http://validate.msg.yahoo.com"
-		"/mobileno?intl=us&version=%s", YAHOO_CLIENT_VERSION);
-	purple_http_request_set_method(req, "POST");
-	purple_http_request_header_set(req, "User-Agent",
-		YAHOO_CLIENT_USERAGENT);
-	cookiejar = purple_http_request_get_cookie_jar(req);
-	purple_http_cookie_jar_set(cookiejar, "T", yd->cookie_t);
-	purple_http_cookie_jar_set(cookiejar, "Y", yd->cookie_y);
-	purple_http_request_set_contents(req, validate_request_str, -1);
-	purple_http_connection_set_add(yd->http_reqs, purple_http_request(gc,
-		req, yahoo_get_sms_carrier_cb, data));
-	purple_http_request_unref(req);
-
-	g_free(validate_request_str);
-}
-
-int yahoo_send_im(PurpleConnection *gc, PurpleMessage *pmsg)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_packet *pkt = NULL;
-	char *msg = yahoo_html_to_codes(purple_message_get_contents(pmsg));
-	char *msg2;
-	PurpleWhiteboard *wb;
-	int ret = 1;
-	gsize lenb = 0;
-	glong lenc = 0;
-	struct yahoo_p2p_data *p2p_data;
-	const gchar *rcpt = purple_message_get_recipient(pmsg);
-
-	msg2 = yahoo_string_encode(gc, msg, TRUE);
-
-	if(msg2) {
-		lenb = strlen(msg2);
-		lenc = g_utf8_strlen(msg2, -1);
-
-		if(lenb > YAHOO_MAX_MESSAGE_LENGTH_BYTES || lenc > YAHOO_MAX_MESSAGE_LENGTH_CHARS) {
-			purple_debug_info("yahoo", "Message too big.  Length is %" G_GSIZE_FORMAT
-					" bytes, %ld characters.  Max is %d bytes, %d chars."
-					"  Message is '%s'.\n", lenb, lenc, YAHOO_MAX_MESSAGE_LENGTH_BYTES,
-					YAHOO_MAX_MESSAGE_LENGTH_CHARS, msg2);
-			g_free(msg);
-			g_free(msg2);
-			return -E2BIG;
-		}
-	}
-
-	if (rcpt[0] == '+') {
-		/* we have an sms to be sent */
-		gchar *carrier = NULL;
-		const char *alias = NULL;
-		PurpleAccount *account = purple_connection_get_account(gc);
-		PurpleIMConversation *im = purple_conversations_find_im_with_account(rcpt, account);
-
-		carrier = g_hash_table_lookup(yd->sms_carrier, rcpt);
-		if (!carrier) {
-			struct yahoo_sms_carrier_cb_data *sms_cb_data;
-			sms_cb_data = g_malloc(sizeof(struct yahoo_sms_carrier_cb_data));
-			sms_cb_data->gc = gc;
-			sms_cb_data->who = g_strdup(rcpt);
-			sms_cb_data->what = g_strdup(purple_message_get_contents(pmsg));
-
-			purple_conversation_write_system_message(PURPLE_CONVERSATION(im),
-				_("Getting mobile carrier to send the SMS."), 0);
-
-			yahoo_get_sms_carrier(gc, sms_cb_data);
-
-			g_free(msg);
-			g_free(msg2);
-			return ret;
-		}
-		else if( strcmp(carrier,"Unknown") == 0 ) {
-			purple_conversation_write_system_message(PURPLE_CONVERSATION(im),
-				_("Can't send SMS. Unknown mobile carrier."), 0);
-
-			g_free(msg);
-			g_free(msg2);
-			return -1;
-		}
-
-		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),
-			69, alias,
-			5, rcpt + 1,
-			68, carrier,
-			14, msg2);
-		yahoo_packet_send_and_free(pkt, yd);
-
-		g_free(msg);
-		g_free(msg2);
-
-		return ret;
-	}
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, yd->session_id);
-	yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, rcpt);
-
-	yahoo_packet_hash_str(pkt, 97, "1"); /* UTF-8 */
-	yahoo_packet_hash_str(pkt, 14, msg2);
-
-	/*
-	 * IMVironment.
-	 *
-	 * If this message is to a user who is also Doodling with the local user,
-	 * format the chat packet with the correct IMV information (thanks Yahoo!)
-	 *
-	 * Otherwise attempt to use the same IMVironment as the remote user,
-	 * just so that we don't inadvertantly reset their IMVironment back
-	 * to nothing.
-	 *
-	 * If they have not set an IMVironment, then use the default.
-	 */
-	wb = purple_whiteboard_get_session(purple_connection_get_account(gc), rcpt);
-	if (wb)
-		yahoo_packet_hash_str(pkt, 63, DOODLE_IMV_KEY);
-	else
-	{
-		const char *imv;
-		imv = g_hash_table_lookup(yd->imvironments, rcpt);
-		if (imv != NULL)
-			yahoo_packet_hash_str(pkt, 63, imv);
-		else
-			yahoo_packet_hash_str(pkt, 63, ";0");
-	}
-
-	yahoo_packet_hash_str(pkt,   64, "0"); /* no idea */
-	yahoo_packet_hash_str(pkt, 1002, "1"); /* no idea, Yahoo 6 or later only it seems */
-	if (!yd->picture_url)
-		yahoo_packet_hash_str(pkt, 206, "0"); /* 0 = no picture, 2 = picture, maybe 1 = avatar? */
-	else
-		yahoo_packet_hash_str(pkt, 206, "2");
-
-	/* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */
-	if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) {
-		/* if p2p link exists, send through it. To-do: key 15, time value to be sent in case of p2p */
-		if( (p2p_data = g_hash_table_lookup(yd->peers, rcpt))) {
-			yahoo_packet_hash_int(pkt, 11, p2p_data->session_id);
-			yahoo_p2p_write_pkt(p2p_data->source, pkt);
-		}
-		else	{
-			yahoo_packet_send(pkt, yd);
-			yahoo_send_p2p_pkt(gc, rcpt, 0);		/* send p2p packet, with val_13=0 */
-		}
-	}
-	else
-		ret = -E2BIG;
-
-	yahoo_packet_free(pkt);
-
-	g_free(msg);
-	g_free(msg2);
-
-	return ret;
-}
-
-unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleIMTypingState state)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_p2p_data *p2p_data;
-	struct yahoo_packet *pkt = NULL;
-
-	/* Don't do anything if sms is being typed */
-	if( strncmp(who, "+", 1) == 0 )
-		return 0;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, yd->session_id);
-
-	/* check to see if p2p link exists, send through it */
-	if( (p2p_data = g_hash_table_lookup(yd->peers, who))) {
-		yahoo_packet_hash(pkt, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc),
-	                  14, " ", 13, state == PURPLE_IM_TYPING ? "1" : "0",
-	                  5, who, 11, p2p_data->session_id, 1002, "1");	/* To-do: key 15 to be sent in case of p2p */
-		yahoo_p2p_write_pkt(p2p_data->source, pkt);
-		yahoo_packet_free(pkt);
-	}
-	else {	/* send through yahoo server */
-
-		yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
-                  14, " ", 13, state == PURPLE_IM_TYPING ? "1" : "0",
-                  5, who, 1002, "1");
-		yahoo_packet_send_and_free(pkt, yd);
-	}
-
-	return 0;
-}
-
-static void yahoo_session_presence_remove(gpointer key, gpointer value, gpointer data)
-{
-	YahooFriend *f = value;
-	if (f && f->presence == YAHOO_PRESENCE_ONLINE)
-		f->presence = YAHOO_PRESENCE_DEFAULT;
-}
-
-void yahoo_set_status(PurpleAccount *account, PurpleStatus *status)
-{
-	PurpleConnection *gc;
-	PurplePresence *presence;
-	YahooData *yd;
-	struct yahoo_packet *pkt;
-	int old_status;
-	const char *msg = NULL;
-	char *tmp = NULL;
-	char *conv_msg = NULL;
-
-	if (!purple_status_is_active(status))
-		return;
-
-	gc = purple_account_get_connection(account);
-	presence = purple_status_get_presence(status);
-	yd = purple_connection_get_protocol_data(gc);
-	old_status = yd->current_status;
-
-	yd->current_status = get_yahoo_status_from_purple_status(status);
-
-	if (yd->current_status == YAHOO_STATUS_CUSTOM)
-	{
-		msg = purple_status_get_attr_string(status, "message");
-
-		if (purple_status_is_available(status)) {
-			tmp = yahoo_string_encode(gc, msg, TRUE);
-			conv_msg = purple_markup_strip_html(tmp);
-			g_free(tmp);
-		} else {
-			if ((msg == NULL) || (*msg == '\0'))
-				msg = _("Away");
-			tmp = yahoo_string_encode(gc, msg, TRUE);
-			conv_msg = purple_markup_strip_html(tmp);
-			g_free(tmp);
-		}
-	}
-
-	if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
-		pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, yd->session_id);
-		yahoo_packet_hash_str(pkt, 13, "2");
-		yahoo_packet_send_and_free(pkt, yd);
-
-		return;
-	}
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash_int(pkt, 10, yd->current_status);
-
-	if (yd->current_status == YAHOO_STATUS_CUSTOM) {
-		yahoo_packet_hash_str(pkt, 97, "1"); /* UTF-8 */
-		yahoo_packet_hash_str(pkt, 19, conv_msg);
-	} else {
-		yahoo_packet_hash_str(pkt, 19, "");
-	}
-
-	g_free(conv_msg);
-
-	if (purple_presence_is_idle(presence))
-		yahoo_packet_hash_str(pkt, 47, "2");
-	else	{
-		if (!purple_status_is_available(status))
-			yahoo_packet_hash_str(pkt, 47, "1");
-		else
-			yahoo_packet_hash_str(pkt, 47, "0");
-	}
-
-	yahoo_packet_send_and_free(pkt, yd);
-
-	if (old_status == YAHOO_STATUS_INVISIBLE) {
-		pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, yd->session_id);
-		yahoo_packet_hash_str(pkt, 13, "1");
-		yahoo_packet_send_and_free(pkt, yd);
-
-		/* Any per-session presence settings are removed */
-		g_hash_table_foreach(yd->friends, yahoo_session_presence_remove, NULL);
-
-	}
-}
-
-void yahoo_set_idle(PurpleConnection *gc, int idle)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_packet *pkt = NULL;
-	char *msg = NULL, *msg2 = NULL;
-	PurpleStatus *status = NULL;
-	gboolean invisible = FALSE;
-
-	if (idle && yd->current_status != YAHOO_STATUS_CUSTOM)
-		yd->current_status = YAHOO_STATUS_IDLE;
-	else if (!idle && yd->current_status == YAHOO_STATUS_IDLE) {
-		status = purple_presence_get_active_status(purple_account_get_presence(purple_connection_get_account(gc)));
-		yd->current_status = get_yahoo_status_from_purple_status(status);
-	}
-
-	invisible = (yd->current_status == YAHOO_STATUS_INVISIBLE);
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id);
-
-	if (!idle && invisible)
-		yahoo_packet_hash_int(pkt, 10, YAHOO_STATUS_AVAILABLE);
-	else
-		yahoo_packet_hash_int(pkt, 10, yd->current_status);
-
-	if (yd->current_status == YAHOO_STATUS_CUSTOM) {
-		const char *tmp;
-		if (status == NULL)
-			status = purple_presence_get_active_status(purple_account_get_presence(purple_connection_get_account(gc)));
-		tmp = purple_status_get_attr_string(status, "message");
-		if (tmp != NULL) {
-			msg = yahoo_string_encode(gc, tmp, TRUE);
-			msg2 = purple_markup_strip_html(msg);
-			yahoo_packet_hash_str(pkt, 97, "1"); /* UTF-8 */
-			yahoo_packet_hash_str(pkt, 19, msg2);
-		} else {
-			/* get_yahoo_status_from_purple_status() returns YAHOO_STATUS_CUSTOM for
-			 * the generic away state (YAHOO_STATUS_TYPE_AWAY) with no message */
-			yahoo_packet_hash_str(pkt, 19, _("Away"));
-		}
-	} else {
-		yahoo_packet_hash_str(pkt, 19, "");
-	}
-
-	if (idle)
-		yahoo_packet_hash_str(pkt, 47, "2");
-	else if (yd->current_status == YAHOO_STATUS_CUSTOM &&
-			!purple_status_is_available(status))
-		/* We are still unavailable in this case.
-		 * Make sure Yahoo knows that */
-		yahoo_packet_hash_str(pkt, 47, "1");
-
-	yahoo_packet_send_and_free(pkt, yd);
-
-	g_free(msg);
-	g_free(msg2);
-}
-
-GList *yahoo_status_types(PurpleAccount *account)
-{
-	PurpleStatusType *type;
-	GList *types = NULL;
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, YAHOO_STATUS_TYPE_AVAILABLE,
-	                                       NULL, TRUE, TRUE, FALSE,
-	                                       "message", _("Message"),
-	                                       purple_value_new(G_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_AWAY,
-	                                       NULL, TRUE, TRUE, FALSE,
-	                                       "message", _("Message"),
-	                                       purple_value_new(G_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_BRB, _("Be Right Back"), TRUE);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_BUSY,
-	                                       _("Busy"), TRUE, TRUE, FALSE,
-	                                       "message", _("Message"),
-	                                       purple_value_new(G_TYPE_STRING), NULL);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTATHOME, _("Not at Home"), TRUE);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTATDESK, _("Not at Desk"), TRUE);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTINOFFICE, _("Not in Office"), TRUE);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_ONPHONE, _("On the Phone"), TRUE);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_EXTENDED_AWAY, YAHOO_STATUS_TYPE_ONVACATION, _("On Vacation"), TRUE);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_OUTTOLUNCH, _("Out to Lunch"), TRUE);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_STEPPEDOUT, _("Stepped Out"), TRUE);
-	types = g_list_append(types, type);
-
-
-	type = purple_status_type_new(PURPLE_STATUS_INVISIBLE, YAHOO_STATUS_TYPE_INVISIBLE, NULL, TRUE);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new(PURPLE_STATUS_OFFLINE, YAHOO_STATUS_TYPE_OFFLINE, NULL, TRUE);
-	types = g_list_append(types, type);
-
-	type = purple_status_type_new_full(PURPLE_STATUS_MOBILE, YAHOO_STATUS_TYPE_MOBILE, NULL, FALSE, FALSE, TRUE);
-	types = g_list_append(types, type);
-
-	return types;
-}
-
-void yahoo_keepalive(PurpleConnection *gc)
-{
-	struct yahoo_packet *pkt;
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	time_t now = time(NULL);
-
-	/* We're only allowed to send a ping once an hour or the servers will boot us */
-	if ((now - yd->last_ping) >= PING_TIMEOUT) {
-		yd->last_ping = now;
-
-		/* The native client will only send PING or CHATPING */
-		if (yd->chat_online) {
-			if (yd->wm) {
-				ycht_chat_send_keepalive(yd->ycht);
-			} else {
-				pkt = yahoo_packet_new(YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, yd->session_id);
-				yahoo_packet_hash_str(pkt, 109, purple_connection_get_display_name(gc));
-				yahoo_packet_send_and_free(pkt, yd);
-			}
-		} else {
-			pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, yd->session_id);
-			yahoo_packet_send_and_free(pkt, yd);
-		}
-	}
-
-	if ((now - yd->last_keepalive) >= KEEPALIVE_TIMEOUT) {
-		yd->last_keepalive = now;
-		pkt = yahoo_packet_new(YAHOO_SERVICE_KEEPALIVE, YAHOO_STATUS_AVAILABLE, yd->session_id);
-		yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc));
-		yahoo_packet_send_and_free(pkt, yd);
-	}
-
-}
-
-void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *g, const char *message)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_packet *pkt;
-	const char *group = NULL;
-	char *group2;
-	const char *bname = purple_buddy_get_name(buddy);
-
-	if (!yd->logged_in)
-		return;
-
-	if (!purple_account_privacy_check(purple_connection_get_account(gc), bname))
-		return;
-
-	group = purple_group_get_name(purple_buddy_get_group(buddy));
-
-	group2 = yahoo_string_encode(gc, group, FALSE);
-	pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash(pkt, "ssssssssss",
-					  14, "",
-					  65, group2,
-					  97, "1", /* UTF-8 */
-					  1, purple_connection_get_display_name(gc),
-					  302, "319",
-					  300, "319",
-					  7, bname,
-					  334, "0",
-					  301, "319",
-					  303, "319");
-
-	yahoo_packet_send_and_free(pkt, yd);
-	g_free(group2);
-}
-
-void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_packet *pkt;
-	GSList *buddies, *l;
-	PurpleGroup *g;
-	gboolean remove = TRUE;
-	char *cg;
-	const char *bname, *gname;
-	YahooFriend *f = NULL;
-
-	bname = purple_buddy_get_name(buddy);
-	f = yahoo_friend_find(gc, bname);
-	if (!f)
-		return;
-
-	gname = purple_group_get_name(group);
-	buddies = purple_blist_find_buddies(purple_connection_get_account(gc), bname);
-	for (l = buddies; l; l = l->next) {
-		g = purple_buddy_get_group(l->data);
-		if (purple_utf8_strcasecmp(gname, purple_group_get_name(g))) {
-			remove = FALSE;
-			break;
-		}
-	}
-
-	g_slist_free(buddies);
-
-	if (remove) {
-		g_hash_table_remove(yd->friends, bname);
-		f = NULL; /* f no longer valid - Just making it clear */
-	}
-
-	cg = yahoo_string_encode(gc, gname, FALSE);
-	pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
-
-	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
-	                  7, bname, 65, cg);
-	yahoo_packet_send_and_free(pkt, yd);
-	g_free(cg);
-}
-
-void yahoo_add_deny(PurpleConnection *gc, const char *who) {
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_packet *pkt;
-
-	if (!yd->logged_in)
-		return;
-
-	if (!who || who[0] == '\0')
-		return;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
-
-	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, who, 13, "1");
-
-	yahoo_packet_send_and_free(pkt, yd);
-}
-
-void yahoo_rem_deny(PurpleConnection *gc, const char *who) {
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_packet *pkt;
-
-	if (!yd->logged_in)
-		return;
-
-	if (!who || who[0] == '\0')
-		return;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
-
-	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, who, 13, "2");
-
-	yahoo_packet_send_and_free(pkt, yd);
-}
-
-void yahoo_set_permit_deny(PurpleConnection *gc)
-{
-	PurpleAccount *account;
-	GSList *deny;
-
-	account = purple_connection_get_account(gc);
-
-	switch (purple_account_get_privacy_type(account))
-	{
-		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_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;
-	}
-}
-
-void yahoo_change_buddys_group(PurpleConnection *gc, const char *who,
-				   const char *old_group, const char *new_group)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_packet *pkt;
-	char *gpn, *gpo;
-	YahooFriend *f = yahoo_friend_find(gc, who);
-	const char *temp = NULL;
-
-	/* Step 0:  If they aren't on the server list anyway,
-	 *          don't bother letting the server know.
-	 */
-	if (!f)
-		return;
-
-	temp = who;
-
-	/* If old and new are the same, we would probably
-	 * end up deleting the buddy, which would be bad.
-	 * This might happen because of the charset conversation.
-	 */
-	gpn = yahoo_string_encode(gc, new_group, FALSE);
-	gpo = yahoo_string_encode(gc, old_group, FALSE);
-	if (!strcmp(gpn, gpo)) {
-		g_free(gpn);
-		g_free(gpo);
-		return;
-	}
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc),
-				  302, "240", 300, "240", 7, temp, 224, gpo, 264, gpn, 301,
-				  "240", 303, "240");
-	yahoo_packet_send_and_free(pkt, yd);
-
-	g_free(gpn);
-	g_free(gpo);
-}
-
-void yahoo_rename_group(PurpleConnection *gc, const char *old_name,
-							   PurpleGroup *group, GList *moved_buddies)
-{
-	YahooData *yd = purple_connection_get_protocol_data(gc);
-	struct yahoo_packet *pkt;
-	char *gpn, *gpo;
-
-	gpn = yahoo_string_encode(gc, purple_group_get_name(group), FALSE);
-	gpo = yahoo_string_encode(gc, old_name, FALSE);
-	if (!strcmp(gpn, gpo)) {
-		g_free(gpn);
-		g_free(gpo);
-		return;
-	}
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
-	                  65, gpo, 67, gpn);
-	yahoo_packet_send_and_free(pkt, yd);
-	g_free(gpn);
-	g_free(gpo);
-}
-
-/********************************* Commands **********************************/
-
-PurpleCmdRet
-yahoopurple_cmd_buzz(PurpleConversation *c, const gchar *cmd, gchar **args, gchar **error, void *data) {
-	PurpleAccount *account = purple_conversation_get_account(c);
-
-	if (*args && args[0])
-		return PURPLE_CMD_RET_FAILED;
-
-	purple_protocol_send_attention(purple_account_get_connection(account), purple_conversation_get_name(c), YAHOO_BUZZ);
-
-	return PURPLE_CMD_RET_OK;
-}
-
-PurpleCmdRet
-yahoopurple_cmd_chat_join(PurpleConversation *conv, const char *cmd,
-                        char **args, char **error, void *data)
-{
-	GHashTable *comp;
-	PurpleConnection *gc;
-
-	if (!args || !args[0])
-		return PURPLE_CMD_RET_FAILED;
-
-	gc = purple_conversation_get_connection(conv);
-	purple_debug_info("yahoo", "Trying to join %s \n", args[0]);
-
-	comp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-	g_hash_table_replace(comp, g_strdup("room"), g_ascii_strdown(args[0], -1));
-	g_hash_table_replace(comp, g_strdup("type"), g_strdup("Chat"));
-
-	yahoo_c_join(gc, comp);
-
-	g_hash_table_destroy(comp);
-	return PURPLE_CMD_RET_OK;
-}
-
-PurpleCmdRet
-yahoopurple_cmd_chat_list(PurpleConversation *conv, const char *cmd,
-                        char **args, char **error, void *data)
-{
-	PurpleAccount *account = purple_conversation_get_account(conv);
-	if (*args && args[0])
-		return PURPLE_CMD_RET_FAILED;
-	purple_roomlist_show_with_account(account);
-	return PURPLE_CMD_RET_OK;
-}
-
-gboolean yahoo_offline_message(const PurpleBuddy *buddy)
-{
-	return TRUE;
-}
-
-gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type)
-{
-	PurpleIMConversation *im;
-
-	im = purple_conversations_find_im_with_account(username,
-			purple_connection_get_account(gc));
-
-	g_return_val_if_fail(im != NULL, FALSE);
-
-	purple_debug_info("yahoo", "Sending <ding> on account %s to buddy %s.\n",
-			username, purple_conversation_get_name(PURPLE_CONVERSATION(im)));
-	purple_conversation_send_with_flags(PURPLE_CONVERSATION(im), "<ding>", PURPLE_MESSAGE_INVISIBLE);
-
-	return TRUE;
-}
-
-GList *yahoo_attention_types(PurpleAccount *account)
-{
-	static GList *list = NULL;
-
-	if (!list) {
-		/* Yahoo only supports one attention command: the 'buzz'. */
-		/* This is index number YAHOO_BUZZ. */
-		list = g_list_append(list, purple_attention_type_new("Buzz", _("Buzz"),
-				_("%s has buzzed you!"), _("Buzzing %s...")));
-	}
-
-	return list;
-}
-
-gssize
-yahoo_get_max_message_size(PurpleConversation *conv)
-{
-	return YAHOO_MAX_MESSAGE_LENGTH_CHARS;
-}
--- a/libpurple/protocols/yahoo/ymsg.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,363 +0,0 @@
-/**
- * @file ymsg.h The Yahoo! Protocol
- *
- * 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 _YMSG_H_
-#define _YMSG_H_
-
-#include "circularbuffer.h"
-#include "cmds.h"
-#include "http.h"
-#include "protocol.h"
-#include "network.h"
-
-#define YAHOO_PAGER_HOST_REQ_URL "http://vcs2.msg.yahoo.com/capacity"
-#define YAHOO_PAGER_HOST_FALLBACK "scsa.msg.yahoo.com"
-#define YAHOO_PAGER_PORT 5050
-#define YAHOO_PAGER_PORT_P2P 5101
-#define YAHOO_LOGIN_URL "https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=&token=%s"
-#define YAHOO_TOKEN_URL "https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=&login=%s&passwd=%s&chal=%s"
-#define YAHOO_P2P_KEEPALIVE_SECS 300
-#define YAHOO_P2P_SERVER_TIMEOUT 10
-#define YAHOO_PROFILE_URL "http://profiles.yahoo.com/"
-#define YAHOO_MAIL_URL "http://rd.yahoo.com/messenger/client/?http://mail.yahoo.com/"
-#define YAHOO_XFER_HOST "filetransfer.msg.yahoo.com"
-#define YAHOO_XFER_RELAY_HOST "relay.msg.yahoo.com"
-#define YAHOO_XFER_RELAY_PORT 80
-#define YAHOO_ROOMLIST_URL "http://insider.msg.yahoo.com/ycontent/"
-#define YAHOO_ROOMLIST_LOCALE "us"
-
-#define YAHOO_AUDIBLE_URL "http://l.yimg.com/pu/dl/aud"
-
-#define WEBMESSENGER_URL "http://login.yahoo.com/config/login?.src=pg"
-
-#define YAHOO_SMS_CARRIER_URL "http://validate.msg.yahoo.com"
-
-#define YAHOO_USERINFO_URL "http://address.yahoo.com/yab/us?v=XM&sync=1&tags=short&useutf8=1&noclear=1&legenc=codepage-1252"
-
-#define YAHOO_PICURL_SETTING "picture_url"
-#define YAHOO_PICCKSUM_SETTING "picture_checksum"
-#define YAHOO_PICEXPIRE_SETTING "picture_expire"
-
-#define YAHOO_STATUS_TYPE_OFFLINE "offline"
-#define YAHOO_STATUS_TYPE_AVAILABLE "available"
-#define YAHOO_STATUS_TYPE_BRB "brb"
-#define YAHOO_STATUS_TYPE_BUSY "busy"
-#define YAHOO_STATUS_TYPE_NOTATHOME "notathome"
-#define YAHOO_STATUS_TYPE_NOTATDESK "notatdesk"
-#define YAHOO_STATUS_TYPE_NOTINOFFICE "notinoffice"
-#define YAHOO_STATUS_TYPE_ONPHONE "onphone"
-#define YAHOO_STATUS_TYPE_ONVACATION "onvacation"
-#define YAHOO_STATUS_TYPE_OUTTOLUNCH "outtolunch"
-#define YAHOO_STATUS_TYPE_STEPPEDOUT "steppedout"
-#define YAHOO_STATUS_TYPE_AWAY "away"
-#define YAHOO_STATUS_TYPE_INVISIBLE "invisible"
-#define YAHOO_STATUS_TYPE_MOBILE "mobile"
-
-#define YAHOO_CLIENT_VERSION_ID "4194239"
-#define YAHOO_CLIENT_VERSION "9.0.0.2162"
-
-#define YAHOO_CLIENT_USERAGENT "Mozilla/5.0"
-#define YAHOO_CLIENT_USERAGENT_ALIAS "Mozilla/4.0 (compatible; MSIE 5.5)"
-
-/* Index into attention types list. */
-#define YAHOO_BUZZ 0
-
-typedef enum {
-	YAHOO_PKT_TYPE_SERVER = 0,
-	YAHOO_PKT_TYPE_P2P
-} yahoo_pkt_type;
-
-typedef enum {
-	YAHOO_P2P_WE_ARE_CLIENT =0,
-	YAHOO_P2P_WE_ARE_SERVER
-} yahoo_p2p_connection_type;
-
-enum yahoo_status {
-	YAHOO_STATUS_AVAILABLE = 0,
-	YAHOO_STATUS_BRB,
-	YAHOO_STATUS_BUSY,
-	YAHOO_STATUS_NOTATHOME,
-	YAHOO_STATUS_NOTATDESK,
-	YAHOO_STATUS_NOTINOFFICE,
-	YAHOO_STATUS_ONPHONE,
-	YAHOO_STATUS_ONVACATION,
-	YAHOO_STATUS_OUTTOLUNCH,
-	YAHOO_STATUS_STEPPEDOUT,
-	YAHOO_STATUS_P2P = 11,
-	YAHOO_STATUS_INVISIBLE = 12,
-	YAHOO_STATUS_CUSTOM = 99,
-	YAHOO_STATUS_IDLE = 999,
-	YAHOO_STATUS_WEBLOGIN = 0x5a55aa55,
-	YAHOO_STATUS_OFFLINE = 0x5a55aa56, /* don't ask */
-	YAHOO_STATUS_TYPING = 0x16,
-	YAHOO_STATUS_DISCONNECTED = -1 /* 0xffffffff; in ymsg 15. doesnt mean the normal sense of 'disconnected' */
-};
-
-struct yahoo_buddy_icon_upload_data {
-	PurpleConnection *gc;
-	char *filename;
-	GString *picture_data;
-};
-
-struct yahoo_p2p_data	{
-	PurpleConnection *gc;
-	char *host_ip;
-	char *host_username;
-	int val_13;
-	guint input_event;
-	gint source;
-	int session_id;
-	yahoo_p2p_connection_type connection_type;
-};
-
-struct _YchtConn;
-
-typedef struct _YahooPersonalDetails {
-	char *id;
-
-	struct {
-		char *first;
-		char *last;
-		char *middle;
-		char *nick;
-	} names;
-
-	struct {
-		char *work;
-		char *home;
-		char *mobile;
-	} phone;
-} YahooPersonalDetails;
-
-typedef struct {
-	PurpleConnection *gc;
-	int fd;
-	guint inpa;
-	guchar *rxqueue;
-	int rxlen;
-	PurpleCircularBuffer *txbuf;
-	guint txhandler;
-	GHashTable *friends;
-
-	char **profiles;  /* Multiple profiles can be associated with an account */
-	YahooPersonalDetails ypd;
-
-	/**
-	 * This is used to keep track of the IMVironment chosen
-	 * by people you talk to.  We don't do very much with
-	 * this right now... but at least now if the remote user
-	 * selects an IMVironment we won't reset it back to the
-	 * default of nothing.
-	 */
-	GHashTable *imvironments;
-
-	int current_status;
-	gboolean logged_in;
-	GString *tmp_serv_blist, *tmp_serv_ilist, *tmp_serv_plist;
-	GSList *confs;
-	unsigned int conf_id; /* just a counter */
-	gboolean chat_online;
-	gboolean in_chat;
-	char *chat_name;
-	char *pending_chat_room;
-	char *pending_chat_id;
-	char *pending_chat_topic;
-	char *pending_chat_goto;
-	char *auth;
-	char *cookie_y;
-	char *cookie_t;
-	char *cookie_b;
-	int session_id;
-	gboolean wm; /* connected w/ web messenger method */
-	/* picture aka buddy icon stuff */
-	char *picture_url;
-	int picture_checksum;
-
-	/* ew. we have to check the icon before we connect,
-	 * but can't upload it til we're connected. */
-	struct yahoo_buddy_icon_upload_data *picture_upload_todo;
-	PurpleHttpConnection *picture_upload_hc;
-
-	struct _YchtConn *ycht;
-
-	/**
-	 * This set contains HTTP connections
-	 * for when we lookup people profile or photo information.
-	 */
-	PurpleHttpConnectionSet *http_reqs;
-
-	GHashTable *xfer_peer_idstring_map;/* Hey, i dont know, but putting this HashTable next to friends gives a run time fault... */
-	GSList *cookies;/* contains all cookies, including _y and _t */
-	PurpleNetworkListenData *listen_data;
-
-	/**
-	 * We may receive a list15 in multiple packets with no prior warning as to how many we'll be getting;
-	 * the server expects us to keep track of the group for which it is sending us contact names.
-	 */
-	char *current_list15_grp;
-	time_t last_ping;
-	time_t last_keepalive;
-	GHashTable *peers;	/* information about p2p data */
-	int yahoo_p2p_timer;
-	int yahoo_local_p2p_server_fd;
-	int yahoo_p2p_server_watcher;
-	GHashTable *sms_carrier;	/* sms carrier data */
-	guint yahoo_p2p_server_timeout_handle;
-} YahooData;
-
-#define YAHOO_MAX_STATUS_MESSAGE_LENGTH (255)
-
-/*
- * Current Maximum Length for Instant Messages
- *
- * This was found by experiment.
- *
- * The YMSG protocol allows a message of up to 948 bytes, but the official client
- * limits to 800 characters.  According to experiments I conducted, it seems that
- * the discrepancy is to allow some leeway for messages with mixed single- and
- * multi-byte characters, as I was able to send messages of 840 and 932 bytes
- * by using some multibyte characters (some random Chinese or Japanese characters,
- * to be precise). - rekkanoryo
- */
-#define YAHOO_MAX_MESSAGE_LENGTH_BYTES 948
-#define YAHOO_MAX_MESSAGE_LENGTH_CHARS 800
-
-/* sometimes i wish prpls could #include things from other prpls. then i could just
- * use the routines from libfaim and not have to admit to knowing how they work. */
-#define yahoo_put16(buf, data) ( \
-		(*(buf) = (unsigned char)((data)>>8)&0xff), \
-		(*((buf)+1) = (unsigned char)(data)&0xff),  \
-		2)
-#define yahoo_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff))
-#define yahoo_put32(buf, data) ( \
-		(*((buf)) = (unsigned char)((data)>>24)&0xff), \
-		(*((buf)+1) = (unsigned char)((data)>>16)&0xff), \
-		(*((buf)+2) = (unsigned char)((data)>>8)&0xff), \
-		(*((buf)+3) = (unsigned char)(data)&0xff), \
-		4)
-#define yahoo_get32(buf) ((((*(buf))<<24)&0xff000000) + \
-		(((*((buf)+1))<<16)&0x00ff0000) + \
-		(((*((buf)+2))<< 8)&0x0000ff00) + \
-		(((*((buf)+3)    )&0x000000ff)))
-
-/* util.c */
-void yahoo_init_colorht(void);
-void yahoo_dest_colorht(void);
-char *yahoo_codes_to_html(const char *x);
-
-/**
- * This function takes a normal HTML message and converts it to the message
- * format used by Yahoo, which uses a frankensteinish combination of ANSI
- * escape codes and broken HTML.
- *
- * It results in slightly different output than would be sent by official
- * Yahoo clients.  The two main differences are:
- *
- * 1. We always close all tags, whereas official Yahoo clients leave tags
- *    dangling open at the end of each message (and the client treats them
- *    as closed).
- * 2. We always close inner tags first before closing outter tags.
- *
- * For example, if you want to send this message:
- *   <b> bold <i> bolditalic </i></b><i> italic </i>
- * Official Yahoo clients would send:
- *   ESC[1m bold ESC[2m bolditalic ESC[x1m italic
- * But we will send:
- *   ESC[1m bold ESC[2m bolditalic ESC[x2mESC[x1mESC[2m italic ESC[x2m
- */
-char *yahoo_html_to_codes(const char *src);
-
-gboolean
-yahoo_account_use_http_proxy(PurpleConnection *conn);
-
-/**
- * Encode some text to send to the yahoo server.
- *
- * @param gc The connection handle.
- * @param str The null terminated utf8 string to encode.
- * @param utf8 Whether to return a UTF-8 string.
- * @return A g_malloc'ed string in the appropriate encoding. If utf8
- *         is true then the string is copied verbatim. Otherwise the
- *         encoding from account settings is used.
- */
-gchar *yahoo_string_encode(PurpleConnection *gc, const char *str, gboolean utf8);
-
-/**
- * Decode some text received from the server.
- *
- * @param gc The gc handle.
- * @param str The null terminated string to decode.
- * @param utf8 Did the server tell us it was supposed to be utf8?
- * @return The decoded, utf-8 string, which must be g_free()'d.
- */
-char *yahoo_string_decode(PurpleConnection *gc, const char *str, gboolean utf8);
-
-char *yahoo_convert_to_numeric(const char *str);
-
-/* yahoo_profile.c */
-void yahoo_get_info(PurpleConnection *gc, const char *name);
-
-/* ymsg.h  - these functions were formerly static but need not to be for the
- * new two-protocol model. */
-const char *yahoo_list_icon(PurpleAccount *a, PurpleBuddy *b);
-const char *yahoo_list_emblem(PurpleBuddy *b);
-char *yahoo_status_text(PurpleBuddy *b);
-void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full);
-GList *yahoo_status_types(PurpleAccount *account);
-GList *yahoo_blist_node_menu(PurpleBlistNode *node);
-void yahoo_login(PurpleAccount *account);
-void yahoo_close(PurpleConnection *gc);
-int yahoo_send_im(PurpleConnection *gc, PurpleMessage *msg);
-unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleIMTypingState state);
-void yahoo_set_status(PurpleAccount *account, PurpleStatus *status);
-void yahoo_set_idle(PurpleConnection *gc, int idle);
-void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *g, const char *message);
-void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-void yahoo_add_deny(PurpleConnection *gc, const char *who);
-void yahoo_rem_deny(PurpleConnection *gc, const char *who);
-void yahoo_set_permit_deny(PurpleConnection *gc);
-void yahoo_keepalive(PurpleConnection *gc);
-void yahoo_change_buddys_group(PurpleConnection *gc, const char *who, const char *old_group, const char *new_group);
-void yahoo_rename_group(PurpleConnection *gc, const char *old_name, PurpleGroup *group, GList *moved_buddies);
-gboolean yahoo_offline_message(const PurpleBuddy *buddy);
-gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type);
-GList *yahoo_attention_types(PurpleAccount *account);
-
-GList *yahoo_get_actions(PurpleConnection *gc);
-void yahoopurple_register_commands(void);
-gssize yahoo_get_max_message_size(PurpleConversation *conv);
-
-PurpleCmdRet yahoopurple_cmd_buzz(PurpleConversation *c, const gchar *cmd, gchar **args, gchar **error, void *data);
-PurpleCmdRet yahoopurple_cmd_chat_join(PurpleConversation *conv, const char *cmd, char **args, char **error, void *data);
-PurpleCmdRet yahoopurple_cmd_chat_list(PurpleConversation *conv, const char *cmd, char **args, char **error, void *data);
-/* needed for xfer, thought theyd be useful for other enhancements later on
-   Returns list of cookies stored in yahoo_data formatted as a single null terminated string
-   returned value must be g_freed
-*/
-gchar* yahoo_get_cookies(PurpleConnection *gc);
-
-/* send p2p pkt containing our encoded ip, asking peer to connect to us */
-void yahoo_send_p2p_pkt(PurpleConnection *gc, const char *who, int val_13);
-
-#endif /* _YMSG_H_ */
--- a/libpurple/proxy.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/proxy.c	Mon Jun 05 16:36:29 2017 +0300
@@ -27,7 +27,6 @@
 #define _PURPLE_PROXY_C_
 
 #include "internal.h"
-#include "ciphers/md5hash.h"
 #include "debug.h"
 #include "http.h"
 #include "notify.h"
--- a/libpurple/tag.sh	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/tag.sh	Mon Jun 05 16:36:29 2017 +0300
@@ -22,17 +22,6 @@
 	if [ "$tag" == "auto" ] && [ "$arg" == "-shared" ]; then
 		tag="CCLD"
 	fi
-	if [ "$tag" == "PERL" ] && [ "${arg%(*}" == "Mkbootstrap" ]; then
-		object="${arg%;}"
-		is_final=1
-		break
-	fi
-	if [ "$tag" == "PERL" ] && [ "${arg%(*}" == "ExtUtils::ParseXS::process_file" ]; then
-		object="${arg#*output => \"}"
-		object="${object%\", *}"
-		is_final=1
-		break
-	fi
 	ext_1=${arg#${arg%??}}
 	if [ "${ext_1}" == ".c" ]; then
 		file_1="$arg"
@@ -51,10 +40,6 @@
 	tag="CC"
 fi
 
-if [ "$tag" == "PERL" ] && [ "$is_final" == 0 ]; then
-	object=`echo "$object" | sed -n 's|.*output *=> *"\([^"]*\)".*|\1|p'`
-fi
-
 if [ "$object" == "" ] && [ "${file_1}" != "" ]; then
 	object="${file_1}"
 fi
--- a/libpurple/tests/Makefile.am	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/tests/Makefile.am	Mon Jun 05 16:36:29 2017 +0300
@@ -8,12 +8,8 @@
 test_programs=\
 	test_des \
 	test_des3 \
-	test_hmac \
 	test_image \
 	test_md4 \
-	test_md5 \
-	test_sha1 \
-	test_sha256 \
 	test_smiley \
 	test_trie \
 	test_util \
@@ -25,24 +21,12 @@
 test_des3_SOURCES=test_des3.c
 test_des3_LDADD=$(COMMON_LIBS)
 
-test_hmac_SOURCES=test_hmac.c
-test_hmac_LDADD=$(COMMON_LIBS)
-
 test_image_SOURCES=test_image.c
 test_image_LDADD=$(COMMON_LIBS)
 
 test_md4_SOURCES=test_md4.c
 test_md4_LDADD=$(COMMON_LIBS)
 
-test_md5_SOURCES=test_md5.c
-test_md5_LDADD=$(COMMON_LIBS)
-
-test_sha1_SOURCES=test_sha1.c
-test_sha1_LDADD=$(COMMON_LIBS)
-
-test_sha256_SOURCES=test_sha256.c
-test_sha256_LDADD=$(COMMON_LIBS)
-
 test_smiley_SOURCES=test_smiley.c
 test_smiley_LDADD=$(COMMON_LIBS)
 
--- a/libpurple/tests/test_hmac.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,401 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-#include <glib.h>
-
-#include <purple.h>
-
-#include "ciphers/hmaccipher.h"
-#include "ciphers/md5hash.h"
-#include "ciphers/sha1hash.h"
-
-/******************************************************************************
- * HMAC Tests
- * See RFC2202 and some other NULL tests I made up
- *****************************************************************************/
-static void
-test_hmac(gchar *data, size_t data_len,
-          const gchar *key, size_t key_len,
-          PurpleHash *hash, const gchar *digest)
-{
-	PurpleCipher *cipher = NULL;
-	gchar cdigest[41];
-	gboolean ret = FALSE;
-
-	cipher = purple_hmac_cipher_new(hash);
-	purple_cipher_set_key(cipher, (guchar *)key, key_len);
-
-	purple_cipher_append(cipher, (guchar *)data, data_len);
-	ret = purple_cipher_digest_to_str(cipher, cdigest, sizeof(cdigest));
-
-	g_assert(ret);
-	g_assert_cmpstr(digest, ==, cdigest);
-
-	g_object_unref(G_OBJECT(cipher));
-	g_object_unref(G_OBJECT(hash));
-}
-
-static void
-test_hmac_md5_hi(void) {
-	test_hmac(
-		"Hi There",
-		8,
-		"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
-		16,
-		purple_md5_hash_new(),
-		"9294727a3638bb1c13f48ef8158bfc9d"
-	);
-}
-
-static void
-test_hmac_md5_what(void) {
-	test_hmac(
-		"what do ya want for nothing?",
-		28,
-		"Jefe",
-		4,
-		purple_md5_hash_new(),
-		"750c783e6ab0b503eaa86e310a5db738"
-	);
-}
-
-static void
-test_hmac_md5_dd(void) {
-	test_hmac(
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
-		50,
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		16,
-		purple_md5_hash_new(),
-		"56be34521d144c88dbb8c733f0e8b3f6"
-	);
-}
-
-static void
-test_hmac_md5_cd(void) {
-	test_hmac(
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
-		50,
-		"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
-		"\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
-		"\x15\x16\x17\x18\x19",
-		25,
-		purple_md5_hash_new(),
-		"697eaf0aca3a3aea3a75164746ffaa79"
-	);
-}
-
-static void
-test_hmac_md5_truncation(void) {
-	test_hmac(
-		"Test With Truncation",
-		20,
-		"\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
-		16,
-		purple_md5_hash_new(),
-		"56461ef2342edc00f9bab995690efd4c"
-	);
-}
-
-static void
-test_hmac_md5_large_key(void) {
-	test_hmac(
-		"Test Using Larger Than Block-Size Key - Hash Key First",
-		54,
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		80,
-		purple_md5_hash_new(),
-		"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"
-	);
-}
-
-static void
-test_hmac_md5_large_key_and_data(void) {
-	test_hmac(
-		"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
-		73,
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		80,
-		purple_md5_hash_new(),
-		"6f630fad67cda0ee1fb1f562db3aa53e"
-	);
-}
-
-static void
-test_hmac_md5_null_key(void) {
-	test_hmac(
-		"Hi There",
-		8,
-		"\x0a\x0b\x00\x0d\x0e\x0f\x1a\x2f\x0b\x0b"
-		"\x0b\x00\x00\x0b\x0b\x49\x5f\x6e\x0b\x0b",
-		20,
-		purple_md5_hash_new(),
-		"597bfd644b797a985561eeb03a169e59"
-	);
-}
-
-static void
-test_hmac_md5_null_text(void) {
-	test_hmac(
-		"Hi\x00There",
-		8,
-		"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-		"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
-		20,
-		purple_md5_hash_new(),
-		"70be8e1b7b50dfcc335d6cd7992c564f"
-	);
-}
-
-static void
-test_hmac_md5_null_key_and_text(void) {
-	test_hmac(
-		"Hi\x00Th\x00re",
-		8,
-		"\x0c\x0d\x00\x0f\x10\x1a\x3a\x3a\xe6\x34"
-		"\x0b\x00\x00\x0b\x0b\x49\x5f\x6e\x0b\x0b",
-		20,
-		purple_md5_hash_new(),
-		"b31bcbba35a33a067cbba9131cba4889"
-	);
-}
-
-static void
-test_hmac_sha1_hi(void) {
-	test_hmac(
-		"Hi There",
-		8,
-		"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-		"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
-		20,
-		purple_sha1_hash_new(),
-		"b617318655057264e28bc0b6fb378c8ef146be00"
-	);
-}
-
-static void
-test_hmac_sha1_what(void) {
-	test_hmac(
-		"what do ya want for nothing?",
-		28,
-		"Jefe",
-		4,
-		purple_sha1_hash_new(),
-		"effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"
-	);
-}
-
-static void
-test_hmac_sha1_dd(void) {
-	test_hmac(
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
-		"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
-		50,
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		20,
-		purple_sha1_hash_new(),
-		"125d7342b9ac11cd91a39af48aa17b4f63f175d3"
-	);
-}
-
-static void
-test_hmac_sha1_cd(void) {
-	test_hmac(
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
-		"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
-		50,
-		"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
-		"\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
-		"\x15\x16\x17\x18\x19",
-		25,
-		purple_sha1_hash_new(),
-		"4c9007f4026250c6bc8414f9bf50c86c2d7235da"
-	);
-}
-
-static void
-test_hmac_sha1_truncation(void) {
-	test_hmac(
-		"Test With Truncation",
-		20,
-		"\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"
-		"\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
-		20,
-		purple_sha1_hash_new(),
-		"4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"
-	);
-}
-
-static void
-test_hmac_sha1_large_key(void) {
-	test_hmac(
-		"Test Using Larger Than Block-Size Key - Hash Key First",
-		54,
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		80,
-		purple_sha1_hash_new(),
-		"aa4ae5e15272d00e95705637ce8a3b55ed402112"
-	);
-}
-
-static void
-test_hmac_sha1_large_key_and_data(void) {
-	test_hmac(
-		"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
-		73,
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
-		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-		80,
-		purple_sha1_hash_new(),
-		"e8e99d0f45237d786d6bbaa7965c7808bbff1a91"
-	);
-}
-
-static void
-test_hmac_sha1_null_key(void) {
-	test_hmac(
-		"Hi There",
-		8,
-		"\x0a\x0b\x00\x0d\x0e\x0f\x1a\x2f\x0b\x0b"
-		"\x0b\x00\x00\x0b\x0b\x49\x5f\x6e\x0b\x0b",
-		20,
-		purple_sha1_hash_new(),
-		"eb62a2e0e33d300be669c52aab3f591bc960aac5"
-	);
-}
-
-static void
-test_hmac_sha1_null_text(void) {
-	test_hmac(
-		"Hi\x00There",
-		8,
-		"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
-		"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
-		20,
-		purple_sha1_hash_new(),
-		"31ca58d849e971e418e3439de2c6f83144b6abb7"
-	);
-}
-
-static void
-test_hmac_sha1_null_key_and_text(void) {
-	test_hmac(
-		"Hi\x00Th\x00re",
-		8,
-		"\x0c\x0d\x00\x0f\x10\x1a\x3a\x3a\xe6\x34"
-		"\x0b\x00\x00\x0b\x0b\x49\x5f\x6e\x0b\x0b",
-		20,
-		purple_sha1_hash_new(),
-		"e6b8e2fede87aa09dcb13e554df1435e056eae36"
-	);
-}
-
-gint
-main(gint argc, gchar **argv) {
-	g_test_init(&argc, &argv, NULL);
-
-	g_test_add_func("/hmac/md5/hi",
-	                test_hmac_md5_hi);
-	g_test_add_func("/hmac/md5/what",
-	                test_hmac_md5_what);
-	g_test_add_func("/hmac/md5/dd",
-	                test_hmac_md5_dd);
-	g_test_add_func("/hmac/md5/cd",
-	                test_hmac_md5_cd);
-	g_test_add_func("/hmac/md5/truncation",
-	                test_hmac_md5_truncation);
-	g_test_add_func("/hmac/md5/large key",
-	                test_hmac_md5_large_key);
-	g_test_add_func("/hmac/md5/large key and data",
-	                test_hmac_md5_large_key_and_data);
-	g_test_add_func("/hmac/md5/null key",
-	                test_hmac_md5_null_key);
-	g_test_add_func("/hmac/md5/null text",
-	                test_hmac_md5_null_text);
-	g_test_add_func("/hmac/md5/null key and text",
-	                test_hmac_md5_null_key_and_text);
-
-	g_test_add_func("/hmac/sha1/hi",
-	                test_hmac_sha1_hi);
-	g_test_add_func("/hmac/sha1/what",
-	                test_hmac_sha1_what);
-	g_test_add_func("/hmac/sha1/dd",
-	                test_hmac_sha1_dd);
-	g_test_add_func("/hmac/sha1/cd",
-	                test_hmac_sha1_cd);
-	g_test_add_func("/hmac/sha1/truncation",
-	                test_hmac_sha1_truncation);
-	g_test_add_func("/hmac/sha1/large key",
-	                test_hmac_sha1_large_key);
-	g_test_add_func("/hmac/sha1/large key and data",
-	                test_hmac_sha1_large_key_and_data);
-	g_test_add_func("/hmac/sha1/null key",
-	                test_hmac_sha1_null_key);
-	g_test_add_func("/hmac/sha1/null text",
-	                test_hmac_sha1_null_text);
-	g_test_add_func("/hmac/sha1/null key and text",
-	                test_hmac_sha1_null_key_and_text);
-
-	return g_test_run();
-}
--- a/libpurple/tests/test_md5.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-#include <glib.h>
-
-#include <purple.h>
-
-#include "ciphers/md5hash.h"
-
-static void
-test_md5hash(gchar *data, gchar *digest) {
-	PurpleHash *hash = NULL;
-	gchar cdigest[33];
-	gboolean ret = FALSE;
-
-	hash = purple_md5_hash_new();
-
-	purple_hash_append(hash, (guchar *)data, strlen(data));
-
-	ret = purple_hash_digest_to_str(hash, cdigest, sizeof(cdigest));
-
-	g_assert(ret);
-	g_assert_cmpstr(digest, ==, cdigest);
-}
-
-static void
-test_md5hash_empty_string(void) {
-	test_md5hash("",
-	             "d41d8cd98f00b204e9800998ecf8427e");
-}
-
-static void
-test_md5hash_a(void) {
-	test_md5hash("a",
-	             "0cc175b9c0f1b6a831c399e269772661");
-}
-
-static void
-test_md5hash_abc(void) {
-	test_md5hash("abc",
-	             "900150983cd24fb0d6963f7d28e17f72");
-}
-
-static void
-test_md5hash_message_digest(void) {
-	test_md5hash("message digest",
-	             "f96b697d7cb7938d525a2f31aaf161d0");
-}
-
-static void
-test_md5hash_a_to_z(void) {
-	test_md5hash("abcdefghijklmnopqrstuvwxyz",
-	             "c3fcd3d76192e4007dfb496cca67e13b");
-}
-
-static void
-test_md5hash_A_to_Z_a_to_z_0_to_9(void) {
-	test_md5hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
-	             "d174ab98d277d9f5a5611c2c9f419d9f");
-}
-
-static void
-test_md5hash_1_to_0_eight_times(void) {
-	test_md5hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
-	             "57edf4a22be3c955ac49da2e2107b67a");
-}
-
-gint
-main(gint argc, gchar **argv) {
-	g_test_init(&argc, &argv, NULL);
-
-	g_test_add_func("/hash/md5/empty-string",
-	                test_md5hash_empty_string);
-	g_test_add_func("/hash/md5/a",
-	                test_md5hash_a);
-	g_test_add_func("/hash/md5/abc",
-	                test_md5hash_abc);
-	g_test_add_func("/hash/md5/message digest",
-	                test_md5hash_message_digest);
-	g_test_add_func("/hash/md5/a to z",
-	                test_md5hash_a_to_z);
-	g_test_add_func("/hash/md5/A to Z, a to z, 0 to 9" ,
-	                test_md5hash_A_to_Z_a_to_z_0_to_9);
-	g_test_add_func("/hash/md5/1 to 0 eight times",
-	                test_md5hash_1_to_0_eight_times);
-
-	return g_test_run();
-}
--- a/libpurple/tests/test_sha1.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-#include <glib.h>
-
-#include <purple.h>
-
-#include "ciphers/sha1hash.h"
-
-static void
-test_sha1hash(gchar *data, gchar *digest) {
-	PurpleHash *hash = NULL;
-	gchar cdigest[41];
-	gboolean ret = FALSE;
-
-	hash = purple_sha1_hash_new();
-
-	if(data) {
-		purple_hash_append(hash, (guchar *)data, strlen(data));
-	} else {
-		gint j;
-		guchar buff[1000];
-
-		memset(buff, 'a', 1000);
-
-		for(j = 0; j < 1000; j++)
-			purple_hash_append(hash, buff, 1000);
-	}
-
-	ret = purple_hash_digest_to_str(hash, cdigest, sizeof(cdigest));
-
-	g_assert(ret);
-	g_assert_cmpstr(digest, ==, cdigest);
-}
-
-static void
-test_sha1hash_empty_string(void) {
-	test_sha1hash("",
-	              "da39a3ee5e6b4b0d3255bfef95601890afd80709");
-}
-
-static void
-test_sha1hash_a(void) {
-	test_sha1hash("a",
-	              "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8");
-}
-
-static void
-test_sha1hash_abc(void) {
-	test_sha1hash("abc",
-	              "a9993e364706816aba3e25717850c26c9cd0d89d");
-}
-
-static void
-test_sha1hash_abcd_gibberish(void) {
-	test_sha1hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-	              "84983e441c3bd26ebaae4aa1f95129e5e54670f1");
-}
-
-static void
-test_sha1hash_1000_as_1000_times(void) {
-	test_sha1hash(NULL,
-	              "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
-}
-
-gint
-main(gint argc, gchar **argv) {
-	g_test_init(&argc, &argv, NULL);
-
-	g_test_add_func("/hash/sha1/empty-string",
-	                test_sha1hash_empty_string);
-	g_test_add_func("/hash/sha1/a",
-	                test_sha1hash_a);
-	g_test_add_func("/hash/sha1/abc",
-	                test_sha1hash_abc);
-	g_test_add_func("/hash/sha1/abcd_gibberish",
-	                test_sha1hash_abcd_gibberish);
-	g_test_add_func("/hash/sha1/1000 a's 1000 times",
-	                test_sha1hash_1000_as_1000_times);
-
-	return g_test_run();
-}
--- a/libpurple/tests/test_sha256.c	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/*
- * purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-#include <glib.h>
-
-#include <purple.h>
-
-#include "ciphers/sha256hash.h"
-
-static void
-test_sha256hash(gchar *data, gchar *digest) {
-	PurpleHash *hash = NULL;
-	gchar cdigest[65];
-	gboolean ret = FALSE;
-
-	hash = purple_sha256_hash_new();
-
-	if(data) {
-		purple_hash_append(hash, (guchar *)data, strlen(data));
-	} else {
-		gint j;
-		guchar buff[1000];
-
-		memset(buff, 'a', 1000);
-
-		for(j = 0; j < 1000; j++)
-			purple_hash_append(hash, buff, 1000);
-	}
-
-	ret = purple_hash_digest_to_str(hash, cdigest, sizeof(cdigest));
-
-	g_assert(ret);
-	g_assert_cmpstr(digest, ==, cdigest);
-}
-
-static void
-test_sha256hash_empty_string(void) {
-	test_sha256hash("",
-	                "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
-}
-
-static void
-test_sha256hash_a(void) {
-	test_sha256hash("a",
-	                "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb");
-}
-
-static void
-test_sha256hash_abc(void) {
-	test_sha256hash("abc",
-	                "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
-}
-
-static void
-test_sha256hash_abcd_gibberish(void) {
-	test_sha256hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
-	                "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
-}
-
-static void
-test_sha256hash_1000_as_1000_times(void) {
-	test_sha256hash(NULL,
-	                "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
-}
-
-gint
-main(gint argc, gchar **argv) {
-	g_test_init(&argc, &argv, NULL);
-
-	g_test_add_func("/hash/sha256/empty-string",
-	                test_sha256hash_empty_string);
-	g_test_add_func("/hash/sha256/a",
-	                test_sha256hash_a);
-	g_test_add_func("/hash/sha256/abc",
-	                test_sha256hash_abc);
-	g_test_add_func("/hash/sha256/abcd_gibberish",
-	                test_sha256hash_abcd_gibberish);
-	g_test_add_func("/hash/sha256/1000 a's 1000 times",
-	                test_sha256hash_1000_as_1000_times);
-
-	return g_test_run();
-}
--- a/libpurple/tests/test_util.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/tests/test_util.c	Mon Jun 05 16:36:29 2017 +0300
@@ -43,24 +43,6 @@
 }
 
 /******************************************************************************
- * base 64 tests
- *****************************************************************************/
-static void
-test_util_base_64_encode(void) {
-	gchar *in = purple_base64_encode((const unsigned char *)"forty-two", 10);
-	g_assert_cmpstr("Zm9ydHktdHdvAA==", ==, in);
-}
-
-static void
-test_util_base_64_decode(void) {
-	gsize sz = 0;
-	guchar *out = purple_base64_decode("b3d0LXl0cm9mAA==", &sz);
-
-	g_assert_cmpint(sz, ==, 10);
-	g_assert_cmpstr("owt-ytrof", ==, (gchar *)out);
-}
-
-/******************************************************************************
  * filename escape tests
  *****************************************************************************/
 static void
@@ -512,11 +494,6 @@
 	g_test_add_func("/util/base/16/decode",
 	                test_util_base_16_decode);
 
-	g_test_add_func("/util/base/64/encode",
-	                test_util_base_64_encode);
-	g_test_add_func("/util/base/64/decode",
-	                test_util_base_64_decode);
-
 	g_test_add_func("/util/filename/escape",
 	                test_util_filename_escape);
 	g_test_add_func("/util/filename/unescape",
--- a/libpurple/tls-certificate-info.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/tls-certificate-info.c	Mon Jun 05 16:36:29 2017 +0300
@@ -23,7 +23,6 @@
 
 #include "internal.h"
 #include "tls-certificate-info.h"
-#include "ciphers/sha1hash.h"
 #include "debug.h"
 #include "util.h"
 
@@ -789,7 +788,7 @@
 GByteArray *
 purple_tls_certificate_get_fingerprint_sha1(GTlsCertificate *certificate)
 {
-	PurpleHash *hash;
+	GChecksum *hash;
 	GByteArray *der = NULL;
 	guint8 *data = NULL;
 	gsize buf_size = 0;
@@ -800,16 +799,16 @@
 
 	g_return_val_if_fail(der != NULL, NULL);
 
-	hash = purple_sha1_hash_new();
+	hash = g_checksum_new(G_CHECKSUM_SHA1);
 
-	buf_size = purple_hash_get_digest_size(hash);
+	buf_size = g_checksum_type_get_length(G_CHECKSUM_SHA1);
 	data = g_malloc(buf_size);
 
-	purple_hash_append(hash, der->data, der->len);
+	g_checksum_update(hash, der->data, der->len);
 	g_byte_array_unref(der);
 
-	purple_hash_digest(hash, data, buf_size);
-	g_object_unref(hash);
+	g_checksum_get_digest(hash, data, &buf_size);
+	g_checksum_free(hash);
 
 	return g_byte_array_new_take(data, buf_size);
 }
--- a/libpurple/util.c	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/util.c	Mon Jun 05 16:36:29 2017 +0300
@@ -18,7 +18,6 @@
  */
 #include "internal.h"
 
-#include "ciphers/md5hash.h"
 #include "conversation.h"
 #include "core.h"
 #include "debug.h"
@@ -330,34 +329,12 @@
 	return ascii;
 }
 
-
 /**************************************************************************
- * Base64 Functions
+ * Quoted Printable Functions (see RFC 2045).
  **************************************************************************/
 static const char xdigits[] =
 	"0123456789abcdef";
 
-gchar *
-purple_base64_encode(const guchar *data, gsize len)
-{
-	return g_base64_encode(data, len);
-}
-
-guchar *
-purple_base64_decode(const char *str, gsize *ret_len)
-{
-	/*
-	 * We want to allow ret_len to be NULL for backward compatibility,
-	 * but g_base64_decode() requires a valid length variable.  So if
-	 * ret_len is NULL then pass in a dummy variable.
-	 */
-	gsize unused;
-	return g_base64_decode(str, ret_len != NULL ? ret_len : &unused);
-}
-
-/**************************************************************************
- * Quoted Printable Functions (see RFC 2045).
- **************************************************************************/
 guchar *
 purple_quotedp_decode(const char *str, gsize *ret_len)
 {
@@ -517,7 +494,7 @@
 				if (g_ascii_strcasecmp(encoding, "Q") == 0)
 					decoded = purple_quotedp_decode(encoded_text, &dec_len);
 				else if (g_ascii_strcasecmp(encoding, "B") == 0)
-					decoded = purple_base64_decode(encoded_text, &dec_len);
+					decoded = g_base64_decode(encoded_text, &dec_len);
 				else
 					decoded = NULL;
 				if (decoded) {
@@ -1424,8 +1401,7 @@
 purple_markup_unescape_entity(const char *text, int *length)
 {
 	const char *pln;
-	int len, pound;
-	char temp[2];
+	int len;
 
 	if (!text || *text != '&')
 		return NULL;
@@ -4961,9 +4937,8 @@
 		const gchar *nonce,
 		const gchar *client_nonce)
 {
-	PurpleHash *hasher;
-	gchar hash[33]; /* We only support MD5. */
-	gboolean digest_ok;
+	GChecksum *hasher;
+	gchar *hash;
 
 	g_return_val_if_fail(username != NULL, NULL);
 	g_return_val_if_fail(realm    != NULL, NULL);
@@ -4976,18 +4951,19 @@
 						 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));
+	hasher = g_checksum_new(G_CHECKSUM_MD5);
+	g_return_val_if_fail(hasher != NULL, NULL);
+
+	g_checksum_update(hasher, (guchar *)username, -1);
+	g_checksum_update(hasher, (guchar *)":", -1);
+	g_checksum_update(hasher, (guchar *)realm, -1);
+	g_checksum_update(hasher, (guchar *)":", -1);
+	g_checksum_update(hasher, (guchar *)password, -1);
 
 	if (algorithm != NULL && !g_ascii_strcasecmp(algorithm, "MD5-sess"))
 	{
 		guchar digest[16];
+		gsize digest_len = 16;
 
 		if (client_nonce == NULL)
 		{
@@ -4996,22 +4972,20 @@
 			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));
+		g_checksum_get_digest(hasher, digest, &digest_len);
+
+		g_checksum_reset(hasher);
+		g_checksum_update(hasher, digest, sizeof(digest));
+		g_checksum_update(hasher, (guchar *)":", -1);
+		g_checksum_update(hasher, (guchar *)nonce, -1);
+		g_checksum_update(hasher, (guchar *)":", -1);
+		g_checksum_update(hasher, (guchar *)client_nonce, -1);
 	}
 
-	digest_ok = purple_hash_digest_to_str(hasher, hash, sizeof(hash));
-	g_object_unref(hasher);
-
-	g_return_val_if_fail(digest_ok, NULL);
-
-	return g_strdup(hash);
+	hash = g_strdup(g_checksum_get_string(hasher));
+	g_checksum_free(hasher);
+
+	return hash;
 }
 
 gchar *purple_http_digest_calculate_response(
@@ -5025,9 +4999,8 @@
 		const gchar *client_nonce,
 		const gchar *session_key)
 {
-	PurpleHash *hash;
-	static gchar hash2[33]; /* We only support MD5. */
-	gboolean digest_ok;
+	GChecksum *hash;
+	gchar *hash2;
 
 	g_return_val_if_fail(method      != NULL, NULL);
 	g_return_val_if_fail(digest_uri  != NULL, NULL);
@@ -5046,85 +5019,83 @@
 						 g_ascii_strcasecmp(qop, "auth") ||
 						 g_ascii_strcasecmp(qop, "auth-int"), NULL);
 
-	hash = purple_md5_hash_new();
+	hash = g_checksum_new(G_CHECKSUM_MD5);
 	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));
+	g_checksum_update(hash, (guchar *)method, -1);
+	g_checksum_update(hash, (guchar *)":", -1);
+	g_checksum_update(hash, (guchar *)digest_uri, -1);
 
 	if (qop != NULL && !g_ascii_strcasecmp(qop, "auth-int"))
 	{
-		PurpleHash *hash2;
-		gchar entity_hash[33];
+		gchar *entity_hash;
 
 		if (entity == NULL)
 		{
-			g_object_unref(hash);
+			g_checksum_free(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));
-		digest_ok = purple_hash_digest_to_str(hash2, entity_hash, sizeof(entity_hash));
-		g_object_unref(hash2);
-
-		if (!digest_ok) {
-			g_object_unref(hash);
+		entity_hash = g_compute_checksum_for_string(G_CHECKSUM_MD5,
+				entity, -1);
+
+		if (entity_hash == NULL) {
+			g_checksum_free(hash);
 			g_return_val_if_reached(NULL);
 		}
 
-		purple_hash_append(hash, (guchar *)":", 1);
-		purple_hash_append(hash, (guchar *)entity_hash, strlen(entity_hash));
+		g_checksum_update(hash, (guchar *)":", -1);
+		g_checksum_update(hash, (guchar *)entity_hash, -1);
+		g_free(entity_hash);
 	}
 
-	digest_ok = purple_hash_digest_to_str(hash, hash2, sizeof(hash2));
-	purple_hash_reset(hash);
-
-	if (!digest_ok) {
-		g_object_unref(hash);
+	hash2 = g_strdup(g_checksum_get_string(hash));
+	g_checksum_reset(hash);
+
+	if (hash2 == NULL) {
+		g_checksum_free(hash);
 		g_return_val_if_reached(NULL);
 	}
 
-	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);
+	g_checksum_update(hash, (guchar *)session_key, -1);
+	g_checksum_update(hash, (guchar *)":", -1);
+	g_checksum_update(hash, (guchar *)nonce, -1);
+	g_checksum_update(hash, (guchar *)":", -1);
 
 	if (qop != NULL && *qop != '\0')
 	{
 		if (nonce_count == NULL)
 		{
-			g_object_unref(hash);
+			g_checksum_free(hash);
 			purple_debug_error("hash", "Required nonce_count missing for digest calculation.\n");
 			return NULL;
 		}
 
 		if (client_nonce == NULL)
 		{
-			g_object_unref(hash);
+			g_checksum_free(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);
+		g_checksum_update(hash, (guchar *)nonce_count, -1);
+		g_checksum_update(hash, (guchar *)":", -1);
+		g_checksum_update(hash, (guchar *)client_nonce, -1);
+		g_checksum_update(hash, (guchar *)":", -1);
+
+		g_checksum_update(hash, (guchar *)qop, -1);
+
+		g_checksum_update(hash, (guchar *)":", -1);
 	}
 
-	purple_hash_append(hash, (guchar *)hash2, strlen(hash2));
-	digest_ok = purple_hash_digest_to_str(hash, hash2, sizeof(hash2));
-	g_object_unref(hash);
-
-	g_return_val_if_fail(digest_ok, NULL);
-
-	return g_strdup(hash2);
+	g_checksum_update(hash, (guchar *)hash2, -1);
+	g_free(hash2);
+
+	hash2 = g_strdup(g_checksum_get_string(hash));
+	g_checksum_free(hash);
+
+	return hash2;
 }
 
 int
--- a/libpurple/util.h	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/util.h	Mon Jun 05 16:36:29 2017 +0300
@@ -287,43 +287,6 @@
  */
 gchar *purple_base16_encode_chunked(const guchar *data, gsize len);
 
-
-/**************************************************************************/
-/* Base64 Functions                                                       */
-/**************************************************************************/
-
-/**
- * purple_base64_encode:
- * @data: The data to convert.
- * @len:  The length of the data.
- *
- * Converts a chunk of binary data to its base-64 equivalent.
- *
- *  See purple_base64_decode()
- *
- * Returns: The base-64 string in the ASCII encoding.  Must be
- *         g_free'd when no longer needed.
- */
-gchar *purple_base64_encode(const guchar *data, gsize len);
-
-/**
- * purple_base64_decode:
- * @str:     The base-64 string to convert to raw data.
- * @ret_len: The length of the returned data.  You can
- *                pass in NULL if you're sure that you know
- *                the length of the decoded data, or if you
- *                know you'll be able to use strlen to
- *                determine the length, etc.
- *
- * Converts an ASCII string of base-64 encoded data to
- * the binary equivalent.
- *
- *  See purple_base64_encode()
- *
- * Returns: The raw data.  Must be g_free'd when no longer needed.
- */
-guchar *purple_base64_decode(const char *str, gsize *ret_len);
-
 /**************************************************************************/
 /* Quoted Printable Functions                                             */
 /**************************************************************************/
--- a/libpurple/win32/global.mak	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/win32/global.mak	Mon Jun 05 16:36:29 2017 +0300
@@ -25,7 +25,6 @@
 LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.9.2_daa1
 MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2_daa3
 NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.24-nspr-4.12
-PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl-5.20.1.1
 SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1.12
 GSTREAMER_TOP ?= $(WIN32_DEV_TOP)/gstreamer-0.10.13
 GCC_SSP_TOP ?= $(shell dirname $(shell which $(CC)))
@@ -40,15 +39,12 @@
 PIDGIN_INSTALL_DIR := $(PIDGIN_TREE_TOP)/win32-install-dir
 PURPLE_INSTALL_DIR := $(PIDGIN_TREE_TOP)/win32-install-dir
 PIDGIN_INSTALL_PLUGINS_DIR := $(PIDGIN_INSTALL_DIR)/plugins
-PIDGIN_INSTALL_PERL_DIR := $(PIDGIN_INSTALL_PLUGINS_DIR)/perl
 PURPLE_INSTALL_PLUGINS_DIR := $(PURPLE_INSTALL_DIR)/plugins
-PURPLE_INSTALL_PERL_DIR := $(PURPLE_INSTALL_PLUGINS_DIR)/perl
 PURPLE_INSTALL_PO_DIR := $(PURPLE_INSTALL_DIR)/locale
 
 # Important (enough) locations in our source code
 PURPLE_TOP := $(PIDGIN_TREE_TOP)/libpurple
 PURPLE_PLUGINS_TOP := $(PURPLE_TOP)/plugins
-PURPLE_PERL_TOP := $(PURPLE_PLUGINS_TOP)/perl
 PIDGIN_TOP := $(PIDGIN_TREE_TOP)/pidgin
 PIDGIN_PIXMAPS_TOP := $(PIDGIN_TOP)/pixmaps
 PIDGIN_PLUGINS_TOP := $(PIDGIN_TOP)/plugins
@@ -63,7 +59,6 @@
 PURPLE_PURPLE_H := $(PURPLE_TOP)/purple.h
 PURPLE_VERSION_H := $(PURPLE_TOP)/version.h
 PURPLE_DLL := $(PURPLE_TOP)/libpurple.dll
-PURPLE_PERL_DLL := $(PURPLE_PERL_TOP)/perl.dll
 PIDGIN_DLL := $(PIDGIN_TOP)/pidgin.dll
 PIDGIN_EXE := $(PIDGIN_TOP)/pidgin.exe
 PIDGIN_PORTABLE_EXE := $(PIDGIN_TOP)/pidgin-portable.exe
--- a/libpurple/win32/rules.mak	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/win32/rules.mak	Mon Jun 05 16:36:29 2017 +0300
@@ -3,9 +3,6 @@
 %.o: %.c
 	$(CC) $(CFLAGS) $(DEFINES) $(INCLUDE_PATHS) -o $@ -c $<
 
-%.c: %.xs
-	$(TAG) "PERL" $(PERL) -MExtUtils::ParseXS -e 'ExtUtils::ParseXS::process_file(filename => "$<", output => "$@", typemap => "$(PURPLE_PERL_TOP)/common/typemap");'
-
 %.o: %.rc
 	@echo -e "  GEN\t$@"
 	@$(WINDRES) -I$(PURPLE_TOP) -i $< -o $@
--- a/libpurple/win32/targets.mak	Sun May 28 13:26:27 2017 +0300
+++ b/libpurple/win32/targets.mak	Mon Jun 05 16:36:29 2017 +0300
@@ -35,9 +35,6 @@
 $(PURPLE_DLL) $(PURPLE_DLL).a: $(PURPLE_VERSION_H)
 	$(MAKE) -C $(PURPLE_TOP) -f $(MINGW_MAKEFILE) libpurple.dll
 
-$(PURPLE_PERL_DLL) $(PURPLE_PERL_DLL).a:
-	$(MAKE) -C $(PURPLE_PERL_TOP) -f $(MINGW_MAKEFILE) perl.dll
-
 $(PIDGIN_DLL) $(PIDGIN_DLL).a:
 	$(MAKE_at) $(MAKE) -C $(PIDGIN_TOP) -f $(MINGW_MAKEFILE) pidgin.dll
 
@@ -48,9 +45,6 @@
 $(PIDGIN_INSTALL_DIR):
 	mkdir -p $(PIDGIN_INSTALL_DIR)
 
-$(PIDGIN_INSTALL_PERL_DIR):
-	mkdir -p $(PIDGIN_INSTALL_PERL_DIR)
-
 $(PIDGIN_INSTALL_PLUGINS_DIR):
 	mkdir -p $(PIDGIN_INSTALL_PLUGINS_DIR)
 
@@ -59,6 +53,3 @@
 
 #$(PURPLE_INSTALL_PLUGINS_DIR):
 #	mkdir -p $(PURPLE_INSTALL_PLUGINS_DIR)
-
-#$(PURPLE_INSTALL_PERL_DIR):
-#	mkdir -p $(PURPLE_INSTALL_PERL_DIR)
--- a/pidgin/gtkdialogs.c	Sun May 28 13:26:27 2017 +0300
+++ b/pidgin/gtkdialogs.c	Mon Jun 05 16:36:29 2017 +0300
@@ -683,25 +683,6 @@
 	g_string_append(str, "<dt>Network Security Services (NSS):</dt><dd>Disabled</dd>");
 #endif
 
-#warning TODO: Check for perl.
-	if (purple_plugins_find_plugin("core-perl") != NULL)
-		g_string_append(str, "<dt>Perl:</dt><dd>Enabled</dd>");
-	else
-		g_string_append(str, "<dt>Perl:</dt><dd>Disabled</dd>");
-
-#warning TODO: Check for tcl.
-	if (purple_plugins_find_plugin("core-tcl") != NULL) {
-		g_string_append(str, "<dt>Tcl:</dt><dd>Enabled</dd>");
-#ifdef HAVE_TK
-		g_string_append(str, "<dt>Tk:</dt><dd>Enabled</dd>");
-#else
-		g_string_append(str, "<dt>Tk:</dt><dd>Disabled</dd>");
-#endif
-	} else {
-		g_string_append(str, "<dt>Tcl:</dt><dd>Disabled</dd>");
-		g_string_append(str, "<dt>Tk:</dt><dd>Disabled</dd>");
-	}
-
 #ifdef USE_IDN
 	g_string_append(str, "<dt>UTF-8 DNS (IDN):</dt><dd>Enabled</dd>");
 #else
--- a/pidgin/gtkwebview.c	Sun May 28 13:26:27 2017 +0300
+++ b/pidgin/gtkwebview.c	Mon Jun 05 16:36:29 2017 +0300
@@ -204,8 +204,7 @@
 			gchar *b64, *src;
 			const gchar *type;
 
-			b64 = purple_base64_encode(
-				purple_image_get_data(img),
+			b64 = g_base64_encode(purple_image_get_data(img),
 				purple_image_get_data_size(img));
 			type = purple_image_get_mimetype(img);
 			src = g_strdup_printf("data:%s;base64,%s", type, b64);
--- a/pidgin/plugins/Makefile.mingw	Sun May 28 13:26:27 2017 +0300
+++ b/pidgin/plugins/Makefile.mingw	Mon Jun 05 16:36:29 2017 +0300
@@ -8,7 +8,6 @@
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
 DISCO_PLUGIN := ./disco
-GTKPERL_PLUGIN := ./perl
 TICKER_PLUGIN := ./ticker
 TRANSPARENCY_PLUGIN := ./win32/transparency
 WINPREFS_PLUGIN := ./win32/winprefs
@@ -66,14 +65,12 @@
 
 all: plugins
 	$(MAKE_at) $(MAKE) -C $(DISCO_PLUGIN) -f $(MINGW_MAKEFILE)
-	$(MAKE_at) $(MAKE) -C $(GTKPERL_PLUGIN) -f $(MINGW_MAKEFILE)
 	$(MAKE_at) $(MAKE) -C $(TICKER_PLUGIN) -f $(MINGW_MAKEFILE)
 	$(MAKE_at) $(MAKE) -C $(TRANSPARENCY_PLUGIN) -f $(MINGW_MAKEFILE)
 	$(MAKE_at) $(MAKE) -C $(WINPREFS_PLUGIN) -f $(MINGW_MAKEFILE)
 
 install: all $(PIDGIN_INSTALL_PLUGINS_DIR)
 	$(MAKE_at) $(MAKE) -C $(DISCO_PLUGIN) -f $(MINGW_MAKEFILE) install
-	$(MAKE_at) $(MAKE) -C $(GTKPERL_PLUGIN) -f $(MINGW_MAKEFILE) install
 	$(MAKE_at) $(MAKE) -C $(TICKER_PLUGIN) -f $(MINGW_MAKEFILE) install
 	$(MAKE_at) $(MAKE) -C $(TRANSPARENCY_PLUGIN) -f $(MINGW_MAKEFILE) install
 	$(MAKE_at) $(MAKE) -C $(WINPREFS_PLUGIN) -f $(MINGW_MAKEFILE) install
@@ -106,7 +103,6 @@
 clean:
 	rm -f *.o *.dll
 	$(MAKE_at) $(MAKE) -C $(DISCO_PLUGIN) -f $(MINGW_MAKEFILE) clean
-	$(MAKE_at) $(MAKE) -C $(GTKPERL_PLUGIN) -f $(MINGW_MAKEFILE) clean
 	$(MAKE_at) $(MAKE) -C $(TICKER_PLUGIN) -f $(MINGW_MAKEFILE) clean
 	$(MAKE_at) $(MAKE) -C $(TRANSPARENCY_PLUGIN) -f $(MINGW_MAKEFILE) clean
 	$(MAKE_at) $(MAKE) -C $(WINPREFS_PLUGIN) -f $(MINGW_MAKEFILE) clean
--- a/pidgin/plugins/imgupload.c	Sun May 28 13:26:27 2017 +0300
+++ b/pidgin/plugins/imgupload.c	Mon Jun 05 16:36:29 2017 +0300
@@ -121,7 +121,7 @@
 		"Client-ID " IMGUP_IMGUR_CLIENT_ID);
 
 	/* TODO: make it a plain, multipart/form-data request */
-	img_data = purple_base64_encode(purple_image_get_data(image),
+	img_data = g_base64_encode(purple_image_get_data(image),
 		purple_image_get_data_size(image));
 	img_data_e = g_uri_escape_string(img_data, NULL, FALSE);
 	g_free(img_data);
--- a/pidgin/plugins/perl/Makefile.am	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-perl_dirs = common
-
-common_sources = \
-	common/GtkAccount.xs \
-	common/GtkBlist.xs \
-	common/GtkConn.xs \
-	common/GtkConv.xs \
-	common/GtkConvWin.xs \
-	common/GtkDebug.xs \
-	common/GtkDialogs.xs \
-	common/GtkFt.xs \
-	common/GtkLog.xs \
-	common/GtkMenuTray.xs \
-	common/GtkPlugin.xs \
-	common/GtkPluginPref.xs \
-	common/GtkPounce.xs \
-	common/GtkPrefs.xs \
-	common/GtkPrivacy.xs \
-	common/GtkRoomlist.xs \
-	common/GtkSavedStatuses.xs \
-	common/GtkSession.xs \
-	common/GtkSound.xs \
-	common/GtkStatusBox.xs \
-	common/GtkUtils.xs \
-	common/Makefile.PL.in \
-	common/Pidgin.pm \
-	common/Pidgin.xs \
-	common/gtkmodule.h \
-	common/typemap
-
-EXTRA_DIST = \
-	Makefile.mingw \
-	common/Makefile.mingw \
-	$(common_sources)
-
-common/Makefile: common/Makefile.PL
-	$(AM_V_GEN)if test "x${top_srcdir}" != "x${top_builddir}"; then \
-		for f in ${common_sources}; do \
-			srcloc=${srcdir}; \
-			case $$srcloc in /*) ;; *) srcloc=../${srcdir} ;; esac; \
-			${LN_S} -f $$srcloc/$$f $$f; \
-		done; \
-	fi
-	$(AM_V_at)cd common && $(perlpath) Makefile.PL > /dev/null
-
-common/Makefile.PL: common/Makefile.PL.in $(top_builddir)/config.status
-	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
-
-all-local: common/Makefile
-	@for dir in $(perl_dirs); do \
-		cd $$dir && \
-		if [ ! -f Makefile ]; then \
-			$(perlpath) Makefile.PL; \
-		fi && \
-		($(MAKE) CC="@$(abs_top_srcdir)/libpurple/tag.sh CC $(CC)" LD="@$(abs_top_srcdir)/libpurple/tag.sh LD $(CC)" PERLRUN="@$(abs_top_srcdir)/libpurple/tag.sh PERL $(PERL)" CCFLAGS="$(PERL_CFLAGS) $(CFLAGS)" CP="@cp" RM_F="@rm -f" CHMOD="@chmod" $(PERL_EXTRA_OPTS) || \
-		$(MAKE) CC="@$(abs_top_srcdir)/libpurple/tag.sh CC $(CC)" LD="@$(abs_top_srcdir)/libpurple/tag.sh LD $(CC)" PERLRUN="@$(abs_top_srcdir)/libpurple/tag.sh PERL $(PERL)" CCFLAGS="$(PERL_CFLAGS) $(CFLAGS)" CP="@cp" RM_F="@rm -f" CHMOD="@chmod" $(PERL_EXTRA_OPTS)) && \
-		cd ..; \
-	done
-
-install-exec-local:
-	@for dir in $(perl_dirs); do \
-		cd $$dir; \
-		$(MAKE) install; \
-		cd ..; \
-	done
-
-# Evil Hack (TM)
-# ... which doesn't work with DESTDIR installs. FIXME?
-uninstall-local:
-	@for dir in $(perl_dirs); do \
-		cd $$dir && \
-		`$(MAKE) uninstall | grep unlink | sed -e 's#/usr#${prefix}#' -e 's#unlink#rm -f#'` && \
-		cd ..; \
-	done
-
-clean-generic:
-	@for dir in $(perl_dirs); do \
-		cd $$dir; \
-		$(MAKE) clean; \
-		cd ..; \
-	done
-	cd common ; rm -rf *.c *.o pm_to_blib Pidgin.bs MYMETA.* blib/*/.exists blib/*/auto/Pidgin blib/*/Pidgin.*pm ; cd ..
-	rm -f *.so
-
-distclean-generic:
-	@for dir in $(perl_dirs); do \
-		cd $$dir; \
-		$(MAKE) realclean; \
-		rm -f Makefile.PL; \
-		rm -f Makefile.old; \
-		rm -f Makefile; \
-		cd ..; \
-	done
-
-	@rm -f Makefile
-
-AM_CPPFLAGS = \
-	-I$(top_srcdir) \
-	-I$(top_srcdir)/libpurple \
-	-I$(top_builddir)/libpurple \
-	-I$(top_srcdir)/pidgin \
-	$(DEBUG_CFLAGS) \
-	$(GTK_CFLAGS) \
-	$(GPLUGIN_CFLAGS) \
-	$(PLUGIN_CFLAGS) \
-	$(PERL_CFLAGS)
--- a/pidgin/plugins/perl/Makefile.mingw	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#
-# Makefile.mingw
-#
-# Description: Makefile for perl plugin loader plugin.
-#
-
-PIDGIN_TREE_TOP := ../../..
-include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
-
-#we cannot include win32dep.h, but we need struct sockaddr_in6 definition
-CFLAGS += -include ws2tcpip.h
-
-##
-## TARGET DEFINITIONS
-##
-.PHONY: all install clean
-
-all:
-	$(MAKE_at) $(MAKE) -C ./common -f $(MINGW_MAKEFILE)
-
-install: all $(PIDGIN_INSTALL_PLUGINS_DIR)
-	$(MAKE_at) $(MAKE) -C ./common -f $(MINGW_MAKEFILE) install
-
-##
-## CLEAN RULES
-##
-clean:
-	$(MAKE_at) $(MAKE) -C ./common -f $(MINGW_MAKEFILE) clean
--- a/pidgin/plugins/perl/common/GtkAccount.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Account  PACKAGE = Pidgin::Account  PREFIX = pidgin_account_
-PROTOTYPES: ENABLE
-
-Purple::Handle
-pidgin_accounts_get_handle()
-
-MODULE = Pidgin::Account  PACKAGE = Pidgin::Account::Dialog  PREFIX = pidgin_account_dialog_
-PROTOTYPES: ENABLE
-
-void
-pidgin_account_dialog_show(type, account)
-	Pidgin::Account::Dialog::Type type
-	Purple::Account account
-
-MODULE = Pidgin::Account  PACKAGE = Pidgin::Account::Window  PREFIX = pidgin_accounts_window_
-PROTOTYPES: ENABLE
-
-void
-pidgin_accounts_window_show()
-
-void
-pidgin_accounts_window_hide()
--- a/pidgin/plugins/perl/common/GtkBlist.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::BuddyList  PACKAGE = Pidgin::BuddyList  PREFIX = pidgin_blist_
-PROTOTYPES: ENABLE
-
-Purple::Handle
-pidgin_blist_get_handle()
-
-Pidgin::BuddyList
-pidgin_blist_get_default_gtk_blist()
-
-void
-pidgin_blist_refresh(list)
-	Purple::BuddyList list
-
-void
-pidgin_blist_update_refresh_timeout()
-
-gboolean
-pidgin_blist_node_is_contact_expanded(node)
-	Purple::BuddyList::Node node
-
-void
-pidgin_blist_toggle_visibility()
-
-void
-pidgin_blist_visibility_manager_add()
-
-void
-pidgin_blist_visibility_manager_remove()
-
-void
-pidgin_blist_get_sort_methods()
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = pidgin_blist_get_sort_methods(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Pidgin::BuddyList::SortMethod")));
-	}
-
-void
-pidgin_blist_sort_method_reg(id, name, func)
-	const char * id
-	const char * name
-	Pidgin::BuddyList::SortFunction func
-
-void
-pidgin_blist_sort_method_unreg(id)
-	const char * id
-
-void
-pidgin_blist_sort_method_set(id)
-	const char * id
-
-void
-pidgin_blist_setup_sort_methods()
-
-void
-pidgin_blist_update_accounts_menu()
-
-void
-pidgin_blist_update_plugin_actions()
-
-void
-pidgin_blist_update_sort_methods()
-
-gboolean
-pidgin_blist_joinchat_is_showable()
-
-void
-pidgin_blist_joinchat_show()
--- a/pidgin/plugins/perl/common/GtkConn.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Connection  PACKAGE = Pidgin::Connection  PREFIX = pidgin_connection_
-PROTOTYPES: ENABLE
-
-Purple::Handle
-pidgin_connection_get_handle()
--- a/pidgin/plugins/perl/common/GtkConv.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Conversation  PACKAGE = Pidgin::Conversation  PREFIX = pidgin_conv_
-PROTOTYPES: ENABLE
-
-void
-pidgin_conv_update_buddy_icon(im)
-	Purple::IMConversation im
-
-void
-pidgin_conv_switch_active_conversation(conv)
-	Purple::Conversation conv
-
-void
-pidgin_conv_update_buttons_by_protocol(conv)
-	Purple::Conversation conv
-
-void
-pidgin_conv_present_conversation(conv)
-	Purple::Conversation conv
-
-Pidgin::Conversation::Window
-pidgin_conv_get_window(conv)
-	Pidgin::Conversation conv
-
-void
-pidgin_conv_new(class, conv)
-	Purple::Conversation conv
-    C_ARGS:
-	conv
-
-gboolean
-pidgin_conv_is_hidden(gtkconv)
-	Pidgin::Conversation gtkconv
-
-void
-pidgin_conv_get_gtkconv(conv)
-	Purple::Conversation conv
-PPCODE:
-	if (conv != NULL && PIDGIN_IS_PIDGIN_CONVERSATION(conv))
-		XPUSHs(sv_2mortal(purple_perl_bless_object(
-				PIDGIN_CONVERSATION(conv),
-				"Pidgin::Conversation")));
-
-MODULE = Pidgin::Conversation  PACKAGE = Pidgin::Conversations  PREFIX = pidgin_conversations_
-PROTOTYPES: ENABLE
-
-void
-pidgin_conversations_get_unseen_all(min_state, hidden_only, max_count)
-	Pidgin::UnseenState min_state
-	gboolean hidden_only
-	guint max_count
-
-void
-pidgin_conversations_get_unseen_ims(min_state, hidden_only, max_count)
-	Pidgin::UnseenState min_state
-	gboolean hidden_only
-	guint max_count
-
-void
-pidgin_conversations_get_unseen_chats(min_state, hidden_only, max_count)
-	Pidgin::UnseenState min_state
-	gboolean hidden_only
-	guint max_count
-
-Purple::Handle
-pidgin_conversations_get_handle()
--- a/pidgin/plugins/perl/common/GtkConvWin.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Conversation::Window  PACKAGE = Pidgin::Conversation::Window  PREFIX = pidgin_conv_window_
-PROTOTYPES: ENABLE
-
-Pidgin::Conversation::Window
-pidgin_conv_window_new(class)
-    C_ARGS: /* void */
-
-void
-pidgin_conv_window_destroy(win)
-	Pidgin::Conversation::Window win
-
-void
-pidgin_conv_window_show(win)
-	Pidgin::Conversation::Window win
-
-void
-pidgin_conv_window_hide(win)
-	Pidgin::Conversation::Window win
-
-void
-pidgin_conv_window_raise(win)
-	Pidgin::Conversation::Window win
-
-void
-pidgin_conv_window_switch_gtkconv(win, gtkconv)
-	Pidgin::Conversation::Window win
-	Pidgin::Conversation gtkconv
-
-void
-pidgin_conv_window_add_gtkconv(win, gtkconv)
-	Pidgin::Conversation::Window win
-	Pidgin::Conversation gtkconv
-
-void
-pidgin_conv_window_remove_gtkconv(win, gtkconv)
-	Pidgin::Conversation::Window win
-	Pidgin::Conversation gtkconv
-
-Pidgin::Conversation
-pidgin_conv_window_get_gtkconv_at_index(win, index)
-	Pidgin::Conversation::Window win
-	int index
-
-Pidgin::Conversation
-pidgin_conv_window_get_active_gtkconv(win)
-	Pidgin::Conversation::Window win
-
-Purple::Conversation
-pidgin_conv_window_get_active_conversation(win)
-	Pidgin::Conversation::Window win
-
-gboolean
-pidgin_conv_window_is_active_conversation(conv)
-	Purple::Conversation conv
-
-gboolean
-pidgin_conv_window_has_focus(win)
-	Pidgin::Conversation::Window win
-
-void
-pidgin_conv_window_get_gtkconvs(win)
-	Pidgin::Conversation::Window win
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = pidgin_conv_window_get_gtkconvs(win); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Pidgin::Conversation")));
-	}
-
-guint
-pidgin_conv_window_get_gtkconv_count(win)
-	Pidgin::Conversation::Window win
-
-Pidgin::Conversation::Window
-pidgin_conv_window_first_im()
-
-Pidgin::Conversation::Window
-pidgin_conv_window_last_im()
-
-Pidgin::Conversation::Window
-pidgin_conv_window_first_chat()
-
-Pidgin::Conversation::Window
-pidgin_conv_window_last_chat()
-
-MODULE = Pidgin::Conversation::Window  PACKAGE = Pidgin::Conversation::Placement  PREFIX = pidgin_conv_placement_
-PROTOTYPES: ENABLE
-
-void
-pidgin_conv_placement_get_options()
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = pidgin_conv_placement_get_options(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Pidgin::Conversation::Window")));
-	}
-
-void
-pidgin_conv_placement_add_fnc(id, name, fnc)
-	const char * id
-	const char * name
-	Pidgin::Conversation::PlacementFunc fnc
-
-void
-pidgin_conv_placement_remove_fnc(id)
-	const char * id
-
-const char *
-pidgin_conv_placement_get_name(id)
-	const char * id
-
-Pidgin::Conversation::PlacementFunc
-pidgin_conv_placement_get_fnc(id)
-	const char * id
-
-void
-pidgin_conv_placement_set_current_func(func)
-	Pidgin::Conversation::PlacementFunc func
-
-Pidgin::Conversation::PlacementFunc
-pidgin_conv_placement_get_current_func()
-
-void
-pidgin_conv_placement_place(gtkconv)
-	Pidgin::Conversation gtkconv
-
-MODULE = Pidgin::Conversation::Window  PACKAGE = Pidgin::Conversation::Windows  PREFIX = pidgin_conv_windows_
-PROTOTYPES: ENABLE
-
-void
-pidgin_conv_windows_get_list()
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = pidgin_conv_windows_get_list(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Pidgin::Conversation::Window")));
-	}
--- a/pidgin/plugins/perl/common/GtkDebug.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Debug  PACKAGE = Pidgin::Debug  PREFIX = pidgin_debug_
-PROTOTYPES: ENABLE
-
-Purple::Handle
-pidgin_debug_get_handle()
-
-MODULE = Pidgin::Debug  PACKAGE = Pidgin::Debug::Window  PREFIX = pidgin_debug_window_
-PROTOTYPES: ENABLE
-
-void
-pidgin_debug_window_show()
-
-void
-pidgin_debug_window_hide()
--- a/pidgin/plugins/perl/common/GtkDialogs.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Dialogs  PACKAGE = Pidgin::Dialogs  PREFIX = pidgin_dialogs_
-PROTOTYPES: ENABLE
-
-void
-pidgin_dialogs_destroy_all()
-
-void
-pidgin_dialogs_about()
-
-void
-pidgin_dialogs_im()
-
-void
-pidgin_dialogs_im_with_user(account, username)
-	Purple::Account account
-	const char * username
-
-void
-pidgin_dialogs_info()
-
-void
-pidgin_dialogs_log()
-
-void
-pidgin_dialogs_alias_buddy(buddy)
-	Purple::BuddyList::Buddy buddy
-
-void
-pidgin_dialogs_alias_chat(chat)
-	Purple::BuddyList::Chat chat
-
-void
-pidgin_dialogs_remove_buddy(buddy)
-	Purple::BuddyList::Buddy buddy
-
-void
-pidgin_dialogs_remove_group(group)
-	Purple::BuddyList::Group group
-
-void
-pidgin_dialogs_remove_chat(chat)
-	Purple::BuddyList::Chat chat
-
-void
-pidgin_dialogs_remove_contact(contact)
-	Purple::BuddyList::Contact contact
--- a/pidgin/plugins/perl/common/GtkFt.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Xfer  PACKAGE = Pidgin::Xfer  PREFIX = pidgin_
-PROTOTYPES: ENABLE
-
-void
-pidgin_set_xfer_dialog(dialog)
-	Pidgin::Xfer::Dialog dialog
-
-Pidgin::Xfer::Dialog
-pidgin_get_xfer_dialog()
-
-MODULE = Pidgin::Xfer  PACKAGE = Pidgin::Xfer::Dialog  PREFIX = pidgin_xfer_dialog_
-PROTOTYPES: ENABLE
-
-Pidgin::Xfer::Dialog
-pidgin_xfer_dialog_new(class)
-    C_ARGS: /* void */
-
-void
-pidgin_xfer_dialog_destroy(dialog)
-	Pidgin::Xfer::Dialog dialog
-
-void
-pidgin_xfer_dialog_show(dialog = NULL)
-	Pidgin::Xfer::Dialog dialog
-
-void
-pidgin_xfer_dialog_hide(dialog)
-	Pidgin::Xfer::Dialog dialog
-
-void
-pidgin_xfer_dialog_add_xfer(dialog, xfer)
-	Pidgin::Xfer::Dialog dialog
-	Purple::Xfer xfer
-
-void
-pidgin_xfer_dialog_remove_xfer(dialog, xfer)
-	Pidgin::Xfer::Dialog dialog
-	Purple::Xfer xfer
-
-void
-pidgin_xfer_dialog_cancel_xfer(dialog, xfer)
-	Pidgin::Xfer::Dialog dialog
-	Purple::Xfer xfer
-
-void
-pidgin_xfer_dialog_update_xfer(dialog, xfer)
-	Pidgin::Xfer::Dialog dialog
-	Purple::Xfer xfer
--- a/pidgin/plugins/perl/common/GtkLog.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Log  PACKAGE = Pidgin::Log  PREFIX = pidgin_log_
-PROTOTYPES: ENABLE
-
-Purple::Handle
-pidgin_log_get_handle()
-
-void
-pidgin_log_show(type, buddyname, account)
-	Purple::LogType type
-	const char * buddyname
-	Purple::Account account
-
-void
-pidgin_log_show_contact(contact)
-	Purple::BuddyList::Contact contact
-
-MODULE = Pidgin::Log  PACKAGE = Pidgin::SysLog  PREFIX = pidgin_syslog_
-PROTOTYPES: ENABLE
-
-void
-pidgin_syslog_show()
--- a/pidgin/plugins/perl/common/GtkMenuTray.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#include "gtkmodule.h"
-
-/* This can't work at the moment since I don't have a typemap for Gtk::Widget.
- * I thought about using the one from libgtk2-perl but wasn't sure how to go
- * about doing that.
-Gtk::Widget
-pidgin_menu_tray_new()
-
-Gtk::Widget
-pidgin_menu_tray_get_box(menu_tray)
-	Pidgin::MenuTray menu_tray
-
-void
-pidgin_menu_tray_append(menu_tray, widget, tooltip)
-	Pidgin::MenuTray menu_tray
-	Gtk::Widget widget
-	const char * tooltip
-
-void
-pidgin_menu_tray_prepend(menu_tray, widget, tooltip)
-	Pidgin::MenuTray menu_tray
-	Gtk::Widget widget
-	const char * tooltip
-
-void
-pidgin_menu_tray_set_tooltip(menu_tray, widget, tooltip)
-	Pidgin::MenuTray menu_tray
-	Gtk::Widget widget
-	const char * tooltip
-*/
-
-MODULE = Pidgin::MenuTray  PACKAGE = Pidgin::MenuTray  PREFIX = pidgin_menu_tray
-PROTOTYPES: ENABLE
--- a/pidgin/plugins/perl/common/GtkPlugin.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Plugin  PACKAGE = Pidgin::Plugins  PREFIX = pidgin_plugins_
-PROTOTYPES: ENABLE
-
-void
-pidgin_plugins_save()
-
-MODULE = Pidgin::Plugin  PACKAGE = Pidgin::Plugin::Dialog  PREFIX = pidgin_plugin_dialog_
-PROTOTYPES: ENABLE
-
-void
-pidgin_plugin_dialog_show()
--- a/pidgin/plugins/perl/common/GtkPluginPref.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::PluginPref  PACKAGE = Pidgin::PluginPref  PREFIX = pidgin_plugin_pref_
-PROTOTYPES: ENABLE
--- a/pidgin/plugins/perl/common/GtkPounce.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Pounce  PACKAGE = Pidgin::Pounce  PREFIX = pidgin_pounce_
-PROTOTYPES: ENABLE
-
-void
-pidgin_pounce_editor_show(account, name, cur_pounce)
-	Purple::Account account
-	const char * name
-	Purple::Pounce cur_pounce
-
-MODULE = Pidgin::Pounce  PACKAGE = Pidgin::Pounces  PREFIX = pidgin_pounces_
-PROTOTYPES: ENABLE
-
-Purple::Handle
-pidgin_pounces_get_handle()
-
-MODULE = Pidgin::Pounce  PACKAGE = Pidgin::Pounces::Manager  PREFIX = pidgin_pounces_manager_
-PROTOTYPES: ENABLE
-
-void
-pidgin_pounces_manager_show()
-
-void
-pidgin_pounces_manager_hide()
--- a/pidgin/plugins/perl/common/GtkPrefs.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Prefs  PACKAGE = Pidgin::Prefs  PREFIX = pidgin_prefs_
-PROTOTYPES: ENABLE
-
-void
-pidgin_prefs_show()
--- a/pidgin/plugins/perl/common/GtkPrivacy.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Privacy  PACKAGE = Pidgin::Privacy  PREFIX = pidgin_
-PROTOTYPES: ENABLE
-
-void
-pidgin_request_add_permit(account, name)
-	Purple::Account account
-	const char * name
-
-void
-pidgin_request_add_block(account, name)
-	Purple::Account account
-	const char * name
-
-MODULE = Pidgin::Privacy  PACKAGE = Pidgin::Privacy::Dialog  PREFIX = pidgin_privacy_dialog_
-PROTOTYPES: ENABLE
-
-void
-pidgin_privacy_dialog_show()
-
-void
-pidgin_privacy_dialog_hide()
--- a/pidgin/plugins/perl/common/GtkRoomlist.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Roomlist  PACKAGE = Pidgin::Roomlist  PREFIX = pidgin_roomlist_
-PROTOTYPES: ENABLE
-
-gboolean
-pidgin_roomlist_is_showable()
-
-MODULE = Pidgin::Roomlist  PACKAGE = Pidgin::Roomlist::Dialog  PREFIX = pidgin_roomlist_dialog_
-PROTOTYPES: ENABLE
-
-void
-pidgin_roomlist_dialog_show()
-
-void
-pidgin_roomlist_dialog_show_with_account(account)
-	Purple::Account account
--- a/pidgin/plugins/perl/common/GtkSavedStatuses.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Status  PACKAGE = Pidgin::Status  PREFIX = pidgin_status_
-PROTOTYPES: ENABLE
-
-Purple::Handle
-pidgin_status_get_handle()
-
-MODULE = Pidgin::Status  PACKAGE = Pidgin::Status::Editor  PREFIX = pidgin_status_editor_
-PROTOTYPES: ENABLE
-
-void
-pidgin_status_editor_show(edit, status)
-	gboolean edit
-	Purple::SavedStatus status
-
-MODULE = Pidgin::Status  PACKAGE = Pidgin::Status::Window  PREFIX = pidgin_status_window_
-PROTOTYPES: ENABLE
-
-void
-pidgin_status_window_show()
-
-void
-pidgin_status_window_hide()
--- a/pidgin/plugins/perl/common/GtkSession.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Session  PACKAGE = Pidgin::Session  PREFIX = pidgin_session_
-PROTOTYPES: ENABLE
-
-void
-pidgin_session_init(argv0, previous_id, config_dir)
-	gchar * argv0
-	gchar * previous_id
-	gchar * config_dir
-
-void
-pidgin_session_end()
--- a/pidgin/plugins/perl/common/GtkSound.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Sound  PACKAGE = Pidgin::Sound  PREFIX = pidgin_sound_
-PROTOTYPES: ENABLE
-
-const char *
-pidgin_sound_get_event_option(event)
-	Purple::SoundEventID event
-
-const char *
-pidgin_sound_get_event_label(event)
-	Purple::SoundEventID event
-
-Purple::Handle
-pidgin_sound_get_handle()
--- a/pidgin/plugins/perl/common/GtkStatusBox.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-#include "gtkmodule.h"
-
-/* This can't work at the moment since I don't have a typemap for Gtk::Widget.
- * I thought about using the one from libgtk2-perl but wasn't sure how to go
- * about doing that.
-Gtk::Widget
-pidgin_status_box_new()
-
-Gtk::Widget
-pidgin_status_box_new_with_account(account)
-	Purple::Account account
-
-void
-pidgin_status_box_add(status_box, type, pixbuf, text, sec_text, data)
-	Pidgin::StatusBox status_box
-	Pidgin::StatusBox::ItemType type
-	GdkPixbuf pixbuf
-	const char * text
-	const char * sec_text
-	gpointer data
-*/
-
-MODULE = Pidgin::StatusBox  PACKAGE = Pidgin::StatusBox  PREFIX = pidgin_status_box_
-PROTOTYPES: ENABLE
-
-void
-pidgin_status_box_add_separator(status_box)
-	Pidgin::StatusBox status_box
-
-void
-pidgin_status_box_set_connecting(status_box, connecting)
-	Pidgin::StatusBox status_box
-	gboolean connecting
-
-void
-pidgin_status_box_pulse_connecting(status_box)
-	Pidgin::StatusBox status_box
-
-gchar_own *
-pidgin_status_box_get_message(status_box)
-	Pidgin::StatusBox status_box
--- a/pidgin/plugins/perl/common/GtkUtils.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-#include "gtkmodule.h"
-
-MODULE = Pidgin::Utils  PACKAGE = Pidgin::Utils  PREFIX = pidgin_
-PROTOTYPES: ENABLE
-
-gboolean
-pidgin_save_accels(data)
-	gpointer data
-
-void
-pidgin_load_accels()
-
-gchar_own *
-pidgin_convert_buddy_icon(plugin, path, size)
-	Purple::Plugin plugin
-	const char * path
-	size_t *size
--- a/pidgin/plugins/perl/common/MANIFEST	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-GtkAccount.xs
-GtkBlist.xs
-GtkConn.xs
-GtkConv.xs
-GtkConvWin.xs
-GtkDebug.xs
-GtkDialogs.xs
-GtkFt.xs
-GtkLog.xs
-GtkMenuTray.xs
-GtkPlugin.xs
-GtkPluginPref.xs
-GtkPounce.xs
-GtkPrefs.xs
-GtkPrivacy.xs
-GtkRoomlist.xs
-GtkSavedStatuses.xs
-GtkSession.xs
-GtkSound.xs
-GtkStatusBox.xs
-GtkUtils.xs
-MANIFEST
-Pidgin.pm
-Pidgin.xs
-typemap
--- a/pidgin/plugins/perl/common/Makefile.PL.in	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-use 5.006;
-use ExtUtils::MakeMaker;
-# See lib/ExtUtils/MakeMaker.pm for details of how to influence the contents
-# of the Makefile that is written.
-WriteMakefile(
-    'NAME'             => 'Pidgin',
-    'VERSION'          => '@VERSION@',
-    ($] >= 5.005 ? ## Add these new keywords supported since 5.005
-      ('ABSTRACT_FROM' => '@srcdir@/Pidgin.pm', # finds $ABSTRACT
-       'AUTHOR'        => 'Pidgin <https://pidgin.im/>') :  ()),
-    'DEFINE'        => '@DEBUG_CFLAGS@ -Wno-float-equal',
-    'dynamic_lib'       => { 'OTHERLDFLAGS' => '@LDFLAGS@' },
-    'INC'           => '-I. -I@srcdir@ -I@top_srcdir@ -I@top_builddir@ -I@top_srcdir@/libpurple -I@top_srcdir@/pidgin @GTK_CFLAGS@ @WEBKIT_CFLAGS@ -DHAVE_CONFIG_H',
-    'OBJECT'        => '$(O_FILES)', # link all the C files too
-    'TYPEMAPS'      => ["@top_srcdir@/libpurple/plugins/perl/common/typemap"],
-#    'OPTIMIZE'      => '-g', # For debugging.
-    'INSTALLDIRS'          => 'vendor',
-    'INSTALL_BASE'         => '$(prefix)',
-    'INSTALLVENDORARCH'    => '$(libdir)/pidgin-$(PURPLE_MAJOR_VERSION)/perl',
-    'INSTALLVENDORMAN3DIR' => '$(mandir)/man3',
-    'macro'                => {
-        'prefix'      => '@prefix@',
-        'exec_prefix' => '@exec_prefix@',
-        'libdir'      => '@libdir@',
-        'mandir'      => '@mandir@',
-        'datarootdir' => '@datarootdir@',
-    },
-);
--- a/pidgin/plugins/perl/common/Makefile.mingw	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-#
-# Makefile.mingw
-#
-# Description: Makefile for Pidgin perl module.
-#
-
-PIDGIN_TREE_TOP := ../../../..
-include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
-
-#we cannot include win32dep.h, but we need struct sockaddr_in6 definition
-CFLAGS += -include ws2tcpip.h
-
-GCCWARNINGS += -Wno-comment -Wno-unused -Wno-nested-externs
-
-DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES))
-
-TARGET = Pidgin
-
-##
-## INCLUDE PATHS
-##
-INCLUDE_PATHS =		-I. \
-			-I$(PIDGIN_TREE_TOP) \
-			-I$(PURPLE_TOP) \
-			-I$(PURPLE_TOP)/win32 \
-			-I$(PIDGIN_TOP) \
-			-I$(PIDGIN_TOP)/win32 \
-			-I$(GTK_TOP)/include \
-			-I$(GTK_TOP)/include/atk-1.0 \
-			-I$(GTK_TOP)/include/cairo \
-			-I$(GTK_TOP)/include/glib-2.0 \
-			-I$(GTK_TOP)/include/gtk-2.0 \
-			-I$(GTK_TOP)/include/pango-1.0 \
-			-I$(GTK_TOP)/include/gdk-pixbuf-2.0 \
-			-I$(GTK_TOP)/lib/glib-2.0/include \
-			-I$(GTK_TOP)/lib/gtk-2.0/include \
-			-I$(LIBSOUP_TOP)/include/libsoup-2.4 \
-			-I$(WEBKITGTK_TOP)/include/webkitgtk-1.0 \
-			-I$(PERL_LIB_TOP)/include
-
-LIB_PATHS += \
-			-L$(PERL_LIB_TOP)/lib \
-			-L$(PURPLE_TOP) \
-			-L$(PIDGIN_TOP) \
-			-L$(PURPLE_PERL_TOP) \
-			-L$(GTK_TOP)/lib
-
-##
-##  SOURCES, OBJECTS
-##
-XS_FILES = \
-	Pidgin.xs \
-	GtkAccount.xs \
-	GtkBlist.xs \
-	GtkConn.xs \
-	GtkConv.xs \
-	GtkConvWin.xs \
-	GtkDebug.xs \
-	GtkDialogs.xs \
-	GtkFt.xs \
-	GtkLog.xs \
-	GtkMenuTray.xs \
-	GtkPlugin.xs \
-	GtkPluginPref.xs \
-	GtkPounce.xs \
-	GtkPrefs.xs \
-	GtkPrivacy.xs \
-	GtkRoomlist.xs \
-	GtkSavedStatuses.xs \
-	GtkSound.xs \
-	GtkStatusBox.xs \
-	GtkUtils.xs
-
-
-C_FILES = $(XS_FILES:%.xs=%.c)
-OBJECTS = $(C_FILES:%.c=%.o)
-
-##
-## LIBRARIES
-##
-LIBS =			-lperl520 \
-			-lperl \
-			-lpurple \
-			-lpidgin \
-			-lglib-2.0
-
-include $(PIDGIN_COMMON_RULES)
-
-##
-## TARGETS
-##
-.PHONY: all install clean
-
-all: $(TARGET).dll
-
-$(PURPLE_INSTALL_PERL_DIR)/Purple.pm:
-	$(MAKE) -C $(PURPLE_PERL_TOP)/common -f $(MINGW_MAKEFILE) install
-
-install: all $(PURPLE_INSTALL_PERL_DIR)/Purple.pm
-	rm -f $(PIDGIN_INSTALL_PERL_DIR)/$(TARGET).dll $(PIDGIN_INSTALL_PERL_DIR)/auto/Pidgin/$(TARGET).pm
-	mkdir -p $(PIDGIN_INSTALL_PERL_DIR)
-	cp $(TARGET).pm $(PIDGIN_INSTALL_PERL_DIR)
-	mkdir -p $(PIDGIN_INSTALL_PERL_DIR)/auto/Pidgin
-	cp $(TARGET).dll $(PIDGIN_INSTALL_PERL_DIR)/auto/Pidgin
-
-$(C_FILES): $(PIDGIN_CONFIG_H)
-
-$(TARGET).dll: $(PIDGIN_DLL).a $(PURPLE_PERL_DLL).a $(OBJECTS)
-	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(DLL_LD_FLAGS) $(LIBS) -o $(TARGET).dll
-
-##
-## CLEAN
-##
-clean:
-	rm -f *.o $(C_FILES) $(TARGET).dll
-
-include $(PIDGIN_COMMON_TARGETS)
--- a/pidgin/plugins/perl/common/Pidgin.pm	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-package Pidgin;
-
-use 5.008;
-use strict;
-use warnings;
-use Carp;
-
-use Purple;
-
-require XSLoader;
-XSLoader::load('Pidgin', $VERSION);
-
-1;
-__END__
-
-=head1 NAME
-
-Pidgin - Perl extension for the Pidgin instant messenger.
-
-=head1 SYNOPSIS
-
-    use Pidgin;
-
-=head1 ABSTRACT
-
-    This module provides the interface for using perl scripts as plugins in
-    Pidgin, with access to the Pidgin Gtk interface functions.
-
-=head1 DESCRIPTION
-
-This module provides the interface for using perl scripts as plugins in Pidgin,
-with access to the Pidgin Gtk interface functions. With this, developers can
-write perl scripts that can be loaded in Pidgin as plugins. The script can
-interact with IMs, chats, accounts, the buddy list, pidgin signals, and more.
-
-The API for the perl interface is very similar to that of the Pidgin C API,
-which can be viewed at https://developer.pidgin.im/doxygen/ or in the header files
-in the Pidgin source tree.
-
-=head1 FUNCTIONS
-
-=over
-
-=back
-
-=head1 SEE ALSO
-Pidgin C API documentation - https://developer.pidgin.im/doxygen/
-
-The Pidgin perl module.
-
-Pidgin website - https://pidgin.im/
-
-=head1 AUTHOR
-
-Etan Reisner, E<lt>deryni@gmail.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2006 by Etan Reisner
--- a/pidgin/plugins/perl/common/Pidgin.xs	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-#define PIDGIN_PERL_BOOT_PROTO(x) \
-	void boot_Pidgin__##x(pTHX_ CV *cv)
-
-#define PIDGIN_PERL_BOOT(x) \
-	purple_perl_callXS(boot_Pidgin__##x, cv, mark)
-
-#include "gtkmodule.h"
-
-/* Prototypes for the BOOT section below. */
-PIDGIN_PERL_BOOT_PROTO(Account);
-PIDGIN_PERL_BOOT_PROTO(BuddyList);
-PIDGIN_PERL_BOOT_PROTO(Connection);
-PIDGIN_PERL_BOOT_PROTO(Conversation);
-PIDGIN_PERL_BOOT_PROTO(Conversation__Window);
-PIDGIN_PERL_BOOT_PROTO(Debug);
-PIDGIN_PERL_BOOT_PROTO(Dialogs);
-PIDGIN_PERL_BOOT_PROTO(Log);
-PIDGIN_PERL_BOOT_PROTO(MenuTray);
-PIDGIN_PERL_BOOT_PROTO(Plugin);
-PIDGIN_PERL_BOOT_PROTO(PluginPref);
-PIDGIN_PERL_BOOT_PROTO(Pounce);
-PIDGIN_PERL_BOOT_PROTO(Prefs);
-PIDGIN_PERL_BOOT_PROTO(Privacy);
-PIDGIN_PERL_BOOT_PROTO(Roomlist);
-PIDGIN_PERL_BOOT_PROTO(Status);
-#ifndef _WIN32
-PIDGIN_PERL_BOOT_PROTO(Session);
-#endif
-PIDGIN_PERL_BOOT_PROTO(Sound);
-PIDGIN_PERL_BOOT_PROTO(StatusBox);
-PIDGIN_PERL_BOOT_PROTO(Utils);
-PIDGIN_PERL_BOOT_PROTO(Xfer);
-
-MODULE = Pidgin  PACKAGE = Pidgin  PREFIX = pidgin_
-PROTOTYPES: ENABLE
-
-BOOT:
-	PIDGIN_PERL_BOOT(Account);
-	PIDGIN_PERL_BOOT(BuddyList);
-	PIDGIN_PERL_BOOT(Connection);
-	PIDGIN_PERL_BOOT(Conversation);
-	PIDGIN_PERL_BOOT(Conversation__Window);
-	PIDGIN_PERL_BOOT(Debug);
-	PIDGIN_PERL_BOOT(Dialogs);
-	PIDGIN_PERL_BOOT(Log);
-	PIDGIN_PERL_BOOT(MenuTray);
-	PIDGIN_PERL_BOOT(Plugin);
-	PIDGIN_PERL_BOOT(PluginPref);
-	PIDGIN_PERL_BOOT(Pounce);
-	PIDGIN_PERL_BOOT(Prefs);
-	PIDGIN_PERL_BOOT(Privacy);
-	PIDGIN_PERL_BOOT(Roomlist);
-	PIDGIN_PERL_BOOT(Status);
-#ifndef _WIN32
-	PIDGIN_PERL_BOOT(Session);
-#endif
-	PIDGIN_PERL_BOOT(Sound);
-	PIDGIN_PERL_BOOT(StatusBox);
-	PIDGIN_PERL_BOOT(Utils);
-	PIDGIN_PERL_BOOT(Xfer);
--- a/pidgin/plugins/perl/common/gtkmodule.h	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/* Allow the Perl code to see deprecated functions, so we can continue to
- * export them to Perl plugins. */
-#undef PIDGIN_DISABLE_DEPRECATED
-
-typedef struct group *Pidgin__Group;
-
-#define group perl_group
-
-#include <glib.h>
-#include <gtk/gtk.h>
-#ifdef _WIN32
-#undef pipe
-#endif
-
-#define SILENT_NO_TAINT_SUPPORT 0
-#define NO_TAINT_SUPPORT 0
-
-#include <EXTERN.h>
-#include <perl.h>
-#include <XSUB.h>
-
-#undef group
-
-#include <plugins/perl/common/module.h>
-
-#include "gtkaccount.h"
-#include "gtkblist.h"
-#include "gtkconn.h"
-#include "gtkconv.h"
-#include "gtkconvwin.h"
-#include "gtkdebug.h"
-#include "gtkdialogs.h"
-#include "gtkxfer.h"
-#include "gtklog.h"
-#include "gtkmenutray.h"
-#include "gtkplugin.h"
-#include "gtkpluginpref.h"
-#include "gtkpounce.h"
-#include "gtkprefs.h"
-#include "gtkprivacy.h"
-#include "gtkroomlist.h"
-#include "gtksavedstatuses.h"
-#include "gtksession.h"
-#include "gtksound.h"
-#include "gtkstatusbox.h"
-#include "gtkutils.h"
-
-/* gtkaccount.h */
-typedef PidginAccountDialogType		Pidgin__Account__Dialog__Type;
-
-/* gtkblist.h */
-typedef PidginBuddyList *		Pidgin__BuddyList;
-typedef pidgin_blist_sort_function	Pidgin__BuddyList__SortFunction;
-
-/* gtkconv.h */
-typedef PidginConversation *		Pidgin__Conversation;
-typedef PidginUnseenState		Pidgin__UnseenState;
-
-/* gtkconvwin.h */
-typedef PidginConvWindow *			Pidgin__Conversation__Window;
-typedef PidginConvPlacementFunc		Pidgin__Conversation__PlacementFunc;
-
-/* gtkxfer.h */
-typedef PidginXferDialog *		Pidgin__Xfer__Dialog;
-
-/* gtkmenutray.h */
-typedef PidginMenuTray *		Pidgin__MenuTray;
-
-/* gtkstatusbox.h */
-typedef PidginStatusBox *		Pidgin__StatusBox;
--- a/pidgin/plugins/perl/common/typemap	Sun May 28 13:26:27 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-TYPEMAP
-
-Pidgin::Account::Dialog::Type      T_IV
-Pidgin::BuddyList                  T_PurpleObj
-Pidgin::BuddyList::SortFunction    T_PurpleObj
-Pidgin::Conversation               T_PurpleObj
-Pidgin::Conversation::PlacementFunc       T_PurpleObj
-Pidgin::Conversation::Window       T_PurpleObj
-Pidgin::Xfer::Dialog               T_PurpleObj
-Pidgin::MenuTray                   T_PurpleObj
-Pidgin::StatusBox                  T_PurpleObj
-Pidgin::UnseenState                T_IV
--- a/pidgin/plugins/raw.c	Sun May 28 13:26:27 2017 +0300
+++ b/pidgin/plugins/raw.c	Mon Jun 05 16:36:29 2017 +0300
@@ -119,7 +119,7 @@
 		"category",     N_("Protocol utility"),
 		"summary",      N_("Lets you send raw input to text-based protocols."),
 		"description",  N_("Lets you send raw input to text-based protocols "
-		                   "(XMPP, MSN, IRC, TOC). Hit 'Enter' in the entry "
+		                   "(XMPP, IRC, TOC). Hit 'Enter' in the entry "
 		                   "box to send. Watch the debug window."),
 		"authors",      authors,
 		"website",      PURPLE_WEBSITE,
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Sun May 28 13:26:27 2017 +0300
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Mon Jun 05 16:36:29 2017 +0300
@@ -543,7 +543,6 @@
     Delete "$INSTDIR\plugins\gtkbuddynote.dll"
     Delete "$INSTDIR\plugins\history.dll"
 	Delete "$INSTDIR\plugins\internalkeyring.dll"
-	Delete "$INSTDIR\plugins\ssl-gnutls.dll"
 	Delete "$INSTDIR\plugins\webkit.dll"
 	Delete "$INSTDIR\plugins\wincred.dll"
     Delete "$INSTDIR\plugins\iconaway.dll"
@@ -564,16 +563,12 @@
     Delete "$INSTDIR\plugins\markerline.dll"
     Delete "$INSTDIR\plugins\newline.dll"
     Delete "$INSTDIR\plugins\notify.dll"
-    Delete "$INSTDIR\plugins\nss-prefs.dll"
     Delete "$INSTDIR\plugins\offlinemsg.dll"
-    Delete "$INSTDIR\plugins\perl.dll"
     Delete "$INSTDIR\plugins\pidginrc.dll"
     Delete "$INSTDIR\plugins\psychic.dll"
     Delete "$INSTDIR\plugins\relnot.dll"
     Delete "$INSTDIR\plugins\sendbutton.dll"
     Delete "$INSTDIR\plugins\spellchk.dll"
-    Delete "$INSTDIR\plugins\ssl-nss.dll"
-    Delete "$INSTDIR\plugins\ssl.dll"
     Delete "$INSTDIR\plugins\statenotify.dll"
     Delete "$INSTDIR\plugins\ticker.dll"
     Delete "$INSTDIR\plugins\timestamp.dll"
@@ -582,15 +577,6 @@
     Delete "$INSTDIR\plugins\winprefs.dll"
     Delete "$INSTDIR\plugins\xmppconsole.dll"
     Delete "$INSTDIR\plugins\xmppdisco.dll"
-    Delete "$INSTDIR\plugins\perl\auto\Pidgin\Pidgin.dll"
-    RMDir "$INSTDIR\plugins\perl\auto\Pidgin"
-    Delete "$INSTDIR\plugins\perl\auto\Purple\autosplit.ix"
-    Delete "$INSTDIR\plugins\perl\auto\Purple\Purple.dll"
-    RMDir "$INSTDIR\plugins\perl\auto\Purple"
-    RMDir "$INSTDIR\plugins\perl\auto"
-    Delete "$INSTDIR\plugins\perl\Pidgin.pm"
-    Delete "$INSTDIR\plugins\perl\Purple.pm"
-    RMDir "$INSTDIR\plugins\perl"
     RMDir "$INSTDIR\plugins"
     Delete "$INSTDIR\sasl2\libanonymous-3.dll"
     Delete "$INSTDIR\sasl2\libcrammd5-3.dll"
--- a/po/POTFILES.skip	Sun May 28 13:26:27 2017 +0300
+++ b/po/POTFILES.skip	Mon Jun 05 16:36:29 2017 +0300
@@ -1,138 +1,6 @@
 libpurple/data/purple-url-handler.desktop.in.in
-libpurple/plugins/mono/loader/mono.c
-libpurple/plugins/perl/common/Account.c
-libpurple/plugins/perl/common/AccountOpts.c
-libpurple/plugins/perl/common/BuddyIcon.c
-libpurple/plugins/perl/common/BuddyList.c
-libpurple/plugins/perl/common/Certificate.c
-libpurple/plugins/perl/common/Cipher.c
-libpurple/plugins/perl/common/Cmds.c
-libpurple/plugins/perl/common/Connection.c
-libpurple/plugins/perl/common/Conversation.c
-libpurple/plugins/perl/common/Core.c
-libpurple/plugins/perl/common/Debug.c
-libpurple/plugins/perl/common/FT.c
-libpurple/plugins/perl/common/Idle.c
-libpurple/plugins/perl/common/Log.c
-libpurple/plugins/perl/common/Network.c
-libpurple/plugins/perl/common/Notify.c
-libpurple/plugins/perl/common/Plugin.c
-libpurple/plugins/perl/common/PluginPref.c
-libpurple/plugins/perl/common/Pounce.c
-libpurple/plugins/perl/common/Prefs.c
-libpurple/plugins/perl/common/Presence.c
-libpurple/plugins/perl/common/Privacy.c
-libpurple/plugins/perl/common/Proxy.c
-libpurple/plugins/perl/common/Prpl.c
-libpurple/plugins/perl/common/Purple.c
-libpurple/plugins/perl/common/Request.c
-libpurple/plugins/perl/common/Roomlist.c
-libpurple/plugins/perl/common/SSLConn.c
-libpurple/plugins/perl/common/SavedStatuses.c
-libpurple/plugins/perl/common/Server.c
-libpurple/plugins/perl/common/Signal.c
-libpurple/plugins/perl/common/Smiley.c
-libpurple/plugins/perl/common/Sound.c
-libpurple/plugins/perl/common/Status.c
-libpurple/plugins/perl/common/Stringref.c
-libpurple/plugins/perl/common/Util.c
-libpurple/plugins/perl/common/Whiteboard.c
-libpurple/plugins/perl/common/XMLNode.c
-libpurple/plugins/perl/common/Xfer.c
-libpurple/plugins/perl/perl.c
-libpurple/plugins/tcl/tcl.c
 libpurple/protocols/null/nullprpl.c
 pidgin/data/pidgin.desktop.in.in
-pidgin/plugins/crazychat/cc_pidgin_plugin.c
-pidgin/plugins/perl/common/GtkAccount.c
-pidgin/plugins/perl/common/GtkBlist.c
-pidgin/plugins/perl/common/GtkConn.c
-pidgin/plugins/perl/common/GtkConv.c
-pidgin/plugins/perl/common/GtkConvWin.c
-pidgin/plugins/perl/common/GtkDebug.c
-pidgin/plugins/perl/common/GtkDialogs.c
-pidgin/plugins/perl/common/GtkFt.c
-pidgin/plugins/perl/common/GtkIMHtml.c
-pidgin/plugins/perl/common/GtkIMHtmlToolbar.c
-pidgin/plugins/perl/common/GtkLog.c
-pidgin/plugins/perl/common/GtkMenuTray.c
-pidgin/plugins/perl/common/GtkPlugin.c
-pidgin/plugins/perl/common/GtkPluginPref.c
-pidgin/plugins/perl/common/GtkPounce.c
-pidgin/plugins/perl/common/GtkPrefs.c
-pidgin/plugins/perl/common/GtkPrivacy.c
-pidgin/plugins/perl/common/GtkRoomlist.c
-pidgin/plugins/perl/common/GtkSavedStatuses.c
-pidgin/plugins/perl/common/GtkSession.c
-pidgin/plugins/perl/common/GtkSound.c
-pidgin/plugins/perl/common/GtkStatusBox.c
-pidgin/plugins/perl/common/GtkThemes.c
-pidgin/plugins/perl/common/GtkUtils.c
-pidgin/plugins/perl/common/Pidgin.c
 sub/libpurple/data/purple-url-handler.desktop.in
-sub/libpurple/plugins/perl/common/Account.c
-sub/libpurple/plugins/perl/common/AccountOpts.c
-sub/libpurple/plugins/perl/common/BuddyIcon.c
-sub/libpurple/plugins/perl/common/BuddyList.c
-sub/libpurple/plugins/perl/common/Certificate.c
-sub/libpurple/plugins/perl/common/Cipher.c
-sub/libpurple/plugins/perl/common/Cmds.c
-sub/libpurple/plugins/perl/common/Connection.c
-sub/libpurple/plugins/perl/common/Conversation.c
-sub/libpurple/plugins/perl/common/Core.c
-sub/libpurple/plugins/perl/common/Debug.c
-sub/libpurple/plugins/perl/common/FT.c
-sub/libpurple/plugins/perl/common/Idle.c
-sub/libpurple/plugins/perl/common/ImgStore.c
-sub/libpurple/plugins/perl/common/Log.c
-sub/libpurple/plugins/perl/common/Network.c
-sub/libpurple/plugins/perl/common/Notify.c
-sub/libpurple/plugins/perl/common/Plugin.c
-sub/libpurple/plugins/perl/common/PluginPref.c
-sub/libpurple/plugins/perl/common/Pounce.c
-sub/libpurple/plugins/perl/common/Prefs.c
-sub/libpurple/plugins/perl/common/Privacy.c
-sub/libpurple/plugins/perl/common/Proxy.c
-sub/libpurple/plugins/perl/common/Prpl.c
-sub/libpurple/plugins/perl/common/Purple.c
-sub/libpurple/plugins/perl/common/Request.c
-sub/libpurple/plugins/perl/common/Roomlist.c
-sub/libpurple/plugins/perl/common/SSLConn.c
-sub/libpurple/plugins/perl/common/SavedStatuses.c
-sub/libpurple/plugins/perl/common/Server.c
-sub/libpurple/plugins/perl/common/Signal.c
-sub/libpurple/plugins/perl/common/Smiley.c
-sub/libpurple/plugins/perl/common/Sound.c
-sub/libpurple/plugins/perl/common/Status.c
-sub/libpurple/plugins/perl/common/Stringref.c
-sub/libpurple/plugins/perl/common/Util.c
-sub/libpurple/plugins/perl/common/Whiteboard.c
-sub/libpurple/plugins/perl/common/XMLNode.c
 sub/libpurple/protocols/null/nullprpl.c
 sub/pidgin/data/pidgin.desktop.in
-sub/pidgin/plugins/crazychat/cc_pidgin_plugin.c
-sub/pidgin/plugins/perl/common/GtkAccount.c
-sub/pidgin/plugins/perl/common/GtkBlist.c
-sub/pidgin/plugins/perl/common/GtkConn.c
-sub/pidgin/plugins/perl/common/GtkConv.c
-sub/pidgin/plugins/perl/common/GtkConvWin.c
-sub/pidgin/plugins/perl/common/GtkDebug.c
-sub/pidgin/plugins/perl/common/GtkDialogs.c
-sub/pidgin/plugins/perl/common/GtkFt.c
-sub/pidgin/plugins/perl/common/GtkIMHtml.c
-sub/pidgin/plugins/perl/common/GtkIMHtmlToolbar.c
-sub/pidgin/plugins/perl/common/GtkLog.c
-sub/pidgin/plugins/perl/common/GtkMenuTray.c
-sub/pidgin/plugins/perl/common/GtkPlugin.c
-sub/pidgin/plugins/perl/common/GtkPluginPref.c
-sub/pidgin/plugins/perl/common/GtkPounce.c
-sub/pidgin/plugins/perl/common/GtkPrefs.c
-sub/pidgin/plugins/perl/common/GtkPrivacy.c
-sub/pidgin/plugins/perl/common/GtkRoomlist.c
-sub/pidgin/plugins/perl/common/GtkSavedStatuses.c
-sub/pidgin/plugins/perl/common/GtkSession.c
-sub/pidgin/plugins/perl/common/GtkSound.c
-sub/pidgin/plugins/perl/common/GtkStatusBox.c
-sub/pidgin/plugins/perl/common/GtkThemes.c
-sub/pidgin/plugins/perl/common/GtkUtils.c
-sub/pidgin/plugins/perl/common/Pidgin.c

mercurial