Index: libgnomevfs/gnome-vfs-standard-callbacks.h
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-standard-callbacks.h,v
retrieving revision 1.11
diff -u -r1.11 gnome-vfs-standard-callbacks.h
--- libgnomevfs/gnome-vfs-standard-callbacks.h	20 Apr 2004 13:27:46 -0000	1.11
+++ libgnomevfs/gnome-vfs-standard-callbacks.h	11 Jun 2004 13:26:29 -0000
@@ -123,7 +123,8 @@
 	GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD = 1<<1,
 	GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME = 1<<2,
 	GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN = 1<<3,
-	GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_SAVING_SUPPORTED = 1<<4
+	GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_SAVING_SUPPORTED = 1<<4,
+	GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_ANON_SUPPORTED = 1<<5
 } GnomeVFSModuleCallbackFullAuthenticationFlags;
 
 typedef struct {
@@ -146,6 +147,10 @@
 	void *reserved2;
 } GnomeVFSModuleCallbackFullAuthenticationIn;
 
+typedef enum {
+	GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_OUT_ANON_SELECTED = 1<<0
+} GnomeVFSModuleCallbackFullAuthenticationOutFlags;
+
 typedef struct {
 	gboolean abort_auth;    /* set to TRUE if the user cancelled */
 	char *username;		/* will be freed by g_free */
@@ -154,9 +159,10 @@
 
 	gboolean save_password;
 	char *keyring;
+
+	GnomeVFSModuleCallbackFullAuthenticationOutFlags out_flags;
 	
 	/* Reserved "padding" to avoid future breaks in ABI compatibility */
-	void *reserved1;
 	void *reserved2;
 } GnomeVFSModuleCallbackFullAuthenticationOut;
 
Index: modules/ftp-method.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/modules/ftp-method.c,v
retrieving revision 1.100
diff -u -r1.100 ftp-method.c
--- modules/ftp-method.c	17 May 2004 17:58:59 -0000	1.100
+++ modules/ftp-method.c	11 Jun 2004 13:26:29 -0000
@@ -38,6 +38,8 @@
 #include <libgnomevfs/gnome-vfs-method.h>
 #include <libgnomevfs/gnome-vfs-mime.h>
 #include <libgnomevfs/gnome-vfs-mime-utils.h>
+#include <libgnomevfs/gnome-vfs-standard-callbacks.h>
+#include <libgnomevfs/gnome-vfs-module-callback-module-api.h>
 #include <libgnomevfs/gnome-vfs-module.h>
 #include <libgnomevfs/gnome-vfs-module-shared.h>
 #include <libgnomevfs/gnome-vfs-parse-ls.h>
@@ -79,7 +81,6 @@
 	gchar *dirlist;
 	gchar *dirlistptr;
 	gchar *server_type; /* the response from TYPE */
-	gboolean anonymous;
 	GnomeVFSResult fivefifty; /* the result to return for an FTP 550 */
 	GnomeVFSFileInfoOptions file_info_options;
 } FtpConnection;
@@ -114,9 +115,6 @@
 		                                GnomeVFSContext *context);
 static void           ftp_connection_release   (FtpConnection *conn);
 
-
-static const char *anon_user = "anonymous";
-static const char *anon_pass = "nobody@gnome.org";
 static const int   control_port = 21;
 
 
@@ -519,6 +517,152 @@
 
 }
 
+static void save_authn_info (GnomeVFSURI *uri,
+               gchar *user, gchar *pass, gchar *keyring)
+{
+       GnomeVFSModuleCallbackSaveAuthenticationIn in_args;
+        GnomeVFSModuleCallbackSaveAuthenticationOut out_args;
+                                                                                                                              
+        memset (&in_args, 0, sizeof (in_args));
+        memset (&out_args, 0, sizeof (out_args));
+                                                                                                                              
+        in_args.keyring = keyring;
+
+       in_args.uri = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
+        in_args.server = (char *)gnome_vfs_uri_get_host_name (uri);
+        in_args.port = gnome_vfs_uri_get_host_port (uri);
+        in_args.username = user;
+        in_args.password = pass;
+        in_args.protocol = "ftp";
+                                                                                                                              
+        gnome_vfs_module_callback_invoke (GNOME_VFS_MODULE_CALLBACK_SAVE_AUTHENTICATION,
+                                                &in_args, sizeof (in_args),
+                                                &out_args, sizeof (out_args));
+
+        g_free (in_args.uri);
+}
+
+static gboolean query_user_for_authn_info (GnomeVFSURI *uri, 
+			gchar **user, gchar **pass, gchar **keyring, gboolean *save,
+			gboolean no_username)
+{
+	GnomeVFSModuleCallbackFullAuthenticationIn in_args;
+        GnomeVFSModuleCallbackFullAuthenticationOut out_args;
+	gboolean ret;
+
+	ret = FALSE;
+
+	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.server = (char *)gnome_vfs_uri_get_host_name (uri);
+        in_args.port = gnome_vfs_uri_get_host_port (uri);
+        if (*user != NULL && *user[0] != 0) {
+                in_args.username = *user;
+        }
+
+	in_args.protocol = "ftp";
+
+	in_args.flags =	GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_SAVING_SUPPORTED | 
+			GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD; 
+        if (no_username) {
+                in_args.flags |= GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME;
+		in_args.flags |= GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_ANON_SUPPORTED;
+        }
+
+	in_args.default_user = in_args.username;
+
+	ret = gnome_vfs_module_callback_invoke (GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION,
+                                                &in_args, sizeof (in_args),
+                                                &out_args, sizeof (out_args));
+
+	if (!ret) {
+                goto error;
+        }
+                                                                                                                                             
+        ret = !out_args.abort_auth;
+                                                                                                                                             
+        if (!ret) {
+                goto error;
+        }
+
+	g_free (*user);
+	g_free (*pass);
+	if (out_args.out_flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_OUT_ANON_SELECTED) {
+		*user = g_strdup ("anonymous");
+		*pass = g_strdup ("");;
+	}
+	else {
+		*user = g_strdup (out_args.username);
+		*pass = g_strdup (out_args.password);
+	}
+
+	*save = FALSE;
+	if (out_args.save_password) {
+		*save = TRUE;
+		g_free (*keyring);
+		*keyring = g_strdup (out_args.keyring);
+	}
+
+error:
+      	g_free (in_args.uri);
+       	g_free (in_args.object);
+       	g_free (out_args.username);
+       	g_free (out_args.domain);
+       	g_free (out_args.password);
+       	g_free (out_args.keyring);
+
+	return ret;
+} 
+
+static gboolean query_keyring_for_authn_info (GnomeVFSURI *uri, gchar **user, gchar **pass)
+{
+	GnomeVFSModuleCallbackFillAuthenticationIn in_args;
+        GnomeVFSModuleCallbackFillAuthenticationOut out_args;
+        gboolean ret;
+
+        ret = FALSE;
+
+        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.server = (char *)gnome_vfs_uri_get_host_name (uri);
+        in_args.port = gnome_vfs_uri_get_host_port (uri);
+        if (*user != NULL && *user[0] != 0) {
+                in_args.username = *user;
+        }
+        in_args.protocol = "ftp";
+                                                                                                                                             
+        ret = gnome_vfs_module_callback_invoke (GNOME_VFS_MODULE_CALLBACK_FILL_AUTHENTICATION,
+                                                &in_args, sizeof (in_args),
+                                                &out_args, sizeof (out_args));
+
+	if (!ret) {
+                goto error;
+        }
+                                                                                                                                             
+        ret = out_args.valid;
+
+        if (!ret) {
+                goto error;
+        }
+
+	g_free (*user);
+	g_free (*pass);
+        *user = g_strdup (out_args.username);
+        *pass = g_strdup (out_args.password);
+                                                                                                                                             
+error:
+        g_free (in_args.uri);
+        g_free (in_args.object);
+        g_free (out_args.username);
+        g_free (out_args.domain);
+        g_free (out_args.password);
+                                                                                                                                             
+        return ret;
+}
 
 static GnomeVFSResult ftp_login (FtpConnection *conn, 
                                  const char *user, const char *password,
@@ -540,95 +684,146 @@
 	return result;
 }
 
+static GnomeVFSResult try_connection (GnomeVFSURI *uri, 
+		FtpConnection *conn,
+		gchar *user, 
+		gchar *pass,
+		GnomeVFSCancellation *cancellation)
+{
+	GnomeVFSInetConnection* inet_connection;
+	GnomeVFSResult result;
+	gint port = control_port;
+
+	if (gnome_vfs_uri_get_host_port (uri)) {
+                port = gnome_vfs_uri_get_host_port (uri);
+        }	
+
+	result = gnome_vfs_inet_connection_create (&inet_connection,
+                                                   gnome_vfs_uri_get_host_name (uri),
+                                                   port,
+                                                   cancellation);
+                                                                                                                             
+        if (result != GNOME_VFS_OK) {
+                g_warning ("gnome_vfs_inet_connection_create (\"%s\", %d) = \"%s\"",
+                           gnome_vfs_uri_get_host_name (uri),
+                           gnome_vfs_uri_get_host_port (uri),
+                           gnome_vfs_result_to_string (result));
+                return result;
+        }
+                                                                                                                             
+        conn->socket_buf = gnome_vfs_inet_connection_to_socket_buffer (inet_connection);
+                                                                                                                             
+        if (conn->socket_buf == NULL) {
+                g_warning ("Getting socket buffer failed");
+                gnome_vfs_inet_connection_destroy (inet_connection, NULL);
+                return GNOME_VFS_ERROR_GENERIC;
+        }
+        conn->offset = 0;
+                                                                                                                             
+        result = get_response (conn, cancellation);
+
+	if (result != GNOME_VFS_OK) {
+                g_warning ("ftp server (%s:%d) said `%d %s'",
+                           gnome_vfs_uri_get_host_name (uri),
+                           gnome_vfs_uri_get_host_port (uri),
+                           conn->response_code, conn->response_message);
+                return result;
+        }
+                                                                                                                             
+        result = ftp_login(conn, user, pass, cancellation);
+                                                                                                                             
+        if (result != GNOME_VFS_OK) {
+                /* login failed */
+                g_warning ("FTP server said: \"%d %s\"\n", conn->response_code,
+                           conn->response_message);
+                gnome_vfs_socket_buffer_destroy (conn->socket_buf, TRUE, cancellation);
+                return result;
+        }
+
+	return result;	
+}
 
 static GnomeVFSResult 
 ftp_connection_create (FtpConnection **connptr, GnomeVFSURI *uri, GnomeVFSContext *context) 
 {
 	FtpConnection *conn = g_new0 (FtpConnection, 1);
 	GnomeVFSResult result;
-	gint port = control_port;
-	const gchar *user = anon_user;
-	const gchar *pass = anon_pass;
-	GnomeVFSInetConnection* inet_connection;
+	gchar *user = NULL;
+	gchar *pass = NULL;
 	GnomeVFSCancellation *cancellation;
+	gchar *keyring = NULL;
+        gboolean save_authn = FALSE;
+	gboolean no_username = TRUE;
 	
 	cancellation = get_cancellation (context);
 	conn->uri = gnome_vfs_uri_dup (uri);
 	conn->response_buffer = g_string_new ("");
 	conn->response_code = -1;
-	conn->anonymous = TRUE;
 	conn->fivefifty = GNOME_VFS_ERROR_NOT_FOUND;
 
-	if (gnome_vfs_uri_get_host_port (uri)) {
-		port = gnome_vfs_uri_get_host_port (uri);
-	}
-
-	if (gnome_vfs_uri_get_user_name (uri)) {
-		user = gnome_vfs_uri_get_user_name (uri);
-		conn->anonymous = FALSE;
-	}
-
-	if (gnome_vfs_uri_get_password (uri)) {
-		pass = gnome_vfs_uri_get_password (uri);
-	}
-
-	result = gnome_vfs_inet_connection_create (&inet_connection, 
-						   gnome_vfs_uri_get_host_name (uri), 
-						   port, 
-						   cancellation);
-	
-	if (result != GNOME_VFS_OK) {
-	        g_warning ("gnome_vfs_inet_connection_create (\"%s\", %d) = \"%s\"",
-			   gnome_vfs_uri_get_host_name (uri),
-			   gnome_vfs_uri_get_host_port (uri),
-			   gnome_vfs_result_to_string (result));
-		gnome_vfs_uri_unref (conn->uri);
-		g_string_free (conn->response_buffer, TRUE);
-		g_free (conn);
-		return result;
-	}
-
-	conn->socket_buf = gnome_vfs_inet_connection_to_socket_buffer (inet_connection);
-
-	if (conn->socket_buf == NULL) {
-		g_warning ("Getting socket buffer failed");
-		gnome_vfs_inet_connection_destroy (inet_connection, NULL);
-		gnome_vfs_uri_unref (conn->uri);
-		g_string_free (conn->response_buffer, TRUE);
-		g_free (conn);
-		return GNOME_VFS_ERROR_GENERIC;
-	}
-	conn->offset = 0;
-
-	result = get_response (conn, cancellation);
-
-	if (result != GNOME_VFS_OK) { 
-		g_warning ("ftp server (%s:%d) said `%d %s'", 
-			   gnome_vfs_uri_get_host_name (uri),
-			   gnome_vfs_uri_get_host_port (uri), 
-			   conn->response_code, conn->response_message);
-		gnome_vfs_uri_unref (conn->uri);
-		g_string_free (conn->response_buffer, TRUE);
-		g_free (conn);
-		return result;
-	}
-
-	result = ftp_login(conn, user, pass, cancellation);
+	if ((gnome_vfs_uri_get_user_name (uri) == NULL) ||
+            (gnome_vfs_uri_get_password (uri) == NULL)) {
+		if (gnome_vfs_uri_get_user_name (uri) != NULL) {
+			user = g_strdup (gnome_vfs_uri_get_user_name (uri));
+			no_username = FALSE;
+		}
+		if (query_keyring_for_authn_info(uri, &user, &pass)) {
+                	result = try_connection (uri, conn, user, pass, cancellation);
+                       	if (result != GNOME_VFS_OK) {
+                       		gnome_vfs_uri_unref (conn->uri);
+                               	g_string_free (conn->response_buffer, TRUE);
+                               	g_free (conn);
+				g_free (user);
+				g_free (pass);
+                               	return result;
+			}
+                }
+		else {
+			while (TRUE) {
+				if (!query_user_for_authn_info (uri, &user, &pass, &keyring, &save_authn, 
+					no_username)) {
+					gnome_vfs_uri_unref (conn->uri);
+					g_string_free (conn->response_buffer, TRUE);
+					g_free (conn);
+					g_free (user);
+					g_free (pass);
+					g_free (keyring);
+                                	return GNOME_VFS_ERROR_ACCESS_DENIED;
+				}
+				g_string_free (conn->response_buffer, TRUE);
+                        	conn->response_buffer = g_string_new ("");
+				conn->response_code = -1;
+				result = try_connection (uri, conn, user, pass, cancellation);
+				if (result == GNOME_VFS_OK) {
+					break;
+				}
+                        }
+               	}
+       	}
+       	else {
+               	user = g_strdup (gnome_vfs_uri_get_user_name (uri));
+               	pass = g_strdup (gnome_vfs_uri_get_password (uri));
 
-	if (result != GNOME_VFS_OK) {
-		/* login failed */
-		g_warning ("FTP server said: \"%d %s\"\n", conn->response_code,
-			   conn->response_message);
-		gnome_vfs_socket_buffer_destroy (conn->socket_buf, TRUE, cancellation);
-		gnome_vfs_uri_unref (conn->uri);
-		g_string_free (conn->response_buffer, TRUE);
-		g_free (conn);
-			
-		return result;
-	}
+		result = try_connection (uri, conn, user, pass, cancellation);
+		if (result != GNOME_VFS_OK) {
+                	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 (save_authn) {
+               	save_authn_info (uri, user, pass, keyring);
+		g_free (keyring);
+        }
+        g_free (user);
+        g_free (pass);
+
 	/* Image mode (binary to the uninitiated) */
 
 	do_basic_command (conn, "TYPE I", cancellation);
@@ -755,12 +950,12 @@
 		conn->uri = gnome_vfs_uri_dup (uri);
 		possible_connections = g_list_remove (possible_connections, 
 						      conn);
-		g_hash_table_insert (spare_connections, uri, 
-				     possible_connections);
 
 		/* Reset offset */
-		conn->offset = 0;
+                conn->offset = 0;
 
+		g_hash_table_insert (spare_connections, uri, 
+				     possible_connections);
 		/* make sure connection hasn't timed out */
 		result = do_basic_command(conn, "PWD", cancellation);
 		if (result != GNOME_VFS_OK) {
