comparison libpurple/protocols/myspace/myspace.c @ 17337:d3e17c9d16e9

Use MsimMessage for receiving messages everywhere, instead of GHashTable.
author Jeffrey Connelly <jaconnel@calpoly.edu>
date Fri, 01 Jun 2007 06:09:32 +0000
parents 793301c04e3a
children 9ecd2bb0ecc1
comparison
equal deleted inserted replaced
17336:3b226f9544a3 17337:d3e17c9d16e9
263 } 263 }
264 /** 264 /**
265 * Process a login challenge, sending a response. 265 * Process a login challenge, sending a response.
266 * 266 *
267 * @param session 267 * @param session
268 * @param table Hash table of login challenge message. 268 * @param msg Login challenge message.
269 * 269 *
270 * @return 0, since the 'table' parameter is no longer needed. 270 * @return 0, since the 'msg' parameter is no longer needed.
271 */ 271 */
272 int msim_login_challenge(MsimSession *session, GHashTable *table) 272 int msim_login_challenge(MsimSession *session, MsimMessage *msg)
273 { 273 {
274 PurpleAccount *account; 274 PurpleAccount *account;
275 gchar *nc_str;
276 guchar *nc;
277 gchar *response; 275 gchar *response;
278 gsize nc_len;
279 guint response_len; 276 guint response_len;
277 gchar *nc;
278 gsize nc_len;
280 279
281 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0); 280 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
282 g_return_val_if_fail(table != NULL, 0); 281 g_return_val_if_fail(msg != NULL, 0);
283 282
284 nc_str = g_hash_table_lookup(table, "nc"); 283 g_return_val_if_fail(msim_msg_get_binary(msg, "nc", &nc, &nc_len), 0);
285 284
286 account = session->account; 285 account = session->account;
287 //assert(account); 286 //assert(account);
288 287
289 purple_connection_update_progress(session->gc, _("Reading challenge"), 1, 4); 288 purple_connection_update_progress(session->gc, _("Reading challenge"), 1, 4);
290 289
291 purple_debug_info("msim", "nc=<%s>\n", nc_str); 290 purple_debug_info("msim", "nc is %d bytes, decoded\n", nc_len);
292 291
293 nc = (guchar *)purple_base64_decode(nc_str, &nc_len);
294 purple_debug_info("msim", "base64 decoded to %d bytes\n", nc_len);
295 if (nc_len != 0x40) 292 if (nc_len != 0x40)
296 { 293 {
297 purple_debug_info("msim", "bad nc length: %x != 0x40\n", nc_len); 294 purple_debug_info("msim", "bad nc length: %x != 0x40\n", nc_len);
298 purple_connection_error(session->gc, _("Unexpected challenge length from server")); 295 purple_connection_error(session->gc, _("Unexpected challenge length from server"));
299 return 0; 296 return 0;
436 * @param response_len Will be written with response length. 433 * @param response_len Will be written with response length.
437 * 434 *
438 * @return Binary login challenge response, ready to send to the server. Must be g_free()'d 435 * @return Binary login challenge response, ready to send to the server. Must be g_free()'d
439 * when finished. 436 * when finished.
440 */ 437 */
441 gchar *msim_compute_login_response(guchar nonce[2 * NONCE_SIZE], 438 gchar *msim_compute_login_response(gchar nonce[2 * NONCE_SIZE],
442 gchar *email, gchar *password, guint *response_len) 439 gchar *email, gchar *password, guint *response_len)
443 { 440 {
444 PurpleCipherContext *key_context; 441 PurpleCipherContext *key_context;
445 PurpleCipher *sha1; 442 PurpleCipher *sha1;
446 #ifdef MSIM_USE_PURPLE_RC4 443 #ifdef MSIM_USE_PURPLE_RC4
489 486
490 /* key = sha1(sha1(pw) + nonce2) */ 487 /* key = sha1(sha1(pw) + nonce2) */
491 sha1 = purple_ciphers_find_cipher("sha1"); 488 sha1 = purple_ciphers_find_cipher("sha1");
492 key_context = purple_cipher_context_new(sha1, NULL); 489 key_context = purple_cipher_context_new(sha1, NULL);
493 purple_cipher_context_append(key_context, hash_pw, HASH_SIZE); 490 purple_cipher_context_append(key_context, hash_pw, HASH_SIZE);
494 purple_cipher_context_append(key_context, nonce + NONCE_SIZE, NONCE_SIZE); 491 purple_cipher_context_append(key_context, (guchar *)(nonce + NONCE_SIZE), NONCE_SIZE);
495 purple_cipher_context_digest(key_context, sizeof(key), key, NULL); 492 purple_cipher_context_digest(key_context, sizeof(key), key, NULL);
496 493
497 #ifdef MSIM_DEBUG_LOGIN_CHALLENGE 494 #ifdef MSIM_DEBUG_LOGIN_CHALLENGE
498 purple_debug_info("msim", "key = "); 495 purple_debug_info("msim", "key = ");
499 for (i = 0; i < sizeof(key); i++) 496 for (i = 0; i < sizeof(key); i++)
640 * @param session 637 * @param session
641 * @param userid ASCII numeric userid. 638 * @param userid ASCII numeric userid.
642 * @param message Text of message to send. 639 * @param message Text of message to send.
643 * @param flags Purple instant message flags. 640 * @param flags Purple instant message flags.
644 * 641 *
645 * @return 0, since the 'table' parameter is no longer needed. 642 * @return 0
646 * 643 *
647 */ 644 */
648 int msim_send_im_by_userid(MsimSession *session, const gchar *userid, const gchar *message, PurpleMessageFlags flags) 645 int msim_send_im_by_userid(MsimSession *session, const gchar *userid, const gchar *message, PurpleMessageFlags flags)
649 { 646 {
650 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0); 647 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
674 * Calls msim_send_im_by_userid. 671 * Calls msim_send_im_by_userid.
675 * 672 *
676 * @param session 673 * @param session
677 * @param userinfo User info message from server containing a 'body' field 674 * @param userinfo User info message from server containing a 'body' field
678 * with a 'UserID' key. This is where the user ID is taken from. 675 * with a 'UserID' key. This is where the user ID is taken from.
676 * Will be destroyed after use.
679 * @param data A send_im_cb_struct * of information on the IM to send. 677 * @param data A send_im_cb_struct * of information on the IM to send.
680 * 678 *
681 */ 679 */
682 void msim_send_im_by_userid_cb(MsimSession *session, GHashTable *userinfo, gpointer data) 680 void msim_send_im_by_userid_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
683 { 681 {
684 send_im_cb_struct *s; 682 send_im_cb_struct *s;
685 gchar *userid; 683 gchar *userid;
686 GHashTable *body; 684 GHashTable *body;
685 gchar *body_str;
687 686
688 g_return_if_fail(MSIM_SESSION_VALID(session)); 687 g_return_if_fail(MSIM_SESSION_VALID(session));
689 g_return_if_fail(userinfo != NULL); 688 g_return_if_fail(userinfo != NULL);
690 689
691 body = msim_parse_body(g_hash_table_lookup(userinfo, "body")); 690 body_str = msim_msg_get_string(userinfo, "body");
691 body = msim_parse_body(body_str);
692 g_free(body_str);
692 g_return_if_fail(body != NULL); 693 g_return_if_fail(body != NULL);
693 694
694 userid = g_hash_table_lookup(body, "UserID"); 695 userid = g_hash_table_lookup(body, "UserID");
695 696
696 s = (send_im_cb_struct *)data; 697 s = (send_im_cb_struct *)data;
697 msim_send_im_by_userid(session, userid, s->message, s->flags); 698 msim_send_im_by_userid(session, userid, s->message, s->flags);
698 699
699 g_hash_table_destroy(body); 700 g_hash_table_destroy(body);
700 g_hash_table_destroy(userinfo); 701 /* g_hash_table_destroy(userinfo); */
702 /* TODO: do we need to free userinfo here? */
703 msim_msg_free(userinfo);
701 g_free(s->message); 704 g_free(s->message);
702 g_free(s->who); 705 g_free(s->who);
703 } 706 }
704 707
705 /** 708 /**
707 * 710 *
708 * @param session 711 * @param session
709 * @param userinfo Message from server on user's info, containing UserName. 712 * @param userinfo Message from server on user's info, containing UserName.
710 * @param data A gchar * of the incoming instant message's text. 713 * @param data A gchar * of the incoming instant message's text.
711 */ 714 */
712 void msim_incoming_im_cb(MsimSession *session, GHashTable *userinfo, gpointer data) 715 void msim_incoming_im_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
713 { 716 {
714 gchar *msg; 717 gchar *msg, *username, *body_str;
715 gchar *username;
716 GHashTable *body; 718 GHashTable *body;
717 719
718 g_return_if_fail(MSIM_SESSION_VALID(session)); 720 g_return_if_fail(MSIM_SESSION_VALID(session));
719 g_return_if_fail(userinfo != NULL); 721 g_return_if_fail(userinfo != NULL);
720 722
721 body = msim_parse_body(g_hash_table_lookup(userinfo, "body")); 723 body_str = msim_msg_get_string(userinfo, "body");
724 body = msim_parse_body(body_str);
725 g_free(body);
722 g_return_if_fail(body != NULL); 726 g_return_if_fail(body != NULL);
723 727
724 username = g_hash_table_lookup(body, "UserName"); 728 username = g_hash_table_lookup(body, "UserName");
725 729
726 msg = (gchar *)data; 730 msg = (gchar *)data;
727 serv_got_im(session->gc, username, msg, PURPLE_MESSAGE_RECV, time(NULL)); 731 serv_got_im(session->gc, username, msg, PURPLE_MESSAGE_RECV, time(NULL));
728 732
733 msim_msg_free(userinfo); /* TODO: Should we? */
729 g_hash_table_destroy(body); 734 g_hash_table_destroy(body);
730 g_hash_table_destroy(userinfo);
731 } 735 }
732 736
733 /** 737 /**
734 * Handle an incoming message. 738 * Handle an incoming message.
735 * 739 *
736 * @param session The session 740 * @param session The session
737 * @param table Message from the server, containing 'f' (userid from) and 'msg'. 741 * @param msg Message from the server, containing 'f' (userid from) and 'msg'.
738 * 742 *
739 * @return 0, since table can be freed. 743 * @return 0, since msg can be freed.
740 */ 744 */
741 int msim_incoming_im(MsimSession *session, GHashTable *table) 745 int msim_incoming_im(MsimSession *session, MsimMessage *msg)
742 { 746 {
743 gchar *userid; 747 gchar *userid;
744 gchar *msg; 748 gchar *msg_text;
745 749
746 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0); 750 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
747 g_return_val_if_fail(table != NULL, 0); 751 g_return_val_if_fail(msg != NULL, 0);
748 752
749 753 /* TODO: where freed? */
750 userid = g_hash_table_lookup(table, "f"); 754 userid = msim_msg_get_string(msg, "f");
751 msg = g_hash_table_lookup(table, "msg"); 755 msg_text = msim_msg_get_string(msg, "msg");
752 756
753 purple_debug_info("msim", 757 purple_debug_info("msim",
754 "msim_incoming_im: got msg <%s> from <%s>, resolving username\n", 758 "msim_incoming_im: got msg <%s> from <%s>, resolving username\n",
755 msg, userid); 759 msg_text, userid);
756 760
757 msim_lookup_user(session, userid, msim_incoming_im_cb, g_strdup(msg)); 761 msim_lookup_user(session, userid, msim_incoming_im_cb, msg_text);
758 762
759 return 0; 763 return 0;
760 } 764 }
761 765
762 766
763 /** 767 /**
764 * Process a message. 768 * Process a message.
765 * 769 *
766 * @param gc Connection. 770 * @param gc Connection.
767 * @param table Any message from the server. 771 * @param msg Any message from the server.
768 * 772 *
769 * @return The return value of the function used to process the message, or -1 if 773 * @return The return value of the function used to process the message, or -1 if
770 * called with invalid parameters. 774 * called with invalid parameters.
771 */ 775 */
772 int msim_process(PurpleConnection *gc, MsimMessage *msg) 776 int msim_process(PurpleConnection *gc, MsimMessage *msg)
790 794
791 purple_debug_info("msim", "------------------------------\n"); 795 purple_debug_info("msim", "------------------------------\n");
792 } 796 }
793 #endif 797 #endif
794 798
795 /* TODO: convert to use MsimMessage. */ 799 if (msim_msg_get(msg, "nc"))
796 #if 0 800 {
797 if (g_hash_table_lookup(table, "nc")) 801 return msim_login_challenge(session, msg);
798 { 802 } else if (msim_msg_get(msg, "sesskey")) {
799 return msim_login_challenge(session, table);
800 } else if (g_hash_table_lookup(table, "sesskey")) {
801 purple_debug_info("msim", "SESSKEY=<%s>\n", (gchar *)g_hash_table_lookup(table, "sesskey"));
802 803
803 purple_connection_update_progress(gc, _("Connected"), 3, 4); 804 purple_connection_update_progress(gc, _("Connected"), 3, 4);
804 805
805 session->sesskey = g_strdup(g_hash_table_lookup(table, "sesskey")); 806 /* Freed in msim_session_destroy */
807 session->sesskey = msim_msg_get_string(msg, "sesskey");
808 purple_debug_info("msim", "SESSKEY=<%s>\n", session->sesskey);
806 809
807 /* Comes with: proof,profileid,userid,uniquenick -- all same values 810 /* Comes with: proof,profileid,userid,uniquenick -- all same values
808 * (at least for me). */ 811 * (at least for me). */
809 session->userid = g_strdup(g_hash_table_lookup(table, "userid")); 812 /* Freed in msim_session_destroy */
813 session->userid = msim_msg_get_string(msg, "userid");
810 814
811 purple_connection_set_state(gc, PURPLE_CONNECTED); 815 purple_connection_set_state(gc, PURPLE_CONNECTED);
812 816
813 return 0; 817 return 0;
814 } else if (g_hash_table_lookup(table, "bm")) { 818 } else if (msim_msg_get(msg, "bm")) {
815 guint bm; 819 guint bm;
816 820
817 bm = atoi(g_hash_table_lookup(table, "bm")); 821 bm = msim_msg_get_integer(msg, "bm");
818 switch (bm) 822 switch (bm)
819 { 823 {
820 case MSIM_BM_STATUS: 824 case MSIM_BM_STATUS:
821 return msim_status(session, table); 825 return msim_status(session, msg);
822 case MSIM_BM_INSTANT: 826 case MSIM_BM_INSTANT:
823 return msim_incoming_im(session, table); 827 return msim_incoming_im(session, msg);
824 default: 828 default:
825 /* Not really an IM, but show it for informational 829 /* Not really an IM, but show it for informational
826 * purposes during development. */ 830 * purposes during development. */
827 return msim_incoming_im(session, table); 831 return msim_incoming_im(session, msg);
828 } 832 }
829 833
830 if (bm == MSIM_BM_STATUS) 834 if (bm == MSIM_BM_STATUS)
831 { 835 {
832 return msim_status(session, table); 836 return msim_status(session, msg);
833 } else { /* else if strcmp(bm, "1") == 0) */ 837 } else { /* else if strcmp(bm, "1") == 0) */
834 return msim_incoming_im(session, table); 838 return msim_incoming_im(session, msg);
835 } 839 }
836 } else if (g_hash_table_lookup(table, "rid")) { 840 } else if (msim_msg_get(msg, "rid")) {
837 return msim_process_reply(session, table); 841 return msim_process_reply(session, msg);
838 } else if (g_hash_table_lookup(table, "error")) { 842 } else if (msim_msg_get(msg, "error")) {
839 return msim_error(session, table); 843 return msim_error(session, msg);
840 } else if (g_hash_table_lookup(table, "ka")) { 844 } else if (msim_msg_get(msg, "ka")) {
841 purple_debug_info("msim", "msim_process: got keep alive\n"); 845 purple_debug_info("msim", "msim_process: got keep alive\n");
842 return 0; 846 return 0;
843 } else { 847 } else {
844 /* TODO: dump unknown msgs to file, so user can send them to me 848 /* TODO: dump unknown msgs to file, so user can send them to me
845 * if they wish, to help add support for new messages (inspired 849 * if they wish, to help add support for new messages (inspired
846 * by Alexandr Shutko, who maintains OSCAR protocol documentation). */ 850 * by Alexandr Shutko, who maintains OSCAR protocol documentation). */
847 purple_debug_info("msim", "msim_process: unhandled message\n"); 851 purple_debug_info("msim", "msim_process: unhandled message\n");
848 return 0; 852 return 0;
849 } 853 }
850 #else
851 return 0;
852 #endif
853 } 854 }
854 855
855 /** 856 /**
856 * Process a message reply from the server. 857 * Process a message reply from the server.
857 * 858 *
858 * @param session 859 * @param session
859 * @param table Message reply from server. 860 * @param msg Message reply from server.
860 * 861 *
861 * @return 0, since the 'table' field is no longer needed. 862 * @return 0, since the 'msg' field is no longer needed.
862 */ 863 */
863 int msim_process_reply(MsimSession *session, GHashTable *table) 864 int msim_process_reply(MsimSession *session, MsimMessage *msg)
864 { 865 {
865 gchar *rid_str;
866
867 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0); 866 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
868 g_return_val_if_fail(table != NULL, 0); 867 g_return_val_if_fail(msg != NULL, 0);
869 868
870 rid_str = g_hash_table_lookup(table, "rid"); 869 if (msim_msg_get(msg, "rid")) /* msim_lookup_user sets callback for here */
871
872 if (rid_str) /* msim_lookup_user sets callback for here */
873 { 870 {
874 MSIM_USER_LOOKUP_CB cb; 871 MSIM_USER_LOOKUP_CB cb;
875 gpointer data; 872 gpointer data;
876 guint rid; 873 guint rid;
877
878 GHashTable *body; 874 GHashTable *body;
879 gchar *username; 875 gchar *username, *body_str;
880 876
881 rid = atol(rid_str); 877 rid = msim_msg_get_integer(msg, "rid");
882 878
883 /* Cache the user info. Currently, the GHashTable of user info in 879 /* Cache the user info. Currently, the GHashTable of user info in
884 * this cache never expires so is never freed. TODO: expire and destroy 880 * this cache never expires so is never freed. TODO: expire and destroy
885 * 881 *
886 * Some information never changes (username->userid map), some does. 882 * Some information never changes (username->userid map), some does.
887 * TODO: Cache what doesn't change only 883 * TODO: Cache what doesn't change only
888 */ 884 */
889 body = msim_parse_body(g_hash_table_lookup(table, "body")); 885 body_str = msim_msg_get_string(msg, "body");
886 body = msim_parse_body(body_str);
887 g_free(body_str);
888
889 /* TODO: implement a better hash-like interface, and use it. */
890 username = g_hash_table_lookup(body, "UserName"); 890 username = g_hash_table_lookup(body, "UserName");
891 if (username) 891 if (username)
892 { 892 {
893 /* TODO: permanently associated with blist item, if in buddy in blist */
893 g_hash_table_insert(session->user_lookup_cache, g_strdup(username), body); 894 g_hash_table_insert(session->user_lookup_cache, g_strdup(username), body);
894 } else { 895 } else {
895 purple_debug_info("msim", 896 purple_debug_info("msim",
896 "msim_process_reply: not caching <%s>, no UserName\n", 897 "msim_process_reply: not caching body, no UserName\n");
897 g_hash_table_lookup(table, "body"));
898 } 898 }
899 899
900 /* If a callback is registered for this userid lookup, call it. */ 900 /* If a callback is registered for this userid lookup, call it. */
901
902 cb = g_hash_table_lookup(session->user_lookup_cb, GUINT_TO_POINTER(rid)); 901 cb = g_hash_table_lookup(session->user_lookup_cb, GUINT_TO_POINTER(rid));
903 data = g_hash_table_lookup(session->user_lookup_cb_data, GUINT_TO_POINTER(rid)); 902 data = g_hash_table_lookup(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
904 903
905 if (cb) 904 if (cb)
906 { 905 {
907 purple_debug_info("msim", 906 purple_debug_info("msim",
908 "msim_process_body: calling callback now\n"); 907 "msim_process_body: calling callback now\n");
909 cb(session, table, data); 908 cb(session, msg, data);
910 g_hash_table_remove(session->user_lookup_cb, GUINT_TO_POINTER(rid)); 909 g_hash_table_remove(session->user_lookup_cb, GUINT_TO_POINTER(rid));
911 g_hash_table_remove(session->user_lookup_cb_data, GUINT_TO_POINTER(rid)); 910 g_hash_table_remove(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
912 911
913 /* Return 1 to tell caller of msim_process (msim_input_cb) to 912 /* Return 1 to tell caller of msim_process (msim_input_cb) to
914 * not destroy 'table'; allow 'cb' to hang on to it and destroy 913 * not destroy 'msg'; allow 'cb' to hang on to it and destroy
915 * it when it wants. */ 914 * it when it wants. */
916 return 1; 915 return 1;
917 } else { 916 } else {
918 purple_debug_info("msim", 917 purple_debug_info("msim",
919 "msim_process_body: no callback for rid %d\n", rid); 918 "msim_process_body: no callback for rid %d\n", rid);
924 923
925 /** 924 /**
926 * Handle an error from the server. 925 * Handle an error from the server.
927 * 926 *
928 * @param session 927 * @param session
929 * @param table The message. 928 * @param msg The message.
930 * 929 *
931 * @return 0, since 'table' can be freed. 930 * @return 0, since 'msg' can be freed.
932 */ 931 */
933 int msim_error(MsimSession *session, GHashTable *table) 932 int msim_error(MsimSession *session, MsimMessage *msg)
934 { 933 {
935 gchar *err, *errmsg, *full_errmsg; 934 gchar *errmsg, *full_errmsg;
935 guint err;
936 936
937 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0); 937 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
938 g_return_val_if_fail(table != NULL, 0); 938 g_return_val_if_fail(msg != NULL, 0);
939 939
940 err = g_hash_table_lookup(table, "err"); 940 err = msim_msg_get_integer(msg, "err");
941 errmsg = g_hash_table_lookup(table, "errmsg"); 941 errmsg = msim_msg_get_string(msg, "errmsg");
942 942
943 full_errmsg = g_strdup_printf(_("Protocol error, code %s: %s"), err, errmsg); 943 full_errmsg = g_strdup_printf(_("Protocol error, code %d: %s"), err, errmsg);
944
945 g_free(errmsg);
944 946
945 purple_debug_info("msim", "msim_error: %s\n", full_errmsg); 947 purple_debug_info("msim", "msim_error: %s\n", full_errmsg);
946 948
947 /* TODO: check 'fatal' and die if asked to. 949 /* TODO: check 'fatal' and die if asked to.
948 * TODO: do something with the error # (localization of errmsg?) */ 950 * TODO: do something with the error # (localization of errmsg?) */
949 purple_notify_error(session->account, g_strdup(_("MySpaceIM Error")), 951 purple_notify_error(session->account, g_strdup(_("MySpaceIM Error")),
950 full_errmsg, NULL); 952 full_errmsg, NULL);
951 953
952 if (g_hash_table_lookup(table, "fatal")) 954 if (msim_msg_get(msg, "fatal"))
953 { 955 {
954 purple_debug_info("msim", "fatal error, destroy session\n"); 956 purple_debug_info("msim", "fatal error, destroy session\n");
955 purple_connection_error(session->gc, full_errmsg); 957 purple_connection_error(session->gc, full_errmsg);
956 close(session->fd); 958 close(session->fd);
957 //msim_session_destroy(session); 959 //msim_session_destroy(session);
971 /** 973 /**
972 * Callback to update incoming status messages, after looked up username. 974 * Callback to update incoming status messages, after looked up username.
973 * 975 *
974 * @param session 976 * @param session
975 * @param userinfo Looked up user information from server. 977 * @param userinfo Looked up user information from server.
976 * @param data gchar * status string. 978 * @param data gchar * status string, will be freed.
977 * 979 *
978 */ 980 */
979 void msim_status_cb(MsimSession *session, GHashTable *userinfo, gpointer data) 981 void msim_status_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
980 { 982 {
981 PurpleBuddyList *blist; 983 PurpleBuddyList *blist;
982 PurpleBuddy *buddy; 984 PurpleBuddy *buddy;
983 PurplePresence *presence; 985 PurplePresence *presence;
984 GHashTable *body; 986 GHashTable *body;
987 gchar *body_str;
985 //PurpleStatus *status; 988 //PurpleStatus *status;
986 gchar **status_array; 989 gchar **status_array;
987 GList *list; 990 GList *list;
988 gchar *status_text, *status_code; 991 gchar *status_text, *status_code;
989 gchar *status_str; 992 gchar *status_str;
993 g_return_if_fail(MSIM_SESSION_VALID(session)); 996 g_return_if_fail(MSIM_SESSION_VALID(session));
994 g_return_if_fail(userinfo != NULL); 997 g_return_if_fail(userinfo != NULL);
995 998
996 status_str = (gchar *)data; 999 status_str = (gchar *)data;
997 1000
998 body = msim_parse_body(g_hash_table_lookup(userinfo, "body")); 1001 body_str = msim_msg_get_string(userinfo, "body");
1002 body = msim_parse_body(body_str);
1003 g_free(body_str);
999 g_return_if_fail(body != NULL); 1004 g_return_if_fail(body != NULL);
1000 1005
1001 username = g_hash_table_lookup(body, "UserName"); 1006 username = g_hash_table_lookup(body, "UserName");
1002 /* Note: DisplayName doesn't seem to be resolvable. It could be displayed on 1007 /* Note: DisplayName doesn't seem to be resolvable. It could be displayed on
1003 * the buddy list, if the UserID was stored along with it. */ 1008 * the buddy list, if the UserID was stored along with it. */
1049 /* purple_presence_set_status_active(presence, PURPLE_STATUS_AVAILABLE, TRUE); */ 1054 /* purple_presence_set_status_active(presence, PURPLE_STATUS_AVAILABLE, TRUE); */
1050 1055
1051 g_strfreev(status_array); 1056 g_strfreev(status_array);
1052 g_list_free(list); 1057 g_list_free(list);
1053 g_hash_table_destroy(body); 1058 g_hash_table_destroy(body);
1054 g_hash_table_destroy(userinfo); 1059 msim_msg_free(userinfo); /* TODO: right? */
1055 /* Do not free status_str - it will be freed by g_hash_table_destroy on session->userid_lookup_cb_data */ 1060 /* Do not free status_str - it will currently be freed by g_hash_table_destroy
1061 * on session->user_lookup_cb_data. But this is questionable (TODO: unask) since
1062 * sometimes user_lookup_cb_data stores integers in gpointers, and sometimes
1063 * real gpointers that need to be freed, like our status_str.
1064 */
1065 /* g_free(status_str); */
1056 } 1066 }
1057 1067
1058 /** 1068 /**
1059 * Process incoming status messages. 1069 * Process incoming status messages.
1060 * 1070 *
1061 * @param session 1071 * @param session
1062 * @param table Status update message. 1072 * @param msg Status update message.
1063 * 1073 *
1064 * @return 0, since 'table' can be freed. 1074 * @return 0, since 'msg' can be freed.
1065 */ 1075 */
1066 int msim_status(MsimSession *session, GHashTable *table) 1076 int msim_status(MsimSession *session, MsimMessage *msg)
1067 { 1077 {
1068 gchar *status_str; 1078 gchar *status_str;
1069 gchar *userid; 1079 gchar *userid;
1070 1080
1071 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0); 1081 g_return_val_if_fail(MSIM_SESSION_VALID(session), 0);
1072 g_return_val_if_fail(table != NULL, 0); 1082 g_return_val_if_fail(msg != NULL, 0);
1073 1083
1074 status_str = g_hash_table_lookup(table, "msg"); 1084 /* TODO: free */
1085 status_str = msim_msg_get_string(msg, "msg");
1075 if (!status_str) 1086 if (!status_str)
1076 { 1087 {
1077 purple_debug_info("msim", "msim_status: bm is status but no status msg\n"); 1088 purple_debug_info("msim", "msim_status: bm is status but no status msg\n");
1078 return 0; 1089 return 0;
1079 } 1090 }
1080 1091
1081 userid = g_hash_table_lookup(table, "f"); 1092 /* TODO: free */
1093 userid = msim_msg_get_string(msg, "f");
1082 if (!userid) 1094 if (!userid)
1083 { 1095 {
1084 purple_debug_info("msim", "msim_status: bm is status but no f field\n"); 1096 purple_debug_info("msim", "msim_status: bm is status but no f field\n");
1085 return 0; 1097 return 0;
1086 } 1098 }
1089 * before updating the status! Much more efficient. */ 1101 * before updating the status! Much more efficient. */
1090 purple_debug_info("msim", 1102 purple_debug_info("msim",
1091 "msim_status: got status msg <%s> for <%s>, scheduling lookup\n", 1103 "msim_status: got status msg <%s> for <%s>, scheduling lookup\n",
1092 status_str, userid); 1104 status_str, userid);
1093 1105
1094 /* Actually update status once obtain username */ 1106 /* Actually update status, once username is obtained.
1095 msim_lookup_user(session, userid, msim_status_cb, g_strdup(status_str)); 1107 * status_str() will currently be freed by g_hash_table_destroy() on
1108 * user_lookup_cb_data (TODO: this is questionable, since it can also
1109 * store gpointers. Fix this, and the 2 other TODOs of the same problem.)
1110 */
1111 msim_lookup_user(session, userid, msim_status_cb, status_str);
1096 1112
1097 return 0; 1113 return 0;
1098 } 1114 }
1099 1115
1100 1116
1273 session->magic = MSIM_SESSION_STRUCT_MAGIC; 1289 session->magic = MSIM_SESSION_STRUCT_MAGIC;
1274 session->account = acct; 1290 session->account = acct;
1275 session->gc = purple_account_get_connection(acct); 1291 session->gc = purple_account_get_connection(acct);
1276 session->fd = -1; 1292 session->fd = -1;
1277 session->user_lookup_cb = g_hash_table_new_full(g_direct_hash, 1293 session->user_lookup_cb = g_hash_table_new_full(g_direct_hash,
1278 g_direct_equal, NULL, NULL); /* do NOT free function pointers! */ 1294 g_direct_equal, NULL, NULL); /* do NOT free function pointers! (values) */
1279 session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash, 1295 session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash,
1280 g_direct_equal, NULL, g_free); 1296 g_direct_equal, NULL, g_free);/* TODO: we don't know what the values are,
1297 they could be integers inside gpointers
1298 or strings, but we free them anyway.
1299 Figure this out, once free cache. */
1281 session->user_lookup_cache = g_hash_table_new_full(g_str_hash, g_str_equal, 1300 session->user_lookup_cache = g_hash_table_new_full(g_str_hash, g_str_equal,
1282 g_free, (GDestroyNotify)g_hash_table_destroy); 1301 g_free, (GDestroyNotify)g_hash_table_destroy);
1283 session->rxoff = 0; 1302 session->rxoff = 0;
1284 session->rxbuf = g_new0(gchar, MSIM_READ_BUF_SIZE); 1303 session->rxbuf = g_new0(gchar, MSIM_READ_BUF_SIZE);
1285 session->next_rid = 1; 1304 session->next_rid = 1;