# HG changeset patch # User Sulabh Mahajan # Date 1215615909 0 # Node ID 2fb8c39d0494e55cfddce2b435d6cc9b817b5535 # Parent 860d8ed4f7a6e0ca5dc768cfe7a2c40c414cc47c Send file by p2p when we are server diff -r 860d8ed4f7a6 -r 2fb8c39d0494 libpurple/protocols/yahoo/yahoo_filexfer.c --- a/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Jul 02 11:16:35 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Jul 09 15:05:09 2008 +0000 @@ -26,6 +26,7 @@ #include "prpl.h" #include "util.h" #include "debug.h" +#include "network.h" #include "notify.h" #include "proxy.h" #include "ft.h" @@ -58,7 +59,10 @@ HEAD_REQUESTED, HEAD_REPLY_RECEIVED, TRANSFER_PHASE, - ACCEPTED + ACCEPTED, + P2P_HEAD_REQUESTED, + P2P_HEAD_REPLIED, + P2P_GET_REQUESTED } status_15; /* contains all filenames, in case of multiple transfers, with the first @@ -66,6 +70,11 @@ GSList *filename_list; GSList *size_list; /*corresponds to filename_list, with size as **STRING** */ gboolean firstoflist; + gchar *xfer_url; /* url of the file, used when we are p2p server */ + int yahoo_local_p2p_ft_server_fd; + int yahoo_local_p2p_ft_server_port; + int yahoo_p2p_ft_server_watcher; + int input_event; }; static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd) @@ -1030,7 +1039,6 @@ 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; @@ -1062,7 +1070,9 @@ purple_xfer_request(xfer); } +static void yahoo_p2p_ft_server_listen_cb(int listenfd, gpointer data); /* using this in yahoo_xfer_send_cb_15 */ 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; @@ -1151,7 +1161,7 @@ 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); @@ -1162,21 +1172,33 @@ xfer->fd = source; purple_xfer_start(xfer, source, NULL, 0); } - else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == ACCEPTED) + else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && (xd->status_15 == ACCEPTED || xd->status_15 == P2P_GET_REQUESTED) ) { xd->status_15 = TRANSFER_PHASE; xfer->fd = source; + /* Remove Read event */ + purple_input_remove(xd->input_event); + xd->input_event = 0; purple_xfer_start(xfer, source, NULL, 0); } + else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == P2P_HEAD_REQUESTED) + { + xd->status_15 = P2P_HEAD_REPLIED; + /* Remove Read event and close descriptor */ + purple_input_remove(xd->input_event); + xd->input_event = 0; + close(source); + xfer->fd = -1; + /* start local server, listen for connections */ + purple_network_listen(xd->yahoo_local_p2p_ft_server_port, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, 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_connected_15(gpointer data, gint source, const gchar *error_message) { PurpleXfer *xfer; @@ -1278,7 +1300,151 @@ } } -/*send (p2p) file transfer information when we are connected as client*/ +static void yahoo_p2p_ft_HEAD_GET_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + PurpleXfer *xfer; + struct yahoo_xfer_data *xd; + guchar buf[1024]; + int len; + char *url_head; + char *url_get; + time_t unix_time; + char *time_str; + + xfer = data; + if (!(xd = xfer->data)) { + purple_xfer_cancel_remote(xfer); + purple_input_remove(xd->input_event); + return; + } + + len = read(source, buf, sizeof(buf)); + if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) + return ; /* No Worries*/ + else if (len <= 0) { + purple_debug_warning("yahoo","p2p-ft: Error in connection, or host disconnected\n"); + purple_xfer_cancel_remote(xfer); + purple_input_remove(xd->input_event); + return; + } + + url_head = g_strdup_printf("HEAD %s", xd->xfer_url); + url_get = g_strdup_printf("GET %s", xd->xfer_url); + + if( strncmp(url_head, (char *)buf, strlen(url_head)) == 0 ) + xd->status_15 = P2P_HEAD_REQUESTED; + else if( strncmp(url_get, (char *)buf, strlen(url_get)) == 0 ) + xd->status_15 = P2P_GET_REQUESTED; + else { + purple_debug_warning("yahoo","p2p-ft: Wrong HEAD/GET request from peer, disconnecting host\n"); + purple_xfer_cancel_remote(xfer); + purple_input_remove(xd->input_event); + g_free(url_head); + return; + } + + unix_time = time(NULL); + time_str = ctime(&unix_time); + strcpy(time_str + strlen(time_str) - 1, "\0"); + + if (xd->txbuflen == 0) { + xd->txbuf = g_strdup_printf("HTTP/1.0 200 OK\r\nDate: %s GMT\r\nServer: Y!/1.0\r\nMIME-version: 1.0\r\nLast-modified: %s GMT\r\nContent-length: %d\r\n\r\n", time_str, time_str, xfer->size); + xd->txbuflen = strlen(xd->txbuf); + xd->txbuf_written = 0; + } + + 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); + } + + g_free(url_head); + g_free(url_get); +} + +static void yahoo_p2p_ft_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + int acceptfd; + PurpleXfer *xfer; + struct yahoo_xfer_data *xd; + + xfer = data; + if (!(xd = xfer->data)) { + purple_xfer_cancel_remote(xfer); + return; + } + + acceptfd = accept(source, NULL, 0); + if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + return; + else if(acceptfd == -1) { + purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno)); + purple_xfer_cancel_remote(xfer); + /*remove watcher and close p2p ft server*/ + purple_input_remove(xd->yahoo_p2p_ft_server_watcher); + close(xd->yahoo_local_p2p_ft_server_fd); + return; + } + + /*remove watcher and close p2p ft server*/ + purple_input_remove(xd->yahoo_p2p_ft_server_watcher); + close(xd->yahoo_local_p2p_ft_server_fd); + + /*Add an Input Read event to the file descriptor*/ + xfer->fd = acceptfd; + xd->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_ft_HEAD_GET_cb, data); +} + +static void yahoo_p2p_ft_server_listen_cb(int listenfd, gpointer data) +{ + PurpleXfer *xfer; + struct yahoo_xfer_data *xd; + struct yahoo_packet *pkt; + PurpleAccount *account; + struct yahoo_data *yd; + gchar *filename; + const char *local_ip; + gchar *url_to_send = NULL; + + xfer = data; + if ( !( (xd = xfer->data) || (listenfd != -1) ) ) { + purple_debug_warning("yahoo","p2p: error starting server for p2p file transfer\n"); + purple_xfer_cancel_remote(xfer); + return; + } + + if(xd->status_15 != P2P_HEAD_REPLIED) { + yd = xd->gc->proto_data; + account = purple_connection_get_account(xd->gc); + + 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)); + + local_ip = purple_network_get_my_ip(listenfd); + xd->yahoo_local_p2p_ft_server_port = purple_network_get_port_from_fd(listenfd); + xd->xfer_url = g_strdup_printf("/Messenger.%s.%d000%s?AppID=Messenger&UserID=%s&K=lc9lu2u89gz1llmplwksajkjx", xfer->who, (int)time(NULL), filename, xfer->who); + url_to_send = g_strdup_printf("http://%s:%d%s", local_ip, xd->yahoo_local_p2p_ft_server_port, xd->xfer_url); + xd->info_val_249 = 1; /* 249=1: we are p2p server */ + + 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, 1, + 250, url_to_send); + yahoo_packet_send_and_free(pkt, yd); + + g_free(filename); + g_free(url_to_send); + } + + /* Add an Input Read event to the file descriptor */ + xd->yahoo_local_p2p_ft_server_fd = listenfd; + xd->yahoo_p2p_ft_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_ft_server_send_connected_cb, data); +} + +/* send (p2p) file transfer information */ static void yahoo_p2p_client_send_ft_info(PurpleConnection *gc, PurpleXfer *xfer) { struct yahoo_xfer_data *xd; @@ -1286,6 +1452,7 @@ PurpleAccount *account; struct yahoo_data *yd; gchar *filename; + struct yahoo_p2p_data *p2p_data; if (!(xd = xfer->data)) return; @@ -1296,16 +1463,23 @@ 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)); + p2p_data = g_hash_table_lookup(yd->peers, xfer->who); + if( p2p_data->connection_type == 1 ) + if(purple_network_listen_range(0, 0, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, xfer)) { + g_free(filename); + return; + } + yahoo_packet_hash(pkt, "ssssi", 1, purple_normalize(account, purple_account_get_username(account)), 5, xfer->who, 265, xd->xfer_peer_idstring, 27, filename, - 249, 2); /*249= 2:we are connected as p2p client, and sending file*/ + 249, 2); /* 249=2: we are p2p client */ xd->info_val_249 = 2; + yahoo_packet_send_and_free(pkt, yd); g_free(filename); - yahoo_packet_send_and_free(pkt, yd); } void yahoo_process_filetrans_15(PurpleConnection *gc, struct yahoo_packet *pkt) @@ -1389,9 +1563,9 @@ * address etc. is not implemented..TODO */ - /*p2p connection exists, we being p2p client*/ + /* To send through p2p */ if( g_hash_table_lookup(yd->peers, from) ) { - /*send p2p file transfer information when we are connected as client*/ + /*send p2p file transfer information */ yahoo_p2p_client_send_ft_info(gc, xfer); return; }