# HG changeset patch # User Sadrul Habib Chowdhury # Date 1278947718 0 # Node ID 28d5f60910c9b32c84551fc518e09a9f62f1aeff # Parent 1f44f0144ff8b7f6ed1b06ff9704372c26e19f07# Parent 7c5f2e776ceb4252fa96f7b78e9a6ab48763b540 merge of '6eb94bb98b242b76b07fe78fe89d136b9201d6f1' and 'a61565c363dde22672cf7caafa30d1279ec84f33' diff -r 1f44f0144ff8 -r 28d5f60910c9 libpurple/protocols/jabber/caps.c --- a/libpurple/protocols/jabber/caps.c Mon Jul 12 15:13:31 2010 +0000 +++ b/libpurple/protocols/jabber/caps.c Mon Jul 12 15:15:18 2010 +0000 @@ -29,6 +29,7 @@ #include "iq.h" #include "presence.h" #include "util.h" +#include "xdata.h" #define JABBER_CAPS_FILENAME "xmpp-caps.xml" @@ -45,8 +46,10 @@ static void free_string_glist(GList *list) { - g_list_foreach(list, (GFunc)g_free, NULL); - g_list_free(list); + while (list) { + g_free(list->data); + list = g_list_delete_link(list, list); + } } static JabberCapsNodeExts* @@ -230,15 +233,15 @@ if(!capsdata) return; - if (strcmp(capsdata->name, "capabilities") != 0) { + if (!g_str_equal(capsdata->name, "capabilities")) { xmlnode_free(capsdata); return; } - for(client = capsdata->child; client; client = client->next) { - if(client->type != XMLNODE_TYPE_TAG) + for (client = capsdata->child; client; client = client->next) { + if (client->type != XMLNODE_TYPE_TAG) continue; - if(!strcmp(client->name, "client")) { + if (g_str_equal(client->name, "client")) { JabberCapsClientInfo *value = g_new0(JabberCapsClientInfo, 1); JabberCapsTuple *key = (JabberCapsTuple*)&value->tuple; xmlnode *child; @@ -251,15 +254,15 @@ if (key->hash == NULL) exts = jabber_caps_find_exts_by_node(key->node); - for(child = client->child; child; child = child->next) { - if(child->type != XMLNODE_TYPE_TAG) + for (child = client->child; child; child = child->next) { + if (child->type != XMLNODE_TYPE_TAG) continue; - if(!strcmp(child->name,"feature")) { + if (g_str_equal(child->name, "feature")) { const char *var = xmlnode_get_attrib(child, "var"); if(!var) continue; value->features = g_list_append(value->features,g_strdup(var)); - } else if(!strcmp(child->name,"identity")) { + } else if (g_str_equal(child->name, "identity")) { const char *category = xmlnode_get_attrib(child, "category"); const char *type = xmlnode_get_attrib(child, "type"); const char *name = xmlnode_get_attrib(child, "name"); @@ -276,15 +279,15 @@ id->lang = g_strdup(lang); value->identities = g_list_append(value->identities,id); - } else if(!strcmp(child->name,"x")) { + } else if (g_str_equal(child->name, "x")) { /* TODO: See #7814 -- this might cause problems if anyone * ever actually specifies forms. In fact, for this to * work properly, that bug needs to be fixed in * xmlnode_from_str, not the output version... */ value->forms = g_list_append(value->forms, xmlnode_copy(child)); - } else if (!strcmp(child->name, "ext") && key->hash != NULL) { + } else if (g_str_equal(child->name, "ext") && key->hash != NULL) { purple_debug_warning("jabber", "Ignoring exts when reading new-style caps\n"); - } else if (!strcmp(child->name, "ext")) { + } else if (g_str_equal(child->name, "ext")) { /* TODO: Do we care about reading in the identities listed here? */ const char *identifier = xmlnode_get_attrib(child, "identifier"); xmlnode *node; @@ -296,7 +299,7 @@ for (node = child->child; node; node = node->next) { if (node->type != XMLNODE_TYPE_TAG) continue; - if (!strcmp(node->name, "feature")) { + if (g_str_equal(node->name, "feature")) { const char *var = xmlnode_get_attrib(node, "var"); if (!var) continue; @@ -455,13 +458,13 @@ * size in jabber_caps_calculate_hash is large enough. The cipher API * doesn't seem to offer a "Get the hash size" function(?). */ - if (!strcmp(userdata->hash, "sha-1")) { + if (g_str_equal(userdata->hash, "sha-1")) { hash = jabber_caps_calculate_hash(info, "sha1"); - } else if (!strcmp(userdata->hash, "md5")) { + } else if (g_str_equal(userdata->hash, "md5")) { hash = jabber_caps_calculate_hash(info, "md5"); } - if (!hash || strcmp(hash, userdata->ver)) { + if (!hash || !g_str_equal(hash, userdata->ver)) { purple_debug_warning("jabber", "Could not validate caps info from " "%s. Expected %s, got %s\n", xmlnode_get_attrib(packet, "from"), @@ -701,44 +704,6 @@ } static gint -jabber_identity_compare(gconstpointer a, gconstpointer b) -{ - const JabberIdentity *ac; - const JabberIdentity *bc; - gint cat_cmp; - gint typ_cmp; - - ac = a; - bc = b; - - if ((cat_cmp = strcmp(ac->category, bc->category)) == 0) { - if ((typ_cmp = strcmp(ac->type, bc->type)) == 0) { - if (!ac->lang && !bc->lang) { - return 0; - } else if (ac->lang && !bc->lang) { - return 1; - } else if (!ac->lang && bc->lang) { - return -1; - } else { - return strcmp(ac->lang, bc->lang); - } - } else { - return typ_cmp; - } - } else { - return cat_cmp; - } -} - -static gchar *jabber_caps_get_formtype(const xmlnode *x) { - xmlnode *formtypefield; - formtypefield = xmlnode_get_child(x, "field"); - while (formtypefield && strcmp(xmlnode_get_attrib(formtypefield, "var"), "FORM_TYPE")) formtypefield = xmlnode_get_next_twin(formtypefield); - formtypefield = xmlnode_get_child(formtypefield, "value"); - return xmlnode_get_data(formtypefield);; -} - -static gint jabber_xdata_compare(gconstpointer a, gconstpointer b) { const xmlnode *aformtypefield = a; @@ -747,8 +712,8 @@ char *bformtype; int result; - aformtype = jabber_caps_get_formtype(aformtypefield); - bformtype = jabber_caps_get_formtype(bformtypefield); + aformtype = jabber_x_data_get_formtype(aformtypefield); + bformtype = jabber_x_data_get_formtype(bformtypefield); result = strcmp(aformtype, bformtype); g_free(aformtype); @@ -770,7 +735,7 @@ for(child = query->child; child; child = child->next) { if (child->type != XMLNODE_TYPE_TAG) continue; - if (!strcmp(child->name,"identity")) { + if (g_str_equal(child->name, "identity")) { /* parse identity */ const char *category = xmlnode_get_attrib(child, "category"); const char *type = xmlnode_get_attrib(child, "type"); @@ -788,13 +753,13 @@ id->lang = g_strdup(lang); info->identities = g_list_append(info->identities, id); - } else if (!strcmp(child->name, "feature")) { + } else if (g_str_equal(child->name, "feature")) { /* parse feature */ const char *var = xmlnode_get_attrib(child, "var"); if (var) info->features = g_list_prepend(info->features, g_strdup(var)); - } else if (!strcmp(child->name, "x")) { - if (child->xmlns && !strcmp(child->xmlns, "jabber:x:data")) { + } else if (g_str_equal(child->name, "x")) { + if (purple_strequal(child->xmlns, "jabber:x:data")) { /* x-data form */ xmlnode *dataform = xmlnode_copy(child); info->forms = g_list_append(info->forms, dataform); @@ -900,7 +865,7 @@ /* concat x-data forms to the verification string */ for(node = info->forms; node; node = node->next) { xmlnode *data = (xmlnode *)node->data; - gchar *formtype = jabber_caps_get_formtype(data); + gchar *formtype = jabber_x_data_get_formtype(data); GList *fields = jabber_caps_xdata_get_fields(data); /* append FORM_TYPE's field value to the verification string */ @@ -961,6 +926,10 @@ } info.features = features; + /* TODO: This copy can go away, I think, since jabber_identities + * is pre-sorted, so the sort in calculate_hash should be idempotent. + * However, I want to test that. --darkrain + */ info.identities = g_list_copy(jabber_identities); info.forms = NULL; @@ -985,7 +954,7 @@ for (node = accounts; node; node = node->next) { PurpleAccount *account = node->data; const char *prpl_id = purple_account_get_protocol_id(account); - if (!strcmp("prpl-jabber", prpl_id) && purple_account_is_connected(account)) { + if (g_str_equal("prpl-jabber", prpl_id) && purple_account_is_connected(account)) { PurpleConnection *gc = purple_account_get_connection(account); jabber_presence_send(gc->proto_data, TRUE); } diff -r 1f44f0144ff8 -r 28d5f60910c9 libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Mon Jul 12 15:13:31 2010 +0000 +++ b/libpurple/protocols/jabber/jabber.c Mon Jul 12 15:15:18 2010 +0000 @@ -1962,20 +1962,53 @@ } } -void jabber_add_identity(const gchar *category, const gchar *type, const gchar *lang, const gchar *name) { +gint +jabber_identity_compare(gconstpointer a, gconstpointer b) +{ + const JabberIdentity *ac; + const JabberIdentity *bc; + gint cat_cmp; + gint typ_cmp; + + ac = a; + bc = b; + + if ((cat_cmp = strcmp(ac->category, bc->category)) == 0) { + if ((typ_cmp = strcmp(ac->type, bc->type)) == 0) { + if (!ac->lang && !bc->lang) { + return 0; + } else if (ac->lang && !bc->lang) { + return 1; + } else if (!ac->lang && bc->lang) { + return -1; + } else { + return strcmp(ac->lang, bc->lang); + } + } else { + return typ_cmp; + } + } else { + return cat_cmp; + } +} + +void jabber_add_identity(const gchar *category, const gchar *type, + const gchar *lang, const gchar *name) +{ GList *identity; JabberIdentity *ident; + /* both required according to XEP-0030 */ g_return_if_fail(category != NULL); g_return_if_fail(type != NULL); - for(identity = jabber_identities; identity; identity = identity->next) { - JabberIdentity *ident = (JabberIdentity*)identity->data; - if (!strcmp(ident->category, category) && - !strcmp(ident->type, type) && - ((!ident->lang && !lang) || (ident->lang && lang && !strcmp(ident->lang, lang)))) { + /* Check if this identity is already there... */ + for (identity = jabber_identities; identity; identity = identity->next) { + JabberIdentity *id = identity->data; + if (g_str_equal(id->category, category) && + g_str_equal(id->type, type) && + purple_strequal(id->lang, lang)) return; - } } ident = g_new0(JabberIdentity, 1); @@ -1983,7 +2016,8 @@ ident->type = g_strdup(type); ident->lang = g_strdup(lang); ident->name = g_strdup(name); - jabber_identities = g_list_prepend(jabber_identities, ident); + jabber_identities = g_list_insert_sorted(jabber_identities, ident, + jabber_identity_compare); } static void jabber_identities_destroy(void) diff -r 1f44f0144ff8 -r 28d5f60910c9 libpurple/protocols/jabber/jabber.h --- a/libpurple/protocols/jabber/jabber.h Mon Jul 12 15:13:31 2010 +0000 +++ b/libpurple/protocols/jabber/jabber.h Mon Jul 12 15:15:18 2010 +0000 @@ -303,6 +303,9 @@ /* what kind of additional features as returned from disco#info are supported? */ extern GList *jabber_features; +/* A sorted list of identities advertised. Use jabber_add_identity to add + * so it remains sorted. + */ extern GList *jabber_identities; void jabber_stream_features_parse(JabberStream *js, xmlnode *packet); @@ -342,6 +345,11 @@ void jabber_add_identity(const gchar *category, const gchar *type, const gchar *lang, const gchar *name); /** + * GCompareFunc for JabberIdentity structs. + */ +gint jabber_identity_compare(gconstpointer a, gconstpointer b); + +/** * Returns true if this connection is over a secure (SSL) stream. Use this * instead of checking js->gsc because BOSH stores its PurpleSslConnection * members in its own data structure. diff -r 1f44f0144ff8 -r 28d5f60910c9 libpurple/protocols/jabber/xdata.c --- a/libpurple/protocols/jabber/xdata.c Mon Jul 12 15:13:31 2010 +0000 +++ b/libpurple/protocols/jabber/xdata.c Mon Jul 12 15:15:18 2010 +0000 @@ -411,4 +411,30 @@ return handle; } +gchar * +jabber_x_data_get_formtype(const xmlnode *form) +{ + xmlnode *field; + g_return_val_if_fail(form != NULL, NULL); + + for (field = xmlnode_get_child((xmlnode *)form, "field"); field; + field = xmlnode_get_next_twin(field)) { + const char *var = xmlnode_get_attrib(field, "var"); + if (purple_strequal(var, "FORM_TYPE")) { + xmlnode *value = xmlnode_get_child(field, "value"); + if (value) + return xmlnode_get_data(value); + else + /* An interesting corner case... Looking for a second + * FORM_TYPE would be more considerate, but I'm in favor + * of not helping broken clients. + */ + return NULL; + } + } + + /* Erm, none found :( */ + return NULL; +} + diff -r 1f44f0144ff8 -r 28d5f60910c9 libpurple/protocols/jabber/xdata.h --- a/libpurple/protocols/jabber/xdata.h Mon Jul 12 15:13:31 2010 +0000 +++ b/libpurple/protocols/jabber/xdata.h Mon Jul 12 15:15:18 2010 +0000 @@ -37,4 +37,19 @@ void *jabber_x_data_request(JabberStream *js, xmlnode *packet, jabber_x_data_cb cb, gpointer user_data); void *jabber_x_data_request_with_actions(JabberStream *js, xmlnode *packet, GList *actions, int defaultaction, jabber_x_data_action_cb cb, gpointer user_data); +/* + * Return the form type (the CDATA of the value child of the FORM_TYPE + * field entry. + * E.g., for the following, "http://jabber.org/protocol/muc#roominfo". + * + * + * http://jabber.org/protocol/muc#roominfo + * + * + * + * @param form The xmlnode for the form (the 'x' element) + * @returns The FORM_TYPE. Must be freed by caller. + */ +gchar *jabber_x_data_get_formtype(const xmlnode *form); + #endif /* PURPLE_JABBER_XDATA_H_ */ diff -r 1f44f0144ff8 -r 28d5f60910c9 libpurple/xmlnode.c --- a/libpurple/xmlnode.c Mon Jul 12 15:13:31 2010 +0000 +++ b/libpurple/xmlnode.c Mon Jul 12 15:15:18 2010 +0000 @@ -223,7 +223,7 @@ const char * -xmlnode_get_attrib(xmlnode *node, const char *attr) +xmlnode_get_attrib(const xmlnode *node, const char *attr) { xmlnode *x; @@ -240,9 +240,9 @@ } const char * -xmlnode_get_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns) +xmlnode_get_attrib_with_namespace(const xmlnode *node, const char *attr, const char *xmlns) { - xmlnode *x; + const xmlnode *x; g_return_val_if_fail(node != NULL, NULL); g_return_val_if_fail(attr != NULL, NULL); diff -r 1f44f0144ff8 -r 28d5f60910c9 libpurple/xmlnode.h --- a/libpurple/xmlnode.h Mon Jul 12 15:13:31 2010 +0000 +++ b/libpurple/xmlnode.h Mon Jul 12 15:15:18 2010 +0000 @@ -205,7 +205,7 @@ * * @return The value of the attribute. */ -const char *xmlnode_get_attrib(xmlnode *node, const char *attr); +const char *xmlnode_get_attrib(const xmlnode *node, const char *attr); /** * Gets a namespaced attribute from a node @@ -216,7 +216,7 @@ * * @return The value of the attribute/ */ -const char *xmlnode_get_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns); +const char *xmlnode_get_attrib_with_namespace(const xmlnode *node, const char *attr, const char *xmlns); /** * Removes an attribute from a node.