Mercurial > pidgin
changeset 17853:7754d39d70c5
Added support for setting the avatar via XEP-0084. Receiving other people's avatar is up next.
author | Andreas Monitzer <pidgin@monitzer.com> |
---|---|
date | Sun, 17 Jun 2007 01:16:55 +0000 |
parents | af833a3204bb |
children | 5ab3c6bb95b4 |
files | libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/buddy.h libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/libxmpp.c libpurple/protocols/jabber/pep.c libpurple/protocols/jabber/pep.h libpurple/protocols/jabber/usermood.c |
diffstat | 7 files changed, 151 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/jabber/buddy.c Fri Jun 15 21:09:22 2007 +0000 +++ b/libpurple/protocols/jabber/buddy.c Sun Jun 17 01:16:55 2007 +0000 @@ -34,6 +34,7 @@ #include "iq.h" #include "presence.h" #include "xdata.h" +#include "pep.h" typedef struct { long idle_seconds; @@ -406,7 +407,7 @@ if ((img = purple_buddy_icons_find_account_icon(gc->account))) { gconstpointer avatar_data; gsize avatar_len; - xmlnode *photo, *binval; + xmlnode *photo, *binval, *type; gchar *enc; int i; unsigned char hashval[20]; @@ -415,6 +416,8 @@ avatar_data = purple_imgstore_get_data(img); avatar_len = purple_imgstore_get_size(img); photo = xmlnode_new_child(vc_node, "PHOTO"); + type = xmlnode_new_child(photo, "TYPE"); + xmlnode_insert_data(type, "image/png", -1); binval = xmlnode_new_child(photo, "BINVAL"); enc = purple_base64_encode(avatar_data, avatar_len); @@ -445,7 +448,128 @@ { PurplePresence *gpresence; PurpleStatus *status; + + if(((JabberStream*)gc->proto_data)->pep) { + /* XEP-0084: User Avatars */ + if(img) { + /* 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 */ + PurpleCipherContext *ctx; + unsigned char digest[20]; + char *hash; + char *base64avatar; + + ctx = purple_cipher_context_new_by_name("sha1", NULL); + purple_cipher_context_append(ctx, purple_imgstore_get_data(img), purple_imgstore_get_size(img)); + purple_cipher_context_digest(ctx, sizeof(digest), digest, NULL); + + /* convert digest to a string */ + hash = g_strdup_printf("%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x",digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6],digest[7],digest[8],digest[9],digest[10],digest[11],digest[12],digest[13],digest[14],digest[15],digest[16],digest[17],digest[18],digest[19]); + + publish = xmlnode_new("publish"); + xmlnode_set_attrib(publish,"node","http://www.xmpp.org/extensions/xep-0084.html#ns-data"); + + item = xmlnode_new_child(publish, "item"); + xmlnode_set_attrib(item, "id", hash); + + data = xmlnode_new_child(item, "data"); + xmlnode_set_namespace(data,"http://www.xmpp.org/extensions/xep-0084.html#ns-data"); + + 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","http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); + + item = xmlnode_new_child(publish, "item"); + xmlnode_set_attrib(item, "id", hash); + + metadata = xmlnode_new_child(item, "metadata"); + xmlnode_set_namespace(metadata,"http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); + + 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(lengthstring); + + /* publish the metadata */ + jabber_pep_publish((JabberStream*)gc->proto_data, publish); + + g_free(hash); + } else { /* if(img) */ + /* remove the metadata */ + xmlnode *metadata, *item; + xmlnode *publish = xmlnode_new("publish"); + xmlnode_set_attrib(publish,"node","http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); + + item = xmlnode_new_child(publish, "item"); + + metadata = xmlnode_new_child(item, "metadata"); + xmlnode_set_namespace(metadata,"http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); + + xmlnode_new_child(metadata, "stop"); + + /* publish the metadata */ + jabber_pep_publish((JabberStream*)gc->proto_data, publish); + } + } else { + purple_debug(PURPLE_DEBUG_ERROR, "jabber", + "jabber_set_buddy_icon received non-png data"); + } + } + + /* even when the image is not png, we can still publish the vCard, since this + one doesn't require a specific image type */ + + /* publish vCard for those poor older clients */ jabber_set_info(gc, purple_account_get_user_info(gc->account)); gpresence = purple_account_get_presence(gc->account); @@ -985,6 +1109,9 @@ jabber_buddy_info_show_if_ready(jbi); } +void jabber_buddy_avatar_update_metadata(JabberStream *js, const char *from, xmlnode *items) { + +} static void jabber_buddy_info_resource_free(gpointer data) {
--- a/libpurple/protocols/jabber/buddy.h Fri Jun 15 21:09:22 2007 +0000 +++ b/libpurple/protocols/jabber/buddy.h Sun Jun 17 01:16:55 2007 +0000 @@ -93,6 +93,7 @@ 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);
--- a/libpurple/protocols/jabber/jabber.c Fri Jun 15 21:09:22 2007 +0000 +++ b/libpurple/protocols/jabber/jabber.c Sun Jun 17 01:16:55 2007 +0000 @@ -1965,5 +1965,9 @@ void jabber_init_plugin(PurplePlugin *plugin) { - my_protocol = plugin; + my_protocol = plugin; + jabber_add_feature("avatarmeta", "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata", jabber_pep_namespace_only_when_pep_enabled_cb); + jabber_add_feature("avatardata", "http://www.xmpp.org/extensions/xep-0084.html#ns-data", jabber_pep_namespace_only_when_pep_enabled_cb); + + jabber_pep_register_handler("avatar", "http://www.xmpp.org/extensions/xep-0084.html#ns-data", jabber_buddy_avatar_update_metadata); }
--- a/libpurple/protocols/jabber/libxmpp.c Fri Jun 15 21:09:22 2007 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Sun Jun 17 01:16:55 2007 +0000 @@ -50,7 +50,7 @@ #endif NULL, /* user_splits */ NULL, /* protocol_options */ - {"png,gif,jpeg", 32, 32, 96, 96, 8191, PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ + {"png", 32, 32, 96, 96, 8191, PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ jabber_list_icon, /* list_icon */ jabber_list_emblem, /* list_emblems */ jabber_status_text, /* status_text */
--- a/libpurple/protocols/jabber/pep.c Fri Jun 15 21:09:22 2007 +0000 +++ b/libpurple/protocols/jabber/pep.c Sun Jun 17 01:16:55 2007 +0000 @@ -46,6 +46,10 @@ g_hash_table_replace(pep_handlers, g_strdup(xmlns), handlerfunc); } +gboolean jabber_pep_namespace_only_when_pep_enabled_cb(JabberStream *js, const gchar *shortname, const gchar *namespace) { + return js->pep; +} + void jabber_handle_event(JabberMessage *jm) { /* this may be called even when the own server doesn't support pep! */ JabberPEPHandler *jph;
--- a/libpurple/protocols/jabber/pep.h Fri Jun 15 21:09:22 2007 +0000 +++ b/libpurple/protocols/jabber/pep.h Sun Jun 17 01:16:55 2007 +0000 @@ -48,6 +48,17 @@ */ void jabber_pep_register_handler(const char *shortname, const char *xmlns, JabberPEPHandler handlerfunc); +/* + * Default callback that can be used for namespaces which should only be enabled when PEP is supported + * + * @parameter js The JabberStream struct for this connection + * @parameter shortname The namespace's shortname (for caps), ignored. + * @parameter namespace The namespace that's queried, ignored. + * + * @returns TRUE when PEP is enabled, FALSE otherwise + */ +gboolean jabber_pep_namespace_only_when_pep_enabled_cb(JabberStream *js, const gchar *shortname, const gchar *namespace); + void jabber_handle_event(JabberMessage *jm); /*
--- a/libpurple/protocols/jabber/usermood.c Fri Jun 15 21:09:22 2007 +0000 +++ b/libpurple/protocols/jabber/usermood.c Sun Jun 17 01:16:55 2007 +0000 @@ -134,12 +134,8 @@ g_free(moodtext); } -static gboolean is_mood_supported(JabberStream *js, const gchar *shortname, const gchar *namespace) { - return js->pep; -} - void jabber_mood_init(void) { - jabber_add_feature("mood", "http://jabber.org/protocol/mood", is_mood_supported); + jabber_add_feature("mood", "http://jabber.org/protocol/mood", jabber_pep_namespace_only_when_pep_enabled_cb); jabber_pep_register_handler("moodn", "http://jabber.org/protocol/mood", jabber_mood_cb); }