comparison libpurple/protocols/jabber/buddy.c @ 27590:a08e84032814

merge of '2348ff22f0ff3453774b8b25b36238465580c609' and 'e76f11543c2a4aa05bdf584f087cbe3439029661'
author Paul Aurich <paul@darkrain42.org>
date Sun, 12 Jul 2009 05:43:38 +0000
parents 95c56191d26c
children a12574d982a1
comparison
equal deleted inserted replaced
27104:048bcf41deef 27590:a08e84032814
159 JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource); 159 JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource);
160 if(!jbr) { 160 if(!jbr) {
161 jbr = g_new0(JabberBuddyResource, 1); 161 jbr = g_new0(JabberBuddyResource, 1);
162 jbr->jb = jb; 162 jbr->jb = jb;
163 jbr->name = g_strdup(resource); 163 jbr->name = g_strdup(resource);
164 jbr->capabilities = JABBER_CAP_XHTML; 164 jbr->capabilities = JABBER_CAP_NONE;
165 jbr->tz_off = PURPLE_NO_TZ_OFF; 165 jbr->tz_off = PURPLE_NO_TZ_OFF;
166 jb->resources = g_list_append(jb->resources, jbr); 166 jb->resources = g_list_append(jb->resources, jbr);
167 } 167 }
168 jbr->priority = priority; 168 jbr->priority = priority;
169 jbr->state = state; 169 jbr->state = state;
648 g_free(jbi->last_message); 648 g_free(jbi->last_message);
649 purple_notify_user_info_destroy(jbi->user_info); 649 purple_notify_user_info_destroy(jbi->user_info);
650 g_free(jbi); 650 g_free(jbi);
651 } 651 }
652 652
653 static void
654 add_jbr_info(JabberBuddyInfo *jbi, const char *resource,
655 JabberBuddyResource *jbr)
656 {
657 JabberBuddyInfoResource *jbir;
658 PurpleNotifyUserInfo *user_info;
659
660 jbir = g_hash_table_lookup(jbi->resources, resource);
661 user_info = jbi->user_info;
662
663 if (jbr && jbr->client.name) {
664 char *tmp =
665 g_strdup_printf("%s%s%s", jbr->client.name,
666 (jbr->client.version ? " " : ""),
667 (jbr->client.version ? jbr->client.version : ""));
668 purple_notify_user_info_prepend_pair(user_info, _("Client"), tmp);
669 g_free(tmp);
670
671 if (jbr->client.os)
672 purple_notify_user_info_prepend_pair(user_info, _("Operating System"), jbr->client.os);
673 }
674
675 if (jbr && jbr->tz_off != PURPLE_NO_TZ_OFF) {
676 time_t now_t;
677 struct tm *now;
678 char *timestamp;
679 time(&now_t);
680 now_t += jbr->tz_off;
681 now = gmtime(&now_t);
682
683 timestamp =
684 g_strdup_printf("%s %c%02d%02d", purple_time_format(now),
685 jbr->tz_off < 0 ? '-' : '+',
686 abs(jbr->tz_off / (60*60)),
687 abs((jbr->tz_off % (60*60)) / 60));
688 purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp);
689 g_free(timestamp);
690 }
691
692 if (jbir && jbir->idle_seconds > 0) {
693 char *idle = purple_str_seconds_to_string(jbir->idle_seconds);
694 purple_notify_user_info_prepend_pair(user_info, _("Idle"), idle);
695 g_free(idle);
696 }
697
698 if (jbr) {
699 char *purdy = NULL;
700 char *tmp;
701 char priority[12];
702 const char *status_name = jabber_buddy_state_get_name(jbr->state);
703
704 if (jbr->status) {
705 purdy = purple_strdup_withhtml(jbr->status);
706
707 if (purple_strequal(status_name, purdy))
708 status_name = NULL;
709 }
710
711 tmp = g_strdup_printf("%s%s%s", (status_name ? status_name : ""),
712 ((status_name && purdy) ? ": " : ""),
713 (purdy ? purdy : ""));
714 purple_notify_user_info_prepend_pair(user_info, _("Status"), tmp);
715
716 g_snprintf(priority, sizeof(priority), "%d", jbr->priority);
717 purple_notify_user_info_prepend_pair(user_info, _("Priority"), priority);
718
719 g_free(tmp);
720 g_free(purdy);
721 } else {
722 purple_notify_user_info_prepend_pair(user_info, _("Status"), _("Unknown"));
723 }
724 }
725
653 static void jabber_buddy_info_show_if_ready(JabberBuddyInfo *jbi) 726 static void jabber_buddy_info_show_if_ready(JabberBuddyInfo *jbi)
654 { 727 {
655 char *resource_name, *tmp; 728 char *resource_name;
656 JabberBuddyResource *jbr; 729 JabberBuddyResource *jbr;
657 JabberBuddyInfoResource *jbir = NULL;
658 GList *resources; 730 GList *resources;
659 PurpleNotifyUserInfo *user_info; 731 PurpleNotifyUserInfo *user_info;
660 732
661 /* not yet */ 733 /* not yet */
662 if(jbi->ids) 734 if (jbi->ids)
663 return; 735 return;
664 736
665 user_info = jbi->user_info; 737 user_info = jbi->user_info;
666 resource_name = jabber_get_resource(jbi->jid); 738 resource_name = jabber_get_resource(jbi->jid);
667 739
668 /* If we have one or more pairs from the vcard, put a section break above it */ 740 /* If we have one or more pairs from the vcard, put a section break above it */
669 if (purple_notify_user_info_get_entries(user_info)) 741 if (purple_notify_user_info_get_entries(user_info))
670 purple_notify_user_info_prepend_section_break(user_info); 742 purple_notify_user_info_prepend_section_break(user_info);
671 743
672 /* Prepend the primary buddy info to user_info so that it goes before the vcard. */ 744 /* Add the information about the user's resource(s) */
673 if(resource_name) { 745 if (resource_name) {
674 jbr = jabber_buddy_find_resource(jbi->jb, resource_name); 746 jbr = jabber_buddy_find_resource(jbi->jb, resource_name);
675 jbir = g_hash_table_lookup(jbi->resources, resource_name); 747 add_jbr_info(jbi, resource_name, jbr);
676 if(jbr && jbr->client.name) {
677 tmp = g_strdup_printf("%s%s%s", jbr->client.name,
678 (jbr->client.version ? " " : ""),
679 (jbr->client.version ? jbr->client.version : ""));
680 purple_notify_user_info_add_pair(user_info, _("Client"), tmp);
681 g_free(tmp);
682
683 if(jbr->client.os) {
684 purple_notify_user_info_prepend_pair(user_info, _("Operating System"), jbr->client.os);
685 }
686 }
687 if (jbr && jbr->tz_off != PURPLE_NO_TZ_OFF) {
688 time_t now_t;
689 struct tm *now;
690 char *timestamp;
691 time(&now_t);
692 now_t += jbr->tz_off;
693 now = gmtime(&now_t);
694
695 timestamp = g_strdup_printf("%s %c%02d%02d", purple_time_format(now),
696 jbr->tz_off < 0 ? '-' : '+',
697 abs(jbr->tz_off / (60*60)),
698 abs((jbr->tz_off % (60*60)) / 60));
699 purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp);
700 g_free(timestamp);
701 }
702 if(jbir) {
703 if(jbir->idle_seconds > 0) {
704 char *idle = purple_str_seconds_to_string(jbir->idle_seconds);
705 purple_notify_user_info_prepend_pair(user_info, _("Idle"), idle);
706 g_free(idle);
707 }
708 }
709 if(jbr) {
710 char *purdy = NULL;
711 const char *status_name = jabber_buddy_state_get_name(jbr->state);
712 if(jbr->status)
713 purdy = purple_strdup_withhtml(jbr->status);
714 if(status_name && purdy && !strcmp(status_name, purdy))
715 status_name = NULL;
716
717 tmp = g_strdup_printf("%s%s%s", (status_name ? status_name : ""),
718 ((status_name && purdy) ? ": " : ""),
719 (purdy ? purdy : ""));
720 purple_notify_user_info_prepend_pair(user_info, _("Status"), tmp);
721 g_free(tmp);
722 g_free(purdy);
723 } else {
724 purple_notify_user_info_prepend_pair(user_info, _("Status"), _("Unknown"));
725 }
726 #if 0
727 /* #if 0 this for now; I think this would be far more useful if we limited this to a particular set of features
728 * of particular interest (-vv jumps out as one). As it is now, I don't picture people getting all excited: "Oh sweet crap!
729 * So-and-so supports 'jabber:x:data' AND 'Collaborative Data Objects'!"
730 */
731
732 if(jbr && jbr->caps) {
733 GString *tmp = g_string_new("");
734 GList *iter;
735 for(iter = jbr->caps->features; iter; iter = g_list_next(iter)) {
736 const char *feature = iter->data;
737
738 if(!strcmp(feature, "jabber:iq:last"))
739 feature = _("Last Activity");
740 else if(!strcmp(feature, "http://jabber.org/protocol/disco#info"))
741 feature = _("Service Discovery Info");
742 else if(!strcmp(feature, "http://jabber.org/protocol/disco#items"))
743 feature = _("Service Discovery Items");
744 else if(!strcmp(feature, "http://jabber.org/protocol/address"))
745 feature = _("Extended Stanza Addressing");
746 else if(!strcmp(feature, "http://jabber.org/protocol/muc"))
747 feature = _("Multi-User Chat");
748 else if(!strcmp(feature, "http://jabber.org/protocol/muc#user"))
749 feature = _("Multi-User Chat Extended Presence Information");
750 else if(!strcmp(feature, "http://jabber.org/protocol/ibb"))
751 feature = _("In-Band Bytestreams");
752 else if(!strcmp(feature, "http://jabber.org/protocol/commands"))
753 feature = _("Ad-Hoc Commands");
754 else if(!strcmp(feature, "http://jabber.org/protocol/pubsub"))
755 feature = _("PubSub Service");
756 else if(!strcmp(feature, "http://jabber.org/protocol/bytestreams"))
757 feature = _("SOCKS5 Bytestreams");
758 else if(!strcmp(feature, "jabber:x:oob"))
759 feature = _("Out of Band Data");
760 else if(!strcmp(feature, "http://jabber.org/protocol/xhtml-im"))
761 feature = _("XHTML-IM");
762 else if(!strcmp(feature, "jabber:iq:register"))
763 feature = _("In-Band Registration");
764 else if(!strcmp(feature, "http://jabber.org/protocol/geoloc"))
765 feature = _("User Location");
766 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0084.html"))
767 feature = _("User Avatar");
768 else if(!strcmp(feature, "http://jabber.org/protocol/chatstates"))
769 feature = _("Chat State Notifications");
770 else if(!strcmp(feature, "jabber:iq:version"))
771 feature = _("Software Version");
772 else if(!strcmp(feature, "http://jabber.org/protocol/si"))
773 feature = _("Stream Initiation");
774 else if(!strcmp(feature, "http://jabber.org/protocol/si/profile/file-transfer"))
775 feature = _("File Transfer");
776 else if(!strcmp(feature, "http://jabber.org/protocol/mood"))
777 feature = _("User Mood");
778 else if(!strcmp(feature, "http://jabber.org/protocol/activity"))
779 feature = _("User Activity");
780 else if(!strcmp(feature, "http://jabber.org/protocol/caps"))
781 feature = _("Entity Capabilities");
782 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0116.html"))
783 feature = _("Encrypted Session Negotiations");
784 else if(!strcmp(feature, "http://jabber.org/protocol/tune"))
785 feature = _("User Tune");
786 else if(!strcmp(feature, "http://jabber.org/protocol/rosterx"))
787 feature = _("Roster Item Exchange");
788 else if(!strcmp(feature, "http://jabber.org/protocol/reach"))
789 feature = _("Reachability Address");
790 else if(!strcmp(feature, "http://jabber.org/protocol/profile"))
791 feature = _("User Profile");
792 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0166.html#ns"))
793 feature = _("Jingle");
794 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0167.html#ns"))
795 feature = _("Jingle Audio");
796 else if(!strcmp(feature, "http://jabber.org/protocol/nick"))
797 feature = _("User Nickname");
798 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0176.html#ns-udp"))
799 feature = _("Jingle ICE UDP");
800 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0176.html#ns-tcp"))
801 feature = _("Jingle ICE TCP");
802 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0177.html#ns"))
803 feature = _("Jingle Raw UDP");
804 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0180.html#ns"))
805 feature = _("Jingle Video");
806 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0181.html#ns"))
807 feature = _("Jingle DTMF");
808 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0184.html#ns"))
809 feature = _("Message Receipts");
810 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0189.html#ns"))
811 feature = _("Public Key Publishing");
812 else if(!strcmp(feature, "http://jabber.org/protocol/chatting"))
813 feature = _("User Chatting");
814 else if(!strcmp(feature, "http://jabber.org/protocol/browsing"))
815 feature = _("User Browsing");
816 else if(!strcmp(feature, "http://jabber.org/protocol/gaming"))
817 feature = _("User Gaming");
818 else if(!strcmp(feature, "http://jabber.org/protocol/viewing"))
819 feature = _("User Viewing");
820 else if(!strcmp(feature, "urn:xmpp:ping"))
821 feature = _("Ping");
822 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0200.html#ns"))
823 feature = _("Stanza Encryption");
824 else if(!strcmp(feature, "urn:xmpp:time"))
825 feature = _("Entity Time");
826 else if(!strcmp(feature, "urn:xmpp:delay"))
827 feature = _("Delayed Delivery");
828 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0204.html#ns"))
829 feature = _("Collaborative Data Objects");
830 else if(!strcmp(feature, "http://jabber.org/protocol/fileshare"))
831 feature = _("File Repository and Sharing");
832 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0215.html#ns"))
833 feature = _("STUN Service Discovery for Jingle");
834 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0116.html#ns"))
835 feature = _("Simplified Encrypted Session Negotiation");
836 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0219.html#ns"))
837 feature = _("Hop Check");
838 else if(g_str_has_suffix(feature, "+notify"))
839 feature = NULL;
840 if(feature)
841 g_string_append_printf(tmp, "%s<br/>", feature);
842 }
843
844 if(strlen(tmp->str) > 0)
845 purple_notify_user_info_prepend_pair(user_info, _("Capabilities"), tmp->str);
846
847 g_string_free(tmp, TRUE);
848 }
849 #endif
850 } else { 748 } else {
851 gboolean multiple_resources = jbi->jb->resources && jbi->jb->resources->next; 749 for (resources = jbi->jb->resources; resources; resources = resources->next) {
852
853 for(resources = jbi->jb->resources; resources; resources = resources->next) {
854 char *purdy = NULL;
855 const char *status_name = NULL;
856
857 jbr = resources->data; 750 jbr = resources->data;
858 751
859 /* put a section break between resources, this is not needed if 752 /* put a section break between resources, this is not needed if
860 we are at the first, because one was already added for the vcard 753 we are at the first, because one was already added for the vcard
861 section */ 754 section */
862 if (resources != jbi->jb->resources) { 755 if (resources != jbi->jb->resources)
863 purple_notify_user_info_prepend_section_break(user_info); 756 purple_notify_user_info_prepend_section_break(user_info);
864 } 757
865 758 add_jbr_info(jbi, jbr->name, jbr);
866 if(jbr->client.name) { 759
867 tmp = g_strdup_printf("%s%s%s", jbr->client.name, 760 if (jbr->name)
868 (jbr->client.version ? " " : ""),
869 (jbr->client.version ? jbr->client.version : ""));
870 purple_notify_user_info_prepend_pair(user_info,
871 _("Client"), tmp);
872 g_free(tmp);
873
874 if(jbr->client.os) {
875 purple_notify_user_info_prepend_pair(user_info, _("Operating System"), jbr->client.os);
876 }
877 }
878
879 if (jbr->tz_off != PURPLE_NO_TZ_OFF) {
880 time_t now_t;
881 struct tm *now;
882 char *timestamp;
883 time(&now_t);
884 now_t += jbr->tz_off;
885 now = gmtime(&now_t);
886
887 timestamp = g_strdup_printf("%s %c%02d%02d", purple_time_format(now),
888 jbr->tz_off < 0 ? '-' : '+',
889 abs(jbr->tz_off / (60*60)),
890 abs((jbr->tz_off % (60*60)) / 60));
891 purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp);
892 g_free(timestamp);
893 }
894
895 if(jbr->name && (jbir = g_hash_table_lookup(jbi->resources, jbr->name))) {
896 if(jbir->idle_seconds > 0) {
897 char *idle = purple_str_seconds_to_string(jbir->idle_seconds);
898 purple_notify_user_info_prepend_pair(user_info, _("Idle"), idle);
899 g_free(idle);
900 }
901 }
902
903 status_name = jabber_buddy_state_get_name(jbr->state);
904 if(jbr->status)
905 purdy = purple_strdup_withhtml(jbr->status);
906 if(status_name && purdy && !strcmp(status_name, purdy))
907 status_name = NULL;
908
909 tmp = g_strdup_printf("%s%s%s", (status_name ? status_name : ""),
910 ((status_name && purdy) ? ": " : ""),
911 (purdy ? purdy : ""));
912 purple_notify_user_info_prepend_pair(user_info, _("Status"), tmp);
913 g_free(tmp);
914 g_free(purdy);
915
916 if(multiple_resources) {
917 tmp = g_strdup_printf("%d", jbr->priority);
918 purple_notify_user_info_prepend_pair(user_info, _("Priority"), tmp);
919 g_free(tmp);
920 }
921
922 if(jbr->name)
923 purple_notify_user_info_prepend_pair(user_info, _("Resource"), jbr->name); 761 purple_notify_user_info_prepend_pair(user_info, _("Resource"), jbr->name);
924 #if 0
925 if(jbr && jbr->caps) {
926 GString *tmp = g_string_new("");
927 GList *iter;
928 for(iter = jbr->caps->features; iter; iter = g_list_next(iter)) {
929 const char *feature = iter->data;
930
931 if(!strcmp(feature, "jabber:iq:last"))
932 feature = _("Last Activity");
933 else if(!strcmp(feature, "http://jabber.org/protocol/disco#info"))
934 feature = _("Service Discovery Info");
935 else if(!strcmp(feature, "http://jabber.org/protocol/disco#items"))
936 feature = _("Service Discovery Items");
937 else if(!strcmp(feature, "http://jabber.org/protocol/address"))
938 feature = _("Extended Stanza Addressing");
939 else if(!strcmp(feature, "http://jabber.org/protocol/muc"))
940 feature = _("Multi-User Chat");
941 else if(!strcmp(feature, "http://jabber.org/protocol/muc#user"))
942 feature = _("Multi-User Chat Extended Presence Information");
943 else if(!strcmp(feature, "http://jabber.org/protocol/ibb"))
944 feature = _("In-Band Bytestreams");
945 else if(!strcmp(feature, "http://jabber.org/protocol/commands"))
946 feature = _("Ad-Hoc Commands");
947 else if(!strcmp(feature, "http://jabber.org/protocol/pubsub"))
948 feature = _("PubSub Service");
949 else if(!strcmp(feature, "http://jabber.org/protocol/bytestreams"))
950 feature = _("SOCKS5 Bytestreams");
951 else if(!strcmp(feature, "jabber:x:oob"))
952 feature = _("Out of Band Data");
953 else if(!strcmp(feature, "http://jabber.org/protocol/xhtml-im"))
954 feature = _("XHTML-IM");
955 else if(!strcmp(feature, "jabber:iq:register"))
956 feature = _("In-Band Registration");
957 else if(!strcmp(feature, "http://jabber.org/protocol/geoloc"))
958 feature = _("User Location");
959 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0084.html"))
960 feature = _("User Avatar");
961 else if(!strcmp(feature, "http://jabber.org/protocol/chatstates"))
962 feature = _("Chat State Notifications");
963 else if(!strcmp(feature, "jabber:iq:version"))
964 feature = _("Software Version");
965 else if(!strcmp(feature, "http://jabber.org/protocol/si"))
966 feature = _("Stream Initiation");
967 else if(!strcmp(feature, "http://jabber.org/protocol/si/profile/file-transfer"))
968 feature = _("File Transfer");
969 else if(!strcmp(feature, "http://jabber.org/protocol/mood"))
970 feature = _("User Mood");
971 else if(!strcmp(feature, "http://jabber.org/protocol/activity"))
972 feature = _("User Activity");
973 else if(!strcmp(feature, "http://jabber.org/protocol/caps"))
974 feature = _("Entity Capabilities");
975 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0116.html"))
976 feature = _("Encrypted Session Negotiations");
977 else if(!strcmp(feature, "http://jabber.org/protocol/tune"))
978 feature = _("User Tune");
979 else if(!strcmp(feature, "http://jabber.org/protocol/rosterx"))
980 feature = _("Roster Item Exchange");
981 else if(!strcmp(feature, "http://jabber.org/protocol/reach"))
982 feature = _("Reachability Address");
983 else if(!strcmp(feature, "http://jabber.org/protocol/profile"))
984 feature = _("User Profile");
985 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0166.html#ns"))
986 feature = _("Jingle");
987 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0167.html#ns"))
988 feature = _("Jingle Audio");
989 else if(!strcmp(feature, "http://jabber.org/protocol/nick"))
990 feature = _("User Nickname");
991 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0176.html#ns-udp"))
992 feature = _("Jingle ICE UDP");
993 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0176.html#ns-tcp"))
994 feature = _("Jingle ICE TCP");
995 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0177.html#ns"))
996 feature = _("Jingle Raw UDP");
997 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0180.html#ns"))
998 feature = _("Jingle Video");
999 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0181.html#ns"))
1000 feature = _("Jingle DTMF");
1001 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0184.html#ns"))
1002 feature = _("Message Receipts");
1003 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0189.html#ns"))
1004 feature = _("Public Key Publishing");
1005 else if(!strcmp(feature, "http://jabber.org/protocol/chatting"))
1006 feature = _("User Chatting");
1007 else if(!strcmp(feature, "http://jabber.org/protocol/browsing"))
1008 feature = _("User Browsing");
1009 else if(!strcmp(feature, "http://jabber.org/protocol/gaming"))
1010 feature = _("User Gaming");
1011 else if(!strcmp(feature, "http://jabber.org/protocol/viewing"))
1012 feature = _("User Viewing");
1013 else if(!strcmp(feature, "urn:xmpp:ping"))
1014 feature = _("Ping");
1015 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0200.html#ns"))
1016 feature = _("Stanza Encryption");
1017 else if(!strcmp(feature, "urn:xmpp:time"))
1018 feature = _("Entity Time");
1019 else if(!strcmp(feature, "urn:xmpp:delay"))
1020 feature = _("Delayed Delivery");
1021 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0204.html#ns"))
1022 feature = _("Collaborative Data Objects");
1023 else if(!strcmp(feature, "http://jabber.org/protocol/fileshare"))
1024 feature = _("File Repository and Sharing");
1025 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0215.html#ns"))
1026 feature = _("STUN Service Discovery for Jingle");
1027 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0116.html#ns"))
1028 feature = _("Simplified Encrypted Session Negotiation");
1029 else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0219.html#ns"))
1030 feature = _("Hop Check");
1031 else if(g_str_has_suffix(feature, "+notify"))
1032 feature = NULL;
1033
1034 if(feature)
1035 g_string_append_printf(tmp, "%s\n", feature);
1036 }
1037 if(strlen(tmp->str) > 0)
1038 purple_notify_user_info_prepend_pair(user_info, _("Capabilities"), tmp->str);
1039
1040 g_string_free(tmp, TRUE);
1041 }
1042 #endif
1043 } 762 }
1044 } 763 }
1045 764
1046 if (!jbi->jb->resources) { 765 if (!jbi->jb->resources) {
1047 /* the buddy is offline */ 766 /* the buddy is offline */
1048 gchar *status = 767 gchar *status =
1049 g_strdup_printf("%s%s%s", _("Offline"), 768 g_strdup_printf("%s%s%s", _("Offline"),
1050 jbi->last_message ? ": " : "", 769 jbi->last_message ? ": " : "",
1051 jbi->last_message ? jbi->last_message : ""); 770 jbi->last_message ? jbi->last_message : "");
1052 if (jbi->last_seconds > 0) { 771 if (jbi->last_seconds > 0) {
1053 char *last = purple_str_seconds_to_string(jbi->last_seconds); 772 char *last = purple_str_seconds_to_string(jbi->last_seconds);
1054 gchar *message = g_strdup_printf(_("%s ago"), last); 773 gchar *message = g_strdup_printf(_("%s ago"), last);
1055 purple_notify_user_info_prepend_pair(user_info, 774 purple_notify_user_info_prepend_pair(user_info,
1056 _("Logged off"), message); 775 _("Logged Off"), message);
1057 g_free(last); 776 g_free(last);
1058 g_free(message); 777 g_free(message);
1059 } 778 }
1060 purple_notify_user_info_prepend_pair(user_info, _("Status"), status); 779 purple_notify_user_info_prepend_pair(user_info, _("Status"), status);
1061 g_free(status); 780 g_free(status);
1063 782
1064 g_free(resource_name); 783 g_free(resource_name);
1065 784
1066 purple_notify_userinfo(jbi->js->gc, jbi->jid, user_info, NULL, NULL); 785 purple_notify_userinfo(jbi->js->gc, jbi->jid, user_info, NULL, NULL);
1067 786
1068 while(jbi->vcard_imgids) { 787 while (jbi->vcard_imgids) {
1069 purple_imgstore_unref_by_id(GPOINTER_TO_INT(jbi->vcard_imgids->data)); 788 purple_imgstore_unref_by_id(GPOINTER_TO_INT(jbi->vcard_imgids->data));
1070 jbi->vcard_imgids = g_slist_delete_link(jbi->vcard_imgids, jbi->vcard_imgids); 789 jbi->vcard_imgids = g_slist_delete_link(jbi->vcard_imgids, jbi->vcard_imgids);
1071 } 790 }
1072 791
1073 jbi->js->pending_buddy_info_requests = g_slist_remove(jbi->js->pending_buddy_info_requests, jbi); 792 jbi->js->pending_buddy_info_requests = g_slist_remove(jbi->js->pending_buddy_info_requests, jbi);
1100 { 819 {
1101 xmlnode *vcard, *photo, *binval; 820 xmlnode *vcard, *photo, *binval;
1102 char *txt, *vcard_hash = NULL; 821 char *txt, *vcard_hash = NULL;
1103 822
1104 if (type == JABBER_IQ_ERROR) { 823 if (type == JABBER_IQ_ERROR) {
1105 purple_debug_warning("jabber", "Server returned error while retrieving vCard"); 824 xmlnode *error;
1106 return; 825 purple_debug_warning("jabber", "Server returned error while retrieving vCard\n");
826
827 error = xmlnode_get_child(packet, "error");
828 if (!error || !xmlnode_get_child(error, "item-not-found"))
829 return;
1107 } 830 }
1108 831
1109 if((vcard = xmlnode_get_child(packet, "vCard")) || 832 if((vcard = xmlnode_get_child(packet, "vCard")) ||
1110 (vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) 833 (vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp")))
1111 { 834 {
1654 } 1377 }
1655 1378
1656 return FALSE; 1379 return FALSE;
1657 } 1380 }
1658 1381
1382 static void
1383 dispatch_queries_for_resource(JabberStream *js, JabberBuddyInfo *jbi,
1384 gboolean is_bare_jid, const char *jid,
1385 JabberBuddyResource *jbr)
1386 {
1387 JabberIq *iq;
1388 JabberBuddyInfoResource *jbir;
1389 char *full_jid = NULL;
1390 const char *to;
1391
1392 g_return_if_fail(jbr->name != NULL);
1393
1394 if (is_bare_jid) {
1395 full_jid = g_strdup_printf("%s/%s", jid, jbr->name);
1396 to = full_jid;
1397 } else
1398 to = jid;
1399
1400 jbir = g_new0(JabberBuddyInfoResource, 1);
1401 g_hash_table_insert(jbi->resources, g_strdup(jbr->name), jbir);
1402
1403 if(!jbr->client.name) {
1404 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:version");
1405 xmlnode_set_attrib(iq->node, "to", to);
1406 jabber_iq_set_callback(iq, jabber_version_parse, jbi);
1407 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
1408 jabber_iq_send(iq);
1409 }
1410
1411 /* this is to fix the feeling of irritation I get when trying
1412 * to get info on a friend running Trillian, which doesn't
1413 * respond (with an error or otherwise) to jabber:iq:last
1414 * requests. There are a number of Trillian users in my
1415 * office. */
1416 if(!_client_is_blacklisted(jbr, "jabber:iq:last")) {
1417 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last");
1418 xmlnode_set_attrib(iq->node, "to", to);
1419 jabber_iq_set_callback(iq, jabber_last_parse, jbi);
1420 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
1421 jabber_iq_send(iq);
1422 }
1423
1424 if (jbr->tz_off == PURPLE_NO_TZ_OFF &&
1425 (!jbr->caps.info ||
1426 jabber_resource_has_capability(jbr, "urn:xmpp:time"))) {
1427 xmlnode *child;
1428 iq = jabber_iq_new(js, JABBER_IQ_GET);
1429 xmlnode_set_attrib(iq->node, "to", to);
1430 child = xmlnode_new_child(iq->node, "time");
1431 xmlnode_set_namespace(child, "urn:xmpp:time");
1432 jabber_iq_set_callback(iq, jabber_time_parse, jbi);
1433 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
1434 jabber_iq_send(iq);
1435 }
1436
1437 g_free(full_jid);
1438 }
1439
1659 static void jabber_buddy_get_info_for_jid(JabberStream *js, const char *jid) 1440 static void jabber_buddy_get_info_for_jid(JabberStream *js, const char *jid)
1660 { 1441 {
1661 JabberIq *iq; 1442 JabberIq *iq;
1662 xmlnode *vcard; 1443 xmlnode *vcard;
1663 GList *resources; 1444 GList *resources;
1664 JabberBuddy *jb; 1445 JabberBuddy *jb;
1665 JabberBuddyInfo *jbi; 1446 JabberBuddyInfo *jbi;
1447 const char *slash;
1448 gboolean is_bare_jid;
1666 1449
1667 jb = jabber_buddy_find(js, jid, TRUE); 1450 jb = jabber_buddy_find(js, jid, TRUE);
1668 1451
1669 /* invalid JID */ 1452 /* invalid JID */
1670 if(!jb) 1453 if(!jb)
1671 return; 1454 return;
1455
1456 slash = strchr(jid, '/');
1457 is_bare_jid = (slash == NULL);
1672 1458
1673 jbi = g_new0(JabberBuddyInfo, 1); 1459 jbi = g_new0(JabberBuddyInfo, 1);
1674 jbi->jid = g_strdup(jid); 1460 jbi->jid = g_strdup(jid);
1675 jbi->js = js; 1461 jbi->js = js;
1676 jbi->jb = jb; 1462 jbi->jb = jb;
1686 jabber_iq_set_callback(iq, jabber_vcard_parse, jbi); 1472 jabber_iq_set_callback(iq, jabber_vcard_parse, jbi);
1687 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); 1473 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
1688 1474
1689 jabber_iq_send(iq); 1475 jabber_iq_send(iq);
1690 1476
1691 for(resources = jb->resources; resources; resources = resources->next) 1477 if (is_bare_jid) {
1692 { 1478 for(resources = jb->resources; resources; resources = resources->next) {
1693 JabberBuddyResource *jbr = resources->data; 1479 JabberBuddyResource *jbr = resources->data;
1694 JabberBuddyInfoResource *jbir; 1480 dispatch_queries_for_resource(js, jbi, is_bare_jid, jid, jbr);
1695 char *full_jid; 1481 }
1696 1482 } else {
1697 if ((strchr(jid, '/') == NULL) && (jbr->name != NULL)) { 1483 JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, slash + 1);
1698 full_jid = g_strdup_printf("%s/%s", jid, jbr->name); 1484 if (jbr)
1699 } else { 1485 dispatch_queries_for_resource(js, jbi, is_bare_jid, jid, jbr);
1700 full_jid = g_strdup(jid); 1486 else
1701 } 1487 purple_debug_warning("jabber", "jabber_buddy_get_info_for_jid() "
1702 1488 "was passed JID %s, but there is no corresponding "
1703 if (jbr->name != NULL) 1489 "JabberBuddyResource!\n", jid);
1704 { 1490 }
1705 jbir = g_new0(JabberBuddyInfoResource, 1); 1491
1706 g_hash_table_insert(jbi->resources, g_strdup(jbr->name), jbir); 1492 if (!jb->resources && is_bare_jid) {
1707 }
1708
1709 if(!jbr->client.name) {
1710 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:version");
1711 xmlnode_set_attrib(iq->node, "to", full_jid);
1712 jabber_iq_set_callback(iq, jabber_version_parse, jbi);
1713 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
1714 jabber_iq_send(iq);
1715 }
1716
1717 /* this is to fix the feeling of irritation I get when trying
1718 * to get info on a friend running Trillian, which doesn't
1719 * respond (with an error or otherwise) to jabber:iq:last
1720 * requests. There are a number of Trillian users in my
1721 * office. */
1722 if(!_client_is_blacklisted(jbr, "jabber:iq:last")) {
1723 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last");
1724 xmlnode_set_attrib(iq->node, "to", full_jid);
1725 jabber_iq_set_callback(iq, jabber_last_parse, jbi);
1726 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
1727 jabber_iq_send(iq);
1728 }
1729
1730 if (jbr->tz_off == PURPLE_NO_TZ_OFF &&
1731 (!jbr->caps.info ||
1732 jabber_resource_has_capability(jbr, "urn:xmpp:time"))) {
1733 xmlnode *child;
1734 iq = jabber_iq_new(js, JABBER_IQ_GET);
1735 xmlnode_set_attrib(iq->node, "to", full_jid);
1736 child = xmlnode_new_child(iq->node, "time");
1737 xmlnode_set_namespace(child, "urn:xmpp:time");
1738 jabber_iq_set_callback(iq, jabber_time_parse, jbi);
1739 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
1740 jabber_iq_send(iq);
1741 }
1742
1743 g_free(full_jid);
1744 }
1745
1746 if (!jb->resources && strchr(jid, '/') == NULL) {
1747 /* user is offline, send a jabber:iq:last to find out last time online */ 1493 /* user is offline, send a jabber:iq:last to find out last time online */
1748 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last"); 1494 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last");
1749 xmlnode_set_attrib(iq->node, "to", jid); 1495 xmlnode_set_attrib(iq->node, "to", jid);
1750 jabber_iq_set_callback(iq, jabber_last_offline_parse, jbi); 1496 jabber_iq_set_callback(iq, jabber_last_offline_parse, jbi);
1751 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); 1497 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
2072 return JABBER_BUDDY_STATE_ERROR; 1818 return JABBER_BUDDY_STATE_ERROR;
2073 1819
2074 return JABBER_BUDDY_STATE_UNKNOWN; 1820 return JABBER_BUDDY_STATE_UNKNOWN;
2075 } 1821 }
2076 1822
2077 JabberBuddyState jabber_buddy_show_get_state(const char *id) { 1823 const struct {
2078 if(!id) 1824 const char *name;
2079 return JABBER_BUDDY_STATE_UNKNOWN; 1825 JabberBuddyState state;
2080 if(!strcmp(id, "available")) 1826 } show_state_pairs[] = {
2081 return JABBER_BUDDY_STATE_ONLINE; 1827 { "available", JABBER_BUDDY_STATE_ONLINE },
2082 if(!strcmp(id, "chat")) 1828 { "chat", JABBER_BUDDY_STATE_CHAT },
2083 return JABBER_BUDDY_STATE_CHAT; 1829 { "away", JABBER_BUDDY_STATE_AWAY },
2084 if(!strcmp(id, "away")) 1830 { "xa", JABBER_BUDDY_STATE_XA },
2085 return JABBER_BUDDY_STATE_AWAY; 1831 { "dnd", JABBER_BUDDY_STATE_DND },
2086 if(!strcmp(id, "xa")) 1832 { "offline", JABBER_BUDDY_STATE_UNAVAILABLE },
2087 return JABBER_BUDDY_STATE_XA; 1833 { "error", JABBER_BUDDY_STATE_ERROR },
2088 if(!strcmp(id, "dnd")) 1834 { NULL, JABBER_BUDDY_STATE_UNKNOWN }
2089 return JABBER_BUDDY_STATE_DND; 1835 };
2090 if(!strcmp(id, "offline")) 1836
2091 return JABBER_BUDDY_STATE_UNAVAILABLE; 1837 JabberBuddyState jabber_buddy_show_get_state(const char *id)
2092 if(!strcmp(id, "error")) 1838 {
2093 return JABBER_BUDDY_STATE_ERROR; 1839 int i;
2094 1840
1841 g_return_val_if_fail(id != NULL, JABBER_BUDDY_STATE_UNKNOWN);
1842
1843 for (i = 0; show_state_pairs[i].name; ++i)
1844 if (g_str_equal(id, show_state_pairs[i].name))
1845 return show_state_pairs[i].state;
1846
1847 purple_debug_warning("jabber", "Invalid value of presence <show/> "
1848 "attribute: %s\n", id);
2095 return JABBER_BUDDY_STATE_UNKNOWN; 1849 return JABBER_BUDDY_STATE_UNKNOWN;
2096 } 1850 }
2097 1851
2098 const char *jabber_buddy_state_get_show(JabberBuddyState state) { 1852 const char *
2099 switch(state) { 1853 jabber_buddy_state_get_show(JabberBuddyState state)
2100 case JABBER_BUDDY_STATE_CHAT: 1854 {
2101 return "chat"; 1855 int i;
2102 case JABBER_BUDDY_STATE_AWAY: 1856
2103 return "away"; 1857 for (i = 0; show_state_pairs[i].name; ++i)
2104 case JABBER_BUDDY_STATE_XA: 1858 if (state == show_state_pairs[i].state)
2105 return "xa"; 1859 return show_state_pairs[i].name;
2106 case JABBER_BUDDY_STATE_DND: 1860
2107 return "dnd"; 1861 /* purple_debug_warning("jabber", "Unknown buddy state: %d\n", state); */
2108 case JABBER_BUDDY_STATE_ONLINE:
2109 return "available";
2110 case JABBER_BUDDY_STATE_UNKNOWN:
2111 case JABBER_BUDDY_STATE_ERROR:
2112 return NULL;
2113 case JABBER_BUDDY_STATE_UNAVAILABLE:
2114 return "offline";
2115 }
2116 return NULL; 1862 return NULL;
2117 } 1863 }
2118 1864
2119 const char *jabber_buddy_state_get_status_id(JabberBuddyState state) { 1865 const char *jabber_buddy_state_get_status_id(JabberBuddyState state) {
2120 switch(state) { 1866 switch(state) {
2478 { 2224 {
2479 const GList *node = NULL; 2225 const GList *node = NULL;
2480 const JabberCapsNodeExts *exts; 2226 const JabberCapsNodeExts *exts;
2481 2227
2482 if (!jbr->caps.info) { 2228 if (!jbr->caps.info) {
2483 purple_debug_error("jabber", 2229 purple_debug_info("jabber",
2484 "Unable to find caps: nothing known about buddy\n"); 2230 "Unable to find caps: nothing known about buddy\n");
2485 return FALSE; 2231 return FALSE;
2486 } 2232 }
2487 2233
2488 node = g_list_find_custom(jbr->caps.info->features, cap, (GCompareFunc)strcmp); 2234 node = g_list_find_custom(jbr->caps.info->features, cap, (GCompareFunc)strcmp);
2496 if (features) 2242 if (features)
2497 node = g_list_find_custom(features, cap, (GCompareFunc)strcmp); 2243 node = g_list_find_custom(features, cap, (GCompareFunc)strcmp);
2498 } 2244 }
2499 } 2245 }
2500 2246
2501 /* TODO: Are these messages actually useful? */
2502 if (node)
2503 purple_debug_info("jabber", "Found cap: %s\n", cap);
2504 else
2505 purple_debug_info("jabber", "Cap %s not found\n", cap);
2506
2507 return (node != NULL); 2247 return (node != NULL);
2508 } 2248 }
2509 2249
2510 gboolean 2250 gboolean
2511 jabber_buddy_has_capability(const JabberBuddy *jb, const gchar *cap) 2251 jabber_buddy_has_capability(const JabberBuddy *jb, const gchar *cap)