diff 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
line wrap: on
line diff
--- a/libpurple/protocols/jabber/buddy.c	Sun Jul 12 05:42:40 2009 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Sun Jul 12 05:43:38 2009 +0000
@@ -161,7 +161,7 @@
 		jbr = g_new0(JabberBuddyResource, 1);
 		jbr->jb = jb;
 		jbr->name = g_strdup(resource);
-		jbr->capabilities = JABBER_CAP_XHTML;
+		jbr->capabilities = JABBER_CAP_NONE;
 		jbr->tz_off = PURPLE_NO_TZ_OFF;
 		jb->resources = g_list_append(jb->resources, jbr);
 	}
@@ -650,16 +650,88 @@
 	g_free(jbi);
 }
 
+static void
+add_jbr_info(JabberBuddyInfo *jbi, const char *resource,
+             JabberBuddyResource *jbr)
+{
+	JabberBuddyInfoResource *jbir;
+	PurpleNotifyUserInfo *user_info;
+
+	jbir = g_hash_table_lookup(jbi->resources, resource);
+	user_info = jbi->user_info;
+
+	if (jbr && jbr->client.name) {
+		char *tmp =
+			g_strdup_printf("%s%s%s", jbr->client.name,
+		                    (jbr->client.version ? " " : ""),
+		                    (jbr->client.version ? jbr->client.version : ""));
+		purple_notify_user_info_prepend_pair(user_info, _("Client"), tmp);
+		g_free(tmp);
+
+		if (jbr->client.os)
+			purple_notify_user_info_prepend_pair(user_info, _("Operating System"), jbr->client.os);
+	}
+
+	if (jbr && jbr->tz_off != PURPLE_NO_TZ_OFF) {
+		time_t now_t;
+		struct tm *now;
+		char *timestamp;
+		time(&now_t);
+		now_t += jbr->tz_off;
+		now = gmtime(&now_t);
+
+		timestamp =
+			g_strdup_printf("%s %c%02d%02d", purple_time_format(now),
+		                    jbr->tz_off < 0 ? '-' : '+',
+		                    abs(jbr->tz_off / (60*60)),
+		                    abs((jbr->tz_off % (60*60)) / 60));
+		purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp);
+		g_free(timestamp);
+	}
+
+	if (jbir && jbir->idle_seconds > 0) {
+		char *idle = purple_str_seconds_to_string(jbir->idle_seconds);
+		purple_notify_user_info_prepend_pair(user_info, _("Idle"), idle);
+		g_free(idle);
+	}
+
+	if (jbr) {
+		char *purdy = NULL;
+		char *tmp;
+		char priority[12];
+		const char *status_name = jabber_buddy_state_get_name(jbr->state);
+
+		if (jbr->status) {
+			purdy = purple_strdup_withhtml(jbr->status);
+
+			if (purple_strequal(status_name, purdy))
+				status_name = NULL;
+		}
+
+		tmp = g_strdup_printf("%s%s%s", (status_name ? status_name : ""),
+						((status_name && purdy) ? ": " : ""),
+						(purdy ? purdy : ""));
+		purple_notify_user_info_prepend_pair(user_info, _("Status"), tmp);
+
+		g_snprintf(priority, sizeof(priority), "%d", jbr->priority);
+		purple_notify_user_info_prepend_pair(user_info, _("Priority"), priority);
+
+		g_free(tmp);
+		g_free(purdy);
+	} else {
+		purple_notify_user_info_prepend_pair(user_info, _("Status"), _("Unknown"));
+	}
+}
+
 static void jabber_buddy_info_show_if_ready(JabberBuddyInfo *jbi)
 {
-	char *resource_name, *tmp;
+	char *resource_name;
 	JabberBuddyResource *jbr;
-	JabberBuddyInfoResource *jbir = NULL;
 	GList *resources;
 	PurpleNotifyUserInfo *user_info;
 
 	/* not yet */
-	if(jbi->ids)
+	if (jbi->ids)
 		return;
 
 	user_info = jbi->user_info;
@@ -669,377 +741,24 @@
 	if (purple_notify_user_info_get_entries(user_info))
 		purple_notify_user_info_prepend_section_break(user_info);
 
-	/* Prepend the primary buddy info to user_info so that it goes before the vcard. */
-	if(resource_name) {
+	/* Add the information about the user's resource(s) */
+	if (resource_name) {
 		jbr = jabber_buddy_find_resource(jbi->jb, resource_name);
-		jbir = g_hash_table_lookup(jbi->resources, resource_name);
-		if(jbr && jbr->client.name) {
-			tmp = g_strdup_printf("%s%s%s", jbr->client.name,
-								  (jbr->client.version ? " " : ""),
-								  (jbr->client.version ? jbr->client.version : ""));
-			purple_notify_user_info_add_pair(user_info, _("Client"), tmp);
-			g_free(tmp);
-
-			if(jbr->client.os) {
-				purple_notify_user_info_prepend_pair(user_info, _("Operating System"), jbr->client.os);
-			}
-		}
-		if (jbr && jbr->tz_off != PURPLE_NO_TZ_OFF) {
-			time_t now_t;
-			struct tm *now;
-			char *timestamp;
-			time(&now_t);
-			now_t += jbr->tz_off;
-			now = gmtime(&now_t);
-
-			timestamp = g_strdup_printf("%s %c%02d%02d", purple_time_format(now),
-			                            jbr->tz_off < 0 ? '-' : '+',
-			                            abs(jbr->tz_off / (60*60)),
-			                            abs((jbr->tz_off % (60*60)) / 60));
-			purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp);
-			g_free(timestamp);
-		}
-		if(jbir) {
-			if(jbir->idle_seconds > 0) {
-				char *idle = purple_str_seconds_to_string(jbir->idle_seconds);
-				purple_notify_user_info_prepend_pair(user_info, _("Idle"), idle);
-				g_free(idle);
-			}
-		}
-		if(jbr) {
-			char *purdy = NULL;
-			const char *status_name = jabber_buddy_state_get_name(jbr->state);
-			if(jbr->status)
-				purdy = purple_strdup_withhtml(jbr->status);
-			if(status_name && purdy && !strcmp(status_name, purdy))
-				status_name = NULL;
-
-			tmp = g_strdup_printf("%s%s%s", (status_name ? status_name : ""),
-							((status_name && purdy) ? ": " : ""),
-							(purdy ? purdy : ""));
-			purple_notify_user_info_prepend_pair(user_info, _("Status"), tmp);
-			g_free(tmp);
-			g_free(purdy);
-		} else {
-			purple_notify_user_info_prepend_pair(user_info, _("Status"), _("Unknown"));
-		}
-#if 0
-		/* #if 0 this for now; I think this would be far more useful if we limited this to a particular set of features
- 		 * of particular interest (-vv jumps out as one). As it is now, I don't picture people getting all excited: "Oh sweet crap!
- 		 * So-and-so supports 'jabber:x:data' AND 'Collaborative Data Objects'!"
- 		 */
-
-		if(jbr && jbr->caps) {
-			GString *tmp = g_string_new("");
-			GList *iter;
-			for(iter = jbr->caps->features; iter; iter = g_list_next(iter)) {
-				const char *feature = iter->data;
-
-				if(!strcmp(feature, "jabber:iq:last"))
-					feature = _("Last Activity");
-				else if(!strcmp(feature, "http://jabber.org/protocol/disco#info"))
-					feature = _("Service Discovery Info");
-				else if(!strcmp(feature, "http://jabber.org/protocol/disco#items"))
-					feature = _("Service Discovery Items");
-				else if(!strcmp(feature, "http://jabber.org/protocol/address"))
-					feature = _("Extended Stanza Addressing");
-				else if(!strcmp(feature, "http://jabber.org/protocol/muc"))
-					feature = _("Multi-User Chat");
-				else if(!strcmp(feature, "http://jabber.org/protocol/muc#user"))
-					feature = _("Multi-User Chat Extended Presence Information");
-				else if(!strcmp(feature, "http://jabber.org/protocol/ibb"))
-					feature = _("In-Band Bytestreams");
-				else if(!strcmp(feature, "http://jabber.org/protocol/commands"))
-					feature = _("Ad-Hoc Commands");
-				else if(!strcmp(feature, "http://jabber.org/protocol/pubsub"))
-					feature = _("PubSub Service");
-				else if(!strcmp(feature, "http://jabber.org/protocol/bytestreams"))
-					feature = _("SOCKS5 Bytestreams");
-				else if(!strcmp(feature, "jabber:x:oob"))
-					feature = _("Out of Band Data");
-				else if(!strcmp(feature, "http://jabber.org/protocol/xhtml-im"))
-					feature = _("XHTML-IM");
-				else if(!strcmp(feature, "jabber:iq:register"))
-					feature = _("In-Band Registration");
-				else if(!strcmp(feature, "http://jabber.org/protocol/geoloc"))
-					feature = _("User Location");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0084.html"))
-					feature = _("User Avatar");
-				else if(!strcmp(feature, "http://jabber.org/protocol/chatstates"))
-					feature = _("Chat State Notifications");
-				else if(!strcmp(feature, "jabber:iq:version"))
-					feature = _("Software Version");
-				else if(!strcmp(feature, "http://jabber.org/protocol/si"))
-					feature = _("Stream Initiation");
-				else if(!strcmp(feature, "http://jabber.org/protocol/si/profile/file-transfer"))
-					feature = _("File Transfer");
-				else if(!strcmp(feature, "http://jabber.org/protocol/mood"))
-					feature = _("User Mood");
-				else if(!strcmp(feature, "http://jabber.org/protocol/activity"))
-					feature = _("User Activity");
-				else if(!strcmp(feature, "http://jabber.org/protocol/caps"))
-					feature = _("Entity Capabilities");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0116.html"))
-					feature = _("Encrypted Session Negotiations");
-				else if(!strcmp(feature, "http://jabber.org/protocol/tune"))
-					feature = _("User Tune");
-				else if(!strcmp(feature, "http://jabber.org/protocol/rosterx"))
-					feature = _("Roster Item Exchange");
-				else if(!strcmp(feature, "http://jabber.org/protocol/reach"))
-					feature = _("Reachability Address");
-				else if(!strcmp(feature, "http://jabber.org/protocol/profile"))
-					feature = _("User Profile");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0166.html#ns"))
-					feature = _("Jingle");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0167.html#ns"))
-					feature = _("Jingle Audio");
-				else if(!strcmp(feature, "http://jabber.org/protocol/nick"))
-					feature = _("User Nickname");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0176.html#ns-udp"))
-					feature = _("Jingle ICE UDP");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0176.html#ns-tcp"))
-					feature = _("Jingle ICE TCP");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0177.html#ns"))
-					feature = _("Jingle Raw UDP");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0180.html#ns"))
-					feature = _("Jingle Video");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0181.html#ns"))
-					feature = _("Jingle DTMF");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0184.html#ns"))
-					feature = _("Message Receipts");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0189.html#ns"))
-					feature = _("Public Key Publishing");
-				else if(!strcmp(feature, "http://jabber.org/protocol/chatting"))
-					feature = _("User Chatting");
-				else if(!strcmp(feature, "http://jabber.org/protocol/browsing"))
-					feature = _("User Browsing");
-				else if(!strcmp(feature, "http://jabber.org/protocol/gaming"))
-					feature = _("User Gaming");
-				else if(!strcmp(feature, "http://jabber.org/protocol/viewing"))
-					feature = _("User Viewing");
-				else if(!strcmp(feature, "urn:xmpp:ping"))
-					feature = _("Ping");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0200.html#ns"))
-					feature = _("Stanza Encryption");
-				else if(!strcmp(feature, "urn:xmpp:time"))
-					feature = _("Entity Time");
-				else if(!strcmp(feature, "urn:xmpp:delay"))
-					feature = _("Delayed Delivery");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0204.html#ns"))
-					feature = _("Collaborative Data Objects");
-				else if(!strcmp(feature, "http://jabber.org/protocol/fileshare"))
-					feature = _("File Repository and Sharing");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0215.html#ns"))
-					feature = _("STUN Service Discovery for Jingle");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0116.html#ns"))
-					feature = _("Simplified Encrypted Session Negotiation");
-				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0219.html#ns"))
-					feature = _("Hop Check");
-				else if(g_str_has_suffix(feature, "+notify"))
-					feature = NULL;
-				if(feature)
-					g_string_append_printf(tmp, "%s<br/>", feature);
-			}
-
-			if(strlen(tmp->str) > 0)
-				purple_notify_user_info_prepend_pair(user_info, _("Capabilities"), tmp->str);
-
-			g_string_free(tmp, TRUE);
-		}
-#endif
+		add_jbr_info(jbi, resource_name, jbr);
 	} else {
-		gboolean multiple_resources = jbi->jb->resources && jbi->jb->resources->next;
-
-		for(resources = jbi->jb->resources; resources; resources = resources->next) {
-			char *purdy = NULL;
-			const char *status_name = NULL;
-
+		for (resources = jbi->jb->resources; resources; resources = resources->next) {
 			jbr = resources->data;
 
 			/* put a section break between resources, this is not needed if
 			 we are at the first, because one was already added for the vcard
 			 section */
-			if (resources != jbi->jb->resources) {
+			if (resources != jbi->jb->resources)
 				purple_notify_user_info_prepend_section_break(user_info);
-			}
-
-			if(jbr->client.name) {
-				tmp = g_strdup_printf("%s%s%s", jbr->client.name,
-									  (jbr->client.version ? " " : ""),
-									  (jbr->client.version ? jbr->client.version : ""));
-				purple_notify_user_info_prepend_pair(user_info,
-												 _("Client"), tmp);
-				g_free(tmp);
-
-				if(jbr->client.os) {
-					purple_notify_user_info_prepend_pair(user_info, _("Operating System"), jbr->client.os);
-				}
-			}
-
-			if (jbr->tz_off != PURPLE_NO_TZ_OFF) {
-				time_t now_t;
-				struct tm *now;
-				char *timestamp;
-				time(&now_t);
-				now_t += jbr->tz_off;
-				now = gmtime(&now_t);
-
-				timestamp = g_strdup_printf("%s %c%02d%02d", purple_time_format(now),
-				                            jbr->tz_off < 0 ? '-' : '+',
-				                            abs(jbr->tz_off / (60*60)),
-				                            abs((jbr->tz_off % (60*60)) / 60));
-				purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp);
-				g_free(timestamp);
-			}
-
-			if(jbr->name && (jbir = g_hash_table_lookup(jbi->resources, jbr->name))) {
-				if(jbir->idle_seconds > 0) {
-					char *idle = purple_str_seconds_to_string(jbir->idle_seconds);
-					purple_notify_user_info_prepend_pair(user_info, _("Idle"), idle);
-					g_free(idle);
-				}
-			}
-
-			status_name = jabber_buddy_state_get_name(jbr->state);
-			if(jbr->status)
-				purdy = purple_strdup_withhtml(jbr->status);
-			if(status_name && purdy && !strcmp(status_name, purdy))
-				status_name = NULL;
-
-			tmp = g_strdup_printf("%s%s%s", (status_name ? status_name : ""),
-								  ((status_name && purdy) ? ": " : ""),
-								  (purdy ? purdy : ""));
-			purple_notify_user_info_prepend_pair(user_info, _("Status"), tmp);
-			g_free(tmp);
-			g_free(purdy);
-
-			if(multiple_resources) {
-				tmp = g_strdup_printf("%d", jbr->priority);
-				purple_notify_user_info_prepend_pair(user_info, _("Priority"), tmp);
-				g_free(tmp);
-			}
-
-			if(jbr->name)
-				purple_notify_user_info_prepend_pair(user_info, _("Resource"), jbr->name);
-#if 0
-			if(jbr && jbr->caps) {
-				GString *tmp = g_string_new("");
-				GList *iter;
-				for(iter = jbr->caps->features; iter; iter = g_list_next(iter)) {
-					const char *feature = iter->data;
 
-					if(!strcmp(feature, "jabber:iq:last"))
-						feature = _("Last Activity");
-					else if(!strcmp(feature, "http://jabber.org/protocol/disco#info"))
-						feature = _("Service Discovery Info");
-					else if(!strcmp(feature, "http://jabber.org/protocol/disco#items"))
-						feature = _("Service Discovery Items");
-					else if(!strcmp(feature, "http://jabber.org/protocol/address"))
-						feature = _("Extended Stanza Addressing");
-					else if(!strcmp(feature, "http://jabber.org/protocol/muc"))
-						feature = _("Multi-User Chat");
-					else if(!strcmp(feature, "http://jabber.org/protocol/muc#user"))
-						feature = _("Multi-User Chat Extended Presence Information");
-					else if(!strcmp(feature, "http://jabber.org/protocol/ibb"))
-						feature = _("In-Band Bytestreams");
-					else if(!strcmp(feature, "http://jabber.org/protocol/commands"))
-						feature = _("Ad-Hoc Commands");
-					else if(!strcmp(feature, "http://jabber.org/protocol/pubsub"))
-						feature = _("PubSub Service");
-					else if(!strcmp(feature, "http://jabber.org/protocol/bytestreams"))
-						feature = _("SOCKS5 Bytestreams");
-					else if(!strcmp(feature, "jabber:x:oob"))
-						feature = _("Out of Band Data");
-					else if(!strcmp(feature, "http://jabber.org/protocol/xhtml-im"))
-						feature = _("XHTML-IM");
-					else if(!strcmp(feature, "jabber:iq:register"))
-						feature = _("In-Band Registration");
-					else if(!strcmp(feature, "http://jabber.org/protocol/geoloc"))
-						feature = _("User Location");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0084.html"))
-						feature = _("User Avatar");
-					else if(!strcmp(feature, "http://jabber.org/protocol/chatstates"))
-						feature = _("Chat State Notifications");
-					else if(!strcmp(feature, "jabber:iq:version"))
-						feature = _("Software Version");
-					else if(!strcmp(feature, "http://jabber.org/protocol/si"))
-						feature = _("Stream Initiation");
-					else if(!strcmp(feature, "http://jabber.org/protocol/si/profile/file-transfer"))
-						feature = _("File Transfer");
-					else if(!strcmp(feature, "http://jabber.org/protocol/mood"))
-						feature = _("User Mood");
-					else if(!strcmp(feature, "http://jabber.org/protocol/activity"))
-						feature = _("User Activity");
-					else if(!strcmp(feature, "http://jabber.org/protocol/caps"))
-						feature = _("Entity Capabilities");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0116.html"))
-						feature = _("Encrypted Session Negotiations");
-					else if(!strcmp(feature, "http://jabber.org/protocol/tune"))
-						feature = _("User Tune");
-					else if(!strcmp(feature, "http://jabber.org/protocol/rosterx"))
-						feature = _("Roster Item Exchange");
-					else if(!strcmp(feature, "http://jabber.org/protocol/reach"))
-						feature = _("Reachability Address");
-					else if(!strcmp(feature, "http://jabber.org/protocol/profile"))
-						feature = _("User Profile");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0166.html#ns"))
-						feature = _("Jingle");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0167.html#ns"))
-						feature = _("Jingle Audio");
-					else if(!strcmp(feature, "http://jabber.org/protocol/nick"))
-						feature = _("User Nickname");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0176.html#ns-udp"))
-						feature = _("Jingle ICE UDP");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0176.html#ns-tcp"))
-						feature = _("Jingle ICE TCP");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0177.html#ns"))
-						feature = _("Jingle Raw UDP");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0180.html#ns"))
-						feature = _("Jingle Video");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0181.html#ns"))
-						feature = _("Jingle DTMF");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0184.html#ns"))
-						feature = _("Message Receipts");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0189.html#ns"))
-						feature = _("Public Key Publishing");
-					else if(!strcmp(feature, "http://jabber.org/protocol/chatting"))
-						feature = _("User Chatting");
-					else if(!strcmp(feature, "http://jabber.org/protocol/browsing"))
-						feature = _("User Browsing");
-					else if(!strcmp(feature, "http://jabber.org/protocol/gaming"))
-						feature = _("User Gaming");
-					else if(!strcmp(feature, "http://jabber.org/protocol/viewing"))
-						feature = _("User Viewing");
-					else if(!strcmp(feature, "urn:xmpp:ping"))
-						feature = _("Ping");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0200.html#ns"))
-						feature = _("Stanza Encryption");
-					else if(!strcmp(feature, "urn:xmpp:time"))
-						feature = _("Entity Time");
-					else if(!strcmp(feature, "urn:xmpp:delay"))
-						feature = _("Delayed Delivery");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0204.html#ns"))
-						feature = _("Collaborative Data Objects");
-					else if(!strcmp(feature, "http://jabber.org/protocol/fileshare"))
-						feature = _("File Repository and Sharing");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0215.html#ns"))
-						feature = _("STUN Service Discovery for Jingle");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0116.html#ns"))
-						feature = _("Simplified Encrypted Session Negotiation");
-					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0219.html#ns"))
-						feature = _("Hop Check");
-					else if(g_str_has_suffix(feature, "+notify"))
-						feature = NULL;
+			add_jbr_info(jbi, jbr->name, jbr);
 
-					if(feature)
-						g_string_append_printf(tmp, "%s\n", feature);
-				}
-				if(strlen(tmp->str) > 0)
-					purple_notify_user_info_prepend_pair(user_info, _("Capabilities"), tmp->str);
-
-				g_string_free(tmp, TRUE);
-			}
-#endif
+			if (jbr->name)
+				purple_notify_user_info_prepend_pair(user_info, _("Resource"), jbr->name);
 		}
 	}
 
@@ -1047,13 +766,13 @@
 		/* the buddy is offline */
 		gchar *status =
 			g_strdup_printf("%s%s%s",	_("Offline"),
-				jbi->last_message ? ": " : "",
-				jbi->last_message ? jbi->last_message : "");
+			                jbi->last_message ? ": " : "",
+			                jbi->last_message ? jbi->last_message : "");
 		if (jbi->last_seconds > 0) {
 			char *last = purple_str_seconds_to_string(jbi->last_seconds);
 			gchar *message = g_strdup_printf(_("%s ago"), last);
 			purple_notify_user_info_prepend_pair(user_info,
-				_("Logged off"), message);
+				_("Logged Off"), message);
 			g_free(last);
 			g_free(message);
 		}
@@ -1065,7 +784,7 @@
 
 	purple_notify_userinfo(jbi->js->gc, jbi->jid, user_info, NULL, NULL);
 
-	while(jbi->vcard_imgids) {
+	while (jbi->vcard_imgids) {
 		purple_imgstore_unref_by_id(GPOINTER_TO_INT(jbi->vcard_imgids->data));
 		jbi->vcard_imgids = g_slist_delete_link(jbi->vcard_imgids, jbi->vcard_imgids);
 	}
@@ -1102,8 +821,12 @@
 	char *txt, *vcard_hash = NULL;
 
 	if (type == JABBER_IQ_ERROR) {
-		purple_debug_warning("jabber", "Server returned error while retrieving vCard");
-		return;
+		xmlnode *error;
+		purple_debug_warning("jabber", "Server returned error while retrieving vCard\n");
+
+		error = xmlnode_get_child(packet, "error");
+		if (!error || !xmlnode_get_child(error, "item-not-found"))
+			return;
 	}
 
 	if((vcard = xmlnode_get_child(packet, "vCard")) ||
@@ -1656,6 +1379,64 @@
 	return FALSE;
 }
 
+static void
+dispatch_queries_for_resource(JabberStream *js, JabberBuddyInfo *jbi,
+                              gboolean is_bare_jid, const char *jid,
+                              JabberBuddyResource *jbr)
+{
+	JabberIq *iq;
+	JabberBuddyInfoResource *jbir;
+	char *full_jid = NULL;
+	const char *to;
+
+	g_return_if_fail(jbr->name != NULL);
+
+	if (is_bare_jid) {
+		full_jid = g_strdup_printf("%s/%s", jid, jbr->name);
+		to = full_jid;
+	} else
+		to = jid;
+
+	jbir = g_new0(JabberBuddyInfoResource, 1);
+	g_hash_table_insert(jbi->resources, g_strdup(jbr->name), jbir);
+
+	if(!jbr->client.name) {
+		iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:version");
+		xmlnode_set_attrib(iq->node, "to", to);
+		jabber_iq_set_callback(iq, jabber_version_parse, jbi);
+		jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
+		jabber_iq_send(iq);
+	}
+
+	/* this is to fix the feeling of irritation I get when trying
+	 * to get info on a friend running Trillian, which doesn't
+	 * respond (with an error or otherwise) to jabber:iq:last
+	 * requests.  There are a number of Trillian users in my
+	 * office. */
+	if(!_client_is_blacklisted(jbr, "jabber:iq:last")) {
+		iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last");
+		xmlnode_set_attrib(iq->node, "to", to);
+		jabber_iq_set_callback(iq, jabber_last_parse, jbi);
+		jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
+		jabber_iq_send(iq);
+	}
+
+	if (jbr->tz_off == PURPLE_NO_TZ_OFF &&
+			(!jbr->caps.info ||
+			 	jabber_resource_has_capability(jbr, "urn:xmpp:time"))) {
+		xmlnode *child;
+		iq = jabber_iq_new(js, JABBER_IQ_GET);
+		xmlnode_set_attrib(iq->node, "to", to);
+		child = xmlnode_new_child(iq->node, "time");
+		xmlnode_set_namespace(child, "urn:xmpp:time");
+		jabber_iq_set_callback(iq, jabber_time_parse, jbi);
+		jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
+		jabber_iq_send(iq);
+	}
+
+	g_free(full_jid);
+}
+
 static void jabber_buddy_get_info_for_jid(JabberStream *js, const char *jid)
 {
 	JabberIq *iq;
@@ -1663,6 +1444,8 @@
 	GList *resources;
 	JabberBuddy *jb;
 	JabberBuddyInfo *jbi;
+	const char *slash;
+	gboolean is_bare_jid;
 
 	jb = jabber_buddy_find(js, jid, TRUE);
 
@@ -1670,6 +1453,9 @@
 	if(!jb)
 		return;
 
+	slash = strchr(jid, '/');
+	is_bare_jid = (slash == NULL);
+
 	jbi = g_new0(JabberBuddyInfo, 1);
 	jbi->jid = g_strdup(jid);
 	jbi->js = js;
@@ -1688,62 +1474,22 @@
 
 	jabber_iq_send(iq);
 
-	for(resources = jb->resources; resources; resources = resources->next)
-	{
-		JabberBuddyResource *jbr = resources->data;
-		JabberBuddyInfoResource *jbir;
-		char *full_jid;
-
-		if ((strchr(jid, '/') == NULL) && (jbr->name != NULL)) {
-			full_jid = g_strdup_printf("%s/%s", jid, jbr->name);
-		} else {
-			full_jid = g_strdup(jid);
-		}
-
-		if (jbr->name != NULL)
-		{
-			jbir = g_new0(JabberBuddyInfoResource, 1);
-			g_hash_table_insert(jbi->resources, g_strdup(jbr->name), jbir);
-		}
-
-		if(!jbr->client.name) {
-			iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:version");
-			xmlnode_set_attrib(iq->node, "to", full_jid);
-			jabber_iq_set_callback(iq, jabber_version_parse, jbi);
-			jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
-			jabber_iq_send(iq);
+	if (is_bare_jid) {
+		for(resources = jb->resources; resources; resources = resources->next) {
+			JabberBuddyResource *jbr = resources->data;
+			dispatch_queries_for_resource(js, jbi, is_bare_jid, jid, jbr);
 		}
-
-		/* this is to fix the feeling of irritation I get when trying
-		 * to get info on a friend running Trillian, which doesn't
-		 * respond (with an error or otherwise) to jabber:iq:last
-		 * requests.  There are a number of Trillian users in my
-		 * office. */
-		if(!_client_is_blacklisted(jbr, "jabber:iq:last")) {
-			iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last");
-			xmlnode_set_attrib(iq->node, "to", full_jid);
-			jabber_iq_set_callback(iq, jabber_last_parse, jbi);
-			jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
-			jabber_iq_send(iq);
-		}
-
-		if (jbr->tz_off == PURPLE_NO_TZ_OFF &&
-				(!jbr->caps.info ||
-				 	jabber_resource_has_capability(jbr, "urn:xmpp:time"))) {
-			xmlnode *child;
-			iq = jabber_iq_new(js, JABBER_IQ_GET);
-			xmlnode_set_attrib(iq->node, "to", full_jid);
-			child = xmlnode_new_child(iq->node, "time");
-			xmlnode_set_namespace(child, "urn:xmpp:time");
-			jabber_iq_set_callback(iq, jabber_time_parse, jbi);
-			jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
-			jabber_iq_send(iq);
-		}
-
-		g_free(full_jid);
+	} else {
+		JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, slash + 1);
+		if (jbr)
+			dispatch_queries_for_resource(js, jbi, is_bare_jid, jid, jbr);
+		else
+			purple_debug_warning("jabber", "jabber_buddy_get_info_for_jid() "
+					"was passed JID %s, but there is no corresponding "
+					"JabberBuddyResource!\n", jid);
 	}
 
-	if (!jb->resources && strchr(jid, '/') == NULL) {
+	if (!jb->resources && is_bare_jid) {
 		/* user is offline, send a jabber:iq:last to find out last time online */
 		iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last");
 		xmlnode_set_attrib(iq->node, "to", jid);
@@ -2074,45 +1820,45 @@
 	return JABBER_BUDDY_STATE_UNKNOWN;
 }
 
-JabberBuddyState jabber_buddy_show_get_state(const char *id) {
-	if(!id)
-		return JABBER_BUDDY_STATE_UNKNOWN;
-	if(!strcmp(id, "available"))
-		return JABBER_BUDDY_STATE_ONLINE;
-	if(!strcmp(id, "chat"))
-		return JABBER_BUDDY_STATE_CHAT;
-	if(!strcmp(id, "away"))
-		return JABBER_BUDDY_STATE_AWAY;
-	if(!strcmp(id, "xa"))
-		return JABBER_BUDDY_STATE_XA;
-	if(!strcmp(id, "dnd"))
-		return JABBER_BUDDY_STATE_DND;
-	if(!strcmp(id, "offline"))
-		return JABBER_BUDDY_STATE_UNAVAILABLE;
-	if(!strcmp(id, "error"))
-		return JABBER_BUDDY_STATE_ERROR;
+const struct {
+	const char *name;
+	JabberBuddyState state;
+} show_state_pairs[] = {
+	{ "available", JABBER_BUDDY_STATE_ONLINE },
+	{ "chat",      JABBER_BUDDY_STATE_CHAT },
+	{ "away",      JABBER_BUDDY_STATE_AWAY },
+	{ "xa",        JABBER_BUDDY_STATE_XA },
+	{ "dnd",       JABBER_BUDDY_STATE_DND },
+	{ "offline",   JABBER_BUDDY_STATE_UNAVAILABLE },
+	{ "error",     JABBER_BUDDY_STATE_ERROR },
+	{ NULL,        JABBER_BUDDY_STATE_UNKNOWN }
+};
 
+JabberBuddyState jabber_buddy_show_get_state(const char *id)
+{
+	int i;
+
+	g_return_val_if_fail(id != NULL, JABBER_BUDDY_STATE_UNKNOWN);
+
+	for (i = 0; show_state_pairs[i].name; ++i)
+		if (g_str_equal(id, show_state_pairs[i].name))
+			return show_state_pairs[i].state;
+
+	purple_debug_warning("jabber", "Invalid value of presence <show/> "
+	                     "attribute: %s\n", id);
 	return JABBER_BUDDY_STATE_UNKNOWN;
 }
 
-const char *jabber_buddy_state_get_show(JabberBuddyState state) {
-	switch(state) {
-		case JABBER_BUDDY_STATE_CHAT:
-			return "chat";
-		case JABBER_BUDDY_STATE_AWAY:
-			return "away";
-		case JABBER_BUDDY_STATE_XA:
-			return "xa";
-		case JABBER_BUDDY_STATE_DND:
-			return "dnd";
-		case JABBER_BUDDY_STATE_ONLINE:
-			return "available";
-		case JABBER_BUDDY_STATE_UNKNOWN:
-		case JABBER_BUDDY_STATE_ERROR:
-			return NULL;
-		case JABBER_BUDDY_STATE_UNAVAILABLE:
-			return "offline";
-	}
+const char *
+jabber_buddy_state_get_show(JabberBuddyState state)
+{
+	int i;
+
+	for (i = 0; show_state_pairs[i].name; ++i)
+		if (state == show_state_pairs[i].state)
+			return show_state_pairs[i].name;
+
+/*	purple_debug_warning("jabber", "Unknown buddy state: %d\n", state); */
 	return NULL;
 }
 
@@ -2480,7 +2226,7 @@
 	const JabberCapsNodeExts *exts;
 
 	if (!jbr->caps.info) {
-		purple_debug_error("jabber",
+		purple_debug_info("jabber",
 			"Unable to find caps: nothing known about buddy\n");
 		return FALSE;
 	}
@@ -2498,12 +2244,6 @@
 		}
 	}
 
-	/* TODO: Are these messages actually useful? */
-	if (node)
-		purple_debug_info("jabber", "Found cap: %s\n", cap);
-	else
-		purple_debug_info("jabber", "Cap %s not found\n", cap);
-
 	return (node != NULL);
 }