comparison libpurple/protocols/yahoo/yahoo.c @ 27933:f44832c6a65b

propagate from branch 'im.pidgin.pidgin' (head a840b7a77c7e395db5e7877fab90763d91f70b3a) to branch 'im.pidgin.pidgin.yaz' (head 42d24988b115ba197f27a95547b1445c10f06d2c)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Sun, 08 Mar 2009 20:38:09 +0000
parents d8e6a2d592a4 7114d475a9e7
children 1337d2813b2d
comparison
equal deleted inserted replaced
27932:4033fea1709c 27933:f44832c6a65b
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"
151 GSList *l = pkt->hash; 153 GSList *l = pkt->hash;
152 YahooFriend *f = NULL; 154 YahooFriend *f = NULL;
153 char *name = NULL; 155 char *name = NULL;
154 gboolean unicode = FALSE; 156 gboolean unicode = FALSE;
155 char *message = NULL; 157 char *message = NULL;
158 char *msn_name = NULL;
156 159
157 if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { 160 if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
158 if (!purple_account_get_remember_password(account)) 161 if (!purple_account_get_remember_password(account))
159 purple_account_set_password(account, NULL); 162 purple_account_set_password(account, NULL);
160 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NAME_IN_USE, 163 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NAME_IN_USE,
233 case 19: /* custom message */ 236 case 19: /* custom message */
234 if (f) 237 if (f)
235 message = pair->value; 238 message = pair->value;
236 break; 239 break;
237 case 11: /* this is the buddy's session id */ 240 case 11: /* this is the buddy's session id */
241 if (f)
242 f->session_id = strtol(pair->value, NULL, 10);
238 break; 243 break;
239 case 17: /* in chat? */ 244 case 17: /* in chat? */
240 break; 245 break;
241 case 47: /* is custom status away or not? 2=idle*/ 246 case 47: /* is custom status away or not? 2=idle*/
242 if (!f) 247 if (!f)
348 break; 353 break;
349 case 244: /* client version number. Yahoo Client Detection */ 354 case 244: /* client version number. Yahoo Client Detection */
350 if(f && strtol(pair->value, NULL, 10)) 355 if(f && strtol(pair->value, NULL, 10))
351 f->version_id = strtol(pair->value, NULL, 10); 356 f->version_id = strtol(pair->value, NULL, 10);
352 break; 357 break;
353 358 case 241: /* protocol buddy belongs to */
359 if(strtol(pair->value, NULL, 10) == 2) {
360 msn_name = g_strconcat("msn/", name, NULL);
361 name = msn_name;
362 }
363 break;
354 default: 364 default:
355 purple_debug_warning("yahoo", 365 purple_debug_warning("yahoo",
356 "Unknown status key %d\n", pair->key); 366 "Unknown status key %d\n", pair->key);
357 break; 367 break;
358 } 368 }
470 480
471 PurpleAccount *account = purple_connection_get_account(gc); 481 PurpleAccount *account = purple_connection_get_account(gc);
472 struct yahoo_data *yd = gc->proto_data; 482 struct yahoo_data *yd = gc->proto_data;
473 GHashTable *ht; 483 GHashTable *ht;
474 char *norm_bud = NULL; 484 char *norm_bud = NULL;
485 char *temp = NULL;
475 YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */ 486 YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */
476 /* But what if you had no friends? */ 487 /* But what if you had no friends? */
477 PurpleBuddy *b; 488 PurpleBuddy *b;
478 PurpleGroup *g; 489 PurpleGroup *g;
490 int protocol = 0;
491 int stealth = 0;
479 492
480 493
481 ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free); 494 ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free);
482 495
483 while (l) { 496 while (l) {
497 yd->current_list15_grp = NULL; 510 yd->current_list15_grp = NULL;
498 } 511 }
499 512
500 break; 513 break;
501 case 301: /* This is 319 before all s/n's in a group after the first. It is followed by an identical 300. */ 514 case 301: /* This is 319 before all s/n's in a group after the first. It is followed by an identical 300. */
502 break; 515 if(temp != NULL) {
503 case 300: /* This is 318 before a group, 319 before any s/n in a group, and 320 before any ignored s/n. */ 516 if(protocol == 2)
504 break; 517 norm_bud = g_strconcat("msn/", temp, NULL);
505 case 65: /* This is the group */ 518 else
506 g_free(yd->current_list15_grp); 519 norm_bud = g_strdup(temp);
507 yd->current_list15_grp = yahoo_string_decode(gc, pair->value, FALSE); 520
508 break; 521 if (yd->current_list15_grp) {
509 case 7: /* buddy's s/n */ 522 /* This buddy is in a group */
510 g_free(norm_bud); 523 f = yahoo_friend_find_or_new(gc, norm_bud);
511 norm_bud = g_strdup(purple_normalize(account, pair->value)); 524 if (!(b = purple_find_buddy(account, norm_bud))) {
512 525 if (!(g = purple_find_group(yd->current_list15_grp))) {
513 if (yd->current_list15_grp) { 526 g = purple_group_new(yd->current_list15_grp);
514 /* This buddy is in a group */ 527 purple_blist_add_group(g, NULL);
515 f = yahoo_friend_find_or_new(gc, norm_bud);
516 if (!(b = purple_find_buddy(account, norm_bud))) {
517 if (!(g = purple_find_group(yd->current_list15_grp))) {
518 g = purple_group_new(yd->current_list15_grp);
519 purple_blist_add_group(g, NULL);
520 } 528 }
521 b = purple_buddy_new(account, norm_bud, NULL); 529 b = purple_buddy_new(account, norm_bud, NULL);
522 purple_blist_add_buddy(b, NULL, g, NULL); 530 purple_blist_add_buddy(b, NULL, g, NULL);
523 } 531 }
524 yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp); 532 yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp);
525 533 if(protocol != 0) {
526 } else { 534 f->protocol = protocol;
527 /* This buddy is on the ignore list (and therefore in no group) */ 535 purple_debug_info("yahoo", "Setting protocol to %d\n", f->protocol);
528 purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n", 536 }
529 account->username, norm_bud); 537 if(stealth == 2)
530 purple_privacy_deny_add(account, norm_bud, 1); 538 f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
539
540 /* set p2p status not connected and no p2p packet sent */
541 if(protocol == 0) {
542 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
543 f->p2p_packet_sent = 0;
544 } else
545 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT);
546 } else {
547 /* This buddy is on the ignore list (and therefore in no group) */
548 purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n",account->username, norm_bud);
549 purple_privacy_deny_add(account, norm_bud, 1);
550 }
551
552 protocol = 0;
553 stealth = 0;
554 norm_bud = NULL;
555 temp = NULL;
531 } 556 }
532 break; 557 break;
558 case 300: /* This is 318 before a group, 319 before any s/n in a group, and 320 before any ignored s/n. */
559 break;
560 case 65: /* This is the group */
561 g_free(yd->current_list15_grp);
562 yd->current_list15_grp = yahoo_string_decode(gc, pair->value, FALSE);
563 break;
564 case 7: /* buddy's s/n */
565 temp = g_strdup(purple_normalize(account, pair->value));
566 break;
533 case 241: /* another protocol user */ 567 case 241: /* another protocol user */
534 if (f) { 568 protocol = strtol(pair->value, NULL, 10);
535 f->protocol = strtol(pair->value, NULL, 10);
536 purple_debug_info("yahoo", "Setting protocol to %d\n", f->protocol);
537 }
538 break; 569 break;
539 case 59: /* somebody told cookies come here too, but im not sure */ 570 case 59: /* somebody told cookies come here too, but im not sure */
540 yahoo_process_cookie(yd, pair->value); 571 yahoo_process_cookie(yd, pair->value);
541 break; 572 break;
542 case 317: /* Stealth Setting */ 573 case 317: /* Stealth Setting */
543 if (f && (strtol(pair->value, NULL, 10) == 2)) { 574 stealth = strtol(pair->value, NULL, 10);
544 f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
545 }
546 break; 575 break;
547 /* case 242: */ /* this seems related to 241 */ 576 /* case 242: */ /* this seems related to 241 */
548 /* break; */ 577 /* break; */
549 } 578 }
550 } 579 }
551 580
552 g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL); 581 g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL);
553 g_hash_table_destroy(ht); 582 g_hash_table_destroy(ht);
554 g_free(norm_bud); 583 g_free(norm_bud);
584 g_free(temp);
555 } 585 }
556 586
557 static void yahoo_process_list(PurpleConnection *gc, struct yahoo_packet *pkt) 587 static void yahoo_process_list(PurpleConnection *gc, struct yahoo_packet *pkt)
558 { 588 {
559 GSList *l = pkt->hash; 589 GSList *l = pkt->hash;
634 purple_blist_add_buddy(b, NULL, g, NULL); 664 purple_blist_add_buddy(b, NULL, g, NULL);
635 export = TRUE; 665 export = TRUE;
636 } 666 }
637 667
638 yahoo_do_group_check(account, ht, norm_bud, grp); 668 yahoo_do_group_check(account, ht, norm_bud, grp);
669 /* set p2p status not connected and no p2p packet sent */
670 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
671 f->p2p_packet_sent = 0;
672
639 g_free(norm_bud); 673 g_free(norm_bud);
640 } 674 }
641 g_strfreev(buddies); 675 g_strfreev(buddies);
642 g_strfreev(split); 676 g_strfreev(split);
643 g_free(grp); 677 g_free(grp);
690 } 724 }
691 /* Now that we've got the list, request aliases */ 725 /* Now that we've got the list, request aliases */
692 yahoo_fetch_aliases(gc); 726 yahoo_fetch_aliases(gc);
693 } 727 }
694 728
695 static void yahoo_process_notify(PurpleConnection *gc, struct yahoo_packet *pkt) 729 /* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
730 static void yahoo_process_notify(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type)
696 { 731 {
697 PurpleAccount *account; 732 PurpleAccount *account;
698 char *msg = NULL; 733 char *msg = NULL;
699 char *from = NULL; 734 char *from = NULL;
700 char *stat = NULL; 735 char *stat = NULL;
701 char *game = NULL; 736 char *game = NULL;
702 YahooFriend *f = NULL; 737 YahooFriend *f = NULL;
703 GSList *l = pkt->hash; 738 GSList *l = pkt->hash;
739 gint val_11 = 0;
740 struct yahoo_data *yd = gc->proto_data;
741 gboolean msn = FALSE;
742 char *msn_from = NULL;
704 743
705 account = purple_connection_get_account(gc); 744 account = purple_connection_get_account(gc);
706 745
707 while (l) { 746 while (l) {
708 struct yahoo_pair *pair = l->data; 747 struct yahoo_pair *pair = l->data;
709 if (pair->key == 4) 748 if (pair->key == 4 || pair->key == 1)
710 from = pair->value; 749 from = pair->value;
711 if (pair->key == 49) 750 if (pair->key == 49)
712 msg = pair->value; 751 msg = pair->value;
713 if (pair->key == 13) 752 if (pair->key == 13)
714 stat = pair->value; 753 stat = pair->value;
715 if (pair->key == 14) 754 if (pair->key == 14)
716 game = pair->value; 755 game = pair->value;
756 if (pair->key == 11)
757 val_11 = strtol(pair->value, NULL, 10);
758 if (pair->key == 241)
759 if(strtol(pair->value, NULL, 10) == 2)
760 msn = TRUE;
717 l = l->next; 761 l = l->next;
718 } 762 }
719 763
720 if (!from || !msg) 764 if (!from || !msg)
721 return; 765 return;
766
767 /* disconnect the peer if connected through p2p and sends wrong value for session id */
768 if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) {
769 purple_debug_warning("yahoo","p2p: %s sent us notify with wrong session id. Disconnecting p2p connection to peer\n", from);
770 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
771 g_hash_table_remove(yd->peers, from);
772 return;
773 }
774
775 if(msn)
776 msn_from = g_strconcat("msn/", from, NULL);
722 777
723 if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING")) 778 if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING"))
724 && (purple_privacy_check(account, from))) 779 && (purple_privacy_check(account, from)))
725 { 780 {
726 if (*stat == '1') 781 if(msn) {
727 serv_got_typing(gc, from, 0, PURPLE_TYPING); 782 if (*stat == '1')
728 else 783 serv_got_typing(gc, msn_from, 0, PURPLE_TYPING);
729 serv_got_typing_stopped(gc, from); 784 else
785 serv_got_typing_stopped(gc, msn_from);
786 }
787 else {
788 if (*stat == '1')
789 serv_got_typing(gc, from, 0, PURPLE_TYPING);
790 else
791 serv_got_typing_stopped(gc, from);
792 }
730 } else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) { 793 } else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) {
731 PurpleBuddy *bud = purple_find_buddy(account, from); 794 PurpleBuddy *bud = purple_find_buddy(account, from);
732 795
733 if (!bud) { 796 if (!bud) {
734 purple_debug(PURPLE_DEBUG_WARNING, "yahoo", 797 purple_debug(PURPLE_DEBUG_WARNING, "yahoo",
752 char *buf = g_strdup_printf(_("%s has sent you a webcam invite, which is not yet supported."), from); 815 char *buf = g_strdup_printf(_("%s has sent you a webcam invite, which is not yet supported."), from);
753 purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NOTIFY, time(NULL)); 816 purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NOTIFY, time(NULL));
754 g_free(buf); 817 g_free(buf);
755 } 818 }
756 819
820 g_free(msn_from);
757 } 821 }
758 822
759 823
760 struct _yahoo_im { 824 struct _yahoo_im {
761 char *from; 825 char *from;
763 int utf8; 827 int utf8;
764 int buddy_icon; 828 int buddy_icon;
765 char *msg; 829 char *msg;
766 }; 830 };
767 831
768 static void yahoo_process_message(PurpleConnection *gc, struct yahoo_packet *pkt) 832 static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt)
833 {
834 PurpleAccount *account;
835 GSList *l = pkt->hash;
836 struct _yahoo_im *sms = NULL;
837 struct yahoo_data *yd;
838 char *server_msg = NULL;
839 char *m;
840
841 yd = gc->proto_data;
842 account = purple_connection_get_account(gc);
843
844 while (l != NULL) {
845 struct yahoo_pair *pair = l->data;
846 if (pair->key == 4) {
847 sms = g_new0(struct _yahoo_im, 1);
848 sms->from = g_strdup_printf("+%s", pair->value);
849 sms->time = time(NULL);
850 sms->utf8 = TRUE;
851 }
852 if (pair->key == 14) {
853 if (sms)
854 sms->msg = pair->value;
855 }
856 if (pair->key == 68)
857 if(sms)
858 g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value));
859 if (pair->key == 16)
860 server_msg = pair->value;
861 l = l->next;
862 }
863
864 if( (pkt->status == -1) || (pkt->status == YAHOO_STATUS_DISCONNECTED) ) {
865 if (server_msg) {
866 PurpleConversation *c;
867 c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms->from, account);
868 if (c == NULL)
869 c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sms->from);
870 purple_conversation_write(c, NULL, server_msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
871 }
872 else
873 purple_notify_error(gc, NULL, _("Your SMS was not delivered"), NULL);
874
875 g_free(sms->from);
876 g_free(sms);
877 return ;
878 }
879
880 if (!sms->from || !sms->msg) {
881 g_free(sms);
882 return;
883 }
884
885 m = yahoo_string_decode(gc, sms->msg, sms->utf8);
886 serv_got_im(gc, sms->from, m, 0, sms->time);
887
888 g_free(m);
889 g_free(sms->from);
890 g_free(sms);
891 }
892
893 /* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
894 static void yahoo_process_message(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type)
769 { 895 {
770 PurpleAccount *account; 896 PurpleAccount *account;
771 struct yahoo_data *yd = gc->proto_data; 897 struct yahoo_data *yd = gc->proto_data;
772 GSList *l = pkt->hash; 898 GSList *l = pkt->hash;
773 GSList *list = NULL; 899 GSList *list = NULL;
774 struct _yahoo_im *im = NULL; 900 struct _yahoo_im *im = NULL;
775 const char *imv = NULL; 901 const char *imv = NULL;
902 gint val_11 = 0;
903 gboolean msn = FALSE;
904 char *msn_from = NULL;
776 905
777 account = purple_connection_get_account(gc); 906 account = purple_connection_get_account(gc);
778 907
779 if (pkt->status <= 1 || pkt->status == 5) { 908 if (pkt->status <= 1 || pkt->status == 5 || pkt->status == YAHOO_STATUS_OFFLINE) {
909 /* messages are received with status YAHOO_STATUS_OFFLINE in case of p2p */
780 while (l != NULL) { 910 while (l != NULL) {
781 struct yahoo_pair *pair = l->data; 911 struct yahoo_pair *pair = l->data;
782 if (pair->key == 4) { 912 if (pair->key == 4 || pair->key == 1) {
783 im = g_new0(struct _yahoo_im, 1); 913 im = g_new0(struct _yahoo_im, 1);
784 list = g_slist_append(list, im); 914 list = g_slist_append(list, im);
785 im->from = pair->value; 915 im->from = pair->value;
786 im->time = time(NULL); 916 im->time = time(NULL);
787 im->utf8 = TRUE; 917 im->utf8 = TRUE;
797 im->buddy_icon = strtol(pair->value, NULL, 10); 927 im->buddy_icon = strtol(pair->value, NULL, 10);
798 if (pair->key == 14) { 928 if (pair->key == 14) {
799 if (im) 929 if (im)
800 im->msg = pair->value; 930 im->msg = pair->value;
801 } 931 }
932 if (pair->key == 241) {
933 if(strtol(pair->value, NULL, 10) == 2)
934 msn = TRUE;
935 }
936 /* peer session id */
937 if (pair->key == 11) {
938 if (im)
939 val_11 = strtol(pair->value, NULL, 10);
940 }
802 /* IMV key */ 941 /* IMV key */
803 if (pair->key == 63) 942 if (pair->key == 63)
804 { 943 {
805 imv = pair->value; 944 imv = pair->value;
806 } 945 }
807 l = l->next; 946 l = l->next;
808 } 947 }
809 } else if (pkt->status == 2) { 948 } else if (pkt->status == 2) {
810 purple_notify_error(gc, NULL, 949 purple_notify_error(gc, NULL,
811 _("Your Yahoo! message did not get sent."), NULL); 950 _("Your Yahoo! message did not get sent."), NULL);
951 }
952
953 if(msn)
954 msn_from = g_strconcat("msn/", im->from, NULL);
955
956 /* disconnect the peer if connected through p2p and sends wrong value for session id */
957 if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) {
958 purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im->from);
959 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
960 g_hash_table_remove(yd->peers, im->from);
961 return;
812 } 962 }
813 963
814 /** TODO: It seems that this check should be per IM, not global */ 964 /** TODO: It seems that this check should be per IM, not global */
815 /* Check for the Doodle IMV */ 965 /* Check for the Doodle IMV */
816 if (im != NULL && imv!= NULL && im->from != NULL) 966 if (im != NULL && imv!= NULL && im->from != NULL)
845 } 995 }
846 996
847 for (l = list; l; l = l->next) { 997 for (l = list; l; l = l->next) {
848 YahooFriend *f; 998 YahooFriend *f;
849 char *m, *m2; 999 char *m, *m2;
1000 PurpleConversation *c;
850 im = l->data; 1001 im = l->data;
851 1002
852 if (!im->from || !im->msg) { 1003 if (!im->from || !im->msg) {
853 g_free(im); 1004 g_free(im);
854 continue; 1005 continue;
867 m2 = purple_strreplace(m, "\r\n", "\n"); 1018 m2 = purple_strreplace(m, "\r\n", "\n");
868 g_free(m); 1019 g_free(m);
869 m = m2; 1020 m = m2;
870 purple_util_chrreplace(m, '\r', '\n'); 1021 purple_util_chrreplace(m, '\r', '\n');
871 1022
1023 c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->from, account);
1024 if ((c == NULL) && msn)
1025 c=purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, msn_from, account);
1026
872 if (!strcmp(m, "<ding>")) { 1027 if (!strcmp(m, "<ding>")) {
873 PurpleConversation *c;
874 char *username; 1028 char *username;
875 1029
876 c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->from, account); 1030 if(c == NULL) {
877 if (c == NULL) 1031 if(msn)
878 c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, im->from); 1032 c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, msn_from);
879 1033 else
880 username = g_markup_escape_text(im->from, -1); 1034 c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, im->from);
1035 }
1036 if(msn)
1037 username = g_markup_escape_text(msn_from, -1);
1038 else
1039 username = g_markup_escape_text(im->from, -1);
1040
881 purple_prpl_got_attention(gc, username, YAHOO_BUZZ); 1041 purple_prpl_got_attention(gc, username, YAHOO_BUZZ);
882 g_free(username); 1042 g_free(username);
883 g_free(m); 1043 g_free(m);
884 g_free(im); 1044 g_free(im);
1045 g_free(msn_from);
885 continue; 1046 continue;
886 } 1047 }
887 1048
888 m2 = yahoo_codes_to_html(m); 1049 m2 = yahoo_codes_to_html(m);
889 g_free(m); 1050 g_free(m);
890 serv_got_im(gc, im->from, m2, 0, im->time); 1051
1052 if(msn)
1053 serv_got_im(gc, msn_from, m2, 0, im->time);
1054 else
1055 serv_got_im(gc, im->from, m2, 0, im->time);
1056
891 g_free(m2); 1057 g_free(m2);
892 1058
893 if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) { 1059 /* laters : implement buddy icon for msn friends */
894 if (yahoo_friend_get_buddy_icon_need_request(f)) { 1060 if(!msn) {
895 yahoo_send_picture_request(gc, im->from); 1061 if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) {
896 yahoo_friend_set_buddy_icon_need_request(f, FALSE); 1062 if (yahoo_friend_get_buddy_icon_need_request(f)) {
1063 yahoo_send_picture_request(gc, im->from);
1064 yahoo_friend_set_buddy_icon_need_request(f, FALSE);
1065 }
897 } 1066 }
898 } 1067 }
899 1068
900 g_free(im); 1069 g_free(im);
1070 g_free(msn_from);
901 } 1071 }
902 g_slist_free(list); 1072 g_slist_free(list);
903 } 1073 }
904 1074
905 static void yahoo_process_sysmessage(PurpleConnection *gc, struct yahoo_packet *pkt) 1075 static void yahoo_process_sysmessage(PurpleConnection *gc, struct yahoo_packet *pkt)
1028 1198
1029 static void yahoo_buddy_auth_req_15(PurpleConnection *gc, struct yahoo_packet *pkt) { 1199 static void yahoo_buddy_auth_req_15(PurpleConnection *gc, struct yahoo_packet *pkt) {
1030 PurpleAccount *account; 1200 PurpleAccount *account;
1031 GSList *l = pkt->hash; 1201 GSList *l = pkt->hash;
1032 const char *msg = NULL; 1202 const char *msg = NULL;
1203 int protocol = 0;
1033 1204
1034 account = purple_connection_get_account(gc); 1205 account = purple_connection_get_account(gc);
1035 1206
1036 /* Buddy authorized/declined our addition */ 1207 /* Buddy authorized/declined our addition */
1037 if (pkt->status == 1) { 1208 if (pkt->status == 1) {
1038 const char *who = NULL; 1209 char *temp = NULL;
1210 char *who = NULL;
1039 int response = 0; 1211 int response = 0;
1040 1212
1041 while (l) { 1213 while (l) {
1042 struct yahoo_pair *pair = l->data; 1214 struct yahoo_pair *pair = l->data;
1043 1215
1044 switch (pair->key) { 1216 switch (pair->key) {
1045 case 4: 1217 case 4:
1046 who = pair->value; 1218 temp = pair->value;
1047 break; 1219 break;
1048 case 13: 1220 case 13:
1049 response = strtol(pair->value, NULL, 10); 1221 response = strtol(pair->value, NULL, 10);
1050 break; 1222 break;
1051 case 14: 1223 case 14:
1052 msg = pair->value; 1224 msg = pair->value;
1053 break; 1225 break;
1226 case 241:
1227 protocol = strtol(pair->value, NULL, 10);
1228 break;
1054 } 1229 }
1055 l = l->next; 1230 l = l->next;
1056 } 1231 }
1232
1233 if(protocol == 0)
1234 who = g_strdup(temp);
1235 else if(protocol == 2)
1236 who = g_strconcat("msn/", temp, NULL);
1057 1237
1058 if (response == 1) /* Authorized */ 1238 if (response == 1) /* Authorized */
1059 purple_debug_info("yahoo", "Received authorization from buddy '%s'.\n", who ? who : "(Unknown Buddy)"); 1239 purple_debug_info("yahoo", "Received authorization from buddy '%s'.\n", who ? who : "(Unknown Buddy)");
1060 else if (response == 2) { /* Declined */ 1240 else if (response == 2) { /* Declined */
1061 purple_debug_info("yahoo", "Received authorization decline from buddy '%s'.\n", who ? who : "(Unknown Buddy)"); 1241 purple_debug_info("yahoo", "Received authorization decline from buddy '%s'.\n", who ? who : "(Unknown Buddy)");
1062 yahoo_buddy_denied_our_add(gc, who, msg); 1242 yahoo_buddy_denied_our_add(gc, who, msg);
1063 } else 1243 } else
1064 purple_debug_error("yahoo", "Received unknown authorization response of %d from buddy '%s'.\n", response, who ? who : "(Unknown Buddy)"); 1244 purple_debug_error("yahoo", "Received unknown authorization response of %d from buddy '%s'.\n", response, who ? who : "(Unknown Buddy)");
1065 1245 g_free(who);
1066 } 1246 }
1067 /* Buddy requested authorization to add us. */ 1247 /* Buddy requested authorization to add us. */
1068 else if (pkt->status == 3) { 1248 else if (pkt->status == 3) {
1069 struct yahoo_add_request *add_req; 1249 struct yahoo_add_request *add_req;
1070 const char *firstname = NULL, *lastname = NULL; 1250 const char *firstname = NULL, *lastname = NULL;
1251 char *temp = NULL;
1071 1252
1072 add_req = g_new0(struct yahoo_add_request, 1); 1253 add_req = g_new0(struct yahoo_add_request, 1);
1073 add_req->gc = gc; 1254 add_req->gc = gc;
1074 1255
1075 while (l) { 1256 while (l) {
1076 struct yahoo_pair *pair = l->data; 1257 struct yahoo_pair *pair = l->data;
1077 1258
1078 switch (pair->key) { 1259 switch (pair->key) {
1079 case 4: 1260 case 4:
1261 temp = pair->value;
1080 add_req->who = g_strdup(pair->value); 1262 add_req->who = g_strdup(pair->value);
1081 break; 1263 break;
1082 case 5: 1264 case 5:
1083 add_req->id = g_strdup(pair->value); 1265 add_req->id = g_strdup(pair->value);
1084 break; 1266 break;
1096 break; 1278 break;
1097 1279
1098 } 1280 }
1099 l = l->next; 1281 l = l->next;
1100 } 1282 }
1283 if(add_req->protocol == 2)
1284 add_req->who = g_strconcat("msn/", temp, NULL);
1285 else
1286 add_req->who = g_strdup(temp);
1101 1287
1102 if (add_req->id && add_req->who) { 1288 if (add_req->id && add_req->who) {
1103 char *alias = NULL, *dec_msg = NULL; 1289 char *alias = NULL, *dec_msg = NULL;
1104 1290
1105 if (!purple_privacy_check(account, add_req->who)) 1291 if (!purple_privacy_check(account, add_req->who))
2197 2383
2198 static void yahoo_process_addbuddy(PurpleConnection *gc, struct yahoo_packet *pkt) 2384 static void yahoo_process_addbuddy(PurpleConnection *gc, struct yahoo_packet *pkt)
2199 { 2385 {
2200 int err = 0; 2386 int err = 0;
2201 char *who = NULL; 2387 char *who = NULL;
2388 char *temp = NULL;
2202 char *group = NULL; 2389 char *group = NULL;
2203 char *decoded_group; 2390 char *decoded_group;
2204 char *buf; 2391 char *buf;
2205 YahooFriend *f; 2392 YahooFriend *f;
2206 GSList *l = pkt->hash; 2393 GSList *l = pkt->hash;
2394 struct yahoo_data *yd = gc->proto_data;
2395 int protocol = 0;
2396 gboolean msn = FALSE;
2207 2397
2208 while (l) { 2398 while (l) {
2209 struct yahoo_pair *pair = l->data; 2399 struct yahoo_pair *pair = l->data;
2210 2400
2211 switch (pair->key) { 2401 switch (pair->key) {
2212 case 66: 2402 case 66:
2213 err = strtol(pair->value, NULL, 10); 2403 err = strtol(pair->value, NULL, 10);
2214 break; 2404 break;
2215 case 7: 2405 case 7:
2216 who = pair->value; 2406 temp = pair->value;
2217 break; 2407 break;
2218 case 65: 2408 case 65:
2219 group = pair->value; 2409 group = pair->value;
2220 break; 2410 break;
2411 case 241:
2412 protocol = strtol(pair->value, NULL, 10);
2413 if(protocol == 2)
2414 msn = TRUE;
2415 break;
2221 } 2416 }
2222 2417
2223 l = l->next; 2418 l = l->next;
2224 } 2419 }
2225 2420
2226 if (!who) 2421 if (!temp)
2227 return; 2422 return;
2228 if (!group) 2423 if (!group)
2229 group = ""; 2424 group = "";
2425
2426 if(msn)
2427 who = g_strconcat("msn/", temp, NULL);
2428 else
2429 who = g_strdup(temp);
2230 2430
2231 if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */ 2431 if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */
2232 f = yahoo_friend_find_or_new(gc, who); 2432 f = yahoo_friend_find_or_new(gc, who);
2233 yahoo_update_status(gc, who, f); 2433 yahoo_update_status(gc, who, f);
2434 if(protocol)
2435 f->protocol = protocol;
2436
2437 if( !g_hash_table_lookup(yd->peers, who) ) {
2438 /* we are not connected as client, so set friend to not connected */
2439 if(msn)
2440 yahoo_friend_set_p2p_status(f,YAHOO_P2PSTATUS_DO_NOT_CONNECT);
2441 else {
2442 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
2443 f->p2p_packet_sent = 0;
2444 }
2445 }
2446 else /* we are already connected. set friend to YAHOO_P2PSTATUS_WE_ARE_CLIENT */
2447 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT);
2234 return; 2448 return;
2235 } 2449 }
2236 2450
2237 decoded_group = yahoo_string_decode(gc, group, FALSE); 2451 decoded_group = yahoo_string_decode(gc, group, FALSE);
2238 buf = g_strdup_printf(_("Could not add buddy %s to group %s to the server list on account %s."), 2452 buf = g_strdup_printf(_("Could not add buddy %s to group %s to the server list on account %s."),
2239 who, decoded_group, purple_connection_get_display_name(gc)); 2453 who, decoded_group, purple_connection_get_display_name(gc));
2240 if (!purple_conv_present_error(who, purple_connection_get_account(gc), buf)) 2454 if (!purple_conv_present_error(who, purple_connection_get_account(gc), buf))
2241 purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf); 2455 purple_notify_error(gc, NULL, _("Could not add buddy to server list"), buf);
2242 g_free(buf); 2456 g_free(buf);
2243 g_free(decoded_group); 2457 g_free(decoded_group);
2458 g_free(who);
2459 }
2460
2461 /* write pkt to the source */
2462 static void yahoo_p2p_write_pkt(gint source, struct yahoo_packet *pkt)
2463 {
2464 size_t pkt_len;
2465 guchar *raw_packet;
2466
2467 /*build the raw packet and send it to the host*/
2468 pkt_len = yahoo_packet_build(pkt, 0, 0, 0, &raw_packet);
2469 if(write(source, raw_packet, pkt_len) != pkt_len)
2470 purple_debug_warning("yahoo","p2p: couldn't write to the source\n");
2471 g_free(raw_packet);
2472 }
2473
2474 static void yahoo_p2p_keepalive_cb(gpointer key, gpointer value, gpointer user_data)
2475 {
2476 struct yahoo_p2p_data *p2p_data = value;
2477 PurpleConnection *gc = user_data;
2478 struct yahoo_packet *pkt_to_send;
2479 PurpleAccount *account;
2480 struct yahoo_data *yd = gc->proto_data;
2481
2482 account = purple_connection_get_account(gc);
2483
2484 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
2485 yahoo_packet_hash(pkt_to_send, "ssisi",
2486 4, purple_normalize(account, purple_account_get_username(account)),
2487 5, p2p_data->host_username,
2488 241, 0, /* Protocol identifier */
2489 49, "PEERTOPEER",
2490 13, 7);
2491 yahoo_p2p_write_pkt(p2p_data->source, pkt_to_send);
2492
2493 yahoo_packet_free(pkt_to_send);
2494 }
2495
2496 static gboolean yahoo_p2p_keepalive(gpointer data)
2497 {
2498 PurpleConnection *gc = data;
2499 struct yahoo_data *yd = gc->proto_data;
2500
2501 g_hash_table_foreach(yd->peers, yahoo_p2p_keepalive_cb, gc);
2502
2503 return TRUE;
2504 }
2505
2506 /* destroy p2p_data associated with a peer and close p2p connection.
2507 * g_hash_table_remove() calls this function to destroy p2p_data associated with the peer,
2508 * call g_hash_table_remove() instead of this fucntion if peer has an entry in the table */
2509 static void yahoo_p2p_disconnect_destroy_data(gpointer data)
2510 {
2511 struct yahoo_p2p_data *p2p_data;
2512 YahooFriend *f;
2513
2514 if(!(p2p_data = data))
2515 return ;
2516
2517 /* If friend, set him not connected */
2518 f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username);
2519 if (f)
2520 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
2521
2522 if(p2p_data->source >= 0)
2523 close(p2p_data->source);
2524 purple_input_remove(p2p_data->input_event);
2525 g_free(p2p_data->host_ip);
2526 g_free(p2p_data->host_username);
2527 g_free(p2p_data);
2528 }
2529
2530 /* exchange of initial p2pfilexfer packets, service type YAHOO_SERVICE_P2PFILEXFER */
2531 static void yahoo_p2p_process_p2pfilexfer(gpointer data, gint source, struct yahoo_packet *pkt)
2532 {
2533 struct yahoo_p2p_data *p2p_data;
2534 char *who = NULL;
2535 GSList *l = pkt->hash;
2536 struct yahoo_packet *pkt_to_send;
2537 PurpleAccount *account;
2538 int val_13_to_send = 0;
2539 struct yahoo_data *yd;
2540 YahooFriend *f;
2541
2542 if(!(p2p_data = data))
2543 return ;
2544
2545 yd = p2p_data->gc->proto_data;
2546
2547 /* lets see whats in the packet */
2548 while (l) {
2549 struct yahoo_pair *pair = l->data;
2550
2551 switch (pair->key) {
2552 case 4:
2553 who = pair->value;
2554 if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) {
2555 /* from whom are we receiving the packets ?? */
2556 purple_debug_warning("yahoo","p2p: received data from wrong user\n");
2557 return;
2558 }
2559 break;
2560 case 13:
2561 p2p_data->val_13 = strtol(pair->value, NULL, 10); /* Value should be 5-7 */
2562 break;
2563 /* case 5, 49 look laters, no use right now */
2564 }
2565 l = l->next;
2566 }
2567
2568 account = purple_connection_get_account(p2p_data->gc);
2569
2570 /* key_13: sort of a counter.
2571 * WHEN WE ARE CLIENT: yahoo server sends val_13 = 0, we send to peer val_13 = 1, receive back val_13 = 5,
2572 * we send val_13=6, receive val_13=7, we send val_13=7, HALT. Keep sending val_13 = 7 as keep alive.
2573 * WHEN WE ARE SERVER: we send val_13 = 0 to yahoo server, peer sends us val_13 = 1, we send val_13 = 5,
2574 * receive val_13 = 6, send val_13 = 7, receive val_13 = 7. HALT. Keep sending val_13 = 7 as keep alive. */
2575
2576 switch(p2p_data->val_13) {
2577 case 1 : val_13_to_send = 5; break;
2578 case 5 : val_13_to_send = 6; break;
2579 case 6 : val_13_to_send = 7; break;
2580 case 7 : if( g_hash_table_lookup(yd->peers, p2p_data->host_username) )
2581 return;
2582 val_13_to_send = 7; break;
2583 default: purple_debug_warning("yahoo","p2p:Unknown value for key 13\n");
2584 return;
2585 }
2586
2587 /* Build the yahoo packet */
2588 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
2589 yahoo_packet_hash(pkt_to_send, "ssisi",
2590 4, purple_normalize(account, purple_account_get_username(account)),
2591 5, p2p_data->host_username,
2592 241, 0, /* Protocol identifier */
2593 49, "PEERTOPEER",
2594 13, val_13_to_send);
2595
2596 /* build the raw packet and send it to the host */
2597 yahoo_p2p_write_pkt(source, pkt_to_send);
2598 yahoo_packet_free(pkt_to_send);
2599
2600 if( val_13_to_send == 7 )
2601 if( !g_hash_table_lookup(yd->peers, p2p_data->host_username) ) {
2602 g_hash_table_insert(yd->peers, g_strdup(p2p_data->host_username), p2p_data);
2603 /* If the peer is a friend, set him connected */
2604 f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username);
2605 if (f) {
2606 if(p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER) {
2607 p2p_data->session_id = f->session_id;
2608 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_SERVER);
2609 }
2610 else
2611 yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT);
2612 }
2613 }
2614 }
2615
2616 /* callback function associated with receiving of data, not considering receipt of multiple YMSG packets in a single TCP packet */
2617 static void yahoo_p2p_read_pkt_cb(gpointer data, gint source, PurpleInputCondition cond)
2618 {
2619 guchar buf[1024]; /* is it safe to assume a fixed array length of 1024 ?? */
2620 int len;
2621 int pos = 0;
2622 int pktlen;
2623 struct yahoo_packet *pkt;
2624 guchar *start = NULL;
2625 struct yahoo_p2p_data *p2p_data;
2626 struct yahoo_data *yd;
2627
2628 if(!(p2p_data = data))
2629 return ;
2630 yd = p2p_data->gc->proto_data;
2631
2632 len = read(source, buf, sizeof(buf));
2633 if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
2634 return ; /* No Worries*/
2635 else if (len <= 0)
2636 {
2637 purple_debug_warning("yahoo","p2p: Error in connection, or host disconnected\n");
2638 /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
2639 if( g_hash_table_lookup(yd->peers, p2p_data->host_username) )
2640 g_hash_table_remove(yd->peers,p2p_data->host_username);
2641 else
2642 yahoo_p2p_disconnect_destroy_data(data);
2643 return;
2644 }
2645
2646 if(len < YAHOO_PACKET_HDRLEN)
2647 return;
2648
2649 if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) {
2650 /* Not a YMSG packet */
2651 purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
2652
2653 start = memchr(buf + 1, 'Y', len - 1);
2654 if(start) {
2655 g_memmove(buf, start, len - (start - buf));
2656 len -= start - buf;
2657 } else {
2658 g_free(buf);
2659 return;
2660 }
2661 }
2662
2663 pos += 4; /* YMSG */
2664 pos += 2;
2665 pos += 2;
2666
2667 pktlen = yahoo_get16(buf + pos); pos += 2;
2668 purple_debug(PURPLE_DEBUG_MISC, "yahoo", "p2p: %d bytes to read\n", len);
2669
2670 pkt = yahoo_packet_new(0, 0, 0);
2671 pkt->service = yahoo_get16(buf + pos); pos += 2;
2672 pkt->status = yahoo_get32(buf + pos); pos += 4;
2673 pkt->id = yahoo_get32(buf + pos); pos += 4;
2674
2675 purple_debug(PURPLE_DEBUG_MISC, "yahoo", "p2p: Yahoo Service: 0x%02x Status: %d\n",pkt->service, pkt->status);
2676 yahoo_packet_read(pkt, buf + pos, pktlen);
2677
2678 /* packet processing */
2679 switch(pkt->service) {
2680 case YAHOO_SERVICE_P2PFILEXFER:
2681 yahoo_p2p_process_p2pfilexfer(data, source, pkt);
2682 break;
2683 case YAHOO_SERVICE_MESSAGE:
2684 yahoo_process_message(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P);
2685 break;
2686 case YAHOO_SERVICE_NOTIFY:
2687 yahoo_process_notify(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P);
2688 break;
2689 default:
2690 purple_debug_warning("yahoo","p2p: p2p service %d Unhandled\n",pkt->service);
2691 }
2692
2693 yahoo_packet_free(pkt);
2694 }
2695
2696 static void yahoo_p2p_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond)
2697 {
2698 int acceptfd;
2699 struct yahoo_p2p_data *p2p_data;
2700 struct yahoo_data *yd;
2701
2702 if(!(p2p_data = data))
2703 return ;
2704 yd = p2p_data->gc->proto_data;
2705
2706 acceptfd = accept(source, NULL, 0);
2707 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
2708 return;
2709 else if(acceptfd == -1) {
2710 purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno));
2711 yahoo_p2p_disconnect_destroy_data(data);
2712 return;
2713 }
2714
2715 /* remove timeout */
2716 purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle);
2717 yd->yahoo_p2p_server_timeout_handle = 0;
2718
2719 /* remove watcher and close p2p server */
2720 purple_input_remove(yd->yahoo_p2p_server_watcher);
2721 close(yd->yahoo_local_p2p_server_fd);
2722 yd->yahoo_local_p2p_server_fd = -1;
2723
2724 /* Add an Input Read event to the file descriptor */
2725 p2p_data->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data);
2726 p2p_data->source = acceptfd;
2727 }
2728
2729 static gboolean yahoo_cancel_p2p_server_listen_cb(gpointer data)
2730 {
2731 struct yahoo_p2p_data *p2p_data;
2732 struct yahoo_data *yd;
2733
2734 if(!(p2p_data = data))
2735 return FALSE;
2736
2737 yd = p2p_data->gc->proto_data;
2738
2739 purple_debug_warning("yahoo","yahoo p2p server timeout, peer failed to connect");
2740 yahoo_p2p_disconnect_destroy_data(data);
2741 purple_input_remove(yd->yahoo_p2p_server_watcher);
2742 yd->yahoo_p2p_server_watcher = 0;
2743 close(yd->yahoo_local_p2p_server_fd);
2744 yd->yahoo_local_p2p_server_fd = -1;
2745 yd->yahoo_p2p_server_timeout_handle = 0;
2746
2747 return FALSE;
2748 }
2749
2750 static void yahoo_p2p_server_listen_cb(int listenfd, gpointer data)
2751 {
2752 struct yahoo_p2p_data *p2p_data;
2753 struct yahoo_data *yd;
2754
2755 if(!(p2p_data = data))
2756 return ;
2757
2758 if(listenfd == -1) {
2759 purple_debug_warning("yahoo","p2p: error starting p2p server\n");
2760 yahoo_p2p_disconnect_destroy_data(data);
2761 return;
2762 }
2763
2764 yd = p2p_data->gc->proto_data;
2765
2766 /* Add an Input Read event to the file descriptor */
2767 yd->yahoo_local_p2p_server_fd = listenfd;
2768 yd->yahoo_p2p_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_server_send_connected_cb,data);
2769
2770 /* add timeout */
2771 yd->yahoo_p2p_server_timeout_handle = purple_timeout_add_seconds(YAHOO_P2P_SERVER_TIMEOUT, yahoo_cancel_p2p_server_listen_cb, data);
2772 }
2773
2774 /* send p2p pkt containing our encoded ip, asking peer to connect to us */
2775 void yahoo_send_p2p_pkt(PurpleConnection *gc, const char *who, int val_13)
2776 {
2777 const char *public_ip;
2778 guint32 temp[4];
2779 guint32 ip;
2780 char temp_str[100];
2781 gchar *base64_ip = NULL;
2782 YahooFriend *f;
2783 struct yahoo_packet *pkt;
2784 PurpleAccount *account;
2785 struct yahoo_data *yd = gc->proto_data;
2786 struct yahoo_p2p_data *p2p_data;
2787
2788 f = yahoo_friend_find(gc, who);
2789 account = purple_connection_get_account(gc);
2790
2791 /* Do not send invitation if already listening for other connection */
2792 if(yd->yahoo_local_p2p_server_fd >= 0)
2793 return;
2794
2795 /* One shouldn't try to connect to self */
2796 if( strcmp(purple_normalize(account, purple_account_get_username(account)), who) == 0)
2797 return;
2798
2799 /* 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 */
2800 if( !( f && (yahoo_friend_get_p2p_status(f) == YAHOO_P2PSTATUS_NOT_CONNECTED) && (f->p2p_packet_sent == 0)) )
2801 return;
2802
2803 /* Dont send p2p packet to buddies of other protocols */
2804 if(f->protocol)
2805 return;
2806
2807 /* Finally, don't try to connect to buddies not online or on sms */
2808 if( (f->status == YAHOO_STATUS_OFFLINE) || f->sms )
2809 return;
2810
2811 public_ip = purple_network_get_public_ip();
2812 if( (sscanf(public_ip, "%u.%u.%u.%u", &temp[0], &temp[1], &temp[2], &temp[3])) !=4 )
2813 return ;
2814
2815 ip = (temp[3] << 24) | (temp[2] <<16) | (temp[1] << 8) | temp[0];
2816 sprintf(temp_str, "%d", ip);
2817 base64_ip = purple_base64_encode( (guchar *)temp_str, strlen(temp_str) );
2818
2819 pkt = yahoo_packet_new(YAHOO_SERVICE_PEERTOPEER, YAHOO_STATUS_AVAILABLE, 0);
2820 yahoo_packet_hash(pkt, "sssissis",
2821 1, purple_normalize(account, purple_account_get_username(account)),
2822 4, purple_normalize(account, purple_account_get_username(account)),
2823 12, base64_ip, /* base64 encode ip */
2824 61, 0, /* To-do : figure out what is 61 for?? */
2825 2, "",
2826 5, who,
2827 13, val_13,
2828 49, "PEERTOPEER");
2829 yahoo_packet_send_and_free(pkt, yd);
2830
2831 f->p2p_packet_sent = 1; /* set p2p_packet_sent to sent */
2832
2833 p2p_data = g_new0(struct yahoo_p2p_data, 1);
2834
2835 p2p_data->gc = gc;
2836 p2p_data->host_ip = NULL;
2837 p2p_data->host_username = g_strdup(who);
2838 p2p_data->val_13 = val_13;
2839 p2p_data->connection_type = YAHOO_P2P_WE_ARE_SERVER;
2840
2841 purple_network_listen(YAHOO_PAGER_PORT_P2P, SOCK_STREAM, yahoo_p2p_server_listen_cb, p2p_data);
2842
2843 g_free(base64_ip);
2844 }
2845
2846 /* function called when connection to p2p host is setup */
2847 static void yahoo_p2p_init_cb(gpointer data, gint source, const gchar *error_message)
2848 {
2849 struct yahoo_p2p_data *p2p_data;
2850 struct yahoo_packet *pkt_to_send;
2851 PurpleAccount *account;
2852 struct yahoo_data *yd;
2853
2854 if(!(p2p_data = data))
2855 return ;
2856 yd = p2p_data->gc->proto_data;
2857
2858 if(error_message != NULL) {
2859 purple_debug_warning("yahoo","p2p: %s\n",error_message);
2860 yahoo_send_p2p_pkt(p2p_data->gc, p2p_data->host_username, 2);/* send p2p init packet with val_13=2 */
2861
2862 yahoo_p2p_disconnect_destroy_data(p2p_data);
2863 return;
2864 }
2865
2866 /* Add an Input Read event to the file descriptor */
2867 p2p_data->input_event = purple_input_add(source, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data);
2868 p2p_data->source = source;
2869
2870 account = purple_connection_get_account(p2p_data->gc);
2871
2872 /* Build the yahoo packet */
2873 pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
2874 yahoo_packet_hash(pkt_to_send, "ssisi",
2875 4, purple_normalize(account, purple_account_get_username(account)),
2876 5, p2p_data->host_username,
2877 241, 0, /* Protocol identifier */
2878 49, "PEERTOPEER",
2879 13, 1); /* we receive key13= 0 or 2, we send key13=1 */
2880
2881 yahoo_p2p_write_pkt(source, pkt_to_send); /* build raw packet and send */
2882 yahoo_packet_free(pkt_to_send);
2244 } 2883 }
2245 2884
2246 static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt) 2885 static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt)
2247 { 2886 {
2248 GSList *l = pkt->hash; 2887 GSList *l = pkt->hash;
2249 char *who = NULL; 2888 char *who = NULL;
2250 char *base64 = NULL; 2889 char *base64 = NULL;
2251 guchar *decoded; 2890 guchar *decoded;
2252 gsize len; 2891 gsize len;
2892 gint val_13 = 0;
2893 gint val_11 = 0;
2894 PurpleAccount *account;
2895 YahooFriend *f;
2896
2897 /* if status is not 1 ie YAHOO_STATUS_BRB, the packet bounced back, so contains our own ip */
2898 if(!(pkt->status == YAHOO_STATUS_BRB))
2899 return ;
2253 2900
2254 while (l) { 2901 while (l) {
2255 struct yahoo_pair *pair = l->data; 2902 struct yahoo_pair *pair = l->data;
2256 2903
2257 switch (pair->key) { 2904 switch (pair->key) {
2267 case 12: 2914 case 12:
2268 base64 = pair->value; 2915 base64 = pair->value;
2269 /* so, this is an ip address. in base64. decoded it's in ascii. 2916 /* so, this is an ip address. in base64. decoded it's in ascii.
2270 after strtol, it's in reversed byte order. Who thought this up?*/ 2917 after strtol, it's in reversed byte order. Who thought this up?*/
2271 break; 2918 break;
2919 case 13:
2920 val_13 = strtol(pair->value, NULL, 10);
2921 break;
2922 case 11:
2923 val_11 = strtol(pair->value, NULL, 10); /* session id of peer */
2924 if( (f = yahoo_friend_find(gc, who)) )
2925 f->session_id = val_11;
2926 break;
2272 /* 2927 /*
2273 TODO: figure these out 2928 TODO: figure these out
2274 yahoo: Key: 61 Value: 0 2929 yahoo: Key: 61 Value: 0
2275 yahoo: Key: 2 Value: 2930 yahoo: Key: 2 Value:
2276 yahoo: Key: 13 Value: 0 2931 yahoo: Key: 13 Value: 0 packet count ??
2277 yahoo: Key: 49 Value: PEERTOPEER 2932 yahoo: Key: 49 Value: PEERTOPEER
2278 yahoo: Key: 140 Value: 1 2933 yahoo: Key: 140 Value: 1
2279 yahoo: Key: 11 Value: -1786225828
2280 */ 2934 */
2281 2935
2282 } 2936 }
2283 2937
2284 l = l->next; 2938 l = l->next;
2286 2940
2287 if (base64) { 2941 if (base64) {
2288 guint32 ip; 2942 guint32 ip;
2289 char *tmp2; 2943 char *tmp2;
2290 YahooFriend *f; 2944 YahooFriend *f;
2945 char *host_ip;
2946 struct yahoo_p2p_data *p2p_data = g_new0(struct yahoo_p2p_data, 1);
2291 2947
2292 decoded = purple_base64_decode(base64, &len); 2948 decoded = purple_base64_decode(base64, &len);
2293 if (len) { 2949 if (len) {
2294 char *tmp = purple_str_binary_to_ascii(decoded, len); 2950 char *tmp = purple_str_binary_to_ascii(decoded, len);
2295 purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp); 2951 purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp);
2298 2954
2299 tmp2 = g_strndup((const gchar *)decoded, len); /* so its \0 terminated...*/ 2955 tmp2 = g_strndup((const gchar *)decoded, len); /* so its \0 terminated...*/
2300 ip = strtol(tmp2, NULL, 10); 2956 ip = strtol(tmp2, NULL, 10);
2301 g_free(tmp2); 2957 g_free(tmp2);
2302 g_free(decoded); 2958 g_free(decoded);
2303 tmp2 = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, 2959 host_ip = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff,
2304 (ip >> 24) & 0xff); 2960 (ip >> 24) & 0xff);
2305 f = yahoo_friend_find(gc, who); 2961 f = yahoo_friend_find(gc, who);
2306 if (f) 2962 if (f)
2307 yahoo_friend_set_ip(f, tmp2); 2963 yahoo_friend_set_ip(f, host_ip);
2308 g_free(tmp2); 2964 purple_debug_info("yahoo", "IP : %s\n", host_ip);
2965
2966 account = purple_connection_get_account(gc);
2967
2968 if(val_11==0) {
2969 if(!f)
2970 return;
2971 else
2972 val_11 = f->session_id;
2973 }
2974
2975 p2p_data->host_username = g_strdup(who);
2976 p2p_data->val_13 = val_13;
2977 p2p_data->session_id = val_11;
2978 p2p_data->host_ip = host_ip;
2979 p2p_data->gc = gc;
2980 p2p_data->connection_type = YAHOO_P2P_WE_ARE_CLIENT;
2981
2982 /* connect to host */
2983 if((purple_proxy_connect(NULL, account, host_ip, YAHOO_PAGER_PORT_P2P, yahoo_p2p_init_cb, p2p_data))==NULL) {
2984 yahoo_p2p_disconnect_destroy_data(p2p_data);
2985 purple_debug_info("yahoo","p2p: Connection to %s failed\n", host_ip);
2986 }
2309 } 2987 }
2310 } 2988 }
2311 2989
2312 static void yahoo_process_audible(PurpleConnection *gc, struct yahoo_packet *pkt) 2990 static void yahoo_process_audible(PurpleConnection *gc, struct yahoo_packet *pkt)
2313 { 2991 {
2383 case YAHOO_SERVICE_Y6_STATUS_UPDATE: 3061 case YAHOO_SERVICE_Y6_STATUS_UPDATE:
2384 case YAHOO_SERVICE_STATUS_15: 3062 case YAHOO_SERVICE_STATUS_15:
2385 yahoo_process_status(gc, pkt); 3063 yahoo_process_status(gc, pkt);
2386 break; 3064 break;
2387 case YAHOO_SERVICE_NOTIFY: 3065 case YAHOO_SERVICE_NOTIFY:
2388 yahoo_process_notify(gc, pkt); 3066 yahoo_process_notify(gc, pkt, YAHOO_PKT_TYPE_SERVER);
2389 break; 3067 break;
2390 case YAHOO_SERVICE_MESSAGE: 3068 case YAHOO_SERVICE_MESSAGE:
2391 case YAHOO_SERVICE_GAMEMSG: 3069 case YAHOO_SERVICE_GAMEMSG:
2392 case YAHOO_SERVICE_CHATMSG: 3070 case YAHOO_SERVICE_CHATMSG:
2393 yahoo_process_message(gc, pkt); 3071 yahoo_process_message(gc, pkt, YAHOO_PKT_TYPE_SERVER);
2394 break; 3072 break;
2395 case YAHOO_SERVICE_SYSMESSAGE: 3073 case YAHOO_SERVICE_SYSMESSAGE:
2396 yahoo_process_sysmessage(gc, pkt); 3074 yahoo_process_sysmessage(gc, pkt);
2397 break; 3075 break;
2398 case YAHOO_SERVICE_NEWMAIL: 3076 case YAHOO_SERVICE_NEWMAIL:
2465 case YAHOO_SERVICE_PRESENCE_SESSION: 3143 case YAHOO_SERVICE_PRESENCE_SESSION:
2466 yahoo_process_presence(gc, pkt); 3144 yahoo_process_presence(gc, pkt);
2467 break; 3145 break;
2468 case YAHOO_SERVICE_P2PFILEXFER: 3146 case YAHOO_SERVICE_P2PFILEXFER:
2469 /* This case had no break and continued; thus keeping it this way.*/ 3147 /* This case had no break and continued; thus keeping it this way.*/
2470 yahoo_process_p2pfilexfer(gc, pkt); 3148 yahoo_process_p2p(gc, pkt); /* P2PFILEXFER handled the same way as process_p2p */
3149 yahoo_process_p2pfilexfer(gc, pkt); /* redundant ??, need to have a break now */
2471 case YAHOO_SERVICE_FILETRANSFER: 3150 case YAHOO_SERVICE_FILETRANSFER:
2472 yahoo_process_filetransfer(gc, pkt); 3151 yahoo_process_filetransfer(gc, pkt);
2473 break; 3152 break;
2474 case YAHOO_SERVICE_PEERTOPEER: 3153 case YAHOO_SERVICE_PEERTOPEER:
2475 yahoo_process_p2p(gc, pkt); 3154 yahoo_process_p2p(gc, pkt);
2498 case YAHOO_SERVICE_FILETRANS_INFO_15: 3177 case YAHOO_SERVICE_FILETRANS_INFO_15:
2499 yahoo_process_filetrans_info_15(gc, pkt); 3178 yahoo_process_filetrans_info_15(gc, pkt);
2500 break; 3179 break;
2501 case YAHOO_SERVICE_FILETRANS_ACC_15: 3180 case YAHOO_SERVICE_FILETRANS_ACC_15:
2502 yahoo_process_filetrans_acc_15(gc, pkt); 3181 yahoo_process_filetrans_acc_15(gc, pkt);
3182 break;
3183 case YAHOO_SERVICE_SMS_MSG:
3184 yahoo_process_sms_message(gc, pkt);
2503 break; 3185 break;
2504 3186
2505 default: 3187 default:
2506 purple_debug(PURPLE_DEBUG_ERROR, "yahoo", 3188 purple_debug(PURPLE_DEBUG_ERROR, "yahoo",
2507 "Unhandled service 0x%02x\n", pkt->service); 3189 "Unhandled service 0x%02x\n", pkt->service);
3014 3696
3015 purple_connection_update_progress(gc, _("Connecting"), 1, 2); 3697 purple_connection_update_progress(gc, _("Connecting"), 1, 2);
3016 3698
3017 purple_connection_set_display_name(gc, purple_account_get_username(account)); 3699 purple_connection_set_display_name(gc, purple_account_get_username(account));
3018 3700
3701 yd->yahoo_local_p2p_server_fd = -1;
3019 yd->fd = -1; 3702 yd->fd = -1;
3020 yd->txhandler = 0; 3703 yd->txhandler = 0;
3021 /* TODO: Is there a good grow size for the buffer? */ 3704 /* TODO: Is there a good grow size for the buffer? */
3022 yd->txbuf = purple_circ_buffer_new(0); 3705 yd->txbuf = purple_circ_buffer_new(0);
3023 yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free); 3706 yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free);
3024 yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); 3707 yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
3025 yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); 3708 yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
3709 yd->peers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_p2p_disconnect_destroy_data);
3710 yd->sms_carrier = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
3711 yd->yahoo_p2p_timer = purple_timeout_add_seconds(YAHOO_P2P_KEEPALIVE_SECS, yahoo_p2p_keepalive, gc);
3026 yd->confs = NULL; 3712 yd->confs = NULL;
3027 yd->conf_id = 2; 3713 yd->conf_id = 2;
3028 yd->last_keepalive = yd->last_ping = time(NULL); 3714 yd->last_keepalive = yd->last_ping = time(NULL);
3029 3715
3030 yd->current_status = get_yahoo_status_from_purple_status(status); 3716 yd->current_status = get_yahoo_status_from_purple_status(status);
3086 3772
3087 yd->chat_online = FALSE; 3773 yd->chat_online = FALSE;
3088 if (yd->in_chat) 3774 if (yd->in_chat)
3089 yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */ 3775 yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */
3090 3776
3777 purple_timeout_remove(yd->yahoo_p2p_timer);
3778 if(yd->yahoo_p2p_server_timeout_handle != 0)
3779 purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle);
3780
3781 /* close p2p server if it is waiting for a peer to connect */
3782 purple_input_remove(yd->yahoo_p2p_server_watcher);
3783 close(yd->yahoo_local_p2p_server_fd);
3784 yd->yahoo_local_p2p_server_fd = -1;
3785
3786 g_hash_table_destroy(yd->sms_carrier);
3787 g_hash_table_destroy(yd->peers);
3091 g_hash_table_destroy(yd->friends); 3788 g_hash_table_destroy(yd->friends);
3092 g_hash_table_destroy(yd->imvironments); 3789 g_hash_table_destroy(yd->imvironments);
3093 g_hash_table_destroy(yd->xfer_peer_idstring_map); 3790 g_hash_table_destroy(yd->xfer_peer_idstring_map);
3094 g_free(yd->chat_name); 3791 g_free(yd->chat_name);
3095 3792
3634 m = g_list_append(m, act); 4331 m = g_list_append(m, act);
3635 4332
3636 return m; 4333 return m;
3637 } 4334 }
3638 4335
4336 struct yahoo_sms_carrier_cb_data {
4337 PurpleConnection *gc;
4338 char *who;
4339 char *what;
4340 };
4341
4342 static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags);
4343
4344 static void yahoo_get_sms_carrier_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
4345 const gchar *webdata, size_t len, const gchar *error_message)
4346 {
4347 struct yahoo_sms_carrier_cb_data *sms_cb_data = user_data;
4348 PurpleConnection *gc = sms_cb_data->gc;
4349 struct yahoo_data *yd = gc->proto_data;
4350 char *mobile_no = NULL;
4351 char *status = NULL;
4352 char *carrier = NULL;
4353 PurpleAccount *account = purple_connection_get_account(gc);
4354 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
4355
4356 if (error_message != NULL) {
4357 purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
4358
4359 g_free(sms_cb_data->who);
4360 g_free(sms_cb_data->what);
4361 g_free(sms_cb_data);
4362 return ;
4363 }
4364 else if (len > 0 && webdata && *webdata) {
4365 xmlnode *validate_data_root = xmlnode_from_str(webdata, -1);
4366 xmlnode *validate_data_child = xmlnode_get_child(validate_data_root, "mobile_no");
4367 mobile_no = (char *)xmlnode_get_attrib(validate_data_child, "msisdn");
4368
4369 validate_data_root = xmlnode_copy(validate_data_child);
4370 validate_data_child = xmlnode_get_child(validate_data_root, "status");
4371 status = xmlnode_get_data(validate_data_child);
4372
4373 validate_data_child = xmlnode_get_child(validate_data_root, "carrier");
4374 carrier = xmlnode_get_data(validate_data_child);
4375
4376 purple_debug_info("yahoo","SMS validate data: Mobile:%s, Status:%s, Carrier:%s\n", mobile_no, status, carrier);
4377
4378 if( strcmp(status, "Valid") == 0) {
4379 g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup(carrier));
4380 yahoo_send_im(sms_cb_data->gc, sms_cb_data->who, sms_cb_data->what, PURPLE_MESSAGE_SEND);
4381 }
4382 else {
4383 g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup("Unknown"));
4384 purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
4385 }
4386
4387 xmlnode_free(validate_data_child);
4388 xmlnode_free(validate_data_root);
4389 g_free(sms_cb_data->who);
4390 g_free(sms_cb_data->what);
4391 g_free(sms_cb_data);
4392 g_free(mobile_no);
4393 g_free(status);
4394 g_free(carrier);
4395 }
4396 }
4397
4398 static void yahoo_get_sms_carrier(PurpleConnection *gc, gpointer data)
4399 {
4400 struct yahoo_data *yd = gc->proto_data;
4401 PurpleUtilFetchUrlData *url_data;
4402 struct yahoo_sms_carrier_cb_data *sms_cb_data;
4403 char *validate_request_str = NULL;
4404 char *request = NULL;
4405 gboolean use_whole_url = FALSE;
4406 xmlnode *validate_request_root = NULL;
4407 xmlnode *validate_request_child = NULL;
4408
4409 if(!(sms_cb_data = data))
4410 return;
4411
4412 validate_request_root = xmlnode_new("validate");
4413 xmlnode_set_attrib(validate_request_root, "intl", "us");
4414 xmlnode_set_attrib(validate_request_root, "version", YAHOO_CLIENT_VERSION);
4415 xmlnode_set_attrib(validate_request_root, "qos", "0");
4416
4417 validate_request_child = xmlnode_new_child(validate_request_root, "mobile_no");
4418 xmlnode_set_attrib(validate_request_child, "msisdn", sms_cb_data->who + 1);
4419
4420 validate_request_str = xmlnode_to_str(validate_request_root, NULL);
4421
4422 xmlnode_free(validate_request_child);
4423 xmlnode_free(validate_request_root);
4424
4425 request = g_strdup_printf(
4426 "POST /mobileno?intl=us&version=%s HTTP/1.1\r\n"
4427 "Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s; path=/; domain=.yahoo.com;\r\n"
4428 "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n"
4429 "Host: validate.msg.yahoo.com\r\n"
4430 "Content-Length: %d\r\n"
4431 "Cache-Control: no-cache\r\n\r\n%s",
4432 YAHOO_CLIENT_VERSION, yd->cookie_t, yd->cookie_y, strlen(validate_request_str), validate_request_str);
4433
4434 /* use whole URL if using HTTP Proxy */
4435 if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP))
4436 use_whole_url = TRUE;
4437
4438 url_data = purple_util_fetch_url_request(YAHOO_SMS_CARRIER_URL, use_whole_url,
4439 "Mozilla/4.0 (compatible; MSIE 5.5)", TRUE, request, FALSE,
4440 yahoo_get_sms_carrier_cb, data);
4441
4442 g_free(request);
4443 g_free(validate_request_str);
4444
4445 if (!url_data) {
4446 PurpleAccount *account = purple_connection_get_account(gc);
4447 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
4448 purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
4449 g_free(sms_cb_data->who);
4450 g_free(sms_cb_data->what);
4451 g_free(sms_cb_data);
4452 }
4453 }
4454
3639 static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags) 4455 static int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags)
3640 { 4456 {
3641 struct yahoo_data *yd = gc->proto_data; 4457 struct yahoo_data *yd = gc->proto_data;
3642 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0); 4458 struct yahoo_packet *pkt = NULL;
3643 char *msg = yahoo_html_to_codes(what); 4459 char *msg = yahoo_html_to_codes(what);
3644 char *msg2; 4460 char *msg2;
3645 gboolean utf8 = TRUE; 4461 gboolean utf8 = TRUE;
3646 PurpleWhiteboard *wb; 4462 PurpleWhiteboard *wb;
3647 int ret = 1; 4463 int ret = 1;
3648 YahooFriend *f = NULL; 4464 YahooFriend *f = NULL;
3649 gsize lenb = 0; 4465 gsize lenb = 0;
3650 glong lenc = 0; 4466 glong lenc = 0;
3651 4467 struct yahoo_p2p_data *p2p_data;
4468 gboolean msn = FALSE;
3652 msg2 = yahoo_string_encode(gc, msg, &utf8); 4469 msg2 = yahoo_string_encode(gc, msg, &utf8);
3653 4470
3654 if(msg2) { 4471 if(msg2) {
3655 lenb = strlen(msg2); 4472 lenb = strlen(msg2);
3656 lenc = g_utf8_strlen(msg2, -1); 4473 lenc = g_utf8_strlen(msg2, -1);
3665 g_free(msg2); 4482 g_free(msg2);
3666 return -E2BIG; 4483 return -E2BIG;
3667 } 4484 }
3668 } 4485 }
3669 4486
3670 yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who); 4487 msn = g_str_has_prefix(who, "msn/") || g_str_has_prefix(who, "MSN/");
3671 if ((f = yahoo_friend_find(gc, who)) && f->protocol) 4488
3672 yahoo_packet_hash_int(pkt, 241, f->protocol); 4489 if( strncmp(who, "+", 1) == 0 ) {
4490 /* we have an sms to be sent */
4491 gchar *carrier = NULL;
4492 const char *alias = NULL;
4493 PurpleAccount *account = purple_connection_get_account(gc);
4494 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account);
4495
4496 carrier = g_hash_table_lookup(yd->sms_carrier, who);
4497 if (!carrier) {
4498 struct yahoo_sms_carrier_cb_data *sms_cb_data;
4499 sms_cb_data = g_malloc(sizeof(struct yahoo_sms_carrier_cb_data));
4500 sms_cb_data->gc = gc;
4501 sms_cb_data->who = g_malloc(strlen(who));
4502 sms_cb_data->what = g_malloc(strlen(what));
4503 strcpy(sms_cb_data->who, who);
4504 strcpy(sms_cb_data->what, what);
4505
4506 purple_conversation_write(conv, NULL, "Getting mobile carrier to send the sms", PURPLE_MESSAGE_SYSTEM, time(NULL));
4507
4508 yahoo_get_sms_carrier(gc, sms_cb_data);
4509
4510 g_free(msg);
4511 g_free(msg2);
4512 return ret;
4513 }
4514 else if( strcmp(carrier,"Unknown") == 0 ) {
4515 purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
4516
4517 g_free(msg);
4518 g_free(msg2);
4519 return -1;
4520 }
4521
4522 alias = purple_account_get_alias(account);
4523 pkt = yahoo_packet_new(YAHOO_SERVICE_SMS_MSG, YAHOO_STATUS_AVAILABLE, 0);
4524 yahoo_packet_hash(pkt, "sssss",
4525 1, purple_connection_get_display_name(gc),
4526 69, alias,
4527 5, who + 1,
4528 68, carrier,
4529 14, msg2);
4530 yahoo_packet_send_and_free(pkt, yd);
4531
4532 g_free(msg);
4533 g_free(msg2);
4534
4535 return ret;
4536 }
4537
4538 pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, 0);
4539 if(msn) {
4540 yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who+4);
4541 yahoo_packet_hash_int(pkt, 241, 2);
4542 }
4543 else {
4544 yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who);
4545 if ((f = yahoo_friend_find(gc, who)) && f->protocol)
4546 yahoo_packet_hash_int(pkt, 241, f->protocol);
4547 }
3673 4548
3674 if (utf8) 4549 if (utf8)
3675 yahoo_packet_hash_str(pkt, 97, "1"); 4550 yahoo_packet_hash_str(pkt, 97, "1");
3676 yahoo_packet_hash_str(pkt, 14, msg2); 4551 yahoo_packet_hash_str(pkt, 14, msg2);
3677 4552
3706 yahoo_packet_hash_str(pkt, 206, "0"); /* 0 = no picture, 2 = picture, maybe 1 = avatar? */ 4581 yahoo_packet_hash_str(pkt, 206, "0"); /* 0 = no picture, 2 = picture, maybe 1 = avatar? */
3707 else 4582 else
3708 yahoo_packet_hash_str(pkt, 206, "2"); 4583 yahoo_packet_hash_str(pkt, 206, "2");
3709 4584
3710 /* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */ 4585 /* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */
3711 if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) 4586 if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) {
3712 yahoo_packet_send(pkt, yd); 4587 /* if p2p link exists, send through it. To-do: key 15, time value to be sent in case of p2p */
4588 if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !msn ) {
4589 yahoo_packet_hash_int(pkt, 11, p2p_data->session_id);
4590 yahoo_p2p_write_pkt(p2p_data->source, pkt);
4591 }
4592 else {
4593 yahoo_packet_send(pkt, yd);
4594 if(!msn)
4595 yahoo_send_p2p_pkt(gc, who, 0); /* send p2p packet, with val_13=0 */
4596 }
4597 }
3713 else 4598 else
3714 ret = -E2BIG; 4599 ret = -E2BIG;
3715 4600
3716 yahoo_packet_free(pkt); 4601 yahoo_packet_free(pkt);
3717 4602
3722 } 4607 }
3723 4608
3724 static unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state) 4609 static unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state)
3725 { 4610 {
3726 struct yahoo_data *yd = gc->proto_data; 4611 struct yahoo_data *yd = gc->proto_data;
3727 struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, 0); 4612 struct yahoo_p2p_data *p2p_data;
3728 yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc), 4613 gboolean msn = (g_str_has_prefix(who, "msn/") || g_str_has_prefix(who, "MSN/"));
4614 struct yahoo_packet *pkt = NULL;
4615
4616 /* Don't do anything if sms is being typed */
4617 if( strncmp(who, "+", 1) == 0 )
4618 return 0;
4619
4620 pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, 0);
4621
4622 /* check to see if p2p link exists, send through it */
4623 if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !msn ) {
4624 yahoo_packet_hash(pkt, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc),
3729 14, " ", 13, state == PURPLE_TYPING ? "1" : "0", 4625 14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
3730 5, who, 1002, "1"); 4626 5, who, 11, p2p_data->session_id, 1002, "1"); /* To-do: key 15 to be sent in case of p2p */
3731 4627 yahoo_p2p_write_pkt(p2p_data->source, pkt);
3732 yahoo_packet_send_and_free(pkt, yd); 4628 yahoo_packet_free(pkt);
4629 }
4630 else { /* send through yahoo server */
4631 if(msn)
4632 yahoo_packet_hash(pkt, "sssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
4633 14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
4634 5, who+4, 1002, "1", 241, "2");
4635 else
4636 yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
4637 14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
4638 5, who+4, 1002, "1");
4639 yahoo_packet_send_and_free(pkt, yd);
4640 }
3733 4641
3734 return 0; 4642 return 0;
3735 } 4643 }
3736 4644
3737 static void yahoo_session_presence_remove(gpointer key, gpointer value, gpointer data) 4645 static void yahoo_session_presence_remove(gpointer key, gpointer value, gpointer data)
3973 struct yahoo_packet *pkt; 4881 struct yahoo_packet *pkt;
3974 const char *group = NULL; 4882 const char *group = NULL;
3975 char *group2; 4883 char *group2;
3976 YahooFriend *f; 4884 YahooFriend *f;
3977 const char *bname; 4885 const char *bname;
4886 gboolean msn = FALSE;
3978 4887
3979 if (!yd->logged_in) 4888 if (!yd->logged_in)
3980 return; 4889 return;
3981 4890
3982 bname = purple_buddy_get_name(buddy); 4891 bname = purple_buddy_get_name(buddy);
3983 if (!purple_privacy_check(purple_connection_get_account(gc), bname)) 4892 if (!purple_privacy_check(purple_connection_get_account(gc), bname))
3984 return; 4893 return;
3985 4894
3986 f = yahoo_friend_find(gc, bname); 4895 f = yahoo_friend_find(gc, bname);
4896 msn = g_str_has_prefix(bname, "msn/") || g_str_has_prefix(bname, "MSN/");
3987 4897
3988 g = purple_buddy_get_group(buddy); 4898 g = purple_buddy_get_group(buddy);
3989 if (g) 4899 if (g)
3990 group = purple_group_get_name(g); 4900 group = purple_group_get_name(g);
3991 else 4901 else
3992 group = "Buddies"; 4902 group = "Buddies";
3993 4903
3994 group2 = yahoo_string_encode(gc, group, NULL); 4904 group2 = yahoo_string_encode(gc, group, NULL);
3995 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0); 4905 pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, 0);
3996 yahoo_packet_hash(pkt, "ssssssssss", 4906 if(msn) {
3997 14, "", 4907 yahoo_packet_hash(pkt, "sssssssssss",
3998 65, group2, 4908 14, "",
3999 97, "1", 4909 65, group2,
4000 1, purple_connection_get_display_name(gc), 4910 97, "1",
4001 302, "319", 4911 1, purple_connection_get_display_name(gc),
4002 300, "319", 4912 302, "319",
4003 7, bname, 4913 300, "319",
4004 334, "0", 4914 7, bname + 4,
4005 301, "319", 4915 241, "2",
4006 303, "319" 4916 334, "0",
4007 ); 4917 301, "319",
4008 if (f && f->protocol) 4918 303, "319"
4919 );
4920 }
4921 else {
4922 yahoo_packet_hash(pkt, "ssssssssss",
4923 14, "",
4924 65, group2,
4925 97, "1",
4926 1, purple_connection_get_display_name(gc),
4927 302, "319",
4928 300, "319",
4929 7, bname,
4930 334, "0",
4931 301, "319",
4932 303, "319"
4933 );
4934 }
4935 if (f && f->protocol && !msn)
4009 yahoo_packet_hash_int(pkt, 241, f->protocol); 4936 yahoo_packet_hash_int(pkt, 241, f->protocol);
4937
4010 yahoo_packet_send_and_free(pkt, yd); 4938 yahoo_packet_send_and_free(pkt, yd);
4011 g_free(group2); 4939 g_free(group2);
4012 } 4940 }
4013 4941
4014 static void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) 4942 static void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
4018 GSList *buddies, *l; 4946 GSList *buddies, *l;
4019 PurpleGroup *g; 4947 PurpleGroup *g;
4020 gboolean remove = TRUE; 4948 gboolean remove = TRUE;
4021 char *cg; 4949 char *cg;
4022 const char *bname, *gname; 4950 const char *bname, *gname;
4951 YahooFriend *f = NULL;
4952 gboolean msn = FALSE;
4023 4953
4024 bname = purple_buddy_get_name(buddy); 4954 bname = purple_buddy_get_name(buddy);
4025 if (!(yahoo_friend_find(gc, bname))) 4955 f = yahoo_friend_find(gc, bname);
4956 if (!f)
4026 return; 4957 return;
4027 4958
4028 gname = purple_group_get_name(group); 4959 gname = purple_group_get_name(group);
4029 buddies = purple_find_buddies(purple_connection_get_account(gc), bname); 4960 buddies = purple_find_buddies(purple_connection_get_account(gc), bname);
4961 if(f->protocol == 2)
4962 msn = TRUE;
4030 for (l = buddies; l; l = l->next) { 4963 for (l = buddies; l; l = l->next) {
4031 g = purple_buddy_get_group(l->data); 4964 g = purple_buddy_get_group(l->data);
4032 if (purple_utf8_strcasecmp(gname, purple_group_get_name(g))) { 4965 if (purple_utf8_strcasecmp(gname, purple_group_get_name(g))) {
4033 remove = FALSE; 4966 remove = FALSE;
4034 break; 4967 break;
4040 if (remove) 4973 if (remove)
4041 g_hash_table_remove(yd->friends, bname); 4974 g_hash_table_remove(yd->friends, bname);
4042 4975
4043 cg = yahoo_string_encode(gc, gname, NULL); 4976 cg = yahoo_string_encode(gc, gname, NULL);
4044 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0); 4977 pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, 0);
4045 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 4978
4979 if(msn)
4980 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
4981 7, bname+4, 65, cg);
4982 else
4983 yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
4046 7, bname, 65, cg); 4984 7, bname, 65, cg);
4985 if(f->protocol)
4986 yahoo_packet_hash_int(pkt, 241, f->protocol);
4047 yahoo_packet_send_and_free(pkt, yd); 4987 yahoo_packet_send_and_free(pkt, yd);
4048 g_free(cg); 4988 g_free(cg);
4049 } 4989 }
4050 4990
4051 static void yahoo_add_deny(PurpleConnection *gc, const char *who) { 4991 static void yahoo_add_deny(PurpleConnection *gc, const char *who) {
4114 const char *old_group, const char *new_group) 5054 const char *old_group, const char *new_group)
4115 { 5055 {
4116 struct yahoo_data *yd = gc->proto_data; 5056 struct yahoo_data *yd = gc->proto_data;
4117 struct yahoo_packet *pkt; 5057 struct yahoo_packet *pkt;
4118 char *gpn, *gpo; 5058 char *gpn, *gpo;
5059 YahooFriend *f = yahoo_friend_find(gc, who);
5060 gboolean msn = FALSE;
5061 const char *temp = NULL;
4119 5062
4120 /* Step 0: If they aren't on the server list anyway, 5063 /* Step 0: If they aren't on the server list anyway,
4121 * don't bother letting the server know. 5064 * don't bother letting the server know.
4122 */ 5065 */
4123 if (!yahoo_friend_find(gc, who)) 5066 if (!f)
4124 return; 5067 return;
5068
5069 if(f->protocol == 2) {
5070 msn = TRUE;
5071 temp = who+4;
5072 } else
5073 temp = who;
4125 5074
4126 /* If old and new are the same, we would probably 5075 /* If old and new are the same, we would probably
4127 * end up deleting the buddy, which would be bad. 5076 * end up deleting the buddy, which would be bad.
4128 * This might happen because of the charset conversation. 5077 * This might happen because of the charset conversation.
4129 */ 5078 */
4134 g_free(gpo); 5083 g_free(gpo);
4135 return; 5084 return;
4136 } 5085 }
4137 5086
4138 pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, 0); 5087 pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, 0);
4139 yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc), 5088 if(f->protocol)
4140 302, "240", 300, "240", 7, who, 224, gpo, 264, gpn, 301, 5089 yahoo_packet_hash(pkt, "ssssissss", 1, purple_connection_get_display_name(gc),
5090 302, "240", 300, "240", 7, temp, 241, f->protocol, 224, gpo, 264, gpn, 301,
5091 "240", 303, "240");
5092 else
5093 yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc),
5094 302, "240", 300, "240", 7, temp, 224, gpo, 264, gpn, 301,
4141 "240", 303, "240"); 5095 "240", 303, "240");
4142 yahoo_packet_send_and_free(pkt, yd); 5096 yahoo_packet_send_and_free(pkt, yd);
4143 5097
4144 g_free(gpn); 5098 g_free(gpn);
4145 g_free(gpo); 5099 g_free(gpo);
4347 /* Spaces are encoded as '+' */ 5301 /* Spaces are encoded as '+' */
4348 g_strdelimit(message, "+", ' '); 5302 g_strdelimit(message, "+", ' ');
4349 purple_conv_send_confirm(conv, message); 5303 purple_conv_send_confirm(conv, message);
4350 } 5304 }
4351 } 5305 }
4352 /*else 5306 /* else
4353 **If pidgindialogs_im() was in the core, we could use it here. 5307 **If pidgindialogs_im() was in the core, we could use it here.
4354 * It is all purple_request_* based, but I'm not sure it really belongs in the core 5308 * It is all purple_request_* based, but I'm not sure it really belongs in the core
4355 pidgindialogs_im();*/ 5309 pidgindialogs_im(); */
4356 5310
4357 return TRUE; 5311 return TRUE;
4358 } 5312 }
4359 /* ymsgr:Chat?roomname */ 5313 /* ymsgr:Chat?roomname */
4360 else if (!g_ascii_strcasecmp(cmd, "Chat")) { 5314 else if (!g_ascii_strcasecmp(cmd, "Chat")) {
4364 /* This is somewhat hacky, but the params aren't useful after this command */ 5318 /* This is somewhat hacky, but the params aren't useful after this command */
4365 g_hash_table_insert(params, g_strdup("room"), g_strdup(rname)); 5319 g_hash_table_insert(params, g_strdup("room"), g_strdup(rname));
4366 g_hash_table_insert(params, g_strdup("type"), g_strdup("Chat")); 5320 g_hash_table_insert(params, g_strdup("type"), g_strdup("Chat"));
4367 serv_join_chat(purple_account_get_connection(acct), params); 5321 serv_join_chat(purple_account_get_connection(acct), params);
4368 } 5322 }
4369 /*else 5323 /* else
4370 ** Same as above (except that this would have to be re-written using purple_request_*) 5324 ** Same as above (except that this would have to be re-written using purple_request_*)
4371 pidgin_blist_joinchat_show(); */ 5325 pidgin_blist_joinchat_show(); */
4372 5326
4373 return TRUE; 5327 return TRUE;
4374 } 5328 }
4434 yahoo_set_idle, 5388 yahoo_set_idle,
4435 NULL, /* change_passwd*/ 5389 NULL, /* change_passwd*/
4436 yahoo_add_buddy, 5390 yahoo_add_buddy,
4437 NULL, /* add_buddies */ 5391 NULL, /* add_buddies */
4438 yahoo_remove_buddy, 5392 yahoo_remove_buddy,
4439 NULL, /*remove_buddies */ 5393 NULL, /* remove_buddies */
4440 NULL, /* add_permit */ 5394 NULL, /* add_permit */
4441 yahoo_add_deny, 5395 yahoo_add_deny,
4442 NULL, /* rem_permit */ 5396 NULL, /* rem_permit */
4443 yahoo_rem_deny, 5397 yahoo_rem_deny,
4444 yahoo_set_permit_deny, 5398 yahoo_set_permit_deny,