changeset 29830:38926d6e5ae1

propagate from branch 'im.pidgin.pidgin' (head 83880c1513774ae8550442dfe002355056d39021) to branch 'im.pidgin.cpw.malu.ft_thumbnails' (head ce7131f6a58510cde83d0cb3945eca0795e1e2aa)
author Marcus Lundblad <ml@update.uu.se>
date Wed, 24 Mar 2010 19:56:07 +0000
parents 33a4d72232a7 (diff) 90dbc46a771f (current diff)
children 816041183dda
files libpurple/protocols/jabber/data.c libpurple/protocols/jabber/data.h libpurple/protocols/jabber/message.c
diffstat 7 files changed, 153 insertions(+), 143 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Mar 22 22:26:14 2010 +0000
+++ b/ChangeLog	Wed Mar 24 19:56:07 2010 +0000
@@ -55,7 +55,9 @@
 	  rjoly for testing)
 	* When sending data using in-band-bytestreams, interpret the block-size
 	  attribute as the size of the BASE64-encoded representation of the data.
-	* Validate the hash on incoming BoB data objects (for custom smileys etc.).
+	* Validate the hash on incoming BoB data objects (for custom smileys etc.),
+	  cache based per JID when the CID is not a valid hash (as specified by the
+	  BoB XEP).
 
 	Yahoo:
 	* Attempt to better handle transparent proxies interfering with HTTP-based
--- a/doc/gtkimhtml-signals.dox	Mon Mar 22 22:26:14 2010 +0000
+++ b/doc/gtkimhtml-signals.dox	Wed Mar 24 19:56:07 2010 +0000
@@ -6,7 +6,7 @@
   @signal format_function_clear
   @signal format_function_toggle
   @signal format_function_update
-  @paste
+  @signal paste
  @endsignals
 
  @see gtkimhtml.h
--- a/finch/libgnt/gntbox.c	Mon Mar 22 22:26:14 2010 +0000
+++ b/finch/libgnt/gntbox.c	Wed Mar 24 19:56:07 2010 +0000
@@ -27,6 +27,9 @@
 
 #include <string.h>
 
+#define PROP_LAST_RESIZE_S "last-resize"
+#define PROP_SIZE_QUEUED_S "size-queued"
+
 enum
 {
 	PROP_0,
@@ -194,7 +197,7 @@
 	GntBox *box = GNT_BOX(widget);
 	GList *iter;
 	int maxw = 0, maxh = 0;
-	
+
 	g_list_foreach(box->list, (GFunc)gnt_widget_size_request, NULL);
 
 	for (iter = box->list; iter; iter = iter->next)
@@ -398,6 +401,7 @@
 	GList *iter;
 	GntBox *box = GNT_BOX(widget);
 	int wchange, hchange;
+	GntWidget *child, *last;
 
 	if (!box->list)
 		return TRUE;
@@ -406,67 +410,59 @@
 	hchange = widget->priv.height - height;
 
 	if (wchange == 0 && hchange == 0)
-		return TRUE;		/* Quit playing games */
+		return TRUE;		/* Quit playing games with my size */
 
-	/* XXX: Right now, I am trying to just apply all the changes to 
-	 * just one widget. It should be possible to distribute the
-	 * changes to all the widgets in the box. */
-	for (iter = box->list; iter; iter = iter->next)
-	{
+	child = NULL;
+	last = g_object_get_data(G_OBJECT(box), PROP_LAST_RESIZE_S);
+
+	/* First, make sure all the widgets will fit into the box after resizing. */
+	for (iter = box->list; iter; iter = iter->next) {
 		GntWidget *wid = iter->data;
 		int w, h;
 
 		gnt_widget_get_size(wid, &w, &h);
 
-		if (gnt_widget_confirm_size(wid, w - wchange, h - hchange))
-		{
-			GList *i;
-
-			for (i = box->list; i; i = i->next)
-			{
-				int tw, th;
-				if (i == iter) continue;
-				gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th);
-				if (box->vertical)
-				{
-					if (!gnt_widget_confirm_size(i->data, tw - wchange, th)) {
-						/* If we are decreasing the size and the widget is going
-						 * to be too large to fit into the box, then do not allow
-						 * resizing. */
-						if (wchange > 0 && tw >= widget->priv.width)
-							return FALSE;
-					}
-				}
-				else
-				{
-					if (!gnt_widget_confirm_size(i->data, tw, th - hchange)) {
-						if (hchange > 0 && th >= widget->priv.height)
-							return FALSE;
-						return FALSE;
-					}
-				}
-			}
-#if 0
-			gnt_widget_set_size(wid, w - wchange, h - hchange);
-			if (box->vertical)
-				hchange = 0;
-			else
-				wchange = 0;
-
-			for (i = box->list; i; i = i->next)
-			{
-				int tw, th;
-				if (i == iter) continue;
-				gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th);
-				gnt_widget_set_size(i->data, tw - wchange, th - hchange);
-			}
-#endif
-			g_object_set_data(G_OBJECT(box), "size-queued", wid);
-			return TRUE;
+		if (wid != last && !child && gnt_widget_confirm_size(wid, w - wchange, h - hchange)) {
+			child = wid;
+			break;
 		}
 	}
 
-	return FALSE;
+	if (!child && (child = last)) {
+		int w, h;
+		gnt_widget_get_size(child, &w, &h);
+		if (!gnt_widget_confirm_size(child, w - wchange, h - hchange))
+			child = NULL;
+	}
+
+	g_object_set_data(G_OBJECT(box), PROP_SIZE_QUEUED_S, child);
+
+	if (child) {
+		for (iter = box->list; iter; iter = iter->next) {
+			GntWidget *wid = iter->data;
+			int w, h;
+
+			gnt_widget_get_size(wid, &w, &h);
+			if (box->vertical) {
+				/* For a vertical box, if we are changing the width, make sure the widgets
+				 * in the box will fit after resizing the width. */
+				if (wchange > 0 &&
+						w >= child->priv.width &&
+						!gnt_widget_confirm_size(wid, w - wchange, h))
+					return FALSE;
+			} else {
+				/* If we are changing the height, make sure the widgets in the box fit after
+				 * the resize. */
+				if (hchange > 0 &&
+						h >= child->priv.height &&
+						!gnt_widget_confirm_size(wid, w, h - hchange))
+					return FALSE;
+			}
+
+		}
+	}
+
+	return (child != NULL);
 }
 
 static void
@@ -477,16 +473,16 @@
 	GntBox *box = GNT_BOX(widget);
 	GntWidget *wid;
 	int tw, th;
-		
+
 	wchange = widget->priv.width - oldw;
 	hchange = widget->priv.height - oldh;
-	
-	wid = g_object_get_data(G_OBJECT(box), "size-queued");
-	if (wid)
-	{
+
+	wid = g_object_get_data(G_OBJECT(box), PROP_SIZE_QUEUED_S);
+	if (wid) {
 		gnt_widget_get_size(wid, &tw, &th);
 		gnt_widget_set_size(wid, tw + wchange, th + hchange);
-		g_object_set_data(G_OBJECT(box), "size-queued", NULL);
+		g_object_set_data(G_OBJECT(box), PROP_SIZE_QUEUED_S, NULL);
+		g_object_set_data(G_OBJECT(box), PROP_LAST_RESIZE_S, wid);
 	}
 
 	if (box->vertical)
--- a/libpurple/protocols/jabber/data.c	Mon Mar 22 22:26:14 2010 +0000
+++ b/libpurple/protocols/jabber/data.c	Wed Mar 24 19:56:07 2010 +0000
@@ -55,58 +55,6 @@
 	return data;
 }
 
-
-static gboolean
-jabber_data_has_valid_hash(const JabberData *data)
-{
-	const gchar *cid = jabber_data_get_cid(data);
-	gchar **cid_parts = g_strsplit(cid, "@", -1);
-	gchar **iter;
-	int num_parts = 0;
-
-	purple_debug_info("jabber", "validating BoB hash %s\n", cid);
-	
-	for (iter = cid_parts; *iter != NULL ; iter++) {
-		num_parts++;
-	}
-
-	if (num_parts == 2 && purple_strequal(cid_parts[1], "bob.xmpp.org")) {
-		gchar **sub_parts = g_strsplit(cid_parts[0], "+", -1);
-
-		num_parts = 0;
-		for (iter = sub_parts ; *iter != NULL ; iter++) {
-			num_parts++;
-		}
-
-		if (num_parts == 2) {
-			const gchar *hash_algo = sub_parts[0];
-			const gchar *hash_value = sub_parts[1];
-			gchar *digest =
-				jabber_calculate_data_hash(jabber_data_get_data(data),
-				    jabber_data_get_size(data), hash_algo);
-
-			purple_debug_info("jabber", "BoB expecting hash: %s\n", digest);
-			
-			if (digest) {
-				gboolean result = purple_strequal(digest, hash_value);
-
-				if (!result) {
-					purple_debug_error("jabber", "invalid BoB hash\n");
-				}
-				g_free(digest);
-				return result;
-			} else {
-				purple_debug_info("jabber", "unknown BoB hash algo\n");
-				return FALSE;
-			}
-		} else {
-			return TRUE;
-		}
-	} else {
-		return TRUE;
-	}
-}
-
 static void
 jabber_data_delete(gpointer cbdata)
 {
@@ -160,11 +108,6 @@
 	data->cid = g_strdup(cid);
 	data->type = g_strdup(type);
 
-	if (!jabber_data_has_valid_hash(data)) {
-		jabber_data_delete(data);
-		return NULL;
-	}
-
 	return data;
 }
 
@@ -240,6 +183,57 @@
 	return tag;
 }
 
+static gboolean
+jabber_data_has_valid_hash(const JabberData *data)
+{
+	const gchar *cid = jabber_data_get_cid(data);
+	gchar **cid_parts = g_strsplit(cid, "@", -1);
+	gchar **iter;
+	int num_parts = 0;
+
+	purple_debug_info("jabber", "validating BoB hash %s\n", cid);
+	
+	for (iter = cid_parts; *iter != NULL ; iter++) {
+		num_parts++;
+	}
+
+	if (num_parts == 2 && purple_strequal(cid_parts[1], "bob.xmpp.org")) {
+		gchar **sub_parts = g_strsplit(cid_parts[0], "+", -1);
+
+		num_parts = 0;
+		for (iter = sub_parts ; *iter != NULL ; iter++) {
+			num_parts++;
+		}
+
+		if (num_parts == 2) {
+			const gchar *hash_algo = sub_parts[0];
+			const gchar *hash_value = sub_parts[1];
+			gchar *digest =
+				jabber_calculate_data_hash(jabber_data_get_data(data),
+				    jabber_data_get_size(data), hash_algo);
+			
+			if (digest) {
+				gboolean result = purple_strequal(digest, hash_value);
+
+				purple_debug_info("jabber", "BoB expecting hash: %s\n", digest);
+
+				if (!result) {
+					purple_debug_error("jabber", "invalid BoB hash\n");
+				}
+				g_free(digest);
+				return result;
+			} else {
+				purple_debug_info("jabber", "unknown BoB hash algo\n");
+				return FALSE;
+			}
+		} else {
+			return FALSE;
+		}
+	} else {
+		return FALSE;
+	}
+}
+
 
 typedef struct {
 	gpointer userdata;
@@ -265,17 +259,10 @@
 	if (data_element && type == JABBER_IQ_RESULT) {
 		JabberData *data = jabber_data_create_from_xml(data_element);
 
-		if (data) {
-			if (!ephemeral) {
-				jabber_data_associate_remote(data);
-			}
-			cb(data, alt, userdata);
-		} else {
-			/* could not validate hash when creating data from XML */
-			purple_debug_info("jabber",
-			    "hash validation failed on requested BoB object\n");
-			cb(NULL, alt, userdata);
+		if (!ephemeral) {
+			jabber_data_associate_remote(js, from, data);
 		}
+		cb(data, alt, userdata);
 	} else if (item_not_found) {
 		purple_debug_info("jabber",
 			"Responder didn't recognize requested data\n");
@@ -323,11 +310,24 @@
 }
 
 const JabberData *
-jabber_data_find_remote_by_cid(const gchar *cid)
+jabber_data_find_remote_by_cid(JabberStream *js, const gchar *who,
+    const gchar *cid)
 {
+	const JabberData *data = g_hash_table_lookup(remote_data_by_cid, cid);
+	purple_debug_info("jabber", "lookup remote smiley with cid = %s\n", cid);
 	purple_debug_info("jabber", "lookup remote data object with cid = %s\n", cid);
 
-	return g_hash_table_lookup(remote_data_by_cid, cid);
+	if (data == NULL) {
+		gchar *jid_cid =
+			g_strdup_printf("%s@%s/%s%s%s", js->user->node, js->user->domain,
+			    js->user->resource, who, cid);
+		purple_debug_info("jabber",
+		    "didn't find BoB object by pure CID, try including JIDs: %s\n",
+		    jid_cid);
+		data = g_hash_table_lookup(remote_data_by_cid, jid_cid);
+		g_free(jid_cid);
+	}
+	return data;
 }
 
 void
@@ -342,12 +342,21 @@
 }
 
 void
-jabber_data_associate_remote(JabberData *data)
+jabber_data_associate_remote(JabberStream *js, const gchar *who, JabberData *data)
 {
-	purple_debug_info("jabber", "associating remote data object, cid = %s\n",
-		jabber_data_get_cid(data));
-	g_hash_table_insert(remote_data_by_cid, g_strdup(jabber_data_get_cid(data)),
-		data);
+	gchar *cid;
+	
+	if (jabber_data_has_valid_hash(data)) {
+		cid = g_strdup(jabber_data_get_cid(data));
+	} else {
+		cid = g_strdup_printf("%s@%s/%s%s%s", js->user->node, js->user->domain,
+		    js->user->resource, who, jabber_data_get_cid(data));
+	}
+
+	purple_debug_info("jabber", "associating remote BoB object with cid = %s\n",
+		cid);
+	
+	g_hash_table_insert(remote_data_by_cid, cid, data);
 }
 
 void
--- a/libpurple/protocols/jabber/data.h	Mon Mar 22 22:26:14 2010 +0000
+++ b/libpurple/protocols/jabber/data.h	Wed Mar 24 19:56:07 2010 +0000
@@ -72,11 +72,13 @@
 /* lookup functions */
 const JabberData *jabber_data_find_local_by_alt(const gchar *alt);
 const JabberData *jabber_data_find_local_by_cid(const gchar *cid);
-const JabberData *jabber_data_find_remote_by_cid(const gchar *cid);
+const JabberData *jabber_data_find_remote_by_cid(JabberStream *js,
+    const gchar *who, const gchar *cid);
 
 /* store data objects */
 void jabber_data_associate_local(JabberData *data, const gchar *alt);
-void jabber_data_associate_remote(JabberData *data);
+void jabber_data_associate_remote(JabberStream *js, const gchar *who,
+    JabberData *data);
 
 /* handles iq requests */
 void jabber_data_parse(JabberStream *js, const char *who, JabberIqType type,
--- a/libpurple/protocols/jabber/jutil.c	Mon Mar 22 22:26:14 2010 +0000
+++ b/libpurple/protocols/jabber/jutil.c	Wed Mar 24 19:56:07 2010 +0000
@@ -733,7 +733,7 @@
     const gchar *hash_algo)
 {
 	PurpleCipherContext *context;
-	static gchar digest[41];
+	static gchar digest[129]; /* 512 bits hex + \0 */
 
 	context = purple_cipher_context_new_by_name(hash_algo, NULL);
 	if (context == NULL)
--- a/libpurple/protocols/jabber/message.c	Mon Mar 22 22:26:14 2010 +0000
+++ b/libpurple/protocols/jabber/message.c	Wed Mar 24 19:56:07 2010 +0000
@@ -462,21 +462,22 @@
 }
 
 static void
-jabber_message_add_remote_smileys(const xmlnode *message)
+jabber_message_add_remote_smileys(JabberStream *js, const gchar *who,
+    const xmlnode *message)
 {
 	xmlnode *data_tag;
 	for (data_tag = xmlnode_get_child_with_namespace(message, "data", NS_BOB) ;
 		 data_tag ;
 		 data_tag = xmlnode_get_next_twin(data_tag)) {
 		const gchar *cid = xmlnode_get_attrib(data_tag, "cid");
-		const JabberData *data = jabber_data_find_remote_by_cid(cid);
+		const JabberData *data = jabber_data_find_remote_by_cid(js, who, cid);
 
 		if (!data && cid != NULL) {
 			/* we haven't cached this already, let's add it */
 			JabberData *new_data = jabber_data_create_from_xml(data_tag);
 
 			if (new_data) {
-				jabber_data_associate_remote(new_data);
+				jabber_data_associate_remote(js, who, new_data);
 			}
 		}
 	}
@@ -634,7 +635,7 @@
 					}
 
 					/* process any newly provided smileys */
-					jabber_message_add_remote_smileys(packet);
+					jabber_message_add_remote_smileys(js, to, packet);
 				}
 
 				/* reformat xhtml so that img tags with a "cid:" src gets
@@ -660,7 +661,7 @@
 					if (purple_conv_custom_smiley_add(conv, alt, "cid", cid,
 						    TRUE)) {
 						const JabberData *data =
-								jabber_data_find_remote_by_cid(cid);
+								jabber_data_find_remote_by_cid(js, from, cid);
 						/* if data is already known, we write it immediatly */
 						if (data) {
 							purple_debug_info("jabber",