Mercurial > pidgin
diff libpurple/protocols/bonjour/mdns_win32.c @ 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 | b839f427cbb2 |
children | 09f52521ff5b |
line wrap: on
line diff
--- 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); }