comparison libpurple/protocols/yahoo/yahoo_filexfer.c @ 25622:2fb8c39d0494

Send file by p2p when we are server
author Sulabh Mahajan <sulabh@soc.pidgin.im>
date Wed, 09 Jul 2008 15:05:09 +0000
parents ccbded331513
children d96190de653a
comparison
equal deleted inserted replaced
25621:860d8ed4f7a6 25622:2fb8c39d0494
24 #include "dnsquery.h" 24 #include "dnsquery.h"
25 25
26 #include "prpl.h" 26 #include "prpl.h"
27 #include "util.h" 27 #include "util.h"
28 #include "debug.h" 28 #include "debug.h"
29 #include "network.h"
29 #include "notify.h" 30 #include "notify.h"
30 #include "proxy.h" 31 #include "proxy.h"
31 #include "ft.h" 32 #include "ft.h"
32 #include "yahoo.h" 33 #include "yahoo.h"
33 #include "yahoo_packet.h" 34 #include "yahoo_packet.h"
56 enum { 57 enum {
57 STARTED = 0, 58 STARTED = 0,
58 HEAD_REQUESTED, 59 HEAD_REQUESTED,
59 HEAD_REPLY_RECEIVED, 60 HEAD_REPLY_RECEIVED,
60 TRANSFER_PHASE, 61 TRANSFER_PHASE,
61 ACCEPTED 62 ACCEPTED,
63 P2P_HEAD_REQUESTED,
64 P2P_HEAD_REPLIED,
65 P2P_GET_REQUESTED
62 } status_15; 66 } status_15;
63 67
64 /* contains all filenames, in case of multiple transfers, with the first 68 /* contains all filenames, in case of multiple transfers, with the first
65 * one in the list being the current file's name (ymsg15) */ 69 * one in the list being the current file's name (ymsg15) */
66 GSList *filename_list; 70 GSList *filename_list;
67 GSList *size_list; /*corresponds to filename_list, with size as **STRING** */ 71 GSList *size_list; /*corresponds to filename_list, with size as **STRING** */
68 gboolean firstoflist; 72 gboolean firstoflist;
73 gchar *xfer_url; /* url of the file, used when we are p2p server */
74 int yahoo_local_p2p_ft_server_fd;
75 int yahoo_local_p2p_ft_server_port;
76 int yahoo_p2p_ft_server_watcher;
77 int input_event;
69 }; 78 };
70 79
71 static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd) 80 static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd)
72 { 81 {
73 PurpleConnection *gc; 82 PurpleConnection *gc;
1028 1037
1029 g_free(filename); 1038 g_free(filename);
1030 yahoo_packet_send_and_free(pkt, yd); 1039 yahoo_packet_send_and_free(pkt, yd);
1031 } 1040 }
1032 1041
1033
1034 void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file) 1042 void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file)
1035 { 1043 {
1036 struct yahoo_xfer_data *xfer_data; 1044 struct yahoo_xfer_data *xfer_data;
1037 struct yahoo_data *yd = gc->proto_data; 1045 struct yahoo_data *yd = gc->proto_data;
1038 int ver = 0; 1046 int ver = 0;
1060 purple_xfer_request_accepted(xfer, file); 1068 purple_xfer_request_accepted(xfer, file);
1061 else 1069 else
1062 purple_xfer_request(xfer); 1070 purple_xfer_request(xfer);
1063 } 1071 }
1064 1072
1073 static void yahoo_p2p_ft_server_listen_cb(int listenfd, gpointer data); /* using this in yahoo_xfer_send_cb_15 */
1065 static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message);/*using this in recv_cb*/ 1074 static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message);/*using this in recv_cb*/
1075
1066 static void yahoo_xfer_recv_cb_15(gpointer data, gint source, PurpleInputCondition condition) 1076 static void yahoo_xfer_recv_cb_15(gpointer data, gint source, PurpleInputCondition condition)
1067 { 1077 {
1068 PurpleXfer *xfer; 1078 PurpleXfer *xfer;
1069 struct yahoo_xfer_data *xd; 1079 struct yahoo_xfer_data *xd;
1070 int did; 1080 int did;
1149 xd->txbuf = NULL; 1159 xd->txbuf = NULL;
1150 xd->txbuflen = 0; 1160 xd->txbuflen = 0;
1151 xd->txbuf_written = 0; 1161 xd->txbuf_written = 0;
1152 1162
1153 if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == STARTED) 1163 if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == STARTED)
1154 { 1164 {
1155 xd->status_15 = HEAD_REQUESTED; 1165 xd->status_15 = HEAD_REQUESTED;
1156 xd->tx_handler = purple_input_add(source, PURPLE_INPUT_READ, yahoo_xfer_recv_cb_15, xfer); 1166 xd->tx_handler = purple_input_add(source, PURPLE_INPUT_READ, yahoo_xfer_recv_cb_15, xfer);
1157 yahoo_xfer_recv_cb_15(xfer, source, PURPLE_INPUT_READ); 1167 yahoo_xfer_recv_cb_15(xfer, source, PURPLE_INPUT_READ);
1158 } 1168 }
1159 else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == HEAD_REPLY_RECEIVED) 1169 else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == HEAD_REPLY_RECEIVED)
1160 { 1170 {
1161 xd->status_15 = TRANSFER_PHASE; 1171 xd->status_15 = TRANSFER_PHASE;
1162 xfer->fd = source; 1172 xfer->fd = source;
1163 purple_xfer_start(xfer, source, NULL, 0); 1173 purple_xfer_start(xfer, source, NULL, 0);
1164 } 1174 }
1165 else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == ACCEPTED) 1175 else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && (xd->status_15 == ACCEPTED || xd->status_15 == P2P_GET_REQUESTED) )
1166 { 1176 {
1167 xd->status_15 = TRANSFER_PHASE; 1177 xd->status_15 = TRANSFER_PHASE;
1168 xfer->fd = source; 1178 xfer->fd = source;
1179 /* Remove Read event */
1180 purple_input_remove(xd->input_event);
1181 xd->input_event = 0;
1169 purple_xfer_start(xfer, source, NULL, 0); 1182 purple_xfer_start(xfer, source, NULL, 0);
1170 } 1183 }
1184 else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == P2P_HEAD_REQUESTED)
1185 {
1186 xd->status_15 = P2P_HEAD_REPLIED;
1187 /* Remove Read event and close descriptor */
1188 purple_input_remove(xd->input_event);
1189 xd->input_event = 0;
1190 close(source);
1191 xfer->fd = -1;
1192 /* start local server, listen for connections */
1193 purple_network_listen(xd->yahoo_local_p2p_ft_server_port, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, xfer);
1194 }
1171 else 1195 else
1172 { 1196 {
1173 purple_debug_error("yahoo", "Unrecognized yahoo file transfer mode and stage (ymsg15):%d,%d\n", purple_xfer_get_type(xfer), xd->status_15); 1197 purple_debug_error("yahoo", "Unrecognized yahoo file transfer mode and stage (ymsg15):%d,%d\n", purple_xfer_get_type(xfer), xd->status_15);
1174 return; 1198 return;
1175 } 1199 }
1176 1200 }
1177 }
1178
1179 1201
1180 static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message) 1202 static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message)
1181 { 1203 {
1182 PurpleXfer *xfer; 1204 PurpleXfer *xfer;
1183 struct yahoo_xfer_data *xd; 1205 struct yahoo_xfer_data *xd;
1276 yahoo_xfer_send_cb_15, xfer); 1298 yahoo_xfer_send_cb_15, xfer);
1277 yahoo_xfer_send_cb_15(xfer, source, PURPLE_INPUT_WRITE); 1299 yahoo_xfer_send_cb_15(xfer, source, PURPLE_INPUT_WRITE);
1278 } 1300 }
1279 } 1301 }
1280 1302
1281 /*send (p2p) file transfer information when we are connected as client*/ 1303 static void yahoo_p2p_ft_HEAD_GET_cb(gpointer data, gint source, PurpleInputCondition cond)
1282 static void yahoo_p2p_client_send_ft_info(PurpleConnection *gc, PurpleXfer *xfer) 1304 {
1283 { 1305 PurpleXfer *xfer;
1306 struct yahoo_xfer_data *xd;
1307 guchar buf[1024];
1308 int len;
1309 char *url_head;
1310 char *url_get;
1311 time_t unix_time;
1312 char *time_str;
1313
1314 xfer = data;
1315 if (!(xd = xfer->data)) {
1316 purple_xfer_cancel_remote(xfer);
1317 purple_input_remove(xd->input_event);
1318 return;
1319 }
1320
1321 len = read(source, buf, sizeof(buf));
1322 if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
1323 return ; /* No Worries*/
1324 else if (len <= 0) {
1325 purple_debug_warning("yahoo","p2p-ft: Error in connection, or host disconnected\n");
1326 purple_xfer_cancel_remote(xfer);
1327 purple_input_remove(xd->input_event);
1328 return;
1329 }
1330
1331 url_head = g_strdup_printf("HEAD %s", xd->xfer_url);
1332 url_get = g_strdup_printf("GET %s", xd->xfer_url);
1333
1334 if( strncmp(url_head, (char *)buf, strlen(url_head)) == 0 )
1335 xd->status_15 = P2P_HEAD_REQUESTED;
1336 else if( strncmp(url_get, (char *)buf, strlen(url_get)) == 0 )
1337 xd->status_15 = P2P_GET_REQUESTED;
1338 else {
1339 purple_debug_warning("yahoo","p2p-ft: Wrong HEAD/GET request from peer, disconnecting host\n");
1340 purple_xfer_cancel_remote(xfer);
1341 purple_input_remove(xd->input_event);
1342 g_free(url_head);
1343 return;
1344 }
1345
1346 unix_time = time(NULL);
1347 time_str = ctime(&unix_time);
1348 strcpy(time_str + strlen(time_str) - 1, "\0");
1349
1350 if (xd->txbuflen == 0) {
1351 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);
1352 xd->txbuflen = strlen(xd->txbuf);
1353 xd->txbuf_written = 0;
1354 }
1355
1356 if (!xd->tx_handler) {
1357 xd->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE, yahoo_xfer_send_cb_15, xfer);
1358 yahoo_xfer_send_cb_15(xfer, source, PURPLE_INPUT_WRITE);
1359 }
1360
1361 g_free(url_head);
1362 g_free(url_get);
1363 }
1364
1365 static void yahoo_p2p_ft_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond)
1366 {
1367 int acceptfd;
1368 PurpleXfer *xfer;
1369 struct yahoo_xfer_data *xd;
1370
1371 xfer = data;
1372 if (!(xd = xfer->data)) {
1373 purple_xfer_cancel_remote(xfer);
1374 return;
1375 }
1376
1377 acceptfd = accept(source, NULL, 0);
1378 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
1379 return;
1380 else if(acceptfd == -1) {
1381 purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno));
1382 purple_xfer_cancel_remote(xfer);
1383 /*remove watcher and close p2p ft server*/
1384 purple_input_remove(xd->yahoo_p2p_ft_server_watcher);
1385 close(xd->yahoo_local_p2p_ft_server_fd);
1386 return;
1387 }
1388
1389 /*remove watcher and close p2p ft server*/
1390 purple_input_remove(xd->yahoo_p2p_ft_server_watcher);
1391 close(xd->yahoo_local_p2p_ft_server_fd);
1392
1393 /*Add an Input Read event to the file descriptor*/
1394 xfer->fd = acceptfd;
1395 xd->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_ft_HEAD_GET_cb, data);
1396 }
1397
1398 static void yahoo_p2p_ft_server_listen_cb(int listenfd, gpointer data)
1399 {
1400 PurpleXfer *xfer;
1284 struct yahoo_xfer_data *xd; 1401 struct yahoo_xfer_data *xd;
1285 struct yahoo_packet *pkt; 1402 struct yahoo_packet *pkt;
1286 PurpleAccount *account; 1403 PurpleAccount *account;
1287 struct yahoo_data *yd; 1404 struct yahoo_data *yd;
1288 gchar *filename; 1405 gchar *filename;
1406 const char *local_ip;
1407 gchar *url_to_send = NULL;
1408
1409 xfer = data;
1410 if ( !( (xd = xfer->data) || (listenfd != -1) ) ) {
1411 purple_debug_warning("yahoo","p2p: error starting server for p2p file transfer\n");
1412 purple_xfer_cancel_remote(xfer);
1413 return;
1414 }
1415
1416 if(xd->status_15 != P2P_HEAD_REPLIED) {
1417 yd = xd->gc->proto_data;
1418 account = purple_connection_get_account(xd->gc);
1419
1420 pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
1421 filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
1422
1423 local_ip = purple_network_get_my_ip(listenfd);
1424 xd->yahoo_local_p2p_ft_server_port = purple_network_get_port_from_fd(listenfd);
1425 xd->xfer_url = g_strdup_printf("/Messenger.%s.%d000%s?AppID=Messenger&UserID=%s&K=lc9lu2u89gz1llmplwksajkjx", xfer->who, (int)time(NULL), filename, xfer->who);
1426 url_to_send = g_strdup_printf("http://%s:%d%s", local_ip, xd->yahoo_local_p2p_ft_server_port, xd->xfer_url);
1427 xd->info_val_249 = 1; /* 249=1: we are p2p server */
1428
1429 yahoo_packet_hash(pkt, "ssssis",
1430 1, purple_normalize(account, purple_account_get_username(account)),
1431 5, xfer->who,
1432 265, xd->xfer_peer_idstring,
1433 27, filename,
1434 249, 1,
1435 250, url_to_send);
1436 yahoo_packet_send_and_free(pkt, yd);
1437
1438 g_free(filename);
1439 g_free(url_to_send);
1440 }
1441
1442 /* Add an Input Read event to the file descriptor */
1443 xd->yahoo_local_p2p_ft_server_fd = listenfd;
1444 xd->yahoo_p2p_ft_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_ft_server_send_connected_cb, data);
1445 }
1446
1447 /* send (p2p) file transfer information */
1448 static void yahoo_p2p_client_send_ft_info(PurpleConnection *gc, PurpleXfer *xfer)
1449 {
1450 struct yahoo_xfer_data *xd;
1451 struct yahoo_packet *pkt;
1452 PurpleAccount *account;
1453 struct yahoo_data *yd;
1454 gchar *filename;
1455 struct yahoo_p2p_data *p2p_data;
1289 1456
1290 if (!(xd = xfer->data)) 1457 if (!(xd = xfer->data))
1291 return; 1458 return;
1292 1459
1293 account = purple_connection_get_account(gc); 1460 account = purple_connection_get_account(gc);
1294 yd = gc->proto_data; 1461 yd = gc->proto_data;
1295 1462
1296 pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id); 1463 pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
1297 filename = g_path_get_basename(purple_xfer_get_local_filename(xfer)); 1464 filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
1465
1466 p2p_data = g_hash_table_lookup(yd->peers, xfer->who);
1467 if( p2p_data->connection_type == 1 )
1468 if(purple_network_listen_range(0, 0, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, xfer)) {
1469 g_free(filename);
1470 return;
1471 }
1298 1472
1299 yahoo_packet_hash(pkt, "ssssi", 1473 yahoo_packet_hash(pkt, "ssssi",
1300 1, purple_normalize(account, purple_account_get_username(account)), 1474 1, purple_normalize(account, purple_account_get_username(account)),
1301 5, xfer->who, 1475 5, xfer->who,
1302 265, xd->xfer_peer_idstring, 1476 265, xd->xfer_peer_idstring,
1303 27, filename, 1477 27, filename,
1304 249, 2); /*249= 2:we are connected as p2p client, and sending file*/ 1478 249, 2); /* 249=2: we are p2p client */
1305 xd->info_val_249 = 2; 1479 xd->info_val_249 = 2;
1480 yahoo_packet_send_and_free(pkt, yd);
1306 1481
1307 g_free(filename); 1482 g_free(filename);
1308 yahoo_packet_send_and_free(pkt, yd);
1309 } 1483 }
1310 1484
1311 void yahoo_process_filetrans_15(PurpleConnection *gc, struct yahoo_packet *pkt) 1485 void yahoo_process_filetrans_15(PurpleConnection *gc, struct yahoo_packet *pkt)
1312 { 1486 {
1313 char *from = NULL; 1487 char *from = NULL;
1387 * purple connect does not give me a way of finding the ip address... 1561 * purple connect does not give me a way of finding the ip address...
1388 * so, purple dnsquery is used... but retries, trying with next ip 1562 * so, purple dnsquery is used... but retries, trying with next ip
1389 * address etc. is not implemented..TODO 1563 * address etc. is not implemented..TODO
1390 */ 1564 */
1391 1565
1392 /*p2p connection exists, we being p2p client*/ 1566 /* To send through p2p */
1393 if( g_hash_table_lookup(yd->peers, from) ) { 1567 if( g_hash_table_lookup(yd->peers, from) ) {
1394 /*send p2p file transfer information when we are connected as client*/ 1568 /*send p2p file transfer information */
1395 yahoo_p2p_client_send_ft_info(gc, xfer); 1569 yahoo_p2p_client_send_ft_info(gc, xfer);
1396 return; 1570 return;
1397 } 1571 }
1398 1572
1399 if (yd->jp) 1573 if (yd->jp)