--- gnome-vfs-2.2.3/modules/ftp-method.c	2003-06-05 06:42:07.000000000 -0700
+++ gnome-vfs-2.2.3.mod1/modules/ftp-method.c	2003-06-05 06:44:00.000000000 -0700
@@ -52,6 +52,7 @@
 #include <libgnomevfs/gnome-vfs-module-shared.h>
 #include <libgnomevfs/gnome-vfs-parse-ls.h>
 #include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-standard-callbacks.h>
 #include <stdio.h> /* for sscanf */
 #include <stdlib.h> /* for atoi */
 #include <string.h>
@@ -92,6 +93,11 @@
 	GnomeVFSFileInfoOptions file_info_options;
 } FtpConnection;
 
+typedef struct {
+	gchar *user;
+	gchar *pass;
+} LoginInfo;
+
 static const char USE_PROXY_KEY[] = "/system/http_proxy/use_http_proxy";
 
 
@@ -121,7 +127,10 @@
 		                                FtpConnection **connection, 
 		                                GnomeVFSContext *context);
 static void           ftp_connection_release   (FtpConnection *conn);
-
+static guint          authn_hash_func  (gconstpointer c);
+static gint           authn_hash_equal (gconstpointer c, gconstpointer d);
+static void	      authn_hash_value_destroy (gpointer data);
+static void 	      authn_hash_key_destroy (gpointer data);
 
 static const char *anon_user = "anonymous";
 static const char *anon_pass = "nobody@gnome.org";
@@ -133,6 +142,8 @@
 G_LOCK_DEFINE_STATIC (spare_connections);
 static gint total_connections = 0;
 static gint allocated_connections = 0;
+static GHashTable *authn_cache = NULL;
+G_LOCK_DEFINE_STATIC (authn_cache);
 
 #if ENABLE_FTP_DEBUG
 
@@ -527,6 +538,96 @@
 	return result;
 }
 
+static void get_authn_info (GnomeVFSURI *uri, gchar **user, gchar **pass)
+{
+	GnomeVFSModuleCallbackAuthenticationIn in_args;
+        GnomeVFSModuleCallbackAuthenticationOut out_args;
+                                                                                                                             
+        memset (&in_args, 0, sizeof (in_args));
+        memset (&out_args, 0, sizeof (out_args));
+                                                                                                                             
+        in_args.uri = gnome_vfs_uri_to_string (uri, 
+			GNOME_VFS_URI_HIDE_NONE);
+        in_args.auth_type = AuthTypeBasic;
+                                                                                                                             
+        gnome_vfs_module_callback_invoke (GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION,
+                                          &in_args, sizeof (in_args),
+                                          &out_args, sizeof (out_args));
+        g_free (in_args.uri);
+        g_free (*user);
+        g_free (*pass);
+        *user = g_strdup (out_args.username);
+        *pass = g_strdup (out_args.password);
+}
+
+static void authn_cache_add (GnomeVFSURI *uri, const gchar *user, const gchar *pass)
+{
+	LoginInfo *info;
+
+	G_LOCK (authn_cache);
+
+        if (authn_cache == NULL) {
+        	authn_cache = g_hash_table_new_full (authn_hash_func,
+                              			     authn_hash_equal,
+						     authn_hash_key_destroy,
+						     authn_hash_value_destroy);
+        }
+
+	info = (LoginInfo *) g_malloc (sizeof (LoginInfo));
+	info->user = g_strdup (user);
+	info->pass = g_strdup (pass);
+ 
+	if (g_hash_table_lookup (authn_cache, uri) != NULL) {
+		/* replace */
+        	g_hash_table_insert (authn_cache, uri, info);
+	}
+	else {
+		/* insert */
+		g_hash_table_insert (authn_cache, 
+				     gnome_vfs_uri_dup (uri), 
+				     info);	
+	}
+
+        G_UNLOCK (authn_cache);
+}
+
+static void authn_cache_remove (GnomeVFSURI *uri)
+{
+	G_LOCK (authn_cache);
+
+	if (authn_cache == NULL) {
+		G_UNLOCK (authn_cache);
+		return;
+	}
+
+	g_hash_table_remove (authn_cache, uri);
+
+	G_UNLOCK (authn_cache);
+} 
+
+static gboolean authn_cache_get_login_info (GnomeVFSURI *uri, gchar **user, gchar **pass) 
+{
+	LoginInfo *info = NULL;
+
+	G_LOCK (authn_cache);
+
+	if (authn_cache != NULL) {
+		info = g_hash_table_lookup (authn_cache, uri);
+	}
+
+	if (info != NULL) {
+		g_free (*user);
+		g_free (*pass);
+		*user = g_strdup (info->user);
+		*pass = g_strdup (info->pass);
+		G_UNLOCK (authn_cache);
+		return TRUE;
+	}
+
+	G_UNLOCK (authn_cache);
+
+	return FALSE;
+}
 
 static GnomeVFSResult 
 ftp_connection_create (FtpConnection **connptr, GnomeVFSURI *uri, GnomeVFSContext *context) 
@@ -534,8 +635,9 @@
 	FtpConnection *conn = g_new0 (FtpConnection, 1);
 	GnomeVFSResult result;
 	gint port = control_port;
-	const gchar *user = anon_user;
-	const gchar *pass = anon_pass;
+	gchar *user = g_strdup(anon_user);
+	gchar *pass = g_strdup(anon_pass);
+	gboolean password_requested;
 	
 	conn->uri = gnome_vfs_uri_dup (uri);
 	conn->response_buffer = g_string_new ("");
@@ -548,12 +650,23 @@
 	}
 
 	if (gnome_vfs_uri_get_user_name (uri)) {
-		user = gnome_vfs_uri_get_user_name (uri);
+		g_free (user);
+		user = g_strdup(gnome_vfs_uri_get_user_name (uri));
 		conn->anonymous = FALSE;
 	}
 
 	if (gnome_vfs_uri_get_password (uri)) {
-		pass = gnome_vfs_uri_get_password (uri);
+		g_free (pass);
+		pass = g_strdup(gnome_vfs_uri_get_password (uri));
+	}
+
+	password_requested = FALSE;
+	if ((gnome_vfs_uri_get_user_name (uri) == NULL) ||
+	    (gnome_vfs_uri_get_password (uri) == NULL)) {
+		if (!authn_cache_get_login_info (uri, &user, &pass)) {
+			get_authn_info (uri, &user, &pass);
+			password_requested = TRUE;
+		}
 	}
 
 	result = gnome_vfs_inet_connection_create (&conn->inet_connection, 
@@ -569,6 +682,8 @@
 		gnome_vfs_uri_unref (conn->uri);
 		g_string_free (conn->response_buffer, TRUE);
 		g_free (conn);
+                g_free (user);
+                g_free (pass);
 		return result;
 	}
 
@@ -580,6 +695,8 @@
 		gnome_vfs_uri_unref (conn->uri);
 		g_string_free (conn->response_buffer, TRUE);
 		g_free (conn);
+                g_free (user);
+                g_free (pass);
 		return GNOME_VFS_ERROR_GENERIC;
 	}
 
@@ -593,6 +710,8 @@
 		gnome_vfs_uri_unref (conn->uri);
 		g_string_free (conn->response_buffer, TRUE);
 		g_free (conn);
+                g_free (user);
+                g_free (pass);
 		return result;
 	}
 
@@ -607,12 +726,24 @@
 		gnome_vfs_uri_unref (conn->uri);
 		g_string_free (conn->response_buffer, TRUE);
 		g_free (conn);
+		g_free (user);
+        	g_free (pass);
 			
 		return result;
 	}
 
 	/* okay, we should be connected now */
 
+	if (password_requested) {	
+		/* add to cache only if the user typed it in
+		   and the login was successful
+		 */
+		authn_cache_add (uri, user, pass);
+	}
+
+	g_free (user);
+        g_free (pass);
+
 	/* Image mode (binary to the uninitiated) */
 
 	do_basic_command (conn, "TYPE I");
@@ -641,6 +772,8 @@
 	if (conn->socket_buf) 
 	        gnome_vfs_socket_buffer_destroy (conn->socket_buf, FALSE);
 
+	authn_cache_remove (conn->uri);
+
 	gnome_vfs_uri_unref (conn->uri);
 	g_free (conn->cwd);
 
@@ -713,6 +846,45 @@
 		gnome_vfs_uri_get_host_port (uri2);
 }
 
+static guint
+authn_hash_func (gconstpointer c)
+{
+        GnomeVFSURI *uri = (GnomeVFSURI *) c;
+                                                                                                                             
+        return my_str_hash (gnome_vfs_uri_get_host_name (uri)) +
+                my_str_hash (gnome_vfs_uri_get_user_name (uri)) +
+                gnome_vfs_uri_get_host_port (uri);
+}
+                                                                                                                             
+static gint
+authn_hash_equal (gconstpointer c,
+                          gconstpointer d)
+{
+        GnomeVFSURI *uri1 = (GnomeVFSURI *)c;
+        GnomeVFSURI *uri2 = (GnomeVFSURI *) d;
+                                                                                                                             
+        return my_str_equal (gnome_vfs_uri_get_host_name(uri1),
+                             gnome_vfs_uri_get_host_name (uri2)) &&
+                my_str_equal (gnome_vfs_uri_get_user_name (uri1),
+                              gnome_vfs_uri_get_user_name (uri2)) &&
+                gnome_vfs_uri_get_host_port (uri1) ==
+                gnome_vfs_uri_get_host_port (uri2);
+}
+
+static void authn_hash_value_destroy (gpointer data)
+{
+	LoginInfo *info = (LoginInfo *) data;
+
+	g_free (info->user);
+	g_free (info->pass);
+	g_free (info);
+}
+
+static void authn_hash_key_destroy (gpointer data)
+{
+	gnome_vfs_uri_unref ((GnomeVFSURI *)data);
+}
+
 static GnomeVFSResult 
 ftp_connection_acquire (GnomeVFSURI *uri, FtpConnection **connection, GnomeVFSContext *context) 
 {
@@ -1676,4 +1848,5 @@
 void
 vfs_module_shutdown (GnomeVFSMethod *method)
 {
+	g_hash_table_destroy (authn_cache);
 }
