Fixing SMB browsing



Hi,

For the past few months at Novell, I've been working on Samba-related
stuff for gnome-vfs and Nautilus.  Attached is a patch for gnome-vfs's
smb-method.c which does a few things:

- Turns off SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON.  This is what causes
the "I get prompted for a password for everything" bug.  I have tried to
figure out why this flag got introduced, but it only seems to cause
trouble --- our perform_authentication() and its series of fallbacks
already take the proper steps to ensure that the user is only prompted
for authentication if absolutely required.

- Enables browsing for SMB printers.  When you double-click on a SMB
printer in Nautilus, it will launch gnome-cups-add to let you configure
the printer.

- Adds a bunch of debugging code, which can be enabled by touching
~/.debug-gnome-vfs-smb --- if this file exists, the code will create a
log in ~/debug-gnome-vfs-smb.log.  This is useful so that random users
can send you a debug log without recompiling.

- Hides administrative shares like IPC$ and ADMIN$, while showing
user-created shares that end in "$".

With this patch, SMB browsing works very well, including kerberized
setups like Active Directory.  "Works very well" assumes that the
network is configured for browsing --- it turns out that many networks
with a mixture of Windows and Unix boxes in various subnets are just not
properly set up for that.

The patch is large, but that is due to the code that produces debug
output.  The meat is pretty small.  I'm surprised that the only changed
really needed to get browsing to work well is the flag I mentioned
above.

OK to commit? :)

  Federico
2006-02-10  Federico Mena Quintero  <federico novell com>

	* modules/smb-method.c (try_init): Add debugging output for the
	default workgroup we get from GConf and smbc_init_context().

2006-02-06  Federico Mena Quintero  <federico ximian com>

	* modules/smb-method.c (is_hidden_entry): Only consider these
	administrative share names to be truly invisible: IPC$, ADMIN$,
	print$, printer$.  Fixes
	https://bugzilla.novell.com/show_bug.cgi?id=127526

2006-01-30  Federico Mena Quintero  <federico ximian com>

	https://bugzilla.novell.com/show_bug.cgi?id=145199 - allow
	browsing for printers.

	* modules/smb-method.c (printer_hash): New hash table where we
	remember the printers we find during calls to smbcctx->readdir().
	This method gives us a struct smbc_dirent that identifies a
	printer, but you cannot perform a smbcctx->stat() on a path to
	know if that path refers to a printer.  So, when doing readdir(),
	we must remember the URIs of the printers we have found.  Later in
	our own do_get_file_info(), we will match the passed URI to this
	hash table and return a magic "it is a printer" datum if
	appropriate.
	(try_init): Create the printer_hash.
	(vfs_module_shutdown): Destroy the printer_hash.
	(do_read_directory): Do not filter out printers, and add them to
	our hash table.  Use a MIME type of "application/x-desktop" for
	printers; we'll generate a fake .desktop item for them.
	(add_printer_to_hash): New helper function
	(make_path_from_uri_and_name): New function to create a URI from
	another parent URI and a name.
	(do_read_directory): Use make_path_from_uri_and_name() to avoid
	leaking the escaped file_info->name.
	(is_printer): New helper function.
	(set_file_info_to_readonly_desktop_file): New helper function.
	(do_get_file_info): Use set_file_info_to_readonly_desktop_file()
	in the case of workgroup or server links.  Use this as well for
	printers.
	(file_handle_new_from_desktop_file_contents): New helper function.
	(do_open): Handle printers by generating .desktop data for them.
	Shorten the code by using
	file_handle_new_from_desktop_file_contents() for this and the
	other cases that generate .desktop data.
	(get_printer_data): New helper function; creates .desktop data for
	a printer.

2006-01-27  Federico Mena Quintero  <federico ximian com>

	Add debug logging to smb-method if there is a
	"~/.debug-gnome-vfs-smb" file.  If this file exists, the SMB
	method will write a ~/debug-gnome-vfs-smb.log file.

	* modules/smb-method.c (debug_init): New function to initialize
	debugging.  This module gets loaded in gnome-vfs-daemon, so it's
	hard to get output from it.
	(debug_shutdown): New function.
	(debug_print): New function.
	(debug_indent): New function.
	(vfs_module_init): Initialize debugging.
	(vfs_module_shutdown): Shut down debugging.
	(debug_print): New function.
	(DEBUG_SMB): Use debug_print() instead of g_print().
	(DEBUG_IN): New macro.
	(DEBUG_OUT): New macro.
	(LOCK_SMB): Use debug_print().
	(UNLOCK_SMB): Use debug_print().
	(do_read_directory): Restore printer filtering until we find out
	how to pick up this info from libsmbclient with a ctx->stat() or similar.
	(*) Add calls to DEBUG_IN() / DEBUG_OUT().
	(debug_dump_auth_context): New function.

2006-01-26  Federico Mena Quintero  <federico ximian com>

	* modules/smb-method.c (do_read_directory): Don't filter out
	printer shares.  Break properly out of the switch() for the case
	of SMBC_PRINTER_SHARE.

2006-01-19  Federico Mena Quintero  <federico ximian com>

	* modules/smb-method.c (try_init): Clean up the code a bit.  Do
	*not* turn on SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON for the global
	smb_context; we only want that to go into a specific share.

Index: modules/smb-method.c
===================================================================
RCS file: /cvsroot/gnome-vfs/modules/smb-method.c,v
retrieving revision 1.1.1.1
retrieving revision 1.14
diff -u -p -r1.1.1.1 -r1.14
--- modules/smb-method.c	16 Jan 2006 22:00:40 -0000	1.1.1.1
+++ modules/smb-method.c	20 Feb 2006 17:38:38 -0000	1.14
@@ -37,6 +37,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <stdio.h>
 
 #include <gconf/gconf-client.h>
 #include <libgnomevfs/gnome-vfs.h>
@@ -90,6 +91,17 @@ static GHashTable *server_cache = NULL;
 
 static GHashTable *user_cache = NULL;
 
+/* smbcctx->readdir() can give us a struct smbc_dirent that identifies a
+ * printer, but you cannot perform a smbcctx->stat() on a path to know if that
+ * path refers to a printer.  So, when doing readdir(), we must remember the
+ * URIs of the printers we have found.  Later in our own do_get_file_info(), we
+ * will match the passed URI to this hash table and return a magic "it is a
+ * printer" datum if appropriate.
+ */
+static GHashTable *printer_hash = NULL;
+
+static FILE *debug_file;
+
 #define SMB_BLOCK_SIZE (32*1024)
 
 /* Reap unused server connections and user cache after 30 minutes */
@@ -144,32 +156,105 @@ typedef struct _SmbAuthContext {
 static void init_authentication (SmbAuthContext *actx, GnomeVFSURI *uri);
 static int  perform_authentication (SmbAuthContext *actx);
 
+static gboolean is_printer (const char *uri);
+
 static SmbAuthContext *current_auth_context = NULL;
 
 static void auth_callback (const char *server_name, const char *share_name,
 		     	   char *domain, int domainmaxlen,
 		     	   char *username, int unmaxlen,
 		     	   char *password, int pwmaxlen);
+
+static void debug_print (const char *format, ...);
+static void debug_indent (int amount);
+static int debug_indentation;
 		     	   
-#if 0
+#if 1
 #define DEBUG_SMB_ENABLE
 #define DEBUG_SMB_LOCKS
 #endif
 
 #ifdef DEBUG_SMB_ENABLE
-#define DEBUG_SMB(x) g_print x
+#define DEBUG_SMB(x) debug_print x
+#define DEBUG_IN() debug_print ("%s() {\n", G_STRFUNC); debug_indent(1)
+#define DEBUG_OUT() debug_indent(-1); debug_print ("} %s()\n", G_STRFUNC)
 #else
-#define DEBUG_SMB(x) 
+#define DEBUG_SMB(x)
+#define DEBUG_IN()
+#define DEBUG_OUT()
 #endif
 
 #ifdef DEBUG_SMB_LOCKS
-#define LOCK_SMB() 	{g_mutex_lock (smb_lock); g_print ("LOCK %s\n", G_GNUC_PRETTY_FUNCTION);}
-#define UNLOCK_SMB() 	{g_print ("UNLOCK %s\n", G_GNUC_PRETTY_FUNCTION); g_mutex_unlock (smb_lock);}
+#define LOCK_SMB() 	{g_mutex_lock (smb_lock); debug_print ("LOCK %s\n", G_STRFUNC);}
+#define UNLOCK_SMB() 	{debug_print ("UNLOCK %s\n", G_STRFUNC); g_mutex_unlock (smb_lock);}
 #else
 #define LOCK_SMB() 	g_mutex_lock (smb_lock)
 #define UNLOCK_SMB() 	g_mutex_unlock (smb_lock)
 #endif
 
+static void
+debug_print (const char *format, ...)
+{
+	va_list args;
+	char *str;
+	int i;
+
+	if (!debug_file)
+		return;
+
+	va_start (args, format);
+	str = g_strdup_vprintf (format, args);
+	va_end (args);
+
+	fprintf (debug_file, "%p: ", g_thread_self ());
+
+	for (i = 0; i < debug_indentation * 4; i++)
+		fputc (' ', debug_file);
+
+	fputs (str, debug_file);
+	g_free (str);
+	fflush (debug_file);
+}
+
+static void
+debug_indent (int amount)
+{
+	debug_indentation += amount;
+	if (debug_indentation < 0)
+		g_error ("You fucked up your indentation");
+}
+
+static void
+DEBUG_DUMP_AUTH_CONTEXT (SmbAuthContext *actx)
+{
+	char *str_uri;
+
+	if (actx->uri)
+		str_uri = gnome_vfs_uri_to_string (actx->uri, 0);
+	else
+		str_uri = g_strdup ("(null)");
+
+	debug_print ("AUTH CONTEXT %p {\n", actx);
+	debug_print ("             uri: %s\n", str_uri);
+	debug_print ("      vfs_result: %d\n", (int) actx->res);
+	debug_print ("          passes: %d\n", actx->passes);
+	debug_print ("           state: %x\n", actx->state);
+	debug_print ("       save_auth: %d\n", actx->save_auth);
+	debug_print ("         keyring: %s\n", actx->keyring);
+	debug_print ("     auth_called: %d\n", actx->auth_called);
+	debug_print ("      for_server: %s\n", actx->for_server);
+	debug_print ("       for_share: %s\n", actx->for_share);
+	debug_print ("        use_user: %s\n", actx->use_user);
+	debug_print ("      use_domain: %s\n", actx->use_domain);
+	debug_print ("    use_password: %s\n", actx->use_password);
+	debug_print ("     cache_added: %d\n", actx->cache_added);
+	debug_print ("      cache_used: %d\n", actx->cache_used);
+	debug_print ("    prompt_flags: %x\n", actx->prompt_flags);
+	debug_print ("}\n");
+
+	g_free (str_uri);
+}
+
 static gchar*
 string_dup_nzero (const gchar *s)
 {
@@ -306,7 +391,8 @@ cache_reap_cb (void)
          * sure when we'll be called */
         if (!g_mutex_trylock (smb_lock))
                 return TRUE;
-        DEBUG_SMB(("LOCK %s\n", G_GNUC_PRETTY_FUNCTION));
+	DEBUG_IN ();
+        DEBUG_SMB(("LOCK %s\n", G_STRFUNC));
 
 	size = g_hash_table_size (server_cache);
 	servers = g_ptr_array_sized_new (size);
@@ -329,6 +415,7 @@ cache_reap_cb (void)
         if (!ret)
                 cache_reap_timeout = 0;
 
+	DEBUG_OUT ();
         UNLOCK_SMB();
 
         return ret;        
@@ -350,6 +437,7 @@ add_cached_server (SMBCCTX *context, SMB
 {
 	SmbServerCacheEntry *entry = NULL;
 
+	DEBUG_IN ();
 	DEBUG_SMB(("[auth] adding cached server: server: %s, share: %s, domain: %s, user: %s\n",
 		   server_name, share_name, domain, username));
 	
@@ -367,6 +455,8 @@ add_cached_server (SMBCCTX *context, SMB
 
 	g_hash_table_insert (server_cache, entry, entry);
 	current_auth_context->cache_added = TRUE;
+
+	DEBUG_OUT ();
 	return 0;
 }
 
@@ -377,6 +467,7 @@ find_cached_server (const char *server_n
 	SmbServerCacheEntry entry;
 	SmbServerCacheEntry *res;
 
+	DEBUG_IN ();
 	DEBUG_SMB(("find_cached_server: server: %s, share: %s, domain: %s, user: %s\n", server_name, share_name, domain, username));
 
 	entry.server_name = (char *)server_name;
@@ -388,9 +479,13 @@ find_cached_server (const char *server_n
 
 	if (res != NULL) {
 		res->last_time = time (NULL);
+		DEBUG_OUT ();
+		DEBUG_SMB (("found server %p\n", res->server));
 		return res->server;
-	} 
+	}
 
+	DEBUG_SMB (("found nothing; returning NULL\n"));
+	DEBUG_OUT ();
 	return NULL;
 }
 
@@ -400,14 +495,19 @@ get_cached_server (SMBCCTX * context,
 		   const char *domain, const char *username)
 {
 	SMBCSRV *srv;
+
+	DEBUG_IN ();
 	
 	srv = find_cached_server (server_name, share_name, domain, username);
 	if (srv != NULL) {
 		DEBUG_SMB(("got cached server: server: %s, share: %s, domain: %s, user: %s\n",
 		   	  	  server_name, share_name, domain, username));
 		current_auth_context->cache_used = TRUE;
+		DEBUG_OUT ();
 		return srv;
 	}
+
+	DEBUG_OUT ();
 	return NULL;
 }
 
@@ -418,7 +518,7 @@ remove_server  (gpointer key,
 {
 	SmbServerCacheEntry *entry;
 	SMBCSRV *server;
-	
+
 	entry = key;
 	server = user_data;
 
@@ -432,9 +532,13 @@ remove_server  (gpointer key,
 static int remove_cached_server(SMBCCTX * context, SMBCSRV * server)
 {
 	int removed;
+
+	DEBUG_IN ();
 	
 	removed = g_hash_table_foreach_remove (server_cache, remove_server, server);
 
+	DEBUG_OUT ();
+
 	/* return 1 if failed */
 	return removed == 0;
 }
@@ -461,6 +565,8 @@ purge_cached(SMBCCTX * context)
 	gboolean could_not_purge_all;
 	int i;
 
+	DEBUG_IN ();
+
 	size = g_hash_table_size (server_cache);
 	servers = g_ptr_array_sized_new (size);
 
@@ -477,6 +583,10 @@ purge_cached(SMBCCTX * context)
 	}
 
 	g_ptr_array_free (servers, TRUE);
+
+	DEBUG_SMB (("returning could_not_purge_all = %d\n", could_not_purge_all));
+
+	DEBUG_OUT ();
 	
 	return could_not_purge_all;
 }
@@ -497,6 +607,8 @@ update_workgroup_cache (void)
 	SMBCFILE *dir = NULL;
 	time_t t;
 	struct smbc_dirent *dirent;
+
+	DEBUG_IN ();
 	
 	t = time (NULL);
 
@@ -504,6 +616,7 @@ update_workgroup_cache (void)
 	    workgroups_timestamp < t &&
 	    t < workgroups_timestamp + WORKGROUP_CACHE_TIMEOUT) {
 		/* Up to date */
+		DEBUG_OUT ();
 		return;
 	}
 	workgroups_timestamp = t;
@@ -515,15 +628,20 @@ update_workgroup_cache (void)
 	LOCK_SMB();
 	
 	init_authentication (&actx, NULL);
+	DEBUG_DUMP_AUTH_CONTEXT (&actx);
 	
 	/* Important: perform_authentication leaves and re-enters the lock! */
 	while (perform_authentication (&actx) > 0) {
+		DEBUG_SMB (("calling ctx->opendir (\"smb://\")\n"));
 		dir = smb_context->opendir (smb_context, "smb://");
 		actx.res = (dir != NULL) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB (("it returned %d\n", (int) actx.res));
 	}
 
 	if (dir != NULL) {
+		DEBUG_SMB (("calling ctx->readdir() in a loop\n"));
 		while ((dirent = smb_context->readdir (smb_context, dir)) != NULL) {
+			DEBUG_SMB (("got dirent '%s' of type %d\n", dirent->name, dirent->smbc_type));
 			if (dirent->smbc_type == SMBC_WORKGROUP &&
 			    dirent->name != NULL &&
 			    strlen (dirent->name) > 0) {
@@ -535,9 +653,13 @@ update_workgroup_cache (void)
 			}
 		}
 
+		DEBUG_SMB (("calling ctx->closedir()\n"));
 		smb_context->closedir (smb_context, dir);
 	}
+	DEBUG_DUMP_AUTH_CONTEXT (&actx);
 	UNLOCK_SMB();
+
+	DEBUG_OUT ();
 }
 
 static SmbUriType
@@ -545,6 +667,9 @@ smb_uri_type (GnomeVFSURI *uri)
 {
 	GnomeVFSToplevelURI *toplevel;
 	char *first_slash;
+	SmbUriType type;
+
+	DEBUG_IN ();
 
 	toplevel = (GnomeVFSToplevelURI *)uri;
 
@@ -553,12 +678,16 @@ smb_uri_type (GnomeVFSURI *uri)
 		if (uri->text == NULL ||
 		    uri->text[0] == 0 ||
 		    strcmp (uri->text, "/") == 0) {
-			return SMB_URI_WHOLE_NETWORK;
+			type = SMB_URI_WHOLE_NETWORK;
+			goto out;
 		}
 		if (strchr (uri->text + 1, '/')) {
-			return SMB_URI_ERROR;
+			type = SMB_URI_ERROR;
+			goto out;
 		}
-		return SMB_URI_WORKGROUP_LINK;
+
+		type = SMB_URI_WORKGROUP_LINK;
+		goto out;
 	}
 	if (uri->text == NULL ||
 	    uri->text[0] == 0 ||
@@ -568,9 +697,11 @@ smb_uri_type (GnomeVFSURI *uri)
 		if (!g_ascii_strcasecmp(toplevel->host_name,
 					DEFAULT_WORKGROUP_NAME) ||
 		    g_hash_table_lookup (workgroups, toplevel->host_name)) {
-			return SMB_URI_WORKGROUP;
+			type = SMB_URI_WORKGROUP;
+			goto out;
 		} else {
-			return SMB_URI_SERVER;
+			type = SMB_URI_SERVER;
+			goto out;
 		}
 	}
 	first_slash = strchr (uri->text + 1, '/');
@@ -580,13 +711,21 @@ smb_uri_type (GnomeVFSURI *uri)
 		if (!g_ascii_strcasecmp(toplevel->host_name,
 					DEFAULT_WORKGROUP_NAME) ||
 		    g_hash_table_lookup (workgroups, toplevel->host_name)) {
-			return SMB_URI_SERVER_LINK;
+			type = SMB_URI_SERVER_LINK;
+			goto out;
 		} else {
-			return SMB_URI_SHARE;
+			type = SMB_URI_SHARE;
+			goto out;
 		}
 	}
-	
-	return SMB_URI_SHARE_FILE;
+
+	type = SMB_URI_SHARE_FILE;
+
+ out:
+
+	DEBUG_OUT ();
+
+	return type;
 }
 
 
@@ -594,9 +733,25 @@ smb_uri_type (GnomeVFSURI *uri)
 static gboolean
 is_hidden_entry (char *name)
 {
+	static const char *hidden_names[] = {
+		"IPC$",
+		"ADMIN$",
+		"print$",
+		"printer$"
+	};
+
+	int i;
+
 	if (name == NULL) return TRUE;
 
-	if (*(name + strlen (name) -1) == '$') return TRUE;
+	for (i = 0; i < G_N_ELEMENTS (hidden_names); i++)
+		if (g_ascii_strcasecmp (name, hidden_names[i]) == 0)
+			return TRUE;
+
+	/* Shares that end in "$" are administrative shares, and Windows hides
+	 * them by default.  We have no way to say "this is a hidden file" in a
+	 * GnomeVFSFileInfo, so we'll make them visible for now.
+	 */
 
 	return FALSE;
 
@@ -628,42 +783,56 @@ try_init (void)
 	g_free (path);
 
 	smb_context = smbc_new_context ();
-	if (smb_context != NULL) {
-		smb_context->debug = 0;
-		smb_context->callbacks.auth_fn 		    = auth_callback;
-		smb_context->callbacks.add_cached_srv_fn    = add_cached_server;
-		smb_context->callbacks.get_cached_srv_fn    = get_cached_server;
-		smb_context->callbacks.remove_cached_srv_fn = remove_cached_server;
-		smb_context->callbacks.purge_cached_fn      = purge_cached;
-
-		gclient = gconf_client_get_default ();
-		if (gclient) {
-			workgroup = gconf_client_get_string (gclient, 
-					PATH_GCONF_GNOME_VFS_SMB_WORKGROUP, NULL);
-
-			/* libsmbclient frees this on it's own, so make sure 
-			 * to use simple system malloc */
-			if (workgroup && workgroup[0])
-				smb_context->workgroup = strdup (workgroup);
-			
-			g_free (workgroup);
-			g_object_unref (gclient);
-		}
+	if (smb_context == NULL)
+		goto out;
 
-		if (!smbc_init_context (smb_context)) {
-			smbc_free_context (smb_context, FALSE);
-			smb_context = NULL;
-		}
+	smb_context->debug = 0;
+	smb_context->callbacks.auth_fn 		    = auth_callback;
+	smb_context->callbacks.add_cached_srv_fn    = add_cached_server;
+	smb_context->callbacks.get_cached_srv_fn    = get_cached_server;
+	smb_context->callbacks.remove_cached_srv_fn = remove_cached_server;
+	smb_context->callbacks.purge_cached_fn      = purge_cached;
+
+	DEBUG_SMB (("created the SMBCCTX; it has smbcctx->workgroup=\"%s\"\n",
+		    smb_context->workgroup ? smb_context->workgroup : "(null)"));
+	
+	gclient = gconf_client_get_default ();
+	if (gclient) {
+		workgroup = gconf_client_get_string (gclient, 
+						     PATH_GCONF_GNOME_VFS_SMB_WORKGROUP, NULL);
+		
+		/* libsmbclient frees this on it's own, so make sure 
+		 * to use simple system malloc */
+		if (workgroup && workgroup[0])
+			smb_context->workgroup = strdup (workgroup);
+		
+		g_free (workgroup);
+		g_object_unref (gclient);
+	}
+	
+	DEBUG_SMB (("after reading from gconf, we have smbcctx->workgroup=\"%s\"\n",
+		    smb_context->workgroup ? smb_context->workgroup : "(null)"));
 
+	if (!smbc_init_context (smb_context)) {
+		smbc_free_context (smb_context, FALSE);
+		smb_context = NULL;
+		DEBUG_SMB (("smbc_init_context() failed!\n"));
+		goto out;
+	}
+
+	DEBUG_SMB (("called smbc_init_context(); we have smbcctx->workgroup=\"%s\"\n",
+		    smb_context->workgroup ? smb_context->workgroup : "(null)"));
+	
 #if defined(HAVE_SAMBA_FLAGS) 
 #if defined(SMB_CTX_FLAG_USE_KERBEROS) && defined(SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS)
-		smb_context->flags |= SMB_CTX_FLAG_USE_KERBEROS | SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS;
+	smb_context->flags |= SMB_CTX_FLAG_USE_KERBEROS | SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS;
 #endif
-#if defined(SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON)
-		smb_context->flags |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON;
+#  if 0
+#    if defined(SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON)
+   	smb_context->flags |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON;
+#    endif
+#  endif
 #endif
-#endif		
-	}
 
 	server_cache = g_hash_table_new_full (server_hash, server_equal,
 					      (GDestroyNotify)server_free, NULL);
@@ -671,7 +840,10 @@ try_init (void)
 					    g_free, NULL);
 	user_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
                                             g_free, (GDestroyNotify)user_free);
-	
+	printer_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+					      g_free, NULL);
+
+ out:
 	UNLOCK_SMB();
 
 	if (smb_context == NULL) {
@@ -712,6 +884,8 @@ update_user_cache (SmbAuthContext *actx,
 {
         SmbCachedUser *user;
         gchar *key;
+
+	DEBUG_IN ();
         
         g_return_if_fail (actx->for_server != NULL);
         
@@ -732,6 +906,8 @@ update_user_cache (SmbAuthContext *actx,
         user->username = string_realloc (user->username, actx->use_user);
         user->password = string_realloc (user->password, actx->use_password);
         user->stamp = time (NULL);
+
+	DEBUG_OUT ();
 }
 
 static gboolean
@@ -739,9 +915,13 @@ lookup_user_cache (SmbAuthContext *actx,
 {
         SmbCachedUser *user;
         gchar *key;
-       
+	gboolean retval;
+
         g_return_val_if_fail (actx->for_server != NULL, FALSE);
        
+	DEBUG_IN ();
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
+       
         key = g_strdup_printf ("%s/%s", actx->for_server, with_share ? actx->for_share : "");
         user = (SmbCachedUser*)g_hash_table_lookup (user_cache, key);
         g_free (key);
@@ -749,20 +929,33 @@ lookup_user_cache (SmbAuthContext *actx,
         if (user) {
                 /* If we already have a user name or domain double check that... */
 		if (!(actx->prompt_flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME) &&
-		    !string_compare(user->username, actx->use_user))
-			return FALSE;
+		    !string_compare(user->username, actx->use_user)) {
+			retval = FALSE;
+			goto out;
+		}
+
 		if (!(actx->prompt_flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN) &&
-		    !string_compare(user->domain, actx->use_domain))
-			return FALSE;
+		    !string_compare(user->domain, actx->use_domain)) {
+			retval = FALSE;
+			goto out;
+		}
 
                 actx->use_user = string_realloc (actx->use_user, user->username);
                 actx->use_domain = string_realloc (actx->use_domain, user->domain);
                 actx->use_password = string_realloc (actx->use_password, user->password);
                 DEBUG_SMB(("[auth] Looked up in cache: %s:%s %s\n", actx->use_user, actx->use_domain, actx->use_password));
-                return TRUE;
+		retval = TRUE;
+		goto out;
         }
+
+	retval = FALSE;
+
+ out:
+
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
+	DEBUG_OUT ();
         
-        return FALSE;
+        return retval;
 }      
 
 static gboolean
@@ -777,7 +970,10 @@ initial_authentication (SmbAuthContext *
         gboolean preset_user = FALSE;
 	char *tmp;
 
+	DEBUG_IN ();
+
 	DEBUG_SMB(("[auth] Initial authentication lookups\n"));
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
 
 	toplevel_uri =	(GnomeVFSToplevelURI*)actx->uri;
 	actx->prompt_flags = GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME |
@@ -843,6 +1039,8 @@ initial_authentication (SmbAuthContext *
         	}
         }
 
+	DEBUG_OUT ();
+
 	return found_user;
 }
 
@@ -856,7 +1054,10 @@ prefill_authentication (SmbAuthContext *
 	gboolean invoked;
 
 	g_return_val_if_fail (actx != NULL, FALSE);
-	g_return_val_if_fail (actx->for_server != NULL, FALSE);	
+	g_return_val_if_fail (actx->for_server != NULL, FALSE);
+
+	DEBUG_IN ();
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
 
 	memset (&in_args, 0, sizeof (in_args));
 	in_args.uri = get_auth_display_uri (actx, FALSE);
@@ -876,6 +1077,8 @@ prefill_authentication (SmbAuthContext *
 		              &in_args, sizeof (in_args),
 		              &out_args, sizeof (out_args));
 
+	DEBUG_SMB(("[auth] vfs module callback for FILL_AUTHENTICATION returned invoked=%d\n", invoked));
+
         g_free (in_args.uri);
                
         /* If that didn't work then try without the share name */
@@ -902,6 +1105,7 @@ prefill_authentication (SmbAuthContext *
                                         (GNOME_VFS_MODULE_CALLBACK_FILL_AUTHENTICATION,
                                         &in_args, sizeof (in_args),
                                         &out_args, sizeof (out_args));                               
+		DEBUG_SMB(("[auth] vfs module callback for FILL_AUTHENTICATION returned invoked=%d\n", invoked));
         }
         
 	if (invoked && out_args.valid) {
@@ -918,6 +1122,9 @@ prefill_authentication (SmbAuthContext *
 	g_free (out_args.domain);
 	g_free (out_args.password);
 
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
+	DEBUG_OUT ();
+
 	return invoked && out_args.valid;
 }
 
@@ -933,6 +1140,9 @@ prompt_authentication (SmbAuthContext *a
 	
 	g_return_val_if_fail (actx != NULL, FALSE);
 	g_return_val_if_fail (actx->for_server != NULL, FALSE);
+
+	DEBUG_IN ();
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
 	
 	memset (&in_args, 0, sizeof (in_args));
 	
@@ -954,29 +1164,38 @@ prompt_authentication (SmbAuthContext *a
 	
 	memset (&out_args, 0, sizeof (out_args));
 
-	DEBUG_SMB(("[auth] Prompting credentials for: %s\n", in_args.uri));
+	DEBUG_SMB(("[auth] Prompting credentials for: uri=%s, server=%s, object=%s, username=%s, domain=%s, default_user=%s, default_domain=%s\n",
+		   in_args.uri,
+		   in_args.server,
+		   in_args.object,
+		   in_args.username,
+		   in_args.domain,
+		   in_args.default_user,
+		   in_args.default_domain));
 
 	invoked = gnome_vfs_module_callback_invoke
 		(GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION,
 		 &in_args, sizeof (in_args),
 		 &out_args, sizeof (out_args));
 
+	DEBUG_SMB(("[auth] vfs module callback for FULL_AUTHENTICATION returned invoked=%d\n", invoked));
+
 	if (invoked) {
                 if (in_args.flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME) {
-                     g_free (actx->use_user);
-                       actx->use_user = string_dup_nzero (out_args.username);
+			g_free (actx->use_user); 
+			actx->use_user = string_dup_nzero (out_args.username);
                 }
                 if (in_args.flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN) {
-                      g_free (actx->use_domain);
-                     actx->use_domain = string_dup_nzero (out_args.domain);
+			g_free (actx->use_domain);
+			actx->use_domain = string_dup_nzero (out_args.domain);
                 }
 		g_free (actx->use_password);
 		actx->use_password = out_args.password ? g_strdup (out_args.password) : NULL;
 		g_free (actx->keyring);
 		actx->save_auth = out_args.save_password;
 		actx->keyring = actx->save_auth && out_args.keyring ? g_strdup (out_args.keyring) : NULL;
-		DEBUG_SMB(("[auth] Prompted credentials: %s %s:%s\n", actx->use_user, actx->use_domain, actx->use_password));
-	} 
+		DEBUG_SMB(("[auth] Prompted credentials: %s %s:%s keyring=%s\n", actx->use_user, actx->use_domain, actx->use_password, actx->keyring));
+	}
 
 	*cancelled = out_args.abort_auth;
 
@@ -989,6 +1208,9 @@ prompt_authentication (SmbAuthContext *a
 
 	g_free (in_args.uri);
 
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
+	DEBUG_OUT ();
+
 	return invoked && !*cancelled;
 }
 
@@ -999,14 +1221,19 @@ save_authentication (SmbAuthContext *act
 	GnomeVFSModuleCallbackSaveAuthenticationOut out_args;
 	gboolean invoked;
 
+	DEBUG_IN ();
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
+
         /* Add to the user cache both with and without shares */
         if (actx->for_server) {
                 update_user_cache (actx, TRUE);
                 update_user_cache (actx, FALSE);
         }
 
-        if (!actx->save_auth)
+        if (!actx->save_auth) {
+		DEBUG_OUT ();
                 return;
+	}
       
         /* Save with the domain name */
 	memset (&in_args, 0, sizeof (in_args));
@@ -1030,6 +1257,8 @@ save_authentication (SmbAuthContext *act
 		                &in_args, sizeof (in_args),
 		                &out_args, sizeof (out_args));
         
+	DEBUG_SMB(("[auth] vfs module callback for SAVE_AUTHENTICATION returned invoked=%d\n", invoked));
+
         g_free (in_args.uri);
               
         /* Save without the domain name */
@@ -1054,14 +1283,18 @@ save_authentication (SmbAuthContext *act
                                 &in_args, sizeof (in_args),
                                 &out_args, sizeof (out_args));
         
+	DEBUG_SMB(("[auth] vfs module callback for SAVE_AUTHENTICATION returned invoked=%d\n", invoked));
+
 	g_free (in_args.uri);
+
+	DEBUG_OUT ();
 }
 	
 static void
 cleanup_authentication (SmbAuthContext *actx)
 {
 	/* IMPORTANT: We are IN the lock at this point */
-	
+	DEBUG_IN ();
 	DEBUG_SMB(("[auth] Cleaning up Authentication\n"));
 	g_return_if_fail (actx != NULL);
 	
@@ -1085,6 +1318,9 @@ cleanup_authentication (SmbAuthContext *
 	
 	g_return_if_fail (current_auth_context == actx);
 	current_auth_context = NULL;
+
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
+	DEBUG_OUT ();
 }
 
 /* 
@@ -1129,9 +1365,12 @@ perform_authentication (SmbAuthContext *
 {
 	gboolean cont, auth_failed = FALSE, auth_cancelled = FALSE;
 	int ret = -1;
+
+	DEBUG_IN ();
 	
 	/* IMPORTANT: We are IN the lock at this point */
 	DEBUG_SMB(("[auth] perform_authentication called.\n"));
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
 	
 	switch (actx->res) {
 	case GNOME_VFS_OK:
@@ -1147,8 +1386,9 @@ perform_authentication (SmbAuthContext *
 	
 	/* Other errors mean we're done */
 	default:
-		DEBUG_SMB(("[auth] Non-authentication error. Leaving auth loop.\n"));
+		DEBUG_SMB(("[auth] Non-authentication VFS error %d. Leaving auth loop.\n", (int) actx->res));
 		cleanup_authentication (actx);
+		DEBUG_OUT ();
 		return -1;
 	}
 	
@@ -1189,7 +1429,7 @@ perform_authentication (SmbAuthContext *
 
 		/* A failed authentication */
 		} else if (actx->auth_called) {
-			
+
 			/* We need a server to perform any authentication */
 			g_return_val_if_fail (actx->for_server != NULL, GNOME_VFS_ERROR_INTERNAL);
 			
@@ -1199,23 +1439,27 @@ perform_authentication (SmbAuthContext *
 			
 			UNLOCK_SMB();
 
-				if (!(actx->state & SMB_AUTH_STATE_PREFILLED)) {
-					actx->state |= SMB_AUTH_STATE_PREFILLED;
-					cont = prefill_authentication (actx);
-				}
-				
-				if (!cont)
-					cont = prompt_authentication (actx, &auth_cancelled);
-				
+			if (!(actx->state & SMB_AUTH_STATE_PREFILLED)) {
+				DEBUG_SMB(("[auth] failed authentication; will prefill from the vfs callback\n"));
+				actx->state |= SMB_AUTH_STATE_PREFILLED;
+				cont = prefill_authentication (actx);
+			} else {
+				DEBUG_SMB(("[auth] failed authentication; will prompt the user for authentication\n"));
+			}
+
+			if (!cont)
+				cont = prompt_authentication (actx, &auth_cancelled);
+
 			LOCK_SMB();
 			
 			/* Claim the global context back */
 			g_return_val_if_fail (current_auth_context == NULL, GNOME_VFS_ERROR_INTERNAL);
 			current_auth_context = actx;
 			
-			if (cont)
+			if (cont) {
+				DEBUG_SMB(("[auth] prefill or prompt returned 1\n"));
 				ret = 1;
-			else {
+			} else {
 				ret = -1;
 
 				if (auth_cancelled) {
@@ -1230,12 +1474,15 @@ perform_authentication (SmbAuthContext *
 					
 		/* Weird, don't want authentication, but failed */
 		} else {
+			DEBUG_SMB(("[auth] don't want authentication, but failed\n"));
 			ret = -1;
 		}
 	}
 
 	if (ret <= 0)
 		cleanup_authentication (actx);
+
+	DEBUG_OUT ();
 	return ret;
 
 	/* IMPORTANT: We need to still be in the lock when returning from this func */
@@ -1250,16 +1497,22 @@ auth_callback (const char *server_name, 
 	/* IMPORTANT: We are IN the global lock */
 	SmbAuthContext *actx;
 	SMBCSRV *server;
+
+	DEBUG_IN ();
 	
-	DEBUG_SMB (("[auth] auth_callback called: server: %s share: %s\n",
-		    server_name, share_name));
+	DEBUG_SMB (("[auth] auth_callback called: server=%s, share=%s, domain_out=%s, username_out=%s, password_out=%s\n",
+		    server_name, share_name, domain_out, username_out, password_out));
 
 	g_return_if_fail (current_auth_context != NULL);
 	actx = current_auth_context;
+
+	DEBUG_DUMP_AUTH_CONTEXT (actx);
 	
 	/* We never authenticate for the toplevel (enumerating workgroups) */
-	if (!server_name || !server_name[0])
+	if (!server_name || !server_name[0]) {
+		DEBUG_OUT ();
 		return;
+	}
 
 	actx->auth_called = TRUE;	
 		
@@ -1270,8 +1523,10 @@ auth_callback (const char *server_name, 
 	actx->for_share = string_dup_nzero (share_name);
 
 	/* The first pass, try the cache, fill in anything we know */
-	if (actx->passes == 1)
+	if (actx->passes == 1) {
+		DEBUG_SMB(("[auth] first pass; call initial_authentication()\n"));
 		initial_authentication (actx);
+	}
 	
 	/* If we have a valid user then go for it */
 	if (actx->use_user) {
@@ -1285,13 +1540,13 @@ auth_callback (const char *server_name, 
         } else if (actx->passes == 1) {
                 strncpy (username_out, "guest", unmaxlen);
                 strncpy (password_out, "", pwmaxlen);
-                DEBUG_SMB(("[auth] No credentials, trying 'guest' user login\n"));
+                DEBUG_SMB(("[auth] No credentials, trying 'guest' user login with empty password\n"));
 
 	/* We have no credentials ... */			
 	} else {
 		strncpy (username_out, "", unmaxlen);
 		strncpy (password_out, "", pwmaxlen);
-                DEBUG_SMB(("[auth] No credentials, returning null values\n"));
+                DEBUG_SMB(("[auth] No credentials, returning empty user and password\n"));
 	}
 
 	/* Put in the default workgroup if none specified */
@@ -1304,15 +1559,30 @@ auth_callback (const char *server_name, 
 	 * this doesn't make much sense, but such is life with libsmbclient.
 	 */
 	if ((actx->state & SMB_AUTH_STATE_PROMPTED) && actx->res != GNOME_VFS_OK) {
+		DEBUG_SMB(("[auth] we had prompted already but auth failed.  Calling find_cached_server() again\n"));
 		server = find_cached_server (server_name, share_name, domain_out, username_out);
 		if (server) {
 			DEBUG_SMB (("[auth] auth_callback. Remove the wrong server entry from server_cache.\n"));
 			g_hash_table_foreach_remove (server_cache, remove_server, server);
 		}
 	}
+
+	DEBUG_OUT ();
 }
 
 static char *
+get_printer_data (const char *display_name, const char *path)
+{
+	return g_strdup_printf ("[Desktop Entry]\n"
+			"Encoding=UTF-8\n"
+			"Name=%s\n"
+			"Type=Application\n"
+			"Exec=gnome-cups-add --printer=%s\n"
+			"Icon=printer-remote\n", /* per the freedesktop.org icon naming spec */
+			display_name, path);
+}
+                                                                                
+static char *
 get_workgroup_data (const char *display_name, const char *name)
 {
 	return g_strdup_printf ("[Desktop Entry]\n"
@@ -1359,6 +1629,21 @@ typedef struct {
 	GnomeVFSFileOffset file_size;
 } FileHandle;
 
+/* Takes ownership of desktop_file_contents */
+static FileHandle *
+file_handle_new_from_desktop_file_contents (char *desktop_file_contents)
+{
+	FileHandle *handle;
+
+	handle = g_new (FileHandle, 1);
+	handle->is_data = TRUE;
+	handle->offset = 0;
+	handle->file_data = desktop_file_contents;
+	handle->file_size = strlen (handle->file_data);
+
+	return handle;
+}
+
 static GnomeVFSResult
 do_open (GnomeVFSMethod *method,
 	 GnomeVFSMethodHandle **method_handle,
@@ -1372,59 +1657,84 @@ do_open (GnomeVFSMethod *method,
 	int type;
 	mode_t unix_mode;
 	SMBCFILE *file = NULL;
-	
+	GnomeVFSResult result;
+
+	DEBUG_IN ();
 	DEBUG_SMB(("do_open() %s mode %d\n",
 				gnome_vfs_uri_to_string (uri, 0), mode));
 
 	type = smb_uri_type (uri);
 
 	if (type == SMB_URI_ERROR) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_INVALID_URI;
 	}
+
+	path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
+
+	if (is_printer (path)) {
+		if (mode & GNOME_VFS_OPEN_WRITE) {
+			result = GNOME_VFS_ERROR_READ_ONLY;
+			goto out;
+		}
+
+		unescaped_name = get_base_from_uri (uri);
+		name = gnome_vfs_uri_extract_short_path_name (uri);
+
+		handle = file_handle_new_from_desktop_file_contents (get_printer_data (unescaped_name, path));
+		*method_handle = (GnomeVFSMethodHandle *)handle;
+
+		g_free (unescaped_name);
+		g_free (name);
+
+		result = GNOME_VFS_OK;
+		goto out;
+	}
 	
 	if (type == SMB_URI_WHOLE_NETWORK ||
 	    type == SMB_URI_WORKGROUP ||
 	    type == SMB_URI_SERVER ||
 	    type == SMB_URI_SHARE) {
-		return GNOME_VFS_ERROR_IS_DIRECTORY;
+		result = GNOME_VFS_ERROR_IS_DIRECTORY;
+		goto out;
 	}
 
 	if (type == SMB_URI_WORKGROUP_LINK) {
 		if (mode & GNOME_VFS_OPEN_WRITE) {
-			return GNOME_VFS_ERROR_READ_ONLY;
+			result = GNOME_VFS_ERROR_READ_ONLY;
+			goto out;
 		}
-		handle = g_new (FileHandle, 1);
-		handle->is_data = TRUE;
-		handle->offset = 0;
+
 		unescaped_name = get_base_from_uri (uri);
 		name = gnome_vfs_uri_extract_short_path_name (uri);
-		handle->file_data = get_workgroup_data (unescaped_name, name);
-		handle->file_size = strlen (handle->file_data);
+
+		handle = file_handle_new_from_desktop_file_contents (get_workgroup_data (unescaped_name, name));
+		*method_handle = (GnomeVFSMethodHandle *)handle;
+
 		g_free (unescaped_name);
 		g_free (name);
 		
-		*method_handle = (GnomeVFSMethodHandle *)handle;
-		
-		return GNOME_VFS_OK;
+		result = GNOME_VFS_OK;
+		goto out;
 	}
 
 	if (type == SMB_URI_SERVER_LINK) {
 		if (mode & GNOME_VFS_OPEN_WRITE) {
-			return GNOME_VFS_ERROR_READ_ONLY;
+			result = GNOME_VFS_ERROR_READ_ONLY;
+			goto out;
 		}
-		handle = g_new (FileHandle, 1);
-		handle->is_data = TRUE;
-		handle->offset = 0;
+
 		unescaped_name = get_base_from_uri (uri);
 		name = gnome_vfs_uri_extract_short_path_name (uri);
-		handle->file_data = get_computer_data (unescaped_name, name);
-		handle->file_size = strlen (handle->file_data);
+
+		handle = file_handle_new_from_desktop_file_contents (get_computer_data (unescaped_name, name));
+		*method_handle = (GnomeVFSMethodHandle *)handle;
+
 		g_free (unescaped_name);
 		g_free (name);
 		
-		*method_handle = (GnomeVFSMethodHandle *)handle;
-		
-		return GNOME_VFS_OK;
+		result = GNOME_VFS_OK;
+		goto out;
 	}
 
 	g_assert (type == SMB_URI_SHARE_FILE);
@@ -1437,16 +1747,16 @@ do_open (GnomeVFSMethod *method,
 	} else {
 		if (mode & GNOME_VFS_OPEN_WRITE)
 			unix_mode = O_WRONLY;
-		else
-			return GNOME_VFS_ERROR_INVALID_OPEN_MODE;
+		else {
+			result = GNOME_VFS_ERROR_INVALID_OPEN_MODE;
+			goto out;
+		}
 	}
 
 	if ((mode & GNOME_VFS_OPEN_TRUNCATE) ||
 	    (!(mode & GNOME_VFS_OPEN_RANDOM) && (mode & GNOME_VFS_OPEN_WRITE)))
 		unix_mode |= O_TRUNC;
 	
-	path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
-	
 	LOCK_SMB();
 	init_authentication (&actx, uri);
 
@@ -1454,14 +1764,15 @@ do_open (GnomeVFSMethod *method,
 	while (perform_authentication (&actx) > 0) {
 		file = smb_context->open (smb_context, path, unix_mode, 0666);
 		actx.res = (file != NULL) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB(("ctx->open(\"%s\") returned file %p and error %d\n", path, file, (int) actx.res));
 	}
 
 	UNLOCK_SMB();
 
-	g_free (path);
-	
-	if (file == NULL)
+	if (file == NULL) {
+		DEBUG_OUT ();
 		return actx.res;
+	}
 	
 	handle = g_new (FileHandle, 1);
 	handle->is_data = FALSE;
@@ -1469,7 +1780,14 @@ do_open (GnomeVFSMethod *method,
 
 	*method_handle = (GnomeVFSMethodHandle *)handle;
 
-	return GNOME_VFS_OK;
+	result = GNOME_VFS_OK;
+
+ out:
+
+	g_free (path);
+
+	DEBUG_OUT ();
+	return result;
 }
 
 static GnomeVFSResult
@@ -1483,6 +1801,7 @@ do_close (GnomeVFSMethod *method,
 	GnomeVFSResult res;
 	int r;
 
+	DEBUG_IN ();
 	DEBUG_SMB(("do_close()\n"));
 
 	res = GNOME_VFS_OK;
@@ -1501,6 +1820,7 @@ do_close (GnomeVFSMethod *method,
 			r = smb_context->close_fn (smb_context, handle->file);
 #endif
 			actx.res = (r >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+			DEBUG_SMB(("ctx->close(%p) returned error %d\n", handle->file, (int) actx.res));
 		}
 
 		res = actx.res;		
@@ -1508,6 +1828,7 @@ do_close (GnomeVFSMethod *method,
 	}
 
 	g_free (handle);
+	DEBUG_OUT ();
 	return res;
 }
 
@@ -1524,6 +1845,7 @@ do_read (GnomeVFSMethod *method,
 	SmbAuthContext actx;
 	ssize_t n = 0;
 
+	DEBUG_IN ();
 	DEBUG_SMB(("do_read() %Lu bytes\n", num_bytes));
 
 	if (handle->is_data) {
@@ -1549,11 +1871,14 @@ do_read (GnomeVFSMethod *method,
 
 	*bytes_read = (n < 0) ? 0 : n;
 
-	if (n == 0) 
+	if (n == 0) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_EOF;
+	}
 
 	handle->offset += n;
 
+	DEBUG_OUT ();
 	return res;
 }
 
@@ -1571,10 +1896,13 @@ do_write (GnomeVFSMethod *method,
 	SmbAuthContext actx;
 	ssize_t written = 0;
 
+	DEBUG_IN ();
 	DEBUG_SMB (("do_write() %p\n", method_handle));
 
-	if (handle->is_data)
+	if (handle->is_data) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_READ_ONLY;
+	}
 
 	LOCK_SMB();
 	init_authentication (&actx, NULL);
@@ -1588,6 +1916,7 @@ do_write (GnomeVFSMethod *method,
 	UNLOCK_SMB();
 
 	*bytes_written = (written < 0) ? 0 : written;
+	DEBUG_OUT ();
 	return actx.res;
 }
 
@@ -1606,30 +1935,39 @@ do_create (GnomeVFSMethod *method,
 	SMBCFILE *file = NULL;
 	FileHandle *handle;
 	SmbAuthContext actx;
-	
+
+	DEBUG_IN ();
 	DEBUG_SMB (("do_create() %s mode %d\n",
 				gnome_vfs_uri_to_string (uri, 0), mode));
 
 	
 	type = smb_uri_type (uri);
 
-	if (type == SMB_URI_ERROR)
+	if (type == SMB_URI_ERROR) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_INVALID_URI;
+	}
 
 	if (type == SMB_URI_WHOLE_NETWORK ||
 	    type == SMB_URI_WORKGROUP ||
 	    type == SMB_URI_SERVER ||
-	    type == SMB_URI_SHARE)
+	    type == SMB_URI_SHARE) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_IS_DIRECTORY;
+	}
 
 	if (type == SMB_URI_WORKGROUP_LINK ||
-	    type == SMB_URI_SERVER_LINK) 
+	    type == SMB_URI_SERVER_LINK) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_PERMITTED;
+	}
 	
 	unix_mode = O_CREAT | O_TRUNC;
 	
-	if (!(mode & GNOME_VFS_OPEN_WRITE))
+	if (!(mode & GNOME_VFS_OPEN_WRITE)) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_INVALID_OPEN_MODE;
+	}
 
 	if (mode & GNOME_VFS_OPEN_READ)
 		unix_mode |= O_RDWR;
@@ -1648,24 +1986,44 @@ do_create (GnomeVFSMethod *method,
 	while (perform_authentication (&actx) > 0) {
 		file = smb_context->open (smb_context, path, unix_mode, perm);
 		actx.res = (file != NULL) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB(("ctx->open(\"%s\") returned file %p and error %d\n", path, file, (int) actx.res));
 	}
 
 	UNLOCK_SMB();
 
 	g_free (path);
 
-	if (file == NULL)
+	if (file == NULL) {
+		DEBUG_OUT ();
 		return actx.res;
+	}
 	
 	handle = g_new (FileHandle, 1);
 	handle->is_data = FALSE;
 	handle->file = file;
 
 	*method_handle = (GnomeVFSMethodHandle *)handle;
-	
+
+	DEBUG_OUT ();
 	return GNOME_VFS_OK;
 }
 
+static void
+set_file_info_to_readonly_desktop_file (GnomeVFSFileInfo *file_info, GnomeVFSURI *uri)
+{
+	file_info->name = get_base_from_uri (uri);
+	file_info->valid_fields = file_info->valid_fields
+		| GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
+		| GNOME_VFS_FILE_INFO_FIELDS_TYPE
+		| GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
+	file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
+	file_info->mime_type = g_strdup ("application/x-desktop");
+	file_info->permissions =
+		GNOME_VFS_PERM_USER_READ |
+		GNOME_VFS_PERM_OTHER_READ |
+		GNOME_VFS_PERM_GROUP_READ;
+}
+
 static GnomeVFSResult
 do_get_file_info (GnomeVFSMethod *method,
 		  GnomeVFSURI *uri,
@@ -1680,19 +2038,34 @@ do_get_file_info (GnomeVFSMethod *method
 	const char *mime_type;
 	SmbAuthContext actx;
 
+	DEBUG_IN ();
 	DEBUG_SMB (("do_get_file_info() %s\n",
 				gnome_vfs_uri_to_string (uri, 0)));
 
 	type = smb_uri_type (uri);
 
 	if (type == SMB_URI_ERROR) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_INVALID_URI;
 	}
+
+	path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
+
+	if (is_printer (path)) {
+		DEBUG_SMB (("is a printer we already saw; will fill in info\n"));
+
+		set_file_info_to_readonly_desktop_file (file_info, uri);
+		g_free (path);
+
+		DEBUG_OUT ();
+		return GNOME_VFS_OK;
+	}
 	
 	if (type == SMB_URI_WHOLE_NETWORK ||
 	    type == SMB_URI_WORKGROUP ||
 	    type == SMB_URI_SERVER ||
 	    type == SMB_URI_SHARE) {
+		DEBUG_SMB (("is whole network, workgroup, server, or share\n"));
 		file_info->name = get_base_from_uri (uri);
 		file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE |
 			GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
@@ -1713,29 +2086,22 @@ do_get_file_info (GnomeVFSMethod *method
  				GNOME_VFS_PERM_OTHER_READ |
  				GNOME_VFS_PERM_GROUP_READ;
 		}
+		DEBUG_OUT();
 		return GNOME_VFS_OK;
 	}
 
 	if (type == SMB_URI_WORKGROUP_LINK ||
 	    type == SMB_URI_SERVER_LINK) {
-		file_info->name = get_base_from_uri (uri);
-		file_info->valid_fields = file_info->valid_fields
-			| GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
-			| GNOME_VFS_FILE_INFO_FIELDS_TYPE
-			| GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS;
-		file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
-		file_info->mime_type = g_strdup ("application/x-desktop");
-		file_info->permissions =
-			GNOME_VFS_PERM_USER_READ |
-			GNOME_VFS_PERM_OTHER_READ |
-			GNOME_VFS_PERM_GROUP_READ;
+		DEBUG_SMB (("is workgroup link, or server link\n"));
+		set_file_info_to_readonly_desktop_file (file_info, uri);
+		DEBUG_OUT ();
 		return GNOME_VFS_OK;
 	}
 
 	g_assert (type == SMB_URI_SHARE_FILE);
-	    
-	path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
 
+	DEBUG_SMB (("is share file\n"));
+	    
 	LOCK_SMB();
 	init_authentication (&actx, uri);
 
@@ -1743,14 +2109,17 @@ do_get_file_info (GnomeVFSMethod *method
 	while (perform_authentication (&actx) > 0) {
 		err = smb_context->stat (smb_context, path, &st);
 		actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB(("ctx->stat(\"%s\") returned error %d\n", path, (int) actx.res));
 	}
 
 	UNLOCK_SMB();
 
 	g_free (path);
 
-	if (err < 0)
+	if (err < 0) {
+		DEBUG_OUT ();
 		return actx.res;
+	}
 	
 	gnome_vfs_stat_to_file_info (file_info, &st);
 	file_info->name = get_base_from_uri (uri);
@@ -1776,6 +2145,7 @@ do_get_file_info (GnomeVFSMethod *method
 				file_info->name, type,
 				file_info->mime_type, file_info->type));
 
+	DEBUG_OUT ();
 	return GNOME_VFS_OK;
 }
 
@@ -1791,6 +2161,7 @@ do_get_file_info_from_handle (GnomeVFSMe
 	struct stat st;
 	int err = -1;
 
+	DEBUG_IN ();
 	LOCK_SMB();
 	init_authentication (&actx, NULL);
 	
@@ -1798,17 +2169,22 @@ do_get_file_info_from_handle (GnomeVFSMe
 	while (perform_authentication (&actx) > 0) {
 		err = smb_context->fstat (smb_context, handle->file, &st);
 		actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB(("ctx->fstat(%p) returned error %d\n", handle->file, (int) actx.res));
 	}
 	
 	UNLOCK_SMB();
 	
-	if (err < 0) 
+	if (err < 0) {
+		DEBUG_OUT ();
 		return actx.res;
+	}
 	
 	gnome_vfs_stat_to_file_info (file_info, &st);
 
 	file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE;
 	file_info->io_block_size = SMB_BLOCK_SIZE;
+
+	DEBUG_OUT ();
 	return GNOME_VFS_OK;
 }
 
@@ -1816,7 +2192,19 @@ static gboolean
 do_is_local (GnomeVFSMethod *method,
 	     const GnomeVFSURI *uri)
 {
-	return FALSE;
+	char *path;
+	gboolean is_local;
+
+	/* FIXME: This is a hack.  In get_printer_data(), we generate data for a desktop item.  This item
+	 * is a "Type=Application" launcher, which launches gnome-cups-add.  However, since we can't execute
+	 * .desktop files from remote sites, we only advertise that printers "are local files".
+	 */
+
+	path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
+	is_local = is_printer (path);
+	g_free (path);
+	
+	return is_local;
 }
 
 typedef struct {
@@ -1854,6 +2242,7 @@ do_open_directory (GnomeVFSMethod *metho
 	SMBCFILE *dir = NULL;
 	SmbAuthContext actx;
 
+	DEBUG_IN ();
 	DEBUG_SMB(("do_open_directory() %s\n",
 		gnome_vfs_uri_to_string (uri, 0)));
 
@@ -1865,12 +2254,14 @@ do_open_directory (GnomeVFSMethod *metho
 		directory_handle = g_new0 (DirectoryHandle, 1);
 		g_hash_table_foreach (workgroups, add_workgroup, directory_handle);
 		*method_handle = (GnomeVFSMethodHandle *) directory_handle;
+		DEBUG_OUT ();
 		return GNOME_VFS_OK;
 	}
 
 	if (type == SMB_URI_ERROR ||
 	    type == SMB_URI_WORKGROUP_LINK ||
 	    type == SMB_URI_SERVER_LINK) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_A_DIRECTORY;
 	}
 
@@ -1879,11 +2270,22 @@ do_open_directory (GnomeVFSMethod *metho
 	host_name = gnome_vfs_uri_get_host_name (uri);
 	if (type == SMB_URI_WORKGROUP && host_name != NULL &&
 	    !g_ascii_strcasecmp(host_name, DEFAULT_WORKGROUP_NAME)) {
+		char *new_workgroup;
+
 		new_uri = gnome_vfs_uri_dup (uri);
-		gnome_vfs_uri_set_host_name (new_uri,
-					     smb_context->workgroup
-					     ? smb_context->workgroup
-					     : "WORKGROUP");
+		if (smb_context->workgroup)
+			new_workgroup = smb_context->workgroup;
+		else
+			new_workgroup = "WORKGROUP";
+
+		DEBUG_SMB (("we are being asked for %s; substituting it for workgroup \"%s\"%s\n",
+			    DEFAULT_WORKGROUP_NAME,
+			    new_workgroup,
+			    (smb_context->workgroup
+			     ? " because that is what was in the smbcctx->workgroup"
+			     : " because smbcctx->workgroup=NULL, so we use this as a last resort")));
+
+		gnome_vfs_uri_set_host_name (new_uri, new_workgroup);
 		uri = new_uri;
 	}
 		
@@ -1898,6 +2300,7 @@ do_open_directory (GnomeVFSMethod *metho
 	while (perform_authentication (&actx) > 0) {
 		dir = smb_context->opendir (smb_context, path);
 		actx.res = (dir != NULL) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB(("ctx->opendir(\"%s\") returned dir %p and error %d\n", path, dir, (int) actx.res));
 	}
 
 	UNLOCK_SMB();
@@ -1907,6 +2310,7 @@ do_open_directory (GnomeVFSMethod *metho
 	
 	if (dir == NULL) {
 		g_free (path);
+		DEBUG_OUT ();
 		return actx.res;
 	}
 	
@@ -1916,6 +2320,7 @@ do_open_directory (GnomeVFSMethod *metho
 	directory_handle->path = path;
 	*method_handle = (GnomeVFSMethodHandle *) directory_handle;
 
+	DEBUG_OUT ();
 	return GNOME_VFS_OK;
 }
 
@@ -1930,10 +2335,13 @@ do_close_directory (GnomeVFSMethod *meth
 	GList *l;
 	int err = -1;
 
+	DEBUG_IN ();
 	DEBUG_SMB(("do_close_directory: %p\n", directory_handle));
 
-	if (directory_handle == NULL)
+	if (directory_handle == NULL) {
+		DEBUG_OUT ();
 		return GNOME_VFS_OK;
+	}
 
 	if (directory_handle->workgroups != NULL) {
 		for (l = directory_handle->workgroups; l != NULL; l = l->next) {
@@ -1952,6 +2360,7 @@ do_close_directory (GnomeVFSMethod *meth
 		while (perform_authentication (&actx) > 0) {
 			err = smb_context->closedir (smb_context, directory_handle->dir);
 			actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+			DEBUG_SMB(("ctx->closedir(%p) returned error %d\n", directory_handle->dir, (int) actx.res));
 		}
 		
 		res = actx.res;
@@ -1960,9 +2369,46 @@ do_close_directory (GnomeVFSMethod *meth
 	g_free (directory_handle->path);
 	g_free (directory_handle);
 
+	DEBUG_OUT ();
 	return res;
 }
 
+static char *
+make_path_from_uri_and_name (const char *path, const char *name)
+{
+	char *escaped_name;
+	char *new_path;
+
+	escaped_name = gnome_vfs_escape_string (name);
+
+	if (path[strlen(path) - 1] == '/') {
+		new_path = g_strconcat (path, escaped_name, NULL);
+	} else {
+		new_path = g_strconcat (path, "/", escaped_name, NULL);
+	}
+
+	g_free (escaped_name);
+
+	return new_path;
+}
+
+static void
+add_printer_to_hash (DirectoryHandle *dh,
+		     GnomeVFSFileInfo *file_info)
+{
+	char *path;
+
+	path = make_path_from_uri_and_name (dh->path, file_info->name);
+		
+	g_hash_table_insert (printer_hash, path, path);
+}
+
+static gboolean
+is_printer (const char *uri)
+{
+	return g_hash_table_lookup (printer_hash, uri) != NULL;
+}
+
 static GnomeVFSResult
 do_read_directory (GnomeVFSMethod *method,
 		   GnomeVFSMethodHandle *method_handle,
@@ -1974,14 +2420,15 @@ do_read_directory (GnomeVFSMethod *metho
 	SmbAuthContext actx;
 	struct stat st;
 	char *statpath;
-	char *path;
 	int r = -1;
 	GList *l;
 
+	DEBUG_IN ();
 	DEBUG_SMB (("do_read_directory()\n"));
 
 	if (dh->dir == NULL) {
 		if (dh->workgroups == NULL) {
+			DEBUG_OUT ();
 			return GNOME_VFS_ERROR_EOF;
 		} else {
 			/* workgroup link */
@@ -1995,6 +2442,7 @@ do_read_directory (GnomeVFSMethod *metho
 				| GNOME_VFS_FILE_INFO_FIELDS_TYPE;
 			file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
 			file_info->mime_type = g_strdup ("application/x-desktop");
+			DEBUG_OUT ();
 			return GNOME_VFS_OK;
 		}
 	}
@@ -2018,16 +2466,20 @@ do_read_directory (GnomeVFSMethod *metho
 			} else {
 				actx.res = GNOME_VFS_OK;
 			}
+			DEBUG_SMB(("ctx->readdir(%p) returned entry %p and error %d\n", dh->dir, entry, (int) actx.res));
 		}
 		
 		if (entry == NULL) {
 			UNLOCK_SMB();
+			DEBUG_OUT ();
 			return actx.res;
 		}
 		
 	} while (entry->smbc_type == SMBC_COMMS_SHARE ||
 		 entry->smbc_type == SMBC_IPC_SHARE ||
+#if 0
 		 entry->smbc_type == SMBC_PRINTER_SHARE ||
+#endif
 		 entry->name == NULL ||
 		 strlen (entry->name) == 0 ||
 		 (entry->smbc_type == SMBC_FILE_SHARE &&
@@ -2057,29 +2509,24 @@ do_read_directory (GnomeVFSMethod *metho
 		file_info->mime_type = g_strdup ("application/x-desktop");
 		break;
 	case SMBC_PRINTER_SHARE:
+#if 0
 		/* Ignored above for now */
+#endif
 		file_info->valid_fields = file_info->valid_fields
 			| GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
 			| GNOME_VFS_FILE_INFO_FIELDS_TYPE;
 		file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
-		file_info->mime_type = g_strdup ("application/x-smb-printer");
+		file_info->mime_type = g_strdup ("application/x-desktop"); /* we'll generate the fake .desktop in do_open() */
+		add_printer_to_hash (dh, file_info);
+		debug_print ("GOT PRINTER: \"%s\"", file_info->name);
+		break;
 	case SMBC_COMMS_SHARE:
 	case SMBC_IPC_SHARE:
 		break;
 	case SMBC_DIR:
 	case SMBC_FILE:
-		path = dh->path;
-		
-		if (path[strlen(path)-1] == '/') {
-			statpath = g_strconcat (path, 
-						gnome_vfs_escape_string (file_info->name),
-						NULL);
-		} else {
-			statpath = g_strconcat (path,
-						"/",
-						gnome_vfs_escape_string (file_info->name),
-						NULL);
-		}
+		statpath = make_path_from_uri_and_name (dh->path, file_info->name);
+
 		/* TODO: might give an auth error, but should be rare due
 		   to the succeeding opendir. If this happens and we can't
 		   auth, we should terminate the readdir to avoid multiple
@@ -2093,6 +2540,7 @@ do_read_directory (GnomeVFSMethod *metho
 		while (perform_authentication (&actx) > 0) {
 			r = smb_context->stat (smb_context, statpath, &st);
 			actx.res = (r == 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+			DEBUG_SMB(("ctx->stat(\"%s\") returned error %d\n", statpath, (int) actx.res));
 		}
 		UNLOCK_SMB();
 		
@@ -2127,6 +2575,7 @@ do_read_directory (GnomeVFSMethod *metho
 		g_assert_not_reached ();
 	}
 
+	DEBUG_OUT ();
 	return GNOME_VFS_OK;
 }
 
@@ -2142,6 +2591,8 @@ do_seek (GnomeVFSMethod *method,
 	int meth_whence;
 	off_t ret = (off_t) -1;
 
+	DEBUG_IN ();
+
 	if (handle->is_data) {
 		switch (whence) {
 		case GNOME_VFS_SEEK_START:
@@ -2158,8 +2609,11 @@ do_seek (GnomeVFSMethod *method,
 			}
 			break;
 		default:
+			DEBUG_OUT ();
 			return GNOME_VFS_ERROR_NOT_SUPPORTED;
 		}
+
+		DEBUG_OUT ();
 		return GNOME_VFS_OK;
 	}
 	
@@ -2174,6 +2628,7 @@ do_seek (GnomeVFSMethod *method,
 		meth_whence = SEEK_END;
 		break;
 	default:
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_SUPPORTED;
 	}
 
@@ -2186,7 +2641,8 @@ do_seek (GnomeVFSMethod *method,
 		actx.res = (ret != (off_t) -1) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
 	}
 	UNLOCK_SMB();
-	
+
+	DEBUG_OUT ();
 	return actx.res;
 }
 
@@ -2199,8 +2655,11 @@ do_tell (GnomeVFSMethod *method,
 	SmbAuthContext actx;
 	off_t ret = (off_t) -1;
 
+	DEBUG_IN ();
+
 	if (handle->is_data) {
 		*offset_return = handle->offset;
+		DEBUG_OUT ();
 		return GNOME_VFS_OK;
 	}
 	
@@ -2215,6 +2674,8 @@ do_tell (GnomeVFSMethod *method,
 	UNLOCK_SMB();
 	
 	*offset_return = (ret == (off_t) -1) ? 0 : (GnomeVFSFileOffset) ret;
+
+	DEBUG_OUT ();
 	return actx.res;
 }
 
@@ -2227,12 +2688,14 @@ do_unlink (GnomeVFSMethod *method,
 	SmbAuthContext actx;
 	int type, err = -1;
 
+	DEBUG_IN ();
 	DEBUG_SMB (("do_unlink() %s\n",
 				gnome_vfs_uri_to_string (uri, 0)));
 
 	type = smb_uri_type (uri);
 
 	if (type == SMB_URI_ERROR) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_INVALID_URI;
 	}
 
@@ -2242,6 +2705,7 @@ do_unlink (GnomeVFSMethod *method,
 	    type == SMB_URI_SHARE ||
 	    type == SMB_URI_WORKGROUP_LINK ||
 	    type == SMB_URI_SERVER_LINK) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_PERMITTED;
 	}
 
@@ -2254,12 +2718,14 @@ do_unlink (GnomeVFSMethod *method,
 	while (perform_authentication (&actx) > 0) {
 		err = smb_context->unlink (smb_context, path);
 		actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB(("ctx->unlink(\"%s\") returned error %d\n", path, (int) actx.res));
 	}
 	
 	UNLOCK_SMB();
 
 	g_free (path);
-	
+
+	DEBUG_OUT ();
 	return actx.res;
 }
 
@@ -2276,6 +2742,7 @@ do_check_same_fs (GnomeVFSMethod *method
 	char *path2;
 	char *p1, *p2;
 
+	DEBUG_IN ();
 	DEBUG_SMB (("do_check_same_fs()\n"));
 
 	server1 =
@@ -2296,6 +2763,7 @@ do_check_same_fs (GnomeVFSMethod *method
 		g_free (path1);
 		g_free (path2);
 		*same_fs_return = FALSE;
+		DEBUG_OUT ();
 		return GNOME_VFS_OK;
 	}
                              
@@ -2324,6 +2792,7 @@ do_check_same_fs (GnomeVFSMethod *method
 	g_free (path1);
 	g_free (path2);
 
+	DEBUG_OUT ();
 	return GNOME_VFS_OK;
 }
 
@@ -2340,7 +2809,7 @@ do_move (GnomeVFSMethod *method,
 	SmbAuthContext actx;
 	int old_type, new_type;
 	
-	
+	DEBUG_IN ();
 	DEBUG_SMB (("do_move() %s %s\n",
 				gnome_vfs_uri_to_string (old_uri, 0),
 				gnome_vfs_uri_to_string (new_uri, 0)));
@@ -2350,6 +2819,7 @@ do_move (GnomeVFSMethod *method,
 
 	if (old_type != SMB_URI_SHARE_FILE ||
 	    new_type != SMB_URI_SHARE_FILE) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_PERMITTED;
 	}
 
@@ -2367,6 +2837,7 @@ do_move (GnomeVFSMethod *method,
 		err = smb_context->rename (smb_context, old_path, smb_context, new_path);
 		errnox = errno;
 		actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB(("ctx->rename(\"%s\", \"%s\") returned error %d\n", old_path, new_path, (int) actx.res));
 	}
 	UNLOCK_SMB();
 	
@@ -2383,6 +2854,7 @@ do_move (GnomeVFSMethod *method,
 			while (perform_authentication (&actx) > 0) {			
 				err = smb_context->unlink (smb_context, new_path);
 				actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+				DEBUG_SMB(("ctx->unlink(\"%s\") returned error %d\n", new_path, (int) actx.res));
 			}
 			UNLOCK_SMB();
 
@@ -2399,6 +2871,7 @@ do_move (GnomeVFSMethod *method,
 	g_free (old_path);
 	g_free (new_path);
 
+	DEBUG_OUT ();
 	return actx.res;
 }
 
@@ -2423,9 +2896,11 @@ do_make_directory (GnomeVFSMethod *metho
 	int type, err = -1;
 	SmbAuthContext actx;
 
+	DEBUG_IN ();
 	type = smb_uri_type (uri);
 
 	if (type == SMB_URI_ERROR) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_INVALID_URI;
 	}
 
@@ -2435,6 +2910,7 @@ do_make_directory (GnomeVFSMethod *metho
 	    type == SMB_URI_SHARE ||
 	    type == SMB_URI_WORKGROUP_LINK ||
 	    type == SMB_URI_SERVER_LINK) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_PERMITTED;
 	}
 
@@ -2448,12 +2924,14 @@ do_make_directory (GnomeVFSMethod *metho
 	while (perform_authentication (&actx) > 0) {
 		err = smb_context->mkdir (smb_context, path, perm);
 		actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB(("ctx->mkdir(\"%s\") returned error %d\n", path, (int) actx.res));
 	}
 
 	UNLOCK_SMB();
 
 	g_free (path);
 
+	DEBUG_OUT ();
 	return actx.res;
 }
 
@@ -2466,9 +2944,11 @@ do_remove_directory (GnomeVFSMethod *met
 	int err = -1, type;
 	SmbAuthContext actx;
 
+	DEBUG_IN ();
 	type = smb_uri_type (uri);
 
 	if (type == SMB_URI_ERROR) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_INVALID_URI;
 	}
 
@@ -2478,6 +2958,7 @@ do_remove_directory (GnomeVFSMethod *met
 	    type == SMB_URI_SHARE ||
 	    type == SMB_URI_WORKGROUP_LINK ||
 	    type == SMB_URI_SERVER_LINK) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_PERMITTED;
 	}
 
@@ -2490,11 +2971,13 @@ do_remove_directory (GnomeVFSMethod *met
 	while (perform_authentication (&actx) > 0) {
 		err = smb_context->rmdir (smb_context, path);
 		actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+		DEBUG_SMB(("ctx->rmdir(\"%s\") returned error %d\n", path, (int) actx.res));
 	}
 	UNLOCK_SMB();
 
 	g_free (path);
 
+	DEBUG_OUT ();
 	return actx.res;
 }
 
@@ -2509,11 +2992,13 @@ do_set_file_info (GnomeVFSMethod *method
 	int err = -1, errnox = 0, type;
 	SmbAuthContext actx;	
 
+	DEBUG_IN ();
 	DEBUG_SMB (("do_set_file_info: mask %x\n", mask));
 
 	type = smb_uri_type (uri);
 
 	if (type == SMB_URI_ERROR) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_INVALID_URI;
 	}
 
@@ -2523,6 +3008,7 @@ do_set_file_info (GnomeVFSMethod *method
 	    type == SMB_URI_SHARE ||
 	    type == SMB_URI_WORKGROUP_LINK ||
 	    type == SMB_URI_SERVER_LINK) {
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_PERMITTED;
 	}
 
@@ -2546,6 +3032,7 @@ do_set_file_info (GnomeVFSMethod *method
 			err = smb_context->rename (smb_context, path, smb_context, new_path);
 			errnox = errno;
 			actx.res = (err >= 0) ? GNOME_VFS_OK : gnome_vfs_result_from_errno ();
+			DEBUG_SMB(("ctx->rename(\"%s\", \"%s\") returned error %d\n", path, new_path, (int) actx.res));
 		}
 		
 		UNLOCK_SMB();
@@ -2558,31 +3045,37 @@ do_set_file_info (GnomeVFSMethod *method
 
 		if (actx.res != GNOME_VFS_OK) {
 			g_free (path);
+			DEBUG_OUT ();
 			return actx.res;
 		}
 	}
 
 	if (gnome_vfs_context_check_cancellation (context)) {
 		g_free (path);
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_CANCELLED;
 	}
 
 	if (mask & GNOME_VFS_SET_FILE_INFO_PERMISSIONS) {
 		g_free (path);
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_SUPPORTED;
 	}
 
 	if (mask & GNOME_VFS_SET_FILE_INFO_OWNER) {
 		g_free (path);
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_SUPPORTED;
 	}
 	
 	if (mask & GNOME_VFS_SET_FILE_INFO_TIME) {
 		g_free (path);
+		DEBUG_OUT ();
 		return GNOME_VFS_ERROR_NOT_SUPPORTED;
 	}
 
 	g_free (path);
+	DEBUG_OUT ();
 	return GNOME_VFS_OK;
 }
 
@@ -2614,11 +3107,50 @@ static GnomeVFSMethod method = {
 	NULL  /* do_create_symbolic_link */
 };
 
+static void
+debug_init (void)
+{
+	char *debug_flag_path;
+	struct stat st;
+
+	LOCK_SMB ();
+
+	debug_flag_path = g_build_filename (g_get_home_dir (), ".debug-gnome-vfs-smb", NULL);
+
+	if (stat (debug_flag_path, &st) == 0) {
+		char *debug_filename;
+
+		debug_filename = g_build_filename (g_get_home_dir (), "debug-gnome-vfs-smb.log", NULL);
+		debug_file = fopen (debug_filename, "w");
+		g_free (debug_filename);
+	} else
+		debug_file = NULL;
+
+	g_free (debug_flag_path);
+
+	UNLOCK_SMB ();
+}
+
+static void
+debug_shutdown (void)
+{
+	LOCK_SMB ();
+
+	if (debug_file) {
+		fclose (debug_file);
+		debug_file = NULL;
+	}
+
+	UNLOCK_SMB ();
+}
+
 GnomeVFSMethod *
 vfs_module_init (const char *method_name, const char *args)
 {
 	smb_lock = g_mutex_new ();
 
+	debug_init ();
+
 	DEBUG_SMB (("<-- smb module init called -->\n"));
 
 	if (try_init ()) {
@@ -2641,9 +3173,12 @@ vfs_module_shutdown (GnomeVFSMethod *met
 	g_hash_table_destroy (server_cache);
 	g_hash_table_destroy (workgroups);
         g_hash_table_destroy (user_cache);
+	g_hash_table_destroy (printer_hash);
 	
 	g_mutex_free (smb_lock);
 
 	DEBUG_SMB (("<-- smb module shutdown called -->\n"));
+
+	debug_shutdown ();
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]