# HG changeset patch # User Tobias Markmann # Date 1214749953 0 # Node ID a5e437b7f915658e3c7e003e1c5fa68ce37478df # Parent 9867a406707e3197ac50fe49625f0cd3d32d398c * implemented jabber_caps_calcualte_hash() which calculates the SHA-1 hash for someones disco response according to XEP-0115 diff -r 9867a406707e -r a5e437b7f915 libpurple/protocols/jabber/caps.c --- a/libpurple/protocols/jabber/caps.c Sun Jun 22 18:59:33 2008 +0000 +++ b/libpurple/protocols/jabber/caps.c Sun Jun 29 14:32:33 2008 +0000 @@ -383,7 +383,7 @@ --userdata->extOutstanding; /* TODO: Better error handling */ - + printf("\n\tjabber_caps_ext_iqcb for %s", xmlnode_get_attrib(packet, "from")); if(node && query) { const char *key; JabberCapsValue *client; @@ -446,7 +446,7 @@ jabber_caps_cbplususerdata *userdata = data; /* TODO: Better error checking! */ - + printf("\n\tjabber_caps_client_iqcb for %s", xmlnode_get_attrib(packet, "from")); if (query) { JabberCapsValue *value = g_new0(JabberCapsValue, 1); @@ -605,6 +605,14 @@ return strcmp(ac, bc); } +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_caps_jabber_xdata_compare(gconstpointer a, gconstpointer b) { const xmlnode *ac; const xmlnode *bc; @@ -617,13 +625,10 @@ ac = a; bc = b; - aformtypefield = xmlnode_get_child(ac, "field"); - while (aformtypefield && strcmp(xmlnode_get_attrib(aformtypefield, "var"), "FORM_TYPE")) aformtypefield = xmlnode_get_next_twin(aformtypefield); - aformtype = xmlnode_get_data(aformtypefield); + + aformtype = jabber_caps_get_formtype(aformtypefield); - bformtypefield = xmlnode_get_child(bc, "field"); - while (bformtypefield && strcmp(xmlnode_get_attrib(bformtypefield, "var"), "FORM_TYPE")) bformtypefield = xmlnode_get_next_twin(bformtypefield); - bformtype = xmlnode_get_data(bformtypefield); + bformtype = jabber_caps_get_formtype(bformtypefield); result = strcmp(aformtype, bformtype); g_free(aformtype); @@ -669,13 +674,132 @@ return info; } +static gint jabber_caps_xdata_field_compare(gconstpointer a, gconstpointer b) { + const JabberDataFormField *ac; + const JabberDataFormField *bc; + + ac = a; + bc = b; + + return strcmp(ac->var, bc->var); +} + +GList *jabber_caps_xdata_get_fields(xmlnode *x) { + GList *fields = 0; + xmlnode *field; + xmlnode *value; + JabberDataFormField *xdatafield; + + if(!x) return 0; + + for(field = xmlnode_get_child(x, "field"); field != 0; field = xmlnode_get_next_twin(field)) { + xdatafield = g_new0(JabberDataFormField, 1); + xdatafield->var = g_strdup(xmlnode_get_attrib(field, "var")); + for(value = xmlnode_get_child(field, "value"); value != 0; value = xmlnode_get_next_twin(value)) { + gchar *val = xmlnode_get_data(value); + xdatafield->values = g_list_append(xdatafield->values, val); + } + xdatafield->values = g_list_sort(xdatafield->values, jabber_caps_string_compare); + fields = g_list_append(fields, xdatafield); + } + fields = g_list_sort(fields, jabber_caps_xdata_field_compare); + return fields; +} + +gchar *jabber_caps_verification_append(gchar *verification_string, gchar *string) { + gchar *verification; + verification = g_strconcat(verification_string, string, "<", NULL); + g_free(verification_string); + return verification; +} + gchar *jabber_caps_calcualte_hash(JabberCapsClientInfo *info) { + GList *identities; + GList *features; + GList *xdata; + gchar *verification = 0; + gchar *feature_string; + gchar *free_verification; + gchar *identity_string; + PurpleCipherContext *context; + guint8 checksum[20]; + gsize checksum_size = 20; + if (!info) return 0; /* sort identities, features and x-data forms */ info->identities = g_list_sort(info->identities, jabber_caps_jabber_identity_compare); info->features = g_list_sort(info->features, jabber_caps_string_compare); info->forms = g_list_sort(info->forms, jabber_caps_jabber_xdata_compare); + + /* concat identities to the verification string */ + for(identities = info->identities; identities; identities = identities->next) { + JabberIdentity *ident = (JabberIdentity*)identities->data; + identity_string = g_strdup_printf("%s/%s//%s<", ident->category, ident->type, ident->name); + free_verification = verification; + if(verification == 0) verification = g_strdup(identity_string); + else verification = g_strconcat(verification, identity_string, NULL); + g_free(identity_string); + g_free(free_verification); + } + + /* concat features to the verification string */ + for(features = info->features; features; features = features->next) { + feature_string = g_strdup_printf("%s<", (gchar*)features->data); + verification = jabber_caps_verification_append(verification, feature_string); + g_free(feature_string); + } + + /* concat x-data forms to the verification string */ + for(xdata = info->forms; xdata; xdata = xdata->next) { + gchar *formtype = 0; + GList *fields; + /* append FORM_TYPE's field value to the verification string */ + formtype = jabber_caps_get_formtype((xmlnode*)xdata->data); + verification = jabber_caps_verification_append(verification, formtype); + g_free(formtype); + + for(fields = jabber_caps_xdata_get_fields((xmlnode*)(xdata->data)); fields != 0; fields = fields->next) { + GList *value; + JabberDataFormField *field = (JabberDataFormField*)fields; + if(strcmp(field->var, "FORM_TYPE")) { + /* Append the value of the "var" attribute, followed by the '<' character. */ + verification = jabber_caps_verification_append(verification, field->var); + /* For each element, append the XML character data, followed by the '<' character. */ + for(value = field->values; value != 0; value = value->next) { + verification = jabber_caps_verification_append(verification, value->data); + } + } + for(value = field->values; value != 0; value = value->next) { + g_free(value->data); + } + g_free(field->var); + g_list_free(field->values); + } + g_list_free(fields); + } + + /* generate SHA-1 hash */ + context = purple_cipher_context_new_by_name("sha1", NULL); + if (context == NULL) { + purple_debug_error("jabber", "Could not find sha1 cipher\n"); + return 0; + } + purple_cipher_context_append(context, verification, strlen(verification)); + + if (!purple_cipher_context_digest(context, strlen(verification), checksum, &checksum_size)) { + purple_debug_error("util", "Failed to get SHA-1 digest.\n"); + } + purple_cipher_context_destroy(context); + + /* apply Base64 on hash */ + + g_free(verification); + verification = purple_base64_encode(checksum, checksum_size); + printf("\n%s", verification); + + if (caps_hash != 0) g_free(caps_hash); + return verification; } void jabber_caps_calculate_own_hash() { @@ -713,9 +837,7 @@ else verification = g_strconcat(verification, feature_string, NULL); g_free(feature_string); if(free_verification) g_free(free_verification); - } - printf("\n%s", verification); - + } /* generate SHA-1 hash */ context = purple_cipher_context_new_by_name("sha1", NULL); @@ -734,7 +856,6 @@ g_free(verification); verification = purple_base64_encode(checksum, checksum_size); // for 2.0 compability - printf("\n%s", verification); if (caps_hash != 0) g_free(caps_hash); caps_hash = verification; diff -r 9867a406707e -r a5e437b7f915 libpurple/protocols/jabber/caps.h --- a/libpurple/protocols/jabber/caps.h Sun Jun 22 18:59:33 2008 +0000 +++ b/libpurple/protocols/jabber/caps.h Sun Jun 29 14:32:33 2008 +0000 @@ -36,6 +36,11 @@ GList *forms; /* xmlnode * */ }; +typedef struct _JabberDataFormField { + gchar *var; + GList *values; +} JabberDataFormField; + typedef void (*jabber_caps_get_info_cb)(JabberCapsClientInfo *info, gpointer user_data); void jabber_caps_init(void);