Mercurial > pidgin.yaz
comparison libpurple/protocols/jabber/buddy.c @ 17580: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 | 95affacf6f82 |
children | 5ab3c6bb95b4 |
comparison
equal
deleted
inserted
replaced
17579:af833a3204bb | 17580:7754d39d70c5 |
---|---|
32 #include "chat.h" | 32 #include "chat.h" |
33 #include "jabber.h" | 33 #include "jabber.h" |
34 #include "iq.h" | 34 #include "iq.h" |
35 #include "presence.h" | 35 #include "presence.h" |
36 #include "xdata.h" | 36 #include "xdata.h" |
37 #include "pep.h" | |
37 | 38 |
38 typedef struct { | 39 typedef struct { |
39 long idle_seconds; | 40 long idle_seconds; |
40 } JabberBuddyInfoResource; | 41 } JabberBuddyInfoResource; |
41 | 42 |
404 PurpleStoredImage *img; | 405 PurpleStoredImage *img; |
405 | 406 |
406 if ((img = purple_buddy_icons_find_account_icon(gc->account))) { | 407 if ((img = purple_buddy_icons_find_account_icon(gc->account))) { |
407 gconstpointer avatar_data; | 408 gconstpointer avatar_data; |
408 gsize avatar_len; | 409 gsize avatar_len; |
409 xmlnode *photo, *binval; | 410 xmlnode *photo, *binval, *type; |
410 gchar *enc; | 411 gchar *enc; |
411 int i; | 412 int i; |
412 unsigned char hashval[20]; | 413 unsigned char hashval[20]; |
413 char *p, hash[41]; | 414 char *p, hash[41]; |
414 | 415 |
415 avatar_data = purple_imgstore_get_data(img); | 416 avatar_data = purple_imgstore_get_data(img); |
416 avatar_len = purple_imgstore_get_size(img); | 417 avatar_len = purple_imgstore_get_size(img); |
417 photo = xmlnode_new_child(vc_node, "PHOTO"); | 418 photo = xmlnode_new_child(vc_node, "PHOTO"); |
419 type = xmlnode_new_child(photo, "TYPE"); | |
420 xmlnode_insert_data(type, "image/png", -1); | |
418 binval = xmlnode_new_child(photo, "BINVAL"); | 421 binval = xmlnode_new_child(photo, "BINVAL"); |
419 enc = purple_base64_encode(avatar_data, avatar_len); | 422 enc = purple_base64_encode(avatar_data, avatar_len); |
420 | 423 |
421 purple_cipher_digest_region("sha1", avatar_data, | 424 purple_cipher_digest_region("sha1", avatar_data, |
422 avatar_len, sizeof(hashval), | 425 avatar_len, sizeof(hashval), |
443 | 446 |
444 void jabber_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) | 447 void jabber_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) |
445 { | 448 { |
446 PurplePresence *gpresence; | 449 PurplePresence *gpresence; |
447 PurpleStatus *status; | 450 PurpleStatus *status; |
448 | 451 |
452 if(((JabberStream*)gc->proto_data)->pep) { | |
453 /* XEP-0084: User Avatars */ | |
454 if(img) { | |
455 /* A PNG header, including the IHDR, but nothing else */ | |
456 const struct { | |
457 guchar signature[8]; /* must be hex 89 50 4E 47 0D 0A 1A 0A */ | |
458 struct { | |
459 guint32 length; /* must be 0x0d */ | |
460 guchar type[4]; /* must be 'I' 'H' 'D' 'R' */ | |
461 guint32 width; | |
462 guint32 height; | |
463 guchar bitdepth; | |
464 guchar colortype; | |
465 guchar compression; | |
466 guchar filter; | |
467 guchar interlace; | |
468 } ihdr; | |
469 } *png = purple_imgstore_get_data(img); /* ATTN: this is in network byte order! */ | |
470 | |
471 /* check if the data is a valid png file (well, at least to some extend) */ | |
472 if(png->signature[0] == 0x89 && | |
473 png->signature[1] == 0x50 && | |
474 png->signature[2] == 0x4e && | |
475 png->signature[3] == 0x47 && | |
476 png->signature[4] == 0x0d && | |
477 png->signature[5] == 0x0a && | |
478 png->signature[6] == 0x1a && | |
479 png->signature[7] == 0x0a && | |
480 ntohl(png->ihdr.length) == 0x0d && | |
481 png->ihdr.type[0] == 'I' && | |
482 png->ihdr.type[1] == 'H' && | |
483 png->ihdr.type[2] == 'D' && | |
484 png->ihdr.type[3] == 'R') { | |
485 /* parse PNG header to get the size of the image (yes, this is required) */ | |
486 guint32 width = ntohl(png->ihdr.width); | |
487 guint32 height = ntohl(png->ihdr.height); | |
488 xmlnode *publish, *item, *data, *metadata, *info; | |
489 char *lengthstring, *widthstring, *heightstring; | |
490 | |
491 /* compute the sha1 hash */ | |
492 PurpleCipherContext *ctx; | |
493 unsigned char digest[20]; | |
494 char *hash; | |
495 char *base64avatar; | |
496 | |
497 ctx = purple_cipher_context_new_by_name("sha1", NULL); | |
498 purple_cipher_context_append(ctx, purple_imgstore_get_data(img), purple_imgstore_get_size(img)); | |
499 purple_cipher_context_digest(ctx, sizeof(digest), digest, NULL); | |
500 | |
501 /* convert digest to a string */ | |
502 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]); | |
503 | |
504 publish = xmlnode_new("publish"); | |
505 xmlnode_set_attrib(publish,"node","http://www.xmpp.org/extensions/xep-0084.html#ns-data"); | |
506 | |
507 item = xmlnode_new_child(publish, "item"); | |
508 xmlnode_set_attrib(item, "id", hash); | |
509 | |
510 data = xmlnode_new_child(item, "data"); | |
511 xmlnode_set_namespace(data,"http://www.xmpp.org/extensions/xep-0084.html#ns-data"); | |
512 | |
513 base64avatar = purple_base64_encode(purple_imgstore_get_data(img), purple_imgstore_get_size(img)); | |
514 xmlnode_insert_data(data,base64avatar,-1); | |
515 g_free(base64avatar); | |
516 | |
517 /* publish the avatar itself */ | |
518 jabber_pep_publish((JabberStream*)gc->proto_data, publish); | |
519 | |
520 /* next step: publish the metadata */ | |
521 publish = xmlnode_new("publish"); | |
522 xmlnode_set_attrib(publish,"node","http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); | |
523 | |
524 item = xmlnode_new_child(publish, "item"); | |
525 xmlnode_set_attrib(item, "id", hash); | |
526 | |
527 metadata = xmlnode_new_child(item, "metadata"); | |
528 xmlnode_set_namespace(metadata,"http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); | |
529 | |
530 info = xmlnode_new_child(metadata, "info"); | |
531 xmlnode_set_attrib(info, "id", hash); | |
532 xmlnode_set_attrib(info, "type", "image/png"); | |
533 lengthstring = g_strdup_printf("%u", (unsigned)purple_imgstore_get_size(img)); | |
534 xmlnode_set_attrib(info, "bytes", lengthstring); | |
535 g_free(lengthstring); | |
536 widthstring = g_strdup_printf("%u", width); | |
537 xmlnode_set_attrib(info, "width", widthstring); | |
538 g_free(widthstring); | |
539 heightstring = g_strdup_printf("%u", height); | |
540 xmlnode_set_attrib(info, "height", heightstring); | |
541 g_free(lengthstring); | |
542 | |
543 /* publish the metadata */ | |
544 jabber_pep_publish((JabberStream*)gc->proto_data, publish); | |
545 | |
546 g_free(hash); | |
547 } else { /* if(img) */ | |
548 /* remove the metadata */ | |
549 xmlnode *metadata, *item; | |
550 xmlnode *publish = xmlnode_new("publish"); | |
551 xmlnode_set_attrib(publish,"node","http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); | |
552 | |
553 item = xmlnode_new_child(publish, "item"); | |
554 | |
555 metadata = xmlnode_new_child(item, "metadata"); | |
556 xmlnode_set_namespace(metadata,"http://www.xmpp.org/extensions/xep-0084.html#ns-metadata"); | |
557 | |
558 xmlnode_new_child(metadata, "stop"); | |
559 | |
560 /* publish the metadata */ | |
561 jabber_pep_publish((JabberStream*)gc->proto_data, publish); | |
562 } | |
563 } else { | |
564 purple_debug(PURPLE_DEBUG_ERROR, "jabber", | |
565 "jabber_set_buddy_icon received non-png data"); | |
566 } | |
567 } | |
568 | |
569 /* even when the image is not png, we can still publish the vCard, since this | |
570 one doesn't require a specific image type */ | |
571 | |
572 /* publish vCard for those poor older clients */ | |
449 jabber_set_info(gc, purple_account_get_user_info(gc->account)); | 573 jabber_set_info(gc, purple_account_get_user_info(gc->account)); |
450 | 574 |
451 gpresence = purple_account_get_presence(gc->account); | 575 gpresence = purple_account_get_presence(gc->account); |
452 status = purple_presence_get_active_status(gpresence); | 576 status = purple_presence_get_active_status(gpresence); |
453 jabber_presence_send(gc->account, status); | 577 jabber_presence_send(gc->account, status); |
983 g_free(bare_jid); | 1107 g_free(bare_jid); |
984 | 1108 |
985 jabber_buddy_info_show_if_ready(jbi); | 1109 jabber_buddy_info_show_if_ready(jbi); |
986 } | 1110 } |
987 | 1111 |
1112 void jabber_buddy_avatar_update_metadata(JabberStream *js, const char *from, xmlnode *items) { | |
1113 | |
1114 } | |
988 | 1115 |
989 static void jabber_buddy_info_resource_free(gpointer data) | 1116 static void jabber_buddy_info_resource_free(gpointer data) |
990 { | 1117 { |
991 JabberBuddyInfoResource *jbri = data; | 1118 JabberBuddyInfoResource *jbri = data; |
992 g_free(jbri); | 1119 g_free(jbri); |