# HG changeset patch # User Daniel Atallah # Date 1186626603 0 # Node ID 32a44f7e9c52ee4c92604ed2edc0ceeb92aa150b # Parent a53992a4437aaf628992e0c2cfbce87f243e2ec5# Parent 2bf2bd713955506dda322ecb16fe60209fe5a26e merge of '27e06af9a3657aa4d9664c8f17f3aee8ebc41e65' and '7a479398307e3af8d16c684697d3ec93cd8e491c' diff -r a53992a4437a -r 32a44f7e9c52 libpurple/protocols/bonjour/buddy.c --- a/libpurple/protocols/bonjour/buddy.c Wed Aug 08 01:57:39 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.c Thu Aug 09 02:30:03 2007 +0000 @@ -18,6 +18,7 @@ #include #include "internal.h" +#include "cipher.h" #include "buddy.h" #include "account.h" #include "blist.h" @@ -106,11 +107,10 @@ PurpleBuddy *buddy; PurpleGroup *group; PurpleAccount *account = bonjour_buddy->account; - const char *status_id, *first, *last, *old_hash, *new_hash; - gchar *alias = NULL; + const char *status_id, *old_hash, *new_hash; /* Translate between the Bonjour status and the Purple status */ - if (g_ascii_strcasecmp("dnd", bonjour_buddy->status) == 0) + if (bonjour_buddy->status != NULL && g_ascii_strcasecmp("dnd", bonjour_buddy->status) == 0) status_id = BONJOUR_STATUS_ID_AWAY; else status_id = BONJOUR_STATUS_ID_AVAILABLE; @@ -138,15 +138,21 @@ } /* Create the alias for the buddy using the first and the last name */ - first = bonjour_buddy->first; - last = bonjour_buddy->last; - if ((first && *first) || (last && *last)) - alias = g_strdup_printf("%s%s%s", - (first && *first ? first : ""), - (first && *first && last && *last ? " " : ""), - (last && *last ? last : "")); - serv_got_alias(purple_account_get_connection(account), buddy->name, alias); - g_free(alias); + if (bonjour_buddy->nick) + serv_got_alias(purple_account_get_connection(account), buddy->name, bonjour_buddy->nick); + else { + gchar *alias = NULL; + const char *first, *last; + first = bonjour_buddy->first; + last = bonjour_buddy->last; + if ((first && *first) || (last && *last)) + alias = g_strdup_printf("%s%s%s", + (first && *first ? first : ""), + (first && *first && last && *last ? " " : ""), + (last && *last ? last : "")); + serv_got_alias(purple_account_get_connection(account), buddy->name, alias); + g_free(alias); + } /* Set the user's status */ if (bonjour_buddy->msg != NULL) @@ -166,12 +172,46 @@ new_hash = (bonjour_buddy->phsh && *(bonjour_buddy->phsh)) ? bonjour_buddy->phsh : NULL; if (new_hash && (!old_hash || strcmp(old_hash, new_hash) != 0)) { /* Look up the new icon data */ + /* TODO: Make sure the hash assigned to the retrieved buddy icon is the same + * as what we looked up. */ bonjour_dns_sd_retrieve_buddy_icon(bonjour_buddy); - } else + } else if (!new_hash) purple_buddy_icons_set_for_user(account, buddy->name, NULL, 0, NULL); } /** + * We got the buddy icon data; deal with it + */ +void bonjour_buddy_got_buddy_icon(BonjourBuddy *buddy, gconstpointer data, gsize len) { + /* Recalculate the hash instead of using the current phsh to make sure it is accurate for the icon. */ + int i; + gchar *enc; + char *p, hash[41]; + unsigned char hashval[20]; + + if (data == NULL || len == 0) + return; + + enc = purple_base64_encode(data, len); + + purple_cipher_digest_region("sha1", data, + len, sizeof(hashval), + hashval, NULL); + + p = hash; + for(i=0; i<20; i++, p+=2) + snprintf(p, 3, "%02x", hashval[i]); + + purple_debug_info("bonjour", "Got buddy icon for %s icon hash='%s' phsh='%s'.\n", buddy->name, + hash, buddy->phsh ? buddy->phsh : "(null)"); + + purple_buddy_icons_set_for_user(buddy->account, buddy->name, + g_memdup(data, len), len, hash); + + g_free(enc); +} + +/** * Deletes a buddy from memory. */ void diff -r a53992a4437a -r 32a44f7e9c52 libpurple/protocols/bonjour/buddy.h --- a/libpurple/protocols/bonjour/buddy.h Wed Aug 08 01:57:39 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.h Thu Aug 09 02:30:03 2007 +0000 @@ -90,6 +90,11 @@ void bonjour_buddy_add_to_purple(BonjourBuddy *buddy); /** + * We got the buddy icon data; deal with it + */ +void bonjour_buddy_got_buddy_icon(BonjourBuddy *buddy, gconstpointer data, gsize len); + +/** * Deletes a buddy from memory. */ void bonjour_buddy_delete(BonjourBuddy *buddy); diff -r a53992a4437a -r 32a44f7e9c52 libpurple/protocols/bonjour/issues.txt --- a/libpurple/protocols/bonjour/issues.txt Wed Aug 08 01:57:39 2007 +0000 +++ b/libpurple/protocols/bonjour/issues.txt Thu Aug 09 02:30:03 2007 +0000 @@ -3,6 +3,5 @@ ========================================== * Status changes don't work -* Avatars * File transfers * Typing notifications diff -r a53992a4437a -r 32a44f7e9c52 libpurple/protocols/bonjour/mdns_avahi.c --- a/libpurple/protocols/bonjour/mdns_avahi.c Wed Aug 08 01:57:39 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_avahi.c Thu Aug 09 02:30:03 2007 +0000 @@ -341,10 +341,10 @@ return TRUE; } -void _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { +gboolean _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { + return FALSE; } - void _mdns_stop(BonjourDnsSd *data) { AvahiSessionImplData *idata = data->mdns_impl_data; @@ -379,7 +379,7 @@ buddy->mdns_impl_data = NULL; } -void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy) { +void _mdns_retrieve_retrieve_buddy_icon(BonjourBuddy* buddy) { PurpleConnection *conn = purple_account_get_connection(buddy->account); BonjourData *bd = conn->proto_data; AvahiSessionImplData *session_idata = bd->dns_sd_data->mdns_impl_data; @@ -401,7 +401,7 @@ purple_debug_error("bonjour", "Unable to initialize record browser. Error: %s\n.", avahi_strerror(avahi_client_errno(session_idata->client))); - } +} } diff -r a53992a4437a -r 32a44f7e9c52 libpurple/protocols/bonjour/mdns_common.c --- a/libpurple/protocols/bonjour/mdns_common.c Wed Aug 08 01:57:39 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_common.c Thu Aug 09 02:30:03 2007 +0000 @@ -67,40 +67,11 @@ _mdns_publish(data, PUBLISH_UPDATE); /* <--We must control the errors */ } -void -bonjour_dns_sd_buddy_icon_data_set(BonjourDnsSd *data) { - PurpleStoredImage *img = purple_buddy_icons_find_account_icon(data->account); - gconstpointer avatar_data; - gsize avatar_len; - gchar *enc; - int i; - unsigned char hashval[20]; - char *p, hash[41]; - - g_return_if_fail(img != NULL); - - avatar_data = purple_imgstore_get_data(img); - avatar_len = purple_imgstore_get_size(img); - - enc = purple_base64_encode(avatar_data, avatar_len); - - purple_cipher_digest_region("sha1", avatar_data, - avatar_len, sizeof(hashval), - hashval, NULL); - - purple_imgstore_unref(img); - - p = hash; - for(i=0; i<20; i++, p+=2) - snprintf(p, 3, "%02x", hashval[i]); - - g_free(data->phsh); - data->phsh = g_strdup(hash); - - g_free(enc); - - /* Update our TXT record */ - _mdns_publish(data, PUBLISH_UPDATE); +/** + * Retrieve the buddy icon blob + */ +void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy) { + _mdns_retrieve_retrieve_buddy_icon(buddy); } void @@ -114,7 +85,30 @@ avatar_data = purple_imgstore_get_data(img); avatar_len = purple_imgstore_get_size(img); - _mdns_set_buddy_icon_data(data, avatar_data, avatar_len); + if (_mdns_set_buddy_icon_data(data, avatar_data, avatar_len)) { + int i; + gchar *enc; + char *p, hash[41]; + unsigned char hashval[20]; + + enc = purple_base64_encode(avatar_data, avatar_len); + + purple_cipher_digest_region("sha1", avatar_data, + avatar_len, sizeof(hashval), + hashval, NULL); + + p = hash; + for(i=0; i<20; i++, p+=2) + snprintf(p, 3, "%02x", hashval[i]); + + g_free(data->phsh); + data->phsh = g_strdup(hash); + + g_free(enc); + + /* Update our TXT record */ + _mdns_publish(data, PUBLISH_UPDATE); + } purple_imgstore_unref(img); } else { diff -r a53992a4437a -r 32a44f7e9c52 libpurple/protocols/bonjour/mdns_common.h --- a/libpurple/protocols/bonjour/mdns_common.h Wed Aug 08 01:57:39 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_common.h Thu Aug 09 02:30:03 2007 +0000 @@ -47,11 +47,6 @@ void bonjour_dns_sd_update_buddy_icon(BonjourDnsSd *data); /** - * The buddy icon blob has been set, notify everyone watching the TXT record - */ -void bonjour_dns_sd_buddy_icon_data_set(BonjourDnsSd *data); - -/** * Advertise our presence within the dns-sd daemon and start * browsing for other bonjour peers. */ diff -r a53992a4437a -r 32a44f7e9c52 libpurple/protocols/bonjour/mdns_howl.c --- a/libpurple/protocols/bonjour/mdns_howl.c Wed Aug 08 01:57:39 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_howl.c Thu Aug 09 02:30:03 2007 +0000 @@ -287,10 +287,10 @@ return FALSE; } -void _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { +gboolean _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { + return FALSE; } - void _mdns_stop(BonjourDnsSd *data) { HowlSessionImplData *idata = data->mdns_impl_data; @@ -315,7 +315,7 @@ void _mdns_delete_buddy(BonjourBuddy *buddy) { } -void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy) { +void _mdns_retrieve_retrieve_buddy_icon(BonjourBuddy* buddy) { } diff -r a53992a4437a -r 32a44f7e9c52 libpurple/protocols/bonjour/mdns_interface.h --- a/libpurple/protocols/bonjour/mdns_interface.h Wed Aug 08 01:57:39 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_interface.h Thu Aug 09 02:30:03 2007 +0000 @@ -28,13 +28,12 @@ void _mdns_stop(BonjourDnsSd *data); -void _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len); +gboolean _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len); void _mdns_init_buddy(BonjourBuddy *buddy); void _mdns_delete_buddy(BonjourBuddy *buddy); -/* This doesn't quite belong here, but there really isn't any shared functionality */ -void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy); +void _mdns_retrieve_retrieve_buddy_icon(BonjourBuddy* buddy); #endif diff -r a53992a4437a -r 32a44f7e9c52 libpurple/protocols/bonjour/mdns_win32.c --- a/libpurple/protocols/bonjour/mdns_win32.c Wed Aug 08 01:57:39 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Thu Aug 09 02:30:03 2007 +0000 @@ -37,14 +37,12 @@ /* data used by win32 bonjour implementation */ typedef struct _win32_session_impl_data { - DNSServiceRef advertisement_svc; + DNSServiceRef presence_svc; DNSServiceRef browser_svc; - DNSServiceRef buddy_icon_svc; DNSRecordRef buddy_icon_rec; - guint advertisement_handler; /* hack... windows bonjour is broken, so we have to have this */ + guint presence_handler; guint browser_handler; - guint buddy_icon_handler; } Win32SessionImplData; typedef struct _win32_buddy_impl_data { @@ -96,8 +94,7 @@ g_return_if_fail(idata != NULL); - purple_buddy_icons_set_for_user(buddy->account, buddy->name, - g_memdup(rdata, rdlen), rdlen, buddy->phsh); + bonjour_buddy_got_buddy_icon(buddy, rdata, rdlen); /* We've got what we need; stop listening */ purple_input_remove(idata->null_query_handler); @@ -126,14 +123,16 @@ /* finally, set up the continuous txt record watcher, and add the buddy to purple */ - if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->txt_query, 0, 0, args->full_service_name, - kDNSServiceType_TXT, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) { - int fd = DNSServiceRefSockFD(idata->txt_query); - idata->txt_query_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, idata->txt_query); + if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->txt_query, kDNSServiceFlagsLongLivedQuery, + kDNSServiceInterfaceIndexAny, args->full_service_name, kDNSServiceType_TXT, + kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) { + + purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", buddy->name, buddy->ip, buddy->port_p2pj); + + idata->txt_query_handler = purple_input_add(DNSServiceRefSockFD(idata->txt_query), + PURPLE_INPUT_READ, _mdns_handle_event, idata->txt_query); bonjour_buddy_add_to_purple(buddy); - - purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", buddy->name, buddy->ip, buddy->port_p2pj); } else bonjour_buddy_delete(buddy); @@ -190,7 +189,6 @@ _mdns_service_register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { - /* we don't actually care about anything said in this callback - this is only here because Bonjour for windows is broken */ /* TODO: deal with collision */ if (kDNSServiceErr_NoError != errorCode) purple_debug_error("bonjour", "service advertisement - callback error (%d).\n", errorCode); @@ -199,17 +197,6 @@ } static void DNSSD_API -_mdns_set_buddy_icon_cb(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, - void *context) { - if (kDNSServiceErr_NoError != errorCode) - purple_debug_error("bonjour", "Error (%d) registering buddy icon data.\n", errorCode); - else { - purple_debug_info("bonjour", "Registered buddy icon data.\n"); - bonjour_dns_sd_buddy_icon_data_set((BonjourDnsSd *) context); - } -} - -static void DNSSD_API _mdns_service_browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) { @@ -321,14 +308,15 @@ switch (type) { case PUBLISH_START: - purple_debug_info("bonjour", "Registering service on port %d\n", data->port_p2pj); - err = DNSServiceRegister(&idata->advertisement_svc, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, + purple_debug_info("bonjour", "Registering presence on port %d\n", data->port_p2pj); + err = DNSServiceRegister(&idata->presence_svc, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), _mdns_service_register_callback, NULL); break; case PUBLISH_UPDATE: - err = DNSServiceUpdateRecord(idata->advertisement_svc, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); + purple_debug_info("bonjour", "Updating presence.\n"); + err = DNSServiceUpdateRecord(idata->presence_svc, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); break; } @@ -336,9 +324,12 @@ purple_debug_error("bonjour", "Failed to publish presence service.\n"); ret = FALSE; } else if (type == PUBLISH_START) { - /* hack: Bonjour on windows is broken. We don't care about the callback but we have to listen anyway */ - idata->advertisement_handler = purple_input_add(DNSServiceRefSockFD(idata->advertisement_svc), - PURPLE_INPUT_READ, _mdns_handle_event, idata->advertisement_svc); + /* We need to do this because according to the Apple docs: + * "the client is responsible for ensuring that DNSServiceProcessResult() is called + * whenever there is a reply from the daemon - the daemon may terminate its connection + * with a client that does not process the daemon's responses */ + idata->presence_handler = purple_input_add(DNSServiceRefSockFD(idata->presence_svc), + PURPLE_INPUT_READ, _mdns_handle_event, idata->presence_svc); } } @@ -369,10 +360,9 @@ if (idata == NULL) return; - if (idata->advertisement_svc != NULL) { - /* hack: for win32, we need to stop listening to the advertisement pipe too */ - purple_input_remove(idata->advertisement_handler); - DNSServiceRefDeallocate(idata->advertisement_svc); + if (idata->presence_svc != NULL) { + purple_input_remove(idata->presence_handler); + DNSServiceRefDeallocate(idata->presence_svc); } if (idata->browser_svc != NULL) { @@ -380,68 +370,37 @@ DNSServiceRefDeallocate(idata->browser_svc); } - if (idata->buddy_icon_svc != NULL) { - purple_input_remove(idata->buddy_icon_handler); - DNSServiceRefDeallocate(idata->buddy_icon_svc); - } - - g_free(idata); data->mdns_impl_data = NULL; } -void _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { +gboolean _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { Win32SessionImplData *idata = data->mdns_impl_data; - gboolean new_svc = FALSE; DNSServiceErrorType err = kDNSServiceErr_NoError; - g_return_if_fail(idata != NULL); - - if (avatar_data != NULL && idata->buddy_icon_svc == NULL) { - gchar *svc_name = g_strdup_printf("%s." ICHAT_SERVICE "local", purple_account_get_username(data->account)); - - purple_debug_info("bonjour", "Setting new buddy icon.\n"); - - err = DNSServiceCreateConnection(&idata->buddy_icon_svc); - if (err == kDNSServiceErr_NoError) { - err = DNSServiceRegisterRecord(idata->buddy_icon_svc, - &idata->buddy_icon_rec, kDNSServiceFlagsShared, kDNSServiceInterfaceIndexAny, svc_name, - kDNSServiceType_NULL, kDNSServiceClass_IN, - avatar_len, avatar_data, 10, _mdns_set_buddy_icon_cb, data); + g_return_val_if_fail(idata != NULL, FALSE); - if (err != kDNSServiceErr_NoError) { - DNSServiceRefDeallocate(idata->buddy_icon_svc); - idata->buddy_icon_svc = NULL; - } - } - - g_free(svc_name); - - if (err == kDNSServiceErr_NoError) - idata->buddy_icon_handler = purple_input_add(DNSServiceRefSockFD(idata->buddy_icon_svc), - PURPLE_INPUT_READ, _mdns_handle_event, idata->buddy_icon_svc); - - new_svc = TRUE; + if (avatar_data != NULL && idata->buddy_icon_rec == NULL) { + purple_debug_info("bonjour", "Setting new buddy icon.\n"); + err = DNSServiceAddRecord(idata->presence_svc, &idata->buddy_icon_rec, + 0, kDNSServiceType_NULL, avatar_len, avatar_data, 0); } else if (avatar_data != NULL) { purple_debug_info("bonjour", "Updating existing buddy icon.\n"); - err = DNSServiceUpdateRecord(idata->buddy_icon_svc, idata->buddy_icon_rec, - 0, avatar_len, avatar_data, 10); - } else if (idata->buddy_icon_svc != NULL) { + err = DNSServiceUpdateRecord(idata->presence_svc, idata->buddy_icon_rec, + 0, avatar_len, avatar_data, 0); + } else if (idata->buddy_icon_rec != NULL) { purple_debug_info("bonjour", "Removing existing buddy icon.\n"); - /* Must be removing the buddy icon */ - purple_input_remove(idata->buddy_icon_handler); - idata->buddy_icon_handler = 0; - DNSServiceRefDeallocate(idata->buddy_icon_svc); - idata->buddy_icon_svc = NULL; + DNSServiceRemoveRecord(idata->presence_svc, idata->buddy_icon_rec, 0); idata->buddy_icon_rec = NULL; } if (err != kDNSServiceErr_NoError) purple_debug_error("bonjour", "Error (%d) setting buddy icon record.\n", err); + + return (err == kDNSServiceErr_NoError); } - void _mdns_init_buddy(BonjourBuddy *buddy) { buddy->mdns_impl_data = g_new0(Win32BuddyImplData, 1); } @@ -466,9 +425,9 @@ buddy->mdns_impl_data = NULL; } -void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy) { +void _mdns_retrieve_retrieve_buddy_icon(BonjourBuddy* buddy) { Win32BuddyImplData *idata = buddy->mdns_impl_data; - gchar *svc_name; + char svc_name[kDNSServiceMaxDomainName]; g_return_if_fail(idata != NULL); @@ -480,13 +439,12 @@ idata->null_query = NULL; } - svc_name = g_strdup_printf("%s." ICHAT_SERVICE "local", buddy->name); - if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->null_query, 0, 0, svc_name, + DNSServiceConstructFullName(svc_name, buddy->name, ICHAT_SERVICE, "local"); + if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->null_query, 0, kDNSServiceInterfaceIndexAny, svc_name, kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) { idata->null_query_handler = purple_input_add(DNSServiceRefSockFD(idata->null_query), PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query); } - g_free(svc_name); }