diff --git a/libpurple/protocols/jabber/buddy.h b/libpurple/protocols/jabber/buddy.h
--- a/libpurple/protocols/jabber/buddy.h
+++ b/libpurple/protocols/jabber/buddy.h
@@ -78,10 +78,7 @@ typedef struct {
 		char *os;
 	} client;
 	GTimeZone *tz_off;
-	struct {
-		JabberCapsClientInfo *info;
-		GList *exts;
-	} caps;
+	JabberCapsClientInfo *caps;
 	GList *commands;
 	gboolean commands_fetched;
 } JabberBuddyResource;
# HG changeset patch
# Node ID 229da991a739
# Parent  5fb843f4e356
diff --git a/libpurple/protocols/jabber/buddy.c b/libpurple/protocols/jabber/buddy.c
--- a/libpurple/protocols/jabber/buddy.c
+++ b/libpurple/protocols/jabber/buddy.c
@@ -59,7 +59,6 @@ jabber_buddy_resource_free(JabberBuddyRe
 	g_return_if_fail(jbr != NULL);
 
 	g_list_free_full(jbr->commands, (GDestroyNotify)jabber_adhoc_commands_free);
-	g_list_free_full(jbr->caps.exts, g_free);
 	g_free(jbr->name);
 	g_free(jbr->status);
 	g_free(jbr->thread_id);
@@ -1507,8 +1506,8 @@ dispatch_queries_for_resource(JabberStre
 	}
 
 	if (jbr->tz_off == NULL &&
-			(!jbr->caps.info ||
-			 	jabber_resource_has_capability(jbr, NS_ENTITY_TIME))) {
+			(jbr->caps == NULL ||
+				jabber_resource_has_capability(jbr, NS_ENTITY_TIME))) {
 		PurpleXmlNode *child;
 		iq = jabber_iq_new(js, JABBER_IQ_GET);
 		purple_xmlnode_set_attrib(iq->node, "to", to);
@@ -2218,34 +2217,21 @@ void jabber_user_search_begin(PurpleProt
 gboolean
 jabber_resource_know_capabilities(const JabberBuddyResource *jbr)
 {
-	return jbr->caps.info != NULL;
+	return jbr->caps != NULL;
 }
 
 gboolean
 jabber_resource_has_capability(const JabberBuddyResource *jbr, const gchar *cap)
 {
 	const GList *node = NULL;
-	const JabberCapsNodeExts *exts;
 
-	if (!jbr->caps.info) {
+	if (jbr->caps == NULL) {
 		purple_debug_info("jabber",
 			"Unable to find caps: nothing known about buddy\n");
 		return FALSE;
 	}
 
-	node = g_list_find_custom(jbr->caps.info->features, cap, (GCompareFunc)strcmp);
-	if (!node && jbr->caps.exts && jbr->caps.info->exts) {
-		const GList *ext;
-		exts = jbr->caps.info->exts;
-		/* Walk through all the enabled caps, checking each list for the cap.
-		 * Don't check it twice, though. */
-		for (ext = jbr->caps.exts; ext && !node; ext = ext->next) {
-			GList *features = g_hash_table_lookup(exts->exts, ext->data);
-			if (features)
-				node = g_list_find_custom(features, cap, (GCompareFunc)strcmp);
-		}
-	}
-
+	node = g_list_find_custom(jbr->caps->features, cap, (GCompareFunc)strcmp);
 	return (node != NULL);
 }
 
@@ -2269,8 +2255,8 @@ jabber_resource_get_identity_category_ty
 {
 	const GList *iter = NULL;
 
-	if (jbr->caps.info) {
-		for (iter = jbr->caps.info->identities ; iter ; iter = g_list_next(iter)) {
+	if (jbr->caps != NULL) {
+		for (iter = jbr->caps->identities ; iter ; iter = g_list_next(iter)) {
 			const JabberIdentity *identity =
 				(JabberIdentity *) iter->data;
 
diff --git a/libpurple/protocols/jabber/caps.h b/libpurple/protocols/jabber/caps.h
--- a/libpurple/protocols/jabber/caps.h
+++ b/libpurple/protocols/jabber/caps.h
@@ -30,8 +30,6 @@ typedef struct _JabberCapsClientInfo Jab
 
 /* Implementation of XEP-0115 - Entity Capabilities */
 
-typedef struct _JabberCapsNodeExts JabberCapsNodeExts;
-
 typedef struct {
 	const char *node;
 	const char *ver;
@@ -42,52 +40,24 @@ struct _JabberCapsClientInfo {
 	GList *identities; /* JabberIdentity */
 	GList *features; /* char * */
 	GList *forms; /* PurpleXmlNode * */
-	JabberCapsNodeExts *exts;
 
 	const JabberCapsTuple tuple;
 };
 
-/*
- * This stores a set of exts "known" for a specific node (which indicates
- * a specific client -- for reference, Pidgin, Finch, Meebo, et al share one
- * node.) In XEP-0115 v1.3, exts are used for features that may or may not be
- * present at a given time (PEP things, buzz might be disabled, etc).
- *
- * This structure is shared among all JabberCapsClientInfo instances matching
- * a specific node (if the capstable key->hash == NULL, which indicates that
- * the ClientInfo is using v1.3 caps as opposed to v1.5 caps).
- *
- * It's only exposed so that jabber_resource_has_capability can use it.
- * Everyone else, STAY AWAY!
- */
-struct _JabberCapsNodeExts {
-	guint ref;
-	GHashTable *exts; /* char *ext_name -> GList *features */
-};
-
-typedef void (*jabber_caps_get_info_cb)(JabberCapsClientInfo *info, GList *exts, gpointer user_data);
+typedef void (*jabber_caps_get_info_cb)(JabberCapsClientInfo *info, gpointer user_data);
 
 void jabber_caps_init(void);
 void jabber_caps_uninit(void);
 
 /**
- * Check whether all of the exts in a char* array are known to the given info.
- */
-gboolean jabber_caps_exts_known(const JabberCapsClientInfo *info, char **exts);
-
-/**
  * Main entity capabilities function to get the capabilities of a contact.
  *
  * The callback will be called synchronously if we already have the
- * capabilities for the specified (node,ver,hash) (and, if exts are specified,
- * if we know what each means)
- *
- * @param exts A g_strsplit'd (NULL-terminated) array of strings. This
- *             function is responsible for freeing it.
+ * capabilities for the specified (node,ver,hash).
  */
 void jabber_caps_get_info(JabberStream *js, const char *who, const char *node,
                           const char *ver, const char *hash,
-                          char **exts, jabber_caps_get_info_cb cb,
+                          jabber_caps_get_info_cb cb,
                           gpointer user_data);
 
 /**
diff --git a/libpurple/protocols/jabber/caps.c b/libpurple/protocols/jabber/caps.c
--- a/libpurple/protocols/jabber/caps.c
+++ b/libpurple/protocols/jabber/caps.c
@@ -38,50 +38,13 @@ typedef struct {
 } JabberDataFormField;
 
 static GHashTable *capstable = NULL; /* JabberCapsTuple -> JabberCapsClientInfo */
-static GHashTable *nodetable = NULL; /* char *node -> JabberCapsNodeExts */
 static guint       save_timer = 0;
 
-/* Free a GList of allocated char* */
-static void
-free_string_glist(GList *list)
-{
-	g_list_free_full(list, g_free);
-}
-
-static JabberCapsNodeExts*
-jabber_caps_node_exts_ref(JabberCapsNodeExts *exts)
-{
-	g_return_val_if_fail(exts != NULL, NULL);
-
-	++exts->ref;
-	return exts;
-}
-
-static void
-jabber_caps_node_exts_unref(JabberCapsNodeExts *exts)
-{
-	if (exts == NULL)
-		return;
-
-	g_return_if_fail(exts->ref != 0);
-
-	if (--exts->ref != 0)
-		return;
-
-	g_hash_table_destroy(exts->exts);
-	g_free(exts);
-}
-
 static guint jabber_caps_hash(gconstpointer data) {
 	const JabberCapsTuple *key = data;
 	guint nodehash = g_str_hash(key->node);
 	guint verhash  = g_str_hash(key->ver);
-	/*
-	 * 'hash' was optional in XEP-0115 v1.4 and g_str_hash crashes on NULL >:O.
-	 * Okay, maybe I've played too much Zelda, but that looks like
-	 * a Deku Shrub...
-	 */
-	guint hashhash = (key->hash ? g_str_hash(key->hash) : 0);
+	guint hashhash = g_str_hash(key->hash);
 	return nodehash ^ verhash ^ hashhash;
 }
 
@@ -102,12 +65,10 @@ jabber_caps_client_info_destroy(JabberCa
 
 	g_list_free_full(info->identities, (GDestroyNotify)jabber_identity_free);
 
-	free_string_glist(info->features);
+	g_list_free_full(info->features, g_free);
 
 	g_list_free_full(info->forms, (GDestroyNotify)purple_xmlnode_free);
 
-	jabber_caps_node_exts_unref(info->exts);
-
 	g_free((char *)info->tuple.node);
 	g_free((char *)info->tuple.ver);
 	g_free((char *)info->tuple.hash);
@@ -115,38 +76,6 @@ jabber_caps_client_info_destroy(JabberCa
 	g_free(info);
 }
 
-/* NOTE: Takes a reference to the exts, unref it if you don't really want to
- * keep it around. */
-static JabberCapsNodeExts*
-jabber_caps_find_exts_by_node(const char *node)
-{
-	JabberCapsNodeExts *exts;
-	if (NULL == (exts = g_hash_table_lookup(nodetable, node))) {
-		exts = g_new0(JabberCapsNodeExts, 1);
-		exts->exts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
-		                                   (GDestroyNotify)free_string_glist);
-		g_hash_table_insert(nodetable, g_strdup(node), jabber_caps_node_exts_ref(exts));
-	}
-
-	return jabber_caps_node_exts_ref(exts);
-}
-
-static void
-exts_to_xmlnode(gconstpointer key, gconstpointer value, gpointer user_data)
-{
-	const char *identifier = key;
-	const GList *features = value, *node;
-	PurpleXmlNode *client = user_data, *ext, *feature;
-
-	ext = purple_xmlnode_new_child(client, "ext");
-	purple_xmlnode_set_attrib(ext, "identifier", identifier);
-
-	for (node = features; node; node = node->next) {
-		feature = purple_xmlnode_new_child(ext, "feature");
-		purple_xmlnode_set_attrib(feature, "var", (const gchar *)node->data);
-	}
-}
-
 static void jabber_caps_store_client(gpointer key, gpointer value, gpointer user_data) {
 	const JabberCapsTuple *tuple = key;
 	const JabberCapsClientInfo *props = value;
@@ -156,8 +85,7 @@ static void jabber_caps_store_client(gpo
 
 	purple_xmlnode_set_attrib(client, "node", tuple->node);
 	purple_xmlnode_set_attrib(client, "ver", tuple->ver);
-	if (tuple->hash)
-		purple_xmlnode_set_attrib(client, "hash", tuple->hash);
+	purple_xmlnode_set_attrib(client, "hash", tuple->hash);
 	for(iter = props->identities; iter; iter = g_list_next(iter)) {
 		JabberIdentity *id = iter->data;
 		PurpleXmlNode *identity = purple_xmlnode_new_child(client, "identity");
@@ -180,10 +108,6 @@ static void jabber_caps_store_client(gpo
 		PurpleXmlNode *xdata = iter->data;
 		purple_xmlnode_insert_child(client, purple_xmlnode_copy(xdata));
 	}
-
-	/* TODO: Ideally, only save this once-per-node... */
-	if (props->exts)
-		g_hash_table_foreach(props->exts->exts, (GHFunc)exts_to_xmlnode, client);
 }
 
 static gboolean
@@ -231,15 +155,10 @@ jabber_caps_load(void)
 			JabberCapsClientInfo *value = g_new0(JabberCapsClientInfo, 1);
 			JabberCapsTuple *key = (JabberCapsTuple*)&value->tuple;
 			PurpleXmlNode *child;
-			JabberCapsNodeExts *exts = NULL;
 			key->node = g_strdup(purple_xmlnode_get_attrib(client,"node"));
 			key->ver  = g_strdup(purple_xmlnode_get_attrib(client,"ver"));
 			key->hash = g_strdup(purple_xmlnode_get_attrib(client,"hash"));
 
-			/* v1.3 capabilities */
-			if (key->hash == NULL)
-				exts = jabber_caps_find_exts_by_node(key->node);
-
 			for (child = client->child; child; child = child->next) {
 				if (child->type != PURPLE_XMLNODE_TYPE_TAG)
 					continue;
@@ -266,42 +185,10 @@ jabber_caps_load(void)
 					 * work properly, that bug needs to be fixed in
 					 * purple_xmlnode_from_str, not the output version... */
 					value->forms = g_list_append(value->forms, purple_xmlnode_copy(child));
-				} else if (purple_strequal(child->name, "ext")) {
-					if (key->hash != NULL)
-						purple_debug_warning("jabber", "Ignoring exts when reading new-style caps\n");
-					else {
-						/* TODO: Do we care about reading in the identities listed here? */
-						const char *identifier = purple_xmlnode_get_attrib(child, "identifier");
-						PurpleXmlNode *node;
-						GList *features = NULL;
-
-						if (!identifier)
-							continue;
-
-						for (node = child->child; node; node = node->next) {
-							if (node->type != PURPLE_XMLNODE_TYPE_TAG)
-								continue;
-							if (purple_strequal(node->name, "feature")) {
-								const char *var = purple_xmlnode_get_attrib(node, "var");
-								if (!var)
-									continue;
-								features = g_list_prepend(features, g_strdup(var));
-							}
-						}
-
-						if (features) {
-							g_hash_table_insert(exts->exts, g_strdup(identifier),
-							                    features);
-						} else
-							purple_debug_warning("jabber", "Caps ext %s had no features.\n",
-							                     identifier);
-					}
 				}
 			}
 
-			value->exts = exts;
 			g_hash_table_replace(capstable, key, value);
-
 		}
 	}
 	purple_xmlnode_free(capsdata);
@@ -309,7 +196,6 @@ jabber_caps_load(void)
 
 void jabber_caps_init(void)
 {
-	nodetable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)jabber_caps_node_exts_unref);
 	capstable = g_hash_table_new_full(jabber_caps_hash, jabber_caps_compare, NULL, (GDestroyNotify)jabber_caps_client_info_destroy);
 	jabber_caps_load();
 }
@@ -322,31 +208,10 @@ void jabber_caps_uninit(void)
 		do_jabber_caps_store(NULL);
 	}
 	g_hash_table_destroy(capstable);
-	g_hash_table_destroy(nodetable);
-	capstable = nodetable = NULL;
-}
-
-gboolean jabber_caps_exts_known(const JabberCapsClientInfo *info,
-                                char **exts)
-{
-	int i;
-	g_return_val_if_fail(info != NULL, FALSE);
-
-	if (!exts)
-		return TRUE;
-
-	for (i = 0; exts[i]; ++i) {
-		if (!info->exts ||
-				!g_hash_table_lookup(info->exts->exts, exts[i]))
-			return FALSE;
-	}
-
-	return TRUE;
+	capstable = NULL;
 }
 
 typedef struct {
-	guint ref;
-
 	jabber_caps_get_info_cb cb;
 	gpointer cb_data;
 
@@ -356,42 +221,21 @@ typedef struct {
 	char *hash;
 
 	JabberCapsClientInfo *info;
-
-	GList *exts;
-	guint extOutstanding;
-	JabberCapsNodeExts *node_exts;
 } jabber_caps_cbplususerdata;
 
-static jabber_caps_cbplususerdata*
-cbplususerdata_ref(jabber_caps_cbplususerdata *data)
-{
-	g_return_val_if_fail(data != NULL, NULL);
-
-	++data->ref;
-	return data;
-}
-
 static void
-cbplususerdata_unref(jabber_caps_cbplususerdata *data)
+cbplususerdata_destroy(jabber_caps_cbplususerdata *data)
 {
 	if (data == NULL)
 		return;
 
-	g_return_if_fail(data->ref != 0);
-
-	if (--data->ref > 0)
-		return;
-
 	g_free(data->who);
 	g_free(data->node);
 	g_free(data->ver);
 	g_free(data->hash);
 
 	/* If we have info here, it's already in the capstable, so don't free it */
-	if (data->exts)
-		free_string_glist(data->exts);
-	if (data->node_exts)
-		jabber_caps_node_exts_unref(data->node_exts);
+
 	g_free(data);
 }
 
@@ -399,77 +243,62 @@ static void
 jabber_caps_get_info_complete(jabber_caps_cbplususerdata *userdata)
 {
 	if (userdata->cb) {
-		userdata->cb(userdata->info, userdata->exts, userdata->cb_data);
+		userdata->cb(userdata->info, userdata->cb_data);
 		userdata->info = NULL;
-		userdata->exts = NULL;
 	}
-
-	if (userdata->ref != 1)
-		purple_debug_warning("jabber", "Lost a reference to caps cbdata: %d\n",
-		                     userdata->ref);
 }
 
 static void
 jabber_caps_client_iqcb(JabberStream *js, const char *from, JabberIqType type,
                         const char *id, PurpleXmlNode *packet, gpointer data)
 {
-	PurpleXmlNode *query = purple_xmlnode_get_child_with_namespace(packet, "query",
-		NS_DISCO_INFO);
 	jabber_caps_cbplususerdata *userdata = data;
+	PurpleXmlNode *query = NULL;
 	JabberCapsClientInfo *info = NULL, *value;
 	JabberCapsTuple key;
+	gchar *hash = NULL;
+	GChecksumType hash_type;
+	gboolean supported_hash = TRUE;
 
-	if (!query || type == JABBER_IQ_ERROR) {
-		/* Any outstanding exts will be dealt with via ref-counting */
-		userdata->cb(NULL, NULL, userdata->cb_data);
-		cbplususerdata_unref(userdata);
+	query = purple_xmlnode_get_child_with_namespace(packet, "query",
+	                                                NS_DISCO_INFO);
+	if(query == NULL || type == JABBER_IQ_ERROR) {
+		userdata->cb(NULL, userdata->cb_data);
+		cbplususerdata_destroy(userdata);
 		return;
 	}
 
 	/* check hash */
 	info = jabber_caps_parse_client_info(query);
 
-	/* Only validate if these are v1.5 capabilities */
-	if (userdata->hash) {
-		gchar *hash = NULL;
-		GChecksumType hash_type;
-		gboolean supported_hash = TRUE;
-
-		if (purple_strequal(userdata->hash, "sha-1")) {
-			hash_type = G_CHECKSUM_SHA1;
-		} else if (purple_strequal(userdata->hash, "md5")) {
-			hash_type = G_CHECKSUM_MD5;
-		} else {
-			supported_hash = FALSE;
-		}
+	if(purple_strequal(userdata->hash, "sha-1")) {
+		hash_type = G_CHECKSUM_SHA1;
+	} else if(purple_strequal(userdata->hash, "md5")) {
+		hash_type = G_CHECKSUM_MD5;
+	} else {
+		supported_hash = FALSE;
+	}
 
-		if (supported_hash) {
-			hash = jabber_caps_calculate_hash(info, hash_type);
-		}
-
-		if (!hash || !purple_strequal(hash, userdata->ver)) {
-			purple_debug_warning("jabber", "Could not validate caps info from "
-			                     "%s. Expected %s, got %s\n",
-			                     purple_xmlnode_get_attrib(packet, "from"),
-			                     userdata->ver, hash ? hash : "(null)");
-
-			userdata->cb(NULL, NULL, userdata->cb_data);
-			jabber_caps_client_info_destroy(info);
-			cbplususerdata_unref(userdata);
-			g_free(hash);
-			return;
-		}
-
-		g_free(hash);
+	if (supported_hash) {
+		hash = jabber_caps_calculate_hash(info, hash_type);
 	}
 
-	if (!userdata->hash && userdata->node_exts) {
-		/* If the ClientInfo doesn't have information about the exts, give them
-		 * ours (along with our ref) */
-		info->exts = userdata->node_exts;
-		userdata->node_exts = NULL;
+	if (hash == NULL || !purple_strequal(hash, userdata->ver)) {
+		purple_debug_warning("jabber",
+		                     "Could not validate caps info from %s. "
+		                     "Expected %s, got %s",
+		                     purple_xmlnode_get_attrib(packet, "from"),
+		                     userdata->ver, hash ? hash : "(null)");
+
+		userdata->cb(NULL, userdata->cb_data);
+		jabber_caps_client_info_destroy(info);
+		cbplususerdata_destroy(userdata);
+		g_free(hash);
+		return;
 	}
 
+	g_free(hash);
+
 	key.node = userdata->node;
 	key.ver  = userdata->ver;
 	key.hash = userdata->hash;
@@ -500,91 +329,22 @@ jabber_caps_client_iqcb(JabberStream *js
 
 	userdata->info = info;
 
-	if (userdata->extOutstanding == 0)
-		jabber_caps_get_info_complete(userdata);
+	jabber_caps_get_info_complete(userdata);
 
-	cbplususerdata_unref(userdata);
+	cbplususerdata_destroy(userdata);
 }
 
-static void
-jabber_caps_ext_iqcb(JabberStream *js, const char *from, JabberIqType type,
-                     const char *id, PurpleXmlNode *packet, gpointer data)
+void
+jabber_caps_get_info(JabberStream *js, const char *who, const char *node,
+                     const char *ver, const char *hash,
+                     jabber_caps_get_info_cb cb, gpointer user_data)
 {
-	PurpleXmlNode *query = purple_xmlnode_get_child_with_namespace(packet, "query",
-		NS_DISCO_INFO);
-	PurpleXmlNode *child;
-	PurpleKeyValuePair *cbdata = data;
-	jabber_caps_cbplususerdata *userdata = cbdata->value;
-	GList *features = NULL;
-	JabberCapsNodeExts *node_exts;
-
-	if (!query || type == JABBER_IQ_ERROR) {
-		purple_key_value_pair_free(cbdata);
-		return;
-	}
-
-	node_exts = (userdata->info ? userdata->info->exts : userdata->node_exts);
-
-	/* TODO: I don't see how this can actually happen, but it crashed khc. */
-	if (!node_exts) {
-		purple_debug_error("jabber", "Couldn't find JabberCapsNodeExts. If you "
-		                   "see this, please tell darkrain42 and save your debug log.\n"
-		                   "JabberCapsClientInfo = %p", userdata->info);
-
-
-		/* Try once more to find the exts and then fail */
-		node_exts = jabber_caps_find_exts_by_node(userdata->node);
-		if (node_exts) {
-			purple_debug_info("jabber", "Found the exts on the second try.\n");
-			if (userdata->info) {
-				userdata->info->exts = node_exts;
-			} else {
-				userdata->node_exts = node_exts;
-			}
-		} else {
-			purple_key_value_pair_free(cbdata);
-			g_return_if_reached();
-		}
-	}
-
-	/* So, we decrement this after checking for an error, which means that
-	 * if there *is* an error, we'll never call the callback passed to
-	 * jabber_caps_get_info. We will still free all of our data, though.
-	 */
-	--userdata->extOutstanding;
-
-	for (child = purple_xmlnode_get_child(query, "feature"); child;
-	        child = purple_xmlnode_get_next_twin(child)) {
-		const char *var = purple_xmlnode_get_attrib(child, "var");
-		if (var)
-			features = g_list_prepend(features, g_strdup(var));
-	}
-
-	g_hash_table_insert(node_exts->exts, g_strdup(cbdata->key), features);
-	schedule_caps_save();
-
-	/* Are we done? */
-	if (userdata->info && userdata->extOutstanding == 0) {
-		jabber_caps_get_info_complete(userdata);
-	}
-
-	purple_key_value_pair_free(cbdata);
-}
-
-void jabber_caps_get_info(JabberStream *js, const char *who, const char *node,
-        const char *ver, const char *hash, char **exts,
-        jabber_caps_get_info_cb cb, gpointer user_data)
-{
-	JabberCapsClientInfo *info;
+	JabberCapsClientInfo *info = NULL;
 	JabberCapsTuple key;
-	jabber_caps_cbplususerdata *userdata;
-
-	if (exts && hash) {
-		purple_debug_misc("jabber", "Ignoring exts in new-style caps from %s\n",
-		                  who);
-		g_strfreev(exts);
-		exts = NULL;
-	}
+	jabber_caps_cbplususerdata *userdata = NULL;
+	JabberIq *iq = NULL;
+	PurpleXmlNode *query = NULL;
+	char *nodever = NULL;
 
 	/* Using this in a read-only fashion, so the cast is OK */
 	key.node = (char *)node;
@@ -592,10 +352,11 @@ void jabber_caps_get_info(JabberStream *
 	key.hash = (char *)hash;
 
 	info = g_hash_table_lookup(capstable, &key);
-	if (info && hash) {
-		/* v1.5 - We already have all the information we care about */
-		if (cb)
-			cb(info, NULL, user_data);
+	if (info != NULL) {
+		/* We already have all the information we care about */
+		if (cb) {
+			cb(info, user_data);
+		}
 		return;
 	}
 
@@ -608,82 +369,18 @@ void jabber_caps_get_info(JabberStream *
 	userdata->ver = g_strdup(ver);
 	userdata->hash = g_strdup(hash);
 
-	if (info) {
-		userdata->info = info;
-	} else {
-		/* If we don't have the basic information about the client, we need
-		 * to fetch it. */
-		JabberIq *iq;
-		PurpleXmlNode *query;
-		char *nodever;
-
-		iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_DISCO_INFO);
-		query = purple_xmlnode_get_child_with_namespace(iq->node, "query",
-					NS_DISCO_INFO);
-		nodever = g_strdup_printf("%s#%s", node, ver);
-		purple_xmlnode_set_attrib(query, "node", nodever);
-		g_free(nodever);
-		purple_xmlnode_set_attrib(iq->node, "to", who);
-
-		cbplususerdata_ref(userdata);
-
-		jabber_iq_set_callback(iq, jabber_caps_client_iqcb, userdata);
-		jabber_iq_send(iq);
-	}
-
-	/* Are there any exts that we don't recognize? */
-	if (exts) {
-		JabberCapsNodeExts *node_exts;
-		int i;
-
-		if (info) {
-			if (info->exts)
-				node_exts = info->exts;
-			else
-				node_exts = info->exts = jabber_caps_find_exts_by_node(node);
-		} else
-			/* We'll put it in later once we have the client info */
-			node_exts = userdata->node_exts = jabber_caps_find_exts_by_node(node);
+	/* If we don't have the basic information about the client, we need to
+	 * fetch it. */
+	iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_DISCO_INFO);
+	query = purple_xmlnode_get_child_with_namespace(iq->node, "query",
+	                                                NS_DISCO_INFO);
+	nodever = g_strdup_printf("%s#%s", node, ver);
+	purple_xmlnode_set_attrib(query, "node", nodever);
+	g_free(nodever);
+	purple_xmlnode_set_attrib(iq->node, "to", who);
 
-		for (i = 0; exts[i]; ++i) {
-			userdata->exts = g_list_prepend(userdata->exts, exts[i]);
-			/* Look it up if we don't already know what it means */
-			if (!g_hash_table_lookup(node_exts->exts, exts[i])) {
-				JabberIq *iq;
-				PurpleXmlNode *query;
-				char *nodeext;
-				PurpleKeyValuePair *cbdata;
-
-				iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_DISCO_INFO);
-				query = purple_xmlnode_get_child_with_namespace(iq->node, "query",
-				            NS_DISCO_INFO);
-				nodeext = g_strdup_printf("%s#%s", node, exts[i]);
-				purple_xmlnode_set_attrib(query, "node", nodeext);
-				g_free(nodeext);
-				purple_xmlnode_set_attrib(iq->node, "to", who);
-
-				cbdata = purple_key_value_pair_new_full(exts[i], cbplususerdata_ref(userdata),
-				                                        (GDestroyNotify)cbplususerdata_unref);
-				jabber_iq_set_callback(iq, jabber_caps_ext_iqcb, cbdata);
-				jabber_iq_send(iq);
-
-				++userdata->extOutstanding;
-			}
-			exts[i] = NULL;
-		}
-		/* All the strings are now part of the GList, so don't need
-		 * g_strfreev. */
-		g_free(exts);
-	}
-
-	if (userdata->info && userdata->extOutstanding == 0) {
-		/* Start with 1 ref so the below functions are happy */
-		userdata->ref = 1;
-
-		/* We have everything we need right now */
-		jabber_caps_get_info_complete(userdata);
-		cbplususerdata_unref(userdata);
-	}
+	jabber_iq_set_callback(iq, jabber_caps_client_iqcb, userdata);
+	jabber_iq_send(iq);
 }
 
 static gint
diff --git a/libpurple/protocols/jabber/message.c b/libpurple/protocols/jabber/message.c
--- a/libpurple/protocols/jabber/message.c
+++ b/libpurple/protocols/jabber/message.c
@@ -888,7 +888,7 @@ int jabber_message_send_im(PurpleProtoco
 	 * For backward compatibility with user expectations or for those not on
 	 * the user's roster, allow sending XHTML-IM markup.
 	 */
-	if (!jbr || !jbr->caps.info ||
+	if (jbr == NULL || jbr->caps == NULL ||
 			jabber_resource_has_capability(jbr, NS_XHTML_IM)) {
 		if (!jabber_xhtml_plain_equal(xhtml, jm->body))
 			/* Wrap the message in <p/> for great interoperability justice. */
diff --git a/libpurple/protocols/jabber/presence.c b/libpurple/protocols/jabber/presence.c
--- a/libpurple/protocols/jabber/presence.c
+++ b/libpurple/protocols/jabber/presence.c
@@ -447,7 +447,7 @@ typedef struct {
 } JabberPresenceCapabilities;
 
 static void
-jabber_presence_set_capabilities(JabberCapsClientInfo *info, GList *exts,
+jabber_presence_set_capabilities(JabberCapsClientInfo *info,
                                  JabberPresenceCapabilities *userdata)
 {
 	JabberBuddyResource *jbr;
@@ -460,15 +460,10 @@ jabber_presence_set_capabilities(JabberC
 	if (!jbr) {
 		g_free(userdata->from);
 		g_free(userdata);
-		g_list_free_full(exts, g_free);
 		return;
 	}
 
-	/* Any old jbr->caps.info is owned by the caps code */
-	g_list_free_full(jbr->caps.exts, g_free);
-
-	jbr->caps.info = info;
-	jbr->caps.exts = exts;
+	jbr->caps = info;
 
 	purple_protocol_got_media_caps(
 			purple_connection_get_account(userdata->js->gc),
@@ -1033,30 +1028,27 @@ void jabber_presence_parse(JabberStream 
 		const char *node = purple_xmlnode_get_attrib(presence.caps, "node");
 		const char *ver  = purple_xmlnode_get_attrib(presence.caps, "ver");
 		const char *hash = purple_xmlnode_get_attrib(presence.caps, "hash");
-		const char *ext  = purple_xmlnode_get_attrib(presence.caps, "ext");
 
-		/* v1.3 uses: node, ver, and optionally ext.
-		 * v1.5 uses: node, ver, and hash. */
-		if (node && *node && ver && *ver) {
-			gchar **exts = ext && *ext ? g_strsplit(ext, " ", -1) : NULL;
+		/* v1.5 uses: node, ver, and hash. */
+		if(node != NULL && *node != '\0' &&
+		   ver != NULL && *ver != '\0' &&
+		   hash != NULL && *hash != '\0')
+		{
 			jbr = jabber_buddy_find_resource(presence.jb, presence.jid_from->resource);
 
 			/* Look it up if we don't already have all this information */
-			if (!jbr || !jbr->caps.info ||
-					!purple_strequal(node, jbr->caps.info->tuple.node) ||
-					!purple_strequal(ver, jbr->caps.info->tuple.ver) ||
-					!purple_strequal(hash, jbr->caps.info->tuple.hash) ||
-					!jabber_caps_exts_known(jbr->caps.info, (gchar **)exts)) {
+			if(jbr == NULL || jbr->caps == NULL ||
+			   !purple_strequal(node, jbr->caps->tuple.node) ||
+			   !purple_strequal(ver, jbr->caps->tuple.ver) ||
+			   !purple_strequal(hash, jbr->caps->tuple.hash))
+			{
 				JabberPresenceCapabilities *userdata = g_new0(JabberPresenceCapabilities, 1);
 				userdata->js = js;
 				userdata->jb = presence.jb;
 				userdata->from = g_strdup(presence.from);
-				jabber_caps_get_info(js, presence.from, node, ver, hash, exts,
+				jabber_caps_get_info(js, presence.from, node, ver, hash,
 				    (jabber_caps_get_info_cb)jabber_presence_set_capabilities,
 				    userdata);
-			} else {
-				if (exts)
-					g_strfreev(exts);
 			}
 		}
 	}
