changeset 22102:e6e018d0bf03

merge of '464169ffadabb173b3052074b132f38025b2e88d' and '88dc67220e1d61e540c931b9f27f5b4419809137'
author Richard Laager <rlaager@wiktel.com>
date Mon, 14 Jan 2008 04:09:03 +0000
parents 0b823f16162c (diff) 7ec5b5724a05 (current diff)
children 1439274f0852
files pidgin/gtkprefs.c pidgin/gtkstatusbox.c
diffstat 35 files changed, 1471 insertions(+), 396 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Mon Jan 14 04:04:08 2008 +0000
+++ b/COPYRIGHT	Mon Jan 14 04:09:03 2008 +0000
@@ -322,6 +322,7 @@
 Jean-Francois Roy
 Peter Ruibal
 Sam S.
+Thanumalayan S.
 Pradyumna Sampath
 Arvind Samptur
 Tom Samstag
@@ -426,6 +427,7 @@
 Andrew Whewell
 Simon Wilkinson
 Dan Willemsen
+Justin Williams (Jaywalker)
 Jason Willis
 Matt Wilson
 Dan Winship
--- a/ChangeLog	Mon Jan 14 04:04:08 2008 +0000
+++ b/ChangeLog	Mon Jan 14 04:09:03 2008 +0000
@@ -9,6 +9,7 @@
 	  now required to use Bonjour.
 	* Partial support for viewing ICQ status notes (Collin from
 	  ComBOTS GmbH).
+	* Support for Yahoo Messenger 7.0+ file transfer method (Thanumalayan S.)
 
 	Pidgin:
 	* Added the ability to theme conversation name colors (red and blue)
@@ -22,14 +23,14 @@
 	Finch:
 	* Color is used in the buddylist to indicate status, and the conversation
 	  window to indicate various message attributes. Look at the sample gntrc
-	  file in the man-page for details.
+	  file in the man page for details.
 	* The default keybinding for dump-screen is now M-D and uses a file
 	  request dialog. M-d will properly delete-forward-word, and M-f has been
 	  fixed to imitate readline's behavior.
 	* New bindings alt+tab and alt+shift+tab to help navigating between the
-	  higlighted windows (details on the man-page).
+	  higlighted windows (details on the man page).
 	* Recently signed on (or off) buddies blink in the buddy list.
-	* New action 'Room List' in the action-list can be used to get the list of
+	* New action 'Room List' in the action list can be used to get the list of
 	  available chat rooms for an online account.
 
 version 2.3.1 (12/7/2007):
--- a/ChangeLog.API	Mon Jan 14 04:04:08 2008 +0000
+++ b/ChangeLog.API	Mon Jan 14 04:09:03 2008 +0000
@@ -18,6 +18,18 @@
 			* purple_roomlist_field_get_type
 			* purple_roomlist_field_get_label
 			* purple_roomlist_field_get_hidden
+		* unlocalized_name field in PurpleAttentionType for UIs that need it.
+		* Some accessor and mutator functions for PurpleAttentionType:
+			* purple_attention_type_set_name
+			* purple_attention_type_set_incoming_desc
+			* purple_attention_type_set_outgoing_desc
+			* purple_attention_type_set_icon_name
+			* purple_attention_type_set_unlocalized_name
+			* purple_attention_type_get_name
+			* purple_attention_type_get_incoming_desc
+			* purple_attention_type_get_outgoing_desc
+			* purple_attention_type_get_icon_name
+			* purple_attention_type_get_unlocalized_name
 
 	Pidgin:
 		Added:
--- a/finch/gntroomlist.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/finch/gntroomlist.c	Mon Jan 14 04:09:03 2008 +0000
@@ -287,10 +287,10 @@
 
 	froomlist.accounts = accounts = gnt_combo_box_new();
 	reset_account_list(account);
-	gnt_box_add_widget(GNT_BOX(window), froomlist.accounts);
-	g_signal_connect(G_OBJECT(froomlist.accounts), "selection-changed",
+	gnt_box_add_widget(GNT_BOX(window), accounts);
+	g_signal_connect(G_OBJECT(accounts), "selection-changed",
 			G_CALLBACK(roomlist_account_changed), NULL);
-	froomlist.account = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(froomlist.accounts));
+	froomlist.account = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(accounts));
 
 	froomlist.tree = tree = gnt_tree_new_with_columns(2);
 	gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
--- a/libpurple/dbus-server.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/dbus-server.c	Mon Jan 14 04:09:03 2008 +0000
@@ -689,6 +689,7 @@
 		switch (purple_values[i]->type)
 		{
 		case PURPLE_TYPE_INT:
+		case PURPLE_TYPE_ENUM:
 			xint = my_arg(gint);
 			dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &xint);
 			break;
--- a/libpurple/protocols/jabber/jabber.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Mon Jan 14 04:09:03 2008 +0000
@@ -2301,14 +2301,10 @@
 GList *jabber_attention_types(PurpleAccount *account)
 {
 	static GList *types = NULL;
-	PurpleAttentionType *attn;
 
 	if (!types) {
-		attn = g_new0(PurpleAttentionType, 1);
-		attn->name = _("Buzz");
-		attn->incoming_description = _("%s has buzzed you!");
-		attn->outgoing_description = _("Buzzing %s...");
-		types = g_list_append(types, attn);
+		types = g_list_append(types, purple_attention_type_new("Buzz", _("Buzz"),
+				_("%s has buzzed you!"), _("Buzzing %s...")));
 	}
 
 	return types;
--- a/libpurple/protocols/msn/msn.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Mon Jan 14 04:09:03 2008 +0000
@@ -126,11 +126,8 @@
 	static GList *list = NULL;
 
 	if (!list) {
-		attn = g_new0(PurpleAttentionType, 1);
-		attn->name = _("Nudge");
-		attn->incoming_description = _("%s has nudged you!");
-		attn->outgoing_description = _("Nudging %s...");
-		list = g_list_append(list, attn);
+		list = g_list_append(list, purple_attention_type_new("Nudge", _("Nudge"),
+				_("%s has nudged you!"), _("Nudging %s...")));
 	}
 
 	return list;
--- a/libpurple/protocols/msnp9/msn.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/msnp9/msn.c	Mon Jan 14 04:09:03 2008 +0000
@@ -122,15 +122,11 @@
 static GList *
 msn_attention_types(PurpleAccount *account)
 {
-	PurpleAttentionType *attn;
 	static GList *list = NULL;
 
 	if (!list) {
-		attn = g_new0(PurpleAttentionType, 1);
-		attn->name = _("Nudge");
-		attn->incoming_description = _("%s has nudged you!");
-		attn->outgoing_description = _("Nudging %s...");
-		list = g_list_append(list, attn);
+		list = g_list_append(list, purple_attention_type_new("Nudge", _("Nudge"),
+				_("%s has nudged you!"), _("Nudging %s...")));
 	}
 
 	return list;
--- a/libpurple/protocols/myspace/myspace.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Mon Jan 14 04:09:03 2008 +0000
@@ -2316,6 +2316,69 @@
 	msim_msg_free(blocklist_msg);
 }
 
+/**
+ * Borrowed this code from oscar_normalize. Added checking for "if userid, get name before normalizing"
+ *
+ * Basically... Returns a string that has been formated with all the spaces and caps removed.
+ */
+const char *msim_normalize(const PurpleAccount *account, const char *str) {
+	static char normalized[BUF_LEN];
+	MsimSession *session;
+	char *tmp1, *tmp2;
+	int i, j;
+	guint id;
+
+	g_return_val_if_fail(str != NULL, NULL);
+
+	if (msim_is_userid(str)) {
+		/* Have user ID, we need to get their username first :) */
+		const char *username;
+
+		/* If the account does not exist, we can't look up the user. */
+		g_return_val_if_fail(account != NULL, str);
+		g_return_val_if_fail(account->gc != NULL, str);
+		g_return_val_if_fail(account->gc->state == PURPLE_CONNECTED, str);
+
+		purple_debug_info("msim_normalize", "%s is a userid\n",str);
+
+		session = (MsimSession *)account->gc->proto_data;
+		id = atol(str);
+		username = msim_uid2username_from_blist(session, id);
+		if (!username) {
+			/* Not in buddy list... scheisse... TODO: Manual Lookup! */
+			/* Note: manual lookup using msim_lookup_user() is a problem inside 
+			 * msim_normalize(), because msim_lookup_user() calls a callback function
+			 * when the user information has been looked up, but msim_normalize() expects
+			 * the result immediately. */
+			purple_debug_info("msim_normalize", "Failure! %s is not in my list\n", str);
+			strncpy(normalized, str, BUF_LEN);
+		} else {
+			purple_debug_info("msim_normalize","%d is %s\n", id, username);
+			strncpy(normalized, username, BUF_LEN);
+		}
+	} else {
+		/* Have username. */
+		strncpy(normalized, str, BUF_LEN);
+	}
+
+	/* Strip spaces. */
+	for (i=0, j=0; normalized[j]; i++, j++) {
+		while (normalized[j] == ' ')
+			j++;
+		normalized[i] = normalized[j];
+	}
+	normalized[i] = '\0';
+
+	/* Lowercase and perform UTF-8 normalization. */
+	tmp1 = g_utf8_strdown(normalized, -1);
+	tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
+	g_snprintf(normalized, sizeof(normalized), "%s", tmp2);
+	g_free(tmp2);
+	g_free(tmp1);
+
+	return normalized;
+}
+
 /** Return whether the buddy can be messaged while offline.
  *
  * The protocol supports offline messages in just the same way as online
@@ -2970,7 +3033,7 @@
 	NULL,              /* rename_group */
 	NULL,              /* buddy_free */
 	NULL,              /* convo_closed */
-	NULL,              /* normalize */
+	msim_normalize,    /* normalize */
 	NULL,              /* set_buddy_icon */
 	NULL,              /* remove_group */
 	NULL,              /* get_cb_real_name */
--- a/libpurple/protocols/myspace/myspace.h	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Mon Jan 14 04:09:03 2008 +0000
@@ -180,8 +180,6 @@
 #define MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS	1
 #define MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS	2
 
-#define MsimAttentionType PurpleAttentionType
-
 /* Functions */
 gboolean msim_load(PurplePlugin *plugin);
 GList *msim_status_types(PurpleAccount *acct);
@@ -201,6 +199,8 @@
 void msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
 void msim_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
 
+const char *msim_normalize(const PurpleAccount *account, const char *str);
+
 gboolean msim_offline_message(const PurpleBuddy *buddy);
 
 void msim_close(PurpleConnection *gc);
--- a/libpurple/protocols/myspace/zap.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/myspace/zap.c	Mon Jan 14 04:09:03 2008 +0000
@@ -29,15 +29,12 @@
 msim_attention_types(PurpleAccount *acct)
 {
 	static GList *types = NULL;
-	MsimAttentionType* attn;
+	PurpleAttentionType* attn;
 
 	if (!types) {
-#define _MSIM_ADD_NEW_ATTENTION(icn, nme, incoming, outgoing)              \
-		attn = g_new0(MsimAttentionType, 1);                       \
-		attn->icon_name = icn;                                     \
-		attn->name = nme;                                          \
-		attn->incoming_description = incoming;                     \
-		attn->outgoing_description = outgoing;                     \
+#define _MSIM_ADD_NEW_ATTENTION(icn, ulname, nme, incoming, outgoing) \
+		attn = purple_attention_type_new(ulname, nme, incoming, outgoing); \
+		purple_attention_type_set_icon_name(attn, icn); \
 		types = g_list_append(types, attn);
 
 		/* TODO: icons for each zap */
@@ -48,37 +45,46 @@
 		 * projectile or weapon."  This term often has an electrical
 		 * connotation, for example, "he was zapped by electricity when
 		 * he put a fork in the toaster." */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Zap"), _("%s has zapped you!"), _("Zapping %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Zap", _("Zap"), _("%s has zapped you!"),
+				_("Zapping %s..."));
 
 		/* Whack means "to hit or strike someone with a sharp blow" */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Whack"), _("%s has whacked you!"), _("Whacking %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Whack", _("Whack"),
+				_("%s has whacked you!"), _("Whacking %s..."));
 
 		/* Torch means "to set on fire."  Don't worry, this doesn't
 		 * make a whole lot of sense in English, either.  Feel free
 		 * to translate it literally. */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Torch"), _("%s has torched you!"), _("Torching %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Torch", _("Torch"),
+				_("%s has torched you!"), _("Torching %s..."));
 
 		/* Smooch means "to kiss someone, often enthusiastically" */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Smooch"), _("%s has smooched you!"), _("Smooching %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Smooch", _("Smooch"),
+				_("%s has smooched you!"), _("Smooching %s..."));
 
 		/* A hug is a display of affection; wrapping your arms around someone */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Hug"), _("%s has hugged you!"), _("Hugging %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Hug", _("Hug"), _("%s has hugged you!"),
+				_("Hugging %s..."));
 
 		/* Slap means "to hit someone with an open/flat hand" */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Slap"), _("%s has slapped you!"), _("Slapping %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Slap", _("Slap"),
+				_("%s has slapped you!"), _("Slapping %s..."));
 
 		/* Goose means "to pinch someone on their butt" */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Goose"), _("%s has goosed you!"), _("Goosing %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Goose", _("Goose"),
+				_("%s has goosed you!"), _("Goosing %s..."));
 
 		/* A high-five is when two people's hands slap each other
 		 * in the air above their heads.  It is done to celebrate
 		 * something, often a victory, or to congratulate someone. */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("High-five"), _("%s has high-fived you!"), _("High-fiving %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "High-five", _("High-five"),
+				_("%s has high-fived you!"), _("High-fiving %s..."));
 
 		/* We're not entirely sure what the MySpace people mean by
 		 * this... but we think it's the equivalent of "prank."  Or, for
 		 * someone to perform a mischievous trick or practical joke. */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Punk"), _("%s has punk'd you!"), _("Punking %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Punk", _("Punk"),
+				_("%s has punk'd you!"), _("Punking %s..."));
 
 		/* Raspberry is a slang term for the vibrating sound made
 		 * when you stick your tongue out of your mouth with your
@@ -87,7 +93,8 @@
 		 * gesture, so it does not carry a harsh negative
 		 * connotation.  It is generally used in a playful tone
 		 * with friends. */
-		_MSIM_ADD_NEW_ATTENTION(NULL, _("Raspberry"), _("%s has raspberried you!"), _("Raspberrying %s..."));
+		_MSIM_ADD_NEW_ATTENTION(NULL, "Raspberry", _("Raspberry"),
+				_("%s has raspberried you!"), _("Raspberrying %s..."));
 	}
 
 	return types;
@@ -99,14 +106,14 @@
 {
 	GList *types;
 	MsimSession *session;
-	MsimAttentionType *attn;
+	PurpleAttentionType *attn;
 	PurpleBuddy *buddy;
 
 	session = (MsimSession *)gc->proto_data;
 
 	/* Look for this attention type, by the code index given. */
 	types = msim_attention_types(gc->account);
-	attn = (MsimAttentionType *)g_list_nth_data(types, code);
+	attn = (PurpleAttentionType *)g_list_nth_data(types, code);
 
 	if (!attn) {
 		purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code);
@@ -200,12 +207,12 @@
 	i = 0;
 	do
 	{
-		MsimAttentionType *attn;
+		PurpleAttentionType *attn;
 
-		attn = (MsimAttentionType *)types->data;
+		attn = (PurpleAttentionType *)types->data;
 
-		act = purple_menu_action_new(attn->name, PURPLE_CALLBACK(msim_send_zap_from_menu),
-				GUINT_TO_POINTER(i), NULL);
+		act = purple_menu_action_new(purple_attention_type_get_name(attn),
+				PURPLE_CALLBACK(msim_send_zap_from_menu), GUINT_TO_POINTER(i), NULL);
 		zap_menu = g_list_append(zap_menu, act);
 
 		++i;
--- a/libpurple/protocols/yahoo/util.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/yahoo/util.c	Mon Jan 14 04:09:03 2008 +0000
@@ -31,6 +31,70 @@
 #include "yahoo.h"
 
 #include <string.h>
+/*
+ * Returns cookies formatted as a null terminated string for the given connection.
+ * Must g_free return value.
+ * 
+ * TODO:will work, but must test for strict correctness
+ */
+gchar* yahoo_get_cookies(PurpleConnection *gc)
+{
+	gchar *ans = NULL;
+	gchar *cur;
+	char firstflag = 1;
+	gchar *t1,*t2,*t3;
+	GSList *tmp;
+	GSList *cookies;
+	cookies = ((struct yahoo_data*)(gc->proto_data))->cookies;
+	tmp = cookies;
+	while(tmp)
+	{
+		cur = tmp->data;
+		t1 = ans;
+		t2 = g_strrstr(cur, ";expires=");
+		if(t2 == NULL)
+			t2 = g_strrstr(cur, "; expires=");
+		if(t2 == NULL)
+		{
+			if(firstflag)
+				ans = g_strdup_printf("%c=%s", cur[0], cur+2);
+			else
+				ans = g_strdup_printf("%s; %c=%s", t1, cur[0], cur+2);
+		}
+		else
+		{
+			t3 = strstr(t2+1, ";");
+			if(t3 != NULL)
+			{
+				t2[0] = '\0';
+
+				if(firstflag)
+					ans = g_strdup_printf("%c=%s%s", cur[0], cur+2, t3);
+				else
+					ans = g_strdup_printf("%s; %c=%s%s", t1, cur[0], cur+2, t3);
+
+				t2[0] = ';';
+			}
+			else
+			{
+				t2[0] = '\0';
+
+				if(firstflag)
+					ans = g_strdup_printf("%c=%s", cur[0], cur+2);
+				else
+					ans = g_strdup_printf("%s; %c=%s", t1, cur[0], cur+2);
+
+				t2[0] = ';';
+			}
+		}
+		if(firstflag)
+			firstflag = 0;
+		else
+			g_free(t1);
+		tmp = g_slist_next(tmp);
+	}
+	return ans;
+}
 
 /**
  * Encode some text to send to the yahoo server.
--- a/libpurple/protocols/yahoo/yahoo.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Mon Jan 14 04:09:03 2008 +0000
@@ -392,6 +392,10 @@
 		case 97: /* Unicode status message */
 			unicode = !strcmp(pair->value, "1");
 			break;
+		case 244: /* client version number. Yahoo Client Detection */
+			if(f && strtol(pair->value, NULL, 10))
+				f->version_id = strtol(pair->value, NULL, 10);
+			break;
 
 		default:
 			purple_debug(PURPLE_DEBUG_ERROR, "yahoo",
@@ -493,16 +497,16 @@
 static void yahoo_process_cookie(struct yahoo_data *yd, char *c)
 {
 	if (c[0] == 'Y') {
-		g_free(yd->cookie_y);
+		if (yd->cookie_y)
+			g_free(yd->cookie_y);
 		yd->cookie_y = _getcookie(c);
 	} else if (c[0] == 'T') {
-		g_free(yd->cookie_t);
+		if (yd->cookie_t)
+			g_free(yd->cookie_t);
 		yd->cookie_t = _getcookie(c);
-	} else if (c[0] == 'C') {
-		g_free(yd->cookie_c);
-		yd->cookie_c = _getcookie(c);
 	} else
-		purple_debug_info("yahoo", "Ignoring unrecognized cookie '%c'\n", c[0]);
+		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)
@@ -510,6 +514,7 @@
 	GSList *l = pkt->hash;
 
 	PurpleAccount *account = purple_connection_get_account(gc);
+	struct yahoo_data *yd = gc->proto_data;
 	GHashTable *ht;
 	char *grp = NULL;
 	char *norm_bud = NULL;
@@ -575,6 +580,9 @@
 				purple_debug_info("yahoo", "Setting protocol to %d\n", f->protocol);
 			}
 			break;
+		case 59: /* somebody told cookies come here too, but im not sure */
+			yahoo_process_cookie(yd, pair->value);
+			break;
 		case 317: /* Stealth Setting */
 			if (f && (strtol(pair->value, NULL, 10) == 2)) {
 				f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
@@ -1507,7 +1515,13 @@
 	to_y64(result96, digest, 16);
 
 	pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP,	YAHOO_STATUS_AVAILABLE, 0);
-	yahoo_packet_hash(pack, "ssss", 0, name, 6, result6, 96, result96, 1, name);
+	yahoo_packet_hash(pack, "ssssss",
+					  0, name,
+					  6, result6,
+					  96, result96,
+					  1, name,
+					  244, YAHOO_CLIENT_VERSION_ID,
+					  135, YAHOO_CLIENT_VERSION);
 	yahoo_packet_send_and_free(pack, yd);
 
 	g_free(hash_string_p);
@@ -1526,11 +1540,11 @@
 	char *enc_pass;
 	struct yahoo_data *yd = gc->proto_data;
 
-	PurpleCipher			*md5_cipher;
+	PurpleCipher		*md5_cipher;
 	PurpleCipherContext	*md5_ctx;
 	guchar				md5_digest[16];
 
-	PurpleCipher			*sha1_cipher;
+	PurpleCipher		*sha1_cipher;
 	PurpleCipherContext	*sha1_ctx1;
 	PurpleCipherContext	*sha1_ctx2;
 
@@ -1542,7 +1556,7 @@
 	char				*delimit_lookup		= ",;";
 
 	char				*password_hash		= (char *)g_malloc(25);
-	char				*crypt_hash		= (char *)g_malloc(25);
+	char				*crypt_hash			= (char *)g_malloc(25);
 	char				*crypt_result		= NULL;
 
 	unsigned char		pass_hash_xor1[64];
@@ -1596,7 +1610,7 @@
 
 	magic_ptr = seed;
 
-	while (*magic_ptr != (int)NULL) {
+	while (*magic_ptr != '\0') {
 		char   *loc;
 
 		/* Ignore parentheses. */
@@ -1649,7 +1663,7 @@
 	 * dust on the values.
 	 */
 
-	for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) {
+	for (magic_cnt = magic_len - 2; magic_cnt >= 0; magic_cnt--) {
 		unsigned char	byte1;
 		unsigned char	byte2;
 
@@ -1665,7 +1679,7 @@
 		byte1 ^= byte2;
 
 		magic[magic_cnt+1] = byte1;
-			}
+	}
 
 	/*
 	 * Magic: Phase 3.  This computes 20 bytes.  The first 4 bytes are used as our magic
@@ -1680,8 +1694,8 @@
 	x = 0;
 
 	do {
-		unsigned int	bl = 0;
-		unsigned int	cl = magic[magic_cnt++];
+		unsigned int bl = 0;
+		unsigned int cl = magic[magic_cnt++];
 
 		if (magic_cnt >= magic_len)
 			break;
@@ -1706,17 +1720,18 @@
 
 	/* First four bytes are magic key. */
 	memcpy(&magic_key_char[0], comparison_src, 4);
-	magic_4 = magic_key_char[0] | (magic_key_char[1]<<8) | (magic_key_char[2]<<16) | (magic_key_char[3]<<24);
+	magic_4 = magic_key_char[0] | (magic_key_char[1] << 8) |
+			(magic_key_char[2] << 16) | (magic_key_char[3] << 24);
 
 	/*
 	 * Magic: Phase 4.  Determine what function to use later by getting outside/inside
 	 * loop values until we match our previous buffer.
 	 */
 	for (x = 0; x < 65535; x++) {
-		int			leave = 0;
+		int leave = 0;
 
 		for (y = 0; y < 5; y++) {
-			unsigned char	test[3];
+			unsigned char test[3];
 
 			/* Calculate buffer. */
 			test[0] = x;
@@ -1952,8 +1967,13 @@
 	}
 	purple_debug_info("yahoo", "yahoo status: %d\n", yd->current_status);
 	pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP,	yd->current_status, 0);
-	yahoo_packet_hash(pack, "sssss", 0, name, 6, resp_6, 96, resp_96, 1,
-	                  name, 135, "6,0,0,1710");
+	yahoo_packet_hash(pack, "ssssss",
+					  0, name,
+					  6, resp_6,
+					  96, resp_96,
+					  1, name,
+					  244, YAHOO_CLIENT_VERSION_ID,
+					  135, YAHOO_CLIENT_VERSION);
 	if (yd->picture_checksum)
 		yahoo_packet_hash_int(pack, 192, yd->picture_checksum);
 
@@ -2443,12 +2463,16 @@
 	case YAHOO_SERVICE_AUDIBLE:
 		yahoo_process_audible(gc, pkt);
 		break;
-	case YAHOO_SERVICE_Y7_FILETRANSFER:
-		yahoo_process_y7_filetransfer(gc, pkt);
+	case YAHOO_SERVICE_FILETRANS_15:
+		yahoo_process_filetrans_15(gc, pkt);
 		break;
-	case YAHOO_SERVICE_Y7_FILETRANSFER_INFO:
-		yahoo_process_y7_filetransfer_info(gc, pkt);
+	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;
+
 	default:
 		purple_debug(PURPLE_DEBUG_ERROR, "yahoo",
 				   "Unhandled service 0x%02x\n", pkt->service);
@@ -2670,11 +2694,15 @@
 	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);
@@ -2964,6 +2992,7 @@
 	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->confs = NULL;
 	yd->conf_id = 2;
 
@@ -3018,17 +3047,23 @@
 	}
 	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 = 0;
 	if (yd->in_chat)
 		yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */
 
 	g_hash_table_destroy(yd->friends);
 	g_hash_table_destroy(yd->imvironments);
+	g_hash_table_destroy(yd->xfer_peer_idstring_map);
 	g_free(yd->chat_name);
 
 	g_free(yd->cookie_y);
 	g_free(yd->cookie_t);
-	g_free(yd->cookie_c);
 
 	if (yd->txhandler)
 		purple_input_remove(yd->txhandler);
@@ -4130,17 +4165,13 @@
 
 GList *yahoo_attention_types(PurpleAccount *account)
 {
-	PurpleAttentionType *attn;
 	static GList *list = NULL;
 
 	if (!list) {
 		/* Yahoo only supports one attention command: the 'buzz'. */
 		/* This is index number YAHOO_BUZZ. */
-		attn = g_new0(PurpleAttentionType, 1);
-		attn->name = _("Buzz");
-		attn->incoming_description = _("%s has buzzed you!");
-		attn->outgoing_description = _("Buzzing %s...");
-		list = g_list_append(list, attn);
+		list = g_list_append(list, purple_attention_type_new("Buzz", _("Buzz"),
+				_("%s has buzzed you!"), _("Buzzing %s...")));
 	}
 
 	return list;
--- a/libpurple/protocols/yahoo/yahoo.h	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.h	Mon Jan 14 04:09:03 2008 +0000
@@ -34,6 +34,8 @@
 #define YAHOO_MAIL_URL "https://login.yahoo.com/config/login?.src=ym"
 #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
@@ -43,6 +45,11 @@
 #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.com" 
+#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"
 
@@ -67,6 +74,9 @@
 #define YAHOO_STATUS_TYPE_INVISIBLE "invisible"
 #define YAHOO_STATUS_TYPE_MOBILE "mobile"
 
+#define YAHOO_CLIENT_VERSION_ID "2097087"
+#define YAHOO_CLIENT_VERSION "8.1.0.421"
+
 /* Index into attention types list. */
 #define YAHOO_BUZZ 0
 
@@ -86,7 +96,8 @@
 	YAHOO_STATUS_IDLE = 999,
 	YAHOO_STATUS_WEBLOGIN = 0x5a55aa55,
 	YAHOO_STATUS_OFFLINE = 0x5a55aa56, /* don't ask */
-	YAHOO_STATUS_TYPING = 0x16
+	YAHOO_STATUS_TYPING = 0x16,
+	YAHOO_STATUS_DISCONNECTED = 0xffffffff /* in ymsg 15. doesnt mean the normal sense of 'disconnected' */
 };
 
 struct yahoo_buddy_icon_upload_data {
@@ -134,7 +145,6 @@
 	gsize auth_written;
 	char *cookie_y;
 	char *cookie_t;
-	char *cookie_c;
 	int session_id;
 	gboolean jp;
 	gboolean wm; /* connected w/ web messenger method */
@@ -154,6 +164,8 @@
 	 * 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*/
 };
 
 #define YAHOO_MAX_STATUS_MESSAGE_LENGTH (255)
@@ -212,6 +224,12 @@
 /* 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);
+
 /**
  * Check to see whether the sender is permitted to send
  *
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Mon Jan 14 04:09:03 2008 +0000
@@ -21,6 +21,7 @@
  */
 
 #include "internal.h"
+#include "dnsquery.h"
 
 #include "prpl.h"
 #include "util.h"
@@ -32,6 +33,7 @@
 #include "yahoo_packet.h"
 #include "yahoo_filexfer.h"
 #include "yahoo_doodle.h"
+#include "yahoo_friend.h"
 
 struct yahoo_xfer_data {
 	gchar *host;
@@ -46,81 +48,65 @@
 	guint tx_handler;
 	gchar *rxqueue;
 	guint rxlen;
+	gchar *xfer_peer_idstring;
+	gchar *xfer_idstring_for_relay;
+	int version; /*0 for old, 15 for Y7(YMSG 15)*/
+	int info_val_249;
 
-	gboolean y7;	/* true for Y7 transfers (receive only for now) */
-	gchar *token;
-	gchar *tid;
+	enum {
+		STARTED = 0,
+		HEAD_REQUESTED,
+		HEAD_REPLY_RECEIVED,
+		TRANSFER_PHASE,
+		ACCEPTED
+	} status_15;
+
+	/* contains all filenames, in case of multiple transfers, with the first
+	 * one in the list being the current file's name (ymsg15) */
+	GSList *filename_list;
+	GSList *size_list; /*corresponds to filename_list, with size as **STRING** */
+	gboolean firstoflist;
 };
 
 static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd)
 {
+	PurpleConnection *gc;
+	struct yahoo_data *yd;
+	PurpleXfer *xfer;
+	GSList *l;
+
+	gc = xd->gc;
+	yd = gc->proto_data;
+
+	/*remove entry from map*/
+	if(xd->xfer_peer_idstring) {
+		xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xd->xfer_peer_idstring);
+		if(xfer)
+			g_hash_table_remove(yd->xfer_peer_idstring_map, xd->xfer_peer_idstring);
+	}
+
+	/*empty file & filesize list*/
+	for (l = xd->filename_list; l; l = l->next) {
+		g_free(l->data);
+		l->data=NULL;
+	}
+	for (l = xd->size_list; l; l = l->next) {
+		g_free(l->data);
+		l->data=NULL;
+	}
+	g_slist_free(xd->filename_list);
+	g_slist_free(xd->size_list);
+
 	g_free(xd->host);
 	g_free(xd->path);
 	g_free(xd->txbuf);
-	g_free(xd->token);
-	g_free(xd->tid);
+	g_free(xd->xfer_peer_idstring);
+	g_free(xd->xfer_idstring_for_relay);
 	if (xd->tx_handler)
 		purple_input_remove(xd->tx_handler);
 	g_free(xd);
 }
 
-
-static void yahoo_xfer_y7_request_next_file(PurpleXfer *xfer)
-{
-	struct yahoo_packet *pack;
-	struct yahoo_xfer_data *xd = xfer->data;
-	PurpleConnection *gc = xd->gc;
-	struct yahoo_data *yd = gc->proto_data;
-
-	g_return_if_fail(xd->y7);
-
-	pack = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFER_ACCEPT, YAHOO_STATUS_AVAILABLE, 0);
-	yahoo_packet_hash(pack, "sssi",
-		1, purple_connection_get_display_name(xd->gc),
-		5, xfer->who,
-		265, xd->tid,
-		271, 1);
-	yahoo_packet_send_and_free(pack, yd);
-}
-
-static void yahoo_xfer_y7_cancel_receive(PurpleXfer *xfer)
-{
-	struct yahoo_packet *pack;
-	struct yahoo_xfer_data *xd = xfer->data;
-	PurpleConnection *gc = xd->gc;
-	struct yahoo_data *yd = gc->proto_data;
-
-	g_return_if_fail(xd->y7);
-
-	pack = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFER_ACCEPT, -1, 0);
-	yahoo_packet_hash(pack, "sssi",
-		1, purple_connection_get_display_name(gc),
-		5, xfer->who,
-		265, xd->tid,
-		66, -1);
-	yahoo_packet_send_and_free(pack, yd);
-}
-
-static void yahoo_xfer_y7_accept_file(PurpleXfer *xfer)
-{
-	struct yahoo_packet *pack;
-	struct yahoo_xfer_data *xd = xfer->data;
-	PurpleConnection *gc = xd->gc;
-	struct yahoo_data *yd = gc->proto_data;
-
-	g_return_if_fail(xd->y7);
-
-	pack = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFER_ACCEPT, YAHOO_STATUS_AVAILABLE, 0);
-	yahoo_packet_hash(pack, "ssssis",
-		1, purple_connection_get_display_name(gc),
-		5, xfer->who,				/* XXX this needs an accessor */
-		265, xd->tid,
-		27, purple_xfer_get_filename(xfer),	/* XXX this might be of incorrect encoding */
-		249, 3,
-		251, xd->token);
-	yahoo_packet_send_and_free(pack, yd);
-}
-
 static void yahoo_receivefile_send_cb(gpointer data, gint source, PurpleInputCondition condition)
 {
 	PurpleXfer *xfer;
@@ -160,7 +146,6 @@
 {
 	PurpleXfer *xfer;
 	struct yahoo_xfer_data *xd;
-	struct yahoo_data *yd;
 
 	purple_debug(PURPLE_DEBUG_INFO, "yahoo",
 			   "AAA - in yahoo_receivefile_connected\n");
@@ -176,22 +161,11 @@
 	}
 
 	xfer->fd = source;
-	yd = xd->gc->proto_data;
 
 	/* The first time we get here, assemble the tx buffer */
 	if (xd->txbuflen == 0) {
-		if (!xd->y7)
-			xd->txbuf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
-				      xd->path, xd->host);
-		else
-			xd->txbuf = g_strdup_printf("GET /%s HTTP/1.0\r\n"
-				"Connection: close\r\n"
-				"Accept: */*\r\n"
-				"Host: %s\r\n"
-				"Cookie: Y=%s; T=%s\r\n"
-				"\r\n",
-				xd->path, xd->host, yd->cookie_y, yd->cookie_t);
-		purple_debug(PURPLE_DEBUG_INFO, "yahoo_filexfer", "HTTP request: [%s]\n", xd->txbuf);
+		xd->txbuf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
+			      xd->path, xd->host);
 		xd->txbuflen = strlen(xd->txbuf);
 		xd->txbuf_written = 0;
 	}
@@ -356,9 +330,6 @@
 			}
 		}
 	} else {
-		if (xfer_data->y7)
-			yahoo_xfer_y7_accept_file(xfer);
-
 		xfer->fd = -1;
 		if (purple_proxy_connect(NULL, account, xfer_data->host, xfer_data->port,
 		                              yahoo_receivefile_connected, xfer) == NULL) {
@@ -369,23 +340,67 @@
 	}
 }
 
+static void yahoo_xfer_init_15(PurpleXfer *xfer)
+{
+	struct yahoo_xfer_data *xfer_data;
+	PurpleConnection *gc;
+	PurpleAccount *account;
+	struct yahoo_data *yd;
+	struct yahoo_packet *pkt;
+
+	xfer_data = xfer->data;
+	gc = xfer_data->gc;
+	yd = gc->proto_data;
+	account = purple_connection_get_account(gc);
+
+	if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND)	{
+		gchar *filename;
+		filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
+		pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
+							   YAHOO_STATUS_AVAILABLE,
+							   yd->session_id);
+		yahoo_packet_hash(pkt, "sssiiiisiii",
+			1, purple_normalize(account, purple_account_get_username(account)),
+			5, xfer->who,
+			265, xfer_data->xfer_peer_idstring,
+			222, 1,
+			266, 1,
+			302, 268,
+			300, 268,
+			27,  filename,
+			28,  xfer->size,
+			301, 268,
+			303, 268);
+		g_free(filename); 
+	} else {
+		if(xfer_data->firstoflist == TRUE) {
+			pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
+				YAHOO_STATUS_AVAILABLE, yd->session_id);
+	
+			yahoo_packet_hash(pkt, "sssi",
+				1, purple_normalize(account, purple_account_get_username(account)),
+				5, xfer->who,
+				265, xfer_data->xfer_peer_idstring,
+				222, 3);
+		} else {
+			pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_ACC_15,
+				YAHOO_STATUS_AVAILABLE, yd->session_id);
+	
+			yahoo_packet_hash(pkt, "sssi",
+				1, purple_normalize(account, purple_account_get_username(account)),
+				5, xfer->who,
+				265, xfer_data->xfer_peer_idstring,
+				271, 1);
+		}
+	}
+	yahoo_packet_send_and_free(pkt, yd);
+}
+
 static void yahoo_xfer_start(PurpleXfer *xfer)
 {
 	/* We don't need to do anything here, do we? */
 }
 
-static void yahoo_xfer_end(PurpleXfer *xfer)
-{
-	struct yahoo_xfer_data *xfer_data;
-
-	xfer_data = xfer->data;
-
-	if (xfer_data)
-		yahoo_xfer_data_free(xfer_data);
-	xfer->data = NULL;
-
-}
-
 static guint calculate_length(const gchar *l, size_t len)
 {
 	int i;
@@ -418,8 +433,6 @@
 		if ((purple_xfer_get_size(xfer) > 0) &&
 		    (purple_xfer_get_bytes_sent(xfer) >= purple_xfer_get_size(xfer))) {
 			purple_xfer_set_completed(xfer, TRUE);
-			if (xd->y7)
-				yahoo_xfer_y7_request_next_file(xfer);
 			return 0;
 		} else
 			return -1;
@@ -499,6 +512,42 @@
 
 	xfer_data = xfer->data;
 
+	if(purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL && xfer_data->version == 15)
+	{
+		PurpleConnection *gc;
+		PurpleAccount *account;
+		struct yahoo_data *yd;
+		struct yahoo_packet *pkt;
+
+		gc = xfer_data->gc;
+		yd = gc->proto_data;
+		account = purple_connection_get_account(gc);
+		if(xfer_data->xfer_idstring_for_relay) /* hack to see if file trans acc/info packet has been received */
+		{
+			pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15,
+								   YAHOO_STATUS_DISCONNECTED,
+								   yd->session_id);
+			yahoo_packet_hash(pkt, "sssi",
+				1, purple_normalize(account, purple_account_get_username(account)),
+				5, xfer->who,
+				265, xfer_data->xfer_peer_idstring,
+				66, -1);
+		}
+		else
+		{
+			pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
+								   YAHOO_STATUS_AVAILABLE,
+								   yd->session_id);
+			yahoo_packet_hash(pkt, "sssi",
+				1, purple_normalize(account, purple_account_get_username(account)),
+				5, xfer->who,
+				265, xfer_data->xfer_peer_idstring,
+				222, 2);
+		}
+		yahoo_packet_send_and_free(pkt, yd);
+	}
+
+
 	if (xfer_data)
 		yahoo_xfer_data_free(xfer_data);
 	xfer->data = NULL;
@@ -510,22 +559,145 @@
 
 	xfer_data = xfer->data;
 
-	if (xfer_data) {
-		if (xfer_data->y7)
-			yahoo_xfer_y7_cancel_receive(xfer);
+	if(purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL && xfer_data->version == 15)
+	{
+
+		PurpleConnection *gc;
+		PurpleAccount *account;
+		struct yahoo_data *yd;
+		struct yahoo_packet *pkt;
+
+		gc = xfer_data->gc;
+		yd = gc->proto_data;
+		account = purple_connection_get_account(gc);
+		if(!xfer_data->xfer_idstring_for_relay) /* hack to see if file trans acc/info packet has been received */
+		{
+			pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
+								   YAHOO_STATUS_AVAILABLE,
+								   yd->session_id);
+			yahoo_packet_hash(pkt, "sssi",
+				1, purple_normalize(account, purple_account_get_username(account)),
+				5, xfer->who,
+				265, xfer_data->xfer_peer_idstring,
+				222, 4);
+		}
+		else
+		{
+			pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
+								   YAHOO_STATUS_DISCONNECTED,
+								   yd->session_id);
+			yahoo_packet_hash(pkt, "sssi",
+				1, purple_normalize(account, purple_account_get_username(account)),
+				5, xfer->who,
+				265, xfer_data->xfer_peer_idstring,
+				66, -1);
+		}
+		yahoo_packet_send_and_free(pkt, yd);
+	}
+
+	if (xfer_data)
 		yahoo_xfer_data_free(xfer_data);
-	}
 	xfer->data = NULL;
 }
 
-static void yahoo_xfer_request_denied(PurpleXfer *xfer)
+static void yahoo_xfer_end(PurpleXfer *xfer_old)
 {
 	struct yahoo_xfer_data *xfer_data;
+	PurpleXfer *xfer = NULL;
+	PurpleConnection *gc;
+	struct yahoo_data *yd;
 
-	xfer_data = xfer->data;
+	xfer_data = xfer_old->data;
+	if(xfer_data && xfer_data->version == 15
+	   && purple_xfer_get_type(xfer_old) == PURPLE_XFER_RECEIVE
+	   && xfer_data->filename_list) {
+		
+		/* removing top of filename & size list completely */
+		g_free( xfer_data->filename_list->data );
+		g_free( xfer_data->size_list->data );
+		   
+		xfer_data->filename_list->data = NULL;
+		xfer_data->size_list->data = NULL;
+		   
+		xfer_data->filename_list = g_slist_delete_link(xfer_data->filename_list, xfer_data->filename_list);
+		xfer_data->size_list = g_slist_delete_link(xfer_data->size_list, xfer_data->size_list);
+
+		/* if there are still more files */
+		if(xfer_data->filename_list)
+		{
+			gchar* filename;
+			long filesize;
+
+			filename = xfer_data->filename_list->data;
+			filesize = atol( xfer_data->size_list->data );
+
+			gc = xfer_data->gc;
+			yd = gc->proto_data;
 
-	if (xfer_data->y7)
-		yahoo_xfer_y7_cancel_receive(xfer);
+			/* setting up xfer_data for next file's tranfer */
+			g_free(xfer_data->host);
+			g_free(xfer_data->path);
+			g_free(xfer_data->txbuf);
+			g_free(xfer_data->rxqueue);
+			g_free(xfer_data->xfer_idstring_for_relay);
+			if (xfer_data->tx_handler)
+				purple_input_remove(xfer_data->tx_handler);
+			xfer_data->host = NULL;
+			xfer_data->host = NULL;
+			xfer_data->port = 0;
+			xfer_data->expires = 0;
+			xfer_data->started = FALSE;
+			xfer_data->txbuf = NULL;
+			xfer_data->txbuflen = 0;
+			xfer_data->txbuf_written = 0;
+			xfer_data->tx_handler = 0;
+			xfer_data->rxqueue = NULL;
+			xfer_data->rxlen = 0;
+			xfer_data->xfer_idstring_for_relay = NULL;
+			xfer_data->info_val_249 = 0;
+			xfer_data->status_15 = STARTED;
+			xfer_data->firstoflist = FALSE;
+
+			/* Dereference xfer_data from old xfer */
+			xfer_old->data = NULL;
+
+			/* Build the file transfer handle. */
+			xfer = purple_xfer_new(gc->account, PURPLE_XFER_RECEIVE, xfer_old->who);
+
+			
+			if (xfer) {
+				/* Set the info about the incoming file. */
+				char *utf8_filename = yahoo_string_decode(gc, filename, TRUE);
+				purple_xfer_set_filename(xfer, utf8_filename);
+				g_free(utf8_filename);
+				purple_xfer_set_size(xfer, filesize);
+		
+				xfer->data = xfer_data;
+	
+				/* Setup our I/O op functions */
+				purple_xfer_set_init_fnc(xfer,        yahoo_xfer_init_15);
+				purple_xfer_set_start_fnc(xfer,       yahoo_xfer_start);
+				purple_xfer_set_end_fnc(xfer,         yahoo_xfer_end);
+				purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
+				purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
+				purple_xfer_set_read_fnc(xfer,        yahoo_xfer_read);
+				purple_xfer_set_write_fnc(xfer,       yahoo_xfer_write);
+				purple_xfer_set_request_denied_fnc(xfer,yahoo_xfer_cancel_recv);
+
+				/*update map to current xfer*/
+				g_hash_table_remove(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring);
+				g_hash_table_insert(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring, xfer);
+
+				/* Now perform the request */
+				purple_xfer_request(xfer);
+			}
+			return;
+		}
+	}
+	if (xfer_data)
+		yahoo_xfer_data_free(xfer_data);
+	xfer_old->data = NULL;
+
 }
 
 void yahoo_process_p2pfilexfer(PurpleConnection *gc, struct yahoo_packet *pkt)
@@ -721,165 +893,6 @@
 	}
 }
 
-void yahoo_process_y7_filetransfer(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	char *who = NULL, *name = NULL;
-	int ttype = 0;
-	char *tid = NULL;
-	GSList *l = pkt->hash;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 4:
-			/* them */
-			who = pair->value;
-			break;
-		case 5:
-			/* us */
-			name = pair->value;
-			break;
-		case 222:
-			/* 1=send, 2=cancel, 3=accept, 4=reject */
-			if(pair->value)
-				ttype = atoi(pair->value);
-			break;
-		case 265:
-			/* transfer ID */
-			tid = pair->value;
-			break;
-		case 266:
-			/* number of files */
-			break;
-		case 27:
-			/* filename */
-			break;
-		case 28:
-			/* filesize */
-			break;
-		}
-
-		l = l->next;
-	}
-	if (ttype == 1 && tid) {
-		/* We auto-accept all offers here, and ask the user about each individual
-		 * file in yahoo_process_y7_filetransfer_info. This works fine for receiving
-		 * a single file; when receiving multiple canceling one in the middle
-		 * will also cancel the rest of them.
-		 * Maybe TODO: UI and API allowing transfer of multiple files as a package. */
-		struct yahoo_packet *pack;
-		pack = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFER, YAHOO_STATUS_AVAILABLE, 0);
-		yahoo_packet_hash(pack, "sssi", 1, name, 5, who, 265, tid, 222, 3);
-		yahoo_packet_send_and_free(pack, yd);
-	}
-}
-
-void yahoo_process_y7_filetransfer_info(PurpleConnection *gc, struct yahoo_packet *pkt)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	char *who = NULL, *name = NULL;
-	int medium = 0;
-	char *tid = NULL, *server_host = NULL, *server_token = NULL, *filename = NULL;
-	GSList *l = pkt->hash;
-	struct yahoo_packet *pack;
-	PurpleXfer *xfer;
-	struct yahoo_xfer_data *xfer_data;
-
-	while (l) {
-		struct yahoo_pair *pair = l->data;
-
-		switch (pair->key) {
-		case 4:
-			/* them */
-			who = pair->value;
-			break;
-		case 5:
-			/* us */
-			name = pair->value;
-			break;
-		case 249:
-			/* 1=p2p, 3=reflection server */
-			if(pair->value)
-				medium = atoi(pair->value);
-			break;
-		case 265:
-			/* transfer ID */
-			tid = pair->value;
-			break;
-		case 27:
-			filename = pair->value;
-			break;
-		case 250:
-			server_host = pair->value;
-			break;
-		case 251:
-			server_token = pair->value;
-			break;
-		}
-
-		l = l->next;
-	}
-	if (medium == 1) {
-		/* reject P2P transfers */
-		pack = yahoo_packet_new(YAHOO_SERVICE_Y7_FILETRANSFER_ACCEPT, YAHOO_STATUS_AVAILABLE, 0);
-		yahoo_packet_hash(pack, "sssi", 1, name, 5, who, 265, tid, 66, -3);
-		yahoo_packet_send_and_free(pack, yd);
-		return;
-	}
-
-	if (medium != 3) {
-		purple_debug_error("yahoo", "Unexpected medium %d.\n", medium);
-		/* weird */
-		return;
-	}
-
-	/* Setup the Yahoo-specific file transfer data */
-	xfer_data = g_new0(struct yahoo_xfer_data, 1);
-	xfer_data->gc = gc;
-	xfer_data->host = g_strdup(server_host);
-	xfer_data->token = g_strdup(server_token);
-	xfer_data->tid = g_strdup(tid);
-	xfer_data->port = 80;
-	xfer_data->y7 = TRUE;
-	
-	/* TODO: full urlencode here */
-	server_token = purple_strreplace(server_token, "\002", "%02");
-	xfer_data->path = g_strdup_printf("relay?token=%s&sender=%s&recver=%s",
-		server_token, who, name);
-	g_free(server_token);
-
-	purple_debug_misc("yahoo_filexfer", "Host is %s, port is %d, path is %s.\n",
-	                xfer_data->host, xfer_data->port, xfer_data->path);
-
-	/* Build the file transfer handle. */
-	xfer = purple_xfer_new(gc->account, PURPLE_XFER_RECEIVE, who);
-	xfer->data = xfer_data;
-
-	/* Set the info about the incoming file. */
-	{
-		char *utf8_filename = yahoo_string_decode(gc, filename, TRUE);
-		purple_xfer_set_filename(xfer, utf8_filename);
-		g_free(utf8_filename);
-	}
-
-	/* purple_xfer_set_size(xfer, filesize); */
-
-	/* Setup our I/O op functions */
-	purple_xfer_set_init_fnc(xfer,        yahoo_xfer_init);
-	purple_xfer_set_start_fnc(xfer,       yahoo_xfer_start);
-	purple_xfer_set_end_fnc(xfer,         yahoo_xfer_end);
-	purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
-	purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
-	purple_xfer_set_read_fnc(xfer,        yahoo_xfer_read);
-	purple_xfer_set_write_fnc(xfer,       yahoo_xfer_write);
-	purple_xfer_set_request_denied_fnc(xfer, yahoo_xfer_request_denied);
-
-	/* Now perform the request */
-	purple_xfer_request(xfer);
-}
-
 PurpleXfer *yahoo_new_xfer(PurpleConnection *gc, const char *who)
 {
 	PurpleXfer *xfer;
@@ -909,15 +922,641 @@
 	return xfer;
 }
 
+static gchar* yahoo_xfer_new_xfer_id()
+{
+	gchar *ans;
+	int i,j;
+	ans = g_strnfill(24, ' ');
+	ans[23] = '$';
+	ans[22] = '$';
+	for(i = 0; i < 22; i++)
+	{
+		j = g_random_int_range (0,61);
+		if(j < 26)
+			ans[i] = j + 'a';
+		else if(j < 52)
+			ans[i] = j - 26 + 'A';
+		else
+			ans[i] = j - 52 + '0';     
+	}
+	return ans;
+}
+
+static void yahoo_xfer_dns_connected_15(GSList *hosts, gpointer data, const char *error_message)
+{
+	PurpleXfer *xfer;
+	struct yahoo_xfer_data *xd;
+	struct sockaddr_in *addr;
+	struct yahoo_packet *pkt;
+	long actaddr;
+	long a,b,c,d;
+	PurpleConnection *gc;
+	PurpleAccount *account;
+	struct yahoo_data *yd;
+	gchar *url;
+	gchar *filename;
+
+	if (!(xfer = data))
+		return;
+	if (!(xd = xfer->data))
+		return;
+	gc = xd->gc;
+	account = purple_connection_get_account(gc);
+	yd = gc->proto_data;
+
+	if(!hosts)
+	{
+		purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+	
+	/* Discard the length... */
+	hosts = g_slist_remove(hosts, hosts->data);
+	if(!hosts)
+	{
+		purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+	
+	/*TODO:actually, u must try with addr no.1 , if its not working addr no.2 .....*/
+	addr = hosts->data;
+	actaddr = addr->sin_addr.s_addr;
+	d = actaddr % 256;
+	actaddr = (actaddr - d) / 256;
+	c = actaddr % 256;
+	actaddr = (actaddr - c) / 256;
+	b = actaddr % 256;
+	actaddr = (actaddr - b) / 256;
+	a = actaddr;
+	if(yd->jp)
+		xd->port = YAHOOJP_XFER_RELAY_PORT;
+	else
+		xd->port = YAHOO_XFER_RELAY_PORT;
+
+	url = g_strdup_printf("%ld.%ld.%ld.%ld", d, c, b, a);
+	if (!purple_url_parse(url, &(xd->host), &(xd->port), &(xd->path), NULL, NULL)) {
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+	g_free(url);
+	/* Free the address... */
+	g_free(hosts->data);
+	hosts = g_slist_remove(hosts, hosts->data);
+	addr = NULL;
+	while (hosts != NULL)
+	{
+		/* Discard the length... */
+		hosts = g_slist_remove(hosts, hosts->data);
+		/* Free the address... */
+		g_free(hosts->data);
+		hosts = g_slist_remove(hosts, hosts->data);
+	}
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
+	filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
+
+	yahoo_packet_hash(pkt, "ssssis",
+		1, purple_normalize(account, purple_account_get_username(account)),
+		5, xfer->who,
+		265, xd->xfer_peer_idstring,
+		27,  filename,
+		249, 3,
+		250, xd->host);
+
+	g_free(filename);
+	yahoo_packet_send_and_free(pkt, yd);
+}
+
+
 void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file)
 {
+	struct yahoo_xfer_data *xfer_data;
+	struct yahoo_data *yd;
+	int ver = 0;
 	PurpleXfer *xfer = yahoo_new_xfer(gc, who);
+	YahooFriend *yf = yahoo_friend_find(gc, who);
 
+	/* To determine whether client uses ymsg 15 i.e. client is higher than YM 7 */
+	if(yf && yf->version_id > 500000)
+		ver=15; 
 	g_return_if_fail(xfer != NULL);
 
+	if(ver == 15) {
+		yd = gc->proto_data;
+		xfer_data = xfer->data;
+		xfer_data->status_15 = STARTED;
+		purple_xfer_set_init_fnc(xfer, yahoo_xfer_init_15);
+		xfer_data->version = 15;
+		xfer_data->xfer_peer_idstring = yahoo_xfer_new_xfer_id();
+		g_hash_table_insert(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring, xfer);
+	}
+
 	/* Now perform the request */
 	if (file)
 		purple_xfer_request_accepted(xfer, file);
 	else
 		purple_xfer_request(xfer);
 }
+
+static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message);/*using this in recv_cb*/
+static void yahoo_xfer_recv_cb_15(gpointer data, gint source, PurpleInputCondition condition)
+{
+	PurpleXfer *xfer;
+	struct yahoo_xfer_data *xd;
+	int did;
+	gchar* buf;
+	gchar* t;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+
+	xfer = data;
+	xd = xfer->data;
+	account = purple_connection_get_account(xd->gc);
+	gc = xd->gc;
+
+	buf=g_strnfill(1000, 0);
+	while((did = read(source, buf, 998)) > 0)
+	{
+		xd->txbuflen += did;
+		buf[did] = '\0';  
+		t = xd->txbuf;
+		xd->txbuf = g_strconcat(t,buf,NULL);
+		g_free(t);
+	}
+	g_free(buf);
+
+	if (did < 0 && errno == EAGAIN) return;
+	else if (did < 0) {
+		purple_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno);
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+
+	purple_input_remove(xd->tx_handler);
+	xd->tx_handler = 0;
+	xd->txbuflen = 0;
+
+	if(xd->status_15 == HEAD_REQUESTED) {
+		xd->status_15 = HEAD_REPLY_RECEIVED;
+		close(source);/*Is this required?*/
+		g_free(xd->txbuf);
+		xd->txbuf = NULL;
+		if (purple_proxy_connect(NULL, account, xd->host, xd->port, yahoo_xfer_connected_15, xfer) == NULL)
+		{
+			purple_notify_error(gc, NULL, _("File Transfer Failed"),
+				_("Unable to establish file descriptor."));
+			purple_xfer_cancel_remote(xfer);
+		}
+	} else {
+		purple_debug_error("yahoo","Unrecognized yahoo file transfer mode and stage (ymsg15):%d,%d\n",
+						   purple_xfer_get_type(xfer),
+						   xd->status_15);
+		return;
+	}
+}
+
+static void yahoo_xfer_send_cb_15(gpointer data, gint source, PurpleInputCondition condition)
+{
+	PurpleXfer *xfer;
+	struct yahoo_xfer_data *xd;
+	int remaining, written;
+
+	xfer = data;
+	xd = xfer->data;
+	remaining = xd->txbuflen - xd->txbuf_written;
+	written = write(source, xd->txbuf + xd->txbuf_written, remaining);
+
+	if (written < 0 && errno == EAGAIN)
+		written = 0;
+	else if (written <= 0) {
+		purple_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno);
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+
+	if (written < remaining) {
+		xd->txbuf_written += written;
+		return;
+	}
+
+	purple_input_remove(xd->tx_handler);
+	xd->tx_handler = 0;
+	g_free(xd->txbuf);
+	xd->txbuf = NULL;
+	xd->txbuflen = 0;
+	xd->txbuf_written = 0;
+
+	if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == STARTED)
+	{	
+		xd->status_15 = HEAD_REQUESTED;
+		xd->tx_handler = purple_input_add(source, PURPLE_INPUT_READ, yahoo_xfer_recv_cb_15, xfer);
+		yahoo_xfer_recv_cb_15(xfer, source, PURPLE_INPUT_READ);
+	}
+	else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == HEAD_REPLY_RECEIVED)
+	{
+		xd->status_15 = TRANSFER_PHASE;
+		xfer->fd = source;
+		purple_xfer_start(xfer, source, NULL, 0);
+	}
+	else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == ACCEPTED)
+	{
+		xd->status_15 = TRANSFER_PHASE;
+		xfer->fd = source;
+		purple_xfer_start(xfer, source, NULL, 0);
+	}
+	else
+	{
+		purple_debug_error("yahoo", "Unrecognized yahoo file transfer mode and stage (ymsg15):%d,%d\n", purple_xfer_get_type(xfer), xd->status_15);
+		return;
+	}
+
+}
+
+
+static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message)
+{
+	PurpleXfer *xfer;
+	struct yahoo_xfer_data *xd;
+	PurpleAccount *account;
+	struct yahoo_data* yd;
+
+	if (!(xfer = data))
+		return;
+	if (!(xd = xfer->data))
+		return;
+	yd = xd->gc->proto_data;
+	account = purple_connection_get_account(xd->gc);
+	if ((source < 0) || (xd->path == NULL) || (xd->host == NULL)) {
+		purple_xfer_error(PURPLE_XFER_RECEIVE, purple_xfer_get_account(xfer),
+			xfer->who, _("Unable to connect."));
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+	/* The first time we get here, assemble the tx buffer */
+	if (xd->txbuflen == 0)
+	{
+		gchar* cookies;
+		cookies = yahoo_get_cookies(xd->gc);
+		if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == ACCEPTED)
+		{
+			xd->txbuf = g_strdup_printf("POST /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\nCookie:%s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost: %s\r\nContent-Length: %ld\r\nCache-Control: no-cache\r\n\r\n",
+										purple_url_encode(xd->xfer_idstring_for_relay),
+										purple_normalize(account, purple_account_get_username(account)),
+										xfer->who,
+										cookies,
+										xd->host,
+										(long int)xfer->size);
+		}
+		else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == STARTED)
+		{	
+			xd->txbuf = g_strdup_printf("HEAD /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\nAccept:*/*\r\nCookie:%s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost:%s\r\nContent-Length: 0\r\nCache-Control: no-cache\r\n\r\n",
+										purple_url_encode(xd->xfer_idstring_for_relay),
+										purple_normalize(account, purple_account_get_username(account)),
+										xfer->who,
+										cookies,
+										xd->host);
+		}
+		else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == HEAD_REPLY_RECEIVED)
+		{
+			xd->txbuf = g_strdup_printf("GET /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\nCookie:%s\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\nHost:%s\r\nConnection: Keep-Alive\r\n\r\n",
+										purple_url_encode(xd->xfer_idstring_for_relay),
+										purple_normalize(account, purple_account_get_username(account)),
+										xfer->who,
+										cookies,
+										xd->host);
+		}
+		else
+		{
+			purple_debug_error("yahoo", "Unrecognized yahoo file transfer mode and stage (ymsg15):%d,%d\n", purple_xfer_get_type(xfer), xd->status_15);
+			g_free(cookies);
+			return;
+		}
+		xd->txbuflen = strlen(xd->txbuf);
+		xd->txbuf_written = 0;
+		g_free(cookies);
+	}
+
+	if (!xd->tx_handler)
+	{
+		xd->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE,
+			yahoo_xfer_send_cb_15, xfer);
+		yahoo_xfer_send_cb_15(xfer, source, PURPLE_INPUT_WRITE);
+	}
+}
+
+void yahoo_process_filetrans_15(PurpleConnection *gc, struct yahoo_packet *pkt)
+{
+	char *from = NULL;
+	char *to = NULL;
+	char *imv = NULL;
+	long val_222 = 0L;
+	PurpleXfer *xfer;
+	struct yahoo_data *yd;
+	struct yahoo_xfer_data *xfer_data;
+	char *service = NULL;
+	char *filename = NULL;
+	char *xfer_peer_idstring = NULL;
+	unsigned long filesize = 0L;
+	GSList *l;
+	GSList *filename_list = NULL;
+	GSList *size_list = NULL;
+	int nooffiles = 0;
+	
+	yd = gc->proto_data;
+
+	for (l = pkt->hash; l; l = l->next) {
+		struct yahoo_pair *pair = l->data;
+
+		switch (pair->key) {
+		case 4:
+			from = pair->value;
+			break;
+		case 5:
+			to = pair->value;
+			break;
+		case 265:
+			xfer_peer_idstring = pair->value;
+			break;
+		case 27:
+			filename_list = g_slist_prepend(filename_list, g_strdup(pair->value));
+			nooffiles++;
+			break;
+		case 28:
+			size_list = g_slist_prepend(size_list, g_strdup(pair->value));
+			break;
+		case 222:
+			val_222 = atol(pair->value);
+			/* 1=send, 2=cancel, 3=accept, 4=reject */ 
+			break;
+
+		/*check for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it.*/
+		case 49:
+			service = pair->value;
+			break;
+		case 63:
+			imv = pair->value;
+			break;
+		/*end check*/
+
+		}
+	}
+	if(!xfer_peer_idstring)
+		return;
+
+	if(val_222 == 2 || val_222 == 4)
+	{
+		xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map,
+								   xfer_peer_idstring);
+		if(!xfer) return;
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+	if(val_222 == 3)
+	{
+		xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map,
+								   xfer_peer_idstring);
+		if(!xfer)
+			return;
+		/*
+		*	In the file trans info packet tht we must reply with , we are supposed to mention the ip address...
+		*	purple connect does not give me a way of finding the ip address...
+		*	so, purple dnsquery is used... but retries, trying with next ip address etc. is not implemented..TODO
+		*/
+		if (yd->jp)
+		{
+			purple_dnsquery_a(YAHOOJP_XFER_RELAY_HOST, YAHOOJP_XFER_RELAY_PORT, yahoo_xfer_dns_connected_15, xfer);
+		}
+		else
+		{
+			purple_dnsquery_a(YAHOO_XFER_RELAY_HOST, YAHOO_XFER_RELAY_PORT, yahoo_xfer_dns_connected_15, xfer);
+		}
+		return;
+	}
+
+	/*processing for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it.*/
+	/*
+	* The remote user has changed their IMVironment.  We
+	* record it for later use.
+	*/
+	if (from && imv && service && (strcmp("IMVIRONMENT", service) == 0)) {
+		g_hash_table_replace(yd->imvironments, g_strdup(from), g_strdup(imv));
+		return;
+	}
+	
+	if (pkt->service == YAHOO_SERVICE_P2PFILEXFER) {
+		if (service && (strcmp("FILEXFER", service) != 0)) {
+			purple_debug_misc("yahoo", "unhandled service 0x%02x\n", pkt->service);
+			return;
+		}
+	}
+	/*end processing*/
+
+	if(!filename_list)
+		return;
+	/* have to change list into order in which client at other end sends */
+	filename_list = g_slist_reverse(filename_list);
+	size_list = g_slist_reverse(size_list);
+	filename = filename_list->data;
+	filesize = atol(size_list->data);
+
+	if(!from) return;
+	xfer_data = g_new0(struct yahoo_xfer_data, 1);
+	xfer_data->version = 15;
+	xfer_data->firstoflist = TRUE;
+	xfer_data->gc = gc;
+	xfer_data->xfer_peer_idstring = g_strdup(xfer_peer_idstring);
+	xfer_data->filename_list = filename_list;
+	xfer_data->size_list = size_list;
+	
+	/* Build the file transfer handle. */
+	xfer = purple_xfer_new(gc->account, PURPLE_XFER_RECEIVE, from);
+	xfer->message = NULL;
+
+	if (xfer)
+	{
+		/* Set the info about the incoming file. */
+		char *utf8_filename = yahoo_string_decode(gc, filename, TRUE);
+		purple_xfer_set_filename(xfer, utf8_filename);
+		g_free(utf8_filename);
+		purple_xfer_set_size(xfer, filesize);
+
+		xfer->data = xfer_data;
+
+
+		/* Setup our I/O op functions */
+		purple_xfer_set_init_fnc(xfer,        yahoo_xfer_init_15);
+		purple_xfer_set_start_fnc(xfer,       yahoo_xfer_start);
+		purple_xfer_set_end_fnc(xfer,         yahoo_xfer_end);
+		purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
+		purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
+		purple_xfer_set_read_fnc(xfer,        yahoo_xfer_read);
+		purple_xfer_set_write_fnc(xfer,       yahoo_xfer_write);
+		purple_xfer_set_request_denied_fnc(xfer,yahoo_xfer_cancel_recv);
+
+		g_hash_table_insert(yd->xfer_peer_idstring_map,
+							xfer_data->xfer_peer_idstring,
+							xfer);
+		
+		if(nooffiles > 1) {
+			gchar* message;
+			message = g_strdup_printf(_("%s is trying to send you a group of %d files.\n"), xfer->who, nooffiles);
+			purple_xfer_conversation_write(xfer, message, FALSE);
+			g_free(message);
+		}
+		/* Now perform the request */
+		purple_xfer_request(xfer);
+	}
+}
+
+void yahoo_process_filetrans_info_15(PurpleConnection *gc, struct yahoo_packet *pkt)
+{
+	char *from = NULL;
+	char *to = NULL;
+	char *url = NULL;
+	long val_249 = 0;
+	long val_66 = 0;
+	PurpleXfer *xfer;
+	struct yahoo_data *yd;
+	struct yahoo_xfer_data *xfer_data;
+	char *filename = NULL;
+	char *xfer_peer_idstring = NULL;
+	char *xfer_idstring_for_relay = NULL;
+	GSList *l;
+	struct yahoo_packet *pkt_to_send;
+	PurpleAccount *account;
+
+	yd = gc->proto_data;
+
+	for (l = pkt->hash; l; l = l->next) {
+		struct yahoo_pair *pair = l->data;
+
+		switch (pair->key) {
+		case 4:
+			from = pair->value;
+			break;
+		case 5:
+			to = pair->value;
+			break;
+		case 265:
+			xfer_peer_idstring = pair->value;
+			break;
+		case 27:
+			filename = pair->value;
+			break;
+		case 66:
+			val_66 = strtol(pair->value, NULL, 10);
+			break;
+		case 249:
+			val_249 = strtol(pair->value, NULL, 10); /*
+					* really pissed off with this- i hv seen 2 occurences of this
+					* being 1(its normally 3) - and in those cases, the url
+					* format and corresponding processing seems to be different
+					* (i havent tested - couldnt reproduce a 1), although i 
+					* guess its easier.
+					*/
+			break;
+		case 250:
+			url = pair->value;
+			break;
+		case 251:
+			xfer_idstring_for_relay = pair->value;
+			break;
+		}
+	}
+
+	if(!xfer_peer_idstring)
+		return;
+
+	xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xfer_peer_idstring);
+
+	if(!xfer) return;
+
+	if(val_66==-1)
+	{
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+
+	xfer_data = xfer->data;
+
+	xfer_data->info_val_249 = val_249;
+	xfer_data->xfer_idstring_for_relay = g_strdup(xfer_idstring_for_relay);
+	if (!purple_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL)) {
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+
+	account = purple_connection_get_account(xfer_data->gc);
+
+	pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_ACC_15,
+		YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+	yahoo_packet_hash(pkt_to_send, "ssssisi",
+		1, purple_normalize(account, purple_account_get_username(account)),
+		5, xfer->who,
+		265, xfer_data->xfer_peer_idstring,
+		27, xfer->filename,
+		249, xfer_data->info_val_249,
+		251, xfer_data->xfer_idstring_for_relay,
+		222, 3);
+
+	yahoo_packet_send_and_free(pkt_to_send, yd);
+	if (purple_proxy_connect(NULL, account, xfer_data->host, xfer_data->port,
+		yahoo_xfer_connected_15, xfer) == NULL) {
+		purple_notify_error(gc, NULL, _("File Transfer Failed"),
+			_("Unable to establish file descriptor."));
+		purple_xfer_cancel_remote(xfer);
+		}
+
+}
+/*TODO: Check filename etc. No probs till some hacker comes in the way*/
+void yahoo_process_filetrans_acc_15(PurpleConnection *gc, struct yahoo_packet *pkt)
+{
+	gchar *xfer_peer_idstring = NULL;
+	gchar *xfer_idstring_for_relay = NULL;
+	PurpleXfer *xfer;
+	struct yahoo_data *yd;
+	struct yahoo_xfer_data *xfer_data;
+	GSList *l;
+	PurpleAccount *account;
+	long val_66 = 0;
+
+	yd = gc->proto_data;
+	for (l = pkt->hash; l; l = l->next) {
+		struct yahoo_pair *pair = l->data;
+
+		switch (pair->key) {
+		case 251:
+			xfer_idstring_for_relay = pair->value;
+			break;
+		case 265:
+			xfer_peer_idstring = pair->value;
+			break;
+		case 66:
+			val_66 = atol(pair->value);
+		}
+	}
+
+	xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xfer_peer_idstring);
+	if(!xfer) return;
+
+	if(val_66 == -1 || !(xfer_idstring_for_relay))
+	{
+		purple_xfer_cancel_remote(xfer);
+		return;
+	}
+
+	xfer_data = xfer->data;
+	xfer_data->xfer_idstring_for_relay = g_strdup(xfer_idstring_for_relay);
+	xfer_data->status_15 = ACCEPTED;
+	account = purple_connection_get_account(gc);
+
+	if (purple_proxy_connect(NULL, account, xfer_data->host, xfer_data->port,
+		yahoo_xfer_connected_15, xfer) == NULL)
+	{
+		purple_notify_error(gc, NULL, _("File Transfer Failed"),_("Unable to connect"));
+			purple_xfer_cancel_remote(xfer);
+	}
+}
--- a/libpurple/protocols/yahoo/yahoo_filexfer.h	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.h	Mon Jan 14 04:09:03 2008 +0000
@@ -30,16 +30,6 @@
 void yahoo_process_p2pfilexfer( PurpleConnection *gc, struct yahoo_packet *pkt );
 
 /**
- * Process ymsg version 7 file receive invites.
- */
-void yahoo_process_y7_filetransfer(PurpleConnection *gc, struct yahoo_packet *pkt);
-
-/**
- * Process ymsg version 7 file receive connection setups.
- */
-void yahoo_process_y7_filetransfer_info(PurpleConnection *gc, struct yahoo_packet *pkt);
-
-/**
  * Process ymsg file receive invites.
  */
 void yahoo_process_filetransfer(PurpleConnection *gc, struct yahoo_packet *pkt);
@@ -61,4 +51,8 @@
  */
 void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file);
 
+void yahoo_process_filetrans_15(PurpleConnection *gc, struct yahoo_packet *pkt);
+void yahoo_process_filetrans_info_15(PurpleConnection *gc, struct yahoo_packet *pkt);
+void yahoo_process_filetrans_acc_15(PurpleConnection *gc, struct yahoo_packet *pkt);
+
 #endif
--- a/libpurple/protocols/yahoo/yahoo_friend.h	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_friend.h	Mon Jan 14 04:09:03 2008 +0000
@@ -48,6 +48,7 @@
 	gboolean bicon_sent_request;
 	YahooPresenceVisibility presence;
 	int protocol; /* 1=LCS, 2=MSN*/
+	long int version_id;
 } YahooFriend;
 
 YahooFriend *yahoo_friend_find(PurpleConnection *gc, const char *name);
--- a/libpurple/protocols/yahoo/yahoo_packet.h	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_packet.h	Mon Jan 14 04:09:03 2008 +0000
@@ -99,12 +99,12 @@
 	YAHOO_SERVICE_VERIFY_ID_EXISTS = 0xc8,
 	YAHOO_SERVICE_AUDIBLE = 0xd0,
 	YAHOO_SERVICE_AUTH_REQ_15 = 0xd6,
-	YAHOO_SERVICE_Y7_FILETRANSFER = 0xdc,
-	YAHOO_SERVICE_Y7_FILETRANSFER_INFO = 0xdd,
-	YAHOO_SERVICE_Y7_FILETRANSFER_ACCEPT = 0xde,
 	YAHOO_SERVICE_CHGRP_15 = 0xe7,
 	YAHOO_SERVICE_STATUS_15 = 0xf0,
 	YAHOO_SERVICE_LIST_15 = 0xf1,
+	YAHOO_SERVICE_FILETRANS_15 = 0xdc,
+	YAHOO_SERVICE_FILETRANS_INFO_15 = 0xdd,
+	YAHOO_SERVICE_FILETRANS_ACC_15 = 0xde,
 	YAHOO_SERVICE_WEBLOGIN = 0x0226,
 	YAHOO_SERVICE_SMS_MSG = 0x02ea
 };
--- a/libpurple/protocols/yahoo/yahoochat.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoochat.c	Mon Jan 14 04:09:03 2008 +0000
@@ -1461,28 +1461,30 @@
 
 PurpleRoomlist *yahoo_roomlist_get_list(PurpleConnection *gc)
 {
-	struct yahoo_roomlist *yrl;
+	PurpleAccount *account;
 	PurpleRoomlist *rl;
-	const char *rll;
+	PurpleRoomlistField *f;
+	GList *fields = NULL;
+	struct yahoo_roomlist *yrl;
+	const char *rll, *rlurl;
 	char *url;
-	GList *fields = NULL;
-	PurpleRoomlistField *f;
 
-	rll = purple_account_get_string(purple_connection_get_account(gc),
-								  "room_list_locale", YAHOO_ROOMLIST_LOCALE);
+	account = purple_connection_get_account(gc);
 
-	if (rll != NULL && *rll != '\0') {
-		url = g_strdup_printf("%s?chatcat=0&intl=%s",
-	        purple_account_get_string(purple_connection_get_account(gc),
-	        "room_list", YAHOO_ROOMLIST_URL), rll);
-	} else {
-		url = g_strdup_printf("%s?chatcat=0",
-	        purple_account_get_string(purple_connection_get_account(gc),
-	        "room_list", YAHOO_ROOMLIST_URL));
+	/* for Yahoo Japan, it appears there is only one valid URL and locale */
+	if(purple_account_get_bool(account, "yahoojp", FALSE)) {
+		rll = YAHOOJP_ROOMLIST_LOCALE;
+		rlurl = YAHOOJP_ROOMLIST_URL;
+	}
+	else { /* but for the rest of the world that isn't the case */
+		rll = purple_account_get_string(account, "room_list_locale", YAHOO_ROOMLIST_LOCALE);
+		rlurl = purple_account_get_string(account, "room_list", YAHOO_ROOMLIST_URL);
 	}
 
+	url = g_strdup_printf("%s?chatcat=0&intl=%s", rlurl, rll);
+
 	yrl = g_new0(struct yahoo_roomlist, 1);
-	rl = purple_roomlist_new(purple_connection_get_account(gc));
+	rl = purple_roomlist_new(account);
 	yrl->list = rl;
 
 	purple_url_parse(url, &(yrl->host), NULL, &(yrl->path), NULL, NULL);
@@ -1508,7 +1510,7 @@
 
 	purple_roomlist_set_fields(rl, fields);
 
-	if (purple_proxy_connect(NULL, purple_connection_get_account(gc), yrl->host, 80,
+	if (purple_proxy_connect(NULL, account, yrl->host, 80,
 	                       yahoo_roomlist_got_connected, yrl) == NULL)
 	{
 		purple_notify_error(gc, NULL, _("Connection problem"), _("Unable to fetch room list."));
--- a/libpurple/prpl.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/prpl.c	Mon Jan 14 04:09:03 2008 +0000
@@ -29,6 +29,107 @@
 #include "util.h"
 
 /**************************************************************************/
+/** @name Attention Type API                                              */
+/**************************************************************************/
+PurpleAttentionType *
+purple_attention_type_new(const char *ulname, const char *name,
+						const char *inc_desc, const char *out_desc)
+{
+	PurpleAttentionType *attn = g_new0(PurpleAttentionType, 1);
+
+	purple_attention_type_set_name(attn, name);
+	purple_attention_type_set_incoming_desc(attn, inc_desc);
+	purple_attention_type_set_outgoing_desc(attn, out_desc);
+	purple_attention_type_set_unlocalized_name(attn, ulname);
+
+	return attn;
+}
+
+
+void
+purple_attention_type_set_name(PurpleAttentionType *type, const char *name)
+{
+	g_return_if_fail(type != NULL);
+
+	type->name = name;
+}
+
+void
+purple_attention_type_set_incoming_desc(PurpleAttentionType *type, const char *desc)
+{
+	g_return_if_fail(type != NULL);
+
+	type->incoming_description = desc;
+}
+
+void
+purple_attention_type_set_outgoing_desc(PurpleAttentionType *type, const char *desc)
+{
+	g_return_if_fail(type != NULL);
+
+	type->outgoing_description = desc;
+}
+
+void
+purple_attention_type_set_icon_name(PurpleAttentionType *type, const char *name)
+{
+	g_return_if_fail(type != NULL);
+	
+	type->icon_name = name;
+}
+
+void
+purple_attention_type_set_unlocalized_name(PurpleAttentionType *type, const char *ulname)
+{
+	g_return_if_fail(type != NULL);
+
+	type->unlocalized_name = ulname;
+}
+
+const char *
+purple_attention_type_get_name(PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	return type->name;
+}
+
+const char *
+purple_attention_type_get_incoming_desc(PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	return type->incoming_description;
+}
+
+const char *
+purple_attention_type_get_outgoing_desc(PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	return type->outgoing_description;
+}
+
+const char *
+purple_attention_type_get_icon_name(PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	if(type->icon_name == NULL || *(type->icon_name) == '\0')
+		return NULL;
+
+	return type->icon_name;
+}
+
+const char *
+purple_attention_type_get_unlocalized_name(PurpleAttentionType *type)
+{
+	g_return_val_if_fail(type != NULL, NULL);
+
+	return type->unlocalized_name;
+}
+
+/**************************************************************************/
 /** @name Protocol Plugin API  */
 /**************************************************************************/
 void
--- a/libpurple/prpl.h	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/prpl.h	Mon Jan 14 04:09:03 2008 +0000
@@ -99,9 +99,9 @@
 	const char *incoming_description;  /**< Shown when sent */
 	const char *outgoing_description;  /**< Shown when receied */
 	const char *icon_name;             /**< Icon to display (optional) */
+	const char *unlocalized_name;      /**< Unlocalized name for UIs needing it */
 
 	/* Reserved fields for future purposes */
-	gpointer _reserved1;
 	gpointer _reserved2;
 	gpointer _reserved3;
 	gpointer _reserved4;
@@ -412,6 +412,127 @@
 #endif
 
 /**************************************************************************/
+/** @name Attention Type API                                              */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Creates a new #PurpleAttentionType object and sets its mandatory parameters.
+ *
+ * @param ulname A non-localized string that can be used by UIs in need of such
+ *               non-localized strings.  This should be the same as @a name,
+ *               without localization.
+ * @param name A localized string that the UI may display for the event. This
+ *             should be the same string as @a ulname, with localization.
+ * @param inc_desc A localized description shown when the event is received.
+ * @param out_desc A localized description shown when the event is sent.
+ * @return A pointer to the new object.
+ * @since 2.4.0
+ */
+PurpleAttentionType *purple_attention_type_new(const char *ulname, const char *name,
+								const char *inc_desc, const char *out_desc);
+
+/**
+ * Sets the displayed name of the attention-demanding event.
+ *
+ * @param type The attention type.
+ * @param name The localized name that will be displayed by UIs. This should be
+ *             the same string given as the unlocalized name, but with
+ *             localization.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_name(PurpleAttentionType *type, const char *name);
+
+/**
+ * Sets the description of the attention-demanding event shown in  conversations
+ * when the event is received.
+ *
+ * @param type The attention type.
+ * @param desc The localized description for incoming events.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_incoming_desc(PurpleAttentionType *type, const char *desc);
+
+/**
+ * Sets the description of the attention-demanding event shown in conversations
+ * when the event is sent.
+ *
+ * @param type The attention type.
+ * @param desc The localized description for outgoing events.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_outgoing_desc(PurpleAttentionType *type, const char *desc);
+
+/**
+ * Sets the name of the icon to display for the attention event; this is optional.
+ *
+ * @param type The attention type.
+ * @param name The icon's name.
+ * @note Icons are optional for attention events.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_icon_name(PurpleAttentionType *type, const char *name);
+
+/**
+ * Sets the unlocalized name of the attention event; some UIs may need this,
+ * thus it is required.
+ *
+ * @param type The attention type.
+ * @param ulname The unlocalized name.  This should be the same string given as
+ *               the localized name, but without localization.
+ * @since 2.4.0
+ */
+void purple_attention_type_set_unlocalized_name(PurpleAttentionType *type, const char *ulname);
+
+/**
+ * Get the attention type's name as displayed by the UI.
+ *
+ * @param type The attention type.
+ * @return The name.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_name(PurpleAttentionType *type);
+
+/**
+ * Get the attention type's description shown when the event is received.
+ *
+ * @param type The attention type.
+ * @return The description.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_incoming_desc(PurpleAttentionType *type);
+
+/**
+ * Get the attention type's description shown when the event is sent.
+ *
+ * @param type The attention type.
+ * @return The description.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_outgoing_desc(PurpleAttentionType *type);
+
+/**
+ * Get the attention type's icon name.
+ *
+ * @param type The attention type.
+ * @return The icon name or @c NULL if unset/empty.
+ * @note Icons are optional for attention events.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_icon_name(PurpleAttentionType *type);
+
+/**
+ * Get the attention type's unlocalized name; this is useful for some UIs.
+ *
+ * @param type The attention type
+ * @return The unlocalized name.
+ * @since 2.4.0
+ */
+const char *purple_attention_type_get_unlocalized_name(PurpleAttentionType *type);
+
+/*@}*/
+
+/**************************************************************************/
 /** @name Protocol Plugin API                                             */
 /**************************************************************************/
 /*@{*/
--- a/libpurple/util.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/libpurple/util.c	Mon Jan 14 04:09:03 2008 +0000
@@ -4629,6 +4629,15 @@
 #endif /* !_WIN32 */
 }
 
+static void
+set_status_with_attrs(PurpleStatus *status, ...)
+{
+	va_list args;
+	va_start(args, status);
+	purple_status_set_active_with_attrs(status, TRUE, args);
+	va_end(args);
+}
+
 void purple_util_set_current_song(const char *title, const char *artist, const char *album)
 {
 	GList *list = purple_accounts_get_all();
@@ -4644,10 +4653,11 @@
 		if (!tune)
 			continue;
 		if (title) {
-			purple_status_set_active(tune, TRUE);
-			purple_status_set_attr_string(tune, PURPLE_TUNE_TITLE, title);
-			purple_status_set_attr_string(tune, PURPLE_TUNE_ARTIST, artist);
-			purple_status_set_attr_string(tune, PURPLE_TUNE_ALBUM, album);
+			set_status_with_attrs(tune,
+					PURPLE_TUNE_TITLE, title,
+					PURPLE_TUNE_ARTIST, artist,
+					PURPLE_TUNE_ALBUM, album,
+					NULL);
 		} else {
 			purple_status_set_active(tune, FALSE);
 		}
@@ -4659,7 +4669,7 @@
 	GString *string;
 	char *esc;
 
-	if (!title)
+	if (!title || !*title)
 		return NULL;
 
 	esc = g_markup_escape_text(title, -1);
@@ -4667,13 +4677,13 @@
 	g_string_append_printf(string, "%s", esc);
 	g_free(esc);
 
-	if (artist) {
+	if (artist && *artist) {
 		esc = g_markup_escape_text(artist, -1);
 		g_string_append_printf(string, _(" - %s"), esc);
 		g_free(esc);
 	}
 
-	if (album) {
+	if (album && *album) {
 		esc = g_markup_escape_text(album, -1);
 		g_string_append_printf(string, _(" (%s)"), esc);
 		g_free(esc);
--- a/pidgin/gtkaccount.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkaccount.c	Mon Jan 14 04:09:03 2008 +0000
@@ -2177,6 +2177,7 @@
 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
 	dialog->treeview = treeview;
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
+	g_object_unref(G_OBJECT(dialog->model));
 
 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
--- a/pidgin/gtkblist.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkblist.c	Mon Jan 14 04:09:03 2008 +0000
@@ -937,7 +937,6 @@
 pidgin_blist_joinchat_show(void)
 {
 	GtkWidget *hbox, *vbox;
-	GtkWidget *rowbox;
 	GtkWidget *label;
 	PidginBuddyList *gtkblist;
 	GtkWidget *img = NULL;
@@ -981,7 +980,6 @@
 	data->account_menu = pidgin_account_option_menu_new(NULL, FALSE,
 			G_CALLBACK(joinchat_select_account_cb),
 			chat_account_filter_func, data);
-	gtk_box_pack_start(GTK_BOX(rowbox), data->account_menu, TRUE, TRUE, 0);
 
 	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Account:"), data->sg, data->account_menu, TRUE, NULL);
 
@@ -6071,6 +6069,7 @@
 	gtkblist->timeout = 0;
 	gtkblist->drag_timeout = 0;
 	gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL;
+	g_object_unref(G_OBJECT(gtkblist->treemodel));
 	gtkblist->treemodel = NULL;
 	g_object_unref(G_OBJECT(gtkblist->ift));
 	g_object_unref(G_OBJECT(gtkblist->empty_avatar));
--- a/pidgin/gtkcertmgr.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkcertmgr.c	Mon Jan 14 04:09:03 2008 +0000
@@ -422,6 +422,7 @@
 	
 	tpm_dat->listview = listview =
 		GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
+	g_object_unref(G_OBJECT(store));
 	
 	{
 		GtkCellRenderer *renderer;
--- a/pidgin/gtkimhtml.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkimhtml.c	Mon Jan 14 04:09:03 2008 +0000
@@ -1455,6 +1455,9 @@
 	gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL);
 	gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL);
 	gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL);
+#if GTK_CHECK_VERSION(2,8,0)
+	gtk_text_buffer_create_tag(imhtml->text_buffer, "comment", "invisible", FALSE, NULL);
+#endif
 
 	/* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */
 	imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2);
@@ -2981,10 +2984,15 @@
 
 					gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
 
+#if GTK_CHECK_VERSION(2,8,0)
+					wpos = g_snprintf (ws, len, "%s", tag);
+					gtk_text_buffer_insert_with_tags_by_name(imhtml->text_buffer, iter, ws, wpos, "comment", NULL);
+#else
 					if (imhtml->show_comments && !(options & GTK_IMHTML_NO_COMMENTS)) {
 						wpos = g_snprintf (ws, len, "%s", tag);
 						gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
 					}
+#endif
 					ws[0] = '\0'; wpos = 0;
 
 					/* NEW_BIT (NEW_COMMENT_BIT); */
@@ -3130,6 +3138,12 @@
 void       gtk_imhtml_show_comments    (GtkIMHtml        *imhtml,
 					gboolean          show)
 {
+#if GTK_CHECK_VERSION(2,8,0)
+	GtkTextTag *tag;
+	tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "comment");
+	if (tag)
+		g_object_set(G_OBJECT(tag), "invisible", !show, NULL);
+#endif
 	imhtml->show_comments = show;
 }
 
--- a/pidgin/gtkimhtmltoolbar.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Mon Jan 14 04:09:03 2008 +0000
@@ -1312,6 +1312,7 @@
 
 	gtk_box_pack_start(GTK_BOX(hbox), box, FALSE, FALSE, 0);
 	g_object_set_data(G_OBJECT(hbox), "lean-view", box);
+	gtk_widget_show(box);
 
 	purple_prefs_connect_callback(toolbar, PIDGIN_PREFS_ROOT "/conversations/toolbar/wide",
 			imhtmltoolbar_view_pref_changed, toolbar);
--- a/pidgin/gtklog.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtklog.c	Mon Jan 14 04:09:03 2008 +0000
@@ -614,6 +614,7 @@
 	gtk_paned_add1(GTK_PANED(pane), sw);
 	lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
 	lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore));
+	g_object_unref(G_OBJECT(lv->treestore));
 	rend = gtk_cell_renderer_text_new();
 	col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL);
 	gtk_tree_view_append_column (GTK_TREE_VIEW(lv->treeview), col);
--- a/pidgin/gtknotify.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtknotify.c	Mon Jan 14 04:09:03 2008 +0000
@@ -379,6 +379,7 @@
 		mail_dialog->treemodel = gtk_tree_store_new(COLUMNS_PIDGIN_MAIL,
 						GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
 		mail_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(mail_dialog->treemodel));
+		g_object_unref(G_OBJECT(mail_dialog->treemodel));
 		gtk_tree_view_set_search_column(GTK_TREE_VIEW(mail_dialog->treeview), PIDGIN_MAIL_TEXT);
 		gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(mail_dialog->treeview),
 			             pidgin_tree_view_search_equal_func, NULL, NULL);
@@ -818,6 +819,7 @@
 
 	/* Setup the treeview */
 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
+	g_object_unref(G_OBJECT(model));
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
 	gtk_widget_set_size_request(treeview, 500, 400);
 	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
--- a/pidgin/gtkpounce.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkpounce.c	Mon Jan 14 04:09:03 2008 +0000
@@ -1237,6 +1237,7 @@
 
 	/* Create the treeview */
 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
+	g_object_unref(G_OBJECT(dialog->model));
 	dialog->treeview = treeview;
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
 
--- a/pidgin/gtkprefs.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkprefs.c	Mon Jan 14 04:09:03 2008 +0000
@@ -1465,15 +1465,15 @@
 	}
 
 	entry = gtk_entry_new();
-	if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser"), "custom"))
-		gtk_widget_set_sensitive(hbox, FALSE);
-	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/browsers/browser",
-								browser_changed2_cb, hbox);
 	gtk_entry_set_text(GTK_ENTRY(entry),
 					   purple_prefs_get_path(PIDGIN_PREFS_ROOT "/browsers/command"));
 	g_signal_connect(G_OBJECT(entry), "focus-out-event",
 					 G_CALLBACK(manual_browser_set), NULL);
-	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Manual:\n(%s for URL)"), sg, entry, TRUE, NULL);
+	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Manual:\n(%s for URL)"), sg, entry, TRUE, NULL);
+	if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser"), "custom"))
+		gtk_widget_set_sensitive(hbox, FALSE);
+	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/browsers/browser",
+			browser_changed2_cb, hbox);
 
 	gtk_widget_show_all(ret);
 	g_object_unref(sg);
--- a/pidgin/gtkprivacy.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkprivacy.c	Mon Jan 14 04:09:03 2008 +0000
@@ -474,6 +474,8 @@
 	if (privacy_dialog == NULL)
 		return;
 
+	g_object_unref(G_OBJECT(privacy_dialog->allow_store));
+	g_object_unref(G_OBJECT(privacy_dialog->block_store));
 	g_free(privacy_dialog);
 	privacy_dialog = NULL;
 }
--- a/pidgin/gtkrequest.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkrequest.c	Mon Jan 14 04:09:03 2008 +0000
@@ -1007,6 +1007,7 @@
 
 	/* Create the tree view */
 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+	g_object_unref(G_OBJECT(store));
 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
 
 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
--- a/pidgin/gtksavedstatuses.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtksavedstatuses.c	Mon Jan 14 04:09:03 2008 +0000
@@ -669,6 +669,7 @@
 	purple_request_close_with_handle(status_window);
 	purple_notify_close_with_handle(status_window);
 	purple_signals_disconnect_by_handle(status_window);
+	g_object_unref(G_OBJECT(status_window->model));
 	g_free(status_window);
 	status_window = NULL;
 }
@@ -723,6 +724,7 @@
 
 	status_editor_remove_dialog(dialog);
 	g_free(dialog->original_title);
+	g_object_unref(G_OBJECT(dialog->model));
 	g_free(dialog);
 
 	return FALSE;
--- a/pidgin/gtkstatusbox.c	Mon Jan 14 04:04:08 2008 +0000
+++ b/pidgin/gtkstatusbox.c	Mon Jan 14 04:09:03 2008 +0000
@@ -515,16 +515,10 @@
 	purple_signals_disconnect_by_handle(statusbox);
 	purple_prefs_disconnect_by_handle(statusbox);
 
-	gdk_cursor_unref(statusbox->hand_cursor);
-	gdk_cursor_unref(statusbox->arrow_cursor);
+	destroy_icon_box(statusbox);
 
-	purple_imgstore_unref(statusbox->buddy_icon_img);
-	g_object_unref(G_OBJECT(statusbox->buddy_icon));
-	g_object_unref(G_OBJECT(statusbox->buddy_icon_hover));
-
-	if (statusbox->buddy_icon_sel)
-		gtk_widget_destroy(statusbox->buddy_icon_sel);
-
+	g_object_unref(G_OBJECT(statusbox->store));
+	g_object_unref(G_OBJECT(statusbox->dropdown_store));
 	G_OBJECT_CLASS(parent_class)->finalize(obj);
 }