summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Aurich <darkrain42@pidgin.im>2009-01-21 17:55:09 +0000
committerPaul Aurich <darkrain42@pidgin.im>2009-01-21 17:55:09 +0000
commit987c4603a0d41f4b05c7b1db318c7e8cf8833916 (patch)
tree8a8dcf9b1e2dba6b858dac693e22ffd2b3f233a5
parentde701476e4c93affd10d9348a89d81f4d6d9924e (diff)
downloadpidgin-987c4603a0d41f4b05c7b1db318c7e8cf8833916.tar.gz
Migrate the XMPP User Avatar (XEP-0084) code to its own file
I also slightly rearranged the ordering of jabber_avatar_set to make the error cases slightly more apparent.
-rw-r--r--libpurple/protocols/jabber/Makefile.am2
-rw-r--r--libpurple/protocols/jabber/buddy.c238
-rw-r--r--libpurple/protocols/jabber/buddy.h1
-rw-r--r--libpurple/protocols/jabber/libxmpp.c4
-rw-r--r--libpurple/protocols/jabber/pep.c2
-rw-r--r--libpurple/protocols/jabber/useravatar.c289
-rw-r--r--libpurple/protocols/jabber/useravatar.h34
7 files changed, 330 insertions, 240 deletions
diff --git a/libpurple/protocols/jabber/Makefile.am b/libpurple/protocols/jabber/Makefile.am
index 5f46e374a9..645be7e52b 100644
--- a/libpurple/protocols/jabber/Makefile.am
+++ b/libpurple/protocols/jabber/Makefile.am
@@ -45,6 +45,8 @@ JABBERSOURCES = auth.c \
adhoccommands.h \
pep.c \
pep.h \
+ useravatar.c \
+ useravatar.h \
usermood.c \
usermood.h \
usernick.c \
diff --git a/libpurple/protocols/jabber/buddy.c b/libpurple/protocols/jabber/buddy.c
index b4954e477a..75fa5317bf 100644
--- a/libpurple/protocols/jabber/buddy.c
+++ b/libpurple/protocols/jabber/buddy.c
@@ -32,12 +32,11 @@
#include "jabber.h"
#include "iq.h"
#include "presence.h"
+#include "useravatar.h"
#include "xdata.h"
#include "pep.h"
#include "adhoccommands.h"
-#define MAX_HTTP_BUDDYICON_BYTES (200 * 1024)
-
typedef struct {
long idle_seconds;
} JabberBuddyInfoResource;
@@ -496,123 +495,13 @@ void jabber_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img)
PurplePresence *gpresence;
PurpleStatus *status;
- if(((JabberStream*)gc->proto_data)->pep) {
- /* XEP-0084: User Avatars */
- if(img) {
- /*
- * TODO: This is pretty gross. The Jabber PRPL really shouldn't
- * do voodoo to try to determine the image type, height
- * and width.
- */
- /* A PNG header, including the IHDR, but nothing else */
- const struct {
- guchar signature[8]; /* must be hex 89 50 4E 47 0D 0A 1A 0A */
- struct {
- guint32 length; /* must be 0x0d */
- guchar type[4]; /* must be 'I' 'H' 'D' 'R' */
- guint32 width;
- guint32 height;
- guchar bitdepth;
- guchar colortype;
- guchar compression;
- guchar filter;
- guchar interlace;
- } ihdr;
- } *png = purple_imgstore_get_data(img); /* ATTN: this is in network byte order! */
-
- /* check if the data is a valid png file (well, at least to some extend) */
- if(png->signature[0] == 0x89 &&
- png->signature[1] == 0x50 &&
- png->signature[2] == 0x4e &&
- png->signature[3] == 0x47 &&
- png->signature[4] == 0x0d &&
- png->signature[5] == 0x0a &&
- png->signature[6] == 0x1a &&
- png->signature[7] == 0x0a &&
- ntohl(png->ihdr.length) == 0x0d &&
- png->ihdr.type[0] == 'I' &&
- png->ihdr.type[1] == 'H' &&
- png->ihdr.type[2] == 'D' &&
- png->ihdr.type[3] == 'R') {
- /* parse PNG header to get the size of the image (yes, this is required) */
- guint32 width = ntohl(png->ihdr.width);
- guint32 height = ntohl(png->ihdr.height);
- xmlnode *publish, *item, *data, *metadata, *info;
- char *lengthstring, *widthstring, *heightstring;
-
- /* compute the sha1 hash */
- char *hash = jabber_calculate_data_sha1sum(purple_imgstore_get_data(img), purple_imgstore_get_size(img));
- char *base64avatar;
-
- publish = xmlnode_new("publish");
- xmlnode_set_attrib(publish,"node",AVATARNAMESPACEDATA);
-
- item = xmlnode_new_child(publish, "item");
- xmlnode_set_attrib(item, "id", hash);
-
- data = xmlnode_new_child(item, "data");
- xmlnode_set_namespace(data,AVATARNAMESPACEDATA);
-
- base64avatar = purple_base64_encode(purple_imgstore_get_data(img), purple_imgstore_get_size(img));
- xmlnode_insert_data(data,base64avatar,-1);
- g_free(base64avatar);
-
- /* publish the avatar itself */
- jabber_pep_publish((JabberStream*)gc->proto_data, publish);
-
- /* next step: publish the metadata */
- publish = xmlnode_new("publish");
- xmlnode_set_attrib(publish,"node",AVATARNAMESPACEMETA);
-
- item = xmlnode_new_child(publish, "item");
- xmlnode_set_attrib(item, "id", hash);
-
- metadata = xmlnode_new_child(item, "metadata");
- xmlnode_set_namespace(metadata,AVATARNAMESPACEMETA);
-
- info = xmlnode_new_child(metadata, "info");
- xmlnode_set_attrib(info, "id", hash);
- xmlnode_set_attrib(info, "type", "image/png");
- lengthstring = g_strdup_printf("%u", (unsigned)purple_imgstore_get_size(img));
- xmlnode_set_attrib(info, "bytes", lengthstring);
- g_free(lengthstring);
- widthstring = g_strdup_printf("%u", width);
- xmlnode_set_attrib(info, "width", widthstring);
- g_free(widthstring);
- heightstring = g_strdup_printf("%u", height);
- xmlnode_set_attrib(info, "height", heightstring);
- g_free(heightstring);
-
- /* publish the metadata */
- jabber_pep_publish((JabberStream*)gc->proto_data, publish);
-
- g_free(hash);
- } else {
- purple_debug_error("jabber", "jabber_set_buddy_icon received non-png data");
- }
- } else {
- /* remove the metadata */
- xmlnode *metadata, *item;
- xmlnode *publish = xmlnode_new("publish");
- xmlnode_set_attrib(publish,"node",AVATARNAMESPACEMETA);
-
- item = xmlnode_new_child(publish, "item");
-
- metadata = xmlnode_new_child(item, "metadata");
- xmlnode_set_namespace(metadata,AVATARNAMESPACEMETA);
-
- xmlnode_new_child(metadata, "stop");
-
- /* publish the metadata */
- jabber_pep_publish((JabberStream*)gc->proto_data, publish);
- }
- }
-
+ jabber_avatar_set(gc->proto_data, img);
/* vCard avatars do not have an image type requirement so update our
* vCard avatar regardless of image type for those poor older clients
*/
jabber_set_info(gc, purple_account_get_user_info(gc->account));
+ /* TODO: Call this in jabber_set_info() if avatar changed? */
gpresence = purple_account_get_presence(gc->account);
status = purple_presence_get_active_status(gpresence);
jabber_presence_send(gc->account, status);
@@ -1427,127 +1316,6 @@ static void jabber_vcard_parse(JabberStream *js, xmlnode *packet, gpointer data)
jabber_buddy_info_show_if_ready(jbi);
}
-typedef struct _JabberBuddyAvatarUpdateURLInfo {
- JabberStream *js;
- char *from;
- char *id;
-} JabberBuddyAvatarUpdateURLInfo;
-
-static void do_buddy_avatar_update_fromurl(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message) {
- JabberBuddyAvatarUpdateURLInfo *info = user_data;
- if(!url_text) {
- purple_debug(PURPLE_DEBUG_ERROR, "jabber",
- "do_buddy_avatar_update_fromurl got error \"%s\"", error_message);
- return;
- }
-
- purple_buddy_icons_set_for_user(purple_connection_get_account(info->js->gc), info->from, (void*)url_text, len, info->id);
- g_free(info->from);
- g_free(info->id);
- g_free(info);
-}
-
-static void do_buddy_avatar_update_data(JabberStream *js, const char *from, xmlnode *items) {
- xmlnode *item, *data;
- const char *checksum;
- char *b64data;
- void *img;
- size_t size;
- if(!items)
- return;
-
- item = xmlnode_get_child(items, "item");
- if(!item)
- return;
-
- data = xmlnode_get_child_with_namespace(item,"data",AVATARNAMESPACEDATA);
- if(!data)
- return;
-
- checksum = xmlnode_get_attrib(item,"id");
- if(!checksum)
- return;
-
- b64data = xmlnode_get_data(data);
- if(!b64data)
- return;
-
- img = purple_base64_decode(b64data, &size);
- if(!img) {
- g_free(b64data);
- return;
- }
-
- purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, img, size, checksum);
- g_free(b64data);
-}
-
-void jabber_buddy_avatar_update_metadata(JabberStream *js, const char *from, xmlnode *items) {
- PurpleBuddy *buddy = purple_find_buddy(purple_connection_get_account(js->gc), from);
- const char *checksum;
- xmlnode *item, *metadata;
- if(!buddy)
- return;
-
- checksum = purple_buddy_icons_get_checksum_for_user(buddy);
- item = xmlnode_get_child(items,"item");
- metadata = xmlnode_get_child_with_namespace(item, "metadata", AVATARNAMESPACEMETA);
- if(!metadata)
- return;
- /* check if we have received a stop */
- if(xmlnode_get_child(metadata, "stop")) {
- purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, NULL, 0, NULL);
- } else {
- xmlnode *info, *goodinfo = NULL;
- gboolean has_children = FALSE;
-
- /* iterate over all info nodes to get one we can use */
- for(info = metadata->child; info; info = info->next) {
- if(info->type == XMLNODE_TYPE_TAG)
- has_children = TRUE;
- if(info->type == XMLNODE_TYPE_TAG && !strcmp(info->name,"info")) {
- const char *type = xmlnode_get_attrib(info,"type");
- const char *id = xmlnode_get_attrib(info,"id");
-
- if(checksum && id && !strcmp(id, checksum)) {
- /* we already have that avatar, so we don't have to do anything */
- goodinfo = NULL;
- break;
- }
- /* We'll only pick the png one for now. It's a very nice image format anyways. */
- if(type && id && !goodinfo && !strcmp(type, "image/png"))
- goodinfo = info;
- }
- }
- if(has_children == FALSE) {
- purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, NULL, 0, NULL);
- } else if(goodinfo) {
- const char *url = xmlnode_get_attrib(goodinfo, "url");
- const char *id = xmlnode_get_attrib(goodinfo,"id");
-
- /* the avatar might either be stored in a pep node, or on a HTTP/HTTPS URL */
- if(!url)
- jabber_pep_request_item(js, from, AVATARNAMESPACEDATA, id, do_buddy_avatar_update_data);
- else {
- PurpleUtilFetchUrlData *url_data;
- JabberBuddyAvatarUpdateURLInfo *info = g_new0(JabberBuddyAvatarUpdateURLInfo, 1);
- info->js = js;
-
- url_data = purple_util_fetch_url_len(url, TRUE, NULL, TRUE,
- MAX_HTTP_BUDDYICON_BYTES,
- do_buddy_avatar_update_fromurl, info);
- if (url_data) {
- info->from = g_strdup(from);
- info->id = g_strdup(id);
- js->url_datas = g_slist_prepend(js->url_datas, url_data);
- } else
- g_free(info);
-
- }
- }
- }
-}
-
static void jabber_buddy_info_resource_free(gpointer data)
{
JabberBuddyInfoResource *jbri = data;
diff --git a/libpurple/protocols/jabber/buddy.h b/libpurple/protocols/jabber/buddy.h
index 0eb49b7c50..1529bb67da 100644
--- a/libpurple/protocols/jabber/buddy.h
+++ b/libpurple/protocols/jabber/buddy.h
@@ -102,7 +102,6 @@ GList *jabber_blist_node_menu(PurpleBlistNode *node);
void jabber_set_info(PurpleConnection *gc, const char *info);
void jabber_setup_set_info(PurplePluginAction *action);
void jabber_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img);
-void jabber_buddy_avatar_update_metadata(JabberStream *js, const char *from, xmlnode *items);
const char *jabber_buddy_state_get_name(JabberBuddyState state);
const char *jabber_buddy_state_get_status_id(JabberBuddyState state);
diff --git a/libpurple/protocols/jabber/libxmpp.c b/libpurple/protocols/jabber/libxmpp.c
index cc8c408320..7b170580cf 100644
--- a/libpurple/protocols/jabber/libxmpp.c
+++ b/libpurple/protocols/jabber/libxmpp.c
@@ -281,14 +281,10 @@ init_plugin(PurplePlugin *plugin)
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);
jabber_add_feature("bob", XEP_0231_NAMESPACE,
jabber_custom_smileys_isenabled);
-
- jabber_pep_register_handler("avatar", AVATARNAMESPACEMETA, jabber_buddy_avatar_update_metadata);
}
diff --git a/libpurple/protocols/jabber/pep.c b/libpurple/protocols/jabber/pep.c
index fae2223b63..d2d35255ec 100644
--- a/libpurple/protocols/jabber/pep.c
+++ b/libpurple/protocols/jabber/pep.c
@@ -24,6 +24,7 @@
#include "pep.h"
#include "iq.h"
#include <string.h>
+#include "useravatar.h"
#include "usermood.h"
#include "usernick.h"
@@ -34,6 +35,7 @@ void jabber_pep_init(void) {
pep_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
/* register PEP handlers */
+ jabber_avatar_init();
jabber_mood_init();
jabber_nick_init();
}
diff --git a/libpurple/protocols/jabber/useravatar.c b/libpurple/protocols/jabber/useravatar.c
new file mode 100644
index 0000000000..3cfdc71350
--- /dev/null
+++ b/libpurple/protocols/jabber/useravatar.c
@@ -0,0 +1,289 @@
+/*
+ * purple - Jabber Protocol Plugin
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "internal.h"
+
+#include "useravatar.h"
+#include "pep.h"
+#include "debug.h"
+
+#define MAX_HTTP_BUDDYICON_BYTES (200 * 1024)
+
+static void update_buddy_metadata(JabberStream *js, const char *from, xmlnode *items);
+
+void jabber_avatar_init(void)
+{
+ jabber_add_feature("avatarmeta", AVATARNAMESPACEMETA,
+ jabber_pep_namespace_only_when_pep_enabled_cb);
+ jabber_add_feature("avatardata", AVATARNAMESPACEMETA,
+ jabber_pep_namespace_only_when_pep_enabled_cb);
+
+ jabber_pep_register_handler("avatar", AVATARNAMESPACEMETA,
+ update_buddy_metadata);
+}
+
+void jabber_avatar_set(JabberStream *js, PurpleStoredImage *img)
+{
+ xmlnode *publish, *metadata, *item;
+
+ if (!js->pep)
+ return;
+
+ if (!img) {
+ /* remove the metadata */
+ publish = xmlnode_new("publish");
+ xmlnode_set_attrib(publish, "node", AVATARNAMESPACEMETA);
+
+ item = xmlnode_new_child(publish, "item");
+ metadata = xmlnode_new_child(item, "metadata");
+ xmlnode_set_namespace(metadata, AVATARNAMESPACEMETA);
+
+ xmlnode_new_child(metadata, "stop");
+ /* publish */
+ jabber_pep_publish(js, publish);
+ } else {
+ /*
+ * TODO: This is pretty gross. The Jabber PRPL really shouldn't
+ * do voodoo to try to determine the image type, height
+ * and width.
+ */
+ /* A PNG header, including the IHDR, but nothing else */
+ const struct {
+ guchar signature[8]; /* must be hex 89 50 4E 47 0D 0A 1A 0A */
+ struct {
+ guint32 length; /* must be 0x0d */
+ guchar type[4]; /* must be 'I' 'H' 'D' 'R' */
+ guint32 width;
+ guint32 height;
+ guchar bitdepth;
+ guchar colortype;
+ guchar compression;
+ guchar filter;
+ guchar interlace;
+ } ihdr;
+ } *png = purple_imgstore_get_data(img); /* ATTN: this is in network byte order! */
+
+ /* check if the data is a valid png file (well, at least to some extend) */
+ if(png->signature[0] == 0x89 &&
+ png->signature[1] == 0x50 &&
+ png->signature[2] == 0x4e &&
+ png->signature[3] == 0x47 &&
+ png->signature[4] == 0x0d &&
+ png->signature[5] == 0x0a &&
+ png->signature[6] == 0x1a &&
+ png->signature[7] == 0x0a &&
+ ntohl(png->ihdr.length) == 0x0d &&
+ png->ihdr.type[0] == 'I' &&
+ png->ihdr.type[1] == 'H' &&
+ png->ihdr.type[2] == 'D' &&
+ png->ihdr.type[3] == 'R') {
+ /* parse PNG header to get the size of the image (yes, this is required) */
+ guint32 width = ntohl(png->ihdr.width);
+ guint32 height = ntohl(png->ihdr.height);
+ xmlnode *data, *info;
+ char *lengthstring, *widthstring, *heightstring;
+
+ /* compute the sha1 hash */
+ char *hash = jabber_calculate_data_sha1sum(purple_imgstore_get_data(img), purple_imgstore_get_size(img));
+ char *base64avatar;
+
+ publish = xmlnode_new("publish");
+ xmlnode_set_attrib(publish, "node", AVATARNAMESPACEDATA);
+
+ item = xmlnode_new_child(publish, "item");
+ xmlnode_set_attrib(item, "id", hash);
+
+ data = xmlnode_new_child(item, "data");
+ xmlnode_set_namespace(data, AVATARNAMESPACEDATA);
+
+ base64avatar = purple_base64_encode(purple_imgstore_get_data(img),
+ purple_imgstore_get_size(img));
+ xmlnode_insert_data(data,base64avatar,-1);
+ g_free(base64avatar);
+
+ /* publish the avatar itself */
+ jabber_pep_publish(js, publish);
+
+ /* next step: publish the metadata */
+ publish = xmlnode_new("publish");
+ xmlnode_set_attrib(publish,"node", AVATARNAMESPACEMETA);
+
+ item = xmlnode_new_child(publish, "item");
+ xmlnode_set_attrib(item, "id", hash);
+
+ metadata = xmlnode_new_child(item, "metadata");
+ xmlnode_set_namespace(metadata, AVATARNAMESPACEMETA);
+
+ lengthstring = g_strdup_printf("%u", (unsigned)purple_imgstore_get_size(img));
+ widthstring = g_strdup_printf("%u", width);
+ heightstring = g_strdup_printf("%u", height);
+
+ info = xmlnode_new_child(metadata, "info");
+ xmlnode_set_attrib(info, "id", hash);
+ xmlnode_set_attrib(info, "type", "image/png");
+ xmlnode_set_attrib(info, "bytes", lengthstring);
+ xmlnode_set_attrib(info, "width", widthstring);
+ xmlnode_set_attrib(info, "height", heightstring);
+ g_free(lengthstring);
+ g_free(widthstring);
+ g_free(heightstring);
+
+ /* publish the metadata */
+ jabber_pep_publish(js, publish);
+
+ g_free(hash);
+ } else {
+ purple_debug_error("jabber", "Cannot set PEP avatar to non-PNG data\n");
+ }
+ }
+}
+
+typedef struct _JabberBuddyAvatarUpdateURLInfo {
+ JabberStream *js;
+ char *from;
+ char *id;
+} JabberBuddyAvatarUpdateURLInfo;
+
+static void
+do_buddy_avatar_update_fromurl(PurpleUtilFetchUrlData *url_data,
+ gpointer user_data, const gchar *url_text,
+ gsize len, const gchar *error_message)
+{
+ JabberBuddyAvatarUpdateURLInfo *info = user_data;
+ if(!url_text) {
+ purple_debug(PURPLE_DEBUG_ERROR, "jabber",
+ "do_buddy_avatar_update_fromurl got error \"%s\"",
+ error_message);
+ return;
+ }
+
+ purple_buddy_icons_set_for_user(purple_connection_get_account(info->js->gc), info->from, (void*)url_text, len, info->id);
+ g_free(info->from);
+ g_free(info->id);
+ g_free(info);
+}
+
+static void
+do_buddy_avatar_update_data(JabberStream *js, const char *from, xmlnode *items)
+{
+ xmlnode *item, *data;
+ const char *checksum;
+ char *b64data;
+ void *img;
+ size_t size;
+ if(!items)
+ return;
+
+ item = xmlnode_get_child(items, "item");
+ if(!item)
+ return;
+
+ data = xmlnode_get_child_with_namespace(item,"data",AVATARNAMESPACEDATA);
+ if(!data)
+ return;
+
+ checksum = xmlnode_get_attrib(item,"id");
+ if(!checksum)
+ return;
+
+ b64data = xmlnode_get_data(data);
+ if(!b64data)
+ return;
+
+ img = purple_base64_decode(b64data, &size);
+ if(!img) {
+ g_free(b64data);
+ return;
+ }
+
+ purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, img, size, checksum);
+ g_free(b64data);
+}
+
+static void
+update_buddy_metadata(JabberStream *js, const char *from, xmlnode *items)
+{
+ PurpleBuddy *buddy = purple_find_buddy(purple_connection_get_account(js->gc), from);
+ const char *checksum;
+ xmlnode *item, *metadata;
+ if(!buddy)
+ return;
+
+ checksum = purple_buddy_icons_get_checksum_for_user(buddy);
+ item = xmlnode_get_child(items,"item");
+ metadata = xmlnode_get_child_with_namespace(item, "metadata", AVATARNAMESPACEMETA);
+ if(!metadata)
+ return;
+ /* check if we have received a stop */
+ if(xmlnode_get_child(metadata, "stop")) {
+ purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, NULL, 0, NULL);
+ } else {
+ xmlnode *info, *goodinfo = NULL;
+ gboolean has_children = FALSE;
+
+ /* iterate over all info nodes to get one we can use */
+ for(info = metadata->child; info; info = info->next) {
+ if(info->type == XMLNODE_TYPE_TAG)
+ has_children = TRUE;
+ if(info->type == XMLNODE_TYPE_TAG && !strcmp(info->name,"info")) {
+ const char *type = xmlnode_get_attrib(info,"type");
+ const char *id = xmlnode_get_attrib(info,"id");
+
+ if(checksum && id && !strcmp(id, checksum)) {
+ /* we already have that avatar, so we don't have to do anything */
+ goodinfo = NULL;
+ break;
+ }
+ /* We'll only pick the png one for now. It's a very nice image format anyways. */
+ if(type && id && !goodinfo && !strcmp(type, "image/png"))
+ goodinfo = info;
+ }
+ }
+ if(has_children == FALSE) {
+ purple_buddy_icons_set_for_user(purple_connection_get_account(js->gc), from, NULL, 0, NULL);
+ } else if(goodinfo) {
+ const char *url = xmlnode_get_attrib(goodinfo, "url");
+ const char *id = xmlnode_get_attrib(goodinfo,"id");
+
+ /* the avatar might either be stored in a pep node, or on a HTTP(S) URL */
+ if(!url)
+ jabber_pep_request_item(js, from, AVATARNAMESPACEDATA, id, do_buddy_avatar_update_data);
+ else {
+ PurpleUtilFetchUrlData *url_data;
+ JabberBuddyAvatarUpdateURLInfo *info = g_new0(JabberBuddyAvatarUpdateURLInfo, 1);
+ info->js = js;
+
+ url_data = purple_util_fetch_url_len(url, TRUE, NULL, TRUE,
+ MAX_HTTP_BUDDYICON_BYTES,
+ do_buddy_avatar_update_fromurl, info);
+ if (url_data) {
+ info->from = g_strdup(from);
+ info->id = g_strdup(id);
+ js->url_datas = g_slist_prepend(js->url_datas, url_data);
+ } else
+ g_free(info);
+
+ }
+ }
+ }
+}
diff --git a/libpurple/protocols/jabber/useravatar.h b/libpurple/protocols/jabber/useravatar.h
new file mode 100644
index 0000000000..febd0cc473
--- /dev/null
+++ b/libpurple/protocols/jabber/useravatar.h
@@ -0,0 +1,34 @@
+/*
+ * purple - Jabber Protocol Plugin
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _PURPLE_JABBER_USERAVATAR_H_
+#define _PURPLE_JABBER_USERAVATAR_H_
+
+#include "jabber.h"
+
+/* Implementation of XEP-0084 */
+
+void jabber_avatar_init(void);
+void jabber_avatar_set(JabberStream *js, PurpleStoredImage *img);
+
+#endif /* _PURPLE_JABBER_USERAVATAR_H_ */