changeset 22080:d6f174c2a83e

propagate from branch 'im.pidgin.pidgin' (head cc7917983d28560aebe8a2b4ba1d8135b856dce5) to branch 'im.pidgin.cpw.rekkanoryo.yahoop15ft' (head 3ad28b49e94fba6bc334942467f846240663721f)
author John Bailey <rekkanoryo@rekkanoryo.org>
date Sat, 12 Jan 2008 02:24:51 +0000
parents eeba86c553be (diff) f808629a0123 (current diff)
children 9bddfb6df976
files COPYRIGHT libpurple/protocols/yahoo/yahoo.c
diffstat 9 files changed, 1053 insertions(+), 302 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Fri Jan 11 00:01:33 2008 +0000
+++ b/COPYRIGHT	Sat Jan 12 02:24:51 2008 +0000
@@ -322,6 +322,7 @@
 Jean-Francois Roy
 Peter Ruibal
 Sam S.
+Thanumalayan S.
 Pradyumna Sampath
 Arvind Samptur
 Tom Samstag
--- a/ChangeLog	Fri Jan 11 00:01:33 2008 +0000
+++ b/ChangeLog	Sat Jan 12 02:24:51 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)
--- a/libpurple/protocols/yahoo/util.c	Fri Jan 11 00:01:33 2008 +0000
+++ b/libpurple/protocols/yahoo/util.c	Sat Jan 12 02:24:51 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	Fri Jan 11 00:01:33 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Sat Jan 12 02:24:51 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);
--- a/libpurple/protocols/yahoo/yahoo.h	Fri Jan 11 00:01:33 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.h	Sat Jan 12 02:24:51 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,9 @@
 #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 YAHOO_AUDIBLE_URL "http://us.dl1.yimg.com/download.yahoo.com/dl/aud"
 
@@ -67,6 +72,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 +94,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 +143,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 +162,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 +222,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	Fri Jan 11 00:01:33 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Sat Jan 12 02:24:51 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	Fri Jan 11 00:01:33 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.h	Sat Jan 12 02:24:51 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	Fri Jan 11 00:01:33 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_friend.h	Sat Jan 12 02:24:51 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	Fri Jan 11 00:01:33 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_packet.h	Sat Jan 12 02:24:51 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_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
 };