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);
 
 }