Blob Blame History Raw
Index: configure.in
===================================================================
RCS file: /cvs/gnome/gnome-vfs/configure.in,v
retrieving revision 1.391
diff -u -p -r1.391 configure.in
--- configure.in	5 Oct 2005 08:49:28 -0000	1.391
+++ configure.in	25 Oct 2005 14:04:25 -0000
@@ -651,12 +651,26 @@ if test "x$enable_gnutls" = "xyes"; then
   fi
 fi
 dnl ****************************
-dnl Howl
+dnl DNS-SD implementations
 dnl ****************************
-msg_howl=no
+AM_CONDITIONAL(HAVE_AVAHI, false)
 AM_CONDITIONAL(HAVE_HOWL, false)
+			  
+AC_ARG_ENABLE(avahi, [  --disable-avahi     build without avahi support])
+msg_avahi=no
+if test "x$enable_avahi" != "xno"; then
+	PKG_CHECK_MODULES(AVAHI, avahi-glib avahi-client,
+		  	[AM_CONDITIONAL(HAVE_AVAHI, true)
+		   	AC_DEFINE(HAVE_AVAHI, [], [Set if we can use avahi])]
+                        msg_avahi=yes,
+	          	[AM_CONDITIONAL(HAVE_AVAHI, false)])
+	AC_SUBST(AVAHI_CFLAGS)
+	AC_SUBST(AVAHI_LIBS)
+fi
+			  
 AC_ARG_ENABLE(howl, [  --disable-howl     build without howl support])
-if test "x$enable_howl" != "xno"; then
+msg_howl=no
+if test "x$msg_avahi" = "xno" -a "x$enable_howl" != "xno"; then
 	PKG_CHECK_MODULES(HOWL, howl >= 0.9.6,
 		  	[AM_CONDITIONAL(HAVE_HOWL, true)
 		   	AC_DEFINE(HAVE_HOWL, [], [Set if we can use howl])]
@@ -969,8 +983,8 @@ dnl End of IPv6 checks
 dnl ==============================================================================
 
 PKG_CHECK_MODULES(LIBGNOMEVFS, glib-2.0 >= $GLIB_REQUIRED gmodule-no-export-2.0 >= $GLIB_REQUIRED gthread-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gconf-2.0 >= $GCONF_REQUIRED bonobo-activation-2.0 >= $BONOBO_ACTIVATION_REQUIRED libbonobo-2.0 >= $BONOBO_REQUIRED ORBit-2.0 >= $ORBIT_REQUIRED libxml-2.0 >= $XML_REQUIRED gnome-mime-data-2.0)
-LIBGNOMEVFS_CFLAGS="$LIBGNOMEVFS_CFLAGS $OPENSSL_CFLAGS $LIBGNUTLS_CFLAGS $HOWL_CFLAGS"
-LIBGNOMEVFS_LIBS="$LIBGNOMEVFS_LIBS $OPENSSL_LIBS $LIBGNUTLS_LIBS $HOWL_LIBS $RESOLVER_LIBS"
+LIBGNOMEVFS_CFLAGS="$LIBGNOMEVFS_CFLAGS $OPENSSL_CFLAGS $LIBGNUTLS_CFLAGS $HOWL_CFLAGS $AVAHI_CFLAGS"
+LIBGNOMEVFS_LIBS="$LIBGNOMEVFS_LIBS $OPENSSL_LIBS $LIBGNUTLS_LIBS $HOWL_LIBS $AVAHI_LIBS $RESOLVER_LIBS"
 AC_SUBST(LIBGNOMEVFS_CFLAGS)
 AC_SUBST(LIBGNOMEVFS_LIBS)
 
@@ -1136,6 +1150,7 @@ echo 
 echo "Gnome VFS configuration summary:"
 echo "
 	IPv6 support:                $have_ipv6
+      	Avahi support:		     $msg_avahi
       	Howl support:		     $msg_howl
 	HAL  support:                $msg_hal
 	Gtk Doc:                     $enable_gtk_doc
Index: libgnomevfs/gnome-vfs-dns-sd.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-dns-sd.c,v
retrieving revision 1.12
diff -u -p -r1.12 gnome-vfs-dns-sd.c
--- libgnomevfs/gnome-vfs-dns-sd.c	14 Jul 2005 07:47:53 -0000	1.12
+++ libgnomevfs/gnome-vfs-dns-sd.c	25 Oct 2005 14:04:25 -0000
@@ -36,6 +36,13 @@
 #include <gconf/gconf-client.h>
 #include <unistd.h>
 
+#ifdef HAVE_AVAHI
+#include <avahi-client/client.h>
+#include <avahi-common/error.h>
+#include <avahi-common/simple-watch.h>
+#include <avahi-glib/glib-watch.h>
+#endif 
+
 #ifdef HAVE_HOWL
 /* Need to work around howl exporting its config file... */
 #undef PACKAGE
@@ -722,6 +729,58 @@ unicast_resolve_sync (const char *name,
 
 /* multicast DNS functions */
 
+#ifdef HAVE_AVAHI
+static AvahiClient *global_client = NULL;
+static gboolean avahi_initialized = FALSE;
+
+/* Callback for state changes on the Client */
+static void
+avahi_client_callback (AvahiClient *client, AvahiClientState state, void *userdata)
+{
+	if (state == AVAHI_CLIENT_DISCONNECTED) {
+	}
+}
+
+static AvahiClient *
+get_global_avahi_client (void) {
+	AvahiGLibPoll *glib_poll;
+	const char *version;
+	int error;
+
+	if (!avahi_initialized) {
+		glib_poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
+
+		/* Create a new AvahiClient instance */
+		global_client = avahi_client_new (avahi_glib_poll_get (glib_poll),
+						  avahi_client_callback,
+						  NULL,
+						  &error);
+
+		if (global_client == NULL) {    
+			/* Print out the error string */
+			g_warning ("Error initializing Avahi: %s", avahi_strerror (error));
+			avahi_glib_poll_free (glib_poll);
+			return NULL;
+		}
+		/* Make a call to get the version string from the daemon */
+		version = avahi_client_get_version_string (global_client);
+		
+		/* Check if the call suceeded */
+		if (version == NULL) {
+			g_warning ("Error getting version string: %s", avahi_strerror (avahi_client_errno (global_client)));
+			avahi_client_free (global_client);
+			avahi_glib_poll_free (glib_poll);
+			global_client = NULL;
+			return NULL;
+		}
+		avahi_initialized = TRUE;
+	}
+
+	return global_client;
+}
+#endif
+
+
 #ifdef HAVE_HOWL
 
 static gboolean
@@ -788,6 +847,10 @@ struct GnomeVFSDNSSDBrowseHandle {
 
 	/* multicast: */
 
+#ifdef HAVE_AVAHI
+	AvahiServiceBrowser *avahi_sb;
+#endif
+
 #ifdef HAVE_HOWL
 	sw_discovery_oid howl_id;
 #endif
@@ -864,6 +927,34 @@ unicast_browse_thread (gpointer data)
 	return NULL;
 }
 
+#ifdef HAVE_AVAHI
+static void 
+avahi_browse_callback (AvahiServiceBrowser *b,
+		       AvahiIfIndex interface,
+		       AvahiProtocol protocol,
+		       AvahiBrowserEvent event,
+		       const char *name,
+		       const char *type,
+		       const char *domain,
+		       void *userdata)
+{
+	GnomeVFSDNSSDBrowseHandle *handle;
+	GnomeVFSDNSSDService service;
+	handle = userdata;
+    
+	service.name = (char *)name;
+	service.type = (char *)type;
+	service.domain = (char *)domain;
+	
+	if (!handle->cancelled) {
+		handle->callback (handle,
+				  (event == AVAHI_BROWSER_NEW) ? GNOME_VFS_DNS_SD_SERVICE_ADDED : GNOME_VFS_DNS_SD_SERVICE_REMOVED,
+				  &service,
+				  handle->callback_data);
+	}
+}
+#endif
+
 #ifdef HAVE_HOWL
 
 struct howl_browse_idle_data {
@@ -1012,7 +1103,23 @@ gnome_vfs_dns_sd_browse (GnomeVFSDNSSDBr
 	handle->callback_data_destroy_func = callback_data_destroy_func;
 	
 	if (strcmp (domain, "local") == 0) {
-#ifdef HAVE_HOWL
+#ifdef HAVE_AVAHI
+		AvahiClient *client;
+		AvahiServiceBrowser *sb;
+
+		handle->is_local = TRUE;
+		client = get_global_avahi_client ();
+		if (client) {
+			sb = avahi_service_browser_new (client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, type, NULL, avahi_browse_callback, handle);
+			if (sb != NULL) {
+				handle->avahi_sb = sb;
+				*handle_out = handle;
+				return GNOME_VFS_OK;
+			}
+			g_warning ("Failed to create service browser: %s\n", avahi_strerror( avahi_client_errno (client)));
+		}
+		return GNOME_VFS_ERROR_GENERIC;
+#elif defined (HAVE_HOWL)
 		sw_result res;
 		sw_discovery session;
 		
@@ -1063,6 +1170,11 @@ GnomeVFSResult
 gnome_vfs_dns_sd_stop_browse (GnomeVFSDNSSDBrowseHandle *handle)
 {
 	if (handle->is_local) {
+#ifdef HAVE_AVAHI
+		handle->cancelled = TRUE;
+		avahi_service_browser_free (handle->avahi_sb);
+		free_browse_handle (handle);
+#endif
 #ifdef HAVE_HOWL
 		handle->cancelled = TRUE;
 		sw_discovery_cancel (get_global_howl_session (), handle->howl_id);
@@ -1093,6 +1205,10 @@ struct GnomeVFSDNSSDResolveHandle {
 	int text_len;
 	
 	/* multicast: */
+#ifdef HAVE_AVAHI
+	AvahiServiceResolver *avahi_sr;
+#endif
+
 #ifdef HAVE_HOWL
 	sw_discovery_oid howl_id;
 	guint timeout_tag;
@@ -1174,6 +1290,70 @@ unicast_resolve_thread (gpointer data)
 	return NULL;
 }
 
+#ifdef HAVE_AVAHI
+static void
+avahi_resolve_async_callback (AvahiServiceResolver *r,
+			      AvahiIfIndex interface,
+			      AvahiProtocol protocol,
+			      AvahiResolverEvent event,
+			      const char *name,
+			      const char *type,
+			      const char *domain,
+			      const char *host_name,
+			      const AvahiAddress *address,
+			      uint16_t port,
+			      AvahiStringList *txt,
+			      void *user_data)
+{
+	GnomeVFSDNSSDResolveHandle *handle;
+	GnomeVFSDNSSDService service;
+	GHashTable *hash;
+	size_t text_len;
+	char *text;
+	char host[128];
+
+	handle = user_data;
+	if (event == AVAHI_RESOLVER_FOUND) {
+		text_len = avahi_string_list_serialize (txt, NULL, 0);
+		text = g_malloc (text_len);
+		text_len = avahi_string_list_serialize (txt, text, text_len);
+
+		hash = decode_txt_record (text, text_len);
+
+		service.name = (char *)name;
+		service.type = (char *)type;
+		service.domain = (char *)domain;
+		
+		avahi_address_snprint (host, sizeof(host), address);
+		handle->callback (handle,
+				  GNOME_VFS_OK,
+				  &service,
+				  host,
+				  port,
+				  hash,
+				  handle->text_len,
+				  handle->text,
+				  handle->callback_data);
+		if (hash) {
+			g_hash_table_destroy (hash);
+		}
+		g_free (text);
+
+	} else if (event == AVAHI_RESOLVER_TIMEOUT) {
+		handle->callback (handle,
+				  GNOME_VFS_ERROR_HOST_NOT_FOUND,
+				  NULL,
+				  NULL, 0,
+				  NULL, 0, NULL,
+				  handle->callback_data);
+	}
+	
+	avahi_service_resolver_free (r);
+	free_resolve_handle (handle);
+}
+
+#endif
+
 
 #ifdef HAVE_HOWL
 static gboolean
@@ -1329,7 +1509,24 @@ gnome_vfs_dns_sd_resolve (GnomeVFSDNSSDR
 	handle->callback_data_destroy_func = callback_data_destroy_func;
 	
 	if (strcmp (domain, "local") == 0) {
-#ifdef HAVE_HOWL
+#ifdef HAVE_AVAHI
+		AvahiClient *client;
+		AvahiServiceResolver *sr;
+
+		handle->is_local = TRUE;
+		client = get_global_avahi_client ();
+		if (client) {
+			sr = avahi_service_resolver_new (client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 
+							 name, type, domain, AVAHI_PROTO_UNSPEC, 
+							 avahi_resolve_async_callback, handle);
+			if (sr != NULL) {
+				handle->avahi_sr = sr;
+				*handle_out = handle;
+				return GNOME_VFS_OK;
+			}
+		}
+		return GNOME_VFS_ERROR_GENERIC;
+#elif defined (HAVE_HOWL)
 		sw_result res;
 		sw_discovery session;
 		
@@ -1386,6 +1583,10 @@ GnomeVFSResult
 gnome_vfs_dns_sd_cancel_resolve (GnomeVFSDNSSDResolveHandle *handle)
 {
 	if (handle->is_local) {
+#ifdef HAVE_AVAHI
+		avahi_service_resolver_free (handle->avahi_sr);
+		free_resolve_handle (handle);
+#endif
 #ifdef HAVE_HOWL
 		g_source_remove (handle->timeout_tag);
 		if (handle->idle_tag) {
@@ -1408,8 +1609,7 @@ gnome_vfs_dns_sd_cancel_resolve (GnomeVF
 	}
 }
 
-
-#ifdef HAVE_HOWL
+#if defined(HAVE_AVAHI) || defined(HAVE_HOWL)
 static int
 find_existing_service (GArray *array,
 		       const char *name,
@@ -1430,6 +1630,87 @@ find_existing_service (GArray *array,
 	return -1;
 		    
 }
+#endif
+
+
+#ifdef HAVE_AVAHI
+struct sync_browse_data {
+	AvahiSimplePoll *poll;
+	GArray *array;
+};
+
+static void
+avahi_browse_sync_client_callback (AvahiClient *client, AvahiClientState state, void *user_data)
+{
+	struct sync_browse_data *data;
+
+	data = user_data;
+	if (state == AVAHI_CLIENT_DISCONNECTED) {
+		avahi_simple_poll_quit (data->poll);
+	}
+}
+
+static void 
+avahi_browse_sync_callback (AvahiServiceBrowser *b,
+			    AvahiIfIndex interface,
+			    AvahiProtocol protocol,
+			    AvahiBrowserEvent event,
+			    const char *name,
+			    const char *type,
+			    const char *domain,
+			    void *user_data)
+{
+	struct sync_browse_data *data;
+	GnomeVFSDNSSDService service, *existing;
+	int i;
+	gboolean free_service;
+
+	data = user_data;
+	
+	free_service = TRUE;
+	service.name = g_strdup (name);
+	service.type = g_strdup (type);
+	service.domain = g_strdup (domain);
+	
+	if (event == AVAHI_BROWSER_NEW) {
+		if (find_existing_service (data->array, service.name, service.type,
+					   service.domain) == -1) {
+			free_service = FALSE;
+			g_array_append_val (data->array, service);
+		} 
+	} else if (event == AVAHI_BROWSER_REMOVE) {
+		i = find_existing_service (data->array, service.name, service.type,
+					   service.domain);
+		if (i != -1) {
+			existing = &g_array_index (data->array, GnomeVFSDNSSDService, i);
+			g_free (existing->name);
+			g_free (existing->type);
+			g_free (existing->domain);
+			g_array_remove_index (data->array, i);
+		}
+	} else {
+		g_warning ("Unknown browse status\n");
+	}
+	
+	if (free_service) {
+		g_free (service.name);
+		g_free (service.type);
+		g_free (service.domain);
+	}	
+}
+
+static void
+stop_poll_timeout (AvahiTimeout *timeout, void *user_data)
+{
+	AvahiSimplePoll *poll = user_data;
+	
+	avahi_simple_poll_quit (poll);
+}
+
+#endif
+
+
+#ifdef HAVE_HOWL
 
 
 static sw_result
@@ -1530,7 +1811,65 @@ gnome_vfs_dns_sd_browse_sync (const char
 	*services = NULL;
 	
 	if (strcmp (domain, "local") == 0) {
-#ifdef HAVE_HOWL
+#ifdef HAVE_AVAHI
+		AvahiSimplePoll *simple_poll;
+		const AvahiPoll *poll;
+		AvahiClient *client = NULL;
+		AvahiServiceBrowser *sb;
+		int error;
+		GArray *array;
+		struct sync_browse_data data;
+		struct timeval tv;
+
+		simple_poll = avahi_simple_poll_new ();
+		data.poll = simple_poll;
+		if (simple_poll == NULL) {
+			g_warning ("Failed to create simple poll object");
+			return GNOME_VFS_ERROR_GENERIC;
+		}
+
+		poll = avahi_simple_poll_get (simple_poll);
+		client = avahi_client_new (poll, 
+					   avahi_browse_sync_client_callback, &data, &error);
+		
+		/* Check wether creating the client object succeeded */
+		if (client == NULL) {
+			g_warning ("Failed to create client: %s\n", avahi_strerror (error));
+			avahi_simple_poll_free (simple_poll);
+			return GNOME_VFS_ERROR_GENERIC;
+		}
+
+
+		array = g_array_new (FALSE, FALSE, sizeof (GnomeVFSDNSSDService));
+		data.array = array;
+		sb = avahi_service_browser_new (client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, type, NULL, avahi_browse_sync_callback, &data);
+		if (sb == NULL) {
+			g_warning ("Failed to create service browser: %s\n", avahi_strerror (avahi_client_errno (client)));
+			g_array_free (array, TRUE);
+			avahi_client_free (client);
+			avahi_simple_poll_free (simple_poll);
+			return GNOME_VFS_ERROR_GENERIC;
+		}
+
+
+		avahi_elapse_time (&tv, timeout_msec,  0);
+		poll->timeout_new (poll, &tv, stop_poll_timeout, (void *)simple_poll);
+
+		/* Run the main loop util reply or timeout */
+		for (;;)
+			if (avahi_simple_poll_iterate (simple_poll, -1) != 0)
+				break;
+
+		
+		avahi_service_browser_free (sb);
+		avahi_client_free (client);
+		avahi_simple_poll_free (simple_poll);
+
+		*n_services = array->len;
+		*services = (GnomeVFSDNSSDService *)g_array_free (array, FALSE);
+		
+		return GNOME_VFS_OK;
+#elif defined (HAVE_HOWL)
 		sw_discovery session;
 		sw_salt salt;
 		sw_result res;
@@ -1599,6 +1938,62 @@ gnome_vfs_dns_sd_browse_sync (const char
 	}
 }
 
+#ifdef HAVE_AVAHI
+struct sync_resolve_data {
+	AvahiSimplePoll *poll;
+	gboolean got_data;
+	char *host;
+	int port;
+	char *text;
+	int text_len;
+};
+
+
+static void
+avahi_resolve_sync_client_callback (AvahiClient *c, AvahiClientState state, void *user_data)
+{
+	struct sync_resolve_data *data;
+
+	data = user_data;
+	if (state == AVAHI_CLIENT_DISCONNECTED) {
+		avahi_simple_poll_quit (data->poll);
+	}
+}
+
+static void
+avahi_resolve_sync_callback (AvahiServiceResolver *r,
+			     AvahiIfIndex interface,
+			     AvahiProtocol protocol,
+			     AvahiResolverEvent event,
+			     const char *name,
+			     const char *type,
+			     const char *domain,
+			     const char *host_name,
+			     const AvahiAddress *address,
+			     uint16_t port,
+			     AvahiStringList *txt,
+			     void *user_data)
+{
+	struct sync_resolve_data *data;
+	char a[128];
+
+	data = user_data;
+	if (event == AVAHI_RESOLVER_FOUND) {
+		data->got_data = TRUE;
+		avahi_address_snprint (a, sizeof(a), address);
+		data->host = g_strdup (a);
+		data->port = port;
+		data->text_len = avahi_string_list_serialize (txt, NULL, 0);
+		data->text = g_malloc (data->text_len);
+		avahi_string_list_serialize (txt, data->text, data->text_len);
+	}
+	
+	avahi_service_resolver_free (r);
+        avahi_simple_poll_quit (data->poll);
+}
+
+#endif
+
 #ifdef HAVE_HOWL
 struct sync_resolve_data {
 	gboolean got_data;
@@ -1672,7 +2067,64 @@ gnome_vfs_dns_sd_resolve_sync (const cha
 	GnomeVFSResult res;
 	
 	if (strcmp (domain, "local") == 0) {
-#ifdef HAVE_HOWL
+#ifdef HAVE_AVAHI
+		AvahiSimplePoll *simple_poll;
+		AvahiClient *client = NULL;
+		AvahiServiceResolver *sr;
+		int error;
+		struct sync_resolve_data resolve_data = {0};
+
+		simple_poll = avahi_simple_poll_new ();
+		resolve_data.poll = simple_poll;
+		if (simple_poll == NULL) {
+			g_warning ("Failed to create simple poll object");
+			return GNOME_VFS_ERROR_GENERIC;
+		}
+
+		client = avahi_client_new (avahi_simple_poll_get (simple_poll), 
+					   avahi_resolve_sync_client_callback, &resolve_data, &error);
+		
+		/* Check wether creating the client object succeeded */
+		if (client == NULL) {
+			g_warning ("Failed to create client: %s\n", avahi_strerror (error));
+			avahi_simple_poll_free (simple_poll);
+			return GNOME_VFS_ERROR_GENERIC;
+		}
+		
+		sr = avahi_service_resolver_new (client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 
+						 name, type, domain, AVAHI_PROTO_UNSPEC, 
+						 avahi_resolve_sync_callback, &resolve_data);
+		if (sr == NULL) {
+			g_warning ("Failed to resolve service '%s': %s\n", name, avahi_strerror (avahi_client_errno (client)));
+			avahi_client_free (client);
+			avahi_simple_poll_free (simple_poll);
+			return GNOME_VFS_ERROR_GENERIC;
+		}
+
+		/* Run the main loop util reply or timeout */
+		for (;;)
+			if (avahi_simple_poll_iterate (simple_poll, -1) != 0)
+				break;
+
+		avahi_client_free (client);
+		avahi_simple_poll_free (simple_poll);
+
+		if (resolve_data.got_data) {
+			*host = resolve_data.host;
+			*port = resolve_data.port;
+			if (text != NULL)
+				*text = decode_txt_record (resolve_data.text, resolve_data.text_len);
+			if (text_raw_len_out != NULL && text_raw_out) {
+				*text_raw_len_out = resolve_data.text_len;
+				*text_raw_out = resolve_data.text;
+			} else {
+				g_free (resolve_data.text);
+			}
+			return GNOME_VFS_OK;
+		}
+		
+		return GNOME_VFS_ERROR_HOST_NOT_FOUND;
+#elif defined (HAVE_HOWL)
 		sw_discovery session;
 		sw_salt salt;
 		sw_result res;
Index: modules/dns-sd-method.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/modules/dns-sd-method.c,v
retrieving revision 1.5
diff -u -p -r1.5 dns-sd-method.c
--- modules/dns-sd-method.c	8 May 2005 13:04:05 -0000	1.5
+++ modules/dns-sd-method.c	25 Oct 2005 14:04:26 -0000
@@ -29,6 +29,13 @@
 #include <time.h>
 #include <sys/time.h>
 
+#ifdef HAVE_AVAHI
+#include <avahi-client/client.h>
+#include <avahi-common/error.h>
+#include <avahi-common/simple-watch.h>
+#include <avahi-glib/glib-watch.h>
+#endif 
+
 #ifdef HAVE_HOWL
 /* Need to work around howl exporting its config file... */
 #undef PACKAGE
@@ -61,12 +68,12 @@ static struct {
 	{"_sftp-ssh._tcp", "sftp", "gnome-fs-ssh"},
 };
 
-#ifdef HAVE_HOWL
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
 G_LOCK_DEFINE_STATIC (local);
 static gboolean started_local = FALSE;
 static GList *local_files = NULL;
 static GList *local_monitors = NULL;
-#endif /* HAVE_HOWL */
+#endif /* HAVE_HOWL || HAVE_AVAHI */
 
 typedef struct {
 	char *data;
@@ -216,8 +223,7 @@ encode_filename (const char *service,
 	return g_string_free (string, FALSE);
 }
 
-#ifdef HAVE_HOWL
-
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
 static void
 call_monitors (gboolean add, char *filename)
 {
@@ -240,7 +246,6 @@ call_monitors (gboolean add, char *filen
 	gnome_vfs_uri_unref (info_uri);
 }
 
-
 static void
 local_browse (gboolean add,
 	      const char *name,
@@ -291,6 +296,137 @@ local_browse (gboolean add,
 	}
 }
 
+static void
+local_browse_callback (GnomeVFSDNSSDBrowseHandle *handle,
+		       GnomeVFSDNSSDServiceStatus status,
+		       const GnomeVFSDNSSDService *service,
+		       gpointer callback_data)
+{
+	G_LOCK (local);
+
+	local_browse (status == GNOME_VFS_DNS_SD_SERVICE_ADDED,
+		      service->name, service->type, service->domain);
+	
+	G_UNLOCK (local);
+}
+#endif /* HAVE_HOWL || HAVE_AVAHI */
+
+
+#ifdef HAVE_AVAHI
+static void
+avahi_client_callback (AvahiClient *client, AvahiClientState state, void *user_data)
+{
+	AvahiSimplePoll *poll;
+
+	poll = user_data;
+	if (state == AVAHI_CLIENT_DISCONNECTED) {
+		avahi_simple_poll_quit (poll);
+	}
+}
+
+static void 
+local_browse_callback_sync (AvahiServiceBrowser *b,
+			    AvahiIfIndex interface,
+			    AvahiProtocol protocol,
+			    AvahiBrowserEvent event,
+			    const char *name,
+			    const char *type,
+			    const char *domain,
+			    void *user_data)
+{
+	if (event == AVAHI_BROWSER_NEW)
+		local_browse (TRUE, name, type, domain);
+	else if (event == AVAHI_BROWSER_REMOVE)
+		local_browse (FALSE, name, type, domain);
+}
+
+static void
+stop_poll_timeout (AvahiTimeout *timeout, void *user_data)
+{
+	AvahiSimplePoll *poll = user_data;
+	
+	avahi_simple_poll_quit (poll);
+}
+
+
+static void
+init_local (void)
+{
+	int i;
+	GnomeVFSResult res;
+	
+	if (!started_local) {
+		AvahiSimplePoll *simple_poll;
+		const AvahiPoll *poll;
+		AvahiClient *client = NULL;
+		AvahiServiceBrowser **sb;
+		struct timeval tv;
+		int error;
+		
+		started_local = TRUE;
+		
+		for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++) {
+			GnomeVFSDNSSDBrowseHandle *handle;
+			res = gnome_vfs_dns_sd_browse (&handle,
+						       "local",
+						       dns_sd_types[i].type,
+						       local_browse_callback,
+						       NULL, NULL);
+			if (res == GNOME_VFS_OK) {
+				dns_sd_types[i].handle = handle;
+			}
+		}
+
+		simple_poll = avahi_simple_poll_new ();
+		if (simple_poll == NULL) {
+			g_warning ("Failed to create simple poll object");
+			return;
+		}
+
+		poll = avahi_simple_poll_get (simple_poll);
+		client = avahi_client_new (poll, 
+					   avahi_client_callback, simple_poll, &error);
+		
+		/* Check wether creating the client object succeeded */
+		if (client == NULL) {
+			g_warning ("Failed to create client: %s\n", avahi_strerror (error));
+			avahi_simple_poll_free (simple_poll);
+			return;
+		}
+
+		sb = g_new0 (AvahiServiceBrowser *, G_N_ELEMENTS (dns_sd_types));
+
+		for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++) {
+			sb[i] = avahi_service_browser_new (client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 
+							   dns_sd_types[i].type, "local",
+							   local_browse_callback_sync, NULL);
+		}
+		
+
+		avahi_elapse_time (&tv, LOCAL_SYNC_BROWSE_DELAY_MSEC, 0);
+		poll->timeout_new (poll, &tv, stop_poll_timeout,
+				   (void *)simple_poll);
+
+		/* Run the main loop util reply or timeout */
+		for (;;)
+			if (avahi_simple_poll_iterate (simple_poll, -1) != 0)
+				break;
+
+		for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++) {
+			if (sb[i] != NULL) {
+				avahi_service_browser_free (sb[i]);
+			}
+		}
+		avahi_client_free (client);
+		avahi_simple_poll_free (simple_poll);
+
+					  
+	}
+}
+#endif /* HAVE_AVAHI */
+
+
+#ifdef HAVE_HOWL
 static sw_result
 local_browse_callback_sync (sw_discovery                 discovery,
 			    sw_discovery_oid             id,
@@ -309,19 +445,6 @@ local_browse_callback_sync (sw_discovery
 	return SW_OKAY;
 }
 			    
-static void
-local_browse_callback (GnomeVFSDNSSDBrowseHandle *handle,
-		       GnomeVFSDNSSDServiceStatus status,
-		       const GnomeVFSDNSSDService *service,
-		       gpointer callback_data)
-{
-	G_LOCK (local);
-
-	local_browse (status == GNOME_VFS_DNS_SD_SERVICE_ADDED,
-		      service->name, service->type, service->domain);
-	
-	G_UNLOCK (local);
-}
 
 static void
 init_local (void)
@@ -694,7 +817,7 @@ directory_handle_add_filename (Directory
 	}
 }
 
-#ifdef HAVE_HOWL
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
 static void
 directory_handle_add_filenames (DirectoryHandle *dir_handle, GList *files)
 {
@@ -703,7 +826,7 @@ directory_handle_add_filenames (Director
 		files = files->next;
 	}
 } 
-#endif
+#endif /* HAVE_HOWL || HAVE_AVAHI */
 
 static GnomeVFSResult
 do_open_directory (GnomeVFSMethod *method,
@@ -733,14 +856,14 @@ do_open_directory (GnomeVFSMethod *metho
 	dir_handle = directory_handle_new (options);
 	
 	if (strcmp (domain, "local") == 0) {
-#ifdef HAVE_HOWL
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
 		G_LOCK (local);
 		init_local ();
 
 		directory_handle_add_filenames (dir_handle, local_files);
 		
 		G_UNLOCK (local);
-#endif /* HAVE_HOWL */
+#endif /* HAVE_HOWL || HAVE_AVAHI */
 	} else 	{
 		for (i=0; i < G_N_ELEMENTS (dns_sd_types); i++) {
 			int n_services;
@@ -1007,7 +1130,7 @@ do_monitor_add (GnomeVFSMethod *method,
 		return GNOME_VFS_ERROR_NOT_SUPPORTED;
 	}
 	
-#ifdef HAVE_HOWL
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
 	if (strcmp (uri->text, "") == 0 ||
 	    strcmp (uri->text, "/") == 0) {
 		int *handle;
@@ -1025,7 +1148,7 @@ do_monitor_add (GnomeVFSMethod *method,
 
 		return GNOME_VFS_OK;
 	} else 
-#endif /* HAVE_HOWL */
+#endif /* HAVE_HOWL || HAVE_AVAHI */
 		return GNOME_VFS_ERROR_NOT_SUPPORTED;
 }
 
@@ -1033,7 +1156,7 @@ static GnomeVFSResult
 do_monitor_cancel (GnomeVFSMethod *method,
 		   GnomeVFSMethodHandle *method_handle)
 {
-#ifdef HAVE_HOWL
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
 	G_LOCK (local);
 	
 	local_monitors = g_list_remove (local_monitors, method_handle);
@@ -1044,7 +1167,7 @@ do_monitor_cancel (GnomeVFSMethod *metho
 	return GNOME_VFS_OK;
 #else
 	return GNOME_VFS_ERROR_NOT_SUPPORTED;
-#endif /* HAVE_HOWL */
+#endif /* HAVE_HOWL || HAVE_AVAHI */
 }
 
 
Index: modules/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-vfs/modules/Makefile.am,v
retrieving revision 1.112
diff -u -p -r1.112 Makefile.am
--- modules/Makefile.am	14 Apr 2005 18:48:29 -0000	1.112
+++ modules/Makefile.am	25 Oct 2005 15:25:51 -0000
@@ -7,6 +7,7 @@ INCLUDES =					\
 	$(MODULES_XML_GCONF_CFLAGS)		\
 	$(MODULES_FILE_CFLAGS) 			\
 	$(HOWL_CFLAGS)				\
+	$(AVAHI_CFLAGS)				\
 	$(LIBEFS_CFLAGS)			\
 	$(SAMBA_CFLAGS)				\
 	$(GSSAPI_CFLAGS)			\
@@ -103,7 +104,7 @@ libcomputer_la_LIBADD = $(MODULES_FILE_L
 
 libdns_sd_la_SOURCES = dns-sd-method.c
 libdns_sd_la_LDFLAGS = $(module_flags)
-libdns_sd_la_LIBADD = $(MODULES_LIBS) $(HOWL_LIBS) ../libgnomevfs/libgnomevfs-2.la
+libdns_sd_la_LIBADD = $(MODULES_LIBS) $(HOWL_LIBS) $(AVAHI_LIBS) ../libgnomevfs/libgnomevfs-2.la
 
 ###  `file' method