Mercurial > pidgin
changeset 18843:7bf6b9a70b41
Some more minor mdns implementation abstraction tweaks and implementation of setting buddy icons for the win32 bonjour implementation.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Wed, 08 Aug 2007 01:50:01 +0000 |
parents | 03a0054954bb |
children | a53992a4437a 09f52521ff5b |
files | libpurple/protocols/bonjour/bonjour.c libpurple/protocols/bonjour/buddy.c libpurple/protocols/bonjour/buddy.h libpurple/protocols/bonjour/mdns_avahi.c libpurple/protocols/bonjour/mdns_common.c libpurple/protocols/bonjour/mdns_common.h libpurple/protocols/bonjour/mdns_howl.c libpurple/protocols/bonjour/mdns_interface.h libpurple/protocols/bonjour/mdns_win32.c |
diffstat | 9 files changed, 222 insertions(+), 66 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/bonjour/bonjour.c Wed Aug 08 01:35:56 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.c Wed Aug 08 01:50:01 2007 +0000 @@ -138,6 +138,8 @@ return; } + bonjour_dns_sd_update_buddy_icon(bd->dns_sd_data); + /* Create a group for bonjour buddies */ bonjour_group = purple_group_new(BONJOUR_GROUP_NAME); purple_blist_add_group(bonjour_group, NULL); @@ -283,6 +285,14 @@ bb->conversation = NULL; } +static +void bonjour_set_buddy_icon(PurpleConnection *conn, PurpleStoredImage *img) +{ + BonjourData *bd = conn->proto_data; + bonjour_dns_sd_update_buddy_icon(bd->dns_sd_data); +} + + static char * bonjour_status_text(PurpleBuddy *buddy) { @@ -339,8 +349,7 @@ OPT_PROTO_NO_PASSWORD, NULL, /* user_splits */ NULL, /* protocol_options */ - /* {"png", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, */ /* icon_spec */ - NO_BUDDY_ICONS, /* not yet */ /* icon_spec */ + {"png,gif,jpeg", 0, 0, 96, 96, 65535, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ bonjour_list_icon, /* list_icon */ NULL, /* list_emblem */ bonjour_status_text, /* status_text */ @@ -384,7 +393,7 @@ NULL, /* buddy_free */ bonjour_convo_closed, /* convo_closed */ NULL, /* normalize */ - NULL, /* set_buddy_icon */ + bonjour_set_buddy_icon, /* set_buddy_icon */ NULL, /* remove_group */ NULL, /* get_cb_real_name */ NULL, /* set_chat_topic */ @@ -533,7 +542,7 @@ { default_firstname = g_strndup(fullname, splitpoint - fullname); tmp = &splitpoint[1]; - + /* The last name may be followed by a comma and additional data. * Only use the last name itself. */
--- a/libpurple/protocols/bonjour/buddy.c Wed Aug 08 01:35:56 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.c Wed Aug 08 01:50:01 2007 +0000 @@ -179,8 +179,6 @@ { g_free(buddy->name); g_free(buddy->ip); - g_free(buddy->full_service_name); - g_free(buddy->first); g_free(buddy->phsh); g_free(buddy->status);
--- a/libpurple/protocols/bonjour/buddy.h Wed Aug 08 01:35:56 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.h Wed Aug 08 01:50:01 2007 +0000 @@ -29,7 +29,6 @@ gchar *name; /* TODO: Remove and just use the hostname */ gchar *ip; - gchar *full_service_name; gint port_p2pj; gchar *first;
--- a/libpurple/protocols/bonjour/mdns_avahi.c Wed Aug 08 01:35:56 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_avahi.c Wed Aug 08 01:50:01 2007 +0000 @@ -317,11 +317,10 @@ return TRUE; } -/* This is done differently than with Howl/Apple Bonjour */ -guint _mdns_register_to_mainloop(BonjourDnsSd *data) { - return 0; +void _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { } + void _mdns_stop(BonjourDnsSd *data) { AvahiSessionImplData *idata = data->mdns_impl_data;
--- a/libpurple/protocols/bonjour/mdns_common.c Wed Aug 08 01:35:56 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_common.c Wed Aug 08 01:50:01 2007 +0000 @@ -17,11 +17,13 @@ #include <string.h> #include "internal.h" +#include "cipher.h" +#include "debug.h" + #include "mdns_common.h" #include "mdns_interface.h" #include "bonjour.h" #include "buddy.h" -#include "debug.h" /** @@ -54,8 +56,7 @@ * Send a new dns-sd packet updating our status. */ void -bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message) -{ +bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message) { g_free(data->status); g_free(data->msg); @@ -66,6 +67,70 @@ _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); +} + +void +bonjour_dns_sd_update_buddy_icon(BonjourDnsSd *data) { + PurpleStoredImage *img; + + if ((img = purple_buddy_icons_find_account_icon(data->account))) { + gconstpointer avatar_data; + gsize avatar_len; + + avatar_data = purple_imgstore_get_data(img); + avatar_len = purple_imgstore_get_size(img); + + _mdns_set_buddy_icon_data(data, avatar_data, avatar_len); + + purple_imgstore_unref(img); + } else { + /* We need to do this regardless of whether data->phsh is set so that we + * cancel any icons that are currently in the process of being set */ + _mdns_set_buddy_icon_data(data, NULL, 0); + if (data->phsh != NULL) { + /* Clear the buddy icon */ + g_free(data->phsh); + data->phsh = NULL; + /* Update our TXT record */ + _mdns_publish(data, PUBLISH_UPDATE); + } + } +} + /** * Advertise our presence within the dns-sd daemon and start browsing * for other bonjour peers. @@ -91,11 +156,6 @@ return FALSE; } - - /* Get the socket that communicates with the mDNS daemon and bind it to a */ - /* callback that will handle the dns_sd packets */ - gc->inpa = _mdns_register_to_mainloop(data); - return TRUE; } @@ -104,13 +164,6 @@ */ void -bonjour_dns_sd_stop(BonjourDnsSd *data) -{ - PurpleConnection *gc; - +bonjour_dns_sd_stop(BonjourDnsSd *data) { _mdns_stop(data); - - gc = purple_account_get_connection(data->account); - if (gc->inpa > 0) - purple_input_remove(gc->inpa); }
--- a/libpurple/protocols/bonjour/mdns_common.h Wed Aug 08 01:35:56 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_common.h Wed Aug 08 01:50:01 2007 +0000 @@ -42,6 +42,16 @@ void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy); /** + * Deal with a buddy icon update + */ +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. */
--- a/libpurple/protocols/bonjour/mdns_howl.c Wed Aug 08 01:35:56 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_howl.c Wed Aug 08 01:50:01 2007 +0000 @@ -26,6 +26,7 @@ typedef struct _howl_impl_data { sw_discovery session; sw_discovery_oid session_id; + guint session_handler; } HowlSessionImplData; static sw_result HOWL_API @@ -276,18 +277,19 @@ g_return_val_if_fail(idata != NULL, FALSE); - return (sw_discovery_browse(idata->session, 0, ICHAT_SERVICE, NULL, _browser_reply, - data->account, &session_id) == SW_OKAY); + if (sw_discovery_browse(idata->session, 0, ICHAT_SERVICE, NULL, _browser_reply, + data->account, &session_id) == SW_OKAY) { + idata->session_handler = purple_input_add(sw_discovery_socket(idata->session), + PURPLE_INPUT_READ, _mdns_handle_event, idata->session); + return TRUE; + } + + return FALSE; } -guint _mdns_register_to_mainloop(BonjourDnsSd *data) { - HowlSessionImplData *idata = data->mdns_impl_data; +void _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { +} - g_return_val_if_fail(idata != NULL, 0); - - return purple_input_add(sw_discovery_socket(idata->session), - PURPLE_INPUT_READ, _mdns_handle_event, idata->session); -} void _mdns_stop(BonjourDnsSd *data) { HowlSessionImplData *idata = data->mdns_impl_data; @@ -297,6 +299,8 @@ sw_discovery_cancel(idata->session, idata->session_id); + purple_input_remove(idata->session_handler); + /* TODO: should this really be g_free()'d ??? */ g_free(idata->session); @@ -313,3 +317,5 @@ void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy) { } + +
--- a/libpurple/protocols/bonjour/mdns_interface.h Wed Aug 08 01:35:56 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_interface.h Wed Aug 08 01:50:01 2007 +0000 @@ -26,9 +26,9 @@ gboolean _mdns_browse(BonjourDnsSd *data); -guint _mdns_register_to_mainloop(BonjourDnsSd *data); +void _mdns_stop(BonjourDnsSd *data); -void _mdns_stop(BonjourDnsSd *data); +void _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len); void _mdns_init_buddy(BonjourBuddy *buddy);
--- a/libpurple/protocols/bonjour/mdns_win32.c Wed Aug 08 01:35:56 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Wed Aug 08 01:50:01 2007 +0000 @@ -21,12 +21,14 @@ #include "mdns_interface.h" #include "dns_sd_proxy.h" #include "dnsquery.h" +#include "mdns_common.h" /* data structure for the resolve callback */ typedef struct _ResolveCallbackArgs { DNSServiceRef resolver; guint resolver_handler; + gchar *full_service_name; PurpleDnsQueryData *query; @@ -35,10 +37,14 @@ /* data used by win32 bonjour implementation */ typedef struct _win32_session_impl_data { - DNSServiceRef advertisement; - DNSServiceRef browser; + DNSServiceRef advertisement_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 browser_handler; + guint buddy_icon_handler; } Win32SessionImplData; typedef struct _win32_buddy_impl_data { @@ -120,7 +126,7 @@ /* finally, set up the continuous txt record watcher, and add the buddy to purple */ - if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->txt_query, 0, 0, buddy->full_service_name, + 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); @@ -138,6 +144,7 @@ /* free the remaining args memory */ purple_dnsquery_destroy(args->query); + g_free(args->full_service_name); g_free(args); } @@ -165,13 +172,14 @@ _mdns_parse_text_record(args->buddy, txtRecord, txtLen); /* set more arguments, and start the host resolver */ - args->buddy->full_service_name = g_strdup(fullname); + args->full_service_name = g_strdup(fullname); if (!(args->query = purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args))) { purple_debug_error("bonjour", "service resolver - host resolution failed.\n"); bonjour_buddy_delete(args->buddy); + g_free(args->full_service_name); g_free(args); } } @@ -180,16 +188,28 @@ static void DNSSD_API _mdns_service_register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, - const char *name, const char *regtype, const char *domain, void *context) -{ + 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.\n"); + purple_debug_error("bonjour", "service advertisement - callback error (%d).\n", errorCode); else purple_debug_info("bonjour", "service advertisement - callback.\n"); } 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) { @@ -302,13 +322,13 @@ switch (type) { case PUBLISH_START: purple_debug_info("bonjour", "Registering service on port %d\n", data->port_p2pj); - err = DNSServiceRegister(&idata->advertisement, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, + err = DNSServiceRegister(&idata->advertisement_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, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); + err = DNSServiceUpdateRecord(idata->advertisement_svc, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); break; } @@ -317,8 +337,8 @@ 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 */ - gint fd = DNSServiceRefSockFD(idata->advertisement); - idata->advertisement_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, idata->advertisement); + idata->advertisement_handler = purple_input_add(DNSServiceRefSockFD(idata->advertisement_svc), + PURPLE_INPUT_READ, _mdns_handle_event, idata->advertisement_svc); } } @@ -332,37 +352,96 @@ g_return_val_if_fail(idata != NULL, FALSE); - return (DNSServiceBrowse(&idata->browser, 0, 0, ICHAT_SERVICE, NULL, + if (DNSServiceBrowse(&idata->browser_svc, 0, 0, ICHAT_SERVICE, NULL, _mdns_service_browse_callback, data->account) - == kDNSServiceErr_NoError); -} + == kDNSServiceErr_NoError) { + idata->browser_handler = purple_input_add(DNSServiceRefSockFD(idata->browser_svc), + PURPLE_INPUT_READ, _mdns_handle_event, idata->browser_svc); + return TRUE; + } -guint _mdns_register_to_mainloop(BonjourDnsSd *data) { - Win32SessionImplData *idata = data->mdns_impl_data; - - g_return_val_if_fail(idata != NULL, 0); - - return purple_input_add(DNSServiceRefSockFD(idata->browser), - PURPLE_INPUT_READ, _mdns_handle_event, idata->browser); + return FALSE; } void _mdns_stop(BonjourDnsSd *data) { Win32SessionImplData *idata = data->mdns_impl_data; - if (idata == NULL || idata->advertisement == NULL || idata->browser == NULL) + if (idata == NULL) return; - /* hack: for win32, we need to stop listening to the advertisement pipe too */ - purple_input_remove(idata->advertisement_handler); + 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); + } - DNSServiceRefDeallocate(idata->advertisement); - DNSServiceRefDeallocate(idata->browser); + if (idata->browser_svc != NULL) { + purple_input_remove(idata->browser_handler); + 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) { + 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); + + 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; + } 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) { + 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; + idata->buddy_icon_rec = NULL; + } + + if (err != kDNSServiceErr_NoError) + purple_debug_error("bonjour", "Error (%d) setting buddy icon record.\n", err); +} + + void _mdns_init_buddy(BonjourBuddy *buddy) { buddy->mdns_impl_data = g_new0(Win32BuddyImplData, 1); } @@ -389,6 +468,7 @@ void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy) { Win32BuddyImplData *idata = buddy->mdns_impl_data; + gchar *svc_name; g_return_if_fail(idata != NULL); @@ -400,11 +480,13 @@ idata->null_query = NULL; } - if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->null_query, 0, 0, buddy->full_service_name, + svc_name = g_strdup_printf("%s." ICHAT_SERVICE "local", buddy->name); + if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->null_query, 0, 0, svc_name, kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) { - int fd = DNSServiceRefSockFD(idata->null_query); - idata->null_query_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query); + idata->null_query_handler = purple_input_add(DNSServiceRefSockFD(idata->null_query), + PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query); } + g_free(svc_name); }