changeset 18798:ed1def07d86e

Refactor the bonjour mdns implementation abstraction in preparation for the avahi implementation. Also fix alias assignment from the server to populate the server alias instead of the local alias.
author Daniel Atallah <daniel.atallah@gmail.com>
date Sun, 05 Aug 2007 02:44:53 +0000
parents 95fe5195bf98
children 83719d57a8ee
files libpurple/protocols/bonjour/Makefile.am libpurple/protocols/bonjour/buddy.c libpurple/protocols/bonjour/buddy.h libpurple/protocols/bonjour/mdns_common.c libpurple/protocols/bonjour/mdns_common.h libpurple/protocols/bonjour/mdns_howl.c libpurple/protocols/bonjour/mdns_howl.h libpurple/protocols/bonjour/mdns_interface.h libpurple/protocols/bonjour/mdns_types.h libpurple/protocols/bonjour/mdns_win32.c libpurple/protocols/bonjour/mdns_win32.h
diffstat 11 files changed, 305 insertions(+), 308 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/bonjour/Makefile.am	Fri Aug 03 23:20:28 2007 +0000
+++ b/libpurple/protocols/bonjour/Makefile.am	Sun Aug 05 02:44:53 2007 +0000
@@ -1,6 +1,5 @@
 EXTRA_DIST = \
 		mdns_win32.c \
-		mdns_win32.h \
 		Makefile.mingw
 
 pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION)
@@ -16,7 +15,7 @@
 	mdns_common.c \
 	mdns_common.h \
 	mdns_howl.c \
-	mdns_howl.h \
+	mdns_interface.h \
 	mdns_types.h \
 	parser.c \
 	parser.h
--- a/libpurple/protocols/bonjour/buddy.c	Fri Aug 03 23:20:28 2007 +0000
+++ b/libpurple/protocols/bonjour/buddy.c	Sun Aug 05 02:44:53 2007 +0000
@@ -22,6 +22,7 @@
 #include "account.h"
 #include "blist.h"
 #include "bonjour.h"
+#include "mdns_interface.h"
 #include "debug.h"
 
 /**
@@ -35,6 +36,8 @@
 	buddy->account = account;
 	buddy->name = g_strdup(name);
 
+	_mdns_init_buddy(buddy);
+
 	return buddy;
 }
 
@@ -102,8 +105,9 @@
 {
 	PurpleBuddy *buddy;
 	PurpleGroup *group;
-	const char *status_id, *first, *last;
-	gchar *alias;
+	PurpleAccount *account = bonjour_buddy->account;
+	const char *status_id, *first, *last, *old_hash, *new_hash;
+	gchar *alias = NULL;
 
 	/* Translate between the Bonjour status and the Purple status */
 	if (g_ascii_strcasecmp("dnd", bonjour_buddy->status) == 0)
@@ -116,44 +120,42 @@
 	 * field from the DNS SD.
 	 */
 
-	/* Create the alias for the buddy using the first and the last name */
-	first = bonjour_buddy->first;
-	last = bonjour_buddy->last;
-	alias = g_strdup_printf("%s%s%s",
-							(first && *first ? first : ""),
-							(first && *first && last && *last ? " " : ""),
-							(last && *last ? last : ""));
-
 	/* Make sure the Bonjour group exists in our buddy list */
 	group = purple_find_group(BONJOUR_GROUP_NAME); /* Use the buddy's domain, instead? */
-	if (group == NULL)
-	{
+	if (group == NULL) {
 		group = purple_group_new(BONJOUR_GROUP_NAME);
 		purple_blist_add_group(group, NULL);
 	}
 
 	/* Make sure the buddy exists in our buddy list */
-	buddy = purple_find_buddy(bonjour_buddy->account, bonjour_buddy->name);
+	buddy = purple_find_buddy(account, bonjour_buddy->name);
 
-	if (buddy == NULL)
-	{
-		buddy = purple_buddy_new(bonjour_buddy->account, bonjour_buddy->name, alias);
+	if (buddy == NULL) {
+		buddy = purple_buddy_new(account, bonjour_buddy->name, NULL);
 		buddy->proto_data = bonjour_buddy;
 		purple_blist_node_set_flags((PurpleBlistNode *)buddy, PURPLE_BLIST_NODE_FLAG_NO_SAVE);
 		purple_blist_add_buddy(buddy, NULL, group, NULL);
 	}
 
+	/* 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);
+
 	/* Set the user's status */
 	if (bonjour_buddy->msg != NULL)
-		purple_prpl_got_user_status(bonjour_buddy->account, buddy->name, status_id,
-								  "message", bonjour_buddy->msg,
-								  NULL);
+		purple_prpl_got_user_status(account, buddy->name, status_id,
+					    "message", bonjour_buddy->msg, NULL);
 	else
-		purple_prpl_got_user_status(bonjour_buddy->account, buddy->name, status_id,
-								  NULL);
-	purple_prpl_got_user_idle(bonjour_buddy->account, buddy->name, FALSE, 0);
+		purple_prpl_got_user_status(account, buddy->name, status_id, NULL);
 
-	g_free(alias);
+	purple_prpl_got_user_idle(account, buddy->name, FALSE, 0);
 }
 
 /**
@@ -182,13 +184,8 @@
 	bonjour_jabber_close_conversation(buddy->conversation);
 	buddy->conversation = NULL;
 
-#ifdef USE_BONJOUR_APPLE
-	if (buddy->txt_query != NULL)
-	{
-		purple_input_remove(buddy->txt_query_fd);
-		DNSServiceRefDeallocate(buddy->txt_query);
-	}
-#endif
+	/* Clean up any mdns implementation data */
+	_mdns_delete_buddy(buddy);
 
 	g_free(buddy);
 }
--- a/libpurple/protocols/bonjour/buddy.h	Fri Aug 03 23:20:28 2007 +0000
+++ b/libpurple/protocols/bonjour/buddy.h	Sun Aug 05 02:44:53 2007 +0000
@@ -19,16 +19,9 @@
 
 #include <glib.h>
 
-#include "config.h"
 #include "account.h"
 #include "jabber.h"
 
-#ifdef USE_BONJOUR_APPLE 
-#include "dns_sd_proxy.h"
-#else /* USE_BONJOUR_HOWL */
-#include <howl.h>
-#endif
-
 typedef struct _BonjourBuddy
 {
 	PurpleAccount *account;
@@ -53,11 +46,7 @@
 
 	BonjourJabberConversation *conversation;
 
-#ifdef USE_BONJOUR_APPLE
-	DNSServiceRef txt_query;
-	int txt_query_fd;
-#endif
-
+	gpointer mdns_impl_data;
 } BonjourBuddy;
 
 static const char *const buddy_TXT_records[] = {
--- a/libpurple/protocols/bonjour/mdns_common.c	Fri Aug 03 23:20:28 2007 +0000
+++ b/libpurple/protocols/bonjour/mdns_common.c	Sun Aug 05 02:44:53 2007 +0000
@@ -17,8 +17,8 @@
 #include <string.h>
 
 #include "internal.h"
-#include "config.h"
 #include "mdns_common.h"
+#include "mdns_interface.h"
 #include "bonjour.h"
 #include "buddy.h"
 #include "debug.h"
@@ -73,65 +73,28 @@
 gboolean
 bonjour_dns_sd_start(BonjourDnsSd *data)
 {
-	PurpleAccount *account;
 	PurpleConnection *gc;
-	gint dns_sd_socket;
-	gpointer opaque_data;
 
-#ifdef USE_BONJOUR_HOWL
-	sw_discovery_oid session_id;
-#endif
-
-	account = data->account;
-	gc = purple_account_get_connection(account);
+	gc = purple_account_get_connection(data->account);
 
 	/* Initialize the dns-sd data and session */
-#ifndef USE_BONJOUR_APPLE
-	if (sw_discovery_init(&data->session) != SW_OKAY)
-	{
-		purple_debug_error("bonjour", "Unable to initialize an mDNS session.\n");
-
-		/* In Avahi, sw_discovery_init frees data->session but doesn't clear it */
-		data->session = NULL;
-
+	if (!_mdns_init_session(data))
 		return FALSE;
-	}
-#endif
 
 	/* Publish our bonjour IM client at the mDNS daemon */
-
-	if (0 != _mdns_publish(data, PUBLISH_START))
-	{
+	if (!_mdns_publish(data, PUBLISH_START))
 		return FALSE;
-	}
 
 	/* Advise the daemon that we are waiting for connections */
-	
-#ifdef USE_BONJOUR_APPLE
-	if (DNSServiceBrowse(&data->browser, 0, 0, ICHAT_SERVICE, NULL, _mdns_service_browse_callback, account) 
-			!= kDNSServiceErr_NoError)
-#else /* USE_BONJOUR_HOWL */
-	if (sw_discovery_browse(data->session, 0, ICHAT_SERVICE, NULL, _browser_reply,
-			account, &session_id) != SW_OKAY)
-#endif
-	{
+	if (!_mdns_browse(data)) {
 		purple_debug_error("bonjour", "Unable to get service.");
 		return FALSE;
 	}
 
+
 	/* Get the socket that communicates with the mDNS daemon and bind it to a */
 	/* callback that will handle the dns_sd packets */
-
-#ifdef USE_BONJOUR_APPLE
-	dns_sd_socket = DNSServiceRefSockFD(data->browser);
-	opaque_data = data->browser;
-#else /* USE_BONJOUR_HOWL */
-	dns_sd_socket = sw_discovery_socket(data->session);
-	opaque_data = data->session;
-#endif
-
-	gc->inpa = purple_input_add(dns_sd_socket, PURPLE_INPUT_READ,
-				    _mdns_handle_event, opaque_data);
+	gc->inpa = _mdns_register_to_mainloop(data);
 
 	return TRUE;
 }
@@ -143,34 +106,10 @@
 void
 bonjour_dns_sd_stop(BonjourDnsSd *data)
 {
-	PurpleAccount *account;
 	PurpleConnection *gc;
 
-#ifdef USE_BONJOUR_APPLE
-	if (data->advertisement == NULL || data->browser == NULL)
-#else /* USE_BONJOUR_HOWL */
-	if (data->session == NULL)
-#endif
-		return;
+	_mdns_stop(data);
 
-#ifdef USE_BONJOUR_HOWL
-	sw_discovery_cancel(data->session, data->session_id);
-#endif
-
-	account = data->account;
-	gc = purple_account_get_connection(account);
+	gc = purple_account_get_connection(data->account);
 	purple_input_remove(gc->inpa);
-
-#ifdef USE_BONJOUR_APPLE
-	/* hack: for win32, we need to stop listening to the advertisement pipe too */
-	purple_input_remove(data->advertisement_handler);
-
-	DNSServiceRefDeallocate(data->advertisement);
-	DNSServiceRefDeallocate(data->browser);
-	data->advertisement = NULL;
-	data->browser = NULL;
-#else /* USE_BONJOUR_HOWL */
-	g_free(data->session);
-	data->session = NULL;
-#endif
 }
--- a/libpurple/protocols/bonjour/mdns_common.h	Fri Aug 03 23:20:28 2007 +0000
+++ b/libpurple/protocols/bonjour/mdns_common.h	Sun Aug 05 02:44:53 2007 +0000
@@ -19,11 +19,7 @@
 
 #include "mdns_types.h"
 
-#ifdef USE_BONJOUR_APPLE
-#include "mdns_win32.h"
-#elif defined USE_BONJOUR_HOWL
-#include "mdns_howl.h"
-#endif
+#include "buddy.h"
 
 /**
  * Allocate space for the dns-sd data.
--- a/libpurple/protocols/bonjour/mdns_howl.c	Fri Aug 03 23:20:28 2007 +0000
+++ b/libpurple/protocols/bonjour/mdns_howl.c	Sun Aug 05 02:44:53 2007 +0000
@@ -15,12 +15,20 @@
  */
 
 #include "internal.h"
-#include "mdns_howl.h"
 
+#include "mdns_interface.h"
 #include "debug.h"
 #include "buddy.h"
 
-sw_result HOWL_API
+#include <howl.h>
+
+/* data used by howl bonjour implementation */
+typedef struct _howl_impl_data {
+	sw_discovery session;
+	sw_discovery_oid session_id;
+} HowlSessionImplData;
+
+static sw_result HOWL_API
 _publish_reply(sw_discovery discovery, sw_discovery_oid oid,
 			   sw_discovery_publish_status status, sw_opaque extra)
 {
@@ -46,7 +54,7 @@
 	return SW_OKAY;
 }
 
-sw_result HOWL_API
+static sw_result HOWL_API
 _resolve_reply(sw_discovery discovery, sw_discovery_oid oid,
 			   sw_uint32 interface_index, sw_const_string name,
 			   sw_const_string type, sw_const_string domain,
@@ -95,7 +103,7 @@
 	return SW_OKAY;
 }
 
-sw_result HOWL_API
+static sw_result HOWL_API
 _browser_reply(sw_discovery discovery, sw_discovery_oid oid,
 			   sw_discovery_browse_status status,
 			   sw_uint32 interface_index, sw_const_string name,
@@ -154,19 +162,49 @@
 	return SW_OKAY;
 }
 
-int
-_mdns_publish(BonjourDnsSd *data, PublishType type)
+static void
+_mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition)
 {
+	sw_discovery_read_socket((sw_discovery)data);
+}
+
+/****************************
+ * mdns_interface functions *
+ ****************************/
+
+gboolean _mdns_init_session(BonjourDnsSd *data) {
+	HowlSessionImplData *idata = g_new0(HowlSessionImplData, 1);
+
+	if (sw_discovery_init(&idata->session) != SW_OKAY) {
+		purple_debug_error("bonjour", "Unable to initialize an mDNS session.\n");
+
+		/* In Avahi, sw_discovery_init frees data->session but doesn't clear it */
+		idata->session = NULL;
+
+		g_free(idata);
+
+		return FALSE;
+	}
+
+	data->mdns_impl_data = idata;
+
+	return TRUE;
+}
+
+
+gboolean _mdns_publish(BonjourDnsSd *data, PublishType type) {
 	sw_text_record dns_data;
 	sw_result publish_result = SW_OKAY;
 	char portstring[6];
 	const char *jid, *aim, *email;
+	HowlSessionImplData *idata = data->mdns_impl_data;
+
+	g_return_val_if_fail(idata != NULL, FALSE);
 
 	/* Fill the data for the service */
-	if (sw_text_record_init(&dns_data) != SW_OKAY)
-	{
+	if (sw_text_record_init(&dns_data) != SW_OKAY) {
 		purple_debug_error("bonjour", "Unable to initialize the data for the mDNS.\n");
-		return -1;
+		return FALSE;
 	}
 
 	/* Convert the port to a string */
@@ -208,32 +246,69 @@
 	/* TODO: ext, nick, node */
 
 	/* Publish the service */
-	switch (type)
-	{
+	switch (type) {
 		case PUBLISH_START:
-			publish_result = sw_discovery_publish(data->session, 0, purple_account_get_username(data->account), ICHAT_SERVICE, NULL,
+			publish_result = sw_discovery_publish(idata->session, 0, purple_account_get_username(data->account), ICHAT_SERVICE, NULL,
 								NULL, data->port_p2pj, sw_text_record_bytes(dns_data), sw_text_record_len(dns_data),
-								_publish_reply, NULL, &data->session_id);
+								_publish_reply, NULL, &idata->session_id);
 			break;
 		case PUBLISH_UPDATE:
-			publish_result = sw_discovery_publish_update(data->session, data->session_id,
+			publish_result = sw_discovery_publish_update(idata->session, idata->session_id,
 								sw_text_record_bytes(dns_data), sw_text_record_len(dns_data));
 			break;
 	}
-	if (publish_result != SW_OKAY)
-	{
+
+	if (publish_result != SW_OKAY) {
 		purple_debug_error("bonjour", "Unable to publish or change the status of the _presence._tcp service.\n");
-		return -1;
+		return FALSE;
 	}
 
 	/* Free the memory used by temp data */
 	sw_text_record_fina(dns_data);
 
-	return 0;
+	return TRUE;
+}
+
+gboolean _mdns_browse(BonjourDnsSd *data) {
+	HowlSessionImplData *idata = data->mdns_impl_data;
+
+	g_return_val_if_fail(idata != NULL, FALSE);
+
+	/* TODO: don't we need to hang onto this to cancel later? */
+	sw_discovery_oid session_id;
+
+	return (sw_discovery_browse(idata->session, 0, ICHAT_SERVICE, NULL, _browser_reply,
+				    data->account, &session_id) == SW_OKAY);
 }
 
-void
-_mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition)
-{
-	sw_discovery_read_socket((sw_discovery)data);
+guint _mdns_register_to_mainloop(BonjourDnsSd *data) {
+	HowlSessionImplData *idata = data->mdns_impl_data;
+
+	g_return_val_if_fail(idata != NULL, FALSE);
+
+	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;
+
+	if (idata == NULL || idata->session == NULL)
+		return;
+
+	sw_discovery_cancel(idata->session, idata->session_id);
+
+	/* TODO: should this really be g_free()'d ??? */
+	g_free(idata->session);
+
+	g_free(idata);
+
+	data->mdns_impl_data = NULL;
+}
+
+void _mdns_init_buddy(BonjourBuddy *buddy) {
+}
+
+void _mdns_delete_buddy(BonjourBuddy *buddy) {
+}
+
--- a/libpurple/protocols/bonjour/mdns_howl.h	Fri Aug 03 23:20:28 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _BONJOUR_MDNS_HOWL
-#define _BONJOUR_MDNS_HOWL
-
-#include "config.h"
-
-#ifdef USE_BONJOUR_HOWL
-
-#include <howl.h>
-#include <glib.h>
-#include "mdns_types.h"
-
-/* callback functions */
-
-sw_result HOWL_API _publish_reply(sw_discovery discovery, sw_discovery_oid oid, sw_discovery_publish_status status, sw_opaque extra);
-
-sw_result HOWL_API _resolve_reply(sw_discovery discovery, sw_discovery_oid oid, sw_uint32 interface_index, sw_const_string name,
-	sw_const_string type, sw_const_string domain, sw_ipv4_address address, sw_port port, sw_octets text_record, 
-	sw_ulong text_record_len, sw_opaque extra);
-
-sw_result HOWL_API _browser_reply(sw_discovery discovery, sw_discovery_oid oid, sw_discovery_browse_status status,
-	sw_uint32 interface_index, sw_const_string name, sw_const_string type, sw_const_string domain, sw_opaque_t extra);
-
-
-/* interface functions */
-
-int _mdns_publish(BonjourDnsSd *data, PublishType type);
-void _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition);
-
-#endif
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/bonjour/mdns_interface.h	Sun Aug 05 02:44:53 2007 +0000
@@ -0,0 +1,39 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BONJOUR_MDNS_INTERFACE
+#define _BONJOUR_MDNS_INTERFACE
+
+#include "mdns_types.h"
+
+gboolean _mdns_init_session(BonjourDnsSd *data);
+
+gboolean _mdns_publish(BonjourDnsSd *data, PublishType type);
+
+gboolean _mdns_browse(BonjourDnsSd *data);
+
+guint _mdns_register_to_mainloop(BonjourDnsSd *data);
+
+void _mdns_stop(BonjourDnsSd *data);
+
+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);
+
+#endif
--- a/libpurple/protocols/bonjour/mdns_types.h	Fri Aug 03 23:20:28 2007 +0000
+++ b/libpurple/protocols/bonjour/mdns_types.h	Sun Aug 05 02:44:53 2007 +0000
@@ -19,31 +19,14 @@
 
 #include <glib.h>
 #include "account.h"
-#include "config.h"
-
-#ifdef USE_BONJOUR_APPLE
-#include "dns_sd_proxy.h"
-#else /* USE_BONJOUR_HOWL */
-#include <howl.h>
-#endif
 
 #define ICHAT_SERVICE "_presence._tcp."
 
 /**
  * Data to be used by the dns-sd connection.
  */
-typedef struct _BonjourDnsSd
-{
-#ifdef USE_BONJOUR_APPLE
-	DNSServiceRef advertisement;
-	DNSServiceRef browser;
-
-	int advertisement_handler; /* hack... windows bonjour is broken, so we have to have this */
-#else /* USE_BONJOUR_HOWL */
-	sw_discovery session;
-	sw_discovery_oid session_id;
-#endif
-
+typedef struct _BonjourDnsSd {
+	gpointer mdns_impl_data;
 	PurpleAccount *account;
 	gchar *first;
 	gchar *last;
@@ -59,5 +42,4 @@
 	PUBLISH_UPDATE
 } PublishType;
 
-
 #endif
--- a/libpurple/protocols/bonjour/mdns_win32.c	Fri Aug 03 23:20:28 2007 +0000
+++ b/libpurple/protocols/bonjour/mdns_win32.c	Sun Aug 05 02:44:53 2007 +0000
@@ -15,15 +15,18 @@
  */
 
 #include "internal.h"
-#include "mdns_win32.h"
+#include "debug.h"
 
-#include "debug.h"
+#include "buddy.h"
+#include "mdns_interface.h"
+#include "dns_sd_proxy.h"
+#include "dnsquery.h"
+
 
 /* data structure for the resolve callback */
-typedef struct _ResolveCallbackArgs
-{
+typedef struct _ResolveCallbackArgs {
 	DNSServiceRef resolver;
-	int resolver_fd;
+	guint resolver_handler;
 
 	PurpleDnsQueryData *query;
 	gchar *fqn;
@@ -31,6 +34,24 @@
 	BonjourBuddy* buddy;
 } ResolveCallbackArgs;
 
+/* data used by win32 bonjour implementation */
+typedef struct _win32_session_impl_data {
+	DNSServiceRef advertisement;
+	DNSServiceRef browser;
+
+	guint advertisement_handler; /* hack... windows bonjour is broken, so we have to have this */
+} Win32SessionImplData;
+
+typedef struct _win32_buddy_impl_data {
+	DNSServiceRef txt_query;
+	guint txt_query_handler;
+} Win32BuddyImplData;
+
+static void
+_mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) {
+	DNSServiceProcessResult((DNSServiceRef) data);
+}
+
 static void
 _mdns_parse_text_record(BonjourBuddy* buddy, const char* record, uint16_t record_len)
 {
@@ -51,11 +72,13 @@
 	uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata,
 	uint32_t ttl, void *context)
 {
+
 	if (kDNSServiceErr_NoError != errorCode)
-		purple_debug_error("bonjour", "text record query - callback error.\n");
+		purple_debug_error("bonjour", "record query - callback error.\n");
 	else if (flags & kDNSServiceFlagsAdd)
 	{
-		BonjourBuddy *buddy = (BonjourBuddy*)context;
+		/* New Buddy */
+		BonjourBuddy *buddy = (BonjourBuddy*) context;
 		_mdns_parse_text_record(buddy, rdata, rdlen);
 		bonjour_buddy_add_to_purple(buddy);
 	}
@@ -68,26 +91,26 @@
 
 	if (!hosts || !hosts->data)
 		purple_debug_error("bonjour", "host resolution - callback error.\n");
-	else
-	{
+	else {
 		struct sockaddr_in *addr = (struct sockaddr_in*)g_slist_nth_data(hosts, 1);
 		BonjourBuddy* buddy = args->buddy;
+		Win32BuddyImplData *idata = buddy->mdns_impl_data;
+
+		g_return_if_fail(idata != NULL);
 
 		buddy->ip = g_strdup(inet_ntoa(addr->sin_addr));
 
 		/* finally, set up the continuous txt record watcher, and add the buddy to purple */
 
-		if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&buddy->txt_query, 0, 0, args->fqn,
-				kDNSServiceType_TXT, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy))
-		{
-			gint fd = DNSServiceRefSockFD(buddy->txt_query);
-			buddy->txt_query_fd = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, buddy->txt_query);
+		if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->txt_query, 0, 0, buddy->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);
 
 			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
+		} else
 			bonjour_buddy_delete(buddy);
 
 	}
@@ -108,7 +131,7 @@
 	ResolveCallbackArgs *args = (ResolveCallbackArgs*)context;
 
 	/* remove the input fd and destroy the service ref */
-	purple_input_remove(args->resolver_fd);
+	purple_input_remove(args->resolver_handler);
 	DNSServiceRefDeallocate(args->resolver);
 
 	if (kDNSServiceErr_NoError != errorCode)
@@ -150,7 +173,7 @@
 		purple_debug_info("bonjour", "service advertisement - callback.\n");
 }
 
-void DNSSD_API
+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)
 {
@@ -159,50 +182,52 @@
 
 	if (kDNSServiceErr_NoError != errorCode)
 		purple_debug_error("bonjour", "service browser - callback error");
-	else if (flags & kDNSServiceFlagsAdd)
-	{
+	else if (flags & kDNSServiceFlagsAdd) {
 		/* A presence service instance has been discovered... check it isn't us! */
-		if (g_ascii_strcasecmp(serviceName, account->username) != 0)
-		{
+		if (g_ascii_strcasecmp(serviceName, account->username) != 0) {
 			/* OK, lets go ahead and resolve it to add to the buddy list */
 			ResolveCallbackArgs *args = g_new0(ResolveCallbackArgs, 1);
 			args->buddy = bonjour_buddy_new(serviceName, account);
 
-			if (kDNSServiceErr_NoError != DNSServiceResolve(&args->resolver, 0, 0, serviceName, regtype, replyDomain, _mdns_service_resolve_callback, args))
-			{
+			if (kDNSServiceErr_NoError != DNSServiceResolve(&args->resolver, 0, 0, serviceName, regtype, replyDomain, _mdns_service_resolve_callback, args)) {
 				bonjour_buddy_delete(args->buddy);
 				g_free(args);
 				purple_debug_error("bonjour", "service browser - failed to resolve service.\n");
-			}
-			else
-			{
+			} else {
 				/* get a file descriptor for this service ref, and add it to the input list */
-				gint resolver_fd = DNSServiceRefSockFD(args->resolver);
-				args->resolver_fd = purple_input_add(resolver_fd, PURPLE_INPUT_READ, _mdns_handle_event, args->resolver);
+				gint fd = DNSServiceRefSockFD(args->resolver);
+				args->resolver_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, args->resolver);
 			}
 		}
-	}
-	else
-	{
+	} else {
 		/* A peer has sent a goodbye packet, remove them from the buddy list */
 		purple_debug_info("bonjour", "service browser - remove notification\n");
 		gb = purple_find_buddy(account, serviceName);
-		if (gb != NULL)
-		{
+		if (gb != NULL) {
 			bonjour_buddy_delete(gb->proto_data);
 			purple_blist_remove_buddy(gb);
 		}
 	}
 }
 
-int
-_mdns_publish(BonjourDnsSd *data, PublishType type)
-{
+/****************************
+ * mdns_interface functions *
+ ****************************/
+
+gboolean _mdns_init_session(BonjourDnsSd *data) {
+	data->mdns_impl_data = g_new0(Win32SessionImplData, 1);
+	return TRUE;
+}
+
+gboolean _mdns_publish(BonjourDnsSd *data, PublishType type) {
 	TXTRecordRef dns_data;
 	char portstring[6];
-	int ret = 0;
+	gboolean ret = TRUE;
 	const char *jid, *aim, *email;
 	DNSServiceErrorType set_ret;
+	Win32SessionImplData *idata = data->mdns_impl_data;
+
+	g_return_val_if_fail(idata != NULL, FALSE);
 
 	TXTRecordCreate(&dns_data, 256, NULL);
 
@@ -250,41 +275,34 @@
 
 	/* TODO: ext, nick, node */
 
-	if (set_ret != kDNSServiceErr_NoError)
-	{
+	if (set_ret != kDNSServiceErr_NoError) {
 		purple_debug_error("bonjour", "Unable to allocate memory for text record.\n");
-		ret = -1;
-	}
-	else
-	{
+		ret = FALSE;
+	} else {
 		DNSServiceErrorType err = kDNSServiceErr_NoError;
 
 		/* OK, we're done constructing the text record, (re)publish the service */
 
-		switch (type)
-		{
+		switch (type) {
 			case PUBLISH_START:
 				purple_debug_info("bonjour", "Registering service on port %d\n", data->port_p2pj);
-				err = DNSServiceRegister(&data->advertisement, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE,
+				err = DNSServiceRegister(&idata->advertisement, 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(data->advertisement, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0);
+				err = DNSServiceUpdateRecord(idata->advertisement, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0);
 				break;
 		}
 
-		if (kDNSServiceErr_NoError != err)
-		{
+		if (err != kDNSServiceErr_NoError) {
 			purple_debug_error("bonjour", "Failed to publish presence service.\n");
-			ret = -1;
-		}
-		else if (PUBLISH_START == type)
-		{
+			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 advertisement_fd = DNSServiceRefSockFD(data->advertisement);
-			data->advertisement_handler = purple_input_add(advertisement_fd, PURPLE_INPUT_READ, _mdns_handle_event, data->advertisement);
+			gint fd = DNSServiceRefSockFD(idata->advertisement);
+			idata->advertisement_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, idata->advertisement);
 		}
 	}
 
@@ -293,8 +311,58 @@
 	return ret;
 }
 
-void
-_mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition)
-{
-	DNSServiceProcessResult((DNSServiceRef)data);
+gboolean _mdns_browse(BonjourDnsSd *data) {
+	Win32SessionImplData *idata = data->mdns_impl_data;
+
+	g_return_val_if_fail(idata != NULL, FALSE);
+
+	return (DNSServiceBrowse(&idata->browser, 0, 0, ICHAT_SERVICE, NULL,
+				 _mdns_service_browse_callback, data->account)
+			== kDNSServiceErr_NoError);
+}
+
+guint _mdns_register_to_mainloop(BonjourDnsSd *data) {
+	Win32SessionImplData *idata = data->mdns_impl_data;
+
+	g_return_val_if_fail(idata != NULL, FALSE);
+
+	return purple_input_add(DNSServiceRefSockFD(idata->browser),
+				PURPLE_INPUT_READ, _mdns_handle_event, idata->browser);
 }
+
+void _mdns_stop(BonjourDnsSd *data) {
+	Win32SessionImplData *idata = data->mdns_impl_data;
+
+	if (idata == NULL || idata->advertisement == NULL || idata->browser == NULL)
+		return;
+
+	/* hack: for win32, we need to stop listening to the advertisement pipe too */
+	purple_input_remove(idata->advertisement_handler);
+
+	DNSServiceRefDeallocate(idata->advertisement);
+	DNSServiceRefDeallocate(idata->browser);
+
+	g_free(idata);
+
+	data->mdns_impl_data = NULL;
+}
+
+void _mdns_init_buddy(BonjourBuddy *buddy) {
+	buddy->mdns_impl_data = g_new0(Win32BuddyImplData, 1);
+}
+
+void _mdns_delete_buddy(BonjourBuddy *buddy) {
+	Win32BuddyImplData *idata = buddy->mdns_impl_data;
+
+	g_return_if_fail(idata != NULL);
+
+	if (idata->txt_query != NULL) {
+		purple_input_remove(idata->txt_query_handler);
+		DNSServiceRefDeallocate(idata->txt_query);
+	}
+
+	g_free(idata);
+
+	buddy->mdns_impl_data = NULL;
+}
+
--- a/libpurple/protocols/bonjour/mdns_win32.h	Fri Aug 03 23:20:28 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _BONJOUR_MDNS_WIN32
-#define _BONJOUR_MDNS_WIN32
-
-#ifdef USE_BONJOUR_APPLE
-
-#include <glib.h>
-#include "mdns_types.h"
-#include "buddy.h"
-#include "dnsquery.h"
-#include "dns_sd_proxy.h"
-
-/* Bonjour async callbacks */
-
-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);
-
-/* interface functions */
-
-int _mdns_publish(BonjourDnsSd *data, PublishType type);
-void _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition);
-
-#endif
-
-#endif