changeset 23988:305fac6af8f9

Updated to use latest spec. in XEP-0231 New namespace. Cache data globally in a running instance based on CID. Set the PNG compression level param when saving a custom smiley from GTKIMHTML.
author Marcus Lundblad <ml@update.uu.se>
date Fri, 05 Sep 2008 21:55:09 +0000
parents 8997acd7d143
children 7b11072ba907
files libpurple/protocols/jabber/chat.c libpurple/protocols/jabber/data.c libpurple/protocols/jabber/data.h libpurple/protocols/jabber/iq.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/libxmpp.c libpurple/protocols/jabber/message.c pidgin/gtksmiley.c
diffstat 8 files changed, 198 insertions(+), 250 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/jabber/chat.c	Thu Sep 04 22:18:58 2008 +0000
+++ b/libpurple/protocols/jabber/chat.c	Fri Sep 05 21:55:09 2008 +0000
@@ -685,9 +685,7 @@
 		xmlnode_insert_data(status, msg, -1);
 	}
 	jabber_send(chat->js, presence);
-
-	jabber_data_delete_associated_with_conv(chat->conv);
-
+	
 	xmlnode_free(presence);
 	g_free(room_jid);
 }
--- a/libpurple/protocols/jabber/data.c	Thu Sep 04 22:18:58 2008 +0000
+++ b/libpurple/protocols/jabber/data.c	Fri Sep 05 21:55:09 2008 +0000
@@ -25,43 +25,23 @@
 #include "conversation.h"
 #include "iq.h"
 
-/* hash table to store locally supplied data objects, by conversation and
- 	alt text (smiley shortcut) */
-static GHashTable *local_datas_by_alt = NULL;
-
-/* hash table to store locally supplied data objects, by content id */
-static GHashTable *local_datas_by_cid = NULL;
-
-/* remote supplied data objects by content id */
-static GHashTable *remote_datas_by_cid = NULL;
-
-
-void
-jabber_data_init(void)
-{
-	/* setup hash tables for storing data instances here */
-	purple_debug_info("jabber", "Setting up data handling\n");
-
-	local_datas_by_alt = g_hash_table_new(NULL, NULL);
-	local_datas_by_cid = g_hash_table_new(NULL, NULL);
-	remote_datas_by_cid = g_hash_table_new(NULL, NULL);
-}
+static GHashTable *local_data_by_alt = NULL;
+static GHashTable *local_data_by_cid = NULL;
+static GHashTable *remote_data_by_cid = NULL;
 
 JabberData *
 jabber_data_create_from_data(gconstpointer rawdata, gsize size, const char *type,
-							 const char *alt)
+	JabberStream *js)
 {
 	JabberData *data = g_new0(JabberData, 1);
 	gchar *checksum = purple_util_get_image_checksum(rawdata, size);
 	gchar cid[256];
 
-	/* is there some better way to generate a content ID? */
-	g_snprintf(cid, sizeof(cid), "%s@%s", checksum, g_get_host_name());
+	g_snprintf(cid, sizeof(cid), "sha1+%s@bob.xmpp.org", checksum);
 	g_free(checksum);
 
 	data->cid = g_strdup(cid);
 	data->type = g_strdup(type);
-	data->alt = g_strdup(alt);
 	data->size = size;
 
 	data->data = g_memdup(rawdata, size);
@@ -91,8 +71,7 @@
 
 	data->cid = g_strdup(xmlnode_get_attrib(tag, "cid"));
 	data->type = g_strdup(xmlnode_get_attrib(tag, "type"));
-	data->alt = g_strdup(xmlnode_get_attrib(tag, "alt"));
-
+	
 	raw_data = xmlnode_get_data(tag);
 	data->data = purple_base64_decode(raw_data, &size);
 	data->size = size;
@@ -107,7 +86,6 @@
 jabber_data_delete(JabberData *data)
 {
 	g_free(data->cid);
-	g_free(data->alt);
 	g_free(data->type);
 	g_free(data->data);
 	g_free(data);
@@ -119,11 +97,6 @@
 	return data->cid;
 }
 
-const char *
-jabber_data_get_alt(const JabberData *data)
-{
-	return data->alt;
-}
 
 const char *
 jabber_data_get_type(const JabberData *data)
@@ -150,7 +123,6 @@
 	char *base64data = purple_base64_encode(data->data, data->size);
 
 	xmlnode_set_namespace(tag, XEP_0231_NAMESPACE);
-	xmlnode_set_attrib(tag, "alt", data->alt);
 	xmlnode_set_attrib(tag, "cid", data->cid);
 	xmlnode_set_attrib(tag, "type", data->type);
 
@@ -162,12 +134,12 @@
 }
 
 xmlnode *
-jabber_data_get_xhtml_im(const JabberData *data)
+jabber_data_get_xhtml_im(const JabberData *data, const gchar *alt)
 {
 	xmlnode *img = xmlnode_new("img");
 	char src[128];
 
-	xmlnode_set_attrib(img, "alt", data->alt);
+	xmlnode_set_attrib(img, "alt", alt);
 	g_snprintf(src, sizeof(src), "cid:%s", data->cid);
 	xmlnode_set_attrib(img, "src", src);
 
@@ -186,107 +158,36 @@
 }
 
 const JabberData *
-jabber_data_find_local_by_alt(const PurpleConversation *conv, const char *alt)
+jabber_data_find_local_by_alt(const gchar *alt)
 {
-	GHashTable *local_datas = g_hash_table_lookup(local_datas_by_alt, conv);
-
-	if (local_datas) {
-		return g_hash_table_lookup(local_datas, alt);
-	} else {
-		return NULL;
-	}
-}
-
-
-const JabberData *
-jabber_data_find_local_by_cid(const PurpleConversation *conv, const char *cid)
-{
-	GHashTable *local_datas = g_hash_table_lookup(local_datas_by_cid, conv);
-
-	if (local_datas) {
-		return g_hash_table_lookup(local_datas, cid);
-	} else {
-		return NULL;
-	}
+	return g_hash_table_lookup(local_data_by_alt, alt);
 }
 
 const JabberData *
-jabber_data_find_remote_by_cid(const PurpleConversation *conv, const char *cid)
+jabber_data_find_local_by_cid(const gchar *cid)
 {
-	GHashTable *remote_datas = g_hash_table_lookup(remote_datas_by_cid, conv);
+	return g_hash_table_lookup(local_data_by_cid, cid);
+}
 
-	if (remote_datas) {
-		return g_hash_table_lookup(remote_datas, cid);
-	} else {
-		return NULL;
-	}
+const JabberData *
+jabber_data_find_remote_by_cid(const gchar *cid)
+{
+	return g_hash_table_lookup(remote_data_by_cid, cid);
 }
 
 void
-jabber_data_associate_local_with_conv(JabberData *data, PurpleConversation *conv)
+jabber_data_associate_local(JabberData *data, const gchar *alt)
 {
-	GHashTable *datas_by_alt = g_hash_table_lookup(local_datas_by_alt, conv);
-	GHashTable *datas_by_cid = g_hash_table_lookup(local_datas_by_cid, conv);
-
-	if (!datas_by_alt) {
-		datas_by_alt = g_hash_table_new(g_str_hash, g_str_equal);
-		g_hash_table_insert(local_datas_by_alt, conv, datas_by_alt);
-	}
-
-	if (!datas_by_cid) {
-		datas_by_cid = g_hash_table_new(g_str_hash, g_str_equal);
-		g_hash_table_insert(local_datas_by_cid, conv, datas_by_cid);
-	}
-
-	g_hash_table_insert(datas_by_alt, g_strdup(jabber_data_get_alt(data)), data);
-	g_hash_table_insert(datas_by_cid, g_strdup(jabber_data_get_cid(data)), data);
+	g_hash_table_insert(local_data_by_alt, g_strdup(alt), data);
+	g_hash_table_insert(local_data_by_cid, g_strdup(jabber_data_get_cid(data)), 
+		data);
 }
 
 void
-jabber_data_associate_remote_with_conv(JabberData *data, PurpleConversation *conv)
-{
-	GHashTable *datas_by_cid = g_hash_table_lookup(remote_datas_by_cid, conv);
-
-	if (!datas_by_cid) {
-		datas_by_cid = g_hash_table_new(g_str_hash, g_str_equal);
-		g_hash_table_insert(remote_datas_by_cid, conv, datas_by_cid);
-	}
-
-	g_hash_table_insert(datas_by_cid, g_strdup(jabber_data_get_cid(data)), data);
-}
-
-static void
-jabber_data_delete_from_hash_table(gpointer key, gpointer value,
-								   gpointer user_data)
+jabber_data_associate_remote(JabberData *data)
 {
-	JabberData *data = (JabberData *) value;
-	jabber_data_delete(data);
-	g_free(key);
-}
-
-void
-jabber_data_delete_associated_with_conv(PurpleConversation *conv)
-{
-	GHashTable *local_datas = g_hash_table_lookup(local_datas_by_cid, conv);
-	GHashTable *remote_datas = g_hash_table_lookup(remote_datas_by_cid, conv);
-	GHashTable *local_datas_alt = g_hash_table_lookup(local_datas_by_alt, conv);
-
-	if (local_datas) {
-		g_hash_table_foreach(local_datas, jabber_data_delete_from_hash_table,
-							 NULL);
-		g_hash_table_destroy(local_datas);
-		g_hash_table_remove(local_datas_by_cid, conv);
-	}
-	if (remote_datas) {
-		g_hash_table_foreach(remote_datas, jabber_data_delete_from_hash_table,
-							 NULL);
-		g_hash_table_destroy(remote_datas);
-		g_hash_table_remove(remote_datas_by_cid, conv);
-	}
-	if (local_datas_alt) {
-		g_hash_table_destroy(local_datas_alt);
-		g_hash_table_remove(local_datas_by_alt, conv);
-	}
+	g_hash_table_insert(remote_data_by_cid, g_strdup(jabber_data_get_cid(data)), 
+		data);
 }
 
 void
@@ -294,15 +195,11 @@
 {
 	JabberIq *result = NULL;
 	const char *who = xmlnode_get_attrib(packet, "from");
-	const PurpleConnection *gc = js->gc;
-	const PurpleAccount *account = purple_connection_get_account(gc);
-	const PurpleConversation *conv =
-		purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, account);
 	xmlnode *data_node = xmlnode_get_child(packet, "data");
 	const JabberData *data =
-		jabber_data_find_local_by_cid(conv, xmlnode_get_attrib(data_node, "cid"));
+		jabber_data_find_local_by_cid(xmlnode_get_attrib(data_node, "cid"));
 
-	if (!conv || !data) {
+	if (!data) {
 		xmlnode *item_not_found = xmlnode_new("item-not-found");
 
 		result = jabber_iq_new(js, JABBER_IQ_ERROR);
@@ -318,3 +215,24 @@
 	}
 	jabber_iq_send(result);
 }
+
+void
+jabber_data_init(void)
+{
+	purple_debug_info("jabber", "creating hash tables for data objects\n");
+	local_data_by_alt = g_hash_table_new_full(g_str_hash, g_str_equal,
+		g_free, NULL);
+	local_data_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal,
+		g_free, jabber_data_delete);
+	remote_data_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal,
+		g_free, jabber_data_delete);
+}
+
+void
+jabber_data_uninit(void)
+{
+	purple_debug_info("jabber", "destroying hash tables for data objects\n");
+	g_hash_table_destroy(local_data_by_alt);
+	g_hash_table_destroy(local_data_by_cid);
+	g_hash_table_destroy(remote_data_by_cid);
+}
--- a/libpurple/protocols/jabber/data.h	Thu Sep 04 22:18:58 2008 +0000
+++ b/libpurple/protocols/jabber/data.h	Fri Sep 05 21:55:09 2008 +0000
@@ -21,24 +21,20 @@
 #include "conversation.h"
 #include "jabber.h"
 
-#define XEP_0231_NAMESPACE "urn:xmpp:tmp:data-element"
-#define XEP_0231_IB_IMAGE_NAMESPACE "urn:xmpp:tmp:data-element:inband-image"
+#define XEP_0231_NAMESPACE "urn:xmpp:bob"
 
 #include <glib.h>
 
 typedef struct {
 	char *cid;
-	char *alt;
 	char *type;
 	gsize size;
 	gpointer data;
 } JabberData;
 
-void jabber_data_init(void);
-
 /* creates a JabberData instance from raw data */
 JabberData *jabber_data_create_from_data(gconstpointer data, gsize size,
-										 const char *type, const char *alt);
+										 const char *type, JabberStream *js);
 
 /* create a JabberData instance from an XML "data" element (as defined by
   XEP 0231 */
@@ -47,7 +43,6 @@
 void jabber_data_delete(JabberData *data);
 
 const char *jabber_data_get_cid(const JabberData *data);
-const char *jabber_data_get_alt(const JabberData *data);
 const char *jabber_data_get_type(const JabberData *data);
 
 gsize jabber_data_get_size(const JabberData *data);
@@ -57,27 +52,39 @@
 xmlnode *jabber_data_get_xml_definition(const JabberData *data);
 
 /* returns an XHTML-IM "img" tag given a data instance */
-xmlnode *jabber_data_get_xhtml_im(const JabberData *data);
+xmlnode *jabber_data_get_xhtml_im(const JabberData *data, const gchar *alt);
 
 /* returns a data request element (to be included in an iq stanza) for requesting
   data */
 xmlnode *jabber_data_get_xml_request(const gchar *cid);
 
 /* lookup functions */
-const JabberData *jabber_data_find_local_by_alt(const PurpleConversation *conv,
+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_local_by_alt(PurpleConversation *conv,
 												const char *alt);
-const JabberData *jabber_data_find_local_by_cid(const PurpleConversation *conv,
+const JabberData *jabber_data_find_local_by_cid(PurpleConversation *conv,
 												const char *cid);
-const JabberData *jabber_data_find_remote_by_cid(const PurpleConversation *conv,
+const JabberData *jabber_data_find_remote_by_cid(PurpleConversation *conv,
 												 const char *cid);
-
-/* associate data objects with a conversation */
-void jabber_data_associate_local_with_conv(JabberData *data, PurpleConversation *conv);
+*/
+												 
+/* store data objects */
+void jabber_data_associate_local(JabberData *data, const gchar *alt);
+void jabber_data_associate_remote(JabberData *data);
+/*
+void jabber_data_associate_local_with_conv(JabberData *data, PurpleConversation *conv,
+	const gchar *alt);
 void jabber_data_associate_remote_with_conv(JabberData *data, PurpleConversation *conv);
 void jabber_data_delete_associated_with_conv(PurpleConversation *conv);
+*/
 
 /* handles iq requests */
 void jabber_data_parse(JabberStream *js, xmlnode *packet);
 
+void jabber_data_init(void);
+void jabber_data_uninit(void);
 
 #endif /* JABBER_DATA_H */
--- a/libpurple/protocols/jabber/iq.c	Thu Sep 04 22:18:58 2008 +0000
+++ b/libpurple/protocols/jabber/iq.c	Fri Sep 05 21:55:09 2008 +0000
@@ -356,8 +356,7 @@
 		return;
 	}
 
-	if (xmlnode_get_child_with_namespace(packet, "data",
-		    "urn:xmpp:tmp:data-element")) {
+	if (xmlnode_get_child_with_namespace(packet, "data", XEP_0231_NAMESPACE)) {
 		jabber_data_parse(js, packet);
 		return;
 	}
--- a/libpurple/protocols/jabber/jabber.c	Thu Sep 04 22:18:58 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Fri Sep 05 21:55:09 2008 +0000
@@ -1902,11 +1902,7 @@
 	JabberID *jid;
 	JabberBuddy *jb;
 	JabberBuddyResource *jbr;
-	PurpleAccount *account = purple_connection_get_account(gc);
-	PurpleConversation *conv =
-		purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY,
-			who, account);
-
+	
 	if(!(jid = jabber_id_new(who)))
 		return;
 
@@ -1920,8 +1916,6 @@
 			jabber_message_conv_closed(js, who);
 	}
 
-	jabber_data_delete_associated_with_conv(conv);
-
 	jabber_id_free(jid);
 }
 
--- a/libpurple/protocols/jabber/libxmpp.c	Thu Sep 04 22:18:58 2008 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Fri Sep 05 21:55:09 2008 +0000
@@ -138,7 +138,8 @@
 			     purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
 			     purple_value_new_outgoing(PURPLE_TYPE_STRING));
 			   
-
+	jabber_data_uninit();
+	
 	return TRUE;
 }
 
@@ -277,14 +278,14 @@
 	
 	jabber_tune_init();
 	jabber_caps_init();
+	
 	jabber_data_init();
-
+	
 	jabber_add_feature("avatarmeta", AVATARNAMESPACEMETA, jabber_pep_namespace_only_when_pep_enabled_cb);
 	jabber_add_feature("avatardata", AVATARNAMESPACEDATA, jabber_pep_namespace_only_when_pep_enabled_cb);
 	jabber_add_feature("buzz", "http://www.xmpp.org/extensions/xep-0224.html#ns",
 					   jabber_buzz_isenabled);
-	/* this string will need to be updated when XEP-0231 turns "draft" */
-	jabber_add_feature("smileys", XEP_0231_IB_IMAGE_NAMESPACE,
+	jabber_add_feature("bob", XEP_0231_NAMESPACE,
 					   jabber_custom_smileys_isenabled);
 
 	jabber_pep_register_handler("avatar", AVATARNAMESPACEMETA, jabber_buddy_avatar_update_metadata);
--- a/libpurple/protocols/jabber/message.c	Thu Sep 04 22:18:58 2008 +0000
+++ b/libpurple/protocols/jabber/message.c	Fri Sep 05 21:55:09 2008 +0000
@@ -24,7 +24,6 @@
 #include "notify.h"
 #include "server.h"
 #include "util.h"
-
 #include "buddy.h"
 #include "chat.h"
 #include "data.h"
@@ -323,66 +322,67 @@
 	gchar *alt;
 } JabberSmileyRef;
 
-static GList *
-_jabber_message_get_refs_from_xmlnode(const xmlnode *message)
+
+static void
+jabber_message_get_refs_from_xmlnode_internal(const xmlnode *message,
+	GHashTable *table)
 {
 	xmlnode *child;
-	GList *refs = NULL;
-
+	
 	for (child = xmlnode_get_child(message, "img") ; child ;
 		 child = xmlnode_get_next_twin(child)) {
 		const gchar *src = xmlnode_get_attrib(child, "src");
-		const gssize len = strlen(src);
-
-		if (len > 4 && g_str_has_prefix(src, "cid:")) {
-			JabberSmileyRef *ref = g_new0(JabberSmileyRef, 1);
-			ref->cid = g_strdup(&(src[4]));
-			ref->alt = g_strdup(xmlnode_get_attrib(child, "alt"));
-			refs = g_list_append(refs, ref);
+		
+		if (g_str_has_prefix(src, "cid:")) {
+			const gchar *cid = src + 4;
+			
+			/* if we haven't "fetched" this yet... */
+			if (!g_hash_table_lookup(table, cid)) {
+				/* take a copy of the cid and let the SmileyRef own it... */
+				gchar *temp_cid = g_strdup(cid);
+				JabberSmileyRef *ref = g_new0(JabberSmileyRef, 1);
+				const gchar *alt = xmlnode_get_attrib(child, "alt");
+				ref->cid = temp_cid;
+				/* if there is no "alt" string, use the cid... */
+				if (alt && alt[0] != '\0') {
+					ref->alt = g_strdup(xmlnode_get_attrib(child, "alt"));
+				} else {
+					ref->alt = g_strdup(cid);
+				}
+				g_hash_table_insert(table, temp_cid, ref);
+			}
 		}
 	}
-
+		
 	for (child = message->child ; child ; child = child->next) {
-		refs = g_list_concat(refs,
-			_jabber_message_get_refs_from_xmlnode(child));
+		jabber_message_get_refs_from_xmlnode_internal(child, table);
 	}
+}
 
-	return refs;
+static gboolean
+jabber_message_get_refs_steal(gpointer key, gpointer value, gpointer user_data)
+{
+	GList **refs = (GList **) user_data;
+	JabberSmileyRef *ref = (JabberSmileyRef *) value;
+	
+	*refs = g_list_append(*refs, ref);
+	
+	return TRUE;
 }
 
 static GList *
 jabber_message_get_refs_from_xmlnode(const xmlnode *message)
 {
-	GList *refs = _jabber_message_get_refs_from_xmlnode(message);
+	GList *refs = NULL;
 	GHashTable *unique_refs = g_hash_table_new(g_str_hash, g_str_equal);
-	GList *result = NULL;
-	GList *iterator = NULL;
-
-	for (iterator = refs ; iterator ; iterator = g_list_next(iterator)) {
-		JabberSmileyRef *ref = (JabberSmileyRef *) iterator->data;
-		if (!g_hash_table_lookup(unique_refs, ref->cid)) {
-			JabberSmileyRef *new_ref = g_new0(JabberSmileyRef, 1);
-			new_ref->cid = g_strdup(ref->cid);
-			new_ref->alt = g_strdup(ref->alt);
-			g_hash_table_insert(unique_refs, ref->cid, ref);
-			result = g_list_append(result, new_ref);
-		}
-	}
-
-	for (iterator = refs ; iterator ; iterator = g_list_next(iterator)) {
-		JabberSmileyRef *ref = (JabberSmileyRef *) iterator->data;
-		g_free(ref->cid);
-		g_free(ref->alt);
-		g_free(ref);
-	}
-
+	
+	jabber_message_get_refs_from_xmlnode_internal(message, unique_refs);
+	(void) g_hash_table_foreach_steal(unique_refs, 
+		jabber_message_get_refs_steal, (gpointer) &refs);
 	g_hash_table_destroy(unique_refs);
-
-	return result;
+	return refs;
 }
 
-
-
 static gchar *
 jabber_message_xml_to_string_strip_img_smileys(xmlnode *xhtml)
 {
@@ -404,6 +404,9 @@
 				if (g_str_has_prefix(&(markup[pos2]), "/>")) {
 					pos2 += 2;
 					break;
+				} else if (g_str_has_prefix(&(markup[pos2]), "</img>")) {
+					pos2 += 5;
+					break;
 				}
 			}
 
@@ -417,10 +420,16 @@
 
 			if (g_str_has_prefix(src, "cid:")) {
 				const gchar *alt = xmlnode_get_attrib(img, "alt");
-				gchar *escaped = g_markup_escape_text(alt, -1);
-				out = g_string_append(out, escaped);
+				gchar *escaped = NULL;
+				/* if the "alt" attribute is empty, put the cid as smiley string */
+				if (alt && alt[0] != '\0') {
+					escaped = g_markup_escape_text(alt, -1);
+					out = g_string_append(out, escaped);
+					g_free(escaped);
+				} else {
+					out = g_string_append(out, src + 4);
+				}
 				pos += pos2 - pos;
-				g_free(escaped);
 			} else {
 				out = g_string_append_c(out, markup[pos]);
 				pos++;
@@ -438,27 +447,36 @@
 }
 
 static void
-jabber_message_add_remote_smileys_to_conv(PurpleConversation *conv,
-	const xmlnode *message)
+jabber_message_add_remote_smileys(const xmlnode *message)
 {
 	xmlnode *data_tag;
-	for (data_tag = xmlnode_get_child(message, "data") ; data_tag ;
+	for (data_tag = xmlnode_get_child_with_namespace(message, "data", XEP_0231_NAMESPACE) ;
+		 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(conv, cid);
+		const JabberData *data = jabber_data_find_remote_by_cid(cid);
 
-		if (!data) {
+		if (!data && cid != NULL) {
 			/* we haven't cached this already, let's add it */
 			JabberData *new_data = jabber_data_create_from_xml(data_tag);
-			jabber_data_associate_remote_with_conv(new_data, conv);
+			jabber_data_associate_remote(new_data);
 		}
 	}
 }
 
+/* used in the function below to supply a conversation and shortcut for a
+ smiley */
+typedef struct {
+	PurpleConversation *conv;
+	const gchar *alt;
+} JabberDataRef;
+
 static void
 jabber_message_get_data_cb(JabberStream *js, xmlnode *packet, gpointer data)
 {
-	PurpleConversation *conv = (PurpleConversation *) data;
+	JabberDataRef *ref = (JabberDataRef *) data;
+	PurpleConversation *conv = ref->conv;
+	const gchar *alt = ref->alt;
 	xmlnode *data_element = xmlnode_get_child(packet, "data");
 	xmlnode *item_not_found = xmlnode_get_child(packet, "item-not-found");
 
@@ -467,11 +485,11 @@
 		JabberData *data = jabber_data_create_from_xml(data_element);
 
 		if (data) {
-			jabber_data_associate_remote_with_conv(data, conv);
-			purple_conv_custom_smiley_write(conv, jabber_data_get_alt(data),
+			jabber_data_associate_remote(data);
+			purple_conv_custom_smiley_write(conv, alt,
 											jabber_data_get_data(data),
 											jabber_data_get_size(data));
-			purple_conv_custom_smiley_close(conv, jabber_data_get_alt(data));
+			purple_conv_custom_smiley_close(conv, alt);
 		}
 
 	} else if (item_not_found) {
@@ -480,17 +498,23 @@
 	} else {
 		purple_debug_error("jabber", "Unknown response to data request\n");
 	}
+	
+	g_free(ref);
 }
 
 static void
 jabber_message_send_data_request(JabberStream *js, PurpleConversation *conv,
-								 const gchar *cid, const gchar *who)
+								 const gchar *cid, const gchar *who, 
+								 const gchar *alt)
 {
 	JabberIq *request = jabber_iq_new(js, JABBER_IQ_GET);
+	JabberDataRef *ref = g_new0(JabberDataRef, 1);
 	xmlnode *data_request = jabber_data_get_xml_request(cid);
 
 	xmlnode_set_attrib(request->node, "to", who);
-	jabber_iq_set_callback(request, jabber_message_get_data_cb, conv);
+	ref->conv = conv;
+	ref->alt = alt;
+	jabber_iq_set_callback(request, jabber_message_get_data_cb, ref);
 	xmlnode_insert_child(request->node, data_request);
 
 	jabber_iq_send(request);
@@ -565,7 +589,9 @@
 					/* find a list of smileys ("cid" and "alt" text pairs)
 					  occuring in the message */
 					smiley_refs = jabber_message_get_refs_from_xmlnode(child);
-
+					purple_debug_info("jabber", "found %d smileys\n",
+						g_list_length(smiley_refs));
+					
 					if (jm->type == JABBER_MESSAGE_GROUPCHAT) {
 						JabberID *jid = jabber_id_new(jm->from);
 						JabberChat *chat = NULL;
@@ -582,17 +608,8 @@
 								who, account);
 					}
 
-					/* if the conversation doesn't exist yet we need to create it
-				  	now */
-					if (!conv) {
-						/* if a message of this type is initiating a conversation,
-					  	that must be an IM */
-						conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
-							account, who);
-					}
-
 					/* process any newly provided smileys */
-					jabber_message_add_remote_smileys_to_conv(conv, packet);
+					jabber_message_add_remote_smileys(packet);
 				}
 
 				/* reformat xhtml so that img tags with a "cid:" src gets
@@ -617,7 +634,7 @@
 					if (purple_conv_custom_smiley_add(conv, alt, "cid", cid,
 						    TRUE)) {
 						const JabberData *data =
-								jabber_data_find_remote_by_cid(conv, cid);
+								jabber_data_find_remote_by_cid(cid);
 						/* if data is already known, we add write it immediatly */
 						if (data) {
 							purple_conv_custom_smiley_write(conv, alt,
@@ -626,7 +643,8 @@
 							purple_conv_custom_smiley_close(conv, alt);
 						} else {
 							/* we need to request the smiley (data) */
-							jabber_message_send_data_request(js, conv, cid, who);
+							jabber_message_send_data_request(js, conv, cid, who,
+								alt);
 						}
 					}
 				}
@@ -814,8 +832,7 @@
 }
 
 static gchar *
-jabber_message_get_smileyfied_xhtml(const PurpleConversation *conv,
-	const gchar *xhtml, const GList *smileys)
+jabber_message_get_smileyfied_xhtml(const gchar *xhtml, const GList *smileys)
 {
 	/* create XML element for all smileys (img tags) */
 	GString *result = g_string_new(NULL);
@@ -836,8 +853,8 @@
 			if (g_str_has_prefix(&(xhtml[pos]), escaped)) {
 				/* we found the current smiley at this position */
 				const JabberData *data =
-					jabber_data_find_local_by_alt(conv, shortcut);
-				xmlnode *img = jabber_data_get_xhtml_im(data);
+					jabber_data_find_local_by_alt(shortcut);
+				xmlnode *img = jabber_data_get_xhtml_im(data, shortcut);
 				int len;
 				gchar *img_text = xmlnode_to_str(img, &len);
 
@@ -868,18 +885,27 @@
 								   const gchar *who)
 {
 	JabberStream *js = (JabberStream *) gc->proto_data;
-	JabberBuddy *jb = jabber_buddy_find(js, who, FALSE);
+	JabberBuddy *jb;
+	
+	if (!js) {
+		purple_debug_error("jabber", 
+			"jabber_conv_support_custom_smileys: could not find stream\n");
+		return FALSE;
+	}
 
+	jb = jabber_buddy_find(js, who, FALSE);
 	if (!jb) {
 		purple_debug_error("jabber",
 			"jabber_conv_support_custom smileys: could not find buddy\n");
 		return FALSE;
 	}
+	
+	
 
 	switch (purple_conversation_get_type(conv)) {
 		/* for the time being, we will not support custom smileys in MUCs */
 		case PURPLE_CONV_TYPE_IM:
-			return jabber_buddy_has_capability(jb, XEP_0231_IB_IMAGE_NAMESPACE);
+			return jabber_buddy_has_capability(jb, XEP_0231_NAMESPACE);
 			break;
 		default:
 			return FALSE;
@@ -976,7 +1002,7 @@
 		PurpleConversation *conv =
 			purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, jm->to,
 				account);
-
+ 
 		if (jabber_conv_support_custom_smileys(jm->js->gc, conv, jm->to)) {
 			GList *found_smileys = jabber_message_xhtml_find_smileys(jm->xhtml);
 
@@ -990,28 +1016,33 @@
 							(PurpleSmiley *) iterator->data;
 					const gchar *shortcut = purple_smiley_get_shortcut(smiley);
 					const JabberData *data =
-							jabber_data_find_local_by_alt(conv, shortcut);
-
-					/* if data has not been sent before, include data */
+						jabber_data_find_local_by_alt(shortcut);
+							
+					/* the object has not been sent before */
 					if (!data) {
 						PurpleStoredImage *image =
 								purple_smiley_get_stored_image(smiley);
 						const gchar *ext = purple_imgstore_get_extension(image);
-
+						JabberStream *js = jm->js;
+						
 						JabberData *new_data =
 							jabber_data_create_from_data(purple_imgstore_get_data(image),
-														purple_imgstore_get_size(image),
-														jabber_message_get_mimetype_from_ext(ext),
-														shortcut);
-						jabber_data_associate_local_with_conv(new_data, conv);
-						xmlnode_insert_child(message,
-							jabber_data_get_xml_definition(new_data));
+								purple_imgstore_get_size(image),
+								jabber_message_get_mimetype_from_ext(ext), js);
+						purple_debug_info("jabber", 
+							"cache local smiley alt = %s, cid = %s\n",
+							shortcut, jabber_data_get_cid(new_data));
+						jabber_data_associate_local(new_data, shortcut);
+						/* if the size of the data is small enough, include it */
+						if (jabber_data_get_size(new_data) <= 1024) {
+							xmlnode_insert_child(message,
+								jabber_data_get_xml_definition(new_data));
+						}
 					}
 				}
 
 				smileyfied_xhtml =
-					jabber_message_get_smileyfied_xhtml(conv, jm->xhtml,
-						found_smileys);
+					jabber_message_get_smileyfied_xhtml(jm->xhtml, found_smileys);
 				child = xmlnode_from_str(smileyfied_xhtml, -1);
 				g_free(smileyfied_xhtml);
 				g_list_free(found_smileys);
--- a/pidgin/gtksmiley.c	Thu Sep 04 22:18:58 2008 +0000
+++ b/pidgin/gtksmiley.c	Fri Sep 05 21:55:09 2008 +0000
@@ -273,8 +273,8 @@
 			gsize size = 0;
 			gchar *filename;
 
-			gdk_pixbuf_save_to_bufferv(s->custom_pixbuf, &buffer, &size,
-									   "png", NULL, NULL, NULL);
+			gdk_pixbuf_save_to_buffer(s->custom_pixbuf, &buffer, &size,
+				"png", NULL, "compression", "9", NULL, NULL);
 			filename = purple_util_get_image_filename(buffer, size);
 			s->filename = g_build_filename(purple_smileys_get_storing_dir(), filename, NULL);
 			purple_util_write_data_to_file_absolute(s->filename, buffer, size);