libpurple/protocols/yahoo/yahoo.c

branch
soc.2008.yahoo
changeset 26362
de9cf498a73a
parent 26360
9af4fa4d22cf
child 26363
63cb37543cbf
equal deleted inserted replaced
26361:eeb395e3523f 26362:de9cf498a73a
28 #include "blist.h" 28 #include "blist.h"
29 #include "cipher.h" 29 #include "cipher.h"
30 #include "cmds.h" 30 #include "cmds.h"
31 #include "core.h" 31 #include "core.h"
32 #include "debug.h" 32 #include "debug.h"
33 #include "network.h"
33 #include "notify.h" 34 #include "notify.h"
34 #include "privacy.h" 35 #include "privacy.h"
35 #include "prpl.h" 36 #include "prpl.h"
36 #include "proxy.h" 37 #include "proxy.h"
37 #include "request.h" 38 #include "request.h"
38 #include "server.h" 39 #include "server.h"
39 #include "util.h" 40 #include "util.h"
40 #include "version.h" 41 #include "version.h"
42 #include "xmlnode.h"
41 43
42 #include "yahoo.h" 44 #include "yahoo.h"
43 #include "yahoochat.h" 45 #include "yahoochat.h"
44 #include "yahoo_aliases.h" 46 #include "yahoo_aliases.h"
45 #include "yahoo_auth.h" 47 #include "yahoo_auth.h"
233 case 19: /* custom message */ 235 case 19: /* custom message */
234 if (f) 236 if (f)
235 message = pair->value; 237 message = pair->value;
236 break; 238 break;
237 case 11: /* this is the buddy's session id */ 239 case 11: /* this is the buddy's session id */
240 if (f)
241 f->session_id = strtol(pair->value, NULL, 10);
238 break; 242 break;
239 case 17: /* in chat? */ 243 case 17: /* in chat? */
240 break; 244 break;
241 case 47: /* is custom status away or not? 2=idle*/ 245 case 47: /* is custom status away or not? 2=idle*/
242 if (!f) 246 if (!f)
519 } 523 }
520 b = purple_buddy_new(account, norm_bud, NULL); 524 b = purple_buddy_new(account, norm_bud, NULL);
521 purple_blist_add_buddy(b, NULL, g, NULL); 525 purple_blist_add_buddy(b, NULL, g, NULL);
522 } 526 }
523 yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp); 527 yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp);
528
529 /* set p2p status not connected and no p2p packet sent */
530 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
531 f->p2p_packet_sent = 0;
524 532
525 } else { 533 } else {
526 /* This buddy is on the ignore list (and therefore in no group) */ 534 /* This buddy is on the ignore list (and therefore in no group) */
527 purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n", 535 purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n",
528 account->username, norm_bud); 536 account->username, norm_bud);
633 purple_blist_add_buddy(b, NULL, g, NULL); 641 purple_blist_add_buddy(b, NULL, g, NULL);
634 export = TRUE; 642 export = TRUE;
635 } 643 }
636 644
637 yahoo_do_group_check(account, ht, norm_bud, grp); 645 yahoo_do_group_check(account, ht, norm_bud, grp);
646 /* set p2p status not connected and no p2p packet sent */
647 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
648 f->p2p_packet_sent = 0;
649
638 g_free(norm_bud); 650 g_free(norm_bud);
639 } 651 }
640 g_strfreev(buddies); 652 g_strfreev(buddies);
641 g_strfreev(split); 653 g_strfreev(split);
642 g_free(grp); 654 g_free(grp);
689 } 701 }
690 /* Now that we've got the list, request aliases */ 702 /* Now that we've got the list, request aliases */
691 yahoo_fetch_aliases(gc); 703 yahoo_fetch_aliases(gc);
692 } 704 }
693 705
694 static void yahoo_process_notify(PurpleConnection *gc, struct yahoo_packet *pkt) 706 /* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
707 static void yahoo_process_notify(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type)
695 { 708 {
696 PurpleAccount *account; 709 PurpleAccount *account;
697 char *msg = NULL; 710 char *msg = NULL;
698 char *from = NULL; 711 char *from = NULL;
699 char *stat = NULL; 712 char *stat = NULL;
700 char *game = NULL; 713 char *game = NULL;
701 YahooFriend *f = NULL; 714 YahooFriend *f = NULL;
702 GSList *l = pkt->hash; 715 GSList *l = pkt->hash;
716 gint val_11 = 0;
717 struct yahoo_data *yd = gc->proto_data;
703 718
704 account = purple_connection_get_account(gc); 719 account = purple_connection_get_account(gc);
705 720
706 while (l) { 721 while (l) {
707 struct yahoo_pair *pair = l->data; 722 struct yahoo_pair *pair = l->data;
708 if (pair->key == 4) 723 if (pair->key == 4 || pair->key == 1)
709 from = pair->value; 724 from = pair->value;
710 if (pair->key == 49) 725 if (pair->key == 49)
711 msg = pair->value; 726 msg = pair->value;
712 if (pair->key == 13) 727 if (pair->key == 13)
713 stat = pair->value; 728 stat = pair->value;
714 if (pair->key == 14) 729 if (pair->key == 14)
715 game = pair->value; 730 game = pair->value;
731 if (pair->key == 11)
732 val_11 = strtol(pair->value, NULL, 10);
716 l = l->next; 733 l = l->next;
717 } 734 }
718 735
719 if (!from || !msg) 736 if (!from || !msg)
720 return; 737 return;
738
739 /* disconnect the peer if connected through p2p and sends wrong value for session id */
740 if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) {
741 purple_debug_warning("yahoo","p2p: %s sent us notify with wrong session id. Disconnecting p2p connection to peer\n", from);
742 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
743 g_hash_table_remove(yd->peers, from);
744 return;
745 }
721 746
722 if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING")) 747 if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING"))
723 && (purple_privacy_check(account, from))) 748 && (purple_privacy_check(account, from)))
724 { 749 {
725 if (*stat == '1') 750 if (*stat == '1')
762 int utf8; 787 int utf8;
763 int buddy_icon; 788 int buddy_icon;
764 char *msg; 789 char *msg;
765 }; 790 };
766 791
767 static void yahoo_process_message(PurpleConnection *gc, struct yahoo_packet *pkt) 792 static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt)
793 {
794 PurpleAccount *account;
795 GSList *l = pkt->hash;
796 struct _yahoo_im *sms = NULL;
797 struct yahoo_data *yd;
798 char *server_msg = NULL;
799 char *m;
800
801 yd = gc->proto_data;
802 account = purple_connection_get_account(gc);
803
804 while (l != NULL) {
805 struct yahoo_pair *pair = l->data;
806 if (pair->key == 4) {
807 sms = g_new0(struct _yahoo_im, 1);
808 sms->from = g_strdup_printf("+%s", pair->value);
809 sms->time = time(NULL);
810 sms->utf8 = TRUE;
811 }
812 if (pair->key == 14) {
813 if (sms)
814 sms->msg = pair->value;
815 }
816 if (pair->key == 68)
817 if(sms)
818 g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value));
819 if (pair->key == 16)
820 server_msg = pair->value;
821 l = l->next;
822 }
823
824 if( (pkt->status == -1) || (pkt->status == YAHOO_STATUS_DISCONNECTED) ) {
825 if (server_msg) {
826 PurpleConversation *c;
827 c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms->from, account);
828 if (c == NULL)
829 c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sms->from);
830 purple_conversation_write(c, NULL, server_msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
831 }
832 else
833 purple_notify_error(gc, NULL, _("Your SMS was not delivered"), NULL);
834
835 g_free(sms->from);
836 g_free(sms);
837 return ;
838 }
839
840 if (!sms->from || !sms->msg) {
841 g_free(sms);
842 return;
843 }
844
845 m = yahoo_string_decode(gc, sms->msg, sms->utf8);
846 serv_got_im(gc, sms->from, m, 0, sms->time);
847
848 g_free(m);
849 g_free(sms->from);
850 g_free(sms);
851 }
852
853 /* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
854 static void yahoo_process_message(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type)
768 { 855 {
769 PurpleAccount *account; 856 PurpleAccount *account;
770 struct yahoo_data *yd = gc->proto_data; 857 struct yahoo_data *yd = gc->proto_data;
771 GSList *l = pkt->hash; 858 GSList *l = pkt->hash;
772 GSList *list = NULL; 859 GSList *list = NULL;
773 struct _yahoo_im *im = NULL; 860 struct _yahoo_im *im = NULL;
774 const char *imv = NULL; 861 const char *imv = NULL;
862 gint val_11 = 0;
775 863
776 account = purple_connection_get_account(gc); 864 account = purple_connection_get_account(gc);
777 865
778 if (pkt->status <= 1 || pkt->status == 5) { 866 if (pkt->status <= 1 || pkt->status == 5 || pkt->status == YAHOO_STATUS_OFFLINE) {
867 /* messages are received with status YAHOO_STATUS_OFFLINE in case of p2p */
779 while (l != NULL) { 868 while (l != NULL) {
780 struct yahoo_pair *pair = l->data; 869 struct yahoo_pair *pair = l->data;
781 if (pair->key == 4) { 870 if (pair->key == 4 || pair->key == 1) {
782 im = g_new0(struct _yahoo_im, 1); 871 im = g_new0(struct _yahoo_im, 1);
783 list = g_slist_append(list, im); 872 list = g_slist_append(list, im);
784 im->from = pair->value; 873 im->from = pair->value;
785 im->time = time(NULL); 874 im->time = time(NULL);
786 im->utf8 = TRUE; 875 im->utf8 = TRUE;
796 im->buddy_icon = strtol(pair->value, NULL, 10); 885 im->buddy_icon = strtol(pair->value, NULL, 10);
797 if (pair->key == 14) { 886 if (pair->key == 14) {
798 if (im) 887 if (im)
799 im->msg = pair->value; 888 im->msg = pair->value;
800 } 889 }
890 /* peer session id */
891 if (pair->key == 11) {
892 if (im)
893 val_11 = strtol(pair->value, NULL, 10);
894 }
801 /* IMV key */ 895 /* IMV key */
802 if (pair->key == 63) 896 if (pair->key == 63)
803 { 897 {
804 imv = pair->value; 898 imv = pair->value;
805 } 899 }
806 l = l->next; 900 l = l->next;
807 } 901 }
808 } else if (pkt->status == 2) { 902 } else if (pkt->status == 2) {
809 purple_notify_error(gc, NULL, 903 purple_notify_error(gc, NULL,
810 _("Your Yahoo! message did not get sent."), NULL); 904 _("Your Yahoo! message did not get sent."), NULL);
905 }
906
907 /* disconnect the peer if connected through p2p and sends wrong value for session id */
908 if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) {
909 purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im->from);
910 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
911 g_hash_table_remove(yd->peers, im->from);
912 return;
811 } 913 }
812 914
813 /** TODO: It seems that this check should be per IM, not global */ 915 /** TODO: It seems that this check should be per IM, not global */
814 /* Check for the Doodle IMV */ 916 /* Check for the Doodle IMV */
815 if (im != NULL && imv!= NULL && im->from != NULL) 917 if (im != NULL && imv!= NULL && im->from != NULL)
2185 char *group = NULL; 2287 char *group = NULL;
2186 char *decoded_group; 2288 char *decoded_group;
2187 char *buf; 2289 char *buf;
2188 YahooFriend *f; 2290 YahooFriend *f;
2189 GSList *l = pkt->hash; 2291 GSList *l = pkt->hash;
2292 struct yahoo_data *yd = gc->proto_data;
2293 int protocol = 0;
2190 2294
2191 while (l) { 2295 while (l) {
2192 struct yahoo_pair *pair = l->data; 2296 struct yahoo_pair *pair = l->data;
2193 2297
2194 switch (pair->key) { 2298 switch (pair->key) {
2199 who = pair->value; 2303 who = pair->value;
2200 break; 2304 break;
2201 case 65: 2305 case 65:
2202 group = pair->value; 2306 group = pair->value;
2203 break; 2307 break;
2308 case 241:
2309 protocol = strtol(pair->value, NULL, 10);
2310 break;
2204 } 2311 }
2205 2312
2206 l = l->next; 2313 l = l->next;
2207 } 2314 }
2208 2315
2212 group = ""; 2319 group = "";
2213 2320
2214 if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */ 2321 if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */
2215 f = yahoo_friend_find_or_new(gc, who); 2322 f = yahoo_friend_find_or_new(gc, who);
2216 yahoo_update_status(gc, who, f); 2323 yahoo_update_status(gc, who, f);
2324 if(protocol)
2325 f->protocol = protocol;
2326
2327 if( !g_hash_table_lookup(yd->peers, who) ) {
2328 /* we are not connected as client, so set friend to not connected */
2329 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
2330 f->p2p_packet_sent = 0;
2331 }
2332 else /* we are already connected. set friend to YAHOO_P2PSTATUS_WE_ARE_CLIENT */
2333 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT);
2217 return; 2334 return;
2218 } 2335 }
2219 2336
2220 decoded_group = yahoo_string_decode(gc, group, FALSE); 2337 decoded_group = yahoo_string_decode(gc, group, FALSE);
2221 buf = g_strdup_printf(_("Could not add buddy %s to group %s to the server list on account %s."), 2338 buf = g_strdup_printf(_("Could not add buddy %s to group %s to the server list on account %s."),
2224 purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf); 2341 purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf);
2225 g_free(buf); 2342 g_free(buf);
2226 g_free(decoded_group); 2343 g_free(decoded_group);
2227 } 2344 }
2228 2345
2346 /* write pkt to the source */
2347 static void yahoo_p2p_write_pkt(gint source, struct yahoo_packet *pkt)
2348 {
2349 size_t pkt_len;
2350 guchar *raw_packet;
2351
2352 /*build the raw packet and send it to the host*/
2353 pkt_len = yahoo_packet_build(pkt, 0, 0, 0, &raw_packet);
2354 if(write(source, raw_packet, pkt_len) != pkt_len)
2355 purple_debug_warning("yahoo","p2p: couldn't write to the source\n");
2356 g_free(raw_packet);
2357 }
2358
2359 static void yahoo_p2p_keepalive_cb(gpointer key, gpointer value, gpointer user_data)
2360 {
2361 struct yahoo_p2p_data *p2p_data = value;
2362 PurpleConnection *gc = user_data;
2363 struct yahoo_packet *pkt_to_send;
2364 PurpleAccount *account;
2365 struct yahoo_data *yd = gc->proto_data;
2366
2367 account = purple_connection_get_account(gc);
2368
2369 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
2370 yahoo_packet_hash(pkt_to_send, "ssisi",
2371 4, purple_normalize(account, purple_account_get_username(account)),
2372 5, p2p_data->host_username,
2373 241, 0, /* Protocol identifier */
2374 49, "PEERTOPEER",
2375 13, 7);
2376 yahoo_p2p_write_pkt(p2p_data->source, pkt_to_send);
2377
2378 yahoo_packet_free(pkt_to_send);
2379 }
2380
2381 static gboolean yahoo_p2p_keepalive(gpointer data)
2382 {
2383 PurpleConnection *gc = data;
2384 struct yahoo_data *yd = gc->proto_data;
2385
2386 g_hash_table_foreach(yd->peers, yahoo_p2p_keepalive_cb, gc);
2387
2388 return TRUE;
2389 }
2390
2391 /* destroy p2p_data associated with a peer and close p2p connection.
2392 * g_hash_table_remove() calls this function to destroy p2p_data associated with the peer,
2393 * call g_hash_table_remove() instead of this fucntion if peer has an entry in the table */
2394 static void yahoo_p2p_disconnect_destroy_data(gpointer data)
2395 {
2396 struct yahoo_p2p_data *p2p_data;
2397 YahooFriend *f;
2398
2399 if(!(p2p_data = data))
2400 return ;
2401
2402 /* If friend, set him not connected */
2403 f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username);
2404 if (f)
2405 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
2406
2407 if(p2p_data->source >= 0)
2408 close(p2p_data->source);
2409 purple_input_remove(p2p_data->input_event);
2410 g_free(p2p_data->host_ip);
2411 g_free(p2p_data->host_username);
2412 g_free(p2p_data);
2413 }
2414
2415 /* exchange of initial p2pfilexfer packets, service type YAHOO_SERVICE_P2PFILEXFER */
2416 static void yahoo_p2p_process_p2pfilexfer(gpointer data, gint source, struct yahoo_packet *pkt)
2417 {
2418 struct yahoo_p2p_data *p2p_data;
2419 char *who = NULL;
2420 GSList *l = pkt->hash;
2421 struct yahoo_packet *pkt_to_send;
2422 PurpleAccount *account;
2423 int val_13_to_send = 0;
2424 struct yahoo_data *yd;
2425 YahooFriend *f;
2426
2427 if(!(p2p_data = data))
2428 return ;
2429
2430 yd = p2p_data->gc->proto_data;
2431
2432 /* lets see whats in the packet */
2433 while (l) {
2434 struct yahoo_pair *pair = l->data;
2435
2436 switch (pair->key) {
2437 case 4:
2438 who = pair->value;
2439 if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) {
2440 /* from whom are we receiving the packets ?? */
2441 purple_debug_warning("yahoo","p2p: received data from wrong user\n");
2442 return;
2443 }
2444 break;
2445 case 13:
2446 p2p_data->val_13 = strtol(pair->value, NULL, 10); /* Value should be 5-7 */
2447 break;
2448 /* case 5, 49 look laters, no use right now */
2449 }
2450 l = l->next;
2451 }
2452
2453 account = purple_connection_get_account(p2p_data->gc);
2454
2455 /* key_13: sort of a counter.
2456 * WHEN WE ARE CLIENT: yahoo server sends val_13 = 0, we send to peer val_13 = 1, receive back val_13 = 5,
2457 * we send val_13=6, receive val_13=7, we send val_13=7, HALT. Keep sending val_13 = 7 as keep alive.
2458 * WHEN WE ARE SERVER: we send val_13 = 0 to yahoo server, peer sends us val_13 = 1, we send val_13 = 5,
2459 * receive val_13 = 6, send val_13 = 7, receive val_13 = 7. HALT. Keep sending val_13 = 7 as keep alive. */
2460
2461 switch(p2p_data->val_13) {
2462 case 1 : val_13_to_send = 5; break;
2463 case 5 : val_13_to_send = 6; break;
2464 case 6 : val_13_to_send = 7; break;
2465 case 7 : if( g_hash_table_lookup(yd->peers, p2p_data->host_username) )
2466 return;
2467 val_13_to_send = 7; break;
2468 default: purple_debug_warning("yahoo","p2p:Unknown value for key 13\n");
2469 return;
2470 }
2471
2472 /* Build the yahoo packet */
2473 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
2474 yahoo_packet_hash(pkt_to_send, "ssisi",
2475 4, purple_normalize(account, purple_account_get_username(account)),
2476 5, p2p_data->host_username,
2477 241, 0, /* Protocol identifier */
2478 49, "PEERTOPEER",
2479 13, val_13_to_send);
2480
2481 /* build the raw packet and send it to the host */
2482 yahoo_p2p_write_pkt(source, pkt_to_send);
2483 yahoo_packet_free(pkt_to_send);
2484
2485 if( val_13_to_send == 7 )
2486 if( !g_hash_table_lookup(yd->peers, p2p_data->host_username) ) {
2487 g_hash_table_insert(yd->peers, g_strdup(p2p_data->host_username), p2p_data);
2488 /* If the peer is a friend, set him connected */
2489 f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username);
2490 if (f) {
2491 if(p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER) {
2492 p2p_data->session_id = f->session_id;
2493 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_SERVER);
2494 }
2495 else
2496 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT);
2497 }
2498 }
2499 }
2500
2501 /* callback function associated with receiving of data, not considering receipt of multiple YMSG packets in a single TCP packet */
2502 static void yahoo_p2p_read_pkt_cb(gpointer data, gint source, PurpleInputCondition cond)
2503 {
2504 guchar buf[1024]; /* is it safe to assume a fixed array length of 1024 ?? */
2505 int len;
2506 int pos = 0;
2507 int pktlen;
2508 struct yahoo_packet *pkt;
2509 guchar *start = NULL;
2510 struct yahoo_p2p_data *p2p_data;
2511 struct yahoo_data *yd;
2512
2513 if(!(p2p_data = data))
2514 return ;
2515 yd = p2p_data->gc->proto_data;
2516
2517 len = read(source, buf, sizeof(buf));
2518 if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
2519 return ; /* No Worries*/
2520 else if (len <= 0)
2521 {
2522 purple_debug_warning("yahoo","p2p: Error in connection, or host disconnected\n");
2523 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
2524 if( g_hash_table_lookup(yd->peers, p2p_data->host_username) )
2525 g_hash_table_remove(yd->peers,p2p_data->host_username);
2526 else
2527 yahoo_p2p_disconnect_destroy_data(data);
2528 return;
2529 }
2530
2531 if(len < YAHOO_PACKET_HDRLEN)
2532 return;
2533
2534 if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) {
2535 /* Not a YMSG packet */
2536 purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
2537
2538 start = memchr(buf + 1, 'Y', len - 1);
2539 if(start) {
2540 g_memmove(buf, start, len - (start - buf));
2541 len -= start - buf;
2542 } else {
2543 g_free(buf);
2544 return;
2545 }
2546 }
2547
2548 pos += 4; /* YMSG */
2549 pos += 2;
2550 pos += 2;
2551
2552 pktlen = yahoo_get16(buf + pos); pos += 2;
2553 purple_debug(PURPLE_DEBUG_MISC, "yahoo", "p2p: %d bytes to read\n", len);
2554
2555 pkt = yahoo_packet_new(0, 0, 0);
2556 pkt->service = yahoo_get16(buf + pos); pos += 2;
2557 pkt->status = yahoo_get32(buf + pos); pos += 4;
2558 pkt->id = yahoo_get32(buf + pos); pos += 4;
2559
2560 purple_debug(PURPLE_DEBUG_MISC, "yahoo", "p2p: Yahoo Service: 0x%02x Status: %d\n",pkt->service, pkt->status);
2561 yahoo_packet_read(pkt, buf + pos, pktlen);
2562
2563 /* packet processing */
2564 switch(pkt->service) {
2565 case YAHOO_SERVICE_P2PFILEXFER:
2566 yahoo_p2p_process_p2pfilexfer(data, source, pkt);
2567 break;
2568 case YAHOO_SERVICE_MESSAGE:
2569 yahoo_process_message(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P);
2570 break;
2571 case YAHOO_SERVICE_NOTIFY:
2572 yahoo_process_notify(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P);
2573 break;
2574 default:
2575 purple_debug_warning("yahoo","p2p: p2p service %d Unhandled\n",pkt->service);
2576 }
2577
2578 yahoo_packet_free(pkt);
2579 }
2580
2581 static void yahoo_p2p_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond)
2582 {
2583 int acceptfd;
2584 struct yahoo_p2p_data *p2p_data;
2585 struct yahoo_data *yd;
2586
2587 if(!(p2p_data = data))
2588 return ;
2589 yd = p2p_data->gc->proto_data;
2590
2591 acceptfd = accept(source, NULL, 0);
2592 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
2593 return;
2594 else if(acceptfd == -1) {
2595 purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno));
2596 yahoo_p2p_disconnect_destroy_data(data);
2597 return;
2598 }
2599
2600 /* remove watcher and close p2p server */
2601 purple_input_remove(yd->yahoo_p2p_server_watcher);
2602 close(yd->yahoo_local_p2p_server_fd);
2603 yd->yahoo_local_p2p_server_fd = -1;
2604
2605 /* Add an Input Read event to the file descriptor */
2606 p2p_data->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data);
2607 p2p_data->source = acceptfd;
2608 }
2609
2610 static gboolean yahoo_cancel_p2p_server_listen_cb(gpointer data)
2611 {
2612 struct yahoo_p2p_data *p2p_data;
2613 struct yahoo_data *yd;
2614
2615 if(!(p2p_data = data))
2616 return FALSE;
2617
2618 yd = p2p_data->gc->proto_data;
2619
2620 purple_debug_warning("yahoo","yahoo p2p server timeout, peer failed to connect");
2621 yahoo_p2p_disconnect_destroy_data(data);
2622 purple_input_remove(yd->yahoo_p2p_server_watcher);
2623 yd->yahoo_p2p_server_watcher = 0;
2624 close(yd->yahoo_local_p2p_server_fd);
2625 yd->yahoo_local_p2p_server_fd = -1;
2626 yd->yahoo_p2p_server_timeout_handle = 0;
2627
2628 return FALSE;
2629 }
2630
2631 static void yahoo_p2p_server_listen_cb(int listenfd, gpointer data)
2632 {
2633 struct yahoo_p2p_data *p2p_data;
2634 struct yahoo_data *yd;
2635
2636 if(!(p2p_data = data))
2637 return ;
2638
2639 if(listenfd == -1) {
2640 purple_debug_warning("yahoo","p2p: error starting p2p server\n");
2641 yahoo_p2p_disconnect_destroy_data(data);
2642 return;
2643 }
2644
2645 yd = p2p_data->gc->proto_data;
2646
2647 /* Add an Input Read event to the file descriptor */
2648 yd->yahoo_local_p2p_server_fd = listenfd;
2649 yd->yahoo_p2p_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_server_send_connected_cb,data);
2650
2651 /* add timeout */
2652 yd->yahoo_p2p_server_timeout_handle = purple_timeout_add_seconds(YAHOO_P2P_SERVER_TIMEOUT, yahoo_cancel_p2p_server_listen_cb, data);
2653 }
2654
2655 /* send p2p pkt containing our encoded ip, asking peer to connect to us */
2656 void yahoo_send_p2p_pkt(PurpleConnection *gc, const char *who, int val_13)
2657 {
2658 const char *public_ip;
2659 guint32 temp[4];
2660 guint32 ip;
2661 char temp_str[100];
2662 gchar *base64_ip = NULL;
2663 YahooFriend *f;
2664 struct yahoo_packet *pkt;
2665 PurpleAccount *account;
2666 struct yahoo_data *yd = gc->proto_data;
2667 struct yahoo_p2p_data *p2p_data;
2668
2669 f = yahoo_friend_find(gc, who);
2670 account = purple_connection_get_account(gc);
2671
2672 /* Do not send invitation if already listening for other connection */
2673 if(yd->yahoo_local_p2p_server_fd >= 0)
2674 return;
2675
2676 /* One shouldn't try to connect to self */
2677 if( strcmp(purple_normalize(account, purple_account_get_username(account)), who) == 0)
2678 return;
2679
2680 /* send packet to only those friends who arent p2p connected and to whom we havent already sent. Do not send if this condition doesn't hold good */
2681 if( !( f && (yahoo_friend_get_p2p_status(f) == YAHOO_P2PSTATUS_NOT_CONNECTED) && (f->p2p_packet_sent == 0)) )
2682 return;
2683
2684 /* Dont send p2p packet to buddies of other protocols */
2685 if(f->protocol)
2686 return;
2687
2688 /* Finally, don't try to connect to buddies not online or on sms */
2689 if( (f->status == YAHOO_STATUS_OFFLINE) || f->sms )
2690 return;
2691
2692 public_ip = purple_network_get_public_ip();
2693 if( (sscanf(public_ip, "%u.%u.%u.%u", &temp[0], &temp[1], &temp[2], &temp[3])) !=4 )
2694 return ;
2695
2696 ip = (temp[3] << 24) | (temp[2] <<16) | (temp[1] << 8) | temp[0];
2697 sprintf(temp_str, "%d", ip);
2698 base64_ip = purple_base64_encode( (guchar *)temp_str, strlen(temp_str) );
2699
2700 pkt = yahoo_packet_new(YAHOO_SERVICE_PEERTOPEER, YAHOO_STATUS_AVAILABLE, 0);
2701 yahoo_packet_hash(pkt, "sssissis",
2702 1, purple_normalize(account, purple_account_get_username(account)),
2703 4, purple_normalize(account, purple_account_get_username(account)),
2704 12, base64_ip, /* base64 encode ip */
2705 61, 0, /* To-do : figure out what is 61 for?? */
2706 2, "",
2707 5, who,
2708 13, val_13,
2709 49, "PEERTOPEER");
2710 yahoo_packet_send_and_free(pkt, yd);
2711
2712 f->p2p_packet_sent = 1; /* set p2p_packet_sent to sent */
2713
2714 p2p_data = g_new0(struct yahoo_p2p_data, 1);
2715
2716 p2p_data->gc = gc;
2717 p2p_data->host_ip = NULL;
2718 p2p_data->host_username = g_strdup(who);
2719 p2p_data->val_13 = val_13;
2720 p2p_data->connection_type = YAHOO_P2P_WE_ARE_SERVER;
2721
2722 purple_network_listen(YAHOO_PAGER_PORT_P2P, SOCK_STREAM, yahoo_p2p_server_listen_cb, p2p_data);
2723
2724 g_free(base64_ip);
2725 }
2726
2727 /* function called when connection to p2p host is setup */
2728 static void yahoo_p2p_init_cb(gpointer data, gint source, const gchar *error_message)
2729 {
2730 struct yahoo_p2p_data *p2p_data;
2731 struct yahoo_packet *pkt_to_send;
2732 PurpleAccount *account;
2733 struct yahoo_data *yd;
2734
2735 if(!(p2p_data = data))
2736 return ;
2737 yd = p2p_data->gc->proto_data;
2738
2739 if(error_message != NULL) {
2740 purple_debug_warning("yahoo","p2p: %s\n",error_message);
2741 yahoo_send_p2p_pkt(p2p_data->gc, p2p_data->host_username, 2);/* send p2p init packet with val_13=2 */
2742
2743 yahoo_p2p_disconnect_destroy_data(p2p_data);
2744 return;
2745 }
2746
2747 /* Add an Input Read event to the file descriptor */
2748 p2p_data->input_event = purple_input_add(source, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data);
2749 p2p_data->source = source;
2750
2751 account = purple_connection_get_account(p2p_data->gc);
2752
2753 /* Build the yahoo packet */
2754 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
2755 yahoo_packet_hash(pkt_to_send, "ssisi",
2756 4, purple_normalize(account, purple_account_get_username(account)),
2757 5, p2p_data->host_username,
2758 241, 0, /* Protocol identifier */
2759 49, "PEERTOPEER",
2760 13, 1); /* we receive key13= 0 or 2, we send key13=1 */
2761
2762 yahoo_p2p_write_pkt(source, pkt_to_send); /* build raw packet and send */
2763 yahoo_packet_free(pkt_to_send);
2764 }
2765
2229 static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt) 2766 static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt)
2230 { 2767 {
2231 GSList *l = pkt->hash; 2768 GSList *l = pkt->hash;
2232 char *who = NULL; 2769 char *who = NULL;
2233 char *base64 = NULL; 2770 char *base64 = NULL;
2234 guchar *decoded; 2771 guchar *decoded;
2235 gsize len; 2772 gsize len;
2773 gint val_13 = 0;
2774 gint val_11 = 0;
2775 PurpleAccount *account;
2776 YahooFriend *f;
2777
2778 /* if status is YAHOO_STATUS_BUSY, don't do anything, peer wont connect */
2779 if(pkt->status == YAHOO_STATUS_BUSY)
2780 return ;
2236 2781
2237 while (l) { 2782 while (l) {
2238 struct yahoo_pair *pair = l->data; 2783 struct yahoo_pair *pair = l->data;
2239 2784
2240 switch (pair->key) { 2785 switch (pair->key) {
2250 case 12: 2795 case 12:
2251 base64 = pair->value; 2796 base64 = pair->value;
2252 /* so, this is an ip address. in base64. decoded it's in ascii. 2797 /* so, this is an ip address. in base64. decoded it's in ascii.
2253 after strtol, it's in reversed byte order. Who thought this up?*/ 2798 after strtol, it's in reversed byte order. Who thought this up?*/
2254 break; 2799 break;
2800 case 13:
2801 val_13 = strtol(pair->value, NULL, 10);
2802 break;
2803 case 11:
2804 val_11 = strtol(pair->value, NULL, 10); /* session id of peer */
2805 if( (f = yahoo_friend_find(gc, who)) )
2806 f->session_id = val_11;
2807 break;
2255 /* 2808 /*
2256 TODO: figure these out 2809 TODO: figure these out
2257 yahoo: Key: 61 Value: 0 2810 yahoo: Key: 61 Value: 0
2258 yahoo: Key: 2 Value: 2811 yahoo: Key: 2 Value:
2259 yahoo: Key: 13 Value: 0 2812 yahoo: Key: 13 Value: 0 packet count ??
2260 yahoo: Key: 49 Value: PEERTOPEER 2813 yahoo: Key: 49 Value: PEERTOPEER
2261 yahoo: Key: 140 Value: 1 2814 yahoo: Key: 140 Value: 1
2262 yahoo: Key: 11 Value: -1786225828
2263 */ 2815 */
2264 2816
2265 } 2817 }
2266 2818
2267 l = l->next; 2819 l = l->next;
2269 2821
2270 if (base64) { 2822 if (base64) {
2271 guint32 ip; 2823 guint32 ip;
2272 char *tmp2; 2824 char *tmp2;
2273 YahooFriend *f; 2825 YahooFriend *f;
2826 char *host_ip;
2827 struct yahoo_p2p_data *p2p_data = g_new0(struct yahoo_p2p_data, 1);
2274 2828
2275 decoded = purple_base64_decode(base64, &len); 2829 decoded = purple_base64_decode(base64, &len);
2276 if (len) { 2830 if (len) {
2277 char *tmp = purple_str_binary_to_ascii(decoded, len); 2831 char *tmp = purple_str_binary_to_ascii(decoded, len);
2278 purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp); 2832 purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp);
2281 2835
2282 tmp2 = g_strndup((const gchar *)decoded, len); /* so its \0 terminated...*/ 2836 tmp2 = g_strndup((const gchar *)decoded, len); /* so its \0 terminated...*/
2283 ip = strtol(tmp2, NULL, 10); 2837 ip = strtol(tmp2, NULL, 10);
2284 g_free(tmp2); 2838 g_free(tmp2);
2285 g_free(decoded); 2839 g_free(decoded);
2286 tmp2 = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, 2840 host_ip = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff,
2287 (ip >> 24) & 0xff); 2841 (ip >> 24) & 0xff);
2288 f = yahoo_friend_find(gc, who); 2842 f = yahoo_friend_find(gc, who);
2289 if (f) 2843 if (f)
2290 yahoo_friend_set_ip(f, tmp2); 2844 yahoo_friend_set_ip(f, host_ip);
2291 g_free(tmp2); 2845 purple_debug_info("yahoo", "IP : %s\n", host_ip);
2846
2847 account = purple_connection_get_account(gc);
2848
2849 if(val_11==0) {
2850 if(!f)
2851 return;
2852 else
2853 val_11 = f->session_id;
2854 }
2855
2856 p2p_data->host_username = g_strdup(who);
2857 p2p_data->val_13 = val_13;
2858 p2p_data->session_id = val_11;
2859 p2p_data->host_ip = host_ip;
2860 p2p_data->gc = gc;
2861 p2p_data->connection_type = YAHOO_P2P_WE_ARE_CLIENT;
2862
2863 /* connect to host */
2864 if((purple_proxy_connect(NULL, account, host_ip, YAHOO_PAGER_PORT_P2P, yahoo_p2p_init_cb, p2p_data))==NULL) {
2865 yahoo_p2p_disconnect_destroy_data(p2p_data);
2866 purple_debug_info("yahoo","p2p: Connection to %s failed\n", host_ip);
2867 }
2292 } 2868 }
2293 } 2869 }
2294 2870
2295 static void yahoo_process_audible(PurpleConnection *gc, struct yahoo_packet *pkt) 2871 static void yahoo_process_audible(PurpleConnection *gc, struct yahoo_packet *pkt)
2296 { 2872 {
2366 case YAHOO_SERVICE_Y6_STATUS_UPDATE: 2942 case YAHOO_SERVICE_Y6_STATUS_UPDATE:
2367 case YAHOO_SERVICE_STATUS_15: 2943 case YAHOO_SERVICE_STATUS_15:
2368 yahoo_process_status(gc, pkt); 2944 yahoo_process_status(gc, pkt);
2369 break; 2945 break;
2370 case YAHOO_SERVICE_NOTIFY: 2946 case YAHOO_SERVICE_NOTIFY:
2371 yahoo_process_notify(gc, pkt); 2947 yahoo_process_notify(gc, pkt, YAHOO_PKT_TYPE_SERVER);
2372 break; 2948 break;
2373 case YAHOO_SERVICE_MESSAGE: 2949 case YAHOO_SERVICE_MESSAGE:
2374 case YAHOO_SERVICE_GAMEMSG: 2950 case YAHOO_SERVICE_GAMEMSG:
2375 case YAHOO_SERVICE_CHATMSG: 2951 case YAHOO_SERVICE_CHATMSG:
2376 yahoo_process_message(gc, pkt); 2952 yahoo_process_message(gc, pkt, YAHOO_PKT_TYPE_SERVER);
2377 break; 2953 break;
2378 case YAHOO_SERVICE_SYSMESSAGE: 2954 case YAHOO_SERVICE_SYSMESSAGE:
2379 yahoo_process_sysmessage(gc, pkt); 2955 yahoo_process_sysmessage(gc, pkt);
2380 break; 2956 break;
2381 case YAHOO_SERVICE_NEWMAIL: 2957 case YAHOO_SERVICE_NEWMAIL:
2448 case YAHOO_SERVICE_PRESENCE_SESSION: 3024 case YAHOO_SERVICE_PRESENCE_SESSION:
2449 yahoo_process_presence(gc, pkt); 3025 yahoo_process_presence(gc, pkt);
2450 break; 3026 break;
2451 case YAHOO_SERVICE_P2PFILEXFER: 3027 case YAHOO_SERVICE_P2PFILEXFER:
2452 /* This case had no break and continued; thus keeping it this way.*/ 3028 /* This case had no break and continued; thus keeping it this way.*/
2453 yahoo_process_p2pfilexfer(gc, pkt); 3029 yahoo_process_p2p(gc, pkt); /* P2PFILEXFER handled the same way as process_p2p */
3030 yahoo_process_p2pfilexfer(gc, pkt); /* redundant ??, need to have a break now */
2454 case YAHOO_SERVICE_FILETRANSFER: 3031 case YAHOO_SERVICE_FILETRANSFER:
2455 yahoo_process_filetransfer(gc, pkt); 3032 yahoo_process_filetransfer(gc, pkt);
2456 break; 3033 break;
2457 case YAHOO_SERVICE_PEERTOPEER: 3034 case YAHOO_SERVICE_PEERTOPEER:
2458 yahoo_process_p2p(gc, pkt); 3035 yahoo_process_p2p(gc, pkt);
2481 case YAHOO_SERVICE_FILETRANS_INFO_15: 3058 case YAHOO_SERVICE_FILETRANS_INFO_15:
2482 yahoo_process_filetrans_info_15(gc, pkt); 3059 yahoo_process_filetrans_info_15(gc, pkt);
2483 break; 3060 break;
2484 case YAHOO_SERVICE_FILETRANS_ACC_15: 3061 case YAHOO_SERVICE_FILETRANS_ACC_15:
2485 yahoo_process_filetrans_acc_15(gc, pkt); 3062 yahoo_process_filetrans_acc_15(gc, pkt);
3063 break;
3064 case YAHOO_SERVICE_SMS_MSG:
3065 yahoo_process_sms_message(gc, pkt);
2486 break; 3066 break;
2487 3067
2488 default: 3068 default:
2489 purple_debug(PURPLE_DEBUG_ERROR, "yahoo", 3069 purple_debug(PURPLE_DEBUG_ERROR, "yahoo",
2490 "Unhandled service 0x%02x\n", pkt->service); 3070 "Unhandled service 0x%02x\n", pkt->service);
3003 /* TODO: Is there a good grow size for the buffer? */ 3583 /* TODO: Is there a good grow size for the buffer? */
3004 yd->txbuf = purple_circ_buffer_new(0); 3584 yd->txbuf = purple_circ_buffer_new(0);
3005 yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free); 3585 yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free);
3006 yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); 3586 yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
3007 yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); 3587 yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
3588 yd->peers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_p2p_disconnect_destroy_data);
3589 yd->sms_carrier = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
3590 yd->yahoo_p2p_timer = purple_timeout_add_seconds(YAHOO_P2P_KEEPALIVE_SECS, yahoo_p2p_keepalive, gc);
3008 yd->confs = NULL; 3591 yd->confs = NULL;
3009 yd->conf_id = 2; 3592 yd->conf_id = 2;
3010 yd->last_keepalive = yd->last_ping = time(NULL); 3593 yd->last_keepalive = yd->last_ping = time(NULL);
3011 3594
3012 yd->current_status = get_yahoo_status_from_purple_status(status); 3595 yd->current_status = get_yahoo_status_from_purple_status(status);
3068 3651
3069 yd->chat_online = FALSE; 3652 yd->chat_online = FALSE;
3070 if (yd->in_chat) 3653 if (yd->in_chat)
3071 yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */ 3654 yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */
3072 3655
3656 purple_timeout_remove(yd->yahoo_p2p_timer);
3657 if(yd->yahoo_p2p_server_timeout_handle != 0)
3658 purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle);
3659
3660 /* close p2p server if it is waiting for a peer to connect */
3661 purple_input_remove(yd->yahoo_p2p_server_watcher);
3662 close(yd->yahoo_local_p2p_server_fd);
3663 yd->yahoo_local_p2p_server_fd = -1;
3664
3665 g_hash_table_destroy(yd->sms_carrier);
3666 g_hash_table_destroy(yd->peers);
3073 g_hash_table_destroy(yd->friends); 3667 g_hash_table_destroy(yd->friends);
3074 g_hash_table_destroy(yd->imvironments); 3668 g_hash_table_destroy(yd->imvironments);
3075 g_hash_table_destroy(yd->xfer_peer_idstring_map); 3669 g_hash_table_destroy(yd->xfer_peer_idstring_map);
3076 g_free(yd->chat_name); 3670 g_free(yd->chat_name);
3077 3671
3607 m = g_list_append(m, act); 4201 m = g_list_append(m, act);
3608 4202
3609 return m; 4203 return m;
3610 } 4204 }
3611 4205
4206 struct yahoo_sms_carrier_cb_data {
4207 PurpleConnection *gc;
4208 char *who;
4209 char *what;
4210 };
4211
4212 static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags);
4213
4214 static void yahoo_get_sms_carrier_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
4215 const gchar *webdata, size_t len, const gchar *error_message)
4216 {
4217 struct yahoo_sms_carrier_cb_data *sms_cb_data = user_data;
4218 PurpleConnection *gc = sms_cb_data->gc;
4219 struct yahoo_data *yd = gc->proto_data;
4220 char *mobile_no = NULL;
4221 char *status = NULL;
4222 char *carrier = NULL;
4223 PurpleAccount *account = purple_connection_get_account(gc);
4224 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
4225
4226 if (error_message != NULL) {
4227 purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
4228
4229 g_free(sms_cb_data->who);
4230 g_free(sms_cb_data->what);
4231 g_free(sms_cb_data);
4232 return ;
4233 }
4234 else if (len > 0 && webdata && *webdata) {
4235 xmlnode *validate_data_root = xmlnode_from_str(webdata, -1);
4236 xmlnode *validate_data_child = xmlnode_get_child(validate_data_root, "mobile_no");
4237 mobile_no = (char *)xmlnode_get_attrib(validate_data_child, "msisdn");
4238
4239 validate_data_root = xmlnode_copy(validate_data_child);
4240 validate_data_child = xmlnode_get_child(validate_data_root, "status");
4241 status = xmlnode_get_data(validate_data_child);
4242
4243 validate_data_child = xmlnode_get_child(validate_data_root, "carrier");
4244 carrier = xmlnode_get_data(validate_data_child);
4245
4246 purple_debug_info("yahoo","SMS validate data: Mobile:%s, Status:%s, Carrier:%s\n", mobile_no, status, carrier);
4247
4248 if( strcmp(status, "Valid") == 0) {
4249 g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup(carrier));
4250 yahoo_send_im(sms_cb_data->gc, sms_cb_data->who, sms_cb_data->what, PURPLE_MESSAGE_SEND);
4251 }
4252 else {
4253 g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup("Unknown"));
4254 purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
4255 }
4256
4257 xmlnode_free(validate_data_child);
4258 xmlnode_free(validate_data_root);
4259 g_free(sms_cb_data->who);
4260 g_free(sms_cb_data->what);
4261 g_free(sms_cb_data);
4262 g_free(mobile_no);
4263 g_free(status);
4264 g_free(carrier);
4265 }
4266 }
4267
4268 static void yahoo_get_sms_carrier(PurpleConnection *gc, gpointer data)
4269 {
4270 struct yahoo_data *yd = gc->proto_data;
4271 PurpleUtilFetchUrlData *url_data;
4272 struct yahoo_sms_carrier_cb_data *sms_cb_data;
4273 char *validate_request_str = NULL;
4274 char *request = NULL;
4275 gboolean use_whole_url = FALSE;
4276 xmlnode *validate_request_root = NULL;
4277 xmlnode *validate_request_child = NULL;
4278
4279 if(!(sms_cb_data = data))
4280 return;
4281
4282 validate_request_root = xmlnode_new("validate");
4283 xmlnode_set_attrib(validate_request_root, "intl", "us");
4284 xmlnode_set_attrib(validate_request_root, "version", YAHOO_CLIENT_VERSION);
4285 xmlnode_set_attrib(validate_request_root, "qos", "0");
4286
4287 validate_request_child = xmlnode_new_child(validate_request_root, "mobile_no");
4288 xmlnode_set_attrib(validate_request_child, "msisdn", sms_cb_data->who + 1);
4289
4290 validate_request_str = xmlnode_to_str(validate_request_root, NULL);
4291
4292 xmlnode_free(validate_request_child);
4293 xmlnode_free(validate_request_root);
4294
4295 request = g_strdup_printf(
4296 "POST /mobileno?intl=us&version=%s HTTP/1.1\r\n"
4297 "Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s; path=/; domain=.yahoo.com;\r\n"
4298 "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n"
4299 "Host: validate.msg.yahoo.com\r\n"
4300 "Content-Length: %d\r\n"
4301 "Cache-Control: no-cache\r\n\r\n%s",
4302 YAHOO_CLIENT_VERSION, yd->cookie_t, yd->cookie_y, strlen(validate_request_str), validate_request_str);
4303
4304 /* use whole URL if using HTTP Proxy */
4305 if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP))
4306 use_whole_url = TRUE;
4307
4308 url_data = purple_util_fetch_url_request(YAHOO_SMS_CARRIER_URL, use_whole_url,
4309 "Mozilla/4.0 (compatible; MSIE 5.5)", TRUE, request, FALSE,
4310 yahoo_get_sms_carrier_cb, data);
4311
4312 g_free(request);
4313 g_free(validate_request_str);
4314
4315 if (!url_data) {
4316 PurpleAccount *account = purple_connection_get_account(gc);
4317 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
4318 purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
4319 g_free(sms_cb_data->who);
4320 g_free(sms_cb_data->what);
4321 g_free(sms_cb_data);
4322 }
4323 }
4324
3612 static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags) 4325 static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags)
3613 { 4326 {
3614 struct yahoo_data *yd = gc->proto_data; 4327 struct yahoo_data *yd = gc->proto_data;
3615 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0); 4328 struct yahoo_packet *pkt;
3616 char *msg = yahoo_html_to_codes(what); 4329 char *msg = yahoo_html_to_codes(what);
3617 char *msg2; 4330 char *msg2;
3618 gboolean utf8 = TRUE; 4331 gboolean utf8 = TRUE;
3619 PurpleWhiteboard *wb; 4332 PurpleWhiteboard *wb;
3620 int ret = 1; 4333 int ret = 1;
3621 YahooFriend *f = NULL; 4334 YahooFriend *f = NULL;
4335 struct yahoo_p2p_data *p2p_data;
3622 4336
3623 msg2 = yahoo_string_encode(gc, msg, &utf8); 4337 msg2 = yahoo_string_encode(gc, msg, &utf8);
3624 4338
4339 if( strncmp(who, "+", 1) == 0 ) {
4340 /* we have an sms to be sent */
4341 gchar *carrier = NULL;
4342 const char *alias = NULL;
4343 PurpleAccount *account = purple_connection_get_account(gc);
4344 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account);
4345
4346 carrier = g_hash_table_lookup(yd->sms_carrier, who);
4347 if (!carrier) {
4348 struct yahoo_sms_carrier_cb_data *sms_cb_data;
4349 sms_cb_data = g_malloc(sizeof(struct yahoo_sms_carrier_cb_data));
4350 sms_cb_data->gc = gc;
4351 sms_cb_data->who = g_malloc(strlen(who));
4352 sms_cb_data->what = g_malloc(strlen(what));
4353 strcpy(sms_cb_data->who, who);
4354 strcpy(sms_cb_data->what, what);
4355
4356 purple_conversation_write(conv, NULL, "Getting mobile carrier to send the sms", PURPLE_MESSAGE_SYSTEM, time(NULL));
4357
4358 yahoo_get_sms_carrier(gc, sms_cb_data);
4359
4360 g_free(msg);
4361 g_free(msg2);
4362 return ret;
4363 }
4364 else if( strcmp(carrier,"Unknown") == 0 ) {
4365 purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
4366
4367 g_free(msg);
4368 g_free(msg2);
4369 return -1;
4370 }
4371
4372 alias = purple_account_get_alias(account);
4373 pkt = yahoo_packet_new(YAHOO_SERVICE_SMS_MSG, YAHOO_STATUS_AVAILABLE, 0);
4374 yahoo_packet_hash(pkt, "sssss",
4375 1, purple_connection_get_display_name(gc),
4376 69, alias,
4377 5, who + 1,
4378 68, carrier,
4379 14, msg2);
4380 yahoo_packet_send_and_free(pkt, yd);
4381
4382 g_free(msg);
4383 g_free(msg2);
4384
4385 return ret;
4386 }
4387
4388 pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0);
3625 yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who); 4389 yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who);
3626 if ((f = yahoo_friend_find(gc, who)) && f->protocol) 4390 if ((f = yahoo_friend_find(gc, who)) && f->protocol)
3627 yahoo_packet_hash_int(pkt, 241, f->protocol); 4391 yahoo_packet_hash_int(pkt, 241, f->protocol);
4392 else
4393 if(strchr(who,'@'))
4394 yahoo_packet_hash_int(pkt, 241, 2);
3628 4395
3629 if (utf8) 4396 if (utf8)
3630 yahoo_packet_hash_str(pkt, 97, "1"); 4397 yahoo_packet_hash_str(pkt, 97, "1");
3631 yahoo_packet_hash_str(pkt, 14, msg2); 4398 yahoo_packet_hash_str(pkt, 14, msg2);
3632 4399
3661 yahoo_packet_hash_str(pkt, 206, "0"); /* 0 = no picture, 2 = picture, maybe 1 = avatar? */ 4428 yahoo_packet_hash_str(pkt, 206, "0"); /* 0 = no picture, 2 = picture, maybe 1 = avatar? */
3662 else 4429 else
3663 yahoo_packet_hash_str(pkt, 206, "2"); 4430 yahoo_packet_hash_str(pkt, 206, "2");
3664 4431
3665 /* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */ 4432 /* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */
3666 if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) 4433 if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) {
3667 yahoo_packet_send(pkt, yd); 4434 /* if p2p link exists, send through it. To-do: key 15, time value to be sent in case of p2p */
4435 if( (p2p_data = g_hash_table_lookup(yd->peers, who)) ) {
4436 yahoo_packet_hash_int(pkt, 11, p2p_data->session_id);
4437 yahoo_p2p_write_pkt(p2p_data->source, pkt);
4438 }
4439 else {
4440 yahoo_packet_send(pkt, yd);
4441 yahoo_send_p2p_pkt(gc, who, 0); /* send p2p packet, with val_13=0 */
4442 }
4443 }
3668 else 4444 else
3669 ret = -E2BIG; 4445 ret = -E2BIG;
3670 4446
3671 yahoo_packet_free(pkt); 4447 yahoo_packet_free(pkt);
3672 4448
3677 } 4453 }
3678 4454
3679 static unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state) 4455 static unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state)
3680 { 4456 {
3681 struct yahoo_data *yd = gc->proto_data; 4457 struct yahoo_data *yd = gc->proto_data;
4458 struct yahoo_p2p_data *p2p_data;
4459
3682 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, 0); 4460 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, 0);
3683 yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc), 4461
4462 /* Don't do anything if sms is being typed */
4463 if( strncmp(who, "+", 1) == 0 )
4464 return 0;
4465
4466 /* check to see if p2p link exists, send through it */
4467 if( (p2p_data = g_hash_table_lookup(yd->peers, who)) ) {
4468 yahoo_packet_hash(pkt, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc),
4469 14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
4470 5, who, 11, p2p_data->session_id, 1002, "1"); /* To-do: key 15 to be sent in case of p2p */
4471 yahoo_p2p_write_pkt(p2p_data->source, pkt);
4472 yahoo_packet_free(pkt);
4473 }
4474 else { /* send through yahoo server */
4475 yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
3684 14, " ", 13, state == PURPLE_TYPING ? "1" : "0", 4476 14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
3685 5, who, 1002, "1"); 4477 5, who, 1002, "1");
3686 4478 yahoo_packet_send_and_free(pkt, yd);
3687 yahoo_packet_send_and_free(pkt, yd); 4479 }
3688 4480
3689 return 0; 4481 return 0;
3690 } 4482 }
3691 4483
3692 static void yahoo_session_presence_remove(gpointer key, gpointer value, gpointer data) 4484 static void yahoo_session_presence_remove(gpointer key, gpointer value, gpointer data)
3933 else 4725 else
3934 group = "Buddies"; 4726 group = "Buddies";
3935 4727
3936 group2 = yahoo_string_encode(gc, group, NULL); 4728 group2 = yahoo_string_encode(gc, group, NULL);
3937 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0); 4729 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0);
3938 yahoo_packet_hash(pkt, "ssssssssss", 4730 if(strchr(buddy->name, '@')) {
3939 14, "", 4731 yahoo_packet_hash(pkt, "sssssssssss",
3940 65, group2, 4732 14, "",
3941 97, "1", 4733 65, group2,
3942 1, purple_connection_get_display_name(gc), 4734 97, "1",
3943 302, "319", 4735 1, purple_connection_get_display_name(gc),
3944 300, "319", 4736 302, "319",
3945 7, buddy->name, 4737 300, "319",
3946 334, "0", 4738 7, buddy->name,
3947 301, "319", 4739 241, "2",
3948 303, "319" 4740 334, "0",
3949 ); 4741 301, "319",
4742 303, "319"
4743 );
4744 }
4745 else {
4746 yahoo_packet_hash(pkt, "ssssssssss",
4747 14, "",
4748 65, group2,
4749 97, "1",
4750 1, purple_connection_get_display_name(gc),
4751 302, "319",
4752 300, "319",
4753 7, buddy->name,
4754 334, "0",
4755 301, "319",
4756 303, "319"
4757 );
4758 }
4759
3950 if (f && f->protocol) 4760 if (f && f->protocol)
3951 yahoo_packet_hash_int(pkt, 241, f->protocol); 4761 yahoo_packet_hash_int(pkt, 241, f->protocol);
3952 yahoo_packet_send_and_free(pkt, yd); 4762 yahoo_packet_send_and_free(pkt, yd);
3953 g_free(group2); 4763 g_free(group2);
3954 } 4764 }
3959 struct yahoo_packet *pkt; 4769 struct yahoo_packet *pkt;
3960 GSList *buddies, *l; 4770 GSList *buddies, *l;
3961 PurpleGroup *g; 4771 PurpleGroup *g;
3962 gboolean remove = TRUE; 4772 gboolean remove = TRUE;
3963 char *cg; 4773 char *cg;
3964 4774 YahooFriend *f = yahoo_friend_find(gc, buddy->name);
3965 if (!(yahoo_friend_find(gc, buddy->name))) 4775
4776 if (!f)
3966 return; 4777 return;
3967 4778
3968 buddies = purple_find_buddies(purple_connection_get_account(gc), buddy->name); 4779 buddies = purple_find_buddies(purple_connection_get_account(gc), buddy->name);
3969 for (l = buddies; l; l = l->next) { 4780 for (l = buddies; l; l = l->next) {
3970 g = purple_buddy_get_group(l->data); 4781 g = purple_buddy_get_group(l->data);
3981 4792
3982 cg = yahoo_string_encode(gc, group->name, NULL); 4793 cg = yahoo_string_encode(gc, group->name, NULL);
3983 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0); 4794 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0);
3984 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 4795 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
3985 7, buddy->name, 65, cg); 4796 7, buddy->name, 65, cg);
4797 if(f->protocol)
4798 yahoo_packet_hash_int(pkt, 241, f->protocol);
3986 yahoo_packet_send_and_free(pkt, yd); 4799 yahoo_packet_send_and_free(pkt, yd);
3987 g_free(cg); 4800 g_free(cg);
3988 } 4801 }
3989 4802
3990 static void yahoo_add_deny(PurpleConnection *gc, const char *who) { 4803 static void yahoo_add_deny(PurpleConnection *gc, const char *who) {
4053 const char *old_group, const char *new_group) 4866 const char *old_group, const char *new_group)
4054 { 4867 {
4055 struct yahoo_data *yd = gc->proto_data; 4868 struct yahoo_data *yd = gc->proto_data;
4056 struct yahoo_packet *pkt; 4869 struct yahoo_packet *pkt;
4057 char *gpn, *gpo; 4870 char *gpn, *gpo;
4871 YahooFriend *f = yahoo_friend_find(gc, who);
4058 4872
4059 /* Step 0: If they aren't on the server list anyway, 4873 /* Step 0: If they aren't on the server list anyway,
4060 * don't bother letting the server know. 4874 * don't bother letting the server know.
4061 */ 4875 */
4062 if (!yahoo_friend_find(gc, who)) 4876 if (!f)
4063 return; 4877 return;
4064 4878
4065 /* If old and new are the same, we would probably 4879 /* If old and new are the same, we would probably
4066 * end up deleting the buddy, which would be bad. 4880 * end up deleting the buddy, which would be bad.
4067 * This might happen because of the charset conversation. 4881 * This might happen because of the charset conversation.
4073 g_free(gpo); 4887 g_free(gpo);
4074 return; 4888 return;
4075 } 4889 }
4076 4890
4077 pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, 0); 4891 pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, 0);
4078 yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc), 4892 if(f->protocol)
4893 yahoo_packet_hash(pkt, "ssssissss", 1, purple_connection_get_display_name(gc),
4894 302, "240", 300, "240", 7, who, 241, f->protocol, 224, gpo, 264, gpn, 301,
4895 "240", 303, "240");
4896 else
4897 yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc),
4079 302, "240", 300, "240", 7, who, 224, gpo, 264, gpn, 301, 4898 302, "240", 300, "240", 7, who, 224, gpo, 264, gpn, 301,
4080 "240", 303, "240"); 4899 "240", 303, "240");
4081 yahoo_packet_send_and_free(pkt, yd); 4900 yahoo_packet_send_and_free(pkt, yd);
4082 4901
4083 g_free(gpn); 4902 g_free(gpn);
4287 /* Spaces are encoded as '+' */ 5106 /* Spaces are encoded as '+' */
4288 g_strdelimit(message, "+", ' '); 5107 g_strdelimit(message, "+", ' ');
4289 purple_conv_send_confirm(conv, message); 5108 purple_conv_send_confirm(conv, message);
4290 } 5109 }
4291 } 5110 }
4292 /*else 5111 /* else
4293 **If pidgindialogs_im() was in the core, we could use it here. 5112 **If pidgindialogs_im() was in the core, we could use it here.
4294 * It is all purple_request_* based, but I'm not sure it really belongs in the core 5113 * It is all purple_request_* based, but I'm not sure it really belongs in the core
4295 pidgindialogs_im();*/ 5114 pidgindialogs_im(); */
4296 5115
4297 return TRUE; 5116 return TRUE;
4298 } 5117 }
4299 /* ymsgr:Chat?roomname */ 5118 /* ymsgr:Chat?roomname */
4300 else if (!g_ascii_strcasecmp(cmd, "Chat")) { 5119 else if (!g_ascii_strcasecmp(cmd, "Chat")) {
4304 /* This is somewhat hacky, but the params aren't useful after this command */ 5123 /* This is somewhat hacky, but the params aren't useful after this command */
4305 g_hash_table_insert(params, g_strdup("room"), g_strdup(rname)); 5124 g_hash_table_insert(params, g_strdup("room"), g_strdup(rname));
4306 g_hash_table_insert(params, g_strdup("type"), g_strdup("Chat")); 5125 g_hash_table_insert(params, g_strdup("type"), g_strdup("Chat"));
4307 serv_join_chat(purple_account_get_connection(acct), params); 5126 serv_join_chat(purple_account_get_connection(acct), params);
4308 } 5127 }
4309 /*else 5128 /* else
4310 ** Same as above (except that this would have to be re-written using purple_request_*) 5129 ** Same as above (except that this would have to be re-written using purple_request_*)
4311 pidgin_blist_joinchat_show(); */ 5130 pidgin_blist_joinchat_show(); */
4312 5131
4313 return TRUE; 5132 return TRUE;
4314 } 5133 }
4374 yahoo_set_idle, 5193 yahoo_set_idle,
4375 NULL, /* change_passwd*/ 5194 NULL, /* change_passwd*/
4376 yahoo_add_buddy, 5195 yahoo_add_buddy,
4377 NULL, /* add_buddies */ 5196 NULL, /* add_buddies */
4378 yahoo_remove_buddy, 5197 yahoo_remove_buddy,
4379 NULL, /*remove_buddies */ 5198 NULL, /* remove_buddies */
4380 NULL, /* add_permit */ 5199 NULL, /* add_permit */
4381 yahoo_add_deny, 5200 yahoo_add_deny,
4382 NULL, /* rem_permit */ 5201 NULL, /* rem_permit */
4383 yahoo_rem_deny, 5202 yahoo_rem_deny,
4384 yahoo_set_permit_deny, 5203 yahoo_set_permit_deny,

mercurial