Mercurial > pidgin
changeset 22018:118046227581
This patch from Thanumalayan S. implements Yahoo protocol version 15 file
transfer support. Currently sending multiple files from an official Yahoo
client is treated as multiple individual transfers that must be accepted
separately. This also changes things so that we identify as Yahoo Messenger
version 8.0 (previously we were identifying as 6.0 or not at all).
committer: John Bailey <rekkanoryo@rekkanoryo.org>
author | Thanumalayan <madthanu@gmail.com> |
---|---|
date | Sun, 06 Jan 2008 19:45:03 +0000 |
parents | 97d530d11cc0 |
children | 0ae2e64dcff9 |
files | libpurple/protocols/yahoo/util.c libpurple/protocols/yahoo/yahoo.c libpurple/protocols/yahoo/yahoo.h libpurple/protocols/yahoo/yahoo_filexfer.c libpurple/protocols/yahoo/yahoo_filexfer.h libpurple/protocols/yahoo/yahoo_friend.h libpurple/protocols/yahoo/yahoo_packet.h |
diffstat | 7 files changed, 1030 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/yahoo/util.c Sun Jan 06 19:28:49 2008 +0000 +++ b/libpurple/protocols/yahoo/util.c Sun Jan 06 19:45: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 Sun Jan 06 19:28:49 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Sun Jan 06 19:45: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", @@ -501,7 +505,8 @@ g_free(yd->cookie_t); yd->cookie_t = _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) @@ -509,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; @@ -574,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; @@ -1497,7 +1506,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); @@ -1942,8 +1957,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); @@ -2433,6 +2453,16 @@ case YAHOO_SERVICE_AUDIBLE: yahoo_process_audible(gc, pkt); break; + case YAHOO_SERVICE_FILETRANS_15: + yahoo_process_filetrans_15(gc, pkt); + break; + case YAHOO_SERVICE_FILETRANS_INFO_15: + yahoo_process_filetrans_info_15(gc, pkt); + break; + case YAHOO_SERVICE_FILETRANS_ACC_15: + yahoo_process_filetrans_acc_15(gc, pkt); + break; + default: purple_debug(PURPLE_DEBUG_ERROR, "yahoo", "Unhandled service 0x%02x\n", pkt->service); @@ -2654,11 +2684,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); @@ -2948,6 +2982,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; @@ -3002,12 +3037,19 @@ } 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);
--- a/libpurple/protocols/yahoo/yahoo.h Sun Jan 06 19:28:49 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo.h Sun Jan 06 19:45: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,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 { @@ -153,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) @@ -211,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 Sun Jan 06 19:28:49 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Sun Jan 06 19:45: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,13 +48,50 @@ guint tx_handler; gchar *rxqueue; guint rxlen; + gchar *xfer_idstring_between_peers; + gchar *xfer_idstring_for_relay; + int version; /*0 for old, 15 for Y7(YMSG 15)*/ + int info_val_249; + enum {STARTED = 0,HEAD_REQUESTED,HEAD_REPLY_RECEIVED,TRANSFER_PHASE,ACCEPTED} status_15; + GSList *filename_list;/*contains all filenames, in case of multiple transfers, with the first one in the list being the current(ymsg15)*/ + 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_idstring_between_peers) { + xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xd->xfer_idstring_between_peers); + if(xfer) + g_hash_table_remove(yd->xfer_peer_idstring_map, xd->xfer_idstring_between_peers); + } + + /*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->xfer_idstring_between_peers); + g_free(xd->xfer_idstring_for_relay); if (xd->tx_handler) purple_input_remove(xd->tx_handler); g_free(xd); @@ -291,23 +330,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_idstring_between_peers, + 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_idstring_between_peers, + 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_idstring_between_peers, + 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; @@ -419,6 +502,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_idstring_between_peers, + 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_idstring_between_peers, + 222, 2); + } + yahoo_packet_send_and_free(pkt, yd); + } + + if (xfer_data) yahoo_xfer_data_free(xfer_data); xfer->data = NULL; @@ -430,11 +549,147 @@ 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_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_idstring_between_peers, + 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_idstring_between_peers, + 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_end(PurpleXfer *xfer_old) +{ + struct yahoo_xfer_data *xfer_data; + PurpleXfer *xfer = NULL; + PurpleConnection *gc; + struct yahoo_data *yd; + + 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; + + /* 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 = (int) NULL; + 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_idstring_between_peers); + g_hash_table_insert(yd->xfer_peer_idstring_map, xfer_data->xfer_idstring_between_peers, 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) { GSList *l = pkt->hash; @@ -657,15 +912,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_idstring_between_peers, + 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_idstring_between_peers = yahoo_xfer_new_xfer_id(); + g_hash_table_insert(yd->xfer_peer_idstring_map, xfer_data->xfer_idstring_between_peers, 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_idstring_between_peers = 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_idstring_between_peers = 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_idstring_between_peers) + return; + + if(val_222 == 2 || val_222 == 4) + { + xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, + xfer_idstring_between_peers); + if(!xfer) return; + purple_xfer_cancel_remote(xfer); + return; + } + if(val_222 == 3) + { + xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, + xfer_idstring_between_peers); + 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_idstring_between_peers = g_strdup(xfer_idstring_between_peers); + 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_idstring_between_peers, + 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_idstring_between_peers = 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_idstring_between_peers = 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_idstring_between_peers) + return; + + xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xfer_idstring_between_peers); + + 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_idstring_between_peers, + 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_idstring_between_peers = 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_idstring_between_peers = pair->value; + break; + case 66: + val_66 = atol(pair->value); + } + } + + xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xfer_idstring_between_peers); + 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 Sun Jan 06 19:28:49 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.h Sun Jan 06 19:45:03 2008 +0000 @@ -51,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 Sun Jan 06 19:28:49 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_friend.h Sun Jan 06 19:45: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 Sun Jan 06 19:28:49 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_packet.h Sun Jan 06 19:45:03 2008 +0000 @@ -102,6 +102,9 @@ 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 };