changeset 27394:16ef6a9e7acd

Start of splitting yahoo into two separate prpls. Not sure if this even comes close to building yet.
author John Bailey <rekkanoryo@rekkanoryo.org>
date Sun, 05 Jul 2009 04:37:33 +0000
parents 319b0f3dd2d0
children ef5f0cde8d74
files libpurple/protocols/yahoo/Makefile.am libpurple/protocols/yahoo/libymsg.c libpurple/protocols/yahoo/libymsg.h libpurple/protocols/yahoo/yahoo.c libpurple/protocols/yahoo/yahoo.h
diffstat 5 files changed, 5581 insertions(+), 5572 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/yahoo/Makefile.am	Sun Jul 05 02:26:03 2009 +0000
+++ b/libpurple/protocols/yahoo/Makefile.am	Sun Jul 05 04:37:33 2009 +0000
@@ -4,9 +4,9 @@
 pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION)
 
 YAHOOSOURCES = \
+	libymsg.c \
+	libymsg.h \
 	util.c \
-	yahoo.c \
-	yahoo.h \
 	yahoochat.h \
 	yahoochat.c \
 	yahoo_aliases.c \
@@ -28,20 +28,29 @@
 AM_CFLAGS = $(st)
 
 libyahoo_la_LDFLAGS = -module -avoid-version
+libyahoojp_la_LDFLAGS = -module -avoid-version
+libymsg_la_LDFLAGS = -module -avoid-version
 
 if STATIC_YAHOO
 
 st = -DPURPLE_STATIC_PRPL
 noinst_LTLIBRARIES  = libyahoo.la
-libyahoo_la_SOURCES = $(YAHOOSOURCES)
-libyahoo_la_CFLAGS  = $(AM_CFLAGS)
+libymsg_la_SOURCES = $(YAHOOSOURCES) libyahoo.c libyahoojp.c
+libymsg_la_CFLAGS  = $(AM_CFLAGS)
 
 else
 
 st =
-pkg_LTLIBRARIES     = libyahoo.la
-libyahoo_la_SOURCES = $(YAHOOSOURCES)
-libyahoo_la_LIBADD  = $(GLIB_LIBS)
+pkg_LTLIBRARIES     = libymsg.la libyahoo.la libyahoojp.la
+
+libymsg_la_SOURCES = $(YAHOOSOURCES)
+libymsg_la_LIBADD  = $(GLIB_LIBS)
+
+libyahoo_la_SOURCES = libyahoo.c
+libyahoo_la_LIBADD = libymsg.la
+
+libyahoojp_la_SOURCES = libyahoojp.c
+libyahoojp_la_LIBADD = libymsg.la
 
 endif
 
@@ -49,4 +58,4 @@
 	-I$(top_srcdir)/libpurple \
 	-I$(top_builddir)/libpurple \
 	$(GLIB_CFLAGS) \
-	$(DEBUG_CFLAGS)
\ No newline at end of file
+	$(DEBUG_CFLAGS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/yahoo/libymsg.c	Sun Jul 05 04:37:33 2009 +0000
@@ -0,0 +1,5254 @@
+/*
+ * 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 "accountopt.h"
+#include "blist.h"
+#include "cipher.h"
+#include "cmds.h"
+#include "core.h"
+#include "debug.h"
+#include "network.h"
+#include "notify.h"
+#include "privacy.h"
+#include "prpl.h"
+#include "proxy.h"
+#include "request.h"
+#include "server.h"
+#include "util.h"
+#include "version.h"
+#include "xmlnode.h"
+
+#include "yahoo.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 */
+
+/* #define TRY_WEBMESSENGER_LOGIN 0 */
+
+/* One hour */
+#define PING_TIMEOUT 3600
+
+/* One minute */
+#define KEEPALIVE_TIMEOUT 60
+
+static void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *, PurpleGroup *);
+#ifdef TRY_WEBMESSENGER_LOGIN
+static void yahoo_login_page_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message);
+#endif /* TRY_WEBMESSENGER_LOGIN */
+static void yahoo_set_status(PurpleAccount *account, PurpleStatus *status);
+
+static void yahoo_update_status(PurpleConnection *gc, const char *name, YahooFriend *f)
+{
+	char *status = NULL;
+
+	if (!gc || !name || !f || !purple_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_prpl_got_user_status(purple_connection_get_account(gc), name, status, "message",
+			                          yahoo_friend_get_status_message(f), NULL);
+		else
+			purple_prpl_got_user_status(purple_connection_get_account(gc), name, status, NULL);
+	}
+
+	if (f->idle != 0)
+		purple_prpl_got_user_idle(purple_connection_get_account(gc), name, TRUE, f->idle);
+	else
+		purple_prpl_got_user_idle(purple_connection_get_account(gc), name, FALSE, 0);
+
+	if (f->sms)
+		purple_prpl_got_user_status(purple_connection_get_account(gc), name, YAHOO_STATUS_TYPE_MOBILE, NULL);
+	else
+		purple_prpl_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;
+	char *msn_name = NULL;
+
+	if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
+		if (!purple_account_get_remember_password(account))
+			purple_account_set_password(account, NULL);
+		purple_connection_error_reason(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)) {
+				GSList *tmplist;
+				int protocol = 0;
+
+				name = pair->value;
+
+				/* Look ahead to see if we have the protocol info about the buddy */
+				for (tmplist = l->next; tmplist; tmplist = tmplist->next) {
+					struct yahoo_pair *p = tmplist->data;
+					if (p->key == 7)
+						break;
+					if (p->key == 241) {
+						if(strtol(p->value, NULL, 10) == 2) {
+							g_free(msn_name);
+							msn_name = g_strconcat("msn/", name, NULL);
+							name = msn_name;
+							protocol = 2;
+						}
+						break;
+					}
+				}
+				f = yahoo_friend_find_or_new(gc, name);
+				f->protocol = protocol;
+			}
+			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)
+					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)
+					f->idle = time(NULL);
+			}
+
+			break;
+		case 138: /* either we're not idle, or we are but won't say how long */
+			if (!f)
+				break;
+
+			if (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_prpl_got_user_status(account, name, "offline", NULL);
+					purple_prpl_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 (len) {
+					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_find_buddy(gc->account, name);
+
+			if (!cksum || (cksum == -1)) {
+				if (f)
+					yahoo_friend_set_buddy_icon_need_request(f, TRUE);
+				purple_buddy_icons_set_for_user(gc->account, 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);
+				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;
+		case 241: /* protocol buddy belongs to */
+			break;  /* We process this when get '7' */
+		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);
+	}
+	g_free(msn_name);
+}
+
+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 = 0;
+	char *oname = NULL;
+	char **oname_p = &oname;
+	GSList **list_p = &list;
+
+	if (!g_hash_table_lookup_extended(ht, purple_normalize(account, name), (gpointer *) oname_p, (gpointer *) list_p))
+		list = purple_find_buddies(account, name);
+	else
+		g_hash_table_steal(ht, 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 = 1;
+			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_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(purple_normalize(account, name));
+		g_hash_table_insert(ht, oname, list);
+	} else if (oname)
+		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(struct yahoo_data *yd, char *c)
+{
+	if (c[0] == 'Y') {
+		if (yd->cookie_y)
+			g_free(yd->cookie_y);
+		yd->cookie_y = _getcookie(c);
+	} else if (c[0] == 'T') {
+		if (yd->cookie_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);
+	struct yahoo_data *yd = gc->proto_data;
+	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? */
+	PurpleBuddy *b;
+	PurpleGroup *g;
+	int protocol = 0;
+	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) {
+				if(protocol == 2)
+					norm_bud = g_strconcat("msn/", temp, NULL);
+				else
+					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 (!(b = purple_find_buddy(account, norm_bud))) {
+						if (!(g = purple_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(protocol != 0) {
+						f->protocol = protocol;
+						purple_debug_info("yahoo", "Setting protocol to %d\n", f->protocol);
+					}
+					if(stealth == 2)
+						f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
+
+					/* set p2p status not connected and no p2p packet sent */
+					if(protocol == 0) {
+						yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
+						f->p2p_packet_sent = 0;
+					} else
+						yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT);
+				} 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",account->username, norm_bud);
+					purple_privacy_deny_add(account, norm_bud, 1);
+				}
+
+				protocol = 0;
+				stealth = 0;
+				norm_bud = NULL;
+				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 */
+			temp = g_strdup(purple_normalize(account, pair->value));
+			break;
+		case 241: /* another protocol user */
+			protocol = strtol(pair->value, NULL, 10);
+			break;
+		case 59: /* somebody told cookies come here too, but im not sure */
+			yahoo_process_cookie(yd, pair->value);
+			break;
+		case 317: /* Stealth Setting */
+			stealth = strtol(pair->value, NULL, 10);
+			break;
+		/* case 242: */ /* this seems related to 241 */
+			/* break; */
+		}
+	}
+
+	g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL);
+
+	/* 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)));
+	purple_connection_set_state(gc, PURPLE_CONNECTED);
+	yd->logged_in = TRUE;
+	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));
+	purple_debug_info("yahoo","Authentication: Connection established\n");
+
+	g_hash_table_destroy(ht);
+	g_free(norm_bud);
+	g_free(temp);
+}
+
+static void yahoo_process_list(PurpleConnection *gc, struct yahoo_packet *pkt)
+{
+	GSList *l = pkt->hash;
+	gboolean export = FALSE;
+	gboolean got_serv_list = FALSE;
+	PurpleBuddy *b;
+	PurpleGroup *g;
+	YahooFriend *f = NULL;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	struct yahoo_data *yd = gc->proto_data;
+	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 (!yd->tmp_serv_ilist)
+				yd->tmp_serv_ilist = g_string_new(pair->value);
+			else
+				g_string_append(yd->tmp_serv_ilist, pair->value);
+			break;
+		case 89:
+			yd->profiles = g_strsplit(pair->value, ",", -1);
+			break;
+		case 59: /* cookies, yum */
+			yahoo_process_cookie(yd, pair->value);
+			break;
+		case YAHOO_SERVICE_PRESENCE_PERM:
+			if (!yd->tmp_serv_plist)
+				yd->tmp_serv_plist = g_string_new(pair->value);
+			else
+				g_string_append(yd->tmp_serv_plist, pair->value);
+			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++) {
+				norm_bud = g_strdup(purple_normalize(account, *bud));
+				f = yahoo_friend_find_or_new(gc, norm_bud);
+
+				if (!(b = purple_find_buddy(account, norm_bud))) {
+					if (!(g = purple_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);
+					export = TRUE;
+				}
+
+				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_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 &&
+		((account->perm_deny != PURPLE_PRIVACY_ALLOW_BUDDYLIST) &&
+		(account->perm_deny != PURPLE_PRIVACY_DENY_ALL) &&
+		(account->perm_deny != PURPLE_PRIVACY_ALLOW_USERS)))
+	{
+		account->perm_deny = PURPLE_PRIVACY_DENY_USERS;
+		purple_debug_info("yahoo", "%s privacy defaulting to PURPLE_PRIVACY_DENY_USERS.\n",
+				account->username);
+	}
+
+	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",
+						account->username, *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;
+	struct yahoo_data *yd = gc->proto_data;
+	gboolean msn = FALSE;
+
+	account = purple_connection_get_account(gc);
+
+	while (l) {
+		struct yahoo_pair *pair = l->data;
+		if (pair->key == 4 || pair->key == 1)
+			from = pair->value;
+		if (pair->key == 49)
+			msg = pair->value;
+		if (pair->key == 13)
+			stat = pair->value;
+		if (pair->key == 14)
+			game = pair->value;
+		if (pair->key == 11)
+			val_11 = strtol(pair->value, NULL, 10);
+		if (pair->key == 241)
+			if(strtol(pair->value, NULL, 10) == 2)
+				msn = TRUE;
+		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_privacy_check(account, from)))
+	{
+		if(msn) {
+			char *msn_from = g_strconcat("msn/", from, NULL);
+			if (*stat == '1')
+				serv_got_typing(gc, msn_from, 0, PURPLE_TYPING);
+			else
+				serv_got_typing_stopped(gc, msn_from);
+			g_free(msn_from);
+		}
+		else	{
+			if (*stat == '1')
+				serv_got_typing(gc, from, 0, PURPLE_TYPING);
+			else
+				serv_got_typing_stopped(gc, from);
+		}
+	} else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) {
+		PurpleBuddy *bud = purple_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 == '1') {
+			yahoo_friend_set_game(f, game);
+			if (bud)
+				yahoo_update_status(gc, from, f);
+		}
+	} else if (!g_ascii_strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) {
+		PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, account);
+		char *buf = g_strdup_printf(_("%s has sent you a webcam invite, which is not yet supported."), from);
+		purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NOTIFY, time(NULL));
+		g_free(buf);
+	}
+}
+
+
+struct _yahoo_im {
+	char *from;
+	char *active_id;
+	int time;
+	int utf8;
+	int buddy_icon;
+	char *id;
+	char *msg;
+	gboolean msn;
+};
+
+static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt)
+{
+	PurpleAccount *account;
+	GSList *l = pkt->hash;
+	struct _yahoo_im *sms = NULL;
+	struct yahoo_data *yd;
+	char *server_msg = NULL;
+	char *m;
+
+	yd = gc->proto_data;
+	account = purple_connection_get_account(gc);
+
+	while (l != NULL) {
+		struct yahoo_pair *pair = l->data;
+		if (pair->key == 4) {
+			sms = g_new0(struct _yahoo_im, 1);
+			sms->from = g_strdup_printf("+%s", pair->value);
+			sms->time = time(NULL);
+			sms->utf8 = TRUE;
+		}
+		if (pair->key == 14) {
+			if (sms)
+				sms->msg = pair->value;
+		}
+		if (pair->key == 68)
+			if(sms)
+				g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value));
+		if (pair->key == 16)
+			server_msg = pair->value;
+		l = l->next;
+	}
+
+	if( (pkt->status == -1) || (pkt->status == YAHOO_STATUS_DISCONNECTED) ) {
+		if (server_msg) {
+			PurpleConversation *c;
+			c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms->from, account);
+			if (c == NULL)
+				c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sms->from);
+			purple_conversation_write(c, NULL, server_msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
+		}
+		else
+			purple_notify_error(gc, NULL, _("Your SMS was not delivered"), NULL);
+
+		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);
+	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;
+	struct yahoo_data *yd = gc->proto_data;
+	GSList *l = pkt->hash;
+	GSList *list = NULL;
+	struct _yahoo_im *im = NULL;
+	const char *imv = NULL;
+	gint val_11 = 0;
+
+	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) {
+				im = g_new0(struct _yahoo_im, 1);
+				list = g_slist_append(list, im);
+				im->from = pair->value;
+				im->time = time(NULL);
+				im->utf8 = TRUE;
+			}
+			if (im && pair->key == 5)
+				im->active_id = pair->value;
+			if (pair->key == 97)
+				if (im)
+					im->utf8 = strtol(pair->value, NULL, 10);
+			if (pair->key == 15)
+				if (im)
+					im->time = strtol(pair->value, NULL, 10);
+			if (pair->key == 206)
+				if (im)
+					im->buddy_icon = strtol(pair->value, NULL, 10);
+			if (pair->key == 14) {
+				if (im)
+					im->msg = pair->value;
+			}
+			if (im && pair->key == 241) {
+				if(strtol(pair->value, NULL, 10) == 2)
+					im->msn = TRUE;
+			}
+			/* peer session id */
+			if (pair->key == 11) {
+				if (im)
+					val_11 = strtol(pair->value, NULL, 10);
+			}
+			/* IMV key */
+			if (pair->key == 63)
+			{
+				imv = pair->value;
+			}
+			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);
+	}
+
+	/* 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 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);
+		return;
+	}
+
+	/** TODO: It seems that this check should be per IM, not global */
+	/* Check for the Doodle IMV */
+	if (im != NULL && imv!= NULL && im->from != NULL)
+	{
+		g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(imv));
+
+		if (strstr(imv, "doodle;") != NULL)
+		{
+			PurpleWhiteboard *wb;
+
+			if (!purple_privacy_check(account, im->from)) {
+				purple_debug_info("yahoo", "Doodle request from %s dropped.\n", im->from);
+				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_create(account, im->from, DOODLE_STATE_REQUESTED);
+				ds = wb->proto_data;
+				ds->imv_key = g_strdup(imv);
+
+				yahoo_doodle_command_send_request(gc, im->from, imv);
+				yahoo_doodle_command_send_ready(gc, im->from, imv);
+			}
+		}
+	}
+
+	for (l = list; l; l = l->next) {
+		YahooFriend *f;
+		char *m, *m2;
+		char *msn_from = NULL;
+		const char *from;
+		PurpleConversation *c;
+		im = l->data;
+
+		if (!im->from || !im->msg) {
+			g_free(im);
+			continue;
+		}
+
+		if (!purple_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 (im->msn) {
+			msn_from = g_strconcat("msn/", im->from, NULL);
+			from = msn_from;
+		} else {
+			from = im->from;
+		}
+
+		c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, account);
+
+		if (!strcmp(m, "<ding>")) {
+			char *username;
+
+			if (c == NULL) {
+				c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, from);
+			}
+			username = g_markup_escape_text(from, -1);
+			purple_prpl_got_attention(gc, username, YAHOO_BUZZ);
+			g_free(username);
+			g_free(m);
+			g_free(im);
+			g_free(msn_from);
+			continue;
+		}
+
+		m2 = yahoo_codes_to_html(m);
+		g_free(m);
+
+		serv_got_im(gc, from, m2, 0, im->time);
+		g_free(m2);
+
+		/* laters : implement buddy icon for msn friends */
+		if (!im->msn) {
+			if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) {
+				if (yahoo_friend_get_buddy_icon_need_request(f)) {
+					yahoo_send_picture_request(gc, im->from);
+					yahoo_friend_set_buddy_icon_need_request(f, FALSE);
+				}
+			}
+		}
+
+		g_free(im);
+		g_free(msn_from);
+	}
+	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)
+			me = pair->value;
+		if (pair->key == 14)
+			msg = pair->value;
+
+		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);
+	g_free(prim);
+}
+
+struct yahoo_add_request {
+	PurpleConnection *gc;
+	char *id;
+	char *who;
+	int protocol;
+};
+
+static void
+yahoo_buddy_add_authorize_cb(gpointer data)
+{
+	struct yahoo_add_request *add_req = data;
+	struct yahoo_packet *pkt;
+	struct yahoo_data *yd = add_req->gc->proto_data;
+	const char *who = add_req->who;
+
+	if (add_req->protocol == 2)
+		who += 4;
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, YAHOO_STATUS_AVAILABLE, 0);
+	yahoo_packet_hash(pkt, "ssiii",
+					  1, add_req->id,
+					  5, who,
+					  241, add_req->protocol,
+					  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(struct yahoo_add_request *add_req, const char *msg)
+{
+	struct yahoo_data *yd = add_req->gc->proto_data;
+	struct yahoo_packet *pkt;
+	char *encoded_msg = NULL;
+	PurpleAccount *account = purple_connection_get_account(add_req->gc);
+
+	if (msg && *msg)
+		encoded_msg = yahoo_string_encode(add_req->gc, msg, NULL);
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15,
+			YAHOO_STATUS_AVAILABLE, 0);
+
+	yahoo_packet_hash(pkt, "ssiiis",
+			1, purple_normalize(account, purple_account_get_username(account)),
+			5, add_req->who,
+			13, 2,
+			334, 0,
+			97, 1,
+			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_add_deny_noreason_cb(struct yahoo_add_request *add_req, const char*msg)
+{
+	yahoo_buddy_add_deny_cb(add_req, NULL);
+}
+
+static void
+yahoo_buddy_add_deny_reason_cb(gpointer data) {
+	struct yahoo_add_request *add_req = data;
+	purple_request_input(add_req->gc, NULL, _("Authorization denied message:"),
+			NULL, _("No reason given."), TRUE, FALSE, NULL,
+			_("OK"), G_CALLBACK(yahoo_buddy_add_deny_cb),
+			_("Cancel"), G_CALLBACK(yahoo_buddy_add_deny_noreason_cb),
+			purple_connection_get_account(add_req->gc), add_req->who, NULL,
+			add_req);
+}
+
+static void yahoo_buddy_denied_our_add(PurpleConnection *gc, const char *who, const char *reason)
+{
+	char *notify_msg;
+	struct yahoo_data *yd = gc->proto_data;
+
+	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);
+	g_free(notify_msg);
+
+	g_hash_table_remove(yd->friends, who);
+	purple_prpl_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;
+	int protocol = 0;
+
+	account = purple_connection_get_account(gc);
+
+	/* Buddy authorized/declined our addition */
+	if (pkt->status == 1) {
+		char *temp = NULL;
+		char *who = NULL;
+		int response = 0;
+
+		while (l) {
+			struct yahoo_pair *pair = l->data;
+
+			switch (pair->key) {
+			case 4:
+				temp = pair->value;
+				break;
+			case 13:
+				response = strtol(pair->value, NULL, 10);
+				break;
+			case 14:
+				msg = pair->value;
+				break;
+			case 241:
+				protocol = strtol(pair->value, NULL, 10);
+				break;
+			}
+			l = l->next;
+		}
+
+		if(protocol == 0)
+			who = g_strdup(temp);
+		else if(protocol == 2)
+			who = g_strconcat("msn/", temp, NULL);
+
+		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;
+		char *temp = 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:
+				temp = pair->value;
+				add_req->who = g_strdup(pair->value);
+				break;
+			case 5:
+				add_req->id = g_strdup(pair->value);
+				break;
+			case 14:
+				msg = pair->value;
+				break;
+			case 216:
+				firstname = pair->value;
+				break;
+			case 241:
+				add_req->protocol = strtol(pair->value, NULL, 10);
+				break;
+			case 254:
+				lastname = pair->value;
+				break;
+
+			}
+			l = l->next;
+		}
+		if(add_req->protocol == 2)
+			add_req->who = g_strconcat("msn/", temp, NULL);
+		else
+			add_req->who = g_strdup(temp);
+
+		if (add_req->id && add_req->who) {
+			char *alias = NULL, *dec_msg = NULL;
+
+			if (!purple_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(add_req, NULL);
+				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_find_buddy(account, add_req->who) != NULL,
+					yahoo_buddy_add_authorize_cb,
+					yahoo_buddy_add_deny_reason_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:
+			add_req->id = g_strdup(pair->value);
+			break;
+		case 3:
+			add_req->who = g_strdup(pair->value);
+			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_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(add_req, NULL);
+			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_find_buddy(account,add_req->who) != NULL,
+						yahoo_buddy_add_authorize_cb,
+						yahoo_buddy_add_deny_reason_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:
+			who = pair->value;
+			break;
+		case 14:
+			msg = pair->value;
+			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';
+
+	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);
+	struct yahoo_data *yd = gc->proto_data;
+	const char *who = NULL;
+	const char *email = NULL;
+	const char *subj = NULL;
+	const char *yahoo_mail_url = (yd->jp? YAHOOJP_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)
+			who = pair->value;
+		else if (pair->key == 42)
+			email = pair->value;
+		else if (pair->key == 18)
+			subj = pair->value;
+		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)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	const char *name = purple_normalize(account, purple_account_get_username(account));
+	PurpleCipher *md5_cipher;
+	PurpleCipherContext *md5_ctx;
+	guchar md5_digest[16];
+	gchar base64_string[25];
+	struct yahoo_packet *pkt;
+
+	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage3\n");
+
+	md5_cipher = purple_ciphers_find_cipher("md5");
+	md5_ctx = purple_cipher_context_new(md5_cipher, NULL);
+	purple_cipher_context_append(md5_ctx, (guchar *)crypt, strlen(crypt));
+	purple_cipher_context_digest(md5_ctx, sizeof(md5_digest), md5_digest, NULL);
+
+	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->jp) {
+		yahoo_packet_hash(pkt, "ssssssss",
+					1, name,
+					0, name,
+					277, yd->cookie_y,
+					278, yd->cookie_t,
+					307, base64_string,
+					2, name,
+					2, "1",
+					135, YAHOOJP_CLIENT_VERSION);
+	} else	{
+		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",
+					135, YAHOO_CLIENT_VERSION);
+	}
+	if (yd->picture_checksum)
+		yahoo_packet_hash_int(pkt, 192, yd->picture_checksum);
+	yahoo_packet_send_and_free(pkt, yd);
+
+	purple_cipher_context_destroy(md5_ctx);
+}
+
+static void yahoo_auth16_stage2(PurpleUtilFetchUrlData *unused, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message)
+{
+	struct yahoo_auth_data *auth_data = user_data;
+	PurpleConnection *gc = auth_data->gc;
+	struct yahoo_data *yd;
+	gboolean try_login_on_error = FALSE;
+
+	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage2\n");
+
+	if (!PURPLE_CONNECTION_IS_VALID(gc)) {
+		g_free(auth_data->seed);
+		g_free(auth_data);
+		g_return_if_reached();
+	}
+
+	yd = (struct yahoo_data *)gc->proto_data;
+
+	if (error_message != NULL) {
+		purple_debug_error("yahoo", "Login Failed, unable to retrieve stage 2 url: %s\n", error_message);
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
+		g_free(auth_data->seed);
+		g_free(auth_data);
+		return;
+	}
+	else if (len > 0 && ret_data && *ret_data) {
+		gchar **split_data = g_strsplit(ret_data, "\r\n", -1);
+		int totalelements = 0;
+		int response_no = -1;
+		char *crumb = NULL;
+		char *crypt = NULL;
+
+#if GLIB_CHECK_VERSION(2,6,0)
+		totalelements = g_strv_length(split_data);
+#else
+		while (split_data[++totalelements] != NULL);
+#endif
+		if (totalelements >= 4) {
+			response_no = strtol(split_data[0], NULL, 10);
+			crumb = g_strdup(split_data[1] + strlen("crumb="));
+			yd->cookie_y = g_strdup(split_data[2] + strlen("Y="));
+			yd->cookie_t = g_strdup(split_data[3] + strlen("T="));
+		}
+
+		g_strfreev(split_data);
+
+		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)) {
+						try_login_on_error = TRUE;
+						break;
+					}
+					error_reason = g_strdup(_("Unknown error"));
+					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+					break;
+			}
+			if(error_reason) {
+				purple_debug_error("yahoo", "Authentication error: %s\n",
+				                   error_reason);
+				purple_connection_error_reason(gc, error, error_reason);
+				g_free(error_reason);
+				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(PurpleUtilFetchUrlData *unused, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message)
+{
+	struct yahoo_auth_data *auth_data = user_data;
+	PurpleConnection *gc = auth_data->gc;
+
+	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage1_cb\n");
+
+	if (!PURPLE_CONNECTION_IS_VALID(gc)) {
+		g_free(auth_data->seed);
+		g_free(auth_data);
+		g_return_if_reached();
+	}
+
+	if (error_message != NULL) {
+		purple_debug_error("yahoo", "Login Failed, unable to retrieve login url: %s\n", error_message);
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
+		g_free(auth_data->seed);
+		g_free(auth_data);
+		return;
+	}
+	else if (len > 0 && ret_data && *ret_data) {
+		gchar **split_data = g_strsplit(ret_data, "\r\n", -1);
+		int totalelements = 0;
+		int response_no = -1;
+		char *token = NULL;
+
+#if GLIB_CHECK_VERSION(2,6,0)
+		totalelements = g_strv_length(split_data);
+#else
+		while (split_data[++totalelements] != NULL);
+#endif
+		if(totalelements == 1)
+			response_no = strtol(split_data[0], NULL, 10);
+		else if(totalelements >= 2) {
+			response_no = strtol(split_data[0], NULL, 10);
+			token = g_strdup(split_data[1] + strlen("ymsgr="));
+		}
+
+		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(purple_connection_get_account(gc)))
+						purple_account_set_password(purple_connection_get_account(gc), 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.\nLogging 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:
+				case 1236:
+					/* indicates a lock of some description */
+					error_reason = g_strdup(_("Account locked: Unknown reason.\nLogging into the Yahoo! website may fix this."));
+					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(_("Unknown error"));
+					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+					break;
+			}
+			purple_debug_error("yahoo", "Authentication error: %s\n",
+			                   error_reason);
+			purple_connection_error_reason(gc, error, error_reason);
+			g_free(error_reason);
+			g_free(auth_data->seed);
+			g_free(auth_data);
+		}
+		else {
+			/* OK to login, correct information provided */
+			PurpleUtilFetchUrlData *url_data = NULL;
+			char *url = NULL;
+			gboolean yahoojp = purple_account_get_bool(purple_connection_get_account(gc),
+				"yahoojp", 0);
+
+			url = g_strdup_printf(yahoojp ? YAHOOJP_LOGIN_URL : YAHOO_LOGIN_URL, token);
+			url_data = purple_util_fetch_url_request_len_with_account(
+					purple_connection_get_account(gc), url, TRUE,
+					YAHOO_CLIENT_USERAGENT, TRUE, NULL, FALSE, -1,
+					yahoo_auth16_stage2, auth_data);
+			g_free(url);
+			g_free(token);
+		}
+	}
+}
+
+static void yahoo_auth16_stage1(PurpleConnection *gc, const char *seed)
+{
+	PurpleUtilFetchUrlData *url_data = NULL;
+	struct yahoo_auth_data *auth_data = NULL;
+	char *url = NULL;
+	char *encoded_username;
+	char *encoded_password;
+	gboolean yahoojp;
+
+	purple_debug_info("yahoo", "Authentication: In yahoo_auth16_stage1\n");
+
+	if(!purple_ssl_is_supported()) {
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, _("SSL support unavailable"));
+		return;
+	}
+
+	yahoojp =  purple_account_get_bool(purple_connection_get_account(gc),
+			"yahoojp", 0);
+	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)));
+	url = g_strdup_printf(yahoojp ? YAHOOJP_TOKEN_URL : YAHOO_TOKEN_URL,
+			encoded_username, encoded_password, purple_url_encode(seed));
+	g_free(encoded_password);
+	g_free(encoded_username);
+
+	url_data = purple_util_fetch_url_request_len_with_account(
+			purple_connection_get_account(gc), url, TRUE,
+			YAHOO_CLIENT_USERAGENT, TRUE, NULL, FALSE, -1,
+			yahoo_auth16_stage1_cb, auth_data);
+
+	g_free(url);
+}
+
+static void yahoo_process_auth(PurpleConnection *gc, struct yahoo_packet *pkt)
+{
+	char *seed = NULL;
+	char *sn   = NULL;
+	GSList *l = pkt->hash;
+	int m = 0;
+	gchar *buf;
+
+	while (l) {
+		struct yahoo_pair *pair = l->data;
+		if (pair->key == 94)
+			seed = pair->value;
+		if (pair->key == 1)
+			sn = pair->value;
+		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);
+				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);
+
+	serv_add_deny(purple_account_get_connection(account), name);
+
+	g_free(name);
+}
+
+static void keep_buddy(PurpleBuddy *b)
+{
+	purple_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 *me = 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:
+			who = pair->value;
+			break;
+		case 1:
+			me = pair->value;
+			break;
+		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_find_buddy(gc->account, 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,
+									  gc->account, who, NULL,
+									  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.",
+							  who);
+			break;
+		case 3:
+			purple_debug_info("yahoo", "Server reported that %s is not in the ignore list; could not delete",
+							  who);
+		case 0:
+		default:
+			break;
+	}
+}
+
+static void yahoo_process_authresp(PurpleConnection *gc, struct yahoo_packet *pkt)
+{
+#ifdef TRY_WEBMESSENGER_LOGIN
+	struct yahoo_data *yd = gc->proto_data;
+#endif /* TRY_WEBMESSENGER_LOGIN */
+	GSList *l = pkt->hash;
+	int err = 0;
+	char *msg;
+	char *url = NULL;
+	char *fullmsg;
+	PurpleAccount *account = gc->account;
+	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)
+			url = pair->value;
+
+		l = l->next;
+	}
+
+	switch (err) {
+	case 0:
+		msg = g_strdup(_("Unknown error."));
+		reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
+		break;
+	case 3:
+		msg = g_strdup(_("Invalid username."));
+		reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
+		break;
+	case 13:
+#ifdef TRY_WEBMESSENGER_LOGIN
+		if (!yd->wm) {
+			PurpleUtilFetchUrlData *url_data;
+			yd->wm = TRUE;
+			if (yd->fd >= 0)
+				close(yd->fd);
+			if (gc->inpa)
+				purple_input_remove(gc->inpa);
+			url_data = purple_util_fetch_url(WEBMESSENGER_URL, TRUE,
+					"Purple/" VERSION, FALSE, yahoo_login_page_cb, gc);
+			if (url_data != NULL)
+				yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
+			return;
+		}
+#endif /* TRY_WEBMESSENGER_LOGIN */
+		if (!purple_account_get_remember_password(account))
+			purple_account_set_password(account, NULL);
+
+		msg = g_strdup(_("Incorrect password."));
+		reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+		break;
+	case 14:
+		msg = g_strdup(_("Your account is locked, please log in to the Yahoo! website."));
+		reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+		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_reason(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;
+	struct yahoo_data *yd = gc->proto_data;
+	int protocol = 0;
+	gboolean msn = FALSE;
+
+	while (l) {
+		struct yahoo_pair *pair = l->data;
+
+		switch (pair->key) {
+		case 66:
+			err = strtol(pair->value, NULL, 10);
+			break;
+		case 7:
+			temp = pair->value;
+			break;
+		case 65:
+			group = pair->value;
+			break;
+		case 241:
+			protocol = strtol(pair->value, NULL, 10);
+			if(protocol == 2)
+				msn = TRUE;
+			break;
+		}
+
+		l = l->next;
+	}
+
+	if (!temp)
+		return;
+	if (!group)
+		group = "";
+
+	if(msn)
+		who = g_strconcat("msn/", temp, NULL);
+	else
+		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(protocol)
+			f->protocol = protocol;
+
+		if( !g_hash_table_lookup(yd->peers, who) ) {
+			/* we are not connected as client, so set friend to not connected */
+			if(msn)
+				yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT);
+			else	{
+				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(_("Could not add buddy %s to group %s to the server list on account %s."),
+				who, decoded_group, purple_connection_get_display_name(gc));
+	if (!purple_conv_present_error(who, purple_connection_get_account(gc), buf))
+		purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf);
+	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;
+	guchar *raw_packet;
+
+	/*build the raw packet and send it to the host*/
+	pkt_len = yahoo_packet_build(pkt, 0, 0, 0, &raw_packet);
+	if(write(source, raw_packet, pkt_len) != 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;
+	struct yahoo_data *yd = gc->proto_data;
+
+	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;
+	struct yahoo_data *yd = gc->proto_data;
+
+	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);
+	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;
+	struct yahoo_data *yd;
+	YahooFriend *f;
+
+	if(!(p2p_data = data))
+		return ;
+
+	yd = p2p_data->gc->proto_data;
+
+	/* lets see whats in the packet */
+	while (l) {
+		struct yahoo_pair *pair = l->data;
+
+		switch (pair->key) {
+		case 4:
+			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;
+			}
+			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 = NULL;
+	struct yahoo_p2p_data *p2p_data;
+	struct yahoo_data *yd;
+
+	if(!(p2p_data = data))
+		return ;
+	yd = p2p_data->gc->proto_data;
+
+	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;
+	}
+
+	if(len < YAHOO_PACKET_HDRLEN)
+		return;
+
+	if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) {
+		/* Not a YMSG packet */
+		purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
+
+		start = memchr(buf + 1, 'Y', len - 1);
+		if (start == NULL)
+			return;
+
+		g_memmove(buf, start, len - (start - buf));
+		len -= start - buf;
+	}
+
+	pos += 4;	/* YMSG */
+	pos += 2;
+	pos += 2;
+
+	pktlen = yahoo_get16(buf + pos); pos += 2;
+	purple_debug_misc("yahoo", "p2p: %d bytes to read\n", len);
+
+	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;
+	struct yahoo_data *yd;
+
+	if(!(p2p_data = data))
+		return ;
+	yd = p2p_data->gc->proto_data;
+
+	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;
+	struct yahoo_data *yd;
+
+	if(!(p2p_data = data))
+		return FALSE;
+
+	yd = p2p_data->gc->proto_data;
+
+	purple_debug_warning("yahoo","yahoo p2p server timeout, peer failed to connect");
+	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;
+	struct yahoo_data *yd;
+
+	if(!(p2p_data = data))
+		return ;
+
+	if(listenfd == -1) {
+		purple_debug_warning("yahoo","p2p: error starting p2p server\n");
+		yahoo_p2p_disconnect_destroy_data(data);
+		return;
+	}
+
+	yd = p2p_data->gc->proto_data;
+
+	/* 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;
+	struct yahoo_data *yd = gc->proto_data;
+	struct yahoo_p2p_data *p2p_data;
+
+	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;
+
+	/* Dont send p2p packet to buddies of other protocols */
+	if(f->protocol)
+		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) );
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_PEERTOPEER, YAHOO_STATUS_AVAILABLE, 0);
+	yahoo_packet_hash(pkt, "sssissis",
+		1, purple_normalize(account, purple_account_get_username(account)),
+		4, purple_normalize(account, purple_account_get_username(account)),
+		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;
+
+	purple_network_listen(YAHOO_PAGER_PORT_P2P, SOCK_STREAM, yahoo_p2p_server_listen_cb, p2p_data);
+
+	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;
+	struct yahoo_data *yd;
+
+	if(!(p2p_data = data))
+		return ;
+	yd = p2p_data->gc->proto_data;
+
+	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 1 ie YAHOO_STATUS_BRB, the packet bounced back, so contains our own ip */
+	if(!(pkt->status == YAHOO_STATUS_BRB))
+		return ;
+
+	while (l) {
+		struct yahoo_pair *pair = l->data;
+
+		switch (pair->key) {
+		case 5:
+			/* our identity */
+			break;
+		case 4:
+			who = pair->value;
+			break;
+		case 1:
+			/* who again, the master identity this time? */
+			break;
+		case 12:
+			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?*/
+			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;
+		struct yahoo_p2p_data *p2p_data;
+
+		decoded = purple_base64_decode(base64, &len);
+		if (len) {
+			char *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:
+			who = pair->value;
+			break;
+		case 5:
+			/* us */
+			break;
+		case 230:
+			/* the audible, in foo.locale.bar.baz format
+			   eg: base.tw.smiley.smiley43 */
+			id = pair->value;
+			break;
+		case 231:
+			/* the text of the audible */
+			msg = pair->value;
+			break;
+		case 232:
+			/* weird number (md5 hash?), like 8ebab9094156135f5dcbaccbeee662a5c5fd1420 */
+			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_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://us.dl1.yimg.com/download.yahoo.com/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);
+
+		serv_got_im(gc, who, buf, 0, time(NULL));
+		g_free(buf);
+	} else
+		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:
+		yahoo_process_filetransfer(gc, pkt);
+		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_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;
+	struct yahoo_data *yd = gc->proto_data;
+	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:\n%s"),
+				g_strerror(errno));
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+		g_free(tmp);
+		return;
+	} else if (len == 0) {
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Server closed the connection."));
+		return;
+	}
+	gc->last_received = time(NULL);
+	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;
+	struct yahoo_data *yd;
+	struct yahoo_packet *pkt;
+
+	if (source < 0) {
+		gchar *tmp;
+		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
+				error_message);
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+		g_free(tmp);
+		return;
+	}
+
+	yd = gc->proto_data;
+	yd->fd = source;
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, yd->current_status, 0);
+
+	yahoo_packet_hash_str(pkt, 1, purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))));
+	yahoo_packet_send_and_free(pkt, yd);
+
+	gc->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc);
+}
+
+#ifdef TRY_WEBMESSENGER_LOGIN
+static void yahoo_got_web_connected(gpointer data, gint source, const gchar *error_message)
+{
+	PurpleConnection *gc = data;
+	struct yahoo_data *yd;
+	struct yahoo_packet *pkt;
+
+	if (source < 0) {
+		gchar *tmp;
+		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
+				error_message);
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+		g_free(tmp);
+		return;
+	}
+
+	yd = gc->proto_data;
+	yd->fd = source;
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_WEBLOGIN, YAHOO_STATUS_WEBLOGIN, 0);
+
+	yahoo_packet_hash(pkt, "sss", 0,
+	                  purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))),
+	                  1, purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))),
+	                  6, yd->auth);
+	yahoo_packet_send_and_free(pkt, yd);
+
+	g_free(yd->auth);
+	gc->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc);
+}
+
+static void yahoo_web_pending(gpointer data, gint source, PurpleInputCondition cond)
+{
+	PurpleConnection *gc = data;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	struct yahoo_data *yd = gc->proto_data;
+	char bufread[2048], *i = bufread, *buf = bufread;
+	int len;
+	GString *s;
+
+	len = read(source, bufread, sizeof(bufread) - 1);
+
+	if (len < 0) {
+		gchar *tmp;
+
+		if (errno == EAGAIN)
+			/* No worries */
+			return;
+
+		tmp = g_strdup_printf(_("Lost connection with server:\n%s"),
+				g_strerror(errno));
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+		g_free(tmp);
+		return;
+	} else if (len == 0) {
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			_("Server closed the connection."));
+		return;
+	}
+
+	if (yd->rxlen > 0 || !g_strstr_len(buf, len, "\r\n\r\n")) {
+		yd->rxqueue = g_realloc(yd->rxqueue, yd->rxlen + len + 1);
+		memcpy(yd->rxqueue + yd->rxlen, buf, len);
+		yd->rxlen += len;
+		i = buf = (char *)yd->rxqueue;
+		len = yd->rxlen;
+	}
+	buf[len] = '\0';
+
+	if ((strncmp(buf, "HTTP/1.0 302", strlen("HTTP/1.0 302")) &&
+			  strncmp(buf, "HTTP/1.1 302", strlen("HTTP/1.1 302")))) {
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			_("Received unexpected HTTP response from server."));
+		purple_debug_misc("yahoo", "Unexpected HTTP response: %s\n", buf);
+		return;
+	}
+
+	s = g_string_sized_new(len);
+
+	while ((i = strstr(i, "Set-Cookie: "))) {
+
+		i += strlen("Set-Cookie: ");
+		for (;*i != ';' && *i != '\0'; i++)
+			g_string_append_c(s, *i);
+
+		g_string_append(s, "; ");
+		/* Should these cookies be included too when trying for xfer?
+		 * It seems to work without these
+		 */
+	}
+
+	yd->auth = g_string_free(s, FALSE);
+	purple_input_remove(gc->inpa);
+	close(source);
+	g_free(yd->rxqueue);
+	yd->rxqueue = NULL;
+	yd->rxlen = 0;
+	/* Now we have our cookies to login with.  I'll go get the milk. */
+	if (purple_proxy_connect(gc, account, "wcs2.msg.dcn.yahoo.com",
+	                         purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
+	                         yahoo_got_web_connected, gc) == NULL) {
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+		                               _("Connection problem"));
+		return;
+	}
+}
+
+static void yahoo_got_cookies_send_cb(gpointer data, gint source, PurpleInputCondition cond)
+{
+	PurpleConnection *gc;
+	struct yahoo_data *yd;
+	int written, remaining;
+
+	gc = data;
+	yd = gc->proto_data;
+
+	remaining = strlen(yd->auth) - yd->auth_written;
+	written = write(source, yd->auth + yd->auth_written, remaining);
+
+	if (written < 0 && errno == EAGAIN)
+		written = 0;
+	else if (written <= 0) {
+		gchar *tmp;
+		g_free(yd->auth);
+		yd->auth = NULL;
+		if (gc->inpa)
+			purple_input_remove(gc->inpa);
+		gc->inpa = 0;
+		tmp = g_strdup_printf(_("Lost connection with %s:\n%s"),
+				"login.yahoo.com:80", g_strerror(errno));
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+		g_free(tmp);
+		return;
+	}
+
+	if (written < remaining) {
+		yd->auth_written += written;
+		return;
+	}
+
+	g_free(yd->auth);
+	yd->auth = NULL;
+	yd->auth_written = 0;
+	purple_input_remove(gc->inpa);
+	gc->inpa = purple_input_add(source, PURPLE_INPUT_READ, yahoo_web_pending, gc);
+}
+
+static void yahoo_got_cookies(gpointer data, gint source, const gchar *error_message)
+{
+	PurpleConnection *gc = data;
+
+	if (source < 0) {
+		gchar *tmp;
+		tmp = g_strdup_printf(_("Could not establish a connection with %s:\n%s"),
+				"login.yahoo.com:80", error_message);
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+		g_free(tmp);
+		return;
+	}
+
+	if (gc->inpa == 0)
+	{
+		gc->inpa = purple_input_add(source, PURPLE_INPUT_WRITE,
+			yahoo_got_cookies_send_cb, gc);
+		yahoo_got_cookies_send_cb(gc, source, PURPLE_INPUT_WRITE);
+	}
+}
+
+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(PurpleUtilFetchUrlData *url_data, gpointer user_data,
+		const gchar *url_text, size_t len, const gchar *error_message)
+{
+	PurpleConnection *gc = (PurpleConnection *)user_data;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	struct yahoo_data *yd = gc->proto_data;
+	const char *sn = purple_account_get_username(account);
+	const char *pass = purple_connection_get_password(gc);
+	GHashTable *hash = yahoo_login_page_hash(url_text, len);
+	GString *url = g_string_new("GET http://login.yahoo.com/config/login?login=");
+	char md5[33], *hashp = md5, *chal;
+	int i;
+	PurpleCipher *cipher;
+	PurpleCipherContext *context;
+	guchar digest[16];
+
+	yd->url_datas = g_slist_remove(yd->url_datas, url_data);
+
+	if (error_message != NULL)
+	{
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+		                               error_message);
+		return;
+	}
+
+	url = g_string_append(url, sn);
+	url = g_string_append(url, "&passwd=");
+
+	cipher = purple_ciphers_find_cipher("md5");
+	context = purple_cipher_context_new(cipher, NULL);
+
+	purple_cipher_context_append(context, (const guchar *)pass, strlen(pass));
+	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
+	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_context_reset(context, NULL);
+	purple_cipher_context_append(context, (const guchar *)chal, strlen(chal));
+	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
+	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_context_reset(context, NULL);
+	purple_cipher_context_append(context, md5, strlen(md5));
+	purple_cipher_context_digest(context, 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_append(url, md5);
+	g_hash_table_foreach(hash, (GHFunc)yahoo_login_page_hash_iter, url);
+
+	url = g_string_append(url, "&.hash=1&.md5=1 HTTP/1.1\r\n"
+			      "Host: login.yahoo.com\r\n\r\n");
+	g_hash_table_destroy(hash);
+	yd->auth = g_string_free(url, FALSE);
+	if (purple_proxy_connect(gc, account, "login.yahoo.com", 80, yahoo_got_cookies, gc) == NULL) {
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+		                               _("Connection problem"));
+		return;
+	}
+
+	purple_cipher_context_destroy(context);
+}
+#endif /* TRY_WEBMESSENGER_LOGIN */
+
+static void yahoo_server_check(PurpleAccount *account)
+{
+	const char *server;
+
+	server = purple_account_get_string(account, "server", YAHOO_PAGER_HOST);
+
+	if (*server == '\0' || g_str_equal(server, "scs.yahoo.com") ||
+			g_str_equal(server, "scs.msg.yahoo.com"))
+		purple_account_set_string(account, "server", YAHOO_PAGER_HOST);
+}
+
+static void yahoo_picture_check(PurpleAccount *account)
+{
+	PurpleConnection *gc = purple_account_get_connection(account);
+	PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account);
+
+	yahoo_set_buddy_icon(gc, img);
+	purple_imgstore_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 (!strcmp(status_id, YAHOO_STATUS_TYPE_AVAILABLE)) {
+		if ((msg != NULL) && (*msg != '\0'))
+			return YAHOO_STATUS_CUSTOM;
+		else
+			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_login(PurpleAccount *account) {
+	PurpleConnection *gc = purple_account_get_connection(account);
+	struct yahoo_data *yd = gc->proto_data = g_new0(struct yahoo_data, 1);
+	PurpleStatus *status = purple_account_get_active_status(account);
+	gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_NO_URLDESC;
+
+	purple_connection_update_progress(gc, _("Connecting"), 1, 2);
+
+	purple_connection_set_display_name(gc, purple_account_get_username(account));
+
+	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_circ_buffer_new(0);
+	yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free);
+	yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
+	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_server_check(account);
+	yahoo_picture_check(account);
+
+	if (purple_account_get_bool(account, "yahoojp", FALSE)) {
+		yd->jp = TRUE;
+		if (purple_proxy_connect(gc, account,
+		                       purple_account_get_string(account, "serverjp",  YAHOOJP_PAGER_HOST),
+		                       purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
+		                       yahoo_got_connected, gc) == NULL)
+		{
+			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			                               _("Connection problem"));
+			return;
+		}
+	} else {
+		yd->jp = FALSE;
+		if (purple_proxy_connect(gc, account,
+		                       purple_account_get_string(account, "server",  YAHOO_PAGER_HOST),
+		                       purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
+		                       yahoo_got_connected, gc) == NULL)
+		{
+			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			                               _("Connection problem"));
+			return;
+		}
+	}
+}
+
+static void yahoo_close(PurpleConnection *gc) {
+	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
+	GSList *l;
+
+	if (gc->inpa)
+		purple_input_remove(gc->inpa);
+
+	while (yd->url_datas) {
+		purple_util_fetch_url_cancel(yd->url_datas->data);
+		yd->url_datas = g_slist_delete_link(yd->url_datas, yd->url_datas);
+	}
+
+	for (l = yd->confs; l; l = l->next) {
+		PurpleConversation *conv = l->data;
+
+		yahoo_conf_leave(yd, purple_conversation_get_name(conv),
+		                 purple_connection_get_display_name(gc),
+				 purple_conv_chat_get_users(PURPLE_CONV_CHAT(conv)));
+	}
+	g_slist_free(yd->confs);
+
+	for (l = yd->cookies; l; l = l->next) {
+		g_free(l->data);
+		l->data=NULL;
+	}
+	g_slist_free(yd->cookies);
+
+	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);
+
+	if (yd->txhandler)
+		purple_input_remove(yd->txhandler);
+
+	purple_circ_buffer_destroy(yd->txbuf);
+
+	if (yd->fd >= 0)
+		close(yd->fd);
+
+	g_free(yd->rxqueue);
+	yd->rxlen = 0;
+	g_free(yd->picture_url);
+
+	if (yd->buddy_icon_connect_data)
+		purple_proxy_connect_cancel(yd->buddy_icon_connect_data);
+	if (yd->picture_upload_todo)
+		yahoo_buddy_icon_upload_data_free(yd->picture_upload_todo);
+	if (yd->ycht)
+		ycht_connection_close(yd->ycht);
+
+	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);
+
+	g_free(yd->current_list15_grp);
+
+	g_free(yd);
+	gc->proto_data = NULL;
+}
+
+static const char *yahoo_list_icon(PurpleAccount *a, PurpleBuddy *b)
+{
+	return "yahoo";
+}
+
+static const char *yahoo_list_emblem(PurpleBuddy *b)
+{
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	struct yahoo_data *yd;
+	YahooFriend *f;
+	PurplePresence *presence;
+
+	if (!b || !(account = purple_buddy_get_account(b)) ||
+			!(gc = purple_account_get_connection(account)) ||
+			!(yd = gc->proto_data))
+		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";
+		if (f->protocol == 2)
+			return "msn";
+	}
+	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;
+	struct yahoo_data *yd;
+	int id;
+
+	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
+
+	buddy = (PurpleBuddy *) node;
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	yd = gc->proto_data;
+	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;
+
+	struct yahoo_data *yd;
+	const char *game;
+	char *game2;
+	char *t;
+	char url[256];
+	YahooFriend *f;
+
+	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
+
+	buddy = (PurpleBuddy *) node;
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	yd = (struct yahoo_data *) gc->proto_data;
+
+	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);
+}
+
+static char *yahoo_status_text(PurpleBuddy *b)
+{
+	YahooFriend *f = NULL;
+	const char *msg;
+	char *msg2;
+	PurpleAccount *account;
+
+	account = purple_buddy_get_account(b);
+	f = yahoo_friend_find(purple_account_get_connection(account), 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 *escaped;
+	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) {
+		escaped = g_markup_escape_text(status, strlen(status));
+		purple_notify_user_info_add_pair(user_info, _("Status"), escaped);
+		g_free(status);
+		g_free(escaped);
+	}
+
+	if (presence != NULL)
+		purple_notify_user_info_add_pair(user_info, _("Presence"), presence);
+}
+
+static void yahoo_addbuddyfrommenu_cb(PurpleBlistNode *node, gpointer data)
+{
+	PurpleBuddy *buddy;
+	PurpleConnection *gc;
+
+	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
+
+	buddy = (PurpleBuddy *) node;
+	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+
+	yahoo_add_buddy(gc, buddy, NULL);
+}
+
+
+static void yahoo_chat_goto_menu(PurpleBlistNode *node, gpointer data)
+{
+	PurpleBuddy *buddy;
+	PurpleConnection *gc;
+
+	g_return_if_fail(PURPLE_BLIST_NODE_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;
+	struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data;
+
+	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));
+}
+
+static GList *yahoo_buddy_menu(PurpleBuddy *buddy)
+{
+	GList *m = NULL;
+	PurpleMenuAction *act;
+
+	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+	struct yahoo_data *yd = gc->proto_data;
+	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);
+	}
+
+	if (f) {
+		act = purple_menu_action_new(_("Start Doodling"),
+		                           PURPLE_CALLBACK(yahoo_doodle_blist_node),
+		                           NULL, NULL);
+		m = g_list_append(m, act);
+	}
+
+	return m;
+}
+
+static GList *yahoo_blist_node_menu(PurpleBlistNode *node)
+{
+	if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+		return yahoo_buddy_menu((PurpleBuddy *) node);
+	} else {
+		return NULL;
+	}
+}
+
+static void yahoo_act_id(PurpleConnection *gc, PurpleRequestFields *fields)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	const char *name = yd->profiles[purple_request_fields_get_choice(fields, "id")];
+
+	struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_IDACT, YAHOO_STATUS_AVAILABLE, 0);
+	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(PurpleUtilFetchUrlData *url_data, gpointer user_data,
+		const gchar *token, size_t len, const gchar *error_message)
+{
+	PurpleConnection *gc = user_data;
+	gboolean set_cookie = FALSE;
+	gchar *url;
+	struct yahoo_data *yd = gc->proto_data;
+
+	g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc));
+
+	yd->url_datas = g_slist_remove(yd->url_datas, url_data);
+
+	if (error_message != NULL)
+		purple_debug_error("yahoo", "Requesting mail login token failed: %s\n", error_message);
+	else if (len > 0 && token && *token) {
+	 	/* Should we not be hardcoding the rd url? */
+		url = g_strdup_printf(
+			"http://login.yahoo.com/config/reset_cookies_token?"
+			".token=%s"
+			"&.done=http://us.rd.yahoo.com/messenger/client/%%3fhttp://mail.yahoo.com/",
+			token);
+		set_cookie = TRUE;
+	}
+
+	if (!set_cookie) {
+		purple_debug_error("yahoo", "No mail login token; forwarding to login screen.\n");
+		url = g_strdup(yd->jp ? YAHOOJP_MAIL_URL : YAHOO_MAIL_URL);
+	}
+
+	/* Open the mailbox with the parsed url data */
+	purple_notify_uri(gc, url);
+
+	g_free(url);
+}
+
+
+static void yahoo_show_inbox(PurplePluginAction *action)
+{
+	/* Setup a cookie that can be used by the browser */
+	/* XXX I have no idea how this will work with Yahoo! Japan. */
+
+	PurpleConnection *gc = action->context;
+	struct yahoo_data *yd = gc->proto_data;
+
+	PurpleUtilFetchUrlData *url_data;
+	const char* base_url = "http://login.yahoo.com";
+	/* use whole URL if using HTTP Proxy */
+	gboolean use_whole_url = yahoo_account_use_http_proxy(gc);
+	gchar *request = g_strdup_printf(
+		"POST %s/config/cookie_token HTTP/1.0\r\n"
+		"Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s;\r\n"
+		"User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
+		"Host: login.yahoo.com\r\n"
+		"Content-Length: 0\r\n\r\n",
+		use_whole_url ? base_url : "",
+		yd->cookie_t, yd->cookie_y);
+
+	url_data = purple_util_fetch_url_request_len_with_account(
+			purple_connection_get_account(gc), base_url, use_whole_url,
+			YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1,
+			yahoo_get_inbox_token_cb, gc);
+
+	g_free(request);
+
+	if (url_data != NULL)
+		yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
+	else {
+		const char *yahoo_mail_url = (yd->jp ? YAHOOJP_MAIL_URL : YAHOO_MAIL_URL);
+		purple_debug_error("yahoo",
+				   "Unable to request mail login token; forwarding to login screen.");
+		purple_notify_uri(gc, yahoo_mail_url);
+	}
+
+}
+
+
+static void yahoo_show_act_id(PurplePluginAction *action)
+{
+	PurpleRequestFields *fields;
+	PurpleRequestFieldGroup *group;
+	PurpleRequestField *field;
+	PurpleConnection *gc = (PurpleConnection *) action->context;
+	struct yahoo_data *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]);
+		if (purple_strequal(yd->profiles[iter], name))
+			purple_request_field_choice_set_default_value(field, iter);
+	}
+
+	purple_request_fields(gc, NULL, _("Select the ID you want to activate"), NULL,
+					   fields,
+					   _("OK"), G_CALLBACK(yahoo_act_id),
+					   _("Cancel"), NULL,
+					   purple_connection_get_account(gc), NULL, NULL,
+					   gc);
+}
+
+static void yahoo_show_chat_goto(PurplePluginAction *action)
+{
+	PurpleConnection *gc = (PurpleConnection *) action->context;
+	purple_request_input(gc, NULL, _("Join whom in chat?"), NULL,
+					   "", FALSE, FALSE, NULL,
+					   _("OK"), G_CALLBACK(yahoo_chat_goto),
+					   _("Cancel"), NULL,
+					   purple_connection_get_account(gc), NULL, NULL,
+					   gc);
+}
+
+static GList *yahoo_actions(PurplePlugin *plugin, gpointer context) {
+	GList *m = NULL;
+	PurplePluginAction *act;
+
+	act = purple_plugin_action_new(_("Activate ID..."),
+			yahoo_show_act_id);
+	m = g_list_append(m, act);
+
+	act = purple_plugin_action_new(_("Join User in Chat..."),
+			yahoo_show_chat_goto);
+	m = g_list_append(m, act);
+
+	m = g_list_append(m, NULL);
+	act = purple_plugin_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 int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags);
+
+static void yahoo_get_sms_carrier_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
+		const gchar *webdata, size_t len, const gchar *error_message)
+{
+	struct yahoo_sms_carrier_cb_data *sms_cb_data = user_data;
+	PurpleConnection *gc = sms_cb_data->gc;
+	struct yahoo_data *yd = gc->proto_data;
+	char *mobile_no = NULL;
+	char *status = NULL;
+	char *carrier = NULL;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
+
+	if (error_message != NULL) {
+		purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
+
+		g_free(sms_cb_data->who);
+		g_free(sms_cb_data->what);
+		g_free(sms_cb_data);
+		return ;
+	}
+	else if (len > 0 && webdata && *webdata) {
+		xmlnode *validate_data_root = xmlnode_from_str(webdata, -1);
+		xmlnode *validate_data_child = xmlnode_get_child(validate_data_root, "mobile_no");
+		mobile_no = (char *)xmlnode_get_attrib(validate_data_child, "msisdn");
+
+		validate_data_root = xmlnode_copy(validate_data_child);
+		validate_data_child = xmlnode_get_child(validate_data_root, "status");
+		status = xmlnode_get_data(validate_data_child);
+
+		validate_data_child = xmlnode_get_child(validate_data_root, "carrier");
+		carrier = xmlnode_get_data(validate_data_child);
+
+		purple_debug_info("yahoo","SMS validate data: Mobile:%s, Status:%s, Carrier:%s\n", mobile_no, status, carrier);
+
+		if( strcmp(status, "Valid") == 0) {
+			g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup(carrier));
+			yahoo_send_im(sms_cb_data->gc, sms_cb_data->who, sms_cb_data->what, PURPLE_MESSAGE_SEND);
+		}
+		else	{
+			g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup("Unknown"));
+			purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
+		}
+
+		xmlnode_free(validate_data_child);
+		xmlnode_free(validate_data_root);
+		g_free(sms_cb_data->who);
+		g_free(sms_cb_data->what);
+		g_free(sms_cb_data);
+		g_free(mobile_no);
+		g_free(status);
+		g_free(carrier);
+	}
+}
+
+static void yahoo_get_sms_carrier(PurpleConnection *gc, gpointer data)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	PurpleUtilFetchUrlData *url_data;
+	struct yahoo_sms_carrier_cb_data *sms_cb_data;
+	char *validate_request_str = NULL;
+	char *request = NULL;
+	gboolean use_whole_url = FALSE;
+	xmlnode *validate_request_root = NULL;
+	xmlnode *validate_request_child = NULL;
+
+	if(!(sms_cb_data = data))
+		return;
+
+	validate_request_root = xmlnode_new("validate");
+	xmlnode_set_attrib(validate_request_root, "intl", "us");
+	xmlnode_set_attrib(validate_request_root, "version", YAHOO_CLIENT_VERSION);
+	xmlnode_set_attrib(validate_request_root, "qos", "0");
+
+	validate_request_child = xmlnode_new_child(validate_request_root, "mobile_no");
+	xmlnode_set_attrib(validate_request_child, "msisdn", sms_cb_data->who + 1);
+
+	validate_request_str = xmlnode_to_str(validate_request_root, NULL);
+
+	xmlnode_free(validate_request_child);
+	xmlnode_free(validate_request_root);
+
+	request = g_strdup_printf(
+		"POST /mobileno?intl=us&version=%s HTTP/1.1\r\n"
+		"Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s; path=/; domain=.yahoo.com;\r\n"
+		"User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
+		"Host: validate.msg.yahoo.com\r\n"
+		"Content-Length: %" G_GSIZE_FORMAT "\r\n"
+		"Cache-Control: no-cache\r\n\r\n%s",
+		YAHOO_CLIENT_VERSION, yd->cookie_t, yd->cookie_y, strlen(validate_request_str), validate_request_str);
+
+	/* use whole URL if using HTTP Proxy */
+	if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP))
+	    use_whole_url = TRUE;
+
+	url_data = purple_util_fetch_url_request_len_with_account(
+			purple_connection_get_account(gc), YAHOO_SMS_CARRIER_URL, use_whole_url,
+			YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1,
+			yahoo_get_sms_carrier_cb, data);
+
+	g_free(request);
+	g_free(validate_request_str);
+
+	if (!url_data) {
+		PurpleAccount *account = purple_connection_get_account(gc);
+		PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
+		purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
+		g_free(sms_cb_data->who);
+		g_free(sms_cb_data->what);
+		g_free(sms_cb_data);
+	}
+}
+
+static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	struct yahoo_packet *pkt = NULL;
+	char *msg = yahoo_html_to_codes(what);
+	char *msg2;
+	gboolean utf8 = TRUE;
+	PurpleWhiteboard *wb;
+	int ret = 1;
+	YahooFriend *f = NULL;
+	gsize lenb = 0;
+	glong lenc = 0;
+	struct yahoo_p2p_data *p2p_data;
+	gboolean msn = FALSE;
+	msg2 = yahoo_string_encode(gc, msg, &utf8);
+
+	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;
+		}
+	}
+
+	msn = !g_strncasecmp(who, "msn/", 4);
+
+	if( strncmp(who, "+", 1) == 0 ) {
+		/* we have an sms to be sent */
+		gchar *carrier = NULL;
+		const char *alias = NULL;
+		PurpleAccount *account = purple_connection_get_account(gc);
+		PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account);
+
+		carrier = g_hash_table_lookup(yd->sms_carrier, who);
+		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(who);
+			sms_cb_data->what = g_strdup(what);
+
+			purple_conversation_write(conv, NULL, "Getting mobile carrier to send the sms", PURPLE_MESSAGE_SYSTEM, time(NULL));
+
+			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(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
+
+			g_free(msg);
+			g_free(msg2);
+			return -1;
+		}
+
+		alias = purple_account_get_alias(account);
+		pkt = yahoo_packet_new(YAHOO_SERVICE_SMS_MSG, YAHOO_STATUS_AVAILABLE, 0);
+		yahoo_packet_hash(pkt, "sssss",
+			1, purple_connection_get_display_name(gc),
+			69, alias,
+			5, who + 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, 0);
+	if(msn) {
+		yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who+4);
+		yahoo_packet_hash_int(pkt, 241, 2);
+	}
+	else	{
+		yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who);
+		if ((f = yahoo_friend_find(gc, who)) && f->protocol)
+			yahoo_packet_hash_int(pkt, 241, f->protocol);
+	}
+
+	if (utf8)
+		yahoo_packet_hash_str(pkt, 97, "1");
+	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 no set an IMVironment, then use the default.
+	 */
+	wb = purple_whiteboard_get_session(gc->account, who);
+	if (wb)
+		yahoo_packet_hash_str(pkt, 63, DOODLE_IMV_KEY);
+	else
+	{
+		const char *imv;
+		imv = g_hash_table_lookup(yd->imvironments, who);
+		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, who)) && !msn ) {
+			yahoo_packet_hash_int(pkt, 11, p2p_data->session_id);
+			yahoo_p2p_write_pkt(p2p_data->source, pkt);
+		}
+		else	{
+			yahoo_packet_send(pkt, yd);
+			if(!msn)
+				yahoo_send_p2p_pkt(gc, who, 0);		/* send p2p packet, with val_13=0 */
+		}
+	}
+	else
+		ret = -E2BIG;
+
+	yahoo_packet_free(pkt);
+
+	g_free(msg);
+	g_free(msg2);
+
+	return ret;
+}
+
+static unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	struct yahoo_p2p_data *p2p_data;
+	gboolean msn = !g_strncasecmp(who, "msn/", 4);
+	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, 0);
+
+	/* check to see if p2p link exists, send through it */
+	if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !msn ) {
+		yahoo_packet_hash(pkt, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc),
+	                  14, " ", 13, state == PURPLE_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 */
+		if(msn)
+			yahoo_packet_hash(pkt, "sssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
+	                  14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
+	                  5, who+4, 1002, "1", 241, "2");
+		else
+			yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
+	                  14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
+	                  5, who+4, 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;
+}
+
+static void yahoo_set_status(PurpleAccount *account, PurpleStatus *status)
+{
+	PurpleConnection *gc;
+	PurplePresence *presence;
+	struct yahoo_data *yd;
+	struct yahoo_packet *pkt;
+	int old_status;
+	const char *msg = NULL;
+	char *tmp = NULL;
+	char *conv_msg = NULL;
+	gboolean utf8 = TRUE;
+
+	if (!purple_status_is_active(status))
+		return;
+
+	gc = purple_account_get_connection(account);
+	presence = purple_status_get_presence(status);
+	yd = (struct yahoo_data *)gc->proto_data;
+	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, &utf8);
+			conv_msg = purple_markup_strip_html(tmp);
+			g_free(tmp);
+		} else {
+			if ((msg == NULL) || (*msg == '\0'))
+				msg = _("Away");
+			tmp = yahoo_string_encode(gc, msg, &utf8);
+			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, 0);
+		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, 0);
+	yahoo_packet_hash_int(pkt, 10, yd->current_status);
+
+	if (yd->current_status == YAHOO_STATUS_CUSTOM) {
+		yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0);
+		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");
+
+	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, 0);
+		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);
+
+	}
+}
+
+static void yahoo_set_idle(PurpleConnection *gc, int idle)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	struct yahoo_packet *pkt = NULL;
+	char *msg = NULL, *msg2 = NULL;
+	PurpleStatus *status = NULL;
+
+	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);
+	}
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, 0);
+
+	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) {
+			gboolean utf8 = TRUE;
+			msg = yahoo_string_encode(gc, tmp, &utf8);
+			msg2 = purple_markup_strip_html(msg);
+			yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0);
+			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 (!purple_presence_is_available(purple_account_get_presence(purple_connection_get_account(gc))))
+		yahoo_packet_hash_str(pkt, 47, "1");
+
+	yahoo_packet_send_and_free(pkt, yd);
+
+	g_free(msg);
+	g_free(msg2);
+}
+
+static 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(PURPLE_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(PURPLE_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(PURPLE_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_BUSY, _("Busy"), TRUE);
+	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;
+}
+
+static void yahoo_keepalive(PurpleConnection *gc)
+{
+	struct yahoo_packet *pkt;
+	struct yahoo_data *yd = gc->proto_data;
+	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, 0);
+				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, 0);
+			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, 0);
+		yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc));
+		yahoo_packet_send_and_free(pkt, yd);
+	}
+
+}
+
+static void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *g)
+{
+	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
+	struct yahoo_packet *pkt;
+	const char *group = NULL;
+	char *group2;
+	YahooFriend *f;
+	const char *bname;
+	gboolean msn = FALSE;
+
+	if (!yd->logged_in)
+		return;
+
+	bname = purple_buddy_get_name(buddy);
+	if (!purple_privacy_check(purple_connection_get_account(gc), bname))
+		return;
+
+	f = yahoo_friend_find(gc, bname);
+	msn = !g_strncasecmp(bname, "msn/", 4);
+
+	g = purple_buddy_get_group(buddy);
+	if (g)
+		group = purple_group_get_name(g);
+	else
+		group = "Buddies";
+
+	group2 = yahoo_string_encode(gc, group, NULL);
+	pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0);
+	if(msn) {
+		yahoo_packet_hash(pkt, "sssssssssss",
+			14, "",
+			65, group2,
+			97, "1",
+			1, purple_connection_get_display_name(gc),
+			302, "319",
+			300, "319",
+			7, bname + 4,
+			241, "2",
+			334, "0",
+			301, "319",
+			303, "319"
+		);
+	}
+	else	{
+		yahoo_packet_hash(pkt, "ssssssssss",
+			14, "",
+			65, group2,
+			97, "1",
+			1, purple_connection_get_display_name(gc),
+			302, "319",
+			300, "319",
+	                7, bname,
+			334, "0",
+			301, "319",
+			303, "319"
+		);
+	}
+	if (f && f->protocol && !msn)
+		yahoo_packet_hash_int(pkt, 241, f->protocol);
+
+	yahoo_packet_send_and_free(pkt, yd);
+	g_free(group2);
+}
+
+static void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
+{
+	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
+	struct yahoo_packet *pkt;
+	GSList *buddies, *l;
+	PurpleGroup *g;
+	gboolean remove = TRUE;
+	char *cg;
+	const char *bname, *gname;
+	YahooFriend *f = NULL;
+	gboolean msn = FALSE;
+
+	bname = purple_buddy_get_name(buddy);
+	f = yahoo_friend_find(gc, bname);
+	if (!f)
+		return;
+
+	gname = purple_group_get_name(group);
+	buddies = purple_find_buddies(purple_connection_get_account(gc), bname);
+	if(f->protocol == 2)
+		msn = TRUE;
+	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);
+
+	cg = yahoo_string_encode(gc, gname, NULL);
+	pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0);
+
+	if(msn)
+		yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
+	                  7, bname+4, 65, cg);
+	else
+		yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
+	                  7, bname, 65, cg);
+	if(f->protocol)
+		yahoo_packet_hash_int(pkt, 241, f->protocol);
+	yahoo_packet_send_and_free(pkt, yd);
+	g_free(cg);
+}
+
+static void yahoo_add_deny(PurpleConnection *gc, const char *who) {
+	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
+	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, 0);
+	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
+	                  7, who, 13, "1");
+	yahoo_packet_send_and_free(pkt, yd);
+}
+
+static void yahoo_rem_deny(PurpleConnection *gc, const char *who) {
+	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
+	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, 0);
+	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, who, 13, "2");
+	yahoo_packet_send_and_free(pkt, yd);
+}
+
+static void yahoo_set_permit_deny(PurpleConnection *gc)
+{
+	PurpleAccount *account;
+	GSList *deny;
+
+	account = purple_connection_get_account(gc);
+
+	switch (account->perm_deny)
+	{
+		case PURPLE_PRIVACY_ALLOW_ALL:
+			for (deny = account->deny; deny; deny = deny->next)
+				yahoo_rem_deny(gc, deny->data);
+			break;
+
+		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
+		case PURPLE_PRIVACY_ALLOW_USERS:
+		case PURPLE_PRIVACY_DENY_USERS:
+		case PURPLE_PRIVACY_DENY_ALL:
+			for (deny = account->deny; deny; deny = deny->next)
+				yahoo_add_deny(gc, deny->data);
+			break;
+	}
+}
+
+static gboolean yahoo_unload_plugin(PurplePlugin *plugin)
+{
+	yahoo_dest_colorht();
+
+	return TRUE;
+}
+
+static void yahoo_change_buddys_group(PurpleConnection *gc, const char *who,
+				   const char *old_group, const char *new_group)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	struct yahoo_packet *pkt;
+	char *gpn, *gpo;
+	YahooFriend *f = yahoo_friend_find(gc, who);
+	gboolean msn = FALSE;
+	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;
+
+	if(f->protocol == 2) {
+		msn = TRUE;
+		temp = who+4;
+	} else
+		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, NULL);
+	gpo = yahoo_string_encode(gc, old_group, NULL);
+	if (!strcmp(gpn, gpo)) {
+		g_free(gpn);
+		g_free(gpo);
+		return;
+	}
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, 0);
+	if(f->protocol)
+		yahoo_packet_hash(pkt, "ssssissss", 1, purple_connection_get_display_name(gc),
+	                  302, "240", 300, "240", 7, temp, 241, f->protocol, 224, gpo, 264, gpn, 301,
+	                  "240", 303, "240");
+	else
+		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);
+}
+
+static void yahoo_rename_group(PurpleConnection *gc, const char *old_name,
+							   PurpleGroup *group, GList *moved_buddies)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	struct yahoo_packet *pkt;
+	char *gpn, *gpo;
+
+	gpn = yahoo_string_encode(gc, purple_group_get_name(group), NULL);
+	gpo = yahoo_string_encode(gc, old_name, NULL);
+	if (!strcmp(gpn, gpo)) {
+		g_free(gpn);
+		g_free(gpo);
+		return;
+	}
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, 0);
+	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 **********************************/
+
+static 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_prpl_send_attention(account->gc, c->name, YAHOO_BUZZ);
+
+	return PURPLE_CMD_RET_OK;
+}
+
+static PurplePlugin *my_protocol = NULL;
+
+static PurpleCmdRet
+yahoopurple_cmd_chat_join(PurpleConversation *conv, const char *cmd,
+                        char **args, char **error, void *data)
+{
+	GHashTable *comp;
+	PurpleConnection *gc;
+	struct yahoo_data *yd;
+	int id;
+
+	if (!args || !args[0])
+		return PURPLE_CMD_RET_FAILED;
+
+	gc = purple_conversation_get_gc(conv);
+	yd = gc->proto_data;
+	id = yd->conf_id;
+	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;
+}
+
+static 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;
+}
+
+static gboolean yahoo_offline_message(const PurpleBuddy *buddy)
+{
+	return TRUE;
+}
+
+gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type)
+{
+	PurpleConversation *c;
+
+	c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
+			username, gc->account);
+
+	g_return_val_if_fail(c != NULL, FALSE);
+
+	purple_debug_info("yahoo", "Sending <ding> on account %s to buddy %s.\n",
+			username, c->name);
+	purple_conv_im_send_with_flags(PURPLE_CONV_IM(c), "<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;
+}
+
+/************************** Plugin Initialization ****************************/
+static void
+yahoopurple_register_commands(void)
+{
+	purple_cmd_register("join", "s", PURPLE_CMD_P_PRPL,
+	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
+	                  PURPLE_CMD_FLAG_PRPL_ONLY,
+	                  "prpl-yahoo", yahoopurple_cmd_chat_join,
+	                  _("join &lt;room&gt;:  Join a chat room on the Yahoo network"), NULL);
+	purple_cmd_register("list", "", PURPLE_CMD_P_PRPL,
+	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
+	                  PURPLE_CMD_FLAG_PRPL_ONLY,
+	                  "prpl-yahoo", yahoopurple_cmd_chat_list,
+	                  _("list: List rooms on the Yahoo network"), NULL);
+	purple_cmd_register("buzz", "", PURPLE_CMD_P_PRPL,
+	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
+	                  "prpl-yahoo", yahoopurple_cmd_buzz,
+	                  _("buzz: Buzz a user to get their attention"), NULL);
+	purple_cmd_register("doodle", "", PURPLE_CMD_P_PRPL,
+	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
+	                  "prpl-yahoo", yahoo_doodle_purple_cmd_start,
+	                 _("doodle: Request user to start a Doodle session"), NULL);
+}
+
+static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
+{
+	PurpleAccount *acct = NULL;
+
+	/* If we have a specific acct, use it */
+	if (acct_id) {
+		acct = purple_accounts_find(acct_id, prpl);
+		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(prpl, 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_plugin_get_id(my_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");
+
+			PurpleConversation *conv = purple_find_conversation_with_account(
+				PURPLE_CONV_TYPE_IM, sname, acct);
+			if (conv == NULL)
+				conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, sname);
+			purple_conversation_present(conv);
+
+			if (message) {
+				/* Spaces are encoded as '+' */
+				g_strdelimit(message, "+", ' ');
+				purple_conv_send_confirm(conv, 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"));
+			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 PurpleWhiteboardPrplOps yahoo_whiteboard_prpl_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 PurplePluginProtocolInfo prpl_info =
+{
+	OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC,
+	NULL, /* user_splits */
+	NULL, /* protocol_options */
+	{"png,gif,jpeg", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND},
+	yahoo_list_icon,
+	yahoo_list_emblem,
+	yahoo_status_text,
+	yahoo_tooltip_text,
+	yahoo_status_types,
+	yahoo_blist_node_menu,
+	yahoo_c_info,
+	yahoo_c_info_defaults,
+	yahoo_login,
+	yahoo_close,
+	yahoo_send_im,
+	NULL, /* set info */
+	yahoo_send_typing,
+	yahoo_get_info,
+	yahoo_set_status,
+	yahoo_set_idle,
+	NULL, /* change_passwd*/
+	yahoo_add_buddy,
+	NULL, /* add_buddies */
+	yahoo_remove_buddy,
+	NULL, /* remove_buddies */
+	NULL, /* add_permit */
+	yahoo_add_deny,
+	NULL, /* rem_permit */
+	yahoo_rem_deny,
+	yahoo_set_permit_deny,
+	yahoo_c_join,
+	NULL, /* reject chat invite */
+	yahoo_get_chat_name,
+	yahoo_c_invite,
+	yahoo_c_leave,
+	NULL, /* chat whisper */
+	yahoo_c_send,
+	yahoo_keepalive,
+	NULL, /* register_user */
+	NULL, /* get_cb_info */
+	NULL, /* get_cb_away */
+	yahoo_update_alias, /* alias_buddy */
+	yahoo_change_buddys_group,
+	yahoo_rename_group,
+	NULL, /* buddy_free */
+	NULL, /* convo_closed */
+	purple_normalize_nocase, /* normalize */
+	yahoo_set_buddy_icon,
+	NULL, /* void (*remove_group)(PurpleConnection *gc, const char *group);*/
+	NULL, /* char *(*get_cb_real_name)(PurpleConnection *gc, int id, const char *who); */
+	NULL, /* set_chat_topic */
+	NULL, /* find_blist_chat */
+	yahoo_roomlist_get_list,
+	yahoo_roomlist_cancel,
+	yahoo_roomlist_expand_category,
+	NULL, /* can_receive_file */
+	yahoo_send_file,
+	yahoo_new_xfer,
+	yahoo_offline_message, /* offline_message */
+	&yahoo_whiteboard_prpl_ops,
+	NULL, /* send_raw */
+	NULL, /* roomlist_room_serialize */
+	NULL, /* unregister_user */
+
+	yahoo_send_attention,
+	yahoo_attention_types,
+
+	sizeof(PurplePluginProtocolInfo),       /* struct_size */
+	yahoo_get_account_text_table,    /* get_account_text_table */
+	NULL, /* initiate_media */
+	NULL  /* can_do_media */
+};
+
+static PurplePluginInfo info =
+{
+	PURPLE_PLUGIN_MAGIC,
+	PURPLE_MAJOR_VERSION,
+	PURPLE_MINOR_VERSION,
+	PURPLE_PLUGIN_PROTOCOL,                             /**< type           */
+	NULL,                                             /**< ui_requirement */
+	0,                                                /**< flags          */
+	NULL,                                             /**< dependencies   */
+	PURPLE_PRIORITY_DEFAULT,                            /**< priority       */
+	"prpl-yahoo",                                     /**< id             */
+	"Yahoo",	                                      /**< name           */
+	DISPLAY_VERSION,                                  /**< version        */
+	                                                  /**  summary        */
+	N_("Yahoo Protocol Plugin"),
+	                                                  /**  description    */
+	N_("Yahoo Protocol Plugin"),
+	NULL,                                             /**< author         */
+	PURPLE_WEBSITE,                                     /**< homepage       */
+	NULL,                                             /**< load           */
+	yahoo_unload_plugin,                              /**< unload         */
+	NULL,                                             /**< destroy        */
+	NULL,                                             /**< ui_info        */
+	&prpl_info,                                       /**< extra_info     */
+	NULL,
+	yahoo_actions,
+
+	/* padding */
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static void
+init_plugin(PurplePlugin *plugin)
+{
+	PurpleAccountOption *option;
+
+	option = purple_account_option_bool_new(_("Yahoo Japan"), "yahoojp", FALSE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_string_new(_("Pager server"), "server", YAHOO_PAGER_HOST);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_string_new(_("Japan Pager server"), "serverjp", YAHOOJP_PAGER_HOST);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_int_new(_("Pager port"), "port", YAHOO_PAGER_PORT);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_string_new(_("File transfer server"), "xfer_host", YAHOO_XFER_HOST);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_string_new(_("Japan file transfer server"), "xferjp_host", YAHOOJP_XFER_HOST);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_int_new(_("File transfer port"), "xfer_port", YAHOO_XFER_PORT);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_string_new(_("Chat room locale"), "room_list_locale", YAHOO_ROOMLIST_LOCALE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_bool_new(_("Ignore conference and chatroom invitations"), "ignore_invites", FALSE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_string_new(_("Encoding"), "local_charset", "ISO-8859-1");
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+
+#if 0
+	option = purple_account_option_string_new(_("Chat room list URL"), "room_list", YAHOO_ROOMLIST_URL);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_string_new(_("Yahoo Chat server"), "ycht-server", YAHOO_YCHT_HOST);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
+	option = purple_account_option_int_new(_("Yahoo Chat port"), "ycht-port", YAHOO_YCHT_PORT);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+#endif
+
+	my_protocol = plugin;
+	yahoopurple_register_commands();
+	yahoo_init_colorht();
+
+	purple_signal_connect(purple_get_core(), "uri-handler", plugin,
+		PURPLE_CALLBACK(yahoo_uri_handler), NULL);
+}
+
+PURPLE_INIT_PLUGIN(yahoo, init_plugin, info);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/yahoo/libymsg.h	Sun Jul 05 04:37:33 2009 +0000
@@ -0,0 +1,310 @@
+/**
+ * @file yahoo.h The Yahoo! protocol plugin
+ *
+ * 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 "circbuffer.h"
+#include "prpl.h"
+
+#define YAHOO_PAGER_HOST "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_PORT 80
+#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"
+/* really we should get the list of servers from
+ http://update.messenger.yahoo.co.jp/servers.html */
+#define YAHOOJP_PAGER_HOST "cs.yahoo.co.jp"
+#define YAHOOJP_TOKEN_URL "https://login.yahoo.co.jp/config/pwtoken_get?src=ymsgr&ts=&login=%s&passwd=%s&chal=%s"
+#define YAHOOJP_LOGIN_URL "https://login.yahoo.co.jp/config/pwtoken_login?src=ymsgr&ts=&token=%s"
+#define YAHOOJP_PROFILE_URL "http://profiles.yahoo.co.jp/"
+#define YAHOOJP_MAIL_URL "http://mail.yahoo.co.jp/"
+#define YAHOOJP_XFER_HOST "filetransfer.msg.yahoo.co.jp"
+#define YAHOOJP_WEBCAM_HOST "wc.yahoo.co.jp"
+/* not sure, must test: */
+#define YAHOOJP_XFER_RELAY_HOST "relay.msg.yahoo.co.jp"
+#define YAHOOJP_XFER_RELAY_PORT 80
+#define YAHOOJP_ROOMLIST_URL "http://insider.msg.yahoo.co.jp/ycontent/"
+#define YAHOOJP_ROOMLIST_LOCALE "ja"
+
+#define YAHOO_AUDIBLE_URL "http://us.dl1.yimg.com/download.yahoo.com/dl/aud"
+
+#define WEBMESSENGER_URL "http://login.yahoo.com/config/login?.src=pg"
+
+#define YAHOO_SMS_CARRIER_URL "http://lookup.msg.vip.mud.yahoo.com"
+
+#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.2152"
+
+#define YAHOOJP_CLIENT_VERSION_ID "4194239"
+#define YAHOOJP_CLIENT_VERSION "9.0.0.2152"
+
+#define YAHOO_CLIENT_USERAGENT "Mozilla/5.0"
+
+/* 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_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 = 0xffffffff /* in ymsg 15. doesnt mean the normal sense of 'disconnected' */
+};
+
+struct yahoo_buddy_icon_upload_data {
+	PurpleConnection *gc;
+	GString *str;
+	char *filename;
+	int pos;
+	int fd;
+	guint watcher;
+};
+
+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;
+
+struct yahoo_data {
+	PurpleConnection *gc;
+	int fd;
+	guchar *rxqueue;
+	int rxlen;
+	PurpleCircBuffer *txbuf;
+	guint txhandler;
+	GHashTable *friends;
+
+	char **profiles;  /* Multiple profiles can be associated with an account */
+
+	/**
+	 * 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;
+	gsize auth_written;
+	char *cookie_y;
+	char *cookie_t;
+	int session_id;
+	gboolean jp;
+	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;
+	PurpleProxyConnectData *buddy_icon_connect_data;
+
+	struct _YchtConn *ycht;
+
+	/**
+	 * This linked list contains PurpleUtilFetchUrlData structs
+	 * for when we lookup people profile or photo information.
+	 */
+	GSList *url_datas;
+	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 */
+
+	/**
+	 * 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;
+};
+
+#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);
+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 If not @c NULL, whether utf8 is okay or not.
+ *             Even if it is okay, we may not use it. If we
+ *             used it, we set this to @c TRUE, else to
+ *             @c FALSE. If @c NULL, false is assumed, and
+ *             it is not dereferenced.
+ * @return The g_malloced string in the appropriate encoding.
+ */
+char *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);
+
+/* previously-static functions, now needed for yahoo_profile.c */
+void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full);
+
+/* yahoo_profile.c */
+void yahoo_get_info(PurpleConnection *gc, const char *name);
+
+/* 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);
+
+gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type);
+GList *yahoo_attention_types(PurpleAccount *account);
+
+/* 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 /* _YAHOO_H_ */
--- a/libpurple/protocols/yahoo/yahoo.c	Sun Jul 05 02:26:03 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5254 +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 "accountopt.h"
-#include "blist.h"
-#include "cipher.h"
-#include "cmds.h"
-#include "core.h"
-#include "debug.h"
-#include "network.h"
-#include "notify.h"
-#include "privacy.h"
-#include "prpl.h"
-#include "proxy.h"
-#include "request.h"
-#include "server.h"
-#include "util.h"
-#include "version.h"
-#include "xmlnode.h"
-
-#include "yahoo.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 */
-
-/* #define TRY_WEBMESSENGER_LOGIN 0 */
-
-/* One hour */
-#define PING_TIMEOUT 3600
-
-/* One minute */
-#define KEEPALIVE_TIMEOUT 60
-
-static void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *, PurpleGroup *);
-#ifdef TRY_WEBMESSENGER_LOGIN
-static void yahoo_login_page_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message);
-#endif /* TRY_WEBMESSENGER_LOGIN */
-static void yahoo_set_status(PurpleAccount *account, PurpleStatus *status);
-
-static void yahoo_update_status(PurpleConnection *gc, const char *name, YahooFriend *f)
-{
-	char *status = NULL;
-
-	if (!gc || !name || !f || !purple_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_prpl_got_user_status(purple_connection_get_account(gc), name, status, "message",
-			                          yahoo_friend_get_status_message(f), NULL);
-		else
-			purple_prpl_got_user_status(purple_connection_get_account(gc), name, status, NULL);
-	}
-
-	if (f->idle != 0)
-		purple_prpl_got_user_idle(purple_connection_get_account(gc), name, TRUE, f->idle);
-	else
-		purple_prpl_got_user_idle(purple_connection_get_account(gc), name, FALSE, 0);
-
-	if (f->sms)
-		purple_prpl_got_user_status(purple_connection_get_account(gc), name, YAHOO_STATUS_TYPE_MOBILE, NULL);
-	else
-		purple_prpl_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;
-	char *msn_name = NULL;
-
-	if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
-		if (!purple_account_get_remember_password(account))
-			purple_account_set_password(account, NULL);
-		purple_connection_error_reason(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)) {
-				GSList *tmplist;
-				int protocol = 0;
-
-				name = pair->value;
-
-				/* Look ahead to see if we have the protocol info about the buddy */
-				for (tmplist = l->next; tmplist; tmplist = tmplist->next) {
-					struct yahoo_pair *p = tmplist->data;
-					if (p->key == 7)
-						break;
-					if (p->key == 241) {
-						if(strtol(p->value, NULL, 10) == 2) {
-							g_free(msn_name);
-							msn_name = g_strconcat("msn/", name, NULL);
-							name = msn_name;
-							protocol = 2;
-						}
-						break;
-					}
-				}
-				f = yahoo_friend_find_or_new(gc, name);
-				f->protocol = protocol;
-			}
-			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)
-					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)
-					f->idle = time(NULL);
-			}
-
-			break;
-		case 138: /* either we're not idle, or we are but won't say how long */
-			if (!f)
-				break;
-
-			if (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_prpl_got_user_status(account, name, "offline", NULL);
-					purple_prpl_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 (len) {
-					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_find_buddy(gc->account, name);
-
-			if (!cksum || (cksum == -1)) {
-				if (f)
-					yahoo_friend_set_buddy_icon_need_request(f, TRUE);
-				purple_buddy_icons_set_for_user(gc->account, 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);
-				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;
-		case 241: /* protocol buddy belongs to */
-			break;  /* We process this when get '7' */
-		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);
-	}
-	g_free(msn_name);
-}
-
-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 = 0;
-	char *oname = NULL;
-	char **oname_p = &oname;
-	GSList **list_p = &list;
-
-	if (!g_hash_table_lookup_extended(ht, purple_normalize(account, name), (gpointer *) oname_p, (gpointer *) list_p))
-		list = purple_find_buddies(account, name);
-	else
-		g_hash_table_steal(ht, 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 = 1;
-			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_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(purple_normalize(account, name));
-		g_hash_table_insert(ht, oname, list);
-	} else if (oname)
-		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(struct yahoo_data *yd, char *c)
-{
-	if (c[0] == 'Y') {
-		if (yd->cookie_y)
-			g_free(yd->cookie_y);
-		yd->cookie_y = _getcookie(c);
-	} else if (c[0] == 'T') {
-		if (yd->cookie_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);
-	struct yahoo_data *yd = gc->proto_data;
-	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? */
-	PurpleBuddy *b;
-	PurpleGroup *g;
-	int protocol = 0;
-	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) {
-				if(protocol == 2)
-					norm_bud = g_strconcat("msn/", temp, NULL);
-				else
-					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 (!(b = purple_find_buddy(account, norm_bud))) {
-						if (!(g = purple_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(protocol != 0) {
-						f->protocol = protocol;
-						purple_debug_info("yahoo", "Setting protocol to %d\n", f->protocol);
-					}
-					if(stealth == 2)
-						f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
-
-					/* set p2p status not connected and no p2p packet sent */
-					if(protocol == 0) {
-						yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
-						f->p2p_packet_sent = 0;
-					} else
-						yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT);
-				} 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",account->username, norm_bud);
-					purple_privacy_deny_add(account, norm_bud, 1);
-				}
-
-				protocol = 0;
-				stealth = 0;
-				norm_bud = NULL;
-				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 */
-			temp = g_strdup(purple_normalize(account, pair->value));
-			break;
-		case 241: /* another protocol user */
-			protocol = strtol(pair->value, NULL, 10);
-			break;
-		case 59: /* somebody told cookies come here too, but im not sure */
-			yahoo_process_cookie(yd, pair->value);
-			break;
-		case 317: /* Stealth Setting */
-			stealth = strtol(pair->value, NULL, 10);
-			break;
-		/* case 242: */ /* this seems related to 241 */
-			/* break; */
-		}
-	}
-
-	g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL);
-
-	/* 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)));
-	purple_connection_set_state(gc, PURPLE_CONNECTED);
-	yd->logged_in = TRUE;
-	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));
-	purple_debug_info("yahoo","Authentication: Connection established\n");
-
-	g_hash_table_destroy(ht);
-	g_free(norm_bud);
-	g_free(temp);
-}
-
-static void yahoo_process_list(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	GSList *l = pkt->hash;
-	gboolean export = FALSE;
-	gboolean got_serv_list = FALSE;
-	PurpleBuddy *b;
-	PurpleGroup *g;
-	YahooFriend *f = NULL;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	struct yahoo_data *yd = gc->proto_data;
-	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 (!yd->tmp_serv_ilist)
-				yd->tmp_serv_ilist = g_string_new(pair->value);
-			else
-				g_string_append(yd->tmp_serv_ilist, pair->value);
-			break;
-		case 89:
-			yd->profiles = g_strsplit(pair->value, ",", -1);
-			break;
-		case 59: /* cookies, yum */
-			yahoo_process_cookie(yd, pair->value);
-			break;
-		case YAHOO_SERVICE_PRESENCE_PERM:
-			if (!yd->tmp_serv_plist)
-				yd->tmp_serv_plist = g_string_new(pair->value);
-			else
-				g_string_append(yd->tmp_serv_plist, pair->value);
-			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++) {
-				norm_bud = g_strdup(purple_normalize(account, *bud));
-				f = yahoo_friend_find_or_new(gc, norm_bud);
-
-				if (!(b = purple_find_buddy(account, norm_bud))) {
-					if (!(g = purple_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);
-					export = TRUE;
-				}
-
-				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_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 &&
-		((account->perm_deny != PURPLE_PRIVACY_ALLOW_BUDDYLIST) &&
-		(account->perm_deny != PURPLE_PRIVACY_DENY_ALL) &&
-		(account->perm_deny != PURPLE_PRIVACY_ALLOW_USERS)))
-	{
-		account->perm_deny = PURPLE_PRIVACY_DENY_USERS;
-		purple_debug_info("yahoo", "%s privacy defaulting to PURPLE_PRIVACY_DENY_USERS.\n",
-				account->username);
-	}
-
-	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",
-						account->username, *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;
-	struct yahoo_data *yd = gc->proto_data;
-	gboolean msn = FALSE;
-
-	account = purple_connection_get_account(gc);
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-		if (pair->key == 4 || pair->key == 1)
-			from = pair->value;
-		if (pair->key == 49)
-			msg = pair->value;
-		if (pair->key == 13)
-			stat = pair->value;
-		if (pair->key == 14)
-			game = pair->value;
-		if (pair->key == 11)
-			val_11 = strtol(pair->value, NULL, 10);
-		if (pair->key == 241)
-			if(strtol(pair->value, NULL, 10) == 2)
-				msn = TRUE;
-		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_privacy_check(account, from)))
-	{
-		if(msn) {
-			char *msn_from = g_strconcat("msn/", from, NULL);
-			if (*stat == '1')
-				serv_got_typing(gc, msn_from, 0, PURPLE_TYPING);
-			else
-				serv_got_typing_stopped(gc, msn_from);
-			g_free(msn_from);
-		}
-		else	{
-			if (*stat == '1')
-				serv_got_typing(gc, from, 0, PURPLE_TYPING);
-			else
-				serv_got_typing_stopped(gc, from);
-		}
-	} else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) {
-		PurpleBuddy *bud = purple_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 == '1') {
-			yahoo_friend_set_game(f, game);
-			if (bud)
-				yahoo_update_status(gc, from, f);
-		}
-	} else if (!g_ascii_strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) {
-		PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, account);
-		char *buf = g_strdup_printf(_("%s has sent you a webcam invite, which is not yet supported."), from);
-		purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NOTIFY, time(NULL));
-		g_free(buf);
-	}
-}
-
-
-struct _yahoo_im {
-	char *from;
-	char *active_id;
-	int time;
-	int utf8;
-	int buddy_icon;
-	char *id;
-	char *msg;
-	gboolean msn;
-};
-
-static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	PurpleAccount *account;
-	GSList *l = pkt->hash;
-	struct _yahoo_im *sms = NULL;
-	struct yahoo_data *yd;
-	char *server_msg = NULL;
-	char *m;
-
-	yd = gc->proto_data;
-	account = purple_connection_get_account(gc);
-
-	while (l != NULL) {
-		struct yahoo_pair *pair = l->data;
-		if (pair->key == 4) {
-			sms = g_new0(struct _yahoo_im, 1);
-			sms->from = g_strdup_printf("+%s", pair->value);
-			sms->time = time(NULL);
-			sms->utf8 = TRUE;
-		}
-		if (pair->key == 14) {
-			if (sms)
-				sms->msg = pair->value;
-		}
-		if (pair->key == 68)
-			if(sms)
-				g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value));
-		if (pair->key == 16)
-			server_msg = pair->value;
-		l = l->next;
-	}
-
-	if( (pkt->status == -1) || (pkt->status == YAHOO_STATUS_DISCONNECTED) ) {
-		if (server_msg) {
-			PurpleConversation *c;
-			c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms->from, account);
-			if (c == NULL)
-				c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sms->from);
-			purple_conversation_write(c, NULL, server_msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
-		}
-		else
-			purple_notify_error(gc, NULL, _("Your SMS was not delivered"), NULL);
-
-		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);
-	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;
-	struct yahoo_data *yd = gc->proto_data;
-	GSList *l = pkt->hash;
-	GSList *list = NULL;
-	struct _yahoo_im *im = NULL;
-	const char *imv = NULL;
-	gint val_11 = 0;
-
-	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) {
-				im = g_new0(struct _yahoo_im, 1);
-				list = g_slist_append(list, im);
-				im->from = pair->value;
-				im->time = time(NULL);
-				im->utf8 = TRUE;
-			}
-			if (im && pair->key == 5)
-				im->active_id = pair->value;
-			if (pair->key == 97)
-				if (im)
-					im->utf8 = strtol(pair->value, NULL, 10);
-			if (pair->key == 15)
-				if (im)
-					im->time = strtol(pair->value, NULL, 10);
-			if (pair->key == 206)
-				if (im)
-					im->buddy_icon = strtol(pair->value, NULL, 10);
-			if (pair->key == 14) {
-				if (im)
-					im->msg = pair->value;
-			}
-			if (im && pair->key == 241) {
-				if(strtol(pair->value, NULL, 10) == 2)
-					im->msn = TRUE;
-			}
-			/* peer session id */
-			if (pair->key == 11) {
-				if (im)
-					val_11 = strtol(pair->value, NULL, 10);
-			}
-			/* IMV key */
-			if (pair->key == 63)
-			{
-				imv = pair->value;
-			}
-			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);
-	}
-
-	/* 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 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);
-		return;
-	}
-
-	/** TODO: It seems that this check should be per IM, not global */
-	/* Check for the Doodle IMV */
-	if (im != NULL && imv!= NULL && im->from != NULL)
-	{
-		g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(imv));
-
-		if (strstr(imv, "doodle;") != NULL)
-		{
-			PurpleWhiteboard *wb;
-
-			if (!purple_privacy_check(account, im->from)) {
-				purple_debug_info("yahoo", "Doodle request from %s dropped.\n", im->from);
-				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_create(account, im->from, DOODLE_STATE_REQUESTED);
-				ds = wb->proto_data;
-				ds->imv_key = g_strdup(imv);
-
-				yahoo_doodle_command_send_request(gc, im->from, imv);
-				yahoo_doodle_command_send_ready(gc, im->from, imv);
-			}
-		}
-	}
-
-	for (l = list; l; l = l->next) {
-		YahooFriend *f;
-		char *m, *m2;
-		char *msn_from = NULL;
-		const char *from;
-		PurpleConversation *c;
-		im = l->data;
-
-		if (!im->from || !im->msg) {
-			g_free(im);
-			continue;
-		}
-
-		if (!purple_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 (im->msn) {
-			msn_from = g_strconcat("msn/", im->from, NULL);
-			from = msn_from;
-		} else {
-			from = im->from;
-		}
-
-		c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, account);
-
-		if (!strcmp(m, "<ding>")) {
-			char *username;
-
-			if (c == NULL) {
-				c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, from);
-			}
-			username = g_markup_escape_text(from, -1);
-			purple_prpl_got_attention(gc, username, YAHOO_BUZZ);
-			g_free(username);
-			g_free(m);
-			g_free(im);
-			g_free(msn_from);
-			continue;
-		}
-
-		m2 = yahoo_codes_to_html(m);
-		g_free(m);
-
-		serv_got_im(gc, from, m2, 0, im->time);
-		g_free(m2);
-
-		/* laters : implement buddy icon for msn friends */
-		if (!im->msn) {
-			if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) {
-				if (yahoo_friend_get_buddy_icon_need_request(f)) {
-					yahoo_send_picture_request(gc, im->from);
-					yahoo_friend_set_buddy_icon_need_request(f, FALSE);
-				}
-			}
-		}
-
-		g_free(im);
-		g_free(msn_from);
-	}
-	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)
-			me = pair->value;
-		if (pair->key == 14)
-			msg = pair->value;
-
-		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);
-	g_free(prim);
-}
-
-struct yahoo_add_request {
-	PurpleConnection *gc;
-	char *id;
-	char *who;
-	int protocol;
-};
-
-static void
-yahoo_buddy_add_authorize_cb(gpointer data)
-{
-	struct yahoo_add_request *add_req = data;
-	struct yahoo_packet *pkt;
-	struct yahoo_data *yd = add_req->gc->proto_data;
-	const char *who = add_req->who;
-
-	if (add_req->protocol == 2)
-		who += 4;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, YAHOO_STATUS_AVAILABLE, 0);
-	yahoo_packet_hash(pkt, "ssiii",
-					  1, add_req->id,
-					  5, who,
-					  241, add_req->protocol,
-					  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(struct yahoo_add_request *add_req, const char *msg)
-{
-	struct yahoo_data *yd = add_req->gc->proto_data;
-	struct yahoo_packet *pkt;
-	char *encoded_msg = NULL;
-	PurpleAccount *account = purple_connection_get_account(add_req->gc);
-
-	if (msg && *msg)
-		encoded_msg = yahoo_string_encode(add_req->gc, msg, NULL);
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15,
-			YAHOO_STATUS_AVAILABLE, 0);
-
-	yahoo_packet_hash(pkt, "ssiiis",
-			1, purple_normalize(account, purple_account_get_username(account)),
-			5, add_req->who,
-			13, 2,
-			334, 0,
-			97, 1,
-			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_add_deny_noreason_cb(struct yahoo_add_request *add_req, const char*msg)
-{
-	yahoo_buddy_add_deny_cb(add_req, NULL);
-}
-
-static void
-yahoo_buddy_add_deny_reason_cb(gpointer data) {
-	struct yahoo_add_request *add_req = data;
-	purple_request_input(add_req->gc, NULL, _("Authorization denied message:"),
-			NULL, _("No reason given."), TRUE, FALSE, NULL,
-			_("OK"), G_CALLBACK(yahoo_buddy_add_deny_cb),
-			_("Cancel"), G_CALLBACK(yahoo_buddy_add_deny_noreason_cb),
-			purple_connection_get_account(add_req->gc), add_req->who, NULL,
-			add_req);
-}
-
-static void yahoo_buddy_denied_our_add(PurpleConnection *gc, const char *who, const char *reason)
-{
-	char *notify_msg;
-	struct yahoo_data *yd = gc->proto_data;
-
-	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);
-	g_free(notify_msg);
-
-	g_hash_table_remove(yd->friends, who);
-	purple_prpl_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;
-	int protocol = 0;
-
-	account = purple_connection_get_account(gc);
-
-	/* Buddy authorized/declined our addition */
-	if (pkt->status == 1) {
-		char *temp = NULL;
-		char *who = NULL;
-		int response = 0;
-
-		while (l) {
-			struct yahoo_pair *pair = l->data;
-
-			switch (pair->key) {
-			case 4:
-				temp = pair->value;
-				break;
-			case 13:
-				response = strtol(pair->value, NULL, 10);
-				break;
-			case 14:
-				msg = pair->value;
-				break;
-			case 241:
-				protocol = strtol(pair->value, NULL, 10);
-				break;
-			}
-			l = l->next;
-		}
-
-		if(protocol == 0)
-			who = g_strdup(temp);
-		else if(protocol == 2)
-			who = g_strconcat("msn/", temp, NULL);
-
-		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;
-		char *temp = 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:
-				temp = pair->value;
-				add_req->who = g_strdup(pair->value);
-				break;
-			case 5:
-				add_req->id = g_strdup(pair->value);
-				break;
-			case 14:
-				msg = pair->value;
-				break;
-			case 216:
-				firstname = pair->value;
-				break;
-			case 241:
-				add_req->protocol = strtol(pair->value, NULL, 10);
-				break;
-			case 254:
-				lastname = pair->value;
-				break;
-
-			}
-			l = l->next;
-		}
-		if(add_req->protocol == 2)
-			add_req->who = g_strconcat("msn/", temp, NULL);
-		else
-			add_req->who = g_strdup(temp);
-
-		if (add_req->id && add_req->who) {
-			char *alias = NULL, *dec_msg = NULL;
-
-			if (!purple_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(add_req, NULL);
-				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_find_buddy(account, add_req->who) != NULL,
-					yahoo_buddy_add_authorize_cb,
-					yahoo_buddy_add_deny_reason_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:
-			add_req->id = g_strdup(pair->value);
-			break;
-		case 3:
-			add_req->who = g_strdup(pair->value);
-			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_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(add_req, NULL);
-			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_find_buddy(account,add_req->who) != NULL,
-						yahoo_buddy_add_authorize_cb,
-						yahoo_buddy_add_deny_reason_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:
-			who = pair->value;
-			break;
-		case 14:
-			msg = pair->value;
-			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';
-
-	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);
-	struct yahoo_data *yd = gc->proto_data;
-	const char *who = NULL;
-	const char *email = NULL;
-	const char *subj = NULL;
-	const char *yahoo_mail_url = (yd->jp? YAHOOJP_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)
-			who = pair->value;
-		else if (pair->key == 42)
-			email = pair->value;
-		else if (pair->key == 18)
-			subj = pair->value;
-		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)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	const char *name = purple_normalize(account, purple_account_get_username(account));
-	PurpleCipher *md5_cipher;
-	PurpleCipherContext *md5_ctx;
-	guchar md5_digest[16];
-	gchar base64_string[25];
-	struct yahoo_packet *pkt;
-
-	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage3\n");
-
-	md5_cipher = purple_ciphers_find_cipher("md5");
-	md5_ctx = purple_cipher_context_new(md5_cipher, NULL);
-	purple_cipher_context_append(md5_ctx, (guchar *)crypt, strlen(crypt));
-	purple_cipher_context_digest(md5_ctx, sizeof(md5_digest), md5_digest, NULL);
-
-	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->jp) {
-		yahoo_packet_hash(pkt, "ssssssss",
-					1, name,
-					0, name,
-					277, yd->cookie_y,
-					278, yd->cookie_t,
-					307, base64_string,
-					2, name,
-					2, "1",
-					135, YAHOOJP_CLIENT_VERSION);
-	} else	{
-		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",
-					135, YAHOO_CLIENT_VERSION);
-	}
-	if (yd->picture_checksum)
-		yahoo_packet_hash_int(pkt, 192, yd->picture_checksum);
-	yahoo_packet_send_and_free(pkt, yd);
-
-	purple_cipher_context_destroy(md5_ctx);
-}
-
-static void yahoo_auth16_stage2(PurpleUtilFetchUrlData *unused, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message)
-{
-	struct yahoo_auth_data *auth_data = user_data;
-	PurpleConnection *gc = auth_data->gc;
-	struct yahoo_data *yd;
-	gboolean try_login_on_error = FALSE;
-
-	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage2\n");
-
-	if (!PURPLE_CONNECTION_IS_VALID(gc)) {
-		g_free(auth_data->seed);
-		g_free(auth_data);
-		g_return_if_reached();
-	}
-
-	yd = (struct yahoo_data *)gc->proto_data;
-
-	if (error_message != NULL) {
-		purple_debug_error("yahoo", "Login Failed, unable to retrieve stage 2 url: %s\n", error_message);
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
-		g_free(auth_data->seed);
-		g_free(auth_data);
-		return;
-	}
-	else if (len > 0 && ret_data && *ret_data) {
-		gchar **split_data = g_strsplit(ret_data, "\r\n", -1);
-		int totalelements = 0;
-		int response_no = -1;
-		char *crumb = NULL;
-		char *crypt = NULL;
-
-#if GLIB_CHECK_VERSION(2,6,0)
-		totalelements = g_strv_length(split_data);
-#else
-		while (split_data[++totalelements] != NULL);
-#endif
-		if (totalelements >= 4) {
-			response_no = strtol(split_data[0], NULL, 10);
-			crumb = g_strdup(split_data[1] + strlen("crumb="));
-			yd->cookie_y = g_strdup(split_data[2] + strlen("Y="));
-			yd->cookie_t = g_strdup(split_data[3] + strlen("T="));
-		}
-
-		g_strfreev(split_data);
-
-		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)) {
-						try_login_on_error = TRUE;
-						break;
-					}
-					error_reason = g_strdup(_("Unknown error"));
-					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-					break;
-			}
-			if(error_reason) {
-				purple_debug_error("yahoo", "Authentication error: %s\n",
-				                   error_reason);
-				purple_connection_error_reason(gc, error, error_reason);
-				g_free(error_reason);
-				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(PurpleUtilFetchUrlData *unused, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message)
-{
-	struct yahoo_auth_data *auth_data = user_data;
-	PurpleConnection *gc = auth_data->gc;
-
-	purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage1_cb\n");
-
-	if (!PURPLE_CONNECTION_IS_VALID(gc)) {
-		g_free(auth_data->seed);
-		g_free(auth_data);
-		g_return_if_reached();
-	}
-
-	if (error_message != NULL) {
-		purple_debug_error("yahoo", "Login Failed, unable to retrieve login url: %s\n", error_message);
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
-		g_free(auth_data->seed);
-		g_free(auth_data);
-		return;
-	}
-	else if (len > 0 && ret_data && *ret_data) {
-		gchar **split_data = g_strsplit(ret_data, "\r\n", -1);
-		int totalelements = 0;
-		int response_no = -1;
-		char *token = NULL;
-
-#if GLIB_CHECK_VERSION(2,6,0)
-		totalelements = g_strv_length(split_data);
-#else
-		while (split_data[++totalelements] != NULL);
-#endif
-		if(totalelements == 1)
-			response_no = strtol(split_data[0], NULL, 10);
-		else if(totalelements >= 2) {
-			response_no = strtol(split_data[0], NULL, 10);
-			token = g_strdup(split_data[1] + strlen("ymsgr="));
-		}
-
-		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(purple_connection_get_account(gc)))
-						purple_account_set_password(purple_connection_get_account(gc), 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.\nLogging 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:
-				case 1236:
-					/* indicates a lock of some description */
-					error_reason = g_strdup(_("Account locked: Unknown reason.\nLogging into the Yahoo! website may fix this."));
-					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(_("Unknown error"));
-					error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
-					break;
-			}
-			purple_debug_error("yahoo", "Authentication error: %s\n",
-			                   error_reason);
-			purple_connection_error_reason(gc, error, error_reason);
-			g_free(error_reason);
-			g_free(auth_data->seed);
-			g_free(auth_data);
-		}
-		else {
-			/* OK to login, correct information provided */
-			PurpleUtilFetchUrlData *url_data = NULL;
-			char *url = NULL;
-			gboolean yahoojp = purple_account_get_bool(purple_connection_get_account(gc),
-				"yahoojp", 0);
-
-			url = g_strdup_printf(yahoojp ? YAHOOJP_LOGIN_URL : YAHOO_LOGIN_URL, token);
-			url_data = purple_util_fetch_url_request_len_with_account(
-					purple_connection_get_account(gc), url, TRUE,
-					YAHOO_CLIENT_USERAGENT, TRUE, NULL, FALSE, -1,
-					yahoo_auth16_stage2, auth_data);
-			g_free(url);
-			g_free(token);
-		}
-	}
-}
-
-static void yahoo_auth16_stage1(PurpleConnection *gc, const char *seed)
-{
-	PurpleUtilFetchUrlData *url_data = NULL;
-	struct yahoo_auth_data *auth_data = NULL;
-	char *url = NULL;
-	char *encoded_username;
-	char *encoded_password;
-	gboolean yahoojp;
-
-	purple_debug_info("yahoo", "Authentication: In yahoo_auth16_stage1\n");
-
-	if(!purple_ssl_is_supported()) {
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, _("SSL support unavailable"));
-		return;
-	}
-
-	yahoojp =  purple_account_get_bool(purple_connection_get_account(gc),
-			"yahoojp", 0);
-	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)));
-	url = g_strdup_printf(yahoojp ? YAHOOJP_TOKEN_URL : YAHOO_TOKEN_URL,
-			encoded_username, encoded_password, purple_url_encode(seed));
-	g_free(encoded_password);
-	g_free(encoded_username);
-
-	url_data = purple_util_fetch_url_request_len_with_account(
-			purple_connection_get_account(gc), url, TRUE,
-			YAHOO_CLIENT_USERAGENT, TRUE, NULL, FALSE, -1,
-			yahoo_auth16_stage1_cb, auth_data);
-
-	g_free(url);
-}
-
-static void yahoo_process_auth(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	char *seed = NULL;
-	char *sn   = NULL;
-	GSList *l = pkt->hash;
-	int m = 0;
-	gchar *buf;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-		if (pair->key == 94)
-			seed = pair->value;
-		if (pair->key == 1)
-			sn = pair->value;
-		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);
-				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);
-
-	serv_add_deny(purple_account_get_connection(account), name);
-
-	g_free(name);
-}
-
-static void keep_buddy(PurpleBuddy *b)
-{
-	purple_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 *me = 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:
-			who = pair->value;
-			break;
-		case 1:
-			me = pair->value;
-			break;
-		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_find_buddy(gc->account, 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,
-									  gc->account, who, NULL,
-									  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.",
-							  who);
-			break;
-		case 3:
-			purple_debug_info("yahoo", "Server reported that %s is not in the ignore list; could not delete",
-							  who);
-		case 0:
-		default:
-			break;
-	}
-}
-
-static void yahoo_process_authresp(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-#ifdef TRY_WEBMESSENGER_LOGIN
-	struct yahoo_data *yd = gc->proto_data;
-#endif /* TRY_WEBMESSENGER_LOGIN */
-	GSList *l = pkt->hash;
-	int err = 0;
-	char *msg;
-	char *url = NULL;
-	char *fullmsg;
-	PurpleAccount *account = gc->account;
-	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)
-			url = pair->value;
-
-		l = l->next;
-	}
-
-	switch (err) {
-	case 0:
-		msg = g_strdup(_("Unknown error."));
-		reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
-		break;
-	case 3:
-		msg = g_strdup(_("Invalid username."));
-		reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
-		break;
-	case 13:
-#ifdef TRY_WEBMESSENGER_LOGIN
-		if (!yd->wm) {
-			PurpleUtilFetchUrlData *url_data;
-			yd->wm = TRUE;
-			if (yd->fd >= 0)
-				close(yd->fd);
-			if (gc->inpa)
-				purple_input_remove(gc->inpa);
-			url_data = purple_util_fetch_url(WEBMESSENGER_URL, TRUE,
-					"Purple/" VERSION, FALSE, yahoo_login_page_cb, gc);
-			if (url_data != NULL)
-				yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
-			return;
-		}
-#endif /* TRY_WEBMESSENGER_LOGIN */
-		if (!purple_account_get_remember_password(account))
-			purple_account_set_password(account, NULL);
-
-		msg = g_strdup(_("Incorrect password."));
-		reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
-		break;
-	case 14:
-		msg = g_strdup(_("Your account is locked, please log in to the Yahoo! website."));
-		reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
-		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_reason(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;
-	struct yahoo_data *yd = gc->proto_data;
-	int protocol = 0;
-	gboolean msn = FALSE;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 66:
-			err = strtol(pair->value, NULL, 10);
-			break;
-		case 7:
-			temp = pair->value;
-			break;
-		case 65:
-			group = pair->value;
-			break;
-		case 241:
-			protocol = strtol(pair->value, NULL, 10);
-			if(protocol == 2)
-				msn = TRUE;
-			break;
-		}
-
-		l = l->next;
-	}
-
-	if (!temp)
-		return;
-	if (!group)
-		group = "";
-
-	if(msn)
-		who = g_strconcat("msn/", temp, NULL);
-	else
-		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(protocol)
-			f->protocol = protocol;
-
-		if( !g_hash_table_lookup(yd->peers, who) ) {
-			/* we are not connected as client, so set friend to not connected */
-			if(msn)
-				yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT);
-			else	{
-				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(_("Could not add buddy %s to group %s to the server list on account %s."),
-				who, decoded_group, purple_connection_get_display_name(gc));
-	if (!purple_conv_present_error(who, purple_connection_get_account(gc), buf))
-		purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf);
-	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;
-	guchar *raw_packet;
-
-	/*build the raw packet and send it to the host*/
-	pkt_len = yahoo_packet_build(pkt, 0, 0, 0, &raw_packet);
-	if(write(source, raw_packet, pkt_len) != 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;
-	struct yahoo_data *yd = gc->proto_data;
-
-	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;
-	struct yahoo_data *yd = gc->proto_data;
-
-	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);
-	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;
-	struct yahoo_data *yd;
-	YahooFriend *f;
-
-	if(!(p2p_data = data))
-		return ;
-
-	yd = p2p_data->gc->proto_data;
-
-	/* lets see whats in the packet */
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 4:
-			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;
-			}
-			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 = NULL;
-	struct yahoo_p2p_data *p2p_data;
-	struct yahoo_data *yd;
-
-	if(!(p2p_data = data))
-		return ;
-	yd = p2p_data->gc->proto_data;
-
-	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;
-	}
-
-	if(len < YAHOO_PACKET_HDRLEN)
-		return;
-
-	if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) {
-		/* Not a YMSG packet */
-		purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
-
-		start = memchr(buf + 1, 'Y', len - 1);
-		if (start == NULL)
-			return;
-
-		g_memmove(buf, start, len - (start - buf));
-		len -= start - buf;
-	}
-
-	pos += 4;	/* YMSG */
-	pos += 2;
-	pos += 2;
-
-	pktlen = yahoo_get16(buf + pos); pos += 2;
-	purple_debug_misc("yahoo", "p2p: %d bytes to read\n", len);
-
-	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;
-	struct yahoo_data *yd;
-
-	if(!(p2p_data = data))
-		return ;
-	yd = p2p_data->gc->proto_data;
-
-	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;
-	struct yahoo_data *yd;
-
-	if(!(p2p_data = data))
-		return FALSE;
-
-	yd = p2p_data->gc->proto_data;
-
-	purple_debug_warning("yahoo","yahoo p2p server timeout, peer failed to connect");
-	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;
-	struct yahoo_data *yd;
-
-	if(!(p2p_data = data))
-		return ;
-
-	if(listenfd == -1) {
-		purple_debug_warning("yahoo","p2p: error starting p2p server\n");
-		yahoo_p2p_disconnect_destroy_data(data);
-		return;
-	}
-
-	yd = p2p_data->gc->proto_data;
-
-	/* 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;
-	struct yahoo_data *yd = gc->proto_data;
-	struct yahoo_p2p_data *p2p_data;
-
-	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;
-
-	/* Dont send p2p packet to buddies of other protocols */
-	if(f->protocol)
-		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) );
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_PEERTOPEER, YAHOO_STATUS_AVAILABLE, 0);
-	yahoo_packet_hash(pkt, "sssissis",
-		1, purple_normalize(account, purple_account_get_username(account)),
-		4, purple_normalize(account, purple_account_get_username(account)),
-		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;
-
-	purple_network_listen(YAHOO_PAGER_PORT_P2P, SOCK_STREAM, yahoo_p2p_server_listen_cb, p2p_data);
-
-	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;
-	struct yahoo_data *yd;
-
-	if(!(p2p_data = data))
-		return ;
-	yd = p2p_data->gc->proto_data;
-
-	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 1 ie YAHOO_STATUS_BRB, the packet bounced back, so contains our own ip */
-	if(!(pkt->status == YAHOO_STATUS_BRB))
-		return ;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 5:
-			/* our identity */
-			break;
-		case 4:
-			who = pair->value;
-			break;
-		case 1:
-			/* who again, the master identity this time? */
-			break;
-		case 12:
-			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?*/
-			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;
-		struct yahoo_p2p_data *p2p_data;
-
-		decoded = purple_base64_decode(base64, &len);
-		if (len) {
-			char *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:
-			who = pair->value;
-			break;
-		case 5:
-			/* us */
-			break;
-		case 230:
-			/* the audible, in foo.locale.bar.baz format
-			   eg: base.tw.smiley.smiley43 */
-			id = pair->value;
-			break;
-		case 231:
-			/* the text of the audible */
-			msg = pair->value;
-			break;
-		case 232:
-			/* weird number (md5 hash?), like 8ebab9094156135f5dcbaccbeee662a5c5fd1420 */
-			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_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://us.dl1.yimg.com/download.yahoo.com/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);
-
-		serv_got_im(gc, who, buf, 0, time(NULL));
-		g_free(buf);
-	} else
-		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:
-		yahoo_process_filetransfer(gc, pkt);
-		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_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;
-	struct yahoo_data *yd = gc->proto_data;
-	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:\n%s"),
-				g_strerror(errno));
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	} else if (len == 0) {
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Server closed the connection."));
-		return;
-	}
-	gc->last_received = time(NULL);
-	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;
-	struct yahoo_data *yd;
-	struct yahoo_packet *pkt;
-
-	if (source < 0) {
-		gchar *tmp;
-		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
-				error_message);
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	}
-
-	yd = gc->proto_data;
-	yd->fd = source;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, yd->current_status, 0);
-
-	yahoo_packet_hash_str(pkt, 1, purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))));
-	yahoo_packet_send_and_free(pkt, yd);
-
-	gc->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc);
-}
-
-#ifdef TRY_WEBMESSENGER_LOGIN
-static void yahoo_got_web_connected(gpointer data, gint source, const gchar *error_message)
-{
-	PurpleConnection *gc = data;
-	struct yahoo_data *yd;
-	struct yahoo_packet *pkt;
-
-	if (source < 0) {
-		gchar *tmp;
-		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
-				error_message);
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	}
-
-	yd = gc->proto_data;
-	yd->fd = source;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_WEBLOGIN, YAHOO_STATUS_WEBLOGIN, 0);
-
-	yahoo_packet_hash(pkt, "sss", 0,
-	                  purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))),
-	                  1, purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))),
-	                  6, yd->auth);
-	yahoo_packet_send_and_free(pkt, yd);
-
-	g_free(yd->auth);
-	gc->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc);
-}
-
-static void yahoo_web_pending(gpointer data, gint source, PurpleInputCondition cond)
-{
-	PurpleConnection *gc = data;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	struct yahoo_data *yd = gc->proto_data;
-	char bufread[2048], *i = bufread, *buf = bufread;
-	int len;
-	GString *s;
-
-	len = read(source, bufread, sizeof(bufread) - 1);
-
-	if (len < 0) {
-		gchar *tmp;
-
-		if (errno == EAGAIN)
-			/* No worries */
-			return;
-
-		tmp = g_strdup_printf(_("Lost connection with server:\n%s"),
-				g_strerror(errno));
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	} else if (len == 0) {
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Server closed the connection."));
-		return;
-	}
-
-	if (yd->rxlen > 0 || !g_strstr_len(buf, len, "\r\n\r\n")) {
-		yd->rxqueue = g_realloc(yd->rxqueue, yd->rxlen + len + 1);
-		memcpy(yd->rxqueue + yd->rxlen, buf, len);
-		yd->rxlen += len;
-		i = buf = (char *)yd->rxqueue;
-		len = yd->rxlen;
-	}
-	buf[len] = '\0';
-
-	if ((strncmp(buf, "HTTP/1.0 302", strlen("HTTP/1.0 302")) &&
-			  strncmp(buf, "HTTP/1.1 302", strlen("HTTP/1.1 302")))) {
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Received unexpected HTTP response from server."));
-		purple_debug_misc("yahoo", "Unexpected HTTP response: %s\n", buf);
-		return;
-	}
-
-	s = g_string_sized_new(len);
-
-	while ((i = strstr(i, "Set-Cookie: "))) {
-
-		i += strlen("Set-Cookie: ");
-		for (;*i != ';' && *i != '\0'; i++)
-			g_string_append_c(s, *i);
-
-		g_string_append(s, "; ");
-		/* Should these cookies be included too when trying for xfer?
-		 * It seems to work without these
-		 */
-	}
-
-	yd->auth = g_string_free(s, FALSE);
-	purple_input_remove(gc->inpa);
-	close(source);
-	g_free(yd->rxqueue);
-	yd->rxqueue = NULL;
-	yd->rxlen = 0;
-	/* Now we have our cookies to login with.  I'll go get the milk. */
-	if (purple_proxy_connect(gc, account, "wcs2.msg.dcn.yahoo.com",
-	                         purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
-	                         yahoo_got_web_connected, gc) == NULL) {
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-		                               _("Connection problem"));
-		return;
-	}
-}
-
-static void yahoo_got_cookies_send_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
-	PurpleConnection *gc;
-	struct yahoo_data *yd;
-	int written, remaining;
-
-	gc = data;
-	yd = gc->proto_data;
-
-	remaining = strlen(yd->auth) - yd->auth_written;
-	written = write(source, yd->auth + yd->auth_written, remaining);
-
-	if (written < 0 && errno == EAGAIN)
-		written = 0;
-	else if (written <= 0) {
-		gchar *tmp;
-		g_free(yd->auth);
-		yd->auth = NULL;
-		if (gc->inpa)
-			purple_input_remove(gc->inpa);
-		gc->inpa = 0;
-		tmp = g_strdup_printf(_("Lost connection with %s:\n%s"),
-				"login.yahoo.com:80", g_strerror(errno));
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	}
-
-	if (written < remaining) {
-		yd->auth_written += written;
-		return;
-	}
-
-	g_free(yd->auth);
-	yd->auth = NULL;
-	yd->auth_written = 0;
-	purple_input_remove(gc->inpa);
-	gc->inpa = purple_input_add(source, PURPLE_INPUT_READ, yahoo_web_pending, gc);
-}
-
-static void yahoo_got_cookies(gpointer data, gint source, const gchar *error_message)
-{
-	PurpleConnection *gc = data;
-
-	if (source < 0) {
-		gchar *tmp;
-		tmp = g_strdup_printf(_("Could not establish a connection with %s:\n%s"),
-				"login.yahoo.com:80", error_message);
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	}
-
-	if (gc->inpa == 0)
-	{
-		gc->inpa = purple_input_add(source, PURPLE_INPUT_WRITE,
-			yahoo_got_cookies_send_cb, gc);
-		yahoo_got_cookies_send_cb(gc, source, PURPLE_INPUT_WRITE);
-	}
-}
-
-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(PurpleUtilFetchUrlData *url_data, gpointer user_data,
-		const gchar *url_text, size_t len, const gchar *error_message)
-{
-	PurpleConnection *gc = (PurpleConnection *)user_data;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	struct yahoo_data *yd = gc->proto_data;
-	const char *sn = purple_account_get_username(account);
-	const char *pass = purple_connection_get_password(gc);
-	GHashTable *hash = yahoo_login_page_hash(url_text, len);
-	GString *url = g_string_new("GET http://login.yahoo.com/config/login?login=");
-	char md5[33], *hashp = md5, *chal;
-	int i;
-	PurpleCipher *cipher;
-	PurpleCipherContext *context;
-	guchar digest[16];
-
-	yd->url_datas = g_slist_remove(yd->url_datas, url_data);
-
-	if (error_message != NULL)
-	{
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-		                               error_message);
-		return;
-	}
-
-	url = g_string_append(url, sn);
-	url = g_string_append(url, "&passwd=");
-
-	cipher = purple_ciphers_find_cipher("md5");
-	context = purple_cipher_context_new(cipher, NULL);
-
-	purple_cipher_context_append(context, (const guchar *)pass, strlen(pass));
-	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
-	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_context_reset(context, NULL);
-	purple_cipher_context_append(context, (const guchar *)chal, strlen(chal));
-	purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
-	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_context_reset(context, NULL);
-	purple_cipher_context_append(context, md5, strlen(md5));
-	purple_cipher_context_digest(context, 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_append(url, md5);
-	g_hash_table_foreach(hash, (GHFunc)yahoo_login_page_hash_iter, url);
-
-	url = g_string_append(url, "&.hash=1&.md5=1 HTTP/1.1\r\n"
-			      "Host: login.yahoo.com\r\n\r\n");
-	g_hash_table_destroy(hash);
-	yd->auth = g_string_free(url, FALSE);
-	if (purple_proxy_connect(gc, account, "login.yahoo.com", 80, yahoo_got_cookies, gc) == NULL) {
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-		                               _("Connection problem"));
-		return;
-	}
-
-	purple_cipher_context_destroy(context);
-}
-#endif /* TRY_WEBMESSENGER_LOGIN */
-
-static void yahoo_server_check(PurpleAccount *account)
-{
-	const char *server;
-
-	server = purple_account_get_string(account, "server", YAHOO_PAGER_HOST);
-
-	if (*server == '\0' || g_str_equal(server, "scs.yahoo.com") ||
-			g_str_equal(server, "scs.msg.yahoo.com"))
-		purple_account_set_string(account, "server", YAHOO_PAGER_HOST);
-}
-
-static void yahoo_picture_check(PurpleAccount *account)
-{
-	PurpleConnection *gc = purple_account_get_connection(account);
-	PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account);
-
-	yahoo_set_buddy_icon(gc, img);
-	purple_imgstore_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 (!strcmp(status_id, YAHOO_STATUS_TYPE_AVAILABLE)) {
-		if ((msg != NULL) && (*msg != '\0'))
-			return YAHOO_STATUS_CUSTOM;
-		else
-			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_login(PurpleAccount *account) {
-	PurpleConnection *gc = purple_account_get_connection(account);
-	struct yahoo_data *yd = gc->proto_data = g_new0(struct yahoo_data, 1);
-	PurpleStatus *status = purple_account_get_active_status(account);
-	gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_NO_URLDESC;
-
-	purple_connection_update_progress(gc, _("Connecting"), 1, 2);
-
-	purple_connection_set_display_name(gc, purple_account_get_username(account));
-
-	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_circ_buffer_new(0);
-	yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free);
-	yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-	yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
-	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_server_check(account);
-	yahoo_picture_check(account);
-
-	if (purple_account_get_bool(account, "yahoojp", FALSE)) {
-		yd->jp = TRUE;
-		if (purple_proxy_connect(gc, account,
-		                       purple_account_get_string(account, "serverjp",  YAHOOJP_PAGER_HOST),
-		                       purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
-		                       yahoo_got_connected, gc) == NULL)
-		{
-			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			                               _("Connection problem"));
-			return;
-		}
-	} else {
-		yd->jp = FALSE;
-		if (purple_proxy_connect(gc, account,
-		                       purple_account_get_string(account, "server",  YAHOO_PAGER_HOST),
-		                       purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
-		                       yahoo_got_connected, gc) == NULL)
-		{
-			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			                               _("Connection problem"));
-			return;
-		}
-	}
-}
-
-static void yahoo_close(PurpleConnection *gc) {
-	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
-	GSList *l;
-
-	if (gc->inpa)
-		purple_input_remove(gc->inpa);
-
-	while (yd->url_datas) {
-		purple_util_fetch_url_cancel(yd->url_datas->data);
-		yd->url_datas = g_slist_delete_link(yd->url_datas, yd->url_datas);
-	}
-
-	for (l = yd->confs; l; l = l->next) {
-		PurpleConversation *conv = l->data;
-
-		yahoo_conf_leave(yd, purple_conversation_get_name(conv),
-		                 purple_connection_get_display_name(gc),
-				 purple_conv_chat_get_users(PURPLE_CONV_CHAT(conv)));
-	}
-	g_slist_free(yd->confs);
-
-	for (l = yd->cookies; l; l = l->next) {
-		g_free(l->data);
-		l->data=NULL;
-	}
-	g_slist_free(yd->cookies);
-
-	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);
-
-	if (yd->txhandler)
-		purple_input_remove(yd->txhandler);
-
-	purple_circ_buffer_destroy(yd->txbuf);
-
-	if (yd->fd >= 0)
-		close(yd->fd);
-
-	g_free(yd->rxqueue);
-	yd->rxlen = 0;
-	g_free(yd->picture_url);
-
-	if (yd->buddy_icon_connect_data)
-		purple_proxy_connect_cancel(yd->buddy_icon_connect_data);
-	if (yd->picture_upload_todo)
-		yahoo_buddy_icon_upload_data_free(yd->picture_upload_todo);
-	if (yd->ycht)
-		ycht_connection_close(yd->ycht);
-
-	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);
-
-	g_free(yd->current_list15_grp);
-
-	g_free(yd);
-	gc->proto_data = NULL;
-}
-
-static const char *yahoo_list_icon(PurpleAccount *a, PurpleBuddy *b)
-{
-	return "yahoo";
-}
-
-static const char *yahoo_list_emblem(PurpleBuddy *b)
-{
-	PurpleAccount *account;
-	PurpleConnection *gc;
-	struct yahoo_data *yd;
-	YahooFriend *f;
-	PurplePresence *presence;
-
-	if (!b || !(account = purple_buddy_get_account(b)) ||
-			!(gc = purple_account_get_connection(account)) ||
-			!(yd = gc->proto_data))
-		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";
-		if (f->protocol == 2)
-			return "msn";
-	}
-	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;
-	struct yahoo_data *yd;
-	int id;
-
-	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-	yd = gc->proto_data;
-	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;
-
-	struct yahoo_data *yd;
-	const char *game;
-	char *game2;
-	char *t;
-	char url[256];
-	YahooFriend *f;
-
-	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-	yd = (struct yahoo_data *) gc->proto_data;
-
-	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);
-}
-
-static char *yahoo_status_text(PurpleBuddy *b)
-{
-	YahooFriend *f = NULL;
-	const char *msg;
-	char *msg2;
-	PurpleAccount *account;
-
-	account = purple_buddy_get_account(b);
-	f = yahoo_friend_find(purple_account_get_connection(account), 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 *escaped;
-	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) {
-		escaped = g_markup_escape_text(status, strlen(status));
-		purple_notify_user_info_add_pair(user_info, _("Status"), escaped);
-		g_free(status);
-		g_free(escaped);
-	}
-
-	if (presence != NULL)
-		purple_notify_user_info_add_pair(user_info, _("Presence"), presence);
-}
-
-static void yahoo_addbuddyfrommenu_cb(PurpleBlistNode *node, gpointer data)
-{
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-
-	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (PurpleBuddy *) node;
-	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-
-	yahoo_add_buddy(gc, buddy, NULL);
-}
-
-
-static void yahoo_chat_goto_menu(PurpleBlistNode *node, gpointer data)
-{
-	PurpleBuddy *buddy;
-	PurpleConnection *gc;
-
-	g_return_if_fail(PURPLE_BLIST_NODE_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;
-	struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data;
-
-	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));
-}
-
-static GList *yahoo_buddy_menu(PurpleBuddy *buddy)
-{
-	GList *m = NULL;
-	PurpleMenuAction *act;
-
-	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-	struct yahoo_data *yd = gc->proto_data;
-	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);
-	}
-
-	if (f) {
-		act = purple_menu_action_new(_("Start Doodling"),
-		                           PURPLE_CALLBACK(yahoo_doodle_blist_node),
-		                           NULL, NULL);
-		m = g_list_append(m, act);
-	}
-
-	return m;
-}
-
-static GList *yahoo_blist_node_menu(PurpleBlistNode *node)
-{
-	if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
-		return yahoo_buddy_menu((PurpleBuddy *) node);
-	} else {
-		return NULL;
-	}
-}
-
-static void yahoo_act_id(PurpleConnection *gc, PurpleRequestFields *fields)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	const char *name = yd->profiles[purple_request_fields_get_choice(fields, "id")];
-
-	struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_IDACT, YAHOO_STATUS_AVAILABLE, 0);
-	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(PurpleUtilFetchUrlData *url_data, gpointer user_data,
-		const gchar *token, size_t len, const gchar *error_message)
-{
-	PurpleConnection *gc = user_data;
-	gboolean set_cookie = FALSE;
-	gchar *url;
-	struct yahoo_data *yd = gc->proto_data;
-
-	g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc));
-
-	yd->url_datas = g_slist_remove(yd->url_datas, url_data);
-
-	if (error_message != NULL)
-		purple_debug_error("yahoo", "Requesting mail login token failed: %s\n", error_message);
-	else if (len > 0 && token && *token) {
-	 	/* Should we not be hardcoding the rd url? */
-		url = g_strdup_printf(
-			"http://login.yahoo.com/config/reset_cookies_token?"
-			".token=%s"
-			"&.done=http://us.rd.yahoo.com/messenger/client/%%3fhttp://mail.yahoo.com/",
-			token);
-		set_cookie = TRUE;
-	}
-
-	if (!set_cookie) {
-		purple_debug_error("yahoo", "No mail login token; forwarding to login screen.\n");
-		url = g_strdup(yd->jp ? YAHOOJP_MAIL_URL : YAHOO_MAIL_URL);
-	}
-
-	/* Open the mailbox with the parsed url data */
-	purple_notify_uri(gc, url);
-
-	g_free(url);
-}
-
-
-static void yahoo_show_inbox(PurplePluginAction *action)
-{
-	/* Setup a cookie that can be used by the browser */
-	/* XXX I have no idea how this will work with Yahoo! Japan. */
-
-	PurpleConnection *gc = action->context;
-	struct yahoo_data *yd = gc->proto_data;
-
-	PurpleUtilFetchUrlData *url_data;
-	const char* base_url = "http://login.yahoo.com";
-	/* use whole URL if using HTTP Proxy */
-	gboolean use_whole_url = yahoo_account_use_http_proxy(gc);
-	gchar *request = g_strdup_printf(
-		"POST %s/config/cookie_token HTTP/1.0\r\n"
-		"Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s;\r\n"
-		"User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
-		"Host: login.yahoo.com\r\n"
-		"Content-Length: 0\r\n\r\n",
-		use_whole_url ? base_url : "",
-		yd->cookie_t, yd->cookie_y);
-
-	url_data = purple_util_fetch_url_request_len_with_account(
-			purple_connection_get_account(gc), base_url, use_whole_url,
-			YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1,
-			yahoo_get_inbox_token_cb, gc);
-
-	g_free(request);
-
-	if (url_data != NULL)
-		yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
-	else {
-		const char *yahoo_mail_url = (yd->jp ? YAHOOJP_MAIL_URL : YAHOO_MAIL_URL);
-		purple_debug_error("yahoo",
-				   "Unable to request mail login token; forwarding to login screen.");
-		purple_notify_uri(gc, yahoo_mail_url);
-	}
-
-}
-
-
-static void yahoo_show_act_id(PurplePluginAction *action)
-{
-	PurpleRequestFields *fields;
-	PurpleRequestFieldGroup *group;
-	PurpleRequestField *field;
-	PurpleConnection *gc = (PurpleConnection *) action->context;
-	struct yahoo_data *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]);
-		if (purple_strequal(yd->profiles[iter], name))
-			purple_request_field_choice_set_default_value(field, iter);
-	}
-
-	purple_request_fields(gc, NULL, _("Select the ID you want to activate"), NULL,
-					   fields,
-					   _("OK"), G_CALLBACK(yahoo_act_id),
-					   _("Cancel"), NULL,
-					   purple_connection_get_account(gc), NULL, NULL,
-					   gc);
-}
-
-static void yahoo_show_chat_goto(PurplePluginAction *action)
-{
-	PurpleConnection *gc = (PurpleConnection *) action->context;
-	purple_request_input(gc, NULL, _("Join whom in chat?"), NULL,
-					   "", FALSE, FALSE, NULL,
-					   _("OK"), G_CALLBACK(yahoo_chat_goto),
-					   _("Cancel"), NULL,
-					   purple_connection_get_account(gc), NULL, NULL,
-					   gc);
-}
-
-static GList *yahoo_actions(PurplePlugin *plugin, gpointer context) {
-	GList *m = NULL;
-	PurplePluginAction *act;
-
-	act = purple_plugin_action_new(_("Activate ID..."),
-			yahoo_show_act_id);
-	m = g_list_append(m, act);
-
-	act = purple_plugin_action_new(_("Join User in Chat..."),
-			yahoo_show_chat_goto);
-	m = g_list_append(m, act);
-
-	m = g_list_append(m, NULL);
-	act = purple_plugin_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 int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags);
-
-static void yahoo_get_sms_carrier_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
-		const gchar *webdata, size_t len, const gchar *error_message)
-{
-	struct yahoo_sms_carrier_cb_data *sms_cb_data = user_data;
-	PurpleConnection *gc = sms_cb_data->gc;
-	struct yahoo_data *yd = gc->proto_data;
-	char *mobile_no = NULL;
-	char *status = NULL;
-	char *carrier = NULL;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
-
-	if (error_message != NULL) {
-		purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
-
-		g_free(sms_cb_data->who);
-		g_free(sms_cb_data->what);
-		g_free(sms_cb_data);
-		return ;
-	}
-	else if (len > 0 && webdata && *webdata) {
-		xmlnode *validate_data_root = xmlnode_from_str(webdata, -1);
-		xmlnode *validate_data_child = xmlnode_get_child(validate_data_root, "mobile_no");
-		mobile_no = (char *)xmlnode_get_attrib(validate_data_child, "msisdn");
-
-		validate_data_root = xmlnode_copy(validate_data_child);
-		validate_data_child = xmlnode_get_child(validate_data_root, "status");
-		status = xmlnode_get_data(validate_data_child);
-
-		validate_data_child = xmlnode_get_child(validate_data_root, "carrier");
-		carrier = xmlnode_get_data(validate_data_child);
-
-		purple_debug_info("yahoo","SMS validate data: Mobile:%s, Status:%s, Carrier:%s\n", mobile_no, status, carrier);
-
-		if( strcmp(status, "Valid") == 0) {
-			g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup(carrier));
-			yahoo_send_im(sms_cb_data->gc, sms_cb_data->who, sms_cb_data->what, PURPLE_MESSAGE_SEND);
-		}
-		else	{
-			g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup("Unknown"));
-			purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
-		}
-
-		xmlnode_free(validate_data_child);
-		xmlnode_free(validate_data_root);
-		g_free(sms_cb_data->who);
-		g_free(sms_cb_data->what);
-		g_free(sms_cb_data);
-		g_free(mobile_no);
-		g_free(status);
-		g_free(carrier);
-	}
-}
-
-static void yahoo_get_sms_carrier(PurpleConnection *gc, gpointer data)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	PurpleUtilFetchUrlData *url_data;
-	struct yahoo_sms_carrier_cb_data *sms_cb_data;
-	char *validate_request_str = NULL;
-	char *request = NULL;
-	gboolean use_whole_url = FALSE;
-	xmlnode *validate_request_root = NULL;
-	xmlnode *validate_request_child = NULL;
-
-	if(!(sms_cb_data = data))
-		return;
-
-	validate_request_root = xmlnode_new("validate");
-	xmlnode_set_attrib(validate_request_root, "intl", "us");
-	xmlnode_set_attrib(validate_request_root, "version", YAHOO_CLIENT_VERSION);
-	xmlnode_set_attrib(validate_request_root, "qos", "0");
-
-	validate_request_child = xmlnode_new_child(validate_request_root, "mobile_no");
-	xmlnode_set_attrib(validate_request_child, "msisdn", sms_cb_data->who + 1);
-
-	validate_request_str = xmlnode_to_str(validate_request_root, NULL);
-
-	xmlnode_free(validate_request_child);
-	xmlnode_free(validate_request_root);
-
-	request = g_strdup_printf(
-		"POST /mobileno?intl=us&version=%s HTTP/1.1\r\n"
-		"Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s; path=/; domain=.yahoo.com;\r\n"
-		"User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
-		"Host: validate.msg.yahoo.com\r\n"
-		"Content-Length: %" G_GSIZE_FORMAT "\r\n"
-		"Cache-Control: no-cache\r\n\r\n%s",
-		YAHOO_CLIENT_VERSION, yd->cookie_t, yd->cookie_y, strlen(validate_request_str), validate_request_str);
-
-	/* use whole URL if using HTTP Proxy */
-	if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP))
-	    use_whole_url = TRUE;
-
-	url_data = purple_util_fetch_url_request_len_with_account(
-			purple_connection_get_account(gc), YAHOO_SMS_CARRIER_URL, use_whole_url,
-			YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1,
-			yahoo_get_sms_carrier_cb, data);
-
-	g_free(request);
-	g_free(validate_request_str);
-
-	if (!url_data) {
-		PurpleAccount *account = purple_connection_get_account(gc);
-		PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
-		purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
-		g_free(sms_cb_data->who);
-		g_free(sms_cb_data->what);
-		g_free(sms_cb_data);
-	}
-}
-
-static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	struct yahoo_packet *pkt = NULL;
-	char *msg = yahoo_html_to_codes(what);
-	char *msg2;
-	gboolean utf8 = TRUE;
-	PurpleWhiteboard *wb;
-	int ret = 1;
-	YahooFriend *f = NULL;
-	gsize lenb = 0;
-	glong lenc = 0;
-	struct yahoo_p2p_data *p2p_data;
-	gboolean msn = FALSE;
-	msg2 = yahoo_string_encode(gc, msg, &utf8);
-
-	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;
-		}
-	}
-
-	msn = !g_strncasecmp(who, "msn/", 4);
-
-	if( strncmp(who, "+", 1) == 0 ) {
-		/* we have an sms to be sent */
-		gchar *carrier = NULL;
-		const char *alias = NULL;
-		PurpleAccount *account = purple_connection_get_account(gc);
-		PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account);
-
-		carrier = g_hash_table_lookup(yd->sms_carrier, who);
-		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(who);
-			sms_cb_data->what = g_strdup(what);
-
-			purple_conversation_write(conv, NULL, "Getting mobile carrier to send the sms", PURPLE_MESSAGE_SYSTEM, time(NULL));
-
-			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(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
-
-			g_free(msg);
-			g_free(msg2);
-			return -1;
-		}
-
-		alias = purple_account_get_alias(account);
-		pkt = yahoo_packet_new(YAHOO_SERVICE_SMS_MSG, YAHOO_STATUS_AVAILABLE, 0);
-		yahoo_packet_hash(pkt, "sssss",
-			1, purple_connection_get_display_name(gc),
-			69, alias,
-			5, who + 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, 0);
-	if(msn) {
-		yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who+4);
-		yahoo_packet_hash_int(pkt, 241, 2);
-	}
-	else	{
-		yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who);
-		if ((f = yahoo_friend_find(gc, who)) && f->protocol)
-			yahoo_packet_hash_int(pkt, 241, f->protocol);
-	}
-
-	if (utf8)
-		yahoo_packet_hash_str(pkt, 97, "1");
-	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 no set an IMVironment, then use the default.
-	 */
-	wb = purple_whiteboard_get_session(gc->account, who);
-	if (wb)
-		yahoo_packet_hash_str(pkt, 63, DOODLE_IMV_KEY);
-	else
-	{
-		const char *imv;
-		imv = g_hash_table_lookup(yd->imvironments, who);
-		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, who)) && !msn ) {
-			yahoo_packet_hash_int(pkt, 11, p2p_data->session_id);
-			yahoo_p2p_write_pkt(p2p_data->source, pkt);
-		}
-		else	{
-			yahoo_packet_send(pkt, yd);
-			if(!msn)
-				yahoo_send_p2p_pkt(gc, who, 0);		/* send p2p packet, with val_13=0 */
-		}
-	}
-	else
-		ret = -E2BIG;
-
-	yahoo_packet_free(pkt);
-
-	g_free(msg);
-	g_free(msg2);
-
-	return ret;
-}
-
-static unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	struct yahoo_p2p_data *p2p_data;
-	gboolean msn = !g_strncasecmp(who, "msn/", 4);
-	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, 0);
-
-	/* check to see if p2p link exists, send through it */
-	if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !msn ) {
-		yahoo_packet_hash(pkt, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc),
-	                  14, " ", 13, state == PURPLE_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 */
-		if(msn)
-			yahoo_packet_hash(pkt, "sssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
-	                  14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
-	                  5, who+4, 1002, "1", 241, "2");
-		else
-			yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
-	                  14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
-	                  5, who+4, 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;
-}
-
-static void yahoo_set_status(PurpleAccount *account, PurpleStatus *status)
-{
-	PurpleConnection *gc;
-	PurplePresence *presence;
-	struct yahoo_data *yd;
-	struct yahoo_packet *pkt;
-	int old_status;
-	const char *msg = NULL;
-	char *tmp = NULL;
-	char *conv_msg = NULL;
-	gboolean utf8 = TRUE;
-
-	if (!purple_status_is_active(status))
-		return;
-
-	gc = purple_account_get_connection(account);
-	presence = purple_status_get_presence(status);
-	yd = (struct yahoo_data *)gc->proto_data;
-	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, &utf8);
-			conv_msg = purple_markup_strip_html(tmp);
-			g_free(tmp);
-		} else {
-			if ((msg == NULL) || (*msg == '\0'))
-				msg = _("Away");
-			tmp = yahoo_string_encode(gc, msg, &utf8);
-			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, 0);
-		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, 0);
-	yahoo_packet_hash_int(pkt, 10, yd->current_status);
-
-	if (yd->current_status == YAHOO_STATUS_CUSTOM) {
-		yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0);
-		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");
-
-	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, 0);
-		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);
-
-	}
-}
-
-static void yahoo_set_idle(PurpleConnection *gc, int idle)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	struct yahoo_packet *pkt = NULL;
-	char *msg = NULL, *msg2 = NULL;
-	PurpleStatus *status = NULL;
-
-	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);
-	}
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, 0);
-
-	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) {
-			gboolean utf8 = TRUE;
-			msg = yahoo_string_encode(gc, tmp, &utf8);
-			msg2 = purple_markup_strip_html(msg);
-			yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0);
-			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 (!purple_presence_is_available(purple_account_get_presence(purple_connection_get_account(gc))))
-		yahoo_packet_hash_str(pkt, 47, "1");
-
-	yahoo_packet_send_and_free(pkt, yd);
-
-	g_free(msg);
-	g_free(msg2);
-}
-
-static 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(PURPLE_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(PURPLE_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(PURPLE_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_BUSY, _("Busy"), TRUE);
-	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;
-}
-
-static void yahoo_keepalive(PurpleConnection *gc)
-{
-	struct yahoo_packet *pkt;
-	struct yahoo_data *yd = gc->proto_data;
-	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, 0);
-				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, 0);
-			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, 0);
-		yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc));
-		yahoo_packet_send_and_free(pkt, yd);
-	}
-
-}
-
-static void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *g)
-{
-	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
-	struct yahoo_packet *pkt;
-	const char *group = NULL;
-	char *group2;
-	YahooFriend *f;
-	const char *bname;
-	gboolean msn = FALSE;
-
-	if (!yd->logged_in)
-		return;
-
-	bname = purple_buddy_get_name(buddy);
-	if (!purple_privacy_check(purple_connection_get_account(gc), bname))
-		return;
-
-	f = yahoo_friend_find(gc, bname);
-	msn = !g_strncasecmp(bname, "msn/", 4);
-
-	g = purple_buddy_get_group(buddy);
-	if (g)
-		group = purple_group_get_name(g);
-	else
-		group = "Buddies";
-
-	group2 = yahoo_string_encode(gc, group, NULL);
-	pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0);
-	if(msn) {
-		yahoo_packet_hash(pkt, "sssssssssss",
-			14, "",
-			65, group2,
-			97, "1",
-			1, purple_connection_get_display_name(gc),
-			302, "319",
-			300, "319",
-			7, bname + 4,
-			241, "2",
-			334, "0",
-			301, "319",
-			303, "319"
-		);
-	}
-	else	{
-		yahoo_packet_hash(pkt, "ssssssssss",
-			14, "",
-			65, group2,
-			97, "1",
-			1, purple_connection_get_display_name(gc),
-			302, "319",
-			300, "319",
-	                7, bname,
-			334, "0",
-			301, "319",
-			303, "319"
-		);
-	}
-	if (f && f->protocol && !msn)
-		yahoo_packet_hash_int(pkt, 241, f->protocol);
-
-	yahoo_packet_send_and_free(pkt, yd);
-	g_free(group2);
-}
-
-static void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
-{
-	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
-	struct yahoo_packet *pkt;
-	GSList *buddies, *l;
-	PurpleGroup *g;
-	gboolean remove = TRUE;
-	char *cg;
-	const char *bname, *gname;
-	YahooFriend *f = NULL;
-	gboolean msn = FALSE;
-
-	bname = purple_buddy_get_name(buddy);
-	f = yahoo_friend_find(gc, bname);
-	if (!f)
-		return;
-
-	gname = purple_group_get_name(group);
-	buddies = purple_find_buddies(purple_connection_get_account(gc), bname);
-	if(f->protocol == 2)
-		msn = TRUE;
-	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);
-
-	cg = yahoo_string_encode(gc, gname, NULL);
-	pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0);
-
-	if(msn)
-		yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
-	                  7, bname+4, 65, cg);
-	else
-		yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
-	                  7, bname, 65, cg);
-	if(f->protocol)
-		yahoo_packet_hash_int(pkt, 241, f->protocol);
-	yahoo_packet_send_and_free(pkt, yd);
-	g_free(cg);
-}
-
-static void yahoo_add_deny(PurpleConnection *gc, const char *who) {
-	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
-	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, 0);
-	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
-	                  7, who, 13, "1");
-	yahoo_packet_send_and_free(pkt, yd);
-}
-
-static void yahoo_rem_deny(PurpleConnection *gc, const char *who) {
-	struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data;
-	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, 0);
-	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, who, 13, "2");
-	yahoo_packet_send_and_free(pkt, yd);
-}
-
-static void yahoo_set_permit_deny(PurpleConnection *gc)
-{
-	PurpleAccount *account;
-	GSList *deny;
-
-	account = purple_connection_get_account(gc);
-
-	switch (account->perm_deny)
-	{
-		case PURPLE_PRIVACY_ALLOW_ALL:
-			for (deny = account->deny; deny; deny = deny->next)
-				yahoo_rem_deny(gc, deny->data);
-			break;
-
-		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
-		case PURPLE_PRIVACY_ALLOW_USERS:
-		case PURPLE_PRIVACY_DENY_USERS:
-		case PURPLE_PRIVACY_DENY_ALL:
-			for (deny = account->deny; deny; deny = deny->next)
-				yahoo_add_deny(gc, deny->data);
-			break;
-	}
-}
-
-static gboolean yahoo_unload_plugin(PurplePlugin *plugin)
-{
-	yahoo_dest_colorht();
-
-	return TRUE;
-}
-
-static void yahoo_change_buddys_group(PurpleConnection *gc, const char *who,
-				   const char *old_group, const char *new_group)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	struct yahoo_packet *pkt;
-	char *gpn, *gpo;
-	YahooFriend *f = yahoo_friend_find(gc, who);
-	gboolean msn = FALSE;
-	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;
-
-	if(f->protocol == 2) {
-		msn = TRUE;
-		temp = who+4;
-	} else
-		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, NULL);
-	gpo = yahoo_string_encode(gc, old_group, NULL);
-	if (!strcmp(gpn, gpo)) {
-		g_free(gpn);
-		g_free(gpo);
-		return;
-	}
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, 0);
-	if(f->protocol)
-		yahoo_packet_hash(pkt, "ssssissss", 1, purple_connection_get_display_name(gc),
-	                  302, "240", 300, "240", 7, temp, 241, f->protocol, 224, gpo, 264, gpn, 301,
-	                  "240", 303, "240");
-	else
-		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);
-}
-
-static void yahoo_rename_group(PurpleConnection *gc, const char *old_name,
-							   PurpleGroup *group, GList *moved_buddies)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	struct yahoo_packet *pkt;
-	char *gpn, *gpo;
-
-	gpn = yahoo_string_encode(gc, purple_group_get_name(group), NULL);
-	gpo = yahoo_string_encode(gc, old_name, NULL);
-	if (!strcmp(gpn, gpo)) {
-		g_free(gpn);
-		g_free(gpo);
-		return;
-	}
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, 0);
-	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 **********************************/
-
-static 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_prpl_send_attention(account->gc, c->name, YAHOO_BUZZ);
-
-	return PURPLE_CMD_RET_OK;
-}
-
-static PurplePlugin *my_protocol = NULL;
-
-static PurpleCmdRet
-yahoopurple_cmd_chat_join(PurpleConversation *conv, const char *cmd,
-                        char **args, char **error, void *data)
-{
-	GHashTable *comp;
-	PurpleConnection *gc;
-	struct yahoo_data *yd;
-	int id;
-
-	if (!args || !args[0])
-		return PURPLE_CMD_RET_FAILED;
-
-	gc = purple_conversation_get_gc(conv);
-	yd = gc->proto_data;
-	id = yd->conf_id;
-	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;
-}
-
-static 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;
-}
-
-static gboolean yahoo_offline_message(const PurpleBuddy *buddy)
-{
-	return TRUE;
-}
-
-gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type)
-{
-	PurpleConversation *c;
-
-	c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
-			username, gc->account);
-
-	g_return_val_if_fail(c != NULL, FALSE);
-
-	purple_debug_info("yahoo", "Sending <ding> on account %s to buddy %s.\n",
-			username, c->name);
-	purple_conv_im_send_with_flags(PURPLE_CONV_IM(c), "<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;
-}
-
-/************************** Plugin Initialization ****************************/
-static void
-yahoopurple_register_commands(void)
-{
-	purple_cmd_register("join", "s", PURPLE_CMD_P_PRPL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
-	                  PURPLE_CMD_FLAG_PRPL_ONLY,
-	                  "prpl-yahoo", yahoopurple_cmd_chat_join,
-	                  _("join &lt;room&gt;:  Join a chat room on the Yahoo network"), NULL);
-	purple_cmd_register("list", "", PURPLE_CMD_P_PRPL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
-	                  PURPLE_CMD_FLAG_PRPL_ONLY,
-	                  "prpl-yahoo", yahoopurple_cmd_chat_list,
-	                  _("list: List rooms on the Yahoo network"), NULL);
-	purple_cmd_register("buzz", "", PURPLE_CMD_P_PRPL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
-	                  "prpl-yahoo", yahoopurple_cmd_buzz,
-	                  _("buzz: Buzz a user to get their attention"), NULL);
-	purple_cmd_register("doodle", "", PURPLE_CMD_P_PRPL,
-	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
-	                  "prpl-yahoo", yahoo_doodle_purple_cmd_start,
-	                 _("doodle: Request user to start a Doodle session"), NULL);
-}
-
-static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
-{
-	PurpleAccount *acct = NULL;
-
-	/* If we have a specific acct, use it */
-	if (acct_id) {
-		acct = purple_accounts_find(acct_id, prpl);
-		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(prpl, 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_plugin_get_id(my_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");
-
-			PurpleConversation *conv = purple_find_conversation_with_account(
-				PURPLE_CONV_TYPE_IM, sname, acct);
-			if (conv == NULL)
-				conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, sname);
-			purple_conversation_present(conv);
-
-			if (message) {
-				/* Spaces are encoded as '+' */
-				g_strdelimit(message, "+", ' ');
-				purple_conv_send_confirm(conv, 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"));
-			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 PurpleWhiteboardPrplOps yahoo_whiteboard_prpl_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 PurplePluginProtocolInfo prpl_info =
-{
-	OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC,
-	NULL, /* user_splits */
-	NULL, /* protocol_options */
-	{"png,gif,jpeg", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND},
-	yahoo_list_icon,
-	yahoo_list_emblem,
-	yahoo_status_text,
-	yahoo_tooltip_text,
-	yahoo_status_types,
-	yahoo_blist_node_menu,
-	yahoo_c_info,
-	yahoo_c_info_defaults,
-	yahoo_login,
-	yahoo_close,
-	yahoo_send_im,
-	NULL, /* set info */
-	yahoo_send_typing,
-	yahoo_get_info,
-	yahoo_set_status,
-	yahoo_set_idle,
-	NULL, /* change_passwd*/
-	yahoo_add_buddy,
-	NULL, /* add_buddies */
-	yahoo_remove_buddy,
-	NULL, /* remove_buddies */
-	NULL, /* add_permit */
-	yahoo_add_deny,
-	NULL, /* rem_permit */
-	yahoo_rem_deny,
-	yahoo_set_permit_deny,
-	yahoo_c_join,
-	NULL, /* reject chat invite */
-	yahoo_get_chat_name,
-	yahoo_c_invite,
-	yahoo_c_leave,
-	NULL, /* chat whisper */
-	yahoo_c_send,
-	yahoo_keepalive,
-	NULL, /* register_user */
-	NULL, /* get_cb_info */
-	NULL, /* get_cb_away */
-	yahoo_update_alias, /* alias_buddy */
-	yahoo_change_buddys_group,
-	yahoo_rename_group,
-	NULL, /* buddy_free */
-	NULL, /* convo_closed */
-	purple_normalize_nocase, /* normalize */
-	yahoo_set_buddy_icon,
-	NULL, /* void (*remove_group)(PurpleConnection *gc, const char *group);*/
-	NULL, /* char *(*get_cb_real_name)(PurpleConnection *gc, int id, const char *who); */
-	NULL, /* set_chat_topic */
-	NULL, /* find_blist_chat */
-	yahoo_roomlist_get_list,
-	yahoo_roomlist_cancel,
-	yahoo_roomlist_expand_category,
-	NULL, /* can_receive_file */
-	yahoo_send_file,
-	yahoo_new_xfer,
-	yahoo_offline_message, /* offline_message */
-	&yahoo_whiteboard_prpl_ops,
-	NULL, /* send_raw */
-	NULL, /* roomlist_room_serialize */
-	NULL, /* unregister_user */
-
-	yahoo_send_attention,
-	yahoo_attention_types,
-
-	sizeof(PurplePluginProtocolInfo),       /* struct_size */
-	yahoo_get_account_text_table,    /* get_account_text_table */
-	NULL, /* initiate_media */
-	NULL  /* can_do_media */
-};
-
-static PurplePluginInfo info =
-{
-	PURPLE_PLUGIN_MAGIC,
-	PURPLE_MAJOR_VERSION,
-	PURPLE_MINOR_VERSION,
-	PURPLE_PLUGIN_PROTOCOL,                             /**< type           */
-	NULL,                                             /**< ui_requirement */
-	0,                                                /**< flags          */
-	NULL,                                             /**< dependencies   */
-	PURPLE_PRIORITY_DEFAULT,                            /**< priority       */
-	"prpl-yahoo",                                     /**< id             */
-	"Yahoo",	                                      /**< name           */
-	DISPLAY_VERSION,                                  /**< version        */
-	                                                  /**  summary        */
-	N_("Yahoo Protocol Plugin"),
-	                                                  /**  description    */
-	N_("Yahoo Protocol Plugin"),
-	NULL,                                             /**< author         */
-	PURPLE_WEBSITE,                                     /**< homepage       */
-	NULL,                                             /**< load           */
-	yahoo_unload_plugin,                              /**< unload         */
-	NULL,                                             /**< destroy        */
-	NULL,                                             /**< ui_info        */
-	&prpl_info,                                       /**< extra_info     */
-	NULL,
-	yahoo_actions,
-
-	/* padding */
-	NULL,
-	NULL,
-	NULL,
-	NULL
-};
-
-static void
-init_plugin(PurplePlugin *plugin)
-{
-	PurpleAccountOption *option;
-
-	option = purple_account_option_bool_new(_("Yahoo Japan"), "yahoojp", FALSE);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_string_new(_("Pager server"), "server", YAHOO_PAGER_HOST);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_string_new(_("Japan Pager server"), "serverjp", YAHOOJP_PAGER_HOST);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_int_new(_("Pager port"), "port", YAHOO_PAGER_PORT);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_string_new(_("File transfer server"), "xfer_host", YAHOO_XFER_HOST);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_string_new(_("Japan file transfer server"), "xferjp_host", YAHOOJP_XFER_HOST);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_int_new(_("File transfer port"), "xfer_port", YAHOO_XFER_PORT);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_string_new(_("Chat room locale"), "room_list_locale", YAHOO_ROOMLIST_LOCALE);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_bool_new(_("Ignore conference and chatroom invitations"), "ignore_invites", FALSE);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_string_new(_("Encoding"), "local_charset", "ISO-8859-1");
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-
-#if 0
-	option = purple_account_option_string_new(_("Chat room list URL"), "room_list", YAHOO_ROOMLIST_URL);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_string_new(_("Yahoo Chat server"), "ycht-server", YAHOO_YCHT_HOST);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-	option = purple_account_option_int_new(_("Yahoo Chat port"), "ycht-port", YAHOO_YCHT_PORT);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-#endif
-
-	my_protocol = plugin;
-	yahoopurple_register_commands();
-	yahoo_init_colorht();
-
-	purple_signal_connect(purple_get_core(), "uri-handler", plugin,
-		PURPLE_CALLBACK(yahoo_uri_handler), NULL);
-}
-
-PURPLE_INIT_PLUGIN(yahoo, init_plugin, info);
--- a/libpurple/protocols/yahoo/yahoo.h	Sun Jul 05 02:26:03 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
-/**
- * @file yahoo.h The Yahoo! protocol plugin
- *
- * 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 "circbuffer.h"
-#include "prpl.h"
-
-#define YAHOO_PAGER_HOST "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_PORT 80
-#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"
-/* really we should get the list of servers from
- http://update.messenger.yahoo.co.jp/servers.html */
-#define YAHOOJP_PAGER_HOST "cs.yahoo.co.jp"
-#define YAHOOJP_TOKEN_URL "https://login.yahoo.co.jp/config/pwtoken_get?src=ymsgr&ts=&login=%s&passwd=%s&chal=%s"
-#define YAHOOJP_LOGIN_URL "https://login.yahoo.co.jp/config/pwtoken_login?src=ymsgr&ts=&token=%s"
-#define YAHOOJP_PROFILE_URL "http://profiles.yahoo.co.jp/"
-#define YAHOOJP_MAIL_URL "http://mail.yahoo.co.jp/"
-#define YAHOOJP_XFER_HOST "filetransfer.msg.yahoo.co.jp"
-#define YAHOOJP_WEBCAM_HOST "wc.yahoo.co.jp"
-/* not sure, must test: */
-#define YAHOOJP_XFER_RELAY_HOST "relay.msg.yahoo.co.jp"
-#define YAHOOJP_XFER_RELAY_PORT 80
-#define YAHOOJP_ROOMLIST_URL "http://insider.msg.yahoo.co.jp/ycontent/"
-#define YAHOOJP_ROOMLIST_LOCALE "ja"
-
-#define YAHOO_AUDIBLE_URL "http://us.dl1.yimg.com/download.yahoo.com/dl/aud"
-
-#define WEBMESSENGER_URL "http://login.yahoo.com/config/login?.src=pg"
-
-#define YAHOO_SMS_CARRIER_URL "http://lookup.msg.vip.mud.yahoo.com"
-
-#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.2152"
-
-#define YAHOOJP_CLIENT_VERSION_ID "4194239"
-#define YAHOOJP_CLIENT_VERSION "9.0.0.2152"
-
-#define YAHOO_CLIENT_USERAGENT "Mozilla/5.0"
-
-/* 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_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 = 0xffffffff /* in ymsg 15. doesnt mean the normal sense of 'disconnected' */
-};
-
-struct yahoo_buddy_icon_upload_data {
-	PurpleConnection *gc;
-	GString *str;
-	char *filename;
-	int pos;
-	int fd;
-	guint watcher;
-};
-
-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;
-
-struct yahoo_data {
-	PurpleConnection *gc;
-	int fd;
-	guchar *rxqueue;
-	int rxlen;
-	PurpleCircBuffer *txbuf;
-	guint txhandler;
-	GHashTable *friends;
-
-	char **profiles;  /* Multiple profiles can be associated with an account */
-
-	/**
-	 * 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;
-	gsize auth_written;
-	char *cookie_y;
-	char *cookie_t;
-	int session_id;
-	gboolean jp;
-	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;
-	PurpleProxyConnectData *buddy_icon_connect_data;
-
-	struct _YchtConn *ycht;
-
-	/**
-	 * This linked list contains PurpleUtilFetchUrlData structs
-	 * for when we lookup people profile or photo information.
-	 */
-	GSList *url_datas;
-	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 */
-
-	/**
-	 * 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;
-};
-
-#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);
-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 If not @c NULL, whether utf8 is okay or not.
- *             Even if it is okay, we may not use it. If we
- *             used it, we set this to @c TRUE, else to
- *             @c FALSE. If @c NULL, false is assumed, and
- *             it is not dereferenced.
- * @return The g_malloced string in the appropriate encoding.
- */
-char *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);
-
-/* previously-static functions, now needed for yahoo_profile.c */
-void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full);
-
-/* yahoo_profile.c */
-void yahoo_get_info(PurpleConnection *gc, const char *name);
-
-/* 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);
-
-gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type);
-GList *yahoo_attention_types(PurpleAccount *account);
-
-/* 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 /* _YAHOO_H_ */