changeset 23780:9d83ae2c1a4f

New files used for custom smileys. committer: Sadrul Habib Chowdhury <imadil@gmail.com>
author Marcus Lundblad <ml@update.uu.se>
date Sun, 01 Jun 2008 21:39:15 +0000
parents b2697ab66d23
children c45d05bd58ed
files libpurple/protocols/jabber/data.c libpurple/protocols/jabber/data.h
diffstat 2 files changed, 403 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/data.c	Sun Jun 01 21:39:15 2008 +0000
@@ -0,0 +1,320 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#include <stdlib.h>
+#include <glib.h>
+#include <string.h>
+
+#include "data.h"
+#include "debug.h"
+#include "xmlnode.h"
+#include "util.h"
+#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);
+}
+
+JabberData *
+jabber_data_create_from_data(gconstpointer rawdata, gsize size, const char *type,
+							 const char *alt)
+{
+	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_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);
+
+	return data;
+}
+
+JabberData *
+jabber_data_create_from_xml(xmlnode *tag)
+{
+	JabberData *data = g_new0(JabberData, 1);
+	gsize size;
+	gpointer raw_data = NULL;
+
+	if (data == NULL) {
+		purple_debug_error("jabber", "Could not allocate data object\n");
+		g_free(data);
+		return NULL;
+	}
+
+	/* check if this is a "data" tag */
+	if (strcmp(tag->name, "data") != 0) {
+		purple_debug_error("jabber", "Invalid data element");
+		g_free(data);
+		return NULL;
+	}
+
+	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;
+
+	g_free(raw_data);
+
+	return data;
+}
+
+
+void
+jabber_data_delete(JabberData *data)
+{
+	g_free(data->cid);
+	g_free(data->alt);
+	g_free(data->type);
+	g_free(data->data);
+	g_free(data);
+}
+
+const char *
+jabber_data_get_cid(const JabberData *data)
+{
+	return data->cid;
+}
+
+const char *
+jabber_data_get_alt(const JabberData *data)
+{
+	return data->alt;
+}
+
+const char *
+jabber_data_get_type(const JabberData *data)
+{
+	return data->type;
+}
+
+gsize
+jabber_data_get_size(const JabberData *data)
+{
+	return data->size;
+}
+
+gpointer
+jabber_data_get_data(const JabberData *data)
+{
+	return data->data;
+}
+
+xmlnode *
+jabber_data_get_xml_definition(const JabberData *data)
+{
+	xmlnode *tag = xmlnode_new("data");
+	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);
+
+	xmlnode_insert_data(tag, base64data, -1);
+
+	g_free(base64data);
+
+	return tag;
+}
+
+xmlnode *
+jabber_data_get_xhtml_im(const JabberData *data)
+{
+	xmlnode *img = xmlnode_new("img");
+	char src[128];
+
+	xmlnode_set_attrib(img, "alt", data->alt);
+	g_snprintf(src, sizeof(src), "cid:%s", data->cid);
+	xmlnode_set_attrib(img, "src", src);
+
+	return img;
+}
+
+xmlnode *
+jabber_data_get_xml_request(const gchar *cid)
+{
+	xmlnode *tag = xmlnode_new("data");
+
+	xmlnode_set_namespace(tag, XEP_0231_NAMESPACE);
+	xmlnode_set_attrib(tag, "cid", cid);
+
+	return tag;
+}
+
+const JabberData *
+jabber_data_find_local_by_alt(const PurpleConversation *conv, const char *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;
+	}
+}
+
+const JabberData *
+jabber_data_find_remote_by_cid(const PurpleConversation *conv, const char *cid)
+{
+	GHashTable *remote_datas = g_hash_table_lookup(remote_datas_by_cid, conv);
+
+	if (remote_datas) {
+		return g_hash_table_lookup(remote_datas, cid);
+	} else {
+		return NULL;
+	}
+}
+
+void
+jabber_data_associate_local_with_conv(JabberData *data, PurpleConversation *conv)
+{
+	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);
+}
+
+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)
+{
+	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);
+	}
+}
+
+void
+jabber_data_parse(JabberStream *js, xmlnode *packet)
+{
+	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"));
+
+	if (!conv || !data) {
+		xmlnode *item_not_found = xmlnode_new("item-not-found");
+
+		result = jabber_iq_new(js, JABBER_IQ_ERROR);
+		xmlnode_set_attrib(result->node, "to", who);
+		xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+		xmlnode_insert_child(result->node, item_not_found);
+	} else {
+		result = jabber_iq_new(js, JABBER_IQ_RESULT);
+		xmlnode_set_attrib(result->node, "to", who);
+		xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+		xmlnode_insert_child(result->node,
+							 jabber_data_get_xml_definition(data));
+	}
+	jabber_iq_send(result);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/data.h	Sun Jun 01 21:39:15 2008 +0000
@@ -0,0 +1,83 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#ifndef JABBER_DATA_H
+#define JABBER_DATA_H
+
+#include "xmlnode.h"
+#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"
+
+#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);
+
+/* create a JabberData instance from an XML "data" element (as defined by
+  XEP 0231 */
+JabberData *jabber_data_create_from_xml(xmlnode *tag);
+
+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);
+gpointer jabber_data_get_data(const JabberData *data);
+
+/* returns the XML definition for the data element */
+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);
+
+/* 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 char *alt);
+const JabberData *jabber_data_find_local_by_cid(const PurpleConversation *conv,
+												const char *cid);
+const JabberData *jabber_data_find_remote_by_cid(const PurpleConversation *conv,
+												 const char *cid);
+
+/* associate data objects with a conversation */
+void jabber_data_associate_local_with_conv(JabberData *data, PurpleConversation *conv);
+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);
+
+
+#endif /* JABBER_DATA_H */