[seahorse] Rework password prompting, key generation and upload.



commit 8f165666aacb2403395f9fdc739a1b2ec294ddde
Author: Stef Walter <stefw collabora co uk>
Date:   Thu Sep 15 10:04:43 2011 +0200

    Rework password prompting, key generation and upload.
    
     * openssh changed and we can no longer pass file descriptors to
       our seahorse-ssh-askpass process.
     * Rework how seahorse-ssh-askpass works, and have it pormpt for
       the password directly.
     * We can no longer ask for confirmation of passwords in the same
       prompt, but at least things work.
     * Fix issue with showing help when generating key.
     * Close key generation and upload dialogs before we start ssh
       operations.

 ssh/seahorse-ssh-askpass.c    |  170 ++++++++++----------
 ssh/seahorse-ssh-generate.c   |   16 +-
 ssh/seahorse-ssh-generate.xml |    1 -
 ssh/seahorse-ssh-operation.c  |  363 +++++++----------------------------------
 ssh/seahorse-ssh-source.c     |   86 +++++++---
 ssh/seahorse-ssh-upload.c     |    5 +-
 6 files changed, 211 insertions(+), 430 deletions(-)
---
diff --git a/ssh/seahorse-ssh-askpass.c b/ssh/seahorse-ssh-askpass.c
index aad85a3..7b380a1 100644
--- a/ssh/seahorse-ssh-askpass.c
+++ b/ssh/seahorse-ssh-askpass.c
@@ -2,6 +2,7 @@
  * Seahorse
  *
  * Copyright (C) 2005 Stefan Walter
+ * Copyright (C) 2011 Collabora Ltd.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,102 +18,101 @@
  * Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330,
  * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
  */
  
 #include "config.h"
 
-#include <errno.h>
+#include "seahorse-passphrase.h"
+
 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
-static FILE* seahorse_link = NULL;
- 
-static gchar* 
-askpass_command (const gchar *cmd, const gchar *arg)
+int
+main (int argc, char* argv[])
 {
-    const gchar* env;
-    gchar *t;
-    int fd;
-        
-    /* Try an open the connection with seahorse */
-    if (!seahorse_link) {
-        env = g_getenv ("SEAHORSE_SSH_ASKPASS_FD");
-        if (env == NULL)
-            return NULL;
-        g_unsetenv ("SEAHORSE_SSH_ASKPASS_FD");
-        
-        fd = strtol (env, &t, 10);
-        if (*t) {
-            g_warning ("fd received from seahorse was not valid: %s", env);
-            return NULL;
-        }
-        
-        seahorse_link = fdopen (fd, "r+b");
-        if (!seahorse_link) {
-            g_warning ("couldn't open fd %d: %s", fd, strerror (errno));
-            return NULL;
-        }
-        
-        setvbuf(seahorse_link, 0, _IONBF, 0);
-    }
-    
-    /* Request a setting be sent */
-    fprintf (seahorse_link, "%s %s\n", cmd, arg ? arg : "");
-    fflush (seahorse_link);
-    
-    /* Read the setting */
-    t = g_new0 (gchar, 512);
-    fgets (t, 512, seahorse_link);
-
-    /* Make sure it worked */
-    if (ferror (seahorse_link)) {
-        g_warning ("error reading from seahorse");
-        fclose (seahorse_link);
-        seahorse_link = NULL;
-        g_free (t);
-        return NULL;
-    }
-    
-    return t;
-}
+	GtkDialog *dialog;
+	const gchar *title;
+	const gchar *argument;
+	gchar *message;
+	const gchar *flags;
+	gint result;
+	const gchar *pass;
+	gsize len;
 
-int main (int argc, char* argv[])
-{
-    gchar *pass, *message, *p;
-
-    bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
-    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-    textdomain (GETTEXT_PACKAGE);
-
-    /* Non buffered stdout */
-    setvbuf(stdout, 0, _IONBF, 0);
-
-    if (argc > 1)
-        message = g_strjoinv (" ", argv + 1);
-    else 
-        message = g_strdup (_("Enter your Secure Shell passphrase:"));
-
-    /* Check if we're being handed a password from seahorse */
-    pass = askpass_command ("PASSWORD", message);
-    g_free (message);
-    
-    if (pass == NULL)
-        return 1;
-    
-    if (write (1, pass, strlen (pass)) != strlen (pass))
-	    g_warning ("couldn't write out password properly");
-    for (p = pass; *p; p++) 
-        *p = 0;
-    g_free (pass);
-
-    if (seahorse_link)
-        fclose (seahorse_link);
-    
-    return 0;
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+
+	gtk_init (&argc, &argv);
+
+	/* Non buffered stdout */
+	setvbuf (stdout, 0, _IONBF, 0);
+
+	/* TODO: Change lousy default, rarely used, and string freeze right now */
+	title = g_getenv ("SEAHORSE_SSH_ASKPASS_TITLE");
+	if (!title || !title[0])
+		title = _("Enter your Secure Shell passphrase:");
+
+	message = (gchar *)g_getenv ("SEAHORSE_SSH_ASKPASS_MESSAGE");
+	if (message && message[0])
+		message = g_strdup (message);
+	else if (argc > 1)
+		message = g_strjoinv (" ", argv + 1);
+	else
+		message = g_strdup (_("Enter your Secure Shell passphrase:"));
+
+	argument = g_getenv ("SEAHORSE_SSH_ASKPASS_ARGUMENT");
+	if (!argument)
+		argument = "";
+
+	flags = g_getenv ("SEAHORSE_SSH_ASKPASS_FLAGS");
+	if (!flags)
+		flags = "";
+	if (strstr (flags, "multiple")) {
+		gchar *lower = g_ascii_strdown (message, -1);
+
+		/* Need the old passphrase */
+		if (strstr (lower, "old pass")) {
+			title = _("Old Key Passphrase");
+			message = g_strdup_printf (_("Enter the old passphrase for: %s"), argument);
+
+		/* Look for the new passphrase thingy */
+		} else if (strstr (lower, "new pass")) {
+			title = _("New Key Passphrase");
+			message = g_strdup_printf (_("Enter the new passphrase for: %s"), argument);
+
+		/* Confirm the new passphrase, just send it again */
+		} else if (strstr (lower, "again")) {
+			title = _("New Key Passphrase");
+			message = g_strdup_printf (_("Enter the new passphrase again: %s"), argument);
+		}
+
+		g_free (lower);
+	}
+
+	dialog = seahorse_passphrase_prompt_show (title, message, _("Password:"),
+	                                          NULL, FALSE);
+
+	g_free (message);
+
+	result = 1;
+	if (gtk_dialog_run (dialog) == GTK_RESPONSE_ACCEPT) {
+		pass = seahorse_passphrase_prompt_get (dialog);
+		len = strlen (pass ? pass : "");
+		if (write (1, pass, len) != len) {
+			g_warning ("couldn't write out password properly");
+			result = 1;
+		} else {
+			result = 0;
+		}
+	}
+
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+	return result;
 }
diff --git a/ssh/seahorse-ssh-generate.c b/ssh/seahorse-ssh-generate.c
index 6cb6bf5..e6e2512 100644
--- a/ssh/seahorse-ssh-generate.c
+++ b/ssh/seahorse-ssh-generate.c
@@ -106,16 +106,13 @@ on_generate_complete (GObject *source,
                       GAsyncResult *result,
                       gpointer user_data)
 {
-	SeahorseWidget *swidget = SEAHORSE_WIDGET (user_data);
 	GError *error = NULL;
 
 	seahorse_ssh_op_generate_finish (SEAHORSE_SSH_SOURCE (source),
 	                                 result, &error);
 
 	if (error != NULL)
-		seahorse_util_handle_error (&error, swidget, _("Couldn't generate Secure Shell key"));
-
-	g_object_unref (swidget);
+		seahorse_util_handle_error (&error, NULL, _("Couldn't generate Secure Shell key"));
 }
 
 static void
@@ -123,7 +120,6 @@ on_generate_complete_and_upload (GObject *source,
                                  GAsyncResult *result,
                                  gpointer user_data)
 {
-	SeahorseWidget *swidget = SEAHORSE_WIDGET (user_data);
 	GError *error = NULL;
 	SeahorseObject *object;
 	GList *keys;
@@ -132,15 +128,13 @@ on_generate_complete_and_upload (GObject *source,
 	                                          result, &error);
 
 	if (error != NULL) {
-		seahorse_util_handle_error (&error, swidget, _("Couldn't generate Secure Shell key"));
+		seahorse_util_handle_error (&error, NULL, _("Couldn't generate Secure Shell key"));
 
 	} else {
 		keys = g_list_append (NULL, object);
-		seahorse_ssh_upload_prompt (keys, GTK_WINDOW (seahorse_widget_get_widget (swidget, swidget->name)));
+		seahorse_ssh_upload_prompt (keys, NULL);
 		g_list_free (keys);
 	}
-
-	g_object_unref (swidget);
 }
 
 static void
@@ -199,9 +193,11 @@ on_response (GtkDialog *dialog, guint response, SeahorseWidget *swidget)
     cancellable = g_cancellable_new ();
     seahorse_ssh_op_generate_async (src, email, type, bits, cancellable,
                                     upload ? on_generate_complete_and_upload : on_generate_complete,
-                                    g_object_ref (swidget));
+                                    NULL);
     seahorse_progress_show (cancellable, _("Creating Secure Shell Key"), FALSE);
     g_object_unref (cancellable);
+
+    seahorse_widget_destroy (swidget);
 }
 
 void
diff --git a/ssh/seahorse-ssh-generate.xml b/ssh/seahorse-ssh-generate.xml
index 0e8b8cd..8b2fb9f 100644
--- a/ssh/seahorse-ssh-generate.xml
+++ b/ssh/seahorse-ssh-generate.xml
@@ -42,7 +42,6 @@
                 <property name="receives_default">False</property>
                 <property name="use_action_appearance">False</property>
                 <property name="use_underline">True</property>
-                <signal name="clicked" handler="on_widget_help" swapped="no"/>
               </object>
               <packing>
                 <property name="expand">False</property>
diff --git a/ssh/seahorse-ssh-operation.c b/ssh/seahorse-ssh-operation.c
index a065260..4ff4235 100644
--- a/ssh/seahorse-ssh-operation.c
+++ b/ssh/seahorse-ssh-operation.c
@@ -35,7 +35,6 @@
 
 #include "seahorse-ssh-operation.h"
 #include "seahorse-util.h"
-#include "seahorse-passphrase.h"
 
 #define DEBUG_FLAG SEAHORSE_DEBUG_OPERATION
 #include "seahorse-debug.h"
@@ -44,14 +43,11 @@
 #define COMMAND_PASSWORD_LEN   9
 
 typedef struct {
-	SeahorseObject *key;
-	GtkDialog *dialog;
-	guint requests;
-} SeahorseSshSourcePrompt;
-
-typedef const gchar * (*SeahorseSshSourcePasswordCallback) (SeahorseSshSourcePrompt *prompt,
-                                                            const gchar* message,
-                                                            gpointer user_data);
+	const gchar *title;
+	const gchar *message;
+	const gchar *argument;
+	const gchar *flags;
+} SeahorseSshPromptInfo;
 
 typedef struct {
 	GError *previous_error;
@@ -75,15 +71,6 @@ typedef struct {
 	GPid pid;
 	guint wpid;
 
-	/* Callback for password prompting */
-	SeahorseSshSourcePasswordCallback password_cb;
-	SeahorseSshSourcePrompt *prompt;
-
-	/* seahorse-ssh-askpass communication */
-	GIOChannel *io_askpass;
-	guint stag_askpass;
-	int fds_askpass[2];
-
 	GCancellable *cancellable;
 	gulong cancelled_sig;
 } ssh_operation_closure;
@@ -100,12 +87,6 @@ ssh_operation_free (gpointer data)
 	g_assert (closure->cancelled_sig == 0);
 	g_clear_object (&closure->cancellable);
 
-	g_assert (closure->prompt);
-	if (closure->prompt->dialog)
-		gtk_widget_destroy (GTK_WIDGET (closure->prompt->dialog));
-	g_clear_object (&closure->prompt->key);
-	g_free (closure->prompt);
-
 	if (closure->win)
 		g_source_remove (closure->win);
 	if (closure->wout)
@@ -126,15 +107,8 @@ ssh_operation_free (gpointer data)
 		g_string_free (closure->sout, TRUE);
 	g_string_free (closure->serr, TRUE);
 
-	/* Close the sockets */
-	if (closure->fds_askpass[0] != -1)
-		close (closure->fds_askpass[0]);
-	if (closure->fds_askpass[1] != -1)
-		close (closure->fds_askpass[1]);
-
 	/* watch_ssh_process always needs to have been called */
 	g_assert (closure->pid == 0 && closure->wpid == 0);
-	g_assert (closure->io_askpass == NULL && closure->stag_askpass == 0);
 
 	g_free (closure);
 }
@@ -185,40 +159,6 @@ escape_shell_arg (const gchar *arg)
     return escaped;
 }
 
-static const gchar*
-seahorse_ssh_source_prompt_passphrase (SeahorseSshSourcePrompt *prompt,
-                                       const gchar* title,
-                                       const gchar* message,
-                                       const gchar* check,
-                                       gboolean confirm)
-{
-	const gchar *display;
-	gchar *msg;
-
-	if (prompt->dialog)
-		gtk_widget_destroy (GTK_WIDGET (prompt->dialog));
-
-	if (prompt->key)
-		display = seahorse_object_get_label (prompt->key);
-	else
-		display = g_strdup (_("Secure Shell key"));
-	msg = g_strdup_printf (message, display);
-
-	prompt->dialog = seahorse_passphrase_prompt_show (title, msg, _("Password:"),
-	                                                  check, confirm);
-	g_free (msg);
-
-	/* Run and check if cancelled? */
-	if (gtk_dialog_run (prompt->dialog) != GTK_RESPONSE_ACCEPT) {
-		gtk_widget_destroy (GTK_WIDGET (prompt->dialog));
-		prompt->dialog = NULL;
-		return NULL;
-	}
-
-	gtk_widget_hide (GTK_WIDGET (prompt->dialog));
-	return seahorse_passphrase_prompt_get (prompt->dialog);
-}
-
 static void
 on_ssh_operation_cancelled (GCancellable *cancellable,
                             gpointer user_data)
@@ -238,14 +178,10 @@ on_watch_ssh_process (GPid pid,
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
 	ssh_operation_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	const gchar *message;
 
 	seahorse_debug ("SSHOP: SSH process done");
 
-	/* Close off the askpass io channel etc... */
-	if (closure->stag_askpass)
-		g_source_remove (closure->stag_askpass);
-	closure->stag_askpass = 0;
-
 	/* Already have an error? */
 	if (closure->previous_error) {
 		g_simple_async_result_take_error (res, closure->previous_error);
@@ -265,10 +201,13 @@ on_watch_ssh_process (GPid pid,
 	} else if (WEXITSTATUS (status) != 0) {
 		g_message ("SSH command failed: (%d)", WEXITSTATUS (status));
 		if (closure->serr->len)
-			g_message ("SSH error output: %s", closure->serr->str);
-		g_simple_async_result_set_error (res, SEAHORSE_ERROR, 0, "%s",
-		                                 closure->serr->len ? closure->serr->str : _("The SSH command failed."));
-
+			message = closure->serr->str;
+		else if (closure->sout->len)
+			message = closure->sout->str;
+		else
+			message = _("The SSH command failed.");
+		g_message ("SSH error: %s", message);
+		g_simple_async_result_set_error (res, SEAHORSE_ERROR, 0, "%s", message);
 	}
 
 	g_cancellable_disconnect (closure->cancellable,
@@ -279,9 +218,13 @@ on_watch_ssh_process (GPid pid,
 	closure->pid = 0;
 	closure->wpid = 0;
 
-	if (closure->io_askpass)
-		g_io_channel_unref (closure->io_askpass);
-	closure->io_askpass = NULL;
+	if (closure->win)
+		g_source_remove (closure->win);
+	if (closure->wout)
+		g_source_remove (closure->wout);
+	if (closure->werr)
+		g_source_remove (closure->werr);
+	closure->win = closure->wout = closure->werr = 0;
 
 	g_simple_async_result_complete (res);
 }
@@ -387,98 +330,10 @@ on_io_ssh_write (GIOChannel *source,
 	return ret;
 }
 
-/* Communication with seahorse-ssh-askpass */
-static gboolean
-on_io_askpass_handler (GIOChannel *source,
-                       GIOCondition condition,
-                       gpointer user_data)
-{
-	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	ssh_operation_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	gchar *string = NULL;
-	gsize length;
-	GError *error = NULL;
-	gboolean ret = TRUE;
-	const gchar *line;
-	const gchar *result = NULL;
-
-	if (condition & G_IO_IN) {
-
-		/* Read 1 line from the io channel, including newline character */
-		g_io_channel_read_line (source, &string, &length, NULL, &error);
-
-		if (error != NULL) {
-			g_critical ("couldn't read from seahorse-ssh-askpass: %s",
-			            error->message);
-			g_clear_error (&error);
-			ret = FALSE;
-		}
-
-		/* Process the line */
-		if (string && ret) {
-
-			string[length] = 0;
-			seahorse_debug ("SSHOP: seahorse-ssh-askpass request: \"%s\"", string);
-
-			if (g_ascii_strncasecmp (COMMAND_PASSWORD, string, COMMAND_PASSWORD_LEN) == 0) {
-				line = g_strstrip (string + COMMAND_PASSWORD_LEN);
-
-				/* Prompt for a password */
-				if (closure->password_cb) {
-					result = (closure->password_cb) (closure->prompt, line,
-					                                 g_async_result_get_user_data (G_ASYNC_RESULT (res)));
-
-					/* Cancelled prompt, cancel operation */
-					if (!result) {
-						kill (closure->pid, SIGTERM);
-						seahorse_debug ("SSHOP: password prompt cancelled");
-						ret = FALSE;
-					}
-				}
-
-				closure->prompt->requests++;
-			}
-
-			if (ret) {
-				/* And write the result back out to seahorse-ssh-askpass */
-				seahorse_debug ("SSHOP: seahorse-ssh-askpass response: %s", result ? result : "");
-				if (result)
-					g_io_channel_write_chars (closure->io_askpass, result,
-					                          strlen (result), &length, &error);
-				if (error == NULL)
-					g_io_channel_write_chars (closure->io_askpass, "\n", 1, &length, &error);
-				if (error == NULL)
-					g_io_channel_flush (closure->io_askpass, &error);
-				if (error != NULL) {
-					g_critical ("couldn't read from seahorse-ssh-askpass: %s",
-					            error->message);
-					g_clear_error (&error);
-					ret = FALSE;
-				}
-			}
-		}
-	}
-
-	if (condition & G_IO_HUP)
-		ret = FALSE;
-
-	if (!ret) {
-		if (closure->io_askpass)
-			g_io_channel_unref (closure->io_askpass);
-		closure->io_askpass = NULL;
-		closure->stag_askpass = 0;
-	}
-
-	g_free (string);
-	return ret;
-}
-
-
 static void
 on_spawn_setup_child (gpointer user_data)
 {
-	ssh_operation_closure *closure = user_data;
-	gchar buf[15];
+	SeahorseSshPromptInfo *prompt = user_data;
 
 	/* No terminal for this process */
 	setsid ();
@@ -490,15 +345,14 @@ on_spawn_setup_child (gpointer user_data)
 		g_setenv ("LC_ALL", "C", TRUE);
 	g_setenv ("LANG", "C", TRUE);
 
-	/* Let child know which fd it is */
-	if (closure->fds_askpass[1] != -1) {
-		snprintf (buf, sizeof (buf), "%d", closure->fds_askpass[1]);
-		g_setenv ("SEAHORSE_SSH_ASKPASS_FD", buf, TRUE);
+	if (prompt != NULL) {
+		if (prompt->title)
+			g_setenv ("SEAHORSE_SSH_ASKPASS_TITLE", prompt->title, TRUE);
+		if (prompt->message)
+			g_setenv ("SEAHORSE_SSH_ASKPASS_MESSAGE", prompt->message, TRUE);
+		if (prompt->flags)
+			g_setenv ("SEAHORSE_SSH_ASKPASS_FLAGS", prompt->flags, TRUE);
 	}
-
-	/* Child doesn't need this stuff */
-	if (closure->fds_askpass[0] != -1)
-		close (closure->fds_askpass[0]);
 }
 
 static void
@@ -506,10 +360,9 @@ seahorse_ssh_operation_async (SeahorseSSHSource *source,
                               const gchar *command,
                               const gchar *input,
                               gssize length,
-                              SeahorseSSHKey *key,
                               GCancellable *cancellable,
                               GAsyncReadyCallback callback,
-                              SeahorseSshSourcePasswordCallback password,
+                              SeahorseSshPromptInfo *prompt,
                               gpointer user_data)
 {
 	GSimpleAsyncResult *res;
@@ -533,17 +386,6 @@ seahorse_ssh_operation_async (SeahorseSSHSource *source,
 	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
 	closure->sout = g_string_new (NULL);
 	closure->serr = g_string_new (NULL);
-	closure->password_cb = password;
-	closure->prompt = g_new0 (SeahorseSshSourcePrompt, 1);
-	closure->prompt->key = key ? g_object_ref (key) : NULL;
-
-	/* The seahorse-ssh-askpass pipes */
-	if (socketpair (AF_UNIX, SOCK_STREAM, 0, closure->fds_askpass) == -1) {
-		g_warning ("couldn't create pipes to communicate with seahorse-ssh-askpass: %s",
-		           strerror(errno));
-		closure->fds_askpass[0] = -1;
-		closure->fds_askpass[1] = -1;
-	}
 
 	g_simple_async_result_set_op_res_gpointer (res, closure, ssh_operation_free);
 
@@ -552,7 +394,7 @@ seahorse_ssh_operation_async (SeahorseSSHSource *source,
 	/* And off we go to run the program */
 	r = g_spawn_async_with_pipes (NULL, argv, NULL,
 	                              G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
-	                              on_spawn_setup_child, closure, &closure->pid,
+	                              on_spawn_setup_child, prompt, &closure->pid,
 	                              input ? &fin : NULL, &fout, &ferr, &error);
 	g_strfreev (argv);
 
@@ -599,22 +441,6 @@ seahorse_ssh_operation_async (SeahorseSSHSource *source,
 	                                        on_watch_ssh_process,
 	                                        g_object_ref (res), g_object_unref);
 
-	/* Setup askpass communication */
-	if (closure->fds_askpass[0] != -1) {
-		closure->io_askpass = g_io_channel_unix_new (closure->fds_askpass[0]);
-		g_io_channel_set_close_on_unref (closure->io_askpass, TRUE);
-		g_io_channel_set_encoding (closure->io_askpass, NULL, NULL);
-		closure->stag_askpass = g_io_add_watch_full (closure->io_askpass, G_PRIORITY_DEFAULT,
-		                                             G_IO_IN | G_IO_HUP, on_io_askpass_handler,
-		                                             g_object_ref (res), g_object_unref);
-		closure->fds_askpass[0] = -1; /* closed by io channel */
-	}
-
-	/* The other end of the pipe, close it */
-	if (closure->fds_askpass[1] != -1)
-		close (closure->fds_askpass[1]);
-	closure->fds_askpass[1] = -1;
-
 	if (cancellable)
 		closure->cancelled_sig = g_cancellable_connect (closure->cancellable,
 		                                                G_CALLBACK (on_ssh_operation_cancelled),
@@ -667,18 +493,6 @@ ssh_upload_free (gpointer data)
 	g_free (closure);
 }
 
-static const gchar*
-on_upload_send_password (SeahorseSshSourcePrompt *prompt,
-                         const gchar* message,
-                         gpointer user_data)
-{
-    seahorse_debug ("in upload_password_cb");
-
-    /* Just prompt over and over again */
-    return seahorse_ssh_source_prompt_passphrase (prompt, _("Remote Host Password"),
-                                                  message, NULL, FALSE);
-}
-
 static void
 on_upload_send_complete (GObject *source,
                          GAsyncResult *result,
@@ -701,6 +515,7 @@ on_upload_export_complete (GObject *source,
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
 	ssh_upload_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseSshPromptInfo prompt = { _("Remote Host Password"), NULL, NULL, NULL };
 	GError *error = NULL;
 	gchar *data;
 	size_t length;
@@ -723,12 +538,14 @@ on_upload_export_complete (GObject *source,
 	                       closure->username, closure->hostname,
 	                       closure->port ? "-p" : "", closure->port ? closure->port : "");
 
+	if (g_output_stream_write_all (G_OUTPUT_STREAM (closure->output), "\n", 1, NULL, NULL, NULL) != 1)
+		g_return_if_reached ();
 	data = g_memory_output_stream_get_data (closure->output);
 	length = g_memory_output_stream_get_data_size (closure->output);
 
-	seahorse_ssh_operation_async (SEAHORSE_SSH_SOURCE (source), cmd, data, length, NULL,
+	seahorse_ssh_operation_async (SEAHORSE_SSH_SOURCE (source), cmd, data, length,
 	                              closure->cancellable, on_upload_send_complete,
-	                              on_upload_send_password, g_object_ref (res));
+	                              &prompt, g_object_ref (res));
 
 	g_free (cmd);
 	g_object_unref (res);
@@ -778,7 +595,7 @@ seahorse_ssh_op_upload_finish (SeahorseSSHSource *source,
                                GError **error)
 {
 	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
-	                      seahorse_ssh_op_change_passphrase_async), FALSE);
+	                      seahorse_ssh_op_upload_async), FALSE);
 
 	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
 		return FALSE;
@@ -790,42 +607,6 @@ seahorse_ssh_op_upload_finish (SeahorseSSHSource *source,
  * CHANGE PASSPHRASE 
  */
 
-static const gchar *
-on_change_passphrase_password (SeahorseSshSourcePrompt *prompt,
-                               const gchar* message,
-                               gpointer user_data)
-{
-	const gchar *ret = NULL;
-	gchar *lcase;
-
-	lcase = g_strdup (message ? message : "");
-	seahorse_util_string_lower (lcase);
-
-	seahorse_debug ("in change_password_cb");
-
-	/* Need the old passphrase */
-	if (strstr (lcase, "old pass"))
-		ret = seahorse_ssh_source_prompt_passphrase (prompt, _("Old Key Passphrase"),
-		                                             _("Enter the old passphrase for: %s"), NULL, FALSE);
-
-	/* Look for the new passphrase thingy */
-	else if (strstr (lcase, "new pass"))
-		ret = seahorse_ssh_source_prompt_passphrase (prompt, _("New Key Passphrase"),
-		                                             _("Enter the new passphrase for: %s"), NULL, TRUE);
-
-	/* Confirm the new passphrase, just send it again */
-	else if (strstr (lcase, "again") && prompt->dialog)
-		ret = seahorse_passphrase_prompt_get (prompt->dialog);
-
-	/* Something we don't understand */
-	else
-		ret = seahorse_ssh_source_prompt_passphrase (prompt, _("Enter Key Passphrase"),
-		                                             message, NULL, FALSE);
-
-	g_free (lcase);
-	return ret;
-}
-
 static void
 on_change_passphrase_complete (GObject *source,
                                GAsyncResult *result,
@@ -850,6 +631,7 @@ seahorse_ssh_op_change_passphrase_async  (SeahorseSSHKey *key,
                                           GAsyncReadyCallback callback,
                                           gpointer user_data)
 {
+	SeahorseSshPromptInfo prompt = { _("Enter Key Passphrase"), NULL, NULL, NULL };
 	GSimpleAsyncResult *res;
 	SeahorseSource *source;
 	gchar *cmd;
@@ -860,14 +642,15 @@ seahorse_ssh_op_change_passphrase_async  (SeahorseSSHKey *key,
 	source = seahorse_object_get_source (SEAHORSE_OBJECT (key));
 	g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (source));
 
+	prompt.argument = seahorse_object_get_label (SEAHORSE_OBJECT (key));
+
 	res = g_simple_async_result_new (G_OBJECT (key), callback, user_data,
 	                                 seahorse_ssh_op_change_passphrase_async);
 	g_simple_async_result_set_op_res_gpointer (res, g_object_ref (key), g_object_unref);
 
 	cmd = g_strdup_printf (SSH_KEYGEN_PATH " -p -f '%s'", key->keydata->privfile);
-	seahorse_ssh_operation_async (SEAHORSE_SSH_SOURCE (source), cmd, NULL, 0, key, cancellable,
-	                              on_change_passphrase_complete, on_change_passphrase_password,
-	                              g_object_ref (res));
+	seahorse_ssh_operation_async (SEAHORSE_SSH_SOURCE (source), cmd, NULL, 0, cancellable,
+	                              on_change_passphrase_complete, &prompt, g_object_ref (res));
 
 	g_free (cmd);
 	g_object_unref (res);
@@ -929,24 +712,6 @@ on_generate_complete (GObject *source,
 	g_object_unref (res);
 }
 
-static const gchar *
-on_generate_password (SeahorseSshSourcePrompt *prompt,
-                      const gchar* message,
-                      gpointer user_data)
-{
-	seahorse_debug ("in generate_password_cb");
-
-	/* If the first time then prompt */
-	if (!prompt->dialog)
-		return seahorse_ssh_source_prompt_passphrase (prompt,
-		                                              _("Passphrase for New Secure Shell Key"),
-		                                              _("Enter a passphrase for your new Secure Shell key."),
-		                                              NULL, TRUE);
-
-	/* Otherwise return the entered passphrase */
-	return seahorse_passphrase_prompt_get (prompt->dialog);
-}
-
 void
 seahorse_ssh_op_generate_async (SeahorseSSHSource *source,
                                 const gchar *email,
@@ -956,6 +721,8 @@ seahorse_ssh_op_generate_async (SeahorseSSHSource *source,
                                 GAsyncReadyCallback callback,
                                 gpointer user_data)
 {
+	SeahorseSshPromptInfo prompt = { _("Passphrase for New Secure Shell Key"),
+	                                 NULL, NULL, NULL };
 	ssh_generate_closure *closure;
 	GSimpleAsyncResult *res;
 	const gchar *algo;
@@ -980,9 +747,8 @@ seahorse_ssh_op_generate_async (SeahorseSSHSource *source,
 	                       bits, algo, comment, closure->filename);
 	g_free (comment);
 
-	seahorse_ssh_operation_async (source, cmd, NULL, 0, NULL, cancellable,
-	                              on_generate_complete, on_generate_password,
-	                              g_object_ref (res));
+	seahorse_ssh_operation_async (source, cmd, NULL, 0, cancellable,
+	                              on_generate_complete, &prompt, g_object_ref (res));
 
 	g_free (cmd);
 	g_object_unref (res);
@@ -1070,29 +836,6 @@ ssh_import_free (gpointer data)
 	g_free (closure);
 }
 
-static const gchar *
-on_import_private_password (SeahorseSshSourcePrompt *prompt,
-                            const gchar* message,
-                            gpointer user_data)
-{
-	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	ssh_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	const gchar *ret;
-	gchar* details;
-
-	/* Add the comment to the output */
-	if (closure->comment)
-		details = g_strdup_printf (_("Importing key: %s"), closure->comment);
-	else
-		details = g_strdup (_("Importing key. Enter passphrase"));
-
-	ret = seahorse_ssh_source_prompt_passphrase (prompt, _("Import Key"),
-	                                             details, NULL, FALSE);
-	g_free (details);
-
-	return ret;
-}
-
 static void
 on_import_private_complete (GObject *source,
                             GAsyncResult *result,
@@ -1145,9 +888,11 @@ seahorse_ssh_op_import_private_async (SeahorseSSHSource *source,
                                       gpointer user_data)
 {
 	GSimpleAsyncResult *res;
+	SeahorseSshPromptInfo prompt = { _("Import Key"), NULL, NULL, NULL };
 	gchar *cmd, *privfile = NULL;
 	GError *error = NULL;
 	ssh_import_closure *closure;
+	gchar *message;
 
 	g_return_if_fail (data && data->rawdata);
 	g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (source));
@@ -1158,6 +903,13 @@ seahorse_ssh_op_import_private_async (SeahorseSSHSource *source,
 		g_return_if_fail (privfile);
 	}
 
+	/* Add the comment to the output */
+	if (data->comment)
+		message = g_strdup_printf (_("Importing key: %s"), data->comment);
+	else
+		message = g_strdup (_("Importing key. Enter passphrase"));
+	prompt.message = message;
+
 	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
 	                                 seahorse_ssh_op_import_private_async);
 	closure = g_new0 (ssh_import_closure, 1);
@@ -1176,10 +928,11 @@ seahorse_ssh_op_import_private_async (SeahorseSSHSource *source,
 
 	/* Start command to generate public key */
 	cmd = g_strdup_printf (SSH_KEYGEN_PATH " -y -f '%s'", privfile);
-	seahorse_ssh_operation_async (source, cmd, NULL, 0, NULL, cancellable,
-	                              on_import_private_complete,
-	                              on_import_private_password,
+	seahorse_ssh_operation_async (source, cmd, NULL, 0, cancellable,
+	                              on_import_private_complete, &prompt,
 	                              g_object_ref (res));
+
+	g_free (message);
 	g_free (cmd);
 
 	g_object_unref (res);
diff --git a/ssh/seahorse-ssh-source.c b/ssh/seahorse-ssh-source.c
index 0f44520..8cf2b0f 100644
--- a/ssh/seahorse-ssh-source.c
+++ b/ssh/seahorse-ssh-source.c
@@ -322,6 +322,7 @@ typedef struct {
 	GHashTable *checks;
 	gchar *pubfile;
 	gchar *privfile;
+	SeahorseSSHKey *last_key;
 } source_load_closure;
 
 static void
@@ -329,8 +330,10 @@ source_load_free (gpointer data)
 {
 	source_load_closure *closure = data;
 	g_object_unref (closure->source);
-	g_hash_table_destroy (closure->loaded);
-	g_hash_table_destroy (closure->checks);
+	if (closure->loaded)
+		g_hash_table_destroy (closure->loaded);
+	if (closure->checks)
+		g_hash_table_destroy (closure->checks);
 	g_free (closure->pubfile);
 	g_free (closure->privfile);
 	g_free (closure);
@@ -455,11 +458,57 @@ on_load_found_public_key (SeahorseSSHKeyData *data,
 	data->partial = FALSE;
 
 	/* Check and register thet key with the context, frees keydata */
-	ssh_key_from_data (closure->source, closure, data);
+	closure->last_key = ssh_key_from_data (closure->source, closure, data);
 	return TRUE;
 }
 
 static void
+load_key_for_private_file (SeahorseSSHSource *self,
+                           source_load_closure *closure,
+                           const gchar *privfile)
+{
+	GError *error = NULL;
+
+	closure->privfile = g_strdup (privfile);
+	closure->pubfile = g_strconcat (closure->privfile, ".pub", NULL);
+
+	/* possibly an SSH key? */
+	if (g_file_test (closure->privfile, G_FILE_TEST_EXISTS) &&
+	    g_file_test (closure->pubfile, G_FILE_TEST_EXISTS) &&
+	    check_file_for_ssh_private (self, closure->privfile)) {
+		seahorse_ssh_key_data_parse_file (closure->pubfile, on_load_found_public_key,
+		                                  NULL, closure, &error);
+		if (error != NULL) {
+			g_warning ("couldn't read SSH file: %s (%s)",
+			           closure->pubfile, error->message);
+			g_clear_error (&error);
+		}
+	}
+
+	g_free (closure->privfile);
+	g_free (closure->pubfile);
+	closure->privfile = closure->pubfile = NULL;
+}
+
+static SeahorseSSHKey *
+seahorse_ssh_source_load_one_sync (SeahorseSSHSource *self,
+                                   const gchar *privfile)
+{
+	source_load_closure *closure;
+	SeahorseSSHKey *key;
+
+	closure = g_new0 (source_load_closure, 1);
+	closure->source = g_object_ref (self);
+
+	load_key_for_private_file (self, closure, privfile);
+
+	key = closure->last_key;
+	source_load_free (closure);
+
+	return key;
+}
+
+static void
 seahorse_ssh_source_load_async (SeahorseSource *source,
                                 GCancellable *cancellable,
                                 GAsyncReadyCallback callback,
@@ -470,6 +519,7 @@ seahorse_ssh_source_load_async (SeahorseSource *source,
 	source_load_closure *closure;
 	GError *error = NULL;
 	const gchar *filename;
+	gchar *privfile;
 	GDir *dir;
 
 	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
@@ -505,26 +555,9 @@ seahorse_ssh_source_load_async (SeahorseSource *source,
 		if (filename == NULL)
 			break;
 
-		closure->privfile = g_build_filename (self->priv->ssh_homedir, filename, NULL);
-		closure->pubfile = g_strconcat (closure->privfile, ".pub", NULL);
-
-		/* possibly an SSH key? */
-		if (g_file_test (closure->privfile, G_FILE_TEST_EXISTS) &&
-		    g_file_test (closure->pubfile, G_FILE_TEST_EXISTS) &&
-		    check_file_for_ssh_private (self, closure->privfile)) {
-
-			seahorse_ssh_key_data_parse_file (closure->pubfile, on_load_found_public_key,
-			                                  NULL, closure, &error);
-			if (error != NULL) {
-				g_warning ("couldn't read SSH file: %s (%s)",
-				           closure->pubfile, error->message);
-				g_clear_error (&error);
-			}
-		}
-
-		g_free (closure->privfile);
-		g_free (closure->pubfile);
-		closure->privfile = closure->pubfile = NULL;
+		privfile = g_build_filename (self->priv->ssh_homedir, filename, NULL);
+		load_key_for_private_file (self, closure, privfile);
+		g_free (privfile);
 	}
 
 	g_dir_close (dir);
@@ -845,11 +878,14 @@ seahorse_ssh_source_key_for_filename (SeahorseSSHSource *ssrc,
 		g_return_val_if_fail (data, NULL);
 
 		/* If it's already loaded then just leave it at that */
-		if (data->privfile && strcmp (privfile, data->privfile) == 0)
+		if (data->privfile && strcmp (privfile, data->privfile) == 0) {
+			g_list_free (keys);
 			return SEAHORSE_SSH_KEY (l->data);
+		}
 	}
+	g_list_free (keys);
 
-	return NULL;
+	return seahorse_ssh_source_load_one_sync (ssrc, privfile);
 }
 
 gchar*
diff --git a/ssh/seahorse-ssh-upload.c b/ssh/seahorse-ssh-upload.c
index 8bc59fc..6a41a79 100644
--- a/ssh/seahorse-ssh-upload.c
+++ b/ssh/seahorse-ssh-upload.c
@@ -44,13 +44,10 @@ on_upload_complete (GObject *source,
                     GAsyncResult *result,
                     gpointer user_data)
 {
-	SeahorseWidget *swidget = SEAHORSE_WIDGET (user_data);
 	GError *error = NULL;
 
 	if (!seahorse_ssh_op_upload_finish (SEAHORSE_SSH_SOURCE (source), result, &error))
-		seahorse_util_handle_error (&error, swidget, _("Couldn't configure Secure Shell keys on remote computer."));
-
-	g_object_unref (swidget);
+		seahorse_util_handle_error (&error, NULL, _("Couldn't configure Secure Shell keys on remote computer."));
 }
 
 G_MODULE_EXPORT void



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