changeset 25021:a5e437b7f915

* implemented jabber_caps_calcualte_hash() which calculates the SHA-1 hash for someones disco response according to XEP-0115
author Tobias Markmann <tfar@soc.pidgin.im>
date Sun, 29 Jun 2008 14:32:33 +0000
parents 9867a406707e
children 4c97156431b4
files libpurple/protocols/jabber/caps.c libpurple/protocols/jabber/caps.h
diffstat 2 files changed, 138 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- 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 <value/> 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;
--- 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);