From fc649fb9d8d2edd3eef0ba6ba54b769c956ab3cb Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sun, 12 Oct 2008 12:17:53 +0200 Subject: GVFS plugin: Implement question and password callbacks --- gvfs/gvfs.c | 228 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 164 insertions(+), 64 deletions(-) (limited to 'gvfs/gvfs.c') diff --git a/gvfs/gvfs.c b/gvfs/gvfs.c index 8ffa70e..5baef7d 100644 --- a/gvfs/gvfs.c +++ b/gvfs/gvfs.c @@ -31,10 +31,9 @@ -#define VERSION "0.1.1" -#define BUILD_DATE "2008-10-06" +#define VERSION "0.1.2" +#define BUILD_DATE "2008-10-11" #define DEFAULT_BLOCK_SIZE 0x10000 /* 64kB */ -#define ANON_FTP_PASS "ftpuser@tuxcmd.net" #define CONST_DEFAULT_QUERY_INFO_ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_NAME "," \ G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," G_FILE_ATTRIBUTE_STANDARD_SIZE "," \ @@ -51,10 +50,15 @@ struct TVFSGlobs { GMainLoop *mount_main_loop; TVFSResult mount_result; gchar *mount_password; + int mount_try; gboolean ftp_anonymous; gboolean break_get_dir_size; guint32 block_size; + + TVFSAskQuestionCallback callback_ask_question; + TVFSAskPasswordCallback callback_ask_password; + void *callbacks_data; }; @@ -123,42 +127,108 @@ ask_password_cb (GMountOperation *op, gpointer user_data) { struct TVFSGlobs *globs; + char *username; + char *password; + int anonymous; + char *domain; + TVFSPasswordSave password_save; + int result; + globs = (struct TVFSGlobs*) user_data; g_assert (globs != NULL); + globs->mount_try++; + + /* First pass, we have a password to supply */ + if (globs->mount_try == 1) { + if ((flags & G_ASK_PASSWORD_NEED_PASSWORD) && globs->mount_password) { + printf ("(WW) ask_password_cb: mount_try = %d, setting password extracted from URI...\n", globs->mount_try); + g_mount_operation_set_password (op, globs->mount_password); + g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED); + return; + } else + if ((flags & G_ASK_PASSWORD_ANONYMOUS_SUPPORTED) && globs->ftp_anonymous) { + printf ("(WW) ask_password_cb: mount_try = %d, trying FTP anonymous login...\n", globs->mount_try); + g_mount_operation_set_anonymous (op, TRUE); + g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED); + return; + } + } - g_print ("(WW) ask_password_cb: message = '%s'\n", message); - if (globs->ftp_anonymous) - g_print ("(II) Trying anonymous FTP login...\n"); + /* Ask user for password */ + g_print ("(WW) ask_password_cb: mount_try = %d, message = '%s'\n", globs->mount_try, message); + + username = NULL; + domain = NULL; + password = NULL; + anonymous = FALSE; + password_save = VFS_PASSWORD_SAVE_NEVER; + + if (globs->callback_ask_password) { + fprintf (stderr, " (II) Spawning callback_ask_password (0x%.16llX)...\n", (unsigned long long) globs->callback_ask_password); + result = globs->callback_ask_password (message, default_user, default_domain, flags, + &username, &password, &anonymous, &domain, &password_save, + globs->callbacks_data); + fprintf (stderr, " (II) Received result = %d\n", result); + if (result) { + if (flags & G_ASK_PASSWORD_NEED_USERNAME) + g_mount_operation_set_username (op, username); + if (flags & G_ASK_PASSWORD_NEED_DOMAIN) + g_mount_operation_set_domain (op, domain); + if (flags & G_ASK_PASSWORD_NEED_PASSWORD) + g_mount_operation_set_password (op, password); + if (flags & G_ASK_PASSWORD_ANONYMOUS_SUPPORTED) + g_mount_operation_set_anonymous (op, anonymous); + if (flags & G_ASK_PASSWORD_SAVING_SUPPORTED) + g_mount_operation_set_password_save (op, password_save); + g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED); + } + else + g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED); + return; + } + /* Unhandled, abort */ + g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED); +} - if (flags & G_ASK_PASSWORD_NEED_USERNAME) - { - g_print (" need username...\n"); - if (globs->ftp_anonymous) - g_mount_operation_set_username (op, "anonymous"); +static void +ask_question_cb (GMountOperation *op, + const gchar *message, + const gchar *choices[], + gpointer user_data) +{ + struct TVFSGlobs *globs; + int len; + int choice; -/* FIXME: need proper API to spawn a callback - g_mount_operation_set_username (op, s); */ - } + globs = (struct TVFSGlobs*) user_data; + g_assert (globs != NULL); - if (flags & G_ASK_PASSWORD_NEED_DOMAIN) - { - g_print (" need domain...\n"); -/* FIXME: need proper API to spawn a callback - g_mount_operation_set_domain (op, s); */ - } + g_print ("(WW) ask_question_cb: message = '%s'\n", message); - if (flags & G_ASK_PASSWORD_NEED_PASSWORD) - { - g_print (" need password...\n"); - if (globs->mount_password) - g_mount_operation_set_password (op, globs->mount_password); - else - if (globs->ftp_anonymous) - g_mount_operation_set_password (op, ANON_FTP_PASS); + len = 0; + while (choices[len] != NULL) { + g_print ("(WW) ask_question_cb: choice[%d] = '%s'\n", len, choices[len]); + len++; + } + + choice = -1; + if (globs->callback_ask_question) { + fprintf (stderr, " (II) Spawning callback_ask_question (0x%.16llX)...\n", (unsigned long long) globs->callback_ask_question); + globs->callback_ask_question (message, choices, &choice, globs->callbacks_data); + fprintf (stderr, " (II) Received choice = %d\n", choice); + + if (choice >= 0) { + g_mount_operation_set_choice (op, choice); + g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED); + } + else { + g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED); } + return; + } - g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED); + g_mount_operation_reply (op, G_MOUNT_OPERATION_UNHANDLED); } static void @@ -196,8 +266,10 @@ vfs_handle_mount (struct TVFSGlobs *globs, GFile *file) g_print ("(II) Mounting location...\n"); op = g_mount_operation_new (); - g_signal_connect (op, "ask_password", (GCallback)ask_password_cb, globs); + g_signal_connect (op, "ask-password", (GCallback)ask_password_cb, globs); + g_signal_connect (op, "ask-question", (GCallback)ask_question_cb, globs); globs->mount_result = cVFS_Failed; + globs->mount_try = 0; /* Inspiration taken from Bastien Nocera's http://svn.gnome.org/viewvc/totem-pl-parser/trunk/plparse/totem-disc.c?view=markup */ globs->mount_main_loop = g_main_loop_new (NULL, FALSE); @@ -228,9 +300,24 @@ VFSNew (TVFSLogFunc log_func) globs->break_get_dir_size = FALSE; globs->block_size = DEFAULT_BLOCK_SIZE; + globs->callbacks_data = NULL; + globs->callback_ask_question = NULL; + globs->callback_ask_password = NULL; + return globs; } +void +VFSSetCallbacks (struct TVFSGlobs *globs, + TVFSAskQuestionCallback ask_question_callback, + TVFSAskPasswordCallback ask_password_callback, + void *data) +{ + globs->callback_ask_question = ask_question_callback; + globs->callback_ask_password = ask_password_callback; + globs->callbacks_data = data; +} + void VFSFree (struct TVFSGlobs *globs) { @@ -292,7 +379,6 @@ VFSOpen (struct TVFSGlobs *globs, char *sName) GFileInfo *info; GError *error; TVFSResult res; - gboolean try_again; gchar **uri_matched; char *uri_schema, *uri_username, *uri_password, *uri_service; gchar *uri; @@ -358,28 +444,27 @@ VFSOpen (struct TVFSGlobs *globs, char *sName) globs->ftp_anonymous = strcasestr (sName, "ftp://") == sName; } - g_print ("(II) VFSOpen: opening URI '%s'\n", uri ? uri : sName); f = g_file_new_for_commandline_arg (uri ? uri : sName); if (uri) g_free (uri); - try_again = FALSE; while (1) { error = NULL; info = g_file_query_info (f, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error); + /* Fallback to parent directory if specified path doesn't exist */ if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { f2 = g_file_get_parent (f); if (f2) { g_object_unref (f); f = f2; - try_again = TRUE; g_error_free (error); continue; } } + /* Mount the target */ if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_MOUNTED)) { g_error_free (error); error = NULL; @@ -389,6 +474,7 @@ VFSOpen (struct TVFSGlobs *globs, char *sName) else continue; } + /* Any other errors --> report */ if (error) { g_print ("(EE) VFSOpen: g_file_query_info() error: %s\n", error->message); res = g_error_to_TVFSResult (error); @@ -513,41 +599,55 @@ VFSChangeDir (struct TVFSGlobs *globs, char *NewPath) return cVFS_Failed; } - error = NULL; res = cVFS_OK; - en = g_file_enumerate_children (f, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error); - - /* if the target is shortcut, change the URI */ - if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY)) { - error_shortcut = NULL; - info = g_file_query_info (f, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error_shortcut); - if (info) { - target_uri = g_strdup (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI)); - g_object_unref (info); - if (target_uri) { - g_print ("(WW) VFSChangeDir: following shortcut, changing URI to '%s'\n", target_uri); + while (1) { + error = NULL; + en = g_file_enumerate_children (f, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error); + + /* if the target is shortcut, change the URI */ + if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY)) { + error_shortcut = NULL; + info = g_file_query_info (f, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error_shortcut); + if (info) { + target_uri = g_strdup (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI)); + g_object_unref (info); + if (target_uri) { + g_print ("(WW) VFSChangeDir: following shortcut, changing URI to '%s'\n", target_uri); + g_object_unref (f); + f = g_file_new_for_uri (target_uri); + g_free (target_uri); + g_error_free (error); + continue; + } + } + if (error_shortcut) + g_error_free (error_shortcut); + } + /* Mount the target */ + if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_MOUNTED)) { + g_error_free (error); + res = vfs_handle_mount (globs, f); + if (res != cVFS_OK) { g_object_unref (f); - f = g_file_new_for_uri (target_uri); - g_free (target_uri); - g_error_free (error); - error = NULL; - en = g_file_enumerate_children (f, CONST_DEFAULT_QUERY_INFO_ATTRIBUTES, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error); + return res; } + else + continue; } - if (error_shortcut) - g_error_free (error_shortcut); + /* Any other errors --> report */ + if (error) { + g_print ("(EE) VFSChangeDir: g_file_enumerate_children() error: %s\n", error->message); + res = g_error_to_TVFSResult (error); + g_error_free (error); + g_object_unref (f); + return res; + } + /* everything ok? */ + break; } - if (error) { - g_print ("(EE) VFSChangeDir: g_file_enumerate_children() error: %s\n", error->message); - res = g_error_to_TVFSResult (error); - g_error_free (error); - g_object_unref (f); - return res; - } globs->enumerator = en; g_object_unref (globs->file); globs->file = f; @@ -1372,6 +1472,6 @@ VFSCopyIn (struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, * - block size settings for GIO subsystem * - variable block size for different protocols? * - support for appending in VFSCopyIn - * - authentication improvements (needs new VFS API) + * DONE- authentication improvements (needs new VFS API) * ***/ -- cgit v1.2.3