Mercurial > pidgin
changeset 21803:ffbd2e3e10e4
Patch from Alex Badea to support receiving files from Yahoo users using the newer yahoo protocol. Committing this is very long overdue, it somehow slipped through the cracks for a long time. References #708.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Mon, 10 Dec 2007 02:07:01 +0000 |
parents | d01d9107f263 |
children | fb73a6ed8197 |
files | 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_packet.h |
diffstat | 5 files changed, 282 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/yahoo/yahoo.c Sun Dec 09 11:25:15 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Mon Dec 10 02:07:01 2007 +0000 @@ -493,13 +493,14 @@ static void yahoo_process_cookie(struct yahoo_data *yd, char *c) { if (c[0] == 'Y') { - if (yd->cookie_y) - g_free(yd->cookie_y); + g_free(yd->cookie_y); yd->cookie_y = _getcookie(c); } else if (c[0] == 'T') { - if (yd->cookie_t) - g_free(yd->cookie_t); + 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]); } @@ -2433,6 +2434,12 @@ case YAHOO_SERVICE_AUDIBLE: yahoo_process_audible(gc, pkt); break; + case YAHOO_SERVICE_Y7_FILETRANSFER: + yahoo_process_y7_filetransfer(gc, pkt); + break; + case YAHOO_SERVICE_Y7_FILETRANSFER_INFO: + yahoo_process_y7_filetransfer_info(gc, pkt); + break; default: purple_debug(PURPLE_DEBUG_ERROR, "yahoo", "Unhandled service 0x%02x\n", pkt->service); @@ -3012,6 +3019,7 @@ 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 Sun Dec 09 11:25:15 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo.h Mon Dec 10 02:07:01 2007 +0000 @@ -134,6 +134,7 @@ gsize auth_written; char *cookie_y; char *cookie_t; + char *cookie_c; int session_id; gboolean jp; gboolean wm; /* connected w/ web messenger method */
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c Sun Dec 09 11:25:15 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Mon Dec 10 02:07:01 2007 +0000 @@ -46,6 +46,10 @@ guint tx_handler; gchar *rxqueue; guint rxlen; + + gboolean y7; /* true for Y7 transfers (receive only for now) */ + gchar *token; + gchar *tid; }; static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd) @@ -53,11 +57,70 @@ g_free(xd->host); g_free(xd->path); g_free(xd->txbuf); + g_free(xd->token); + g_free(xd->tid); 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; @@ -97,6 +160,7 @@ { PurpleXfer *xfer; struct yahoo_xfer_data *xd; + struct yahoo_data *yd; purple_debug(PURPLE_DEBUG_INFO, "yahoo", "AAA - in yahoo_receivefile_connected\n"); @@ -112,11 +176,22 @@ } xfer->fd = source; + yd = xd->gc->proto_data; /* The first time we get here, assemble the tx buffer */ if (xd->txbuflen == 0) { - xd->txbuf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", - xd->path, xd->host); + 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->txbuflen = strlen(xd->txbuf); xd->txbuf_written = 0; } @@ -281,6 +356,9 @@ } } } 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) { @@ -340,6 +418,8 @@ 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; @@ -430,11 +510,24 @@ xfer_data = xfer->data; - if (xfer_data) + if (xfer_data) { + if (xfer_data->y7) + yahoo_xfer_y7_cancel_receive(xfer); yahoo_xfer_data_free(xfer_data); + } xfer->data = NULL; } +static void yahoo_xfer_request_denied(PurpleXfer *xfer) +{ + struct yahoo_xfer_data *xfer_data; + + xfer_data = xfer->data; + + if (xfer_data->y7) + yahoo_xfer_y7_cancel_receive(xfer); +} + void yahoo_process_p2pfilexfer(PurpleConnection *gc, struct yahoo_packet *pkt) { GSList *l = pkt->hash; @@ -628,6 +721,165 @@ } } +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;
--- a/libpurple/protocols/yahoo/yahoo_filexfer.h Sun Dec 09 11:25:15 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.h Mon Dec 10 02:07:01 2007 +0000 @@ -30,6 +30,16 @@ 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);
--- a/libpurple/protocols/yahoo/yahoo_packet.h Sun Dec 09 11:25:15 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_packet.h Mon Dec 10 02:07:01 2007 +0000 @@ -99,9 +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_WEBLOGIN = 0x0226, YAHOO_SERVICE_SMS_MSG = 0x02ea };