? daapsharing/rb-daap-marshal.list
? daapsharing/rb-daap-mdns-browser-avahi.c
? daapsharing/rb-daap-mdns-browser-howl.c
? daapsharing/rb-daap-mdns-browser.h
? daapsharing/rb-daap-mdns-publisher-avahi.c
? daapsharing/rb-daap-mdns-publisher-howl.c
? daapsharing/rb-daap-mdns-publisher.h
Index: configure.ac
===================================================================
RCS file: /cvs/gnome/rhythmbox/configure.ac,v
retrieving revision 1.203
diff -p -u -r1.203 configure.ac
--- configure.ac	21 Jan 2006 09:17:02 -0000	1.203
+++ configure.ac	27 Jan 2006 23:35:20 -0000
@@ -241,6 +241,8 @@ AC_ARG_WITH(mdns,
 have_howl=no
 have_avahi=no
 have_mdns=no
+use_howl=no
+use_avahi=no
 
 PKG_CHECK_MODULES(AVAHI,
    avahi-client >= 0.6
@@ -270,6 +272,7 @@ if test x"$with_mdns" = xauto; then
       MDNS_CFLAGS=$AVAHI_CFLAGS
       MDNS_LIBS=$AVAHI_LIBS
       AC_DEFINE(WITH_AVAHI, 1, [Define if mDNS/DNS-SD implementation uses Avahi])
+      use_avahi=yes
       AC_MSG_NOTICE([Detected Avahi, using it for mDNS/DNS-SD])
       if test x$have_avahi_06 == xyes; then
          AC_DEFINE(HAVE_AVAHI_0_6, 1, [Define if mDNS/DNS-SD implementation uses Avahi 0.6])
@@ -282,6 +285,7 @@ if test x"$with_mdns" = xauto; then
       MDNS_CFLAGS=$HOWL_CFLAGS
       MDNS_LIBS=$HOWL_LIBS
       AC_DEFINE(WITH_HOWL, 1, [Define if mDNS/DNS-SD implementation uses Howl])
+      use_howl=yes
       AC_MSG_NOTICE([Detected Howl, using it for mDNS/DNS-SD])
 
       have_mdns=yes
@@ -296,8 +300,8 @@ if test x"$with_mdns" = xhowl; then
    MDNS_CFLAGS=$HOWL_CFLAGS
    MDNS_LIBS=$HOWL_LIBS
    AC_DEFINE(WITH_HOWL, 1, [Define if mDNS/DNS-SD implementation uses Howl])
+   use_howl=yes
    AC_MSG_NOTICE([Using Howl for mDNS/DNS-SD])
-
    have_mdns=yes
 fi
 
@@ -309,6 +313,7 @@ if test x"$with_mdns" = xavahi; then
    MDNS_CFLAGS=$AVAHI_CFLAGS
    MDNS_LIBS=$AVAHI_LIBS
    AC_DEFINE(WITH_AVAHI, 1, [Define if mDNS/DNS-SD implementation uses Avahi])
+   use_avahi=yes
    AC_MSG_NOTICE([Using Avahi for mDNS/DNS-SD])
 
    if test x$have_avahi_06 == xyes; then
@@ -334,6 +339,8 @@ if test x"$enable_daap" = xyes; then
   fi	
 fi
 AM_CONDITIONAL(USE_DAAP, test "x$enable_daap" = "xyes")
+AM_CONDITIONAL(USE_HOWL, test "x$use_howl" = "xyes")
+AM_CONDITIONAL(USE_AVAHI, test "x$use_avahi" = "xyes")
 
 LIBNOTIFY_REQUIRED=0.2.2
 AC_ARG_ENABLE(libnotify,
Index: daapsharing/.cvsignore
===================================================================
RCS file: /cvs/gnome/rhythmbox/daapsharing/.cvsignore,v
retrieving revision 1.1
diff -p -u -r1.1 .cvsignore
--- daapsharing/.cvsignore	6 Sep 2005 19:23:44 -0000	1.1
+++ daapsharing/.cvsignore	27 Jan 2006 23:35:20 -0000
@@ -1,2 +1,4 @@
 Makefile
 Makefile.in
+rb-daap-marshal.c
+rb-daap-marshal.h
Index: daapsharing/Makefile.am
===================================================================
RCS file: /cvs/gnome/rhythmbox/daapsharing/Makefile.am,v
retrieving revision 1.2
diff -p -u -r1.2 Makefile.am
--- daapsharing/Makefile.am	9 Sep 2005 10:08:52 -0000	1.2
+++ daapsharing/Makefile.am	27 Jan 2006 23:35:20 -0000
@@ -1,23 +1,40 @@
+NULL =
+
 noinst_LTLIBRARIES = libdaapsharing.la
 
 libdaapsharing_la_SOURCES = 
 
 if USE_DAAP
 libdaapsharing_la_SOURCES += \
+		$(BUILT_SOURCES)	\
 		rb-daap-sharing.c	\
 		rb-daap-sharing.h 	\
 		rb-daap-share.c		\
 		rb-daap-share.h 	\
 		rb-daap-structure.c 	\
 		rb-daap-structure.h 	\
-		rb-daap-mdns.c 		\
-		rb-daap-mdns.h 		\
+		rb-daap-mdns-publisher.h \
+		rb-daap-mdns-browser.h 	\
 		rb-daap-connection.c 	\
 		rb-daap-connection.h 	\
 		rb-daap-src.c 		\
 		rb-daap-src.h		\
 		rb-daap-dialog.c	\
-		rb-daap-dialog.h
+		rb-daap-dialog.h	\
+		$(NULL)
+
+if USE_HOWL
+libdaapsharing_la_SOURCES += \
+		rb-daap-mdns-publisher-howl.c		\
+		rb-daap-mdns-browser-howl.c		\
+		$(NULL)
+else
+libdaapsharing_la_SOURCES += \
+		rb-daap-mdns-publisher-avahi.c		\
+		rb-daap-mdns-browser-avahi.c		\
+		$(NULL)
+endif
+
 endif
 
 INCLUDES =						\
@@ -40,7 +57,19 @@ INCLUDES =						\
 	$(WARN_CFLAGS)					\
 	$(RHYTHMBOX_CFLAGS)				\
 	$(SOUP_CFLAGS)					\
-	$(MDNS_CFLAGS)
+	$(MDNS_CFLAGS)					\
+	$(NULL)
 
 libdaapsharing_la_LDFLAGS = -export-dynamic
 
+BUILT_SOURCES = rb-daap-marshal.c rb-daap-marshal.h
+
+CLEAN_FILES = $(BUILT_SOURCES)
+
+rb-daap-marshal.c: rb-daap-marshal.list
+	@GLIB_GENMARSHAL@ --prefix=rb_daap_marshal $(srcdir)/rb-daap-marshal.list --header --body > rb-daap-marshal.c
+
+rb-daap-marshal.h: rb-daap-marshal.list
+	@GLIB_GENMARSHAL@ --prefix=rb_daap_marshal $(srcdir)/rb-daap-marshal.list --header > rb-daap-marshal.h
+
+EXTRA_DIST = rb-daap-marshal.list
Index: daapsharing/rb-daap-connection.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/daapsharing/rb-daap-connection.c,v
retrieving revision 1.15
diff -p -u -r1.15 rb-daap-connection.c
--- daapsharing/rb-daap-connection.c	27 Jan 2006 10:00:26 -0000	1.15
+++ daapsharing/rb-daap-connection.c	27 Jan 2006 23:35:20 -0000
@@ -1,4 +1,5 @@
-/*
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
  *  Implementation of DAAP (iTunes Music Sharing) hashing, parsing, connection
  *
  *  Copyright (C) 2004,2005 Charles Schmidt <cschmidt2@emich.edu>
@@ -19,25 +20,35 @@
  *
  */
 
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <math.h>
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include <libsoup/soup.h>
+#include <libsoup/soup-connection.h>
+#include <libsoup/soup-session-sync.h>
+#include <libsoup/soup-uri.h>
+
 #include "rb-daap-connection.h"
 #include "rb-daap-structure.h"
 #include "rb-daap-dialog.h"
 
-#include <libgnome/gnome-i18n.h>
 #include "rb-debug.h"
 
-#ifdef HAVE_LIBZ
-#include <zlib.h>
-#endif
+#define RB_DAAP_USER_AGENT "iTunes/4.6 (Windows; N)"
 
 /* hashing - based on/copied from libopendaap
  * Copyright (c) 2004 David Hammerton
  */
 
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-
 typedef struct {
     guint32 buf[4];
     guint32 bits[2];
@@ -517,15 +528,6 @@ rb_daap_hash_generate (short version_maj
 
 
 /* connection */
-#include <math.h>
-#include <libsoup/soup.h>
-#include <libsoup/soup-connection.h>
-#include <libsoup/soup-session-sync.h>
-
-#include <libsoup/soup-uri.h>
-
-#define RB_DAAP_USER_AGENT "iTunes/4.6 (Windows; N)"
-
 
 static GObject * rb_daap_connection_constructor (GType type, guint n_construct_properties,
 						 GObjectConstructParam *construct_properties);
@@ -544,16 +546,18 @@ static void rb_daap_connection_state_don
 
 
 G_DEFINE_TYPE (RBDAAPConnection, rb_daap_connection, G_TYPE_OBJECT)
-#define DAAP_CONNECTION_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_CONNECTION, RBDaapConnectionPrivate))
+
+#define RB_DAAP_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_CONNECTION, RBDAAPConnectionPrivate))
 
 typedef void (*RBDAAPResponseHandler) (RBDAAPConnection *connection,
 				       guint status,
 				       GNode *structure);
 
-typedef struct {
-	gchar *name;
+struct RBDAAPConnectionPrivate {
+	char *name;
 	gboolean password_protected;
-	gchar *password;
+	char *username;
+	char *password;
 	char *host;
 	guint port;
 	
@@ -592,7 +596,7 @@ typedef struct {
 	gboolean result;
 	RBDAAPConnectionCallback callback;
 	gpointer callback_user_data;
-} RBDaapConnectionPrivate;
+};
 
 
 enum {
@@ -617,7 +621,7 @@ rb_daap_connection_class_init (RBDAAPCon
 	object_class->set_property = rb_daap_connection_set_property;
 	object_class->get_property = rb_daap_connection_get_property;
 
-	g_type_class_add_private (klass, sizeof (RBDaapConnectionPrivate));
+	g_type_class_add_private (klass, sizeof (RBDAAPConnectionPrivate));
 
 	g_object_class_install_property (object_class,
 					 PROP_DB,
@@ -679,16 +683,16 @@ rb_daap_connection_class_init (RBDAAPCon
 static void
 rb_daap_connection_init (RBDAAPConnection *connection)
 {
+	connection->priv = RB_DAAP_CONNECTION_GET_PRIVATE (connection);
 
+	connection->priv->username = g_strdup_printf ("Rhythmbox_%s", VERSION);
 }
 
 
-static gchar *
+static char *
 connection_get_password (RBDAAPConnection *connection)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
-
-	return rb_daap_password_dialog_new_run (priv->name);
+	return rb_daap_password_dialog_new_run (connection->priv->name);
 }
 
 
@@ -700,7 +704,7 @@ build_message (RBDAAPConnection *connect
 	       gint req_id, 
 	       gboolean send_close)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	SoupMessage *message = NULL;
 	SoupUri *uri = NULL;
 	
@@ -718,8 +722,9 @@ build_message (RBDAAPConnection *connect
 	soup_message_add_header (message->request_headers, "Accept-Encoding",		"gzip");
 #endif
 	soup_message_add_header (message->request_headers, "Client-DAAP-Access-Index", 	"2");
+
 	if (priv->password_protected) {
-		gchar *h = g_strconcat ("Basic ", priv->password, NULL);
+		char *h = g_strdup_printf ("Basic %s", priv->password);
 		
 		soup_message_add_header (message->request_headers, "Authorization", h);
 		g_free (h);
@@ -768,13 +773,26 @@ static void
 http_response_handler (SoupMessage *message,
 		       RBDAAPConnection *connection)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
-	GNode *structure = NULL;
-	guint status = message->status_code;
-	char *response = message->response.body;
-	int response_length = message->response.length;
-	const char *encoding_header = NULL;
+	RBDAAPConnectionPrivate *priv;
+	GNode *structure;
+	guint status;
+	char *response;
+	int response_length;
+	const char *encoding_header;
+
+	priv = connection->priv;
+	structure = NULL;
+	status = message->status_code;
+	response = message->response.body;
+	response_length = message->response.length;
+	encoding_header = NULL;
 
+	rb_debug ("Received response from http://%s:%d/%s: %d, %s\n", 
+		  priv->base_uri->host,
+		  priv->base_uri->port,
+		  priv->base_uri->path, 
+		  message->status_code,
+		  message->reason_phrase);
 
 	if (response_length >= G_MAXUINT/4 - 1) {
 		/* If response_length is too big, 
@@ -783,17 +801,17 @@ http_response_handler (SoupMessage *mess
 		status = SOUP_STATUS_MALFORMED;
 	}
 
-	if (message->response_headers)
+	if (message->response_headers) {
 		encoding_header = soup_message_get_header (message->response_headers, "Content-Encoding");
+	}
 
-	if (SOUP_STATUS_IS_SUCCESSFUL (status) && encoding_header && strcmp(encoding_header, "gzip") == 0) {
+	if (SOUP_STATUS_IS_SUCCESSFUL (status) && encoding_header && strcmp (encoding_header, "gzip") == 0) {
 #ifdef HAVE_LIBZ
 		z_stream stream;
 		char *new_response;
 		unsigned int factor = 4;
 		unsigned int unc_size = response_length * factor;
 
-
 		stream.next_in = (unsigned char *)response;
 		stream.avail_in = response_length;
 		stream.total_in = 0;
@@ -880,7 +898,8 @@ http_response_handler (SoupMessage *mess
 			  priv->base_uri->host,
 			  priv->base_uri->port,
 			  priv->base_uri->path, 
-			  message->status_code, message->reason_phrase);
+			  message->status_code,
+			  message->reason_phrase);
 	}
 
 	if (priv->response_handler) {
@@ -905,7 +924,7 @@ http_get (RBDAAPConnection *connection, 
 	  gboolean send_close,
 	  RBDAAPResponseHandler handler)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	SoupMessage *message;
        
 	message = build_message (connection, path, need_hash, version, req_id, send_close);
@@ -953,7 +972,7 @@ entry_set_string_prop (RhythmDB *db, 
 static void
 handle_server_info (RBDAAPConnection *connection, guint status, GNode *structure)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	RBDAAPItem *item = NULL;
 
 	if (!SOUP_STATUS_IS_SUCCESSFUL (status) || structure == NULL) {
@@ -975,7 +994,7 @@ handle_server_info (RBDAAPConnection *co
 static void
 handle_login (RBDAAPConnection *connection, guint status, GNode *structure)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	RBDAAPItem *item = NULL;
 
 	if (status == SOUP_STATUS_UNAUTHORIZED || status == SOUP_STATUS_FORBIDDEN) {
@@ -1003,7 +1022,7 @@ handle_login (RBDAAPConnection *connecti
 static void
 handle_update (RBDAAPConnection *connection, guint status, GNode *structure)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	RBDAAPItem *item;
 
 	if (structure == NULL || SOUP_STATUS_IS_SUCCESSFUL (status) == FALSE) {
@@ -1026,7 +1045,7 @@ handle_update (RBDAAPConnection *connect
 static void 
 handle_database_info (RBDAAPConnection *connection, guint status, GNode *structure)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	RBDAAPItem *item = NULL;
 	GNode *listing_node;
 	gint n_databases = 0;
@@ -1071,7 +1090,7 @@ handle_database_info (RBDAAPConnection *
 static void
 handle_song_listing (RBDAAPConnection *connection, guint status, GNode *structure)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	RBDAAPItem *item = NULL;
 	GNode *listing_node;
 	gint returned_count;
@@ -1286,7 +1305,7 @@ handle_song_listing (RBDAAPConnection *c
 static void
 handle_playlists (RBDAAPConnection *connection, guint status, GNode *structure)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	GNode *listing_node;
 	gint i;
 	GNode *n;
@@ -1345,7 +1364,7 @@ handle_playlists (RBDAAPConnection *conn
 static void
 handle_playlist_entries (RBDAAPConnection *connection, guint status, GNode *structure)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	RBDAAPPlaylist *playlist;
 	GNode *listing_node;
 	GNode *node;
@@ -1425,17 +1444,18 @@ rb_daap_connection_new (const gchar *nam
 }
 
 static GObject *
-rb_daap_connection_constructor (GType type, guint n_construct_properties,
+rb_daap_connection_constructor (GType type,
+				guint n_construct_properties,
 				GObjectConstructParam *construct_properties)
 {
 	RBDAAPConnection *connection;
-	RBDaapConnectionPrivate *priv;
+	RBDAAPConnectionPrivate *priv;
 	gchar *path = NULL;
 
 	connection = RB_DAAP_CONNECTION (G_OBJECT_CLASS(rb_daap_connection_parent_class)->
 			constructor (type, n_construct_properties, construct_properties));
 
-	priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	priv = connection->priv;
 	priv->result = TRUE;
 
 	rb_debug ("Creating new DAAP connection to %s:%d", priv->host, priv->port);
@@ -1464,7 +1484,7 @@ rb_daap_connection_logout (RBDAAPConnect
 			   RBDAAPConnectionCallback callback,
 			   gpointer user_data)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	int old_state = priv->state;
 
 	if (priv->state == DAAP_LOGOUT)
@@ -1487,7 +1507,7 @@ rb_daap_connection_logout (RBDAAPConnect
 static void
 rb_daap_connection_state_done (RBDAAPConnection *connection, gboolean result)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 
 	if (result == FALSE) {
 		priv->state = DAAP_DONE;
@@ -1532,7 +1552,7 @@ rb_daap_connection_state_done (RBDAAPCon
 static void
 rb_daap_connection_do_something (RBDAAPConnection *connection)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	char *path;
 
 	switch (priv->state) {
@@ -1682,16 +1702,16 @@ rb_daap_connection_get_headers (RBDAAPCo
 				const gchar *uri, 
 				gint64 bytes)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
+	RBDAAPConnectionPrivate *priv = connection->priv;
 	GString *headers;
-	gchar hash[33] = {0};
-	gchar *norb_daap_uri = (gchar *)uri;
-	gchar *s;
+	char hash[33] = {0};
+	char *norb_daap_uri = (char *)uri;
+	char *s;
 	
 	priv->request_id++;
 	
-	if (g_strncasecmp (uri,"daap://",7) == 0) {
-		norb_daap_uri = strstr (uri,"/data");
+	if (g_strncasecmp (uri, "daap://", 7) == 0) {
+		norb_daap_uri = strstr (uri, "/data");
 	}
 
 	rb_daap_hash_generate ((short)floorf (priv->daap_version), 
@@ -1710,8 +1730,16 @@ rb_daap_connection_get_headers (RBDAAPCo
 				"Client-DAAP-Request-ID: %d\r\n"
 				"Connection: close\r\n", 
 				hash, priv->request_id);
+
 	if (priv->password_protected) {
-		g_string_append_printf (headers, "Authentication: Basic %s\r\n", priv->password);
+		char *user_pass;
+		char *token;
+
+		user_pass = g_strdup_printf ("%s:%s", priv->username, priv->password);
+		token = soup_base64_encode (user_pass, strlen (user_pass));
+		g_string_append_printf (headers, "Authentication: Basic %s\r\n", token);
+		g_free (token);
+		g_free (user_pass);
 	}
 
 	if (bytes != 0) {
@@ -1727,16 +1755,14 @@ rb_daap_connection_get_headers (RBDAAPCo
 GSList * 
 rb_daap_connection_get_playlists (RBDAAPConnection *connection)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (connection);
-
-	return priv->playlists;
+	return connection->priv->playlists;
 }
 
 
 static void 
 rb_daap_connection_dispose (GObject *object)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (object);
+	RBDAAPConnectionPrivate *priv = RB_DAAP_CONNECTION (object)->priv;
 	GSList *l;
 
 	g_assert (priv->callback == NULL);
@@ -1746,6 +1772,11 @@ rb_daap_connection_dispose (GObject *obj
 		priv->name = NULL;
 	}
 	
+	if (priv->username) {
+		g_free (priv->username);
+		priv->username = NULL;
+	}
+
 	if (priv->password) {
 		g_free (priv->password);
 		priv->password = NULL;
@@ -1804,10 +1835,9 @@ rb_daap_connection_set_property (GObject
 				 const GValue *value,
 				 GParamSpec *pspec)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (object);
+	RBDAAPConnectionPrivate *priv = RB_DAAP_CONNECTION (object)->priv;
 
-	switch (prop_id)
-	{
+	switch (prop_id) {
 	case PROP_NAME:
 		g_free (priv->name);
 		priv->name = g_value_dup_string (value);
@@ -1846,10 +1876,9 @@ rb_daap_connection_get_property (GObject
 				 GValue *value,
 				 GParamSpec *pspec)
 {
-	RBDaapConnectionPrivate *priv = DAAP_CONNECTION_GET_PRIVATE (object);
+	RBDAAPConnectionPrivate *priv = RB_DAAP_CONNECTION (object)->priv;
 
-	switch (prop_id)
-	{
+	switch (prop_id) {
 	case PROP_DB:
 		g_value_set_object (value, priv->db);
 		break;
Index: daapsharing/rb-daap-connection.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/daapsharing/rb-daap-connection.h,v
retrieving revision 1.4
diff -p -u -r1.4 rb-daap-connection.h
--- daapsharing/rb-daap-connection.h	22 Nov 2005 04:14:16 -0000	1.4
+++ daapsharing/rb-daap-connection.h	27 Jan 2006 23:35:20 -0000
@@ -43,9 +43,11 @@ typedef struct {
 #define RB_IS_DAAP_CONNECTION_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DAAP_CONNECTION))
 #define RB_DAAP_CONNECTION_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DAAP_CONNECTION, RBDAAPConnectionClass))
 
+typedef struct RBDAAPConnectionPrivate RBDAAPConnectionPrivate;
 
 typedef struct {
 	GObject parent;
+	RBDAAPConnectionPrivate *priv;
 } RBDAAPConnection;
 
 typedef struct {
Index: daapsharing/rb-daap-dialog.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/daapsharing/rb-daap-dialog.c,v
retrieving revision 1.3
diff -p -u -r1.3 rb-daap-dialog.c
--- daapsharing/rb-daap-dialog.c	11 Sep 2005 10:31:45 -0000	1.3
+++ daapsharing/rb-daap-dialog.c	27 Jan 2006 23:35:20 -0000
@@ -1,4 +1,5 @@
-/*
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
  *  Implementation of DAAP (iTunes Music Sharing) dialogs 
  *  (password & name collision)
  *
@@ -20,12 +21,16 @@
  *
  */
 
-#include "rb-daap-dialog.h"
-#include <gtk/gtk.h>
-#include <libgnome/gnome-i18n.h>
-#include <glib/gprintf.h>
+#include "config.h"
+
 #include <string.h>
 
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+#include <gtk/gtk.h>
+
+#include "rb-daap-dialog.h"
+
 static gchar *
 encode_base64 (const gchar *string)
 {
@@ -101,7 +106,8 @@ rb_daap_password_dialog_new_run (const g
 					      GTK_RESPONSE_OK,
 					      NULL);
 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-	
+	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
 	hbox = gtk_hbox_new (FALSE, 6);
 	gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
 	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);
@@ -178,7 +184,8 @@ rb_daap_collision_dialog_new_run (const 
 					      GTK_RESPONSE_OK,
 					      NULL);
 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-	
+	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
 	hbox = gtk_hbox_new (FALSE, 6);
 	gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
 	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);
Index: daapsharing/rb-daap-share.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/daapsharing/rb-daap-share.c,v
retrieving revision 1.13
diff -p -u -r1.13 rb-daap-share.c
--- daapsharing/rb-daap-share.c	8 Jan 2006 11:05:23 -0000	1.13
+++ daapsharing/rb-daap-share.c	27 Jan 2006 23:35:20 -0000
@@ -20,7 +20,7 @@
  *
  */
 
-#include <config.h>
+#include "config.h"
 
 #include <time.h>
 #include <string.h>
@@ -32,12 +32,13 @@
 #include <libsoup/soup-message.h>
 #include <libsoup/soup-uri.h>
 #include <libsoup/soup-server.h>
+#include <libsoup/soup-server-auth.h>
 #include <libsoup/soup-server-message.h>
 #include <libgnomevfs/gnome-vfs.h>
 
 #include "rb-daap-share.h"
 #include "rb-daap-structure.h"
-#include "rb-daap-mdns.h"
+#include "rb-daap-mdns-publisher.h"
 #include "rb-daap-dialog.h"
 
 #include "rb-playlist-source.h"
@@ -53,9 +54,11 @@ static void rb_daap_share_get_property  
 					 GValue *value,
 				 	 GParamSpec *pspec);
 static void rb_daap_share_dispose	(GObject *object);
-
-static void rb_daap_share_start_publish (RBDAAPShare *share);
-static void rb_daap_share_stop_publish  (RBDAAPShare *share);
+static void rb_daap_share_maybe_restart (RBDAAPShare *share);
+static gboolean rb_daap_share_publish_start (RBDAAPShare *share);
+static gboolean rb_daap_share_publish_stop  (RBDAAPShare *share);
+static gboolean rb_daap_share_server_start  (RBDAAPShare *share);
+static gboolean rb_daap_share_server_stop   (RBDAAPShare *share);
 static void rb_daap_share_playlist_created (RBPlaylistManager *mgr,
 					    RBSource *playlist,
 					    RBDAAPShare *share);
@@ -66,20 +69,27 @@ static void rb_daap_share_playlist_destr
 static void rb_daap_share_forget_playlist (gpointer data,
 					   RBDAAPShare *share);
 
-
-#define CONF_NAME CONF_PREFIX "/sharing/share_name"
 #define STANDARD_DAAP_PORT 3689
 
 /* HTTP chunk size used to send files to clients */
 #define DAAP_SHARE_CHUNK_SIZE	16384
 
+typedef enum {
+	RB_DAAP_SHARE_AUTH_METHOD_NONE              = 0,
+	RB_DAAP_SHARE_AUTH_METHOD_NAME_AND_PASSWORD = 1,
+	RB_DAAP_SHARE_AUTH_METHOD_PASSWORD          = 2
+} RBDAAPShareAuthMethod;
+
 struct RBDAAPSharePrivate {
 	gchar *name;
 	guint port;
+	char *password;
+	RBDAAPShareAuthMethod auth_method;
 
 	/* mdns/dns-sd publishing things */
+	gboolean server_active;
 	gboolean published;
-	RBDAAPmDNSPublisher publisher;
+	RBDaapMdnsPublisher *publisher;
 
 	/* http server things */
 	SoupServer *server;
@@ -111,6 +121,7 @@ typedef struct {
 enum {
 	PROP_0,
 	PROP_NAME,
+	PROP_PASSWORD,
 	PROP_DB,
 	PROP_PLAYLIST_MANAGER
 };
@@ -136,6 +147,13 @@ rb_daap_share_class_init (RBDAAPShareCla
 							      NULL,
 							      G_PARAM_READWRITE));
 	g_object_class_install_property (object_class,
+					 PROP_PASSWORD,
+					 g_param_spec_string ("password",
+							      "Authentication password",
+							      "Authentication password",
+							      NULL,
+							      G_PARAM_READWRITE));
+	g_object_class_install_property (object_class,
 					 PROP_DB,
 					 g_param_spec_object ("db",
 							      "RhythmDB",
@@ -154,11 +172,126 @@ rb_daap_share_class_init (RBDAAPShareCla
 }
 
 static void
+rb_daap_share_set_name (RBDAAPShare *share,
+			const char  *name)
+{
+	GError *error;
+	gboolean res;
+
+	g_return_if_fail (share != NULL);
+
+	g_free (share->priv->name);
+	share->priv->name = g_strdup (name);
+
+	error = NULL;
+	res = rb_daap_mdns_publisher_set_name (share->priv->publisher, name, &error);
+	if (error != NULL) {
+		g_warning ("Unable to change MDNS service name: %s", error->message);
+		g_error_free (error);
+	}
+}
+
+static void
+published_cb (RBDaapMdnsPublisher *publisher,
+	      const char          *name,
+	      RBDAAPShare         *share)
+{
+	if (share->priv->name == NULL || name == NULL) {
+		return;
+	}
+
+	if (strcmp (name, share->priv->name) == 0) {
+		rb_debug ("mDNS publish successful");
+		share->priv->published = TRUE;
+	}
+}
+
+static void
+name_collision_cb (RBDaapMdnsPublisher *publisher,
+		   const char          *name,
+		   RBDAAPShare         *share)
+{
+	char *new_name;
+
+	if (share->priv->name == NULL || name == NULL) {
+		return;
+	}
+
+	if (strcmp (name, share->priv->name) == 0) {
+		rb_debug ("Duplicate share name on mDNS");
+		
+		new_name = rb_daap_collision_dialog_new_run (share->priv->name);
+
+		rb_daap_share_set_name (share, new_name);
+		g_free (new_name);
+	}
+	
+	return;
+}
+
+static void
 rb_daap_share_init (RBDAAPShare *share)
 {
 	share->priv = RB_DAAP_SHARE_GET_PRIVATE (share);
 
 	share->priv->revision_number = 5;
+
+	share->priv->auth_method = RB_DAAP_SHARE_AUTH_METHOD_NONE;
+	share->priv->publisher = rb_daap_mdns_publisher_new ();
+	g_signal_connect_object (share->priv->publisher,
+				 "published",
+				 G_CALLBACK (published_cb),
+				 share, 0);
+	g_signal_connect_object (share->priv->publisher,
+				 "name-collision",
+				 G_CALLBACK (name_collision_cb),
+				 share, 0);
+
+}
+
+static void
+rb_daap_share_set_password (RBDAAPShare *share,
+			    const char  *password)
+{
+	g_return_if_fail (share != NULL);
+
+	if (share->priv->password && password &&
+	    strcmp (password, share->priv->password) == 0) {
+		return;
+	}
+
+	g_free (share->priv->password);
+	share->priv->password = g_strdup (password);
+	if (password != NULL) {
+		share->priv->auth_method = RB_DAAP_SHARE_AUTH_METHOD_PASSWORD;
+	} else {
+		share->priv->auth_method = RB_DAAP_SHARE_AUTH_METHOD_NONE;
+	}
+
+	rb_daap_share_maybe_restart (share);
+}
+
+static void
+rb_daap_share_set_playlist_manager (RBDAAPShare       *share,
+				    RBPlaylistManager *playlist_manager)
+{
+	GList *playlists;
+
+	g_return_if_fail (share != NULL);
+
+	share->priv->playlist_manager = playlist_manager;
+
+	g_signal_connect_object (G_OBJECT (share->priv->playlist_manager),
+				 "playlist_added",
+				 G_CALLBACK (rb_daap_share_playlist_created),
+				 share, 0);
+
+	/* Currently, there are no playlists when this object is created, but in
+	 * case it changes..
+	 */
+	playlists = rb_playlist_manager_get_playlists (share->priv->playlist_manager);
+	g_list_foreach (playlists, (GFunc) rb_daap_share_process_playlist, share);
+	g_list_free (playlists);
 }
 
 static void
@@ -170,52 +303,17 @@ rb_daap_share_set_property (GObject *obj
 	RBDAAPShare *share = RB_DAAP_SHARE (object);
 
 	switch (prop_id) {
-	case PROP_NAME: {
-		gboolean restart_publish = FALSE;
-		const char *name = g_value_get_string (value);
-
-		/* check if the name hasn't really changed */
-		if (share->priv->name && name &&
-		    strcmp (name, share->priv->name) == 0) {
-			return;
-		}
-	
-		if (share->priv->name) {
-			g_free (share->priv->name);
-
-			if (share->priv->published) {
-				rb_daap_share_stop_publish (share);
-				restart_publish = TRUE;
-			}
-		}
-
-		share->priv->name = g_strdup (name);
-
-		if (restart_publish) {
-			rb_daap_share_start_publish (share);
-		}
-
+	case PROP_NAME:
+		rb_daap_share_set_name (share, g_value_get_string (value));
+		break;
+	case PROP_PASSWORD:
+		rb_daap_share_set_password (share, g_value_get_string (value));
 		break;
-	}
 	case PROP_DB:
 		share->priv->db = g_value_get_object (value);
 		break;
 	case PROP_PLAYLIST_MANAGER:
-		{
-			GList *playlists;
-			share->priv->playlist_manager = g_value_get_object (value);
-			g_signal_connect_object (G_OBJECT (share->priv->playlist_manager),
-						 "playlist_added",
-						 G_CALLBACK (rb_daap_share_playlist_created),
-						 share, 0);
-
-			/* Currently, there are no playlists when this object is created, but in
-			 * case it changes..
-			 */
-			playlists = rb_playlist_manager_get_playlists (share->priv->playlist_manager);
-			g_list_foreach (playlists, (GFunc) rb_daap_share_process_playlist, share);
-			g_list_free (playlists);
-		}
+		rb_daap_share_set_playlist_manager (share, g_value_get_object (value));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -235,6 +333,9 @@ rb_daap_share_get_property (GObject *obj
 	case PROP_NAME:
 		g_value_set_string (value, share->priv->name);
 		break;
+	case PROP_PASSWORD:
+		g_value_set_string (value, share->priv->password);
+		break;
 	case PROP_DB:
 		g_value_set_object (value, share->priv->db);
 		break;
@@ -318,23 +419,28 @@ rb_daap_share_forget_playlist (gpointer 
 			     share);
 }
 
-
 static void
 rb_daap_share_dispose (GObject *object)
 {
 	RBDAAPShare *share = RB_DAAP_SHARE (object);
 
 	if (share->priv->published) {
-		rb_daap_share_stop_publish (share);
+		rb_daap_share_publish_stop (share);
 	}
 
-	if (share->priv) {
-		g_free (share->priv->name);
-		g_object_unref (share->priv->db);
-		g_object_unref (share->priv->playlist_manager);
+	if (share->priv->server_active) {
+		rb_daap_share_server_stop (share);
+	}
+
+	g_free (share->priv->name);
+	g_object_unref (share->priv->db);
+	g_object_unref (share->priv->playlist_manager);
 		
-		g_list_foreach (share->priv->playlist_ids, (GFunc) rb_daap_share_forget_playlist, share);
-		g_list_foreach (share->priv->playlist_ids, (GFunc) g_free, NULL);
+	g_list_foreach (share->priv->playlist_ids, (GFunc) rb_daap_share_forget_playlist, share);
+	g_list_foreach (share->priv->playlist_ids, (GFunc) g_free, NULL);
+
+	if (share->priv->publisher) {
+		g_object_unref (share->priv->publisher);
 	}
 
 	G_OBJECT_CLASS (rb_daap_share_parent_class)->dispose (object);
@@ -342,7 +448,8 @@ rb_daap_share_dispose (GObject *object)
 
 
 RBDAAPShare *
-rb_daap_share_new (const gchar *name,
+rb_daap_share_new (const char *name,
+		   const char *password,
 		   RhythmDB *db,
 		   RBPlaylistManager *playlist_manager)
 {
@@ -350,10 +457,13 @@ rb_daap_share_new (const gchar *name,
 
 	share = RB_DAAP_SHARE (g_object_new (RB_TYPE_DAAP_SHARE,
 					     "name", name,
+					     "password", password,
 					     "db", db,
 					     "playlist-manager", playlist_manager,
 					     NULL));
-	rb_daap_share_start_publish (share);
+
+	rb_daap_share_server_start (share);
+	rb_daap_share_publish_start (share);
 
 	return share;
 }
@@ -387,7 +497,7 @@ message_set_from_rb_daap_structure (Soup
 	resp = rb_daap_structure_serialize (structure, &length);
 
 	if (resp == NULL) {
-		g_print ("serialize gave us null?\n");
+		rb_debug ("serialize gave us null?\n");
 		return;
 	}
 
@@ -444,7 +554,7 @@ server_info_cb (RBDAAPShare *share, 
 	 * 3.0 is 2/3
 	 */
 	rb_daap_structure_add (msrv, RB_DAAP_CC_MINM, share->priv->name);
-	rb_daap_structure_add (msrv, RB_DAAP_CC_MSAU, 0);
+	rb_daap_structure_add (msrv, RB_DAAP_CC_MSAU, share->priv->auth_method);
 	/* authentication method
 	 * 0 is nothing
 	 * 1 is name & password
@@ -528,6 +638,15 @@ login_cb (RBDAAPShare *share, 
 	rb_daap_structure_destroy (mlog);
 }
 
+static void 
+logout_cb (RBDAAPShare *share, 
+	   SoupMessage *message)
+{
+	/* FIXME: check session id ? */
+	soup_message_set_status (message, SOUP_STATUS_NO_CONTENT);
+	soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (message), SOUP_TRANSFER_CONTENT_LENGTH);
+}
+
 static void
 update_cb (RBDAAPShare *share,
 	   SoupMessage *message)
@@ -541,7 +660,7 @@ update_cb (RBDAAPShare *share,
 	revision_number_position = strstr (path, "revision-number=");
 
 	if (revision_number_position == NULL) {
-		g_print ("client asked for an update without a revision number?!?\n");
+		rb_debug ("client asked for an update without a revision number?!?\n");
 		g_free (path);
 		return;
 	}
@@ -772,7 +891,7 @@ add_entry_to_mlcl (RhythmDBEntry *entry,
 	if (client_requested (mb->bits, SONG_TRACK_NUMBER))
 		rb_daap_structure_add (mlit, RB_DAAP_CC_ASTN, (gint32) rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER));
 	if (client_requested (mb->bits, SONG_USER_RATING))
-		rb_daap_structure_add (mlit, RB_DAAP_CC_ASUR, 0); // fixme
+		rb_daap_structure_add (mlit, RB_DAAP_CC_ASUR, 0); /* FIXME */
 	if (client_requested (mb->bits, SONG_YEAR))
 		rb_daap_structure_add (mlit, RB_DAAP_CC_ASYR, 0);
 	
@@ -910,7 +1029,7 @@ databases_cb (RBDAAPShare *share, 
 {
 	gchar *path;
 	gchar *rest_of_path;
-//	guint revision_number;
+	/*guint revision_number;*/
 	
 	path = soup_uri_to_string (soup_message_get_uri (message), TRUE);
 
@@ -1112,13 +1231,13 @@ databases_cb (RBDAAPShare *share, 
 			GnomeVFSFileOffset range;
 			gchar *content_range;
 			
-			s = range_header + 6; // bytes=
+			s = range_header + 6; /* bytes= */
 			range = atoll (s);
 			
 			result = gnome_vfs_seek (handle, GNOME_VFS_SEEK_START, range);
 			
 			if (result != GNOME_VFS_OK) {
-				g_message ("Error seeking: %s", gnome_vfs_result_to_string (result));
+				g_warning ("Error seeking: %s", gnome_vfs_result_to_string (result));
 				soup_message_set_status (message, SOUP_STATUS_INTERNAL_SERVER_ERROR);
 				goto out;
 			}
@@ -1140,7 +1259,7 @@ databases_cb (RBDAAPShare *share, 
 		soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (message), SOUP_TRANSFER_CHUNKED);
 
 	} else {
-		g_print ("unhandled: %s\n", path);
+		rb_debug ("unhandled: %s\n", path);
 	}
 	
 out:
@@ -1159,6 +1278,7 @@ static const struct DAAPPath paths_to_fu
 	{"/server-info", 12, server_info_cb},
 	{"/content-codes", 14, content_codes_cb},
 	{"/login", 6, login_cb},
+	{"/logout", 7, logout_cb},
 	{"/update", 7, update_cb},
 	{"/databases", 10, databases_cb}
 };
@@ -1172,6 +1292,7 @@ server_cb (SoupServerContext *context,
 	guint i;
 
 	path = soup_uri_to_string (soup_message_get_uri (message), TRUE);
+	rb_debug ("request for %s", path);
 
 	for (i = 0; i < G_N_ELEMENTS (paths_to_functions); i++) {
 		if (g_ascii_strncasecmp (paths_to_functions[i].path, path, paths_to_functions[i].path_length) == 0) {
@@ -1233,36 +1354,54 @@ db_entry_changed_cb (RhythmDB *db,
 		db_entry_added_cb (db, entry, share);
 }
 
+static gboolean
+soup_auth_callback (SoupServerAuthContext *auth_ctx,
+                    SoupServerAuth        *auth,
+                    SoupMessage           *message,
+                    RBDAAPShare           *share)
+{
+	const char *username;
+	gboolean    allowed;
+	char       *path;
 
-static gchar *
-publish_cb (RBDAAPmDNSPublisher publisher,
-	    RBDAAPmDNSPublisherStatus status,
-	    RBDAAPShare *share)
-{
-	switch (status) {
-		case RB_DAAP_MDNS_PUBLISHER_STARTED:
-			rb_debug ("mDNS publish successful");
-			share->priv->published = TRUE;
-			break;
-		case RB_DAAP_MDNS_PUBLISHER_COLLISION: {
-			gchar *new_name;
-		
-			rb_debug ("Duplicate share name on mDNS");
-		
-			new_name = rb_daap_collision_dialog_new_run (share->priv->name);
-			return new_name;
+	path = soup_uri_to_string (soup_message_get_uri (message), TRUE);
+	rb_debug ("Auth request for %s", path);
+
+	if (auth == NULL) {
+
+		/* This is to workaround libsoup looking up handlers by directory.
+		   We require auth for "/databases?" but not "/databases/" */
+		if (g_str_has_prefix (path, "/databases/")) {
+
+			/* FIXME: need to check for valid session id */
+
+			allowed = TRUE;
+			goto done;
 		}
-	
+
+		rb_debug ("Auth DENIED: information not provided");
+		allowed = FALSE;
+		goto done;
 	}
 
-	return NULL;
+	username = soup_server_auth_get_user (auth);
+	rb_debug ("Auth request for user: %s", username);
+
+	allowed = soup_server_auth_check_passwd (auth, share->priv->password);
+	rb_debug ("Auth request: %s", allowed ? "ALLOWED" : "DENIED");
+
+ done:
+	g_free (path);
+
+	return allowed;
 }
 
-static void
-rb_daap_share_start_publish (RBDAAPShare *share)
+static gboolean
+rb_daap_share_server_start (RBDAAPShare *share)
 {
-	gint port = STANDARD_DAAP_PORT;
-	gboolean ret;
+	int                   port = STANDARD_DAAP_PORT;
+	gboolean              password_required;
+	SoupServerAuthContext auth_ctx = { 0 };
 
 	share->priv->server = soup_server_new (SOUP_SERVER_PORT, port, NULL);
 	if (share->priv->server == NULL) {
@@ -1271,12 +1410,40 @@ rb_daap_share_start_publish (RBDAAPShare
 
 		if (share->priv->server == NULL) {
 			g_warning ("Unable to start music sharing server");
-			return;
+			return FALSE;
 		}
 	}
 
-	share->priv->port = soup_server_get_port (share->priv->server);
-	rb_debug ("Started DAAP server on port %d", port);
+	share->priv->port = (guint)soup_server_get_port (share->priv->server);
+	rb_debug ("Started DAAP server on port %u", share->priv->port);
+
+	password_required = (share->priv->auth_method != RB_DAAP_SHARE_AUTH_METHOD_NONE);
+
+	if (password_required) {
+		auth_ctx.types = SOUP_AUTH_TYPE_BASIC;
+		auth_ctx.callback = (SoupServerAuthCallbackFn)soup_auth_callback;
+		auth_ctx.user_data = share;
+		auth_ctx.basic_info.realm = "Music Sharing";
+
+		soup_server_add_handler (share->priv->server, 
+					 "/login",
+					 &auth_ctx, 
+					 (SoupServerCallbackFn)server_cb,
+					 NULL,
+					 share);
+		soup_server_add_handler (share->priv->server, 
+					 "/update",
+					 &auth_ctx, 
+					 (SoupServerCallbackFn)server_cb,
+					 NULL,
+					 share);
+		soup_server_add_handler (share->priv->server,
+					 "/databases",
+					 &auth_ctx, 
+					 (SoupServerCallbackFn)server_cb,
+					 NULL,
+					 share);
+	}
 
 	soup_server_add_handler (share->priv->server, 
 				 NULL, 
@@ -1286,18 +1453,6 @@ rb_daap_share_start_publish (RBDAAPShare
 				 share);
 	soup_server_run_async (share->priv->server);
 	
-	ret = rb_daap_mdns_publish (&(share->priv->publisher),
-				    share->priv->name,
-				    share->priv->port,
-				    (RBDAAPmDNSPublisherCallback) publish_cb,
-				    share);
-	
-	if (ret == FALSE) {
-		g_warning ("Unable to notify network of music sharing");
-		return;
-	}
-
-	rb_debug ("Published DAAP server information to mdns");
 
 	share->priv->id_to_entry = g_hash_table_new (NULL, NULL);
 	share->priv->entry_to_id = g_hash_table_new (NULL, NULL);
@@ -1317,10 +1472,14 @@ rb_daap_share_start_publish (RBDAAPShare
 							  "entry-changed",
 							  G_CALLBACK (db_entry_changed_cb),
 							  share);
+
+	share->priv->server_active = TRUE;
+
+	return TRUE;
 }
 
-static void
-rb_daap_share_stop_publish (RBDAAPShare *share)
+static gboolean
+rb_daap_share_server_stop (RBDAAPShare *share)
 {
 	if (share->priv->server) {
 		/* FIXME */
@@ -1328,7 +1487,7 @@ rb_daap_share_stop_publish (RBDAAPShare 
 		 * GLib-CRITICAL **: g_main_loop_quit: assertion `loop != NULL' failed
 		 * But it doesn't seem to matter.
 		 */
-//		soup_server_quit (share->priv->server);
+		/*soup_server_quit (share->priv->server); */
 		g_object_unref (G_OBJECT (share->priv->server));
 		share->priv->server = NULL;
 	}
@@ -1358,10 +1517,80 @@ rb_daap_share_stop_publish (RBDAAPShare 
 		share->priv->entry_changed_id = 0;
 	}
 
+	share->priv->server_active = FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+rb_daap_share_publish_start (RBDAAPShare *share)
+{
+	GError  *error;
+	gboolean res;
+	gboolean password_required;
+
+	password_required = (share->priv->auth_method != RB_DAAP_SHARE_AUTH_METHOD_NONE);
+
+	error = NULL;
+	res = rb_daap_mdns_publisher_publish (share->priv->publisher,
+					      share->priv->name,
+					      share->priv->port,
+					      password_required,
+					      &error);
+	
+	if (res == FALSE) {
+		if (error != NULL) {
+			g_warning ("Unable to notify network of music sharing: %s", error->message);
+			g_error_free (error);
+		} else {
+			g_warning ("Unable to notify network of music sharing");
+		}
+		return FALSE;
+	} else {
+		rb_debug ("Published DAAP server information to mdns");
+	}
+
+	return TRUE;
+}
+
+static gboolean
+rb_daap_share_publish_stop (RBDAAPShare *share)
+{
 	if (share->priv->publisher) {
-		rb_daap_mdns_publish_cancel (share->priv->publisher);
-		share->priv->publisher = 0;
+		gboolean res;
+		GError  *error;
+		error = NULL;
+		res = rb_daap_mdns_publisher_withdraw (share->priv->publisher, &error);
+		if (error != NULL) {
+			g_warning ("Unable to withdraw music sharing service: %s", error->message);
+			g_error_free (error);
+		}
+		return res;
 	}
 
 	share->priv->published = FALSE;
+	return TRUE;
+}
+
+static void
+rb_daap_share_restart (RBDAAPShare *share)
+{
+	gboolean res;
+
+	rb_daap_share_server_stop (share);
+	res = rb_daap_share_server_start (share);
+	if (res) {
+		/* To update information just publish again */
+		rb_daap_share_publish_start (share);
+	} else {
+		rb_daap_share_publish_stop (share);
+	}
+}
+
+static void
+rb_daap_share_maybe_restart (RBDAAPShare *share)
+{
+	if (share->priv->published) {
+		rb_daap_share_restart (share);
+	}
 }
Index: daapsharing/rb-daap-share.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/daapsharing/rb-daap-share.h,v
retrieving revision 1.1
diff -p -u -r1.1 rb-daap-share.h
--- daapsharing/rb-daap-share.h	6 Sep 2005 07:15:31 -0000	1.1
+++ daapsharing/rb-daap-share.h	27 Jan 2006 23:35:20 -0000
@@ -47,13 +47,12 @@ typedef struct {
 	GObjectClass parent;
 } RBDAAPShareClass;
 
-GType 
-rb_daap_share_get_type (void);
+GType         rb_daap_share_get_type (void);
 
-RBDAAPShare * 
-rb_daap_share_new (const gchar *name, 
-		   RhythmDB *db, 
-		   RBPlaylistManager *playlist_manager);
+RBDAAPShare * rb_daap_share_new      (const char *name, 
+                                      const char *password,
+                                      RhythmDB *db, 
+                                      RBPlaylistManager *playlist_manager);
 
 #endif /* __RB_DAAP_SHARE_H */
 
Index: daapsharing/rb-daap-sharing.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/daapsharing/rb-daap-sharing.c,v
retrieving revision 1.3
diff -p -u -r1.3 rb-daap-sharing.c
--- daapsharing/rb-daap-sharing.c	15 Sep 2005 05:04:06 -0000	1.3
+++ daapsharing/rb-daap-sharing.c	27 Jan 2006 23:35:20 -0000
@@ -1,4 +1,5 @@
-/*
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
  *  Implmentation of DAAP (iTunes Music Sharing) sharing
  *
  *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
@@ -19,12 +20,13 @@
  *
  */
 
-#include <config.h>
+#include "config.h"
 
-#include <libgnome/gnome-i18n.h>
-#include <glib/gprintf.h>
 #include <string.h>
 
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+
 #include "rb-daap-sharing.h"
 #include "rb-daap-share.h"
 #include "rb-debug.h"
@@ -33,24 +35,25 @@
 #include "eel-gconf-extensions.h"
 #include "rb-preferences.h"
 
-#define CONF_ENABLE_SHARING CONF_PREFIX "/sharing/enable_sharing"
-#define CONF_SHARE_NAME CONF_PREFIX "/sharing/share_name"
-
 static RBDAAPShare *share = NULL;
 static guint enable_sharing_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
+static guint require_password_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 static guint share_name_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
+static guint share_password_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 
 static void 
 create_share (RBShell *shell)
 {
 	RhythmDB *db;
 	RBPlaylistManager *playlist_manager;
-	gchar *name;
+	char *name;
+	char *password;
+	gboolean require_password;
 
 	g_assert (share == NULL);
 	rb_debug ("initialize daap sharing\n");
 
-	name = eel_gconf_get_string (CONF_SHARE_NAME);
+	name = eel_gconf_get_string (CONF_DAAP_SHARE_NAME);
 
 	if (name == NULL || *name == '\0') {
 		const gchar *real_name;
@@ -63,13 +66,22 @@ create_share (RBShell *shell)
 		}
 
 		name = g_strdup_printf (_("%s's Music"), real_name);
-		eel_gconf_set_string (CONF_SHARE_NAME, name);
+		eel_gconf_set_string (CONF_DAAP_SHARE_NAME, name);
 	}
 
 	g_object_get (G_OBJECT (shell), "db", &db, "playlist-manager", &playlist_manager, NULL);
 
-	share = rb_daap_share_new (name, db, playlist_manager);
+	require_password = eel_gconf_get_boolean (CONF_DAAP_REQUIRE_PASSWORD);
+	if (require_password) {
+		password = eel_gconf_get_string (CONF_DAAP_SHARE_PASSWORD);
+	} else {
+		password = NULL;
+	}
+
+	share = rb_daap_share_new (name, password, db, playlist_manager);
+
 	g_free (name);
+	g_free (password);
 }
 
 static void 
@@ -80,31 +92,87 @@ enable_sharing_changed_cb (GConfClient *
 {
 	gboolean enabled;
 
-	enabled = eel_gconf_get_boolean (CONF_ENABLE_SHARING);
+	enabled = eel_gconf_get_boolean (CONF_DAAP_ENABLE_SHARING);
 
 	if (enabled) {
-		if (share == NULL)
+		if (share == NULL) {
 			create_share (shell);
+		}
 	} else {
 		rb_debug ("shutdown daap sharing");
 
-		if (share)
+		if (share) {
 			g_object_unref (share);
+		}
 		share = NULL;
 	}
 }
 
 static void 
+require_password_changed_cb (GConfClient *client,
+			     guint cnxn_id,
+			     GConfEntry *entry,
+			     RBShell *shell)
+{
+	gboolean required;
+	char    *password;
+
+	if (share == NULL) {
+		return;
+	}
+
+	required = eel_gconf_get_boolean (CONF_DAAP_REQUIRE_PASSWORD);
+
+	if (required) {
+		password = eel_gconf_get_string (CONF_DAAP_SHARE_PASSWORD);
+	} else {
+		password = NULL;
+	}
+
+	g_object_set (G_OBJECT (share), "password", password, NULL);
+	g_free (password);
+}
+
+static void 
 share_name_changed_cb (GConfClient *client, 
 		       guint cnxn_id, 
 		       GConfEntry *entry, 
 		       RBShell *shell)
 {
-	if (share) {
-		gchar *name = eel_gconf_get_string (CONF_SHARE_NAME);;
-		g_object_set (G_OBJECT (share), "name", name, NULL);
-		g_free (name);
+	char *name;
+
+	if (share == NULL) {
+		return;
+	}
+
+	name = eel_gconf_get_string (CONF_DAAP_SHARE_NAME);
+	g_object_set (G_OBJECT (share), "name", name, NULL);
+	g_free (name);
+}
+
+static void 
+share_password_changed_cb (GConfClient *client, 
+			   guint cnxn_id, 
+			   GConfEntry *entry, 
+			   RBShell *shell)
+{
+	gboolean require_password;
+	char    *password;
+
+	if (share == NULL) {
+		return;
+	}
+
+	require_password = eel_gconf_get_boolean (CONF_DAAP_REQUIRE_PASSWORD);
+
+	/* Don't do anything unless we require a password */
+	if (! require_password) {
+		return;
 	}
+
+	password = eel_gconf_get_string (CONF_DAAP_SHARE_PASSWORD);
+	g_object_set (G_OBJECT (share), "password", password, NULL);
+	g_free (password);
 }
 
 
@@ -113,18 +181,26 @@ rb_daap_sharing_init (RBShell *shell)
 {
 	g_object_ref (shell);
 
-	if (eel_gconf_get_boolean (CONF_ENABLE_SHARING)) {
+	if (eel_gconf_get_boolean (CONF_DAAP_ENABLE_SHARING)) {
 		create_share (shell);
 	}
 
 	enable_sharing_notify_id =
-		eel_gconf_notification_add (CONF_ENABLE_SHARING,
+		eel_gconf_notification_add (CONF_DAAP_ENABLE_SHARING,
 					    (GConfClientNotifyFunc) enable_sharing_changed_cb,
 					    shell);
+	require_password_notify_id =
+		eel_gconf_notification_add (CONF_DAAP_REQUIRE_PASSWORD,
+					    (GConfClientNotifyFunc) require_password_changed_cb,
+					    shell);
 	share_name_notify_id =
-		eel_gconf_notification_add (CONF_ENABLE_SHARING,
+		eel_gconf_notification_add (CONF_DAAP_SHARE_NAME,
 					    (GConfClientNotifyFunc) share_name_changed_cb,
 					    shell);
+	share_password_notify_id =
+		eel_gconf_notification_add (CONF_DAAP_SHARE_PASSWORD,
+					    (GConfClientNotifyFunc) share_password_changed_cb,
+					    shell);
 }
 
 void 
@@ -141,9 +217,17 @@ rb_daap_sharing_shutdown (RBShell *shell
 		eel_gconf_notification_remove (enable_sharing_notify_id);
 		enable_sharing_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 	}
+	if (require_password_notify_id != EEL_GCONF_UNDEFINED_CONNECTION) {
+		eel_gconf_notification_remove (require_password_notify_id);
+		require_password_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
+	}
 	if (share_name_notify_id != EEL_GCONF_UNDEFINED_CONNECTION) {
 		eel_gconf_notification_remove (share_name_notify_id);
 		share_name_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
+	}
+	if (share_password_notify_id != EEL_GCONF_UNDEFINED_CONNECTION) {
+		eel_gconf_notification_remove (share_password_notify_id);
+		share_password_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 	}
 
 	g_object_unref (shell);
Index: daapsharing/rb-daap-src.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/daapsharing/rb-daap-src.c,v
retrieving revision 1.6
diff -p -u -r1.6 rb-daap-src.c
--- daapsharing/rb-daap-src.c	21 Jan 2006 09:17:03 -0000	1.6
+++ daapsharing/rb-daap-src.c	27 Jan 2006 23:35:21 -0000
@@ -1,4 +1,5 @@
-/*
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
  *  Implementatin of DAAP (iTunes Music Sharing) GStreamer source
  *
  *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
@@ -21,9 +22,6 @@
 
 #include "config.h"
 
-#include "rb-daap-src.h"
-#include "rb-daap-source.h"
-
 #include <string.h>
 #include <netdb.h>
 #include <netinet/in.h>
@@ -46,6 +44,9 @@
 #include <gst/base/gstpushsrc.h>
 #endif
 
+#include "rb-daap-source.h"
+#include "rb-daap-src.h"
+
 #define RB_TYPE_DAAP_SRC (rb_daap_src_get_type())
 #define RB_DAAP_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RB_TYPE_DAAP_SRC,RBDAAPSrc))
 #define RB_DAAP_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RB_TYPE_DAAP_SRC,RBDAAPSrcClass))
@@ -693,7 +694,11 @@ rb_daap_src_open (RBDAAPSrc *src)
 
 	/* construct request */
 	source = rb_daap_source_find_for_uri (src->daap_uri);
-	g_assert (source != NULL);
+	if (source == NULL) {
+		g_warning ("Unable to lookup source for URI: %s", src->daap_uri);
+		return FALSE;
+	}
+
 	headers = rb_daap_source_get_headers (source, src->daap_uri, src->seek_time, &src->seek_bytes);
 	request = g_strdup_printf ("GET %s HTTP/1.1\r\nHost: %s\r\n%s\r\n",
 				   path, host, headers);
Index: data/rhythmbox.schemas
===================================================================
RCS file: /cvs/gnome/rhythmbox/data/rhythmbox.schemas,v
retrieving revision 1.62
diff -p -u -r1.62 rhythmbox.schemas
--- data/rhythmbox.schemas	7 Jan 2006 16:07:25 -0000	1.62
+++ data/rhythmbox.schemas	27 Jan 2006 23:35:21 -0000
@@ -530,6 +530,17 @@
 	</locale>
       </schema>
       <schema>
+	<key>/schemas/apps/rhythmbox/sharing/require_password</key>
+	<applyto>/apps/rhythmbox/sharing/require_password</applyto>
+	<owner>rhythmbox</owner>
+	<type>bool</type>
+	<default>0</default>
+	<locale name="C">
+	<short>Require a password to access your music over the network</short>
+	<long>When enabled, Rhythmbox will require a password for others to access your music over the network.</long>
+	</locale>
+      </schema>
+      <schema>
 	<key>/schemas/apps/rhythmbox/sharing/share_name</key>
 	<applyto>/apps/rhythmbox/sharing/share_name</applyto>
 	<owner>rhythmbox</owner>
@@ -538,6 +549,17 @@
 	<locale name="C">
 	<short>Name for your shared music</short>
 	<long>Name other computers will see your music shared as</long>
+	</locale>
+      </schema>
+      <schema>
+	<key>/schemas/apps/rhythmbox/sharing/share_password</key>
+	<applyto>/apps/rhythmbox/sharing/share_password</applyto>
+	<owner>rhythmbox</owner>
+	<type>string</type>
+	<default></default>
+	<locale name="C">
+	<short>Password for your shared music</short>
+	<long>Password that is required for accessing your shared music.</long>
 	</locale>
       </schema>
       <schema>
Index: data/glade/daap-prefs.glade
===================================================================
RCS file: /cvs/gnome/rhythmbox/data/glade/daap-prefs.glade,v
retrieving revision 1.2
diff -p -u -r1.2 daap-prefs.glade
--- data/glade/daap-prefs.glade	4 Nov 2005 14:31:08 -0000	1.2
+++ data/glade/daap-prefs.glade	27 Jan 2006 23:35:21 -0000
@@ -158,10 +158,56 @@
 			  </child>
 
 			  <child>
-			    <widget class="GtkHBox" id="daap_hbox">
+			    <widget class="GtkTable" id="daap_box">
 			      <property name="visible">True</property>
+			      <property name="n_rows">2</property>
+			      <property name="n_columns">2</property>
 			      <property name="homogeneous">False</property>
-			      <property name="spacing">12</property>
+			      <property name="row_spacing">6</property>
+			      <property name="column_spacing">6</property>
+
+			      <child>
+				<widget class="GtkCheckButton" id="daap_password_check">
+				  <property name="visible">True</property>
+				  <property name="can_focus">True</property>
+				  <property name="label" translatable="yes">Require _password:</property>
+				  <property name="use_underline">True</property>
+				  <property name="relief">GTK_RELIEF_NORMAL</property>
+				  <property name="focus_on_click">True</property>
+				  <property name="active">False</property>
+				  <property name="inconsistent">False</property>
+				  <property name="draw_indicator">True</property>
+				</widget>
+				<packing>
+				  <property name="left_attach">0</property>
+				  <property name="right_attach">1</property>
+				  <property name="top_attach">1</property>
+				  <property name="bottom_attach">2</property>
+				  <property name="x_options">fill</property>
+				  <property name="y_options"></property>
+				</packing>
+			      </child>
+
+			      <child>
+				<widget class="GtkEntry" id="daap_name_entry">
+				  <property name="visible">True</property>
+				  <property name="can_focus">True</property>
+				  <property name="editable">True</property>
+				  <property name="visibility">True</property>
+				  <property name="max_length">0</property>
+				  <property name="text" translatable="yes"></property>
+				  <property name="has_frame">True</property>
+				  <property name="invisible_char">*</property>
+				  <property name="activates_default">False</property>
+				</widget>
+				<packing>
+				  <property name="left_attach">1</property>
+				  <property name="right_attach">2</property>
+				  <property name="top_attach">0</property>
+				  <property name="bottom_attach">1</property>
+				  <property name="y_options"></property>
+				</packing>
+			      </child>
 
 			      <child>
 				<widget class="GtkLabel" id="label18">
@@ -183,18 +229,21 @@
 				  <property name="angle">0</property>
 				</widget>
 				<packing>
-				  <property name="padding">0</property>
-				  <property name="expand">False</property>
-				  <property name="fill">False</property>
+				  <property name="left_attach">0</property>
+				  <property name="right_attach">1</property>
+				  <property name="top_attach">0</property>
+				  <property name="bottom_attach">1</property>
+				  <property name="x_options">fill</property>
+				  <property name="y_options"></property>
 				</packing>
 			      </child>
 
 			      <child>
-				<widget class="GtkEntry" id="daap_name_entry">
+				<widget class="GtkEntry" id="daap_password_entry">
 				  <property name="visible">True</property>
 				  <property name="can_focus">True</property>
 				  <property name="editable">True</property>
-				  <property name="visibility">True</property>
+				  <property name="visibility">False</property>
 				  <property name="max_length">0</property>
 				  <property name="text" translatable="yes"></property>
 				  <property name="has_frame">True</property>
@@ -202,16 +251,18 @@
 				  <property name="activates_default">False</property>
 				</widget>
 				<packing>
-				  <property name="padding">0</property>
-				  <property name="expand">True</property>
-				  <property name="fill">True</property>
+				  <property name="left_attach">1</property>
+				  <property name="right_attach">2</property>
+				  <property name="top_attach">1</property>
+				  <property name="bottom_attach">2</property>
+				  <property name="y_options"></property>
 				</packing>
 			      </child>
 			    </widget>
 			    <packing>
 			      <property name="padding">0</property>
-			      <property name="expand">False</property>
-			      <property name="fill">False</property>
+			      <property name="expand">True</property>
+			      <property name="fill">True</property>
 			    </packing>
 			  </child>
 			</widget>
Index: lib/rb-preferences.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-preferences.h,v
retrieving revision 1.24
diff -p -u -r1.24 rb-preferences.h
--- lib/rb-preferences.h	4 Jan 2006 09:50:15 -0000	1.24
+++ lib/rb-preferences.h	27 Jan 2006 23:35:21 -0000
@@ -52,6 +52,11 @@ G_BEGIN_DECLS
 #define CONF_AUDIOSCROBBLER_PASSWORD CONF_PREFIX "/audioscrobbler/password"
 #define CONF_AUDIOSCROBBLER_ENABLED CONF_PREFIX "/audioscrobbler/enabled"
 
+#define CONF_DAAP_ENABLE_SHARING   CONF_PREFIX "/sharing/enable_sharing"
+#define CONF_DAAP_SHARE_NAME       CONF_PREFIX "/sharing/share_name"
+#define CONF_DAAP_SHARE_PASSWORD   CONF_PREFIX "/sharing/share_password"
+#define CONF_DAAP_REQUIRE_PASSWORD CONF_PREFIX "/sharing/require_password"
+
 G_END_DECLS
 
 #endif /* __RB_PREFERENCES_H */
Index: shell/rb-shell-preferences.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-shell-preferences.c,v
retrieving revision 1.55
diff -p -u -r1.55 rb-shell-preferences.c
--- shell/rb-shell-preferences.c	6 Jan 2006 16:00:41 -0000	1.55
+++ shell/rb-shell-preferences.c	27 Jan 2006 23:35:21 -0000
@@ -247,69 +247,150 @@ rb_shell_preferences_append_view_page (R
 
 #ifdef WITH_DAAP_SUPPORT
 
-#define CONF_ENABLE_SHARING "/apps/rhythmbox/sharing/enable_sharing"
-#define CONF_NAME "/apps/rhythmbox/sharing/share_name"
+static void
+share_check_button_toggled_cb (GtkToggleButton *button,
+			       GtkWidget *widget)
+{
+	gboolean b;
+
+	b = gtk_toggle_button_get_active (button);
+
+	eel_gconf_set_boolean (CONF_DAAP_ENABLE_SHARING, b);
+
+	gtk_widget_set_sensitive (widget, b);
+	
+	return;
+}
 
 static void
-share_check_button_toggled_cb (GtkToggleButton *button, GtkWidget *hbox)
+password_check_button_toggled_cb (GtkToggleButton *button,
+				  GtkWidget *widget)
 {
 	gboolean b;
 
 	b = gtk_toggle_button_get_active (button);
 
-	eel_gconf_set_boolean (CONF_ENABLE_SHARING, b);
+	eel_gconf_set_boolean (CONF_DAAP_REQUIRE_PASSWORD, b);
 
-	gtk_widget_set_sensitive (hbox, b);
+	gtk_widget_set_sensitive (widget, b);
 	
 	return;
 }
 
 static gboolean
-share_name_entry_focus_out_event_cb (GtkEntry *entry, GdkEventFocus *event, gpointer data)
+share_name_entry_focus_out_event_cb (GtkEntry *entry,
+				     GdkEventFocus *event,
+				     gpointer data)
 {
-	const gchar *name;
-	char *old_name;
+	gboolean    changed;
+	const char *name;
+	char       *old_name;
 
 	name = gtk_entry_get_text (entry);
-	old_name = eel_gconf_get_string (CONF_NAME);
+	old_name = eel_gconf_get_string (CONF_DAAP_SHARE_NAME);
 
-	if (strcmp (name, old_name) != 0)
-		eel_gconf_set_string (CONF_NAME, name);
+	if (name == NULL && old_name == NULL) {
+		changed = FALSE;
+	} else if (name == NULL || old_name == NULL) {
+		changed = TRUE;
+	} else if (strcmp (name, old_name) != 0) {
+		changed = TRUE;
+	} else {
+		changed = FALSE;
+	}
+
+	if (changed) {
+		eel_gconf_set_string (CONF_DAAP_SHARE_NAME, name);
+	}
 
 	g_free (old_name);
 
 	return FALSE;
 }
 
+static gboolean
+share_password_entry_focus_out_event_cb (GtkEntry *entry,
+					 GdkEventFocus *event,
+					 gpointer data)
+{
+	gboolean    changed;
+	const char *pw;
+	char       *old_pw;
+
+	pw = gtk_entry_get_text (entry);
+	old_pw = eel_gconf_get_string (CONF_DAAP_SHARE_PASSWORD);
+
+	if (pw == NULL && old_pw == NULL) {
+		changed = FALSE;
+	} else if (pw == NULL || old_pw == NULL) {
+		changed = TRUE;
+	} else if (strcmp (pw, old_pw) != 0) {
+		changed = TRUE;
+	} else {
+		changed = FALSE;
+	}
+
+	if (changed) {
+		eel_gconf_set_string (CONF_DAAP_SHARE_PASSWORD, pw);
+	}
+
+	g_free (old_pw);
+
+	return FALSE;
+}
+
 static void
 add_daap_preferences (RBShellPreferences *shell_preferences)
 {
 	GladeXML *xml;
 	GtkWidget *check;
-	GtkWidget *entry;
-	GtkWidget *hbox;
-	gboolean b;
+	GtkWidget *name_entry;
+	GtkWidget *password_entry;
+	GtkWidget *password_check;
+	GtkWidget *box;
+	gboolean sharing_enabled;
+	gboolean require_password;
 
-	gchar *name;
+	char *name;
+	char *password;
 
 	xml = rb_glade_xml_new ("daap-prefs.glade",
 				"daap_vbox",
 				shell_preferences);
 
 	check = glade_xml_get_widget (xml, "daap_enable_check");
-	entry = glade_xml_get_widget (xml, "daap_name_entry");
-	hbox = glade_xml_get_widget (xml, "daap_hbox");
+	password_check = glade_xml_get_widget (xml, "daap_password_check");
+	name_entry = glade_xml_get_widget (xml, "daap_name_entry");
+	password_entry = glade_xml_get_widget (xml, "daap_password_entry");
+	box = glade_xml_get_widget (xml, "daap_box");
 	
-	b = eel_gconf_get_boolean (CONF_ENABLE_SHARING);
-	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), b);
-	g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (share_check_button_toggled_cb), hbox);
+	sharing_enabled = eel_gconf_get_boolean (CONF_DAAP_ENABLE_SHARING);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), sharing_enabled);
+	g_signal_connect (check, "toggled", G_CALLBACK (share_check_button_toggled_cb), box);
+
+	require_password = eel_gconf_get_boolean (CONF_DAAP_REQUIRE_PASSWORD);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_check), require_password);
+	g_signal_connect (password_check, "toggled", G_CALLBACK (password_check_button_toggled_cb), password_entry);
 	
-	name = eel_gconf_get_string (CONF_NAME);
-	gtk_entry_set_text (GTK_ENTRY (entry), name);
-	g_signal_connect (G_OBJECT (entry), "focus-out-event", G_CALLBACK (share_name_entry_focus_out_event_cb), NULL);	
+	name = eel_gconf_get_string (CONF_DAAP_SHARE_NAME);
+	if (name != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (name_entry), name);
+	}
+	g_free (name);
+	g_signal_connect (name_entry, "focus-out-event",
+			  G_CALLBACK (share_name_entry_focus_out_event_cb), NULL);	
+
+	password = eel_gconf_get_string (CONF_DAAP_SHARE_PASSWORD);
+	if (password != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (password_entry), password);
+	}
+	g_free (password);
+	g_signal_connect (password_entry, "focus-out-event",
+			  G_CALLBACK (share_password_entry_focus_out_event_cb), NULL);	
+
+	gtk_widget_set_sensitive (box, sharing_enabled);
+	gtk_widget_set_sensitive (password_entry, require_password);
 
-	gtk_widget_set_sensitive (hbox, b);
-	
 	gtk_notebook_append_page (GTK_NOTEBOOK (shell_preferences->priv->notebook),
 				  glade_xml_get_widget (xml, "daap_vbox"),
 				  gtk_label_new (_("Sharing")));
Index: sources/rb-daap-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-daap-source.c,v
retrieving revision 1.16
diff -p -u -r1.16 rb-daap-source.c
--- sources/rb-daap-source.c	21 Jan 2006 09:17:03 -0000	1.16
+++ sources/rb-daap-source.c	27 Jan 2006 23:35:21 -0000
@@ -38,7 +38,7 @@
 #include "rb-preferences.h"
 
 #include "rb-daap-connection.h"
-#include "rb-daap-mdns.h"
+#include "rb-daap-mdns-browser.h"
 
 #include "rb-static-playlist-source.h"
 
@@ -58,8 +58,8 @@ static void rb_daap_source_connection_cb
 					  RBSource *source);
 static gboolean rb_daap_source_disconnect (RBSource *source);
 static gboolean rb_daap_source_show_popup (RBSource *source);
-static const gchar * rb_daap_source_get_browser_key (RBSource *source);
-static const gchar * rb_daap_source_get_paned_key (RBLibrarySource *source);
+static const char * rb_daap_source_get_browser_key (RBSource *source);
+static const char * rb_daap_source_get_paned_key (RBLibrarySource *source);
 
 
 #define CONF_ENABLE_BROWSING CONF_PREFIX "/sharing/enable_browsing"
@@ -68,16 +68,17 @@ static const gchar * rb_daap_source_get_
 #define CONF_STATE_SHOW_BROWSER CONF_PREFIX "/state/daap/show_browser"
 
 
-static RBDAAPmDNSBrowser browser = 0;
-static GHashTable *service_name_to_resolver = NULL;
-static GSList *sources = NULL;
+static RBDaapMdnsBrowser *mdns_browser = NULL;
+
+static GHashTable *source_lookup = NULL;
+
 static guint enable_browsing_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 
 
 struct RBDAAPSourcePrivate
 {
-	gchar *service_name;
-	gchar *host;
+	char *service_name;
+	char *host;
 	guint port;
 	gboolean password_protected;
 
@@ -267,9 +268,9 @@ rb_daap_get_icon (void)
 
 static RBSource *
 rb_daap_source_new (RBShell *shell,
-		    const gchar *service_name,
-		    const gchar *name,
-		    const gchar *host,
+		    const char *service_name,
+		    const char *name,
+		    const char *host,
 		    guint port,
 		    gboolean password_protected)
 {
@@ -299,165 +300,135 @@ rb_daap_source_new (RBShell *shell,
 
 
 static RBSource *
-find_source_by_service_name (const gchar *service_name)
+find_source_by_service_name (const char *service_name)
 {
-	GSList *l;
-
-	for (l = sources; l != NULL; l = l->next) {
-		RBSource *source = l->data;
+	RBSource *source;
 
-		if (strcmp (service_name, RB_DAAP_SOURCE (source)->priv->service_name) == 0) {
-			return source;
-		}
-	}
+	source = g_hash_table_lookup (source_lookup, service_name);
 
-	return NULL;
+	return source;
 }
 
 static void
-resolve_cb (RBDAAPmDNSResolver resolver,
-	    RBDAAPmDNSResolverStatus status,
-	    const gchar *service_name,
-	    gchar *name,
-	    gchar *host,
-	    guint port,
-	    gboolean password_protected,
-	    RBShell *shell)
-{
-	if (status == RB_DAAP_MDNS_RESOLVER_FOUND) {
-		RBSource *source = find_source_by_service_name (service_name);
-
-		if (source == NULL) {
-			source = rb_daap_source_new (shell, service_name, name, host, port, password_protected);
-			sources = g_slist_prepend (sources, source);
-			rb_shell_append_source (shell, source, NULL);
-		} else {
-			g_object_set (G_OBJECT (source),
-				      "name", name,
-				      "host", host,
-				      "port", port,
-				      "password-protected", password_protected,
-				      NULL);
-		}
-	} else if (status == RB_DAAP_MDNS_RESOLVER_TIMEOUT) {
-		g_warning ("Unable to resolve %s", service_name);
+mdns_service_added (RBDaapMdnsBrowser *browser,
+		    const char        *service_name,
+		    const char        *name,
+		    const char        *host,
+		    guint              port,
+		    gboolean           password_protected,
+		    RBShell           *shell)
+{
+	RBSource *source;
+
+#if 0
+	g_message ("New service: %s name=%s host=%s port=%u password=%d",
+		   service_name, name, host, port, password_protected);
+#endif
+
+	source = find_source_by_service_name (service_name);
+
+	if (source == NULL) {
+		source = rb_daap_source_new (shell, service_name, name, host, port, password_protected);
+		g_hash_table_insert (source_lookup, g_strdup (service_name), source);
+		rb_shell_append_source (shell, source, NULL);
+	} else {
+		g_object_set (G_OBJECT (source),
+			      "name", name,
+			      "host", host,
+			      "port", port,
+			      "password-protected", password_protected,
+			      NULL);
 	}
 }
 
-
 static void
-browse_cb (RBDAAPmDNSBrowser b,
-	   RBDAAPmDNSBrowserStatus status,
-	   const gchar *service_name,
-	   RBShell *shell)
+mdns_service_removed (RBDaapMdnsBrowser *browser,
+		      const char        *service_name,
+		      RBShell           *shell)
 {
-	if (status == RB_DAAP_MDNS_BROWSER_ADD_SERVICE) {
-		gboolean ret;
-		RBDAAPmDNSResolver *resolver;
-
-		if (find_source_by_service_name (service_name)) {
-			rb_debug ("Ignoring duplicate DAAP source");
-			return;
-		}
-
-		rb_debug ("New DAAP (music sharing) source '%s' discovered", service_name);
-
-		/* the resolver takes care of ignoring our own shares,
-		 * if this is us, the callback won't fire
-		 */
-		resolver = g_new0 (RBDAAPmDNSResolver, 1);
-		g_hash_table_insert (service_name_to_resolver, g_strdup (service_name), resolver);
-		ret = rb_daap_mdns_resolve (resolver,
-					    service_name,
-					    (RBDAAPmDNSResolverCallback) resolve_cb,
-					    shell);
-		if (!ret) {
-			g_warning ("could not start resolving host");
-		}
-
-	} else if (status == RB_DAAP_MDNS_BROWSER_REMOVE_SERVICE) {
-		RBSource *source = find_source_by_service_name (service_name);
-
-		rb_debug ("DAAP source '%s' went away", service_name);
-		if (source == NULL) {
-			/* if this happens, its because the user's own share
-			 * went away.  since that one doesnt resolve,
-			 * it doesnt get added to the sources list
-			 * it does have a resolver tho, so we should remove
-			 * that.
-			 */
-			g_hash_table_remove (service_name_to_resolver, service_name);
-
-			return;
-		}
+	RBSource *source;
 
-		g_hash_table_remove (service_name_to_resolver, service_name);
-		sources = g_slist_remove (sources, source);
+	source = find_source_by_service_name (service_name);
 
-		rb_daap_source_disconnect (source);
-		rb_source_delete_thyself (source);
-		/* unref is done via gtk in rb_shell_source_delete_cb at
-		 * gtk_notebook_remove_page */
+	rb_debug ("DAAP source '%s' went away", service_name);
+	if (source == NULL) {
+		return;
 	}
+
+	g_hash_table_remove (source_lookup, service_name);
 }
 
 static void
-stop_resolver (RBDAAPmDNSResolver *resolver)
+remove_source (RBSource *source)
 {
-	rb_daap_mdns_resolve_cancel (*resolver);
-	g_free (resolver);
-
-	resolver = NULL;
+	rb_daap_source_disconnect (source);
+	rb_source_delete_thyself (source);
 }
 
-
 static void
 start_browsing (RBShell *shell)
 {
-	if (service_name_to_resolver != NULL)
-		return;
+	GError *error;
 
-	gboolean ret = rb_daap_mdns_browse (&browser,
-					   (RBDAAPmDNSBrowserCallback) browse_cb,
-					   shell);
+	if (mdns_browser != NULL) {
+		return;
+	}
 
-	if (!ret) {
+	mdns_browser = rb_daap_mdns_browser_new ();
+	if (mdns_browser == NULL) {
 		g_warning ("Unable to start mDNS browsing");
 		return;
 	}
 
-	service_name_to_resolver = g_hash_table_new_full ((GHashFunc)g_str_hash,
-		       				 	  (GEqualFunc)g_str_equal, 
-							  (GDestroyNotify)g_free, 
-							  (GDestroyNotify)stop_resolver);
+	g_signal_connect_object (mdns_browser,
+				 "service-added",
+				 G_CALLBACK (mdns_service_added),
+				 shell,
+				 0);
+	g_signal_connect_object (mdns_browser,
+				 "service-removed",
+				 G_CALLBACK (mdns_service_removed),
+				 shell,
+				 0);
+
+	error = NULL;
+	rb_daap_mdns_browser_start (mdns_browser, &error);
+	if (error != NULL) {
+		g_warning ("Unable to start mDNS browsing: %s", error->message);
+		g_error_free (error);
+	}
+
+	source_lookup = g_hash_table_new_full ((GHashFunc)g_str_hash,
+					       (GEqualFunc)g_str_equal, 
+					       (GDestroyNotify)g_free, 
+					       (GDestroyNotify)remove_source);
 
 }
 
 static void
 stop_browsing (RBShell *shell)
 {
-	GSList *l;
+	GError *error;
 
-	if (service_name_to_resolver == NULL)
+	if (mdns_browser == NULL) {
 		return;
+	}
 
-	g_hash_table_destroy (service_name_to_resolver);
-	service_name_to_resolver = NULL;
+	g_hash_table_destroy (source_lookup);
+	source_lookup = NULL;
 
-	for (l = sources; l != NULL; l = l->next) {
-		RBSource *source = l->data;
+	g_signal_handlers_disconnect_by_func (mdns_browser, mdns_service_added, shell);
+	g_signal_handlers_disconnect_by_func (mdns_browser, mdns_service_removed, shell);
 
-		rb_daap_source_disconnect (source);
-		rb_source_delete_thyself (source);
+	error = NULL;
+	rb_daap_mdns_browser_stop (mdns_browser, &error);
+	if (error != NULL) {
+		g_warning ("Unable to stop mDNS browsing: %s", error->message);
+		g_error_free (error);
 	}
 
-	g_slist_free (sources);
-	sources = NULL;
-
-	if (browser) {
-		rb_daap_mdns_browse_cancel (browser);
-		browser = 0;
-	}
+	g_object_unref (mdns_browser);
+	mdns_browser = NULL;
 }
 
 static void
@@ -506,7 +477,7 @@ rb_daap_sources_init (RBShell *shell)
 void
 rb_daap_sources_shutdown (RBShell *shell)
 {
-	if (browser) {
+	if (mdns_browser) {
 		stop_browsing (shell);
 	}
 
@@ -525,7 +496,7 @@ rb_daap_source_activate (RBSource *sourc
 	RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
 	RBShell *shell = NULL;
 	RhythmDB *db = NULL;
-	gchar *name = NULL;
+	char *name = NULL;
 	RhythmDBEntryType type;
 
 	if (daap_source->priv->connection != NULL) 
@@ -648,36 +619,47 @@ rb_daap_source_show_popup (RBSource *sou
 	return TRUE;
 }
 
-RBDAAPSource *
-rb_daap_source_find_for_uri (const gchar *uri)
+static gboolean
+source_host_find (const char *key,
+		  RBDAAPSource *source,
+		  const char *host)
 {
-	GSList *l;
-	gchar *ip;
-	gchar *s;
-	RBDAAPSource *found_source = NULL;
+	if (source == NULL || host == NULL) {
+		return FALSE;
+	}
 
-	ip = strdup (uri + 7); // daap://
-	s = strchr (ip, ':');
-	*s = '\0';
+	if (strcmp (host, source->priv->host) == 0) {
+		return TRUE;
+	}
 
-	for (l = sources; l != NULL; l = l->next) {
-		RBDAAPSource *source = l->data;
+	return FALSE;
+}
 
-		if (strcmp (ip, source->priv->host) == 0) {
-			found_source = source;
-			break;
-		}
+RBDAAPSource *
+rb_daap_source_find_for_uri (const char *uri)
+{
+	char *ip;
+	char *s;
+	RBDAAPSource *source = NULL;
 
+	if (uri == NULL) {
+		return NULL;
 	}
 
-	g_free (ip);
+	ip = strdup (uri + 7); /* daap:// */
+	s = strchr (ip, ':');
+	*s = '\0';
+
+	source = (RBDAAPSource *)g_hash_table_find (source_lookup, (GHRFunc)source_host_find, ip);
 
-	return found_source;
+	g_free (ip);
+	
+	return source;
 }
 
-gchar *
+char *
 rb_daap_source_get_headers (RBDAAPSource *source,
-			    const gchar *uri,
+			    const char *uri,
 			    glong time,
 			    gint64 *bytes_out)
 {
@@ -708,13 +690,13 @@ rb_daap_source_get_headers (RBDAAPSource
 }
 
 
-static const gchar * 
+static const char * 
 rb_daap_source_get_browser_key (RBSource *source)
 {
 	return CONF_STATE_SHOW_BROWSER;
 }
 
-static const gchar * 
+static const char * 
 rb_daap_source_get_paned_key (RBLibrarySource *source)
 {
 	return CONF_STATE_PANED_POSITION;
Index: sources/rb-podcast-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-podcast-source.c,v
retrieving revision 1.43
diff -p -u -r1.43 rb-podcast-source.c
--- sources/rb-podcast-source.c	25 Jan 2006 05:15:09 -0000	1.43
+++ sources/rb-podcast-source.c	27 Jan 2006 23:35:21 -0000
@@ -597,7 +597,7 @@ rb_podcast_source_constructor (GType typ
 	query = rhythmdb_query_parse (source->priv->db,
 				      RHYTHMDB_QUERY_PROP_EQUALS,
 				      RHYTHMDB_PROP_TYPE,
-				      RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
+				      RHYTHMDB_ENTRY_TYPE_PODCAST_FEED,
 				      RHYTHMDB_QUERY_END);
 	
 	query_model = rhythmdb_query_model_new_empty (source->priv->db);
@@ -608,7 +608,7 @@ rb_podcast_source_constructor (GType typ
 
 
 	source->priv->feeds = rb_simple_view_new (source->priv->db,
-						  RHYTHMDB_PROP_SUBTITLE,
+						  RHYTHMDB_PROP_LOCATION,
 						  _("Feed"));	
 	
 	rb_property_view_set_selection_mode (RB_PROPERTY_VIEW (source->priv->feeds), GTK_SELECTION_MULTIPLE);
@@ -1521,11 +1521,11 @@ rb_podcast_source_feed_title_cell_data_f
 		/* Subtract one for the All node */
 		nodes--;
 
-		fmt = ngettext ("All %d feed (%d)", "All %d feeds (%d)", nodes);
+		fmt = ngettext ("All %d feed", "All %d feeds", nodes);
 
 		str = g_strdup_printf (fmt, nodes, number);
 	} else {
-		str = g_strdup_printf (_("%s (%d)"), title, number);
+		str = g_strdup_printf ("%s", title);
 	}
 
 	g_object_set (G_OBJECT (renderer), "text", str,
--- /dev/null	2006-01-26 04:39:02.728534000 -0500
+++ daapsharing/rb-daap-marshal.list	2006-01-25 21:46:56.000000000 -0500
@@ -0,0 +1 @@
+VOID:STRING,STRING,STRING,UINT,BOOLEAN
--- /dev/null	2006-01-26 04:39:02.728534000 -0500
+++ daapsharing/rb-daap-mdns-browser-avahi.c	2006-01-27 15:23:21.000000000 -0500
@@ -0,0 +1,470 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
+ *  Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#ifdef HAVE_AVAHI_0_6
+#include <avahi-client/lookup.h>
+#include <avahi-client/publish.h>
+#endif
+#include <avahi-client/client.h>
+#include <avahi-common/error.h>
+#include <avahi-glib/glib-malloc.h>
+#include <avahi-glib/glib-watch.h>
+
+#include "rb-daap-mdns-browser.h"
+#include "rb-daap-marshal.h"
+#include "rb-debug.h"
+
+static void	rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass *klass);
+static void	rb_daap_mdns_browser_init	(RBDaapMdnsBrowser	*browser);
+static void	rb_daap_mdns_browser_finalize   (GObject	        *object);
+
+#define RB_DAAP_MDNS_BROWSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_BROWSER, RBDaapMdnsBrowserPrivate))
+
+struct RBDaapMdnsBrowserPrivate
+{
+	AvahiClient         *client;
+	AvahiGLibPoll       *poll;
+	AvahiServiceBrowser *service_browser;
+
+	GSList              *resolvers;
+};
+
+enum { 
+	SERVICE_ADDED,
+	SERVICE_REMOVED,
+	LAST_SIGNAL
+};
+
+enum {
+	PROP_0
+};
+
+static GObjectClass *parent_class = NULL;
+static guint	     signals [LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (RBDaapMdnsBrowser, rb_daap_mdns_browser, G_TYPE_OBJECT)
+
+static gpointer browser_object = NULL;
+
+GQuark
+rb_daap_mdns_browser_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("rb_daap_mdns_browser_error");
+
+	return quark;
+}
+
+static void
+client_cb (AvahiClient         *client,
+	   AvahiClientState     state,
+	   RBDaapMdnsBrowser   *browser)
+{
+	/* Called whenever the client or server state changes */
+ 
+	switch (state) {
+	case AVAHI_CLIENT_FAILURE:
+             
+		 g_warning ("Client failure: %s\n", avahi_strerror (avahi_client_errno (client)));
+		 break;
+	default:
+		break;
+	}
+}
+
+static void
+avahi_client_init (RBDaapMdnsBrowser *browser)
+{
+	int error = 0;
+
+	avahi_set_allocator (avahi_glib_allocator ());
+
+	browser->priv->poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
+
+	if (! browser->priv->poll) {
+		rb_debug ("Unable to create AvahiGlibPoll object for mDNS");
+	}
+
+#ifdef HAVE_AVAHI_0_5
+	browser->priv->client = avahi_client_new (avahi_glib_poll_get (browser->priv->poll),
+						  client_cb,
+						  browser,
+						  &error);
+#endif
+#ifdef HAVE_AVAHI_0_6
+	{
+		AvahiClientFlags flags;
+		flags = 0;
+
+		browser->priv->client = avahi_client_new (avahi_glib_poll_get (browser->priv->poll),
+							  flags,
+							  (AvahiClientCallback)client_cb,
+							  browser,
+							  &error);
+	}
+#endif
+}
+
+static void
+resolve_cb (AvahiServiceResolver  *service_resolver,
+	    AvahiIfIndex           interface,
+	    AvahiProtocol          protocol,
+	    AvahiResolverEvent     event,
+	    const char            *service_name,
+	    const char            *type,
+	    const char            *domain,
+	    const char            *host_name,
+	    const AvahiAddress    *address,
+	    uint16_t               port,
+	    AvahiStringList       *text,
+#ifdef HAVE_AVAHI_0_6
+	    AvahiLookupResultFlags flags,
+#endif
+	    RBDaapMdnsBrowser     *browser)
+{
+	if (event == AVAHI_RESOLVER_FOUND) {
+		char    *name = NULL;
+		char     host [AVAHI_ADDRESS_STR_MAX];
+		gboolean pp = FALSE;
+		
+		if (text) {
+			AvahiStringList *l;
+
+			for (l = text; l != NULL; l = l->next) {
+				size_t size;
+				char  *key;
+				char  *value;
+				int    ret;
+
+				ret = avahi_string_list_get_pair (l, &key, &value, &size);
+				if (ret != 0 || key == NULL) {
+					continue;
+				}
+
+				if (strcmp (key, "Password") == 0) {
+					if (size >= 4 && strncmp (value, "true", 4) == 0) {
+						pp = TRUE;
+					}
+				} else if (strcmp (key, "Machine Name") == 0) {
+					name = g_strdup (value);
+				}
+
+				g_free (key);
+				g_free (value);
+			}
+		}
+
+		if (name == NULL) {
+			name = g_strdup (service_name);
+		}
+		
+		avahi_address_snprint (host, AVAHI_ADDRESS_STR_MAX, address);
+
+		g_signal_emit (browser,
+			       signals [SERVICE_ADDED],
+			       0,
+			       service_name,
+			       name,
+			       host,
+			       port,
+			       pp);
+
+		g_free (name);
+	}
+
+	browser->priv->resolvers = g_slist_remove (browser->priv->resolvers, service_resolver);
+	avahi_service_resolver_free (service_resolver);
+}
+
+static gboolean
+rb_daap_mdns_browser_resolve (RBDaapMdnsBrowser *browser,
+			      const char        *name)
+{
+	AvahiServiceResolver *service_resolver;
+
+	service_resolver = avahi_service_resolver_new (browser->priv->client,
+						       AVAHI_IF_UNSPEC,
+						       AVAHI_PROTO_INET,
+						       name,
+						       "_daap._tcp",
+						       NULL,
+						       AVAHI_PROTO_UNSPEC,
+#ifdef HAVE_AVAHI_0_6
+						       0,
+#endif
+						       (AvahiServiceResolverCallback)resolve_cb,
+						       browser);
+	if (service_resolver == NULL) {
+		rb_debug ("Error starting mDNS resolving using AvahiServiceResolver");
+		return FALSE;
+	}
+
+	browser->priv->resolvers = g_slist_prepend (browser->priv->resolvers, service_resolver);
+
+	return TRUE;
+}
+
+static void
+browser_add_service (RBDaapMdnsBrowser *browser,
+		     const char        *service_name)
+{
+	rb_daap_mdns_browser_resolve (browser, service_name);
+}
+
+static void
+browser_remove_service (RBDaapMdnsBrowser *browser,
+			const char        *service_name)
+{
+	g_signal_emit (browser, signals [SERVICE_REMOVED], 0, service_name);
+}
+
+static void
+browse_cb (AvahiServiceBrowser   *service_browser,
+	   AvahiIfIndex           interface,
+	   AvahiProtocol          protocol,
+	   AvahiBrowserEvent      event,
+	   const char            *name,
+	   const char            *type,
+	   const char            *domain,
+#ifdef HAVE_AVAHI_0_6
+	   AvahiLookupResultFlags flags,
+#endif
+	   RBDaapMdnsBrowser     *browser)
+{
+	gboolean local;
+
+#ifdef HAVE_AVAHI_0_5
+	local = avahi_client_is_service_local (get_avahi_client (NULL), interface, protocol, name, type, domain);
+#endif
+#ifdef HAVE_AVAHI_0_6
+	local = ((flags & AVAHI_LOOKUP_RESULT_LOCAL) != 0);
+#endif
+	if (local) {
+		rb_debug ("Ignoring local service %s", name);
+		return;
+	}
+	
+	if (event == AVAHI_BROWSER_NEW) {
+		browser_add_service (browser, name);
+	} else if (event == AVAHI_BROWSER_REMOVE) {
+		browser_remove_service (browser, name);
+	}
+}
+
+gboolean
+rb_daap_mdns_browser_start (RBDaapMdnsBrowser *browser,
+			    GError           **error)
+{
+	if (browser->priv->client == NULL) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING,
+			     "%s",
+			     _("MDNS service is not running"));
+		return FALSE;
+	}
+	if (browser->priv->service_browser != NULL) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
+			     "%s",
+			     _("Browser already active"));
+		return FALSE;
+	}
+
+	browser->priv->service_browser = avahi_service_browser_new (browser->priv->client,
+								    AVAHI_IF_UNSPEC,
+								    AVAHI_PROTO_UNSPEC,
+								    "_daap._tcp",
+								    NULL,
+#ifdef HAVE_AVAHI_0_6
+								    0,
+#endif
+								    (AvahiServiceBrowserCallback)browse_cb,
+								    browser);
+	if (browser->priv->service_browser == NULL) {
+		rb_debug ("Error starting mDNS discovery using AvahiServiceBrowser");
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
+			     "%s",
+			     _("Unable to activate browser"));
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+gboolean
+rb_daap_mdns_browser_stop (RBDaapMdnsBrowser *browser,
+			   GError           **error)
+{
+	if (browser->priv->client == NULL) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING,
+			     "%s",
+			     _("MDNS service is not running"));
+		return FALSE;
+	}
+	if (browser->priv->service_browser == NULL) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
+			     "%s",
+			     _("Browser is not active"));
+		return FALSE;
+
+	}
+	avahi_service_browser_free (browser->priv->service_browser);
+	browser->priv->service_browser = NULL;
+
+	return TRUE;
+}
+
+static void
+rb_daap_mdns_browser_set_property (GObject      *object,
+				   guint	 prop_id,
+				   const GValue *value,
+				   GParamSpec   *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_daap_mdns_browser_get_property (GObject	 *object,
+				   guint	  prop_id,
+				   GValue	 *value,
+				   GParamSpec	 *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->finalize	   = rb_daap_mdns_browser_finalize;
+	object_class->get_property = rb_daap_mdns_browser_get_property;
+	object_class->set_property = rb_daap_mdns_browser_set_property;
+
+	signals [SERVICE_ADDED] =
+		g_signal_new ("service-added",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBDaapMdnsBrowserClass, service_added),
+			      NULL,
+			      NULL,
+			      rb_daap_marshal_VOID__STRING_STRING_STRING_UINT_BOOLEAN,
+			      G_TYPE_NONE,
+			      5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_BOOLEAN);
+	signals [SERVICE_REMOVED] =
+		g_signal_new ("service-removed",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBDaapMdnsBrowserClass, service_removed),
+			      NULL,
+			      NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE,
+			      1, G_TYPE_STRING);
+
+	g_type_class_add_private (klass, sizeof (RBDaapMdnsBrowserPrivate));
+}
+
+static void
+rb_daap_mdns_browser_init (RBDaapMdnsBrowser *browser)
+{
+	browser->priv = RB_DAAP_MDNS_BROWSER_GET_PRIVATE (browser);
+
+	avahi_client_init (browser);
+}
+
+static void
+rb_daap_mdns_browser_finalize (GObject *object)
+{
+	RBDaapMdnsBrowser *browser;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (RB_IS_DAAP_MDNS_BROWSER (object));
+
+	browser = RB_DAAP_MDNS_BROWSER (object);
+
+	g_return_if_fail (browser->priv != NULL);
+
+	if (browser->priv->resolvers) {
+		g_slist_foreach (browser->priv->resolvers,
+				 (GFunc)avahi_service_resolver_free,
+				 NULL);
+		g_slist_free (browser->priv->resolvers);
+	}
+
+	if (browser->priv->service_browser) {
+		avahi_service_browser_free (browser->priv->service_browser);
+	}
+
+	if (browser->priv->client) {
+		avahi_client_free (browser->priv->client);
+	}
+
+	if (browser->priv->poll) {
+		avahi_glib_poll_free (browser->priv->poll);
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+RBDaapMdnsBrowser *
+rb_daap_mdns_browser_new (void)
+{
+	if (browser_object) {
+		g_object_ref (browser_object);
+	} else {
+		browser_object = g_object_new (RB_TYPE_DAAP_MDNS_BROWSER, NULL);
+		g_object_add_weak_pointer (browser_object,
+					   (gpointer *) &browser_object);
+	}
+
+	return RB_DAAP_MDNS_BROWSER (browser_object);
+}
--- /dev/null	2006-01-26 04:39:02.728534000 -0500
+++ daapsharing/rb-daap-mdns-browser-howl.c	2006-01-27 09:27:50.000000000 -0500
@@ -0,0 +1,519 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
+ *  Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include <libgnomevfs/gnome-vfs-address.h>
+#include <libgnomevfs/gnome-vfs-resolve.h>
+
+/* stupid howl includes howl_config.h */
+#undef PACKAGE
+#undef VERSION
+#include <howl.h>
+
+#include "rb-daap-mdns-browser.h"
+#include "rb-daap-marshal.h"
+#include "rb-debug.h"
+
+static void	rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass *klass);
+static void	rb_daap_mdns_browser_init	(RBDaapMdnsBrowser	*browser);
+static void	rb_daap_mdns_browser_finalize   (GObject	        *object);
+
+#define RB_DAAP_MDNS_BROWSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_BROWSER, RBDaapMdnsBrowserPrivate))
+
+struct RBDaapMdnsBrowserPrivate
+{
+	sw_discovery     *discovery;
+	sw_discovery_oid *oid;
+
+	GnomeVFSAddress  *local_address;
+	guint             watch_id;
+	GSList           *resolvers;
+};
+
+enum { 
+	SERVICE_ADDED,
+	SERVICE_REMOVED,
+	LAST_SIGNAL
+};
+
+enum {
+	PROP_0
+};
+
+static GObjectClass *parent_class = NULL;
+static guint	     signals [LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (RBDaapMdnsBrowser, rb_daap_mdns_browser, G_TYPE_OBJECT)
+
+static gpointer browser_object = NULL;
+
+GQuark
+rb_daap_mdns_browser_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("rb_daap_mdns_browser_error");
+
+	return quark;
+}
+
+static gboolean
+howl_in_cb (GIOChannel        *io_channel,
+	    GIOCondition       condition,
+	    RBDaapMdnsBrowser *browser)
+{
+	sw_salt salt;
+
+	if (sw_discovery_salt (*browser->priv->discovery, &salt) == SW_OKAY) {
+		sw_salt_lock (salt);
+		sw_discovery_read_socket (*browser->priv->discovery);
+		sw_salt_unlock (salt);
+	}
+	
+	return TRUE;
+}
+
+static void
+howl_client_init (RBDaapMdnsBrowser *browser)
+{
+	sw_result   result;
+	int         fd;
+	GIOChannel *channel;
+
+	browser->priv->discovery = g_new0 (sw_discovery, 1);
+	result = sw_discovery_init (browser->priv->discovery);
+
+	if (result != SW_OKAY) {
+		g_free (browser->priv->discovery);
+		browser->priv->discovery = NULL;
+		return;
+	}
+
+	fd = sw_discovery_socket (*browser->priv->discovery);
+
+	channel = g_io_channel_unix_new (fd);
+	browser->priv->watch_id = g_io_add_watch (channel, G_IO_IN, (GIOFunc)howl_in_cb, browser);
+	g_io_channel_unref (channel);
+}
+
+static gboolean
+host_is_local (RBDaapMdnsBrowser *browser,
+	       const char        *host)
+{
+	GnomeVFSAddress *remote;
+	gboolean         equal;
+	guint32          l_ip;
+	guint32          r_ip;
+
+	if (browser->priv->local_address == NULL) {
+		g_warning ("Unable to resolve address");
+		return FALSE;
+	}
+
+	remote = gnome_vfs_address_new_from_string (host);
+	if (remote == NULL) {
+		g_warning ("Unable to resolve address for %s", host);
+		return FALSE;
+	}
+
+	l_ip = gnome_vfs_address_get_ipv4 (browser->priv->local_address);
+	r_ip = gnome_vfs_address_get_ipv4 (remote);
+	equal = l_ip == r_ip;
+
+	/* FIXME: Use this when we can depend on gnome-vfs 2.14 */
+	/*equal = gnome_vfs_address_equal (browser->priv->local_address, remote);*/
+
+	gnome_vfs_address_free (remote);
+
+	return equal;
+}
+
+static void
+set_local_address (RBDaapMdnsBrowser *browser)
+{
+	char                   host_name [256];
+	GnomeVFSResolveHandle *rh;
+	GnomeVFSAddress       *address;
+	GnomeVFSResult         res;
+
+	if (gethostname (host_name, sizeof (host_name)) != 0) {
+		g_warning ("gethostname failed: %s", g_strerror (errno));
+		return;
+	}
+
+	res = gnome_vfs_resolve (host_name, &rh);
+
+	if (res != GNOME_VFS_OK) {
+		return;
+	}
+
+	address = NULL;
+	while (gnome_vfs_resolve_next_address (rh, &address)) {
+		if (browser->priv->local_address == NULL) {
+			browser->priv->local_address = gnome_vfs_address_dup (address);
+		}
+		gnome_vfs_address_free (address);
+	}
+
+	gnome_vfs_resolve_free (rh);
+}
+
+static sw_result
+resolve_cb (sw_discovery       discovery,
+	    sw_discovery_oid   oid, 
+	    sw_uint32          interface_index, 
+	    sw_const_string    service_name, 
+	    sw_const_string    type, 
+	    sw_const_string    domain, 
+	    sw_ipv4_address    address, 
+	    sw_port            port, 
+	    sw_octets          text_record, 
+	    sw_ulong           text_record_length, 
+	    RBDaapMdnsBrowser *browser)
+{
+	char                   *host;
+	char                   *name;
+	sw_text_record_iterator it;
+	gboolean                pp = FALSE;
+	
+	host = g_malloc (16);
+	name = NULL;
+
+	sw_ipv4_address_name (address, host, 16);
+
+	/* skip local services */
+	if (host_is_local (browser, host)) {
+		goto done;
+	}
+
+	if (sw_text_record_iterator_init (&it, text_record, text_record_length) == SW_OKAY) {
+		sw_char  key [SW_TEXT_RECORD_MAX_LEN];
+		sw_octet val [SW_TEXT_RECORD_MAX_LEN];
+		sw_ulong val_len;
+		
+		while (sw_text_record_iterator_next (it, (char *)key, val, &val_len) == SW_OKAY) {
+			if (strcmp ((char *)key, "Password") == 0) {
+				if (val_len >= 4 && strncmp ((char *)val, "true", 4) == 0) {
+					pp = TRUE;
+				}
+			}
+			if (strcmp ((char *)key, "Machine Name") == 0) {
+				if (name != NULL)
+					g_free (name);
+				name = g_strdup ((char *)val);
+			}
+		}
+		
+		sw_text_record_iterator_fina (it);
+	}
+
+	if (name == NULL) {
+		name = g_strdup (service_name);
+	}
+
+	g_signal_emit (browser,
+		       signals [SERVICE_ADDED],
+		       0,
+		       service_name,
+		       name,
+		       host,
+		       port,
+		       pp);
+ done:
+	g_free (host);
+	g_free (name);
+	
+	return SW_OKAY;
+}
+
+static gboolean
+rb_daap_mdns_browser_resolve (RBDaapMdnsBrowser *browser,
+			      const char        *name)
+{
+	sw_result        result;
+	sw_discovery_oid oid;
+
+       	result = sw_discovery_resolve (*browser->priv->discovery,
+				       0,
+				       name, 
+				       "_daap._tcp", 
+				       "local",
+				       (sw_discovery_resolve_reply) resolve_cb,
+	       			       (sw_opaque) browser,
+				       (sw_discovery_oid *) &oid);
+
+	return TRUE;
+}
+
+static void
+browser_add_service (RBDaapMdnsBrowser *browser,
+		     const char        *service_name)
+{
+	rb_daap_mdns_browser_resolve (browser, service_name);
+}
+
+static void
+browser_remove_service (RBDaapMdnsBrowser *browser,
+			const char        *service_name)
+{
+	g_signal_emit (browser, signals [SERVICE_REMOVED], 0, service_name);
+}
+
+static sw_result
+browse_cb (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,
+	   RBDaapMdnsBrowser         *browser)
+{
+	if (status == SW_DISCOVERY_BROWSE_ADD_SERVICE) {
+		browser_add_service (browser, name);
+	} else if (status == SW_DISCOVERY_BROWSE_REMOVE_SERVICE) {
+		browser_remove_service (browser, name);
+	}
+
+	return SW_OKAY;
+}
+
+gboolean
+rb_daap_mdns_browser_start (RBDaapMdnsBrowser *browser,
+			    GError           **error)
+{
+	sw_result result;
+
+	if (browser->priv->discovery == NULL) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING,
+			     "%s",
+			     _("MDNS service is not running"));
+		return FALSE;
+	}
+
+	if (browser->priv->oid != NULL) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
+			     "%s",
+			     _("Browser already active"));
+		return FALSE;
+	}
+
+	browser->priv->oid = g_new0 (sw_discovery_oid, 1);
+
+       	result = sw_discovery_browse (*browser->priv->discovery,
+				      0,
+				      "_daap._tcp", 
+				      "local", 
+				      (sw_discovery_browse_reply) browse_cb, 
+				      (sw_opaque) browser,
+				      (sw_discovery_oid *) browser->priv->oid);
+
+
+	if (result != SW_OKAY) {
+		rb_debug ("Error starting mDNS discovery using Howl");
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
+			     "%s",
+			     _("Unable to activate browser"));
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+gboolean
+rb_daap_mdns_browser_stop (RBDaapMdnsBrowser *browser,
+			   GError           **error)
+{
+	if (browser->priv->discovery == NULL) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING,
+			     "%s",
+			     _("MDNS service is not running"));
+		return FALSE;
+	}
+	if (browser->priv->oid == NULL) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_BROWSER_ERROR,
+			     RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
+			     "%s",
+			     _("Browser is not active"));
+		return FALSE;
+
+	}
+
+	sw_discovery_cancel (*browser->priv->discovery, *browser->priv->oid);
+
+	g_free (browser->priv->oid);
+	browser->priv->oid = NULL;
+
+	return TRUE;
+}
+
+static void
+rb_daap_mdns_browser_set_property (GObject      *object,
+				   guint	 prop_id,
+				   const GValue *value,
+				   GParamSpec   *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_daap_mdns_browser_get_property (GObject	 *object,
+				   guint	  prop_id,
+				   GValue	 *value,
+				   GParamSpec	 *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->finalize	   = rb_daap_mdns_browser_finalize;
+	object_class->get_property = rb_daap_mdns_browser_get_property;
+	object_class->set_property = rb_daap_mdns_browser_set_property;
+
+	signals [SERVICE_ADDED] =
+		g_signal_new ("service-added",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBDaapMdnsBrowserClass, service_added),
+			      NULL,
+			      NULL,
+			      rb_daap_marshal_VOID__STRING_STRING_STRING_UINT_BOOLEAN,
+			      G_TYPE_NONE,
+			      5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_BOOLEAN);
+	signals [SERVICE_REMOVED] =
+		g_signal_new ("service-removed",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBDaapMdnsBrowserClass, service_removed),
+			      NULL,
+			      NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE,
+			      1, G_TYPE_STRING);
+
+	g_type_class_add_private (klass, sizeof (RBDaapMdnsBrowserPrivate));
+}
+
+static void
+rb_daap_mdns_browser_init (RBDaapMdnsBrowser *browser)
+{
+	browser->priv = RB_DAAP_MDNS_BROWSER_GET_PRIVATE (browser);
+
+	set_local_address (browser);
+
+	howl_client_init (browser);
+}
+
+static void
+resolver_free (sw_discovery_oid  *oid,
+	       RBDaapMdnsBrowser *browser)
+{
+	sw_discovery_cancel (*browser->priv->discovery,
+			     *oid);
+	g_free (oid);
+}
+
+
+static void
+rb_daap_mdns_browser_finalize (GObject *object)
+{
+	RBDaapMdnsBrowser *browser;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (RB_IS_DAAP_MDNS_BROWSER (object));
+
+	browser = RB_DAAP_MDNS_BROWSER (object);
+
+	g_return_if_fail (browser->priv != NULL);
+
+	if (browser->priv->oid) {
+		rb_daap_mdns_browser_stop (browser, NULL);
+	}
+
+	if (browser->priv->resolvers) {
+		g_slist_foreach (browser->priv->resolvers,
+				 (GFunc)resolver_free,
+				 browser);
+		g_slist_free (browser->priv->resolvers);
+	}
+
+	if (browser->priv->discovery) {
+		sw_discovery_fina (*browser->priv->discovery);
+		g_free (browser->priv->discovery);
+	}
+
+	if (browser->priv->watch_id > 0) {
+		g_source_remove (browser->priv->watch_id);
+	}
+
+	if (browser->priv->local_address) {
+		gnome_vfs_address_free (browser->priv->local_address);
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+RBDaapMdnsBrowser *
+rb_daap_mdns_browser_new (void)
+{
+	if (browser_object) {
+		g_object_ref (browser_object);
+	} else {
+		browser_object = g_object_new (RB_TYPE_DAAP_MDNS_BROWSER, NULL);
+		g_object_add_weak_pointer (browser_object,
+					   (gpointer *) &browser_object);
+	}
+
+	return RB_DAAP_MDNS_BROWSER (browser_object);
+}
--- /dev/null	2006-01-26 04:39:02.728534000 -0500
+++ daapsharing/rb-daap-mdns-browser.h	2006-01-26 12:53:11.000000000 -0500
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Header for abstraction of Multicast DNS for DAAP sharing
+ *
+ *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
+ *  Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
+ *
+ *  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 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 __RB_DAAP_MDNS_BROWSER_H
+#define __RB_DAAP_MDNS_BROWSER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DAAP_MDNS_BROWSER         (rb_daap_mdns_browser_get_type ())
+#define RB_DAAP_MDNS_BROWSER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DAAP_MDNS_BROWSER, RBDaapMdnsBrowser))
+#define RB_DAAP_MDNS_BROWSER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DAAP_MDNS_BROWSER, RBDaapMdnsBrowserClass))
+#define RB_IS_DAAP_MDNS_BROWSER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_DAAP_MDNS_BROWSER))
+#define RB_IS_DAAP_MDNS_BROWSER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DAAP_MDNS_BROWSER))
+#define RB_DAAP_MDNS_BROWSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DAAP_MDNS_BROWSER, RBDaapMdnsBrowserClass))
+
+typedef struct RBDaapMdnsBrowserPrivate RBDaapMdnsBrowserPrivate;
+
+typedef struct
+{
+	GObject object;
+
+	RBDaapMdnsBrowserPrivate *priv;
+} RBDaapMdnsBrowser;
+
+typedef struct
+{
+	GObjectClass parent_class;
+
+	void (* service_added)    (RBDaapMdnsBrowser *browser,
+				   const char        *service_name,
+				   const char        *name,
+				   const char        *host,
+				   guint              port,
+				   gboolean           password_protected);
+	void (* service_removed ) (RBDaapMdnsBrowser *browser,
+				   const char        *service_name);
+
+} RBDaapMdnsBrowserClass;
+
+typedef enum
+{
+	RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING,
+	RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
+} RBDaapMdnsBrowserError;
+
+#define RB_DAAP_MDNS_BROWSER_ERROR rb_daap_mdns_browser_error_quark ()
+
+GQuark             rb_daap_mdns_browser_error_quark (void);
+
+GType              rb_daap_mdns_browser_get_type    (void);
+
+RBDaapMdnsBrowser *rb_daap_mdns_browser_new         (void);
+gboolean           rb_daap_mdns_browser_start       (RBDaapMdnsBrowser *browser,
+						     GError           **error);
+gboolean           rb_daap_mdns_browser_stop        (RBDaapMdnsBrowser *browser,
+						     GError           **error);
+
+G_END_DECLS
+
+#endif /* __RB_DAAP_MDNS_BROWSER_H */
+
+
--- /dev/null	2006-01-26 04:39:02.728534000 -0500
+++ daapsharing/rb-daap-mdns-publisher-avahi.c	2006-01-27 15:32:33.000000000 -0500
@@ -0,0 +1,501 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
+ *  Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#ifdef HAVE_AVAHI_0_6
+#include <avahi-client/lookup.h>
+#include <avahi-client/publish.h>
+#endif
+#include <avahi-client/client.h>
+#include <avahi-common/error.h>
+#include <avahi-glib/glib-malloc.h>
+#include <avahi-glib/glib-watch.h>
+
+#include "rb-daap-mdns-publisher.h"
+#include "rb-debug.h"
+
+static void	rb_daap_mdns_publisher_class_init (RBDaapMdnsPublisherClass *klass);
+static void	rb_daap_mdns_publisher_init	  (RBDaapMdnsPublisher	    *publisher);
+static void	rb_daap_mdns_publisher_finalize   (GObject	            *object);
+
+#define RB_DAAP_MDNS_PUBLISHER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_PUBLISHER, RBDaapMdnsPublisherPrivate))
+
+struct RBDaapMdnsPublisherPrivate
+{
+	AvahiClient     *client;
+	AvahiGLibPoll   *poll;
+	AvahiEntryGroup *entry_group;
+
+	char            *name;
+	guint            port;
+	gboolean         password_required;
+};
+
+enum { 
+	PUBLISHED,
+	NAME_COLLISION,
+	LAST_SIGNAL
+};
+
+enum {
+	PROP_0
+};
+
+static GObjectClass *parent_class = NULL;
+static guint	     signals [LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (RBDaapMdnsPublisher, rb_daap_mdns_publisher, G_TYPE_OBJECT)
+
+static gpointer publisher_object = NULL;
+
+GQuark
+rb_daap_mdns_publisher_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("rb_daap_mdns_publisher_error");
+
+	return quark;
+}
+
+static void
+client_cb (AvahiClient         *client,
+	   AvahiClientState     state,
+	   RBDaapMdnsPublisher *publisher)
+{
+	/* FIXME
+	 * check to make sure we're in the _RUNNING state before we publish
+	 * check for COLLISION state and remove published information
+	 */
+
+	/* Called whenever the client or server state changes */
+ 
+	switch (state) {
+	case AVAHI_CLIENT_S_RUNNING:
+         
+		/* The server has startup successfully and registered its host
+		 * name on the network, so it's time to create our services */
+		
+		break;
+ 
+	case AVAHI_CLIENT_S_COLLISION:
+         
+		 /* Let's drop our registered services. When the server is back
+		  * in AVAHI_SERVER_RUNNING state we will register them
+		  * again with the new host name. */
+		 if (publisher->priv->entry_group) {
+			 avahi_entry_group_reset (publisher->priv->entry_group);
+		 }
+		 break;
+             
+	case AVAHI_CLIENT_FAILURE:
+             
+		 g_warning ("Client failure: %s\n", avahi_strerror (avahi_client_errno (client)));
+		 break;
+	case AVAHI_CLIENT_CONNECTING:
+	case AVAHI_CLIENT_S_REGISTERING:
+	default:
+		break;
+	}
+}
+
+static void
+avahi_client_init (RBDaapMdnsPublisher *publisher)
+{
+	gint error = 0;
+
+	avahi_set_allocator (avahi_glib_allocator ());
+
+	publisher->priv->poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
+
+	if (! publisher->priv->poll) {
+		rb_debug ("Unable to create AvahiGlibPoll object for mDNS");
+	}
+
+#ifdef HAVE_AVAHI_0_5
+	publisher->priv->client = avahi_client_new (avahi_glib_poll_get (publisher->priv->poll),
+						    client_cb,
+						    publisher,
+						    &error);
+#endif
+#ifdef HAVE_AVAHI_0_6
+	{
+		AvahiClientFlags flags;
+		flags = 0;
+
+		publisher->priv->client = avahi_client_new (avahi_glib_poll_get (publisher->priv->poll),
+							    flags,
+							    (AvahiClientCallback)client_cb,
+							    publisher,
+							    &error);
+	}
+#endif
+}
+
+static void
+entry_group_cb (AvahiEntryGroup     *group,
+		AvahiEntryGroupState state,
+		RBDaapMdnsPublisher *publisher)
+{
+	if (state == AVAHI_ENTRY_GROUP_ESTABLISHED) {
+
+		g_signal_emit (publisher, signals [PUBLISHED], 0, publisher->priv->name);
+
+	} else if (state == AVAHI_ENTRY_GROUP_COLLISION) {
+		g_warning ("MDNS name collision");
+
+		g_signal_emit (publisher, signals [NAME_COLLISION], 0, publisher->priv->name);
+	}
+}
+
+static gboolean
+create_service (RBDaapMdnsPublisher *publisher,
+		GError             **error)
+{
+	int         ret;
+	const char *txt_record;
+
+	if (publisher->priv->entry_group == NULL) {
+		publisher->priv->entry_group = avahi_entry_group_new (publisher->priv->client,
+								      (AvahiEntryGroupCallback)entry_group_cb,
+								      publisher);
+	} else {
+		avahi_entry_group_reset (publisher->priv->entry_group);
+	}
+
+	if (publisher->priv->entry_group == NULL) {
+		rb_debug ("Could not create AvahiEntryGroup for publishing");
+		g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
+			     "%s",
+			     _("Could not create AvahiEntryGroup for publishing"));
+		return FALSE;
+	}
+
+#if 0
+	g_message ("Service name:%s port:%u password:%d",
+		   publisher->priv->name,
+		   publisher->priv->port,
+		   publisher->priv->password_required);
+#endif
+
+	if (publisher->priv->password_required) {
+		txt_record = "Password=true";
+	} else {
+		txt_record = "Password=false";
+	}
+
+	ret = avahi_entry_group_add_service (publisher->priv->entry_group,
+					     AVAHI_IF_UNSPEC,
+					     AVAHI_PROTO_UNSPEC,
+#ifdef HAVE_AVAHI_0_6
+					     0,
+#endif
+					     publisher->priv->name,
+					     "_daap._tcp",
+					     NULL,
+					     NULL,
+					     publisher->priv->port,
+					     txt_record,
+					     NULL);
+
+	if (ret < 0) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
+			     "%s: %s",
+			     _("Could not add service"),
+			     avahi_strerror (ret));
+		return FALSE;
+	}
+
+	ret = avahi_entry_group_commit (publisher->priv->entry_group);
+
+	if (ret < 0) {
+		g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
+			     "%s: %s",
+			     _("Could not commit service"),
+			     avahi_strerror (ret));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+refresh_service (RBDaapMdnsPublisher *publisher,
+		 GError             **error)
+{
+	return create_service (publisher, error);
+}
+
+static gboolean
+publisher_set_name_internal (RBDaapMdnsPublisher *publisher,
+			     const char          *name,
+			     GError             **error)
+{
+	g_free (publisher->priv->name);
+	publisher->priv->name = g_strdup (name);
+
+	return TRUE;
+}
+
+gboolean
+rb_daap_mdns_publisher_set_name (RBDaapMdnsPublisher *publisher,
+				 const char          *name,
+				 GError             **error)
+{
+        g_return_val_if_fail (publisher != NULL, FALSE);
+
+	publisher_set_name_internal (publisher, name, error);
+
+	if (publisher->priv->entry_group) {
+		refresh_service (publisher, error);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+publisher_set_port_internal (RBDaapMdnsPublisher *publisher,
+			     guint                port,
+			     GError             **error)
+{
+	publisher->priv->port = port;
+
+	return TRUE;
+}
+
+gboolean
+rb_daap_mdns_publisher_set_port (RBDaapMdnsPublisher *publisher,
+				 guint                port,
+				 GError             **error)
+{
+        g_return_val_if_fail (publisher != NULL, FALSE);
+
+	publisher_set_port_internal (publisher, port, error);
+
+	if (publisher->priv->entry_group) {
+		refresh_service (publisher, error);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+publisher_set_password_required_internal (RBDaapMdnsPublisher *publisher,
+					  gboolean             required,
+					  GError             **error)
+{
+	publisher->priv->password_required = required;
+	return TRUE;
+}
+
+gboolean
+rb_daap_mdns_publisher_set_password_required (RBDaapMdnsPublisher *publisher,
+					      gboolean             required,
+					      GError             **error)
+{
+        g_return_val_if_fail (publisher != NULL, FALSE);
+
+	publisher_set_password_required_internal (publisher, required, error);
+
+	if (publisher->priv->entry_group) {
+		refresh_service (publisher, error);
+	}
+
+	return TRUE;
+}
+
+gboolean
+rb_daap_mdns_publisher_publish (RBDaapMdnsPublisher *publisher,
+				const char          *name,
+				guint                port,
+				gboolean             password_required,
+				GError             **error)
+{
+	if (publisher->priv->client == NULL) {
+                g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_NOT_RUNNING,
+                             "%s",
+                             _("The avahi MDNS service is not running"));
+		return FALSE;
+	}
+
+	publisher_set_name_internal (publisher, name, NULL);
+	publisher_set_port_internal (publisher, port, NULL);
+	publisher_set_password_required_internal (publisher, password_required, NULL);
+
+	return create_service (publisher, error);
+}
+
+gboolean
+rb_daap_mdns_publisher_withdraw (RBDaapMdnsPublisher *publisher,
+				 GError             **error)
+{
+	if (publisher->priv->client == NULL) {
+                g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_NOT_RUNNING,
+                             "%s",
+                             _("The avahi MDNS service is not running"));
+		return FALSE;
+	}
+
+	if (publisher->priv->entry_group == NULL) {
+                g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
+                             "%s",
+                             _("The MDNS service is not published"));
+		return FALSE;
+	}
+
+	avahi_entry_group_reset (publisher->priv->entry_group);
+	avahi_entry_group_free (publisher->priv->entry_group);
+	publisher->priv->entry_group = NULL;
+
+	return TRUE;
+}
+
+static void
+rb_daap_mdns_publisher_set_property (GObject	  *object,
+				     guint	   prop_id,
+				     const GValue *value,
+				     GParamSpec	  *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_daap_mdns_publisher_get_property (GObject	 *object,
+				     guint	  prop_id,
+				     GValue	 *value,
+				     GParamSpec	 *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_daap_mdns_publisher_class_init (RBDaapMdnsPublisherClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->finalize	   = rb_daap_mdns_publisher_finalize;
+	object_class->get_property = rb_daap_mdns_publisher_get_property;
+	object_class->set_property = rb_daap_mdns_publisher_set_property;
+
+	signals [PUBLISHED] =
+		g_signal_new ("published",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBDaapMdnsPublisherClass, published),
+			      NULL,
+			      NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE,
+			      1, G_TYPE_STRING);
+	signals [NAME_COLLISION] =
+		g_signal_new ("name-collision",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBDaapMdnsPublisherClass, name_collision),
+			      NULL,
+			      NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE,
+			      1, G_TYPE_STRING);
+
+	g_type_class_add_private (klass, sizeof (RBDaapMdnsPublisherPrivate));
+}
+
+static void
+rb_daap_mdns_publisher_init (RBDaapMdnsPublisher *publisher)
+{
+	publisher->priv = RB_DAAP_MDNS_PUBLISHER_GET_PRIVATE (publisher);
+
+	avahi_client_init (publisher);
+}
+
+static void
+rb_daap_mdns_publisher_finalize (GObject *object)
+{
+	RBDaapMdnsPublisher *publisher;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (RB_IS_DAAP_MDNS_PUBLISHER (object));
+
+	publisher = RB_DAAP_MDNS_PUBLISHER (object);
+
+	g_return_if_fail (publisher->priv != NULL);
+
+	if (publisher->priv->entry_group) {
+		avahi_entry_group_free (publisher->priv->entry_group);
+	}
+
+	if (publisher->priv->client) {
+		avahi_client_free (publisher->priv->client);
+	}
+
+	if (publisher->priv->poll) {
+		avahi_glib_poll_free (publisher->priv->poll);
+	}
+
+	g_free (publisher->priv->name);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+RBDaapMdnsPublisher *
+rb_daap_mdns_publisher_new (void)
+{
+	if (publisher_object) {
+		g_object_ref (publisher_object);
+	} else {
+		publisher_object = g_object_new (RB_TYPE_DAAP_MDNS_PUBLISHER, NULL);
+		g_object_add_weak_pointer (publisher_object,
+					   (gpointer *) &publisher_object);
+	}
+
+	return RB_DAAP_MDNS_PUBLISHER (publisher_object);
+}
--- /dev/null	2006-01-26 04:39:02.728534000 -0500
+++ daapsharing/rb-daap-mdns-publisher-howl.c	2006-01-26 10:54:30.000000000 -0500
@@ -0,0 +1,443 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
+ *  Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+/* stupid howl includes howl_config.h */
+#undef PACKAGE
+#undef VERSION
+#include <howl.h>
+
+#include "rb-daap-mdns-publisher.h"
+#include "rb-debug.h"
+
+static void	rb_daap_mdns_publisher_class_init (RBDaapMdnsPublisherClass *klass);
+static void	rb_daap_mdns_publisher_init	  (RBDaapMdnsPublisher	    *publisher);
+static void	rb_daap_mdns_publisher_finalize   (GObject	            *object);
+
+#define RB_DAAP_MDNS_PUBLISHER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_PUBLISHER, RBDaapMdnsPublisherPrivate))
+
+struct RBDaapMdnsPublisherPrivate
+{
+	sw_discovery     *discovery;
+	sw_discovery_oid *oid;
+
+	guint             watch_id;
+
+	char             *name;
+	guint             port;
+	gboolean          password_required;
+};
+
+enum { 
+	PUBLISHED,
+	NAME_COLLISION,
+	LAST_SIGNAL
+};
+
+enum {
+	PROP_0
+};
+
+static GObjectClass *parent_class = NULL;
+static guint	     signals [LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (RBDaapMdnsPublisher, rb_daap_mdns_publisher, G_TYPE_OBJECT)
+
+static gpointer publisher_object = NULL;
+
+GQuark
+rb_daap_mdns_publisher_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("rb_daap_mdns_publisher_error");
+
+	return quark;
+}
+
+static gboolean
+howl_in_cb (GIOChannel          *io_channel,
+	    GIOCondition         condition,
+	    RBDaapMdnsPublisher *publisher)
+{
+	sw_salt salt;
+
+	if (sw_discovery_salt (*publisher->priv->discovery, &salt) == SW_OKAY) {
+		sw_salt_lock (salt);
+		sw_discovery_read_socket (*publisher->priv->discovery);
+		sw_salt_unlock (salt);
+	}
+	
+	return TRUE;
+}
+
+static void
+howl_client_init (RBDaapMdnsPublisher *publisher)
+{
+	sw_result   result;
+	int         fd;
+	GIOChannel *channel;
+
+	publisher->priv->discovery = g_new0 (sw_discovery, 1);
+	result = sw_discovery_init (publisher->priv->discovery);
+
+	if (result != SW_OKAY) {
+		g_free (publisher->priv->discovery);
+		publisher->priv->discovery = NULL;
+		return;
+	}
+
+	fd = sw_discovery_socket (*publisher->priv->discovery);
+
+	channel = g_io_channel_unix_new (fd);
+	publisher->priv->watch_id = g_io_add_watch (channel, G_IO_IN, (GIOFunc)howl_in_cb, publisher);
+	g_io_channel_unref (channel);
+}
+
+static sw_result
+publish_cb (sw_discovery                discovery,
+	    sw_discovery_oid            oid,
+	    sw_discovery_publish_status status,
+	    RBDaapMdnsPublisher        *publisher)
+{
+	if (status == SW_DISCOVERY_PUBLISH_STARTED) {
+		g_signal_emit (publisher, signals [PUBLISHED], 0, publisher->priv->name);
+	} else if (status == SW_DISCOVERY_PUBLISH_NAME_COLLISION) {
+		/* This is all well and good, but howl won't report a name collision.
+		 * http://lists.porchdogsoft.com/pipermail/howl-users/Week-of-Mon-20041206/000487.html
+		 * So.  Fuck.
+		 */
+		g_warning ("MDNS name collision");
+
+		g_signal_emit (publisher, signals [NAME_COLLISION], 0, publisher->priv->name);
+	}
+	
+	return SW_OKAY;
+}
+
+static const char *
+howl_strerror (sw_result result)
+{
+	const char *str;
+
+	switch (result) {
+		case SW_OKAY:
+			str = "No error";
+		case SW_DISCOVERY_E_NO_MEM:
+			str = "Out of memory";
+		case SW_DISCOVERY_E_BAD_PARAM:
+			str = "Invalid paramater";
+		case SW_DISCOVERY_E_UNKNOWN:
+		default:
+			str = "Unknown error";
+	}
+
+	return str;
+}
+
+static gboolean
+create_service (RBDaapMdnsPublisher *publisher,
+		GError             **error)
+{
+	sw_text_record text_record;
+	sw_result      result;
+
+	if (sw_text_record_init (&text_record) != SW_OKAY) {
+		rb_debug ("Error initializing Howl text record");
+		g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
+			     "%s",
+			     _("Error initializing Howl for publishing"));
+		return FALSE;
+	}
+
+	if (publisher->priv->oid != NULL) {
+		rb_daap_mdns_publisher_withdraw (publisher, NULL);
+	}
+
+	publisher->priv->oid = g_new0 (sw_discovery_oid, 1);
+
+	sw_text_record_add_key_and_string_value (text_record,
+						 "Password",
+						 publisher->priv->password_required ? "true" : "false");
+
+	result = sw_discovery_publish (*publisher->priv->discovery,
+				       0,
+				       publisher->priv->name,
+				       "_daap._tcp",
+				       "local",
+				       NULL,
+				       publisher->priv->port,
+				       sw_text_record_bytes (text_record),
+				       sw_text_record_len (text_record),
+				       (sw_discovery_publish_reply) publish_cb,
+	       			       (sw_opaque) publisher,
+				       (sw_discovery_oid *) publisher->priv->oid);
+
+	sw_text_record_fina (text_record);
+
+	if (result != SW_OKAY) {
+		rb_debug ("Error starting mDNS publish with Howl: %s", howl_strerror (result));
+		g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
+			     "%s: %s",
+			     _("Error initializing Howl for publishing"),
+			     howl_strerror (result));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+refresh_service (RBDaapMdnsPublisher *publisher,
+		 GError             **error)
+{
+	return create_service (publisher, error);
+}
+
+gboolean
+rb_daap_mdns_publisher_publish (RBDaapMdnsPublisher *publisher,
+				const char          *name,
+				guint                port,
+				gboolean             password_required,
+				GError             **error)
+{
+	if (publisher->priv->discovery == NULL) {
+                g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_NOT_RUNNING,
+                             "%s",
+                             _("The howl MDNS service is not running"));
+		return FALSE;
+	}
+
+	rb_daap_mdns_publisher_set_name (publisher, name, NULL);
+	rb_daap_mdns_publisher_set_port (publisher, port, NULL);
+	rb_daap_mdns_publisher_set_password_required (publisher, password_required, NULL);
+
+	/* special case: the _set_ functions have updated the existing entry group */
+	if (publisher->priv->oid != NULL) {
+		return TRUE;
+	}
+
+	return create_service (publisher, error);
+}
+
+gboolean
+rb_daap_mdns_publisher_withdraw (RBDaapMdnsPublisher *publisher,
+				 GError             **error)
+{
+	if (publisher->priv->discovery == NULL) {
+                g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_NOT_RUNNING,
+                             "%s",
+                             _("The howl MDNS service is not running"));
+		return FALSE;
+	}
+
+	if (publisher->priv->oid == NULL) {
+                g_set_error (error,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR,
+			     RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
+                             "%s",
+                             _("The MDNS service is not published"));
+		return FALSE;
+	}
+
+	sw_discovery_cancel (*publisher->priv->discovery, *publisher->priv->oid);
+
+	g_free (publisher->priv->oid);
+	publisher->priv->oid = NULL;
+
+	return TRUE;
+}
+
+gboolean
+rb_daap_mdns_publisher_set_name (RBDaapMdnsPublisher *publisher,
+				 const char          *name,
+				 GError             **error)
+{
+        g_return_val_if_fail (publisher != NULL, FALSE);
+
+	g_free (publisher->priv->name);
+	publisher->priv->name = g_strdup (name);
+
+	if (publisher->priv->oid) {
+		refresh_service (publisher, error);
+	}
+
+	return TRUE;
+}
+gboolean
+rb_daap_mdns_publisher_set_port (RBDaapMdnsPublisher *publisher,
+				 guint                port,
+				 GError             **error)
+{
+        g_return_val_if_fail (publisher != NULL, FALSE);
+
+	publisher->priv->port = port;
+
+	if (publisher->priv->oid) {
+		refresh_service (publisher, error);
+	}
+
+	return TRUE;
+}
+gboolean
+rb_daap_mdns_publisher_set_password_required (RBDaapMdnsPublisher *publisher,
+					      gboolean             required,
+					      GError             **error)
+{
+        g_return_val_if_fail (publisher != NULL, FALSE);
+
+	publisher->priv->password_required = required;
+
+	if (publisher->priv->oid) {
+		refresh_service (publisher, error);
+	}
+
+	return TRUE;
+}
+
+static void
+rb_daap_mdns_publisher_set_property (GObject	  *object,
+				     guint	   prop_id,
+				     const GValue *value,
+				     GParamSpec	  *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_daap_mdns_publisher_get_property (GObject	 *object,
+				     guint	  prop_id,
+				     GValue	 *value,
+				     GParamSpec	 *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_daap_mdns_publisher_class_init (RBDaapMdnsPublisherClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->finalize	   = rb_daap_mdns_publisher_finalize;
+	object_class->get_property = rb_daap_mdns_publisher_get_property;
+	object_class->set_property = rb_daap_mdns_publisher_set_property;
+
+	signals [PUBLISHED] =
+		g_signal_new ("published",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBDaapMdnsPublisherClass, published),
+			      NULL,
+			      NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE,
+			      1, G_TYPE_STRING);
+	signals [NAME_COLLISION] =
+		g_signal_new ("name-collision",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBDaapMdnsPublisherClass, name_collision),
+			      NULL,
+			      NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE,
+			      1, G_TYPE_STRING);
+
+	g_type_class_add_private (klass, sizeof (RBDaapMdnsPublisherPrivate));
+}
+
+static void
+rb_daap_mdns_publisher_init (RBDaapMdnsPublisher *publisher)
+{
+	publisher->priv = RB_DAAP_MDNS_PUBLISHER_GET_PRIVATE (publisher);
+
+	howl_client_init (publisher);
+}
+
+static void
+rb_daap_mdns_publisher_finalize (GObject *object)
+{
+	RBDaapMdnsPublisher *publisher;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (RB_IS_DAAP_MDNS_PUBLISHER (object));
+
+	publisher = RB_DAAP_MDNS_PUBLISHER (object);
+
+	g_return_if_fail (publisher->priv != NULL);
+
+	if (publisher->priv->oid) {
+		rb_daap_mdns_publisher_withdraw (publisher, NULL);
+	}
+
+	if (publisher->priv->discovery) {
+		sw_discovery_fina (*publisher->priv->discovery);
+		g_free (publisher->priv->discovery);
+	}
+
+	if (publisher->priv->watch_id > 0) {
+		g_source_remove (publisher->priv->watch_id);
+	}
+
+	g_free (publisher->priv->name);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+RBDaapMdnsPublisher *
+rb_daap_mdns_publisher_new (void)
+{
+	if (publisher_object) {
+		g_object_ref (publisher_object);
+	} else {
+		publisher_object = g_object_new (RB_TYPE_DAAP_MDNS_PUBLISHER, NULL);
+		g_object_add_weak_pointer (publisher_object,
+					   (gpointer *) &publisher_object);
+	}
+
+	return RB_DAAP_MDNS_PUBLISHER (publisher_object);
+}
--- /dev/null	2006-01-26 04:39:02.728534000 -0500
+++ daapsharing/rb-daap-mdns-publisher.h	2006-01-26 12:52:35.000000000 -0500
@@ -0,0 +1,92 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Header for abstraction of Multicast DNS for DAAP sharing
+ *
+ *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
+ *  Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
+ *
+ *  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 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 __RB_DAAP_MDNS_PUBLISHER_H
+#define __RB_DAAP_MDNS_PUBLISHER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_DAAP_MDNS_PUBLISHER         (rb_daap_mdns_publisher_get_type ())
+#define RB_DAAP_MDNS_PUBLISHER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DAAP_MDNS_PUBLISHER, RBDaapMdnsPublisher))
+#define RB_DAAP_MDNS_PUBLISHER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DAAP_MDNS_PUBLISHER, RBDaapMdnsPublisherClass))
+#define RB_IS_DAAP_MDNS_PUBLISHER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_DAAP_MDNS_PUBLISHER))
+#define RB_IS_DAAP_MDNS_PUBLISHER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_DAAP_MDNS_PUBLISHER))
+#define RB_DAAP_MDNS_PUBLISHER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_DAAP_MDNS_PUBLISHER, RBDaapMdnsPublisherClass))
+
+typedef struct RBDaapMdnsPublisherPrivate RBDaapMdnsPublisherPrivate;
+
+typedef struct
+{
+	GObject object;
+
+	RBDaapMdnsPublisherPrivate *priv;
+} RBDaapMdnsPublisher;
+
+typedef struct
+{
+	GObjectClass parent_class;
+
+	void (* published)         (RBDaapMdnsPublisher *publisher,
+				    const char          *name);
+	void (* name_collision)    (RBDaapMdnsPublisher *publisher,
+				    const char          *name);
+} RBDaapMdnsPublisherClass;
+
+typedef enum
+{
+	RB_DAAP_MDNS_PUBLISHER_ERROR_NOT_RUNNING,
+	RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
+} RBDaapMdnsPublisherError;
+
+#define RB_DAAP_MDNS_PUBLISHER_ERROR rb_daap_mdns_publisher_error_quark ()
+
+GQuark      rb_daap_mdns_publisher_error_quark                     (void);
+
+GType       rb_daap_mdns_publisher_get_type                        (void);
+
+RBDaapMdnsPublisher *rb_daap_mdns_publisher_new                    (void);
+gboolean             rb_daap_mdns_publisher_publish                (RBDaapMdnsPublisher *publisher,
+								    const char          *name,
+								    guint                port,
+								    gboolean             password_required,
+								    GError             **error);
+gboolean             rb_daap_mdns_publisher_set_name               (RBDaapMdnsPublisher *publisher,
+								    const char          *name,
+								    GError             **error);
+gboolean             rb_daap_mdns_publisher_set_port               (RBDaapMdnsPublisher *publisher,
+								    guint                port,
+								    GError             **error);
+gboolean             rb_daap_mdns_publisher_set_password_required  (RBDaapMdnsPublisher *publisher,
+								    gboolean             required,
+								    GError             **error);
+gboolean             rb_daap_mdns_publisher_withdraw               (RBDaapMdnsPublisher *publisher,
+								    GError             **error);
+
+G_END_DECLS
+
+#endif /* __RB_DAAP_MDNS_PUBLISHER_H */
+
+
