# HG changeset patch # User Paul Aurich # Date 1241750319 0 # Node ID d0a049ede31edec77d0466b9acb898bd2e0d0d58 # Parent 70fdb6fc8aee33bfbddff8bc6fa3c1c9a3a373e7 Only call jabber_caps_get_info if we don't have all the information we want. Has the pleasant side-effect of *not* polling for adhoc commands every time we get presence (this should make MattJ happy). diff -r 70fdb6fc8aee -r d0a049ede31e libpurple/protocols/jabber/caps.c --- a/libpurple/protocols/jabber/caps.c Thu May 07 23:46:11 2009 +0000 +++ b/libpurple/protocols/jabber/caps.c Fri May 08 02:38:39 2009 +0000 @@ -346,6 +346,27 @@ 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) { + /* Hack since we advertise the ext but don't have any */ + if (g_str_equal(exts[i], "voice-v1") && !info->exts) + continue; + if (!info->exts || + !g_hash_table_lookup(info->exts->exts, exts[i])) + return FALSE; + } + + return TRUE; +} + typedef struct _jabber_caps_cbplususerdata { guint ref; @@ -539,16 +560,19 @@ } void jabber_caps_get_info(JabberStream *js, const char *who, const char *node, - const char *ver, const char *hash, const char *ext, + const char *ver, const char *hash, char **exts, jabber_caps_get_info_cb cb, gpointer user_data) { JabberCapsClientInfo *info; JabberCapsTuple key; jabber_caps_cbplususerdata *userdata; - if (ext && *ext && hash) + if (exts && hash) { purple_debug_info("jabber", "Ignoring exts in new-style caps from %s\n", who); + g_strfreev(exts); + exts = NULL; + } /* Using this in a read-only fashion, so the cast is OK */ key.node = (char *)node; @@ -597,9 +621,8 @@ } /* Are there any exts that we don't recognize? */ - if (ext && *ext && !hash) { + if (exts) { JabberCapsNodeExts *node_exts; - gchar **splat = g_strsplit(ext, " ", 0); int i; if (info) { @@ -611,23 +634,23 @@ /* We'll put it in later once we have the client info */ node_exts = userdata->node_exts = jabber_caps_find_exts_by_node(node); - for (i = 0; splat[i]; ++i) { - userdata->exts = g_list_prepend(userdata->exts, splat[i]); + 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, splat[i])) { + if (!g_hash_table_lookup(node_exts->exts, exts[i])) { JabberIq *iq; xmlnode *query; char *nodeext; ext_iq_data *cbdata = g_new(ext_iq_data, 1); - cbdata->name = splat[i]; + cbdata->name = exts[i]; cbdata->data = cbplususerdata_ref(userdata); iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#info"); query = xmlnode_get_child_with_namespace(iq->node, "query", "http://jabber.org/protocol/disco#info"); - nodeext = g_strdup_printf("%s#%s", node, splat[i]); + nodeext = g_strdup_printf("%s#%s", node, exts[i]); xmlnode_set_attrib(query, "node", nodeext); g_free(nodeext); xmlnode_set_attrib(iq->node, "to", who); @@ -637,11 +660,11 @@ ++userdata->extOutstanding; } - splat[i] = NULL; + exts[i] = NULL; } /* All the strings are now part of the GList, so don't need * g_strfreev. */ - g_free(splat); + g_free(exts); } if (userdata->info && userdata->extOutstanding == 0) { diff -r 70fdb6fc8aee -r d0a049ede31e libpurple/protocols/jabber/caps.h --- a/libpurple/protocols/jabber/caps.h Thu May 07 23:46:11 2009 +0000 +++ b/libpurple/protocols/jabber/caps.h Fri May 08 02:38:39 2009 +0000 @@ -68,7 +68,10 @@ void jabber_caps_init(void); void jabber_caps_uninit(void); -void jabber_caps_destroy_key(gpointer value); +/** + * 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 capabilites function to get the capabilities of a contact. @@ -76,10 +79,13 @@ * 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. */ void jabber_caps_get_info(JabberStream *js, const char *who, const char *node, const char *ver, const char *hash, - const char *ext, jabber_caps_get_info_cb cb, + char **exts, jabber_caps_get_info_cb cb, gpointer user_data); /** diff -r 70fdb6fc8aee -r d0a049ede31e libpurple/protocols/jabber/presence.c --- a/libpurple/protocols/jabber/presence.c Thu May 07 23:46:11 2009 +0000 +++ b/libpurple/protocols/jabber/presence.c Fri May 08 02:38:39 2009 +0000 @@ -854,13 +854,26 @@ /* v1.3 uses: node, ver, and optionally ext. * v1.5 uses: node, ver, and hash. */ if (node && *node && ver && *ver) { - JabberPresenceCapabilities *userdata = g_new0(JabberPresenceCapabilities, 1); - userdata->js = js; - userdata->jb = jb; - userdata->from = g_strdup(from); - jabber_caps_get_info(js, from, node, ver, hash, ext, - (jabber_caps_get_info_cb)jabber_presence_set_capabilities, - userdata); + gchar **exts = ext && *ext ? g_strsplit(ext, " ", -1) : NULL; + jbr = jabber_buddy_find_resource(jb, jid->resource); + + /* Look it up if we don't already have all this information */ + if (!jbr || !jbr->caps.info || + !g_str_equal(node, jbr->caps.info->tuple.node) || + !g_str_equal(ver, jbr->caps.info->tuple.ver) || + !purple_strequal(hash, jbr->caps.info->tuple.hash) || + !jabber_caps_exts_known(jbr->caps.info, (gchar **)exts)) { + JabberPresenceCapabilities *userdata = g_new0(JabberPresenceCapabilities, 1); + userdata->js = js; + userdata->jb = jb; + userdata->from = g_strdup(from); + jabber_caps_get_info(js, from, node, ver, hash, exts, + (jabber_caps_get_info_cb)jabber_presence_set_capabilities, + userdata); + } else { + if (exts) + g_strfreev(exts); + } } }