[seahorse] Refactor asynchronous operation code in seahorse.



commit c7e0a9535dd0416f7bcfd753667095020771964f
Author: Stef Walter <stefw collabora co uk>
Date:   Thu Aug 18 21:54:10 2011 +0200

    Refactor asynchronous operation code in seahorse.
    
     * This is a very large commit.
     * We use GIO style async now instead of SeahorseOperation.
     * Makes things easier to hack on because it's more consistent with
       other GNOME software.
     * More predictable cancellation and error code paths.
     * Some other cleanup here too. When rewriting entire functions to
       refactor the async code, I cleaned up some other things too.

 configure.ac                              |    2 +-
 gkr/seahorse-gkr-add-item.c               |   15 +-
 gkr/seahorse-gkr-add-keyring.c            |   15 +-
 gkr/seahorse-gkr-item-commands.c          |   48 +-
 gkr/seahorse-gkr-item-properties.c        |  409 ++-----
 gkr/seahorse-gkr-item-properties.xml      |  153 ---
 gkr/seahorse-gkr-item.c                   |  106 +--
 gkr/seahorse-gkr-item.h                   |    5 -
 gkr/seahorse-gkr-keyring-commands.c       |   72 +-
 gkr/seahorse-gkr-keyring.c                |  445 +++----
 gkr/seahorse-gkr-operation.c              |  618 ++++++---
 gkr/seahorse-gkr-operation.h              |   64 +-
 gkr/seahorse-gkr-source.c                 |  495 +++----
 libseahorse/Makefile.am                   |    3 +-
 libseahorse/seahorse-commands.c           |   22 +-
 libseahorse/seahorse-commands.h           |   12 +-
 libseahorse/seahorse-context.c            |  740 ++++++-----
 libseahorse/seahorse-context.h            |  193 ++--
 libseahorse/seahorse-object.c             |   22 -
 libseahorse/seahorse-object.h             |    4 -
 libseahorse/seahorse-operation.c          |  937 -------------
 libseahorse/seahorse-operation.h          |  336 -----
 libseahorse/seahorse-passphrase.c         |   21 -
 libseahorse/seahorse-progress.c           |  913 ++++++++-----
 libseahorse/seahorse-progress.h           |   47 +-
 libseahorse/seahorse-progress.xml         |   89 +-
 libseahorse/seahorse-source.c             |  549 ++++----
 libseahorse/seahorse-source.h             |  218 ++--
 libseahorse/seahorse-transfer-operation.c |  382 ------
 libseahorse/seahorse-transfer-operation.h |   61 -
 libseahorse/seahorse-transfer.c           |  204 +++
 libseahorse/seahorse-transfer.h           |   37 +
 libseahorse/seahorse-unknown-source.c     |  111 +-
 libseahorse/seahorse-unknown-source.h     |    4 +-
 libseahorse/seahorse-unknown.c            |   14 +-
 libseahorse/seahorse-util.c               |   59 +-
 libseahorse/seahorse-util.h               |    6 +-
 pgp/Makefile.am                           |    1 -
 pgp/seahorse-gpg-options.c                |    4 +-
 pgp/seahorse-gpgme-generate.c             |   75 +-
 pgp/seahorse-gpgme-key-op.c               |  240 +++--
 pgp/seahorse-gpgme-key-op.h               |   12 +-
 pgp/seahorse-gpgme-key.c                  |   33 +-
 pgp/seahorse-gpgme-operation.c            |  438 ------
 pgp/seahorse-gpgme-operation.h            |   94 --
 pgp/seahorse-gpgme-photos.c               |    6 +-
 pgp/seahorse-gpgme-source.c               | 1488 +++++++++++----------
 pgp/seahorse-gpgme.c                      |  309 ++++-
 pgp/seahorse-gpgme.h                      |    6 +-
 pgp/seahorse-hkp-source.c                 | 1056 +++++++--------
 pgp/seahorse-ldap-source.c                | 1956 ++++++++++++++-------------
 pgp/seahorse-pgp-commands.c               |   48 +-
 pgp/seahorse-pgp-commands.h               |    2 -
 pgp/seahorse-pgp-generate.xml             |    2 +-
 pgp/seahorse-pgp-key-properties.c         |   36 +-
 pgp/seahorse-server-source.c              |  121 +--
 pgp/seahorse-server-source.h              |    8 +-
 pgp/seahorse-signer.c                     |    1 -
 pkcs11/seahorse-pkcs11-certificate.c      |    2 +-
 pkcs11/seahorse-pkcs11-commands.c         |   45 +-
 pkcs11/seahorse-pkcs11-object.c           |   11 +-
 pkcs11/seahorse-pkcs11-operations.c       |  492 +++-----
 pkcs11/seahorse-pkcs11-operations.h       |   19 +-
 pkcs11/seahorse-pkcs11-source.c           |   23 +-
 src/seahorse-key-manager-store.c          |   78 +-
 src/seahorse-key-manager.c                |   79 +-
 src/seahorse-keyserver-results.c          |   57 +-
 src/seahorse-keyserver-results.h          |    8 +-
 src/seahorse-keyserver-results.xml        |    2 +-
 src/seahorse-keyserver-search.c           |   15 +-
 src/seahorse-keyserver-sync.c             |  181 ++--
 src/seahorse-viewer.c                     |  158 +--
 ssh/seahorse-ssh-commands.c               |   29 +-
 ssh/seahorse-ssh-commands.h               |    2 -
 ssh/seahorse-ssh-generate.c               |  105 +-
 ssh/seahorse-ssh-generate.xml             |    2 +-
 ssh/seahorse-ssh-key-properties.c         |  215 ++--
 ssh/seahorse-ssh-key.c                    |   48 +-
 ssh/seahorse-ssh-key.h                    |   12 +-
 ssh/seahorse-ssh-operation.c              | 2117 ++++++++++++++++-------------
 ssh/seahorse-ssh-operation.h              |  126 +-
 ssh/seahorse-ssh-source.c                 |  935 +++++++------
 ssh/seahorse-ssh-source.h                 |    4 +-
 ssh/seahorse-ssh-upload.c                 |   92 +-
 84 files changed, 8339 insertions(+), 9885 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index ccefcda..e9387b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ dnl MAIN SEAHORSE VERSION (update after release)
 
 AC_INIT(seahorse, 3.1.5)
 
-GCR_REQUIRED=3.1.5
+GCR_REQUIRED=3.1.4
 
 dnl ****************************************************************************
 
diff --git a/gkr/seahorse-gkr-add-item.c b/gkr/seahorse-gkr-add-item.c
index 4c9ba79..9fa8bc8 100644
--- a/gkr/seahorse-gkr-add-item.c
+++ b/gkr/seahorse-gkr-add-item.c
@@ -35,25 +35,16 @@ static void
 item_add_done (GnomeKeyringResult result, guint32 item, gpointer data)
 {
 	SeahorseWidget *swidget = SEAHORSE_WIDGET (data);
-	SeahorseOperation *op;
 
 	g_return_if_fail (swidget);
 
 	/* Clear the operation without cancelling it since it is complete */
 	seahorse_gkr_dialog_complete_request (swidget, FALSE);
-    
+
 	/* Successful. Update the listings and stuff. */
 	if (result == GNOME_KEYRING_RESULT_OK) {
-		
-		op = seahorse_source_load (SEAHORSE_SOURCE (seahorse_gkr_source_default ()));
-		
-		/* 
-		 * HACK: Major hack alert. This whole area needs some serious refactoring,
-		 * so for now we're just going to let any viewers listen in on this
-		 * operation like so:
-		 */
-		g_signal_emit_by_name (seahorse_context_instance (), "refreshing", op);
-		g_object_unref (op);
+		seahorse_source_load_async (SEAHORSE_SOURCE (seahorse_gkr_source_default ()),
+		                            NULL, NULL, NULL);
 
 	/* Setting the default keyring failed */
 	} else if (result != GNOME_KEYRING_RESULT_CANCELLED) {     
diff --git a/gkr/seahorse-gkr-add-keyring.c b/gkr/seahorse-gkr-add-keyring.c
index 5cc3f8c..6d56428 100644
--- a/gkr/seahorse-gkr-add-keyring.c
+++ b/gkr/seahorse-gkr-add-keyring.c
@@ -47,25 +47,16 @@ static void
 keyring_add_done (GnomeKeyringResult result, gpointer data)
 {
 	SeahorseWidget *swidget = SEAHORSE_WIDGET (data);
-	SeahorseOperation *op;
 
 	g_return_if_fail (swidget);
 
 	/* Clear the operation without cancelling it since it is complete */
 	seahorse_gkr_dialog_complete_request (swidget, FALSE);
-    
+
 	/* Successful. Update the listings and stuff. */
 	if (result == GNOME_KEYRING_RESULT_OK) {
-		
-		op = seahorse_source_load (SEAHORSE_SOURCE (seahorse_gkr_source_default ()));
-		
-		/* 
-		 * HACK: Major hack alert. This whole area needs some serious refactoring,
-		 * so for now we're just going to let any viewers listen in on this
-		 * operation like so:
-		 */
-		g_signal_emit_by_name (seahorse_context_instance (), "refreshing", op);
-		g_object_unref (op);
+		seahorse_source_load_async (SEAHORSE_SOURCE (seahorse_gkr_source_default ()),
+		                            NULL, NULL, NULL);
 
 	/* Setting the default keyring failed */
 	} else if (result != GNOME_KEYRING_RESULT_CANCELLED) {     
diff --git a/gkr/seahorse-gkr-item-commands.c b/gkr/seahorse-gkr-item-commands.c
index 370b661..cfe5ce3 100644
--- a/gkr/seahorse-gkr-item-commands.c
+++ b/gkr/seahorse-gkr-item-commands.c
@@ -26,9 +26,11 @@
 #include "seahorse-gkr.h"
 #include "seahorse-gkr-item.h"
 #include "seahorse-gkr-dialogs.h"
+#include "seahorse-gkr-operation.h"
 
 #include "common/seahorse-registry.h"
 
+#include "seahorse-progress.h"
 #include "seahorse-source.h"
 #include "seahorse-util.h"
 
@@ -62,17 +64,37 @@ seahorse_gkr_item_commands_show_properties (SeahorseCommands* base, SeahorseObje
 		g_return_if_reached ();
 }
 
-static SeahorseOperation* 
-seahorse_gkr_item_commands_delete_objects (SeahorseCommands* base, GList* objects) 
+static void
+on_delete_objects (GObject *source,
+                   GAsyncResult *result,
+                   gpointer user_data)
 {
-	gchar *prompt;
+	SeahorseCommands *commands = SEAHORSE_COMMANDS (user_data);
+	GError *error = NULL;
+	GtkWidget *parent;
+
+	if (!seahorse_gkr_delete_finish (result, &error)) {
+		parent = GTK_WIDGET (seahorse_view_get_window (seahorse_commands_get_view (commands)));
+		seahorse_util_show_error (parent, _("Couldn't delete item"), error->message);
+		g_error_free (error);
+	}
+
+	g_object_unref (commands);
+}
+
+static gboolean
+seahorse_gkr_item_commands_delete_objects (SeahorseCommands* commands,
+                                           GList* objects)
+{
+	GCancellable *cancellable;
 	GtkWidget *parent;
+	gchar *prompt;
 	gboolean ret;
 	guint num;
 
 	num = g_list_length (objects);
 	if (num == 0)
-		return NULL;
+		return TRUE;
 
 	if (num == 1) {
 		prompt = g_strdup_printf (_ ("Are you sure you want to delete the password '%s'?"), 
@@ -83,14 +105,18 @@ seahorse_gkr_item_commands_delete_objects (SeahorseCommands* base, GList* object
 		                                    num), num);
 	}
 	
-	parent = GTK_WIDGET (seahorse_view_get_window (seahorse_commands_get_view (base)));
+	parent = GTK_WIDGET (seahorse_view_get_window (seahorse_commands_get_view (commands)));
 	ret = seahorse_util_prompt_delete (prompt, parent);
-	g_free (prompt);
-	
-	if (!ret)
-		return NULL;
 
-	return seahorse_source_delete_objects (objects);
+	if (ret) {
+		cancellable = g_cancellable_new ();
+		seahorse_gkr_delete_async (objects, cancellable, on_delete_objects, g_object_ref (commands));
+		seahorse_progress_show (cancellable, ngettext (_("Deleting item"), _("Deleting items"), num), TRUE);
+		g_object_unref (cancellable);
+	}
+
+	g_free (prompt);
+	return ret;
 }
 
 static GObject* 
@@ -128,7 +154,7 @@ seahorse_gkr_item_commands_class_init (SeahorseGkrItemCommandsClass *klass)
 
 	cmd_class->show_properties = seahorse_gkr_item_commands_show_properties;
 	cmd_class->delete_objects = seahorse_gkr_item_commands_delete_objects;
-	
+
 	/* Setup the predicate that matches our commands */
 	commands_predicate.type = SEAHORSE_TYPE_GKR_ITEM;
 
diff --git a/gkr/seahorse-gkr-item-properties.c b/gkr/seahorse-gkr-item-properties.c
index 72f6b9d..06193e5 100644
--- a/gkr/seahorse-gkr-item-properties.c
+++ b/gkr/seahorse-gkr-item-properties.c
@@ -29,6 +29,7 @@
 #include "seahorse-gtkstock.h"
 #include "seahorse-object.h"
 #include "seahorse-object-widget.h"
+#include "seahorse-progress.h"
 #include "seahorse-secure-memory.h"
 #include "seahorse-util.h"
 #include "seahorse-widget.h"
@@ -190,14 +191,40 @@ transfer_password (SeahorseGkrItem *git, SeahorseWidget *swidget)
 }
 
 static void
-password_activate (GtkEntry *entry, SeahorseWidget *swidget)
+on_update_password_ready (GObject *source,
+                          GAsyncResult *result,
+                          gpointer user_data)
+{
+	SeahorseWidget *swidget = SEAHORSE_WIDGET (user_data);
+	SeahorseGkrItem *git = SEAHORSE_GKR_ITEM (source);
+	GError *error = NULL;
+	GtkWidget *expander;
+
+	if (seahorse_gkr_update_secret_finish (git, result, &error)) {
+		transfer_password (git, swidget);
+
+	} else {
+		seahorse_util_show_error (seahorse_widget_get_toplevel (swidget),
+		                          _("Couldn't change password."), error->message);
+		g_clear_error (&error);
+	}
+
+	expander = seahorse_widget_get_widget (swidget, "password-expander");
+	gtk_widget_set_sensitive (expander, TRUE);
+	g_object_set_data (G_OBJECT (swidget), "updating-password", NULL);
+
+	g_object_unref (swidget);
+}
+
+static void
+password_activate (GtkEntry *entry,
+                   SeahorseWidget *swidget)
 {
 	SeahorseObject *object;
 	SeahorseGkrItem *git;
-	SeahorseOperation *op;
-	GnomeKeyringItemInfo *info;
 	GtkWidget *expander;
-    
+	GCancellable *cancellable;
+
 	object = SEAHORSE_OBJECT_WIDGET (swidget)->object;
 	if (!object)
 		return;
@@ -206,6 +233,7 @@ password_activate (GtkEntry *entry, SeahorseWidget *swidget)
 
 	expander = seahorse_widget_get_widget (swidget, "password-expander");
 	g_return_if_fail (expander);
+
 	if (!gtk_expander_get_expanded (GTK_EXPANDER (expander)))
 		return;
 
@@ -217,37 +245,13 @@ password_activate (GtkEntry *entry, SeahorseWidget *swidget)
 		return;
 	g_object_set_data (G_OBJECT (swidget), "updating-password", "updating");
 
-	g_object_ref (git);
-	g_object_ref (entry);
 	gtk_widget_set_sensitive (expander, FALSE);
-    	
-	/* Make sure we've loaded the information */
-	seahorse_util_wait_until (seahorse_gkr_item_get_info (git));
-    
-	info = gnome_keyring_item_info_copy (seahorse_gkr_item_get_info (git));
-	gnome_keyring_item_info_set_secret (info, gtk_entry_get_text (entry));
-
-	op = seahorse_gkr_operation_update_info (git, info);
-	gnome_keyring_item_info_free (info);
-    
-	/* This is usually a quick operation */
-	seahorse_operation_wait (op);
-	
-	/* Set the password back if failed */
-	if (!seahorse_operation_is_successful (op))
-		transfer_password (git, swidget);
-
-	gtk_widget_set_sensitive (expander, TRUE);
-	g_object_unref (entry);
-	g_object_unref (git);
-    
-	if (!seahorse_operation_is_successful (op))
-		seahorse_operation_display_error (op, _("Couldn't change password."),
-		                                  seahorse_widget_get_toplevel (swidget));
-	
-	g_object_unref (op);
-	g_object_set_data (G_OBJECT (swidget), "updating-description", NULL);
 
+	cancellable = g_cancellable_new ();
+	seahorse_gkr_update_secret_async (git, gtk_entry_get_text (entry), cancellable,
+	                                  on_update_password_ready, g_object_ref (swidget));
+	seahorse_progress_show (cancellable, _("Updating password"), TRUE);
+	g_object_unref (cancellable);
 }
 
 static void
@@ -294,16 +298,54 @@ on_item_password_expander_activate (GtkExpander *expander, SeahorseWidget *swidg
     transfer_password (git, swidget);
 }
 
+typedef struct {
+	SeahorseWidget *swidget;
+	GtkEntry *entry;
+} item_description_closure;
+
+static void
+item_description_free (gpointer data)
+{
+	item_description_closure *closure = data;
+	g_object_unref (closure->swidget);
+	g_free (closure);
+}
+
+static void
+on_item_description_complete (GObject *source,
+                              GAsyncResult *result,
+                              gpointer user_data)
+{
+	item_description_closure *closure = user_data;
+	SeahorseGkrItem *git = SEAHORSE_GKR_ITEM (source);
+	GError *error = NULL;
+
+	if (!seahorse_gkr_update_description_finish (git, result, &error)) {
+
+		/* Set back to original */
+		gtk_entry_set_text (closure->entry,
+		                    seahorse_object_get_label (SEAHORSE_OBJECT (git)));
+
+		seahorse_util_show_error (seahorse_widget_get_toplevel (closure->swidget),
+		                          _("Couldn't set description."), error->message);
+		g_clear_error (&error);
+	}
+
+	gtk_widget_set_sensitive (GTK_WIDGET (closure->entry), TRUE);
+	g_object_set_data (G_OBJECT (closure->swidget), "updating-description", NULL);
+
+	item_description_free (closure);
+}
+
 G_MODULE_EXPORT void
-on_item_description_activate (GtkWidget *entry, SeahorseWidget *swidget)
+on_item_description_activate (GtkWidget *entry,
+                              SeahorseWidget *swidget)
 {
+	item_description_closure *closure;
+	GCancellable *cancellable;
 	SeahorseObject *object;
 	SeahorseGkrItem *git;
-	SeahorseOperation *op = NULL;
-	GnomeKeyringItemInfo *info;
-	const gchar *text;
-	const gchar *original;
-    
+
 	object = SEAHORSE_OBJECT_WIDGET (swidget)->object;
 	if (!object)
 		return;
@@ -313,46 +355,19 @@ on_item_description_activate (GtkWidget *entry, SeahorseWidget *swidget)
 	g_object_set_data (G_OBJECT (swidget), "updating-description", "updating");
 
 	git = SEAHORSE_GKR_ITEM (object);
-	
-	g_object_ref (git);
-	g_object_ref (entry);
-	gtk_widget_set_sensitive (entry, FALSE);
 
-	/* Make sure we've loaded the information */
-	seahorse_util_wait_until (seahorse_gkr_item_get_info (git));
-	info = seahorse_gkr_item_get_info (git);
-    
-	/* Make sure not the same */
-	text = gtk_entry_get_text (GTK_ENTRY (entry));
-	original = seahorse_object_get_label (object);
-	if (text != original && g_utf8_collate (text, original ? original : "") != 0) {
-		
-		info = gnome_keyring_item_info_copy (info);
-		gnome_keyring_item_info_set_display_name (info, text);
-		
-		op = seahorse_gkr_operation_update_info (git, info);
-		gnome_keyring_item_info_free (info);
-
-		/* This is usually a quick operation */
-		seahorse_operation_wait (op);
-
-		if (!seahorse_operation_is_successful (op)) 
-			gtk_entry_set_text (GTK_ENTRY (entry), original);
+	gtk_widget_set_sensitive (entry, FALSE);
 
-	}
+	closure = g_new0 (item_description_closure, 1);
+	closure->swidget = g_object_ref (swidget);
+	closure->entry = GTK_ENTRY (entry);
 
-	gtk_widget_set_sensitive (entry, TRUE);
-	g_object_unref (entry);
-	g_object_unref (git);
-    
-	if (op) {
-		if (!seahorse_operation_is_successful (op)) 
-			seahorse_operation_display_error (op, _("Couldn't set description."),
-			                                  seahorse_widget_get_toplevel (swidget));
-		g_object_unref (op);
-	}
-	
-	g_object_set_data (G_OBJECT (swidget), "updating-description", NULL);
+	cancellable = g_cancellable_new ();
+	seahorse_gkr_update_description_async (git, gtk_entry_get_text (GTK_ENTRY (entry)),
+	                                       cancellable, on_item_description_complete,
+	                                       closure);
+	seahorse_progress_show (cancellable, _("Updating password"), TRUE);
+	g_object_unref (cancellable);
 }
 
 G_MODULE_EXPORT gboolean
@@ -495,241 +510,6 @@ setup_details (SeahorseWidget *swidget)
 }
 
 /* -----------------------------------------------------------------------------
- * APPLICATIONS TAB 
- */
-
-enum {
-	APPS_ACCESS,
-	APPS_NAME,
-	APPS_N_COLUMNS
-};
-
-static void
-update_application_details (SeahorseWidget *swidget)
-{
-	GnomeKeyringAccessControl *ac;
-	GtkLabel *label;
-	GtkToggleButton *toggle;
-	GnomeKeyringAccessType access;
-	GtkTreeView *tree;
-	GtkTreePath *path;
-	GtkTreeModel *model;
-	GtkTreeSelection *selection;
-	GtkTreeIter iter;
-	gchar *filename;
-    
-	tree = GTK_TREE_VIEW (seahorse_widget_get_widget (swidget, "application-list"));
-	g_return_if_fail (GTK_IS_TREE_VIEW (tree));
-	    
-	selection = gtk_tree_view_get_selection (tree);
-	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
-		return;
-	        
-	path = gtk_tree_model_get_path (model, &iter);
-	g_return_if_fail (path);
-	
-	/* Dig out the current value */
-	gtk_tree_model_get (model, &iter, APPS_ACCESS, &ac, -1);
-	
-	seahorse_widget_set_sensitive (swidget, "application-details", ac != NULL);
-    
-	label = GTK_LABEL (seahorse_widget_get_widget (swidget, "application-path"));
-	g_return_if_fail (GTK_IS_LABEL (label));
-	filename = ac ? gnome_keyring_item_ac_get_path_name (ac) : NULL;
-	gtk_label_set_text (label, filename ? filename : "");
-	g_free (filename);
-
-	g_object_set_data (G_OBJECT (swidget), "updating", "updating");
-	access = ac ? gnome_keyring_item_ac_get_access_type (ac) : 0;
-    
-	toggle = GTK_TOGGLE_BUTTON (seahorse_widget_get_widget (swidget, "application-read"));
-	g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle));
-	gtk_toggle_button_set_active (toggle, access & GNOME_KEYRING_ACCESS_READ);    
-
-	toggle = GTK_TOGGLE_BUTTON (seahorse_widget_get_widget (swidget, "application-write"));
-	g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle));    
-	gtk_toggle_button_set_active (toggle, access & GNOME_KEYRING_ACCESS_WRITE);    
-
-	toggle = GTK_TOGGLE_BUTTON (seahorse_widget_get_widget (swidget, "application-delete"));
-	g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle));
-	gtk_toggle_button_set_active (toggle, access & GNOME_KEYRING_ACCESS_REMOVE);
-    
-	g_object_set_data (G_OBJECT (swidget), "updating", NULL);
-	gnome_keyring_access_control_free (ac);
-}
-
-static void
-application_selection_changed (GtkTreeSelection *selection, SeahorseWidget *swidget)
-{
-	update_application_details (swidget);
-}
-
-static void 
-merge_toggle_button_access (SeahorseWidget *swidget, const gchar *identifier, 
-                            GnomeKeyringAccessType *access, GnomeKeyringAccessType type)
-{
-	GtkToggleButton *toggle;
-    
-	toggle = GTK_TOGGLE_BUTTON (seahorse_widget_get_widget (swidget, identifier));
-	g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle));
-	if (gtk_toggle_button_get_active (toggle))
-		*access |= type;
-	else
-		*access &= ~type;
-}
-
-G_MODULE_EXPORT void
-on_item_application_access_toggled (GtkCheckButton *check, SeahorseWidget *swidget)
-{
-	SeahorseObject *object;
-	SeahorseGkrItem *git;
-	SeahorseOperation *op;
-	GnomeKeyringAccessType access;
-	GnomeKeyringAccessControl *ac;
-	GtkTreeView *tree;
-	GtkTreePath *path;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
-	GtkTreeSelection *selection;
-	GError *err = NULL;
-	GList *acl;
-    
-	/* Just us setting up the controls, not the user */
-	if (g_object_get_data (G_OBJECT (swidget), "updating"))
-		return;
-    
-	object = SEAHORSE_OBJECT_WIDGET (swidget)->object;
-	git = SEAHORSE_GKR_ITEM (object);
-
-	tree = GTK_TREE_VIEW (seahorse_widget_get_widget (swidget, "application-list"));
-	g_return_if_fail (GTK_IS_TREE_VIEW (tree));
-	    
-	selection = gtk_tree_view_get_selection (tree);
-	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
-		g_return_if_reached ();
-	        
-	path = gtk_tree_model_get_path (model, &iter);
-	g_return_if_fail (path);
-	
-	/* Update the access control on that one */
-	gtk_tree_model_get (model, &iter, APPS_ACCESS, &ac, -1);
-	access = gnome_keyring_item_ac_get_access_type (ac);
-	merge_toggle_button_access (swidget, "application-read", &access, GNOME_KEYRING_ACCESS_READ);    
-	merge_toggle_button_access (swidget, "application-write", &access, GNOME_KEYRING_ACCESS_WRITE);    
-	merge_toggle_button_access (swidget, "application-delete", &access, GNOME_KEYRING_ACCESS_REMOVE);
-	
-	/* If it's changed */
-	if (access != gnome_keyring_item_ac_get_access_type (ac)) {
-		
-		/* Update the store with this new stuff */
-	        gnome_keyring_item_ac_set_access_type (ac, access);
-	        gtk_list_store_set (GTK_LIST_STORE (model), &iter, APPS_ACCESS, ac, -1);
-	        gnome_keyring_access_control_free (ac);
-		
-	        /* Build up a full ACL from what we have */
-	        acl = NULL;
-	        if (!gtk_tree_model_get_iter_first (model, &iter))
-	        	g_return_if_reached ();
-        	do {
-        		gtk_tree_model_get (model, &iter, APPS_ACCESS, &ac, -1);
-        		acl = g_list_append (acl, ac);
-        	} while (gtk_tree_model_iter_next (model, &iter));
-
-        	seahorse_widget_set_sensitive (swidget, "application-details", FALSE);
-        	g_object_ref (git);
-        
-        	op = seahorse_gkr_operation_update_acl (git, acl);
-        	g_return_if_fail (op);
-        
-        	seahorse_operation_wait (op);
-        	
-        	gnome_keyring_acl_free (acl);
-        	
-        	if (!seahorse_operation_is_successful (op))
-        		update_application_details (swidget);
-
-                seahorse_widget_set_sensitive (swidget, "application-details", TRUE);
-                g_object_unref (git);
-
-        	if (!seahorse_operation_is_successful (op)) {
-        		seahorse_operation_copy_error (op, &err);
-        		seahorse_util_handle_error (err, _("Couldn't set application access."));
-        		g_clear_error (&err);
-        	}
-        	
-        	g_object_unref (op);
-	}
-}
-
-static void 
-update_application (SeahorseGkrItem *git, SeahorseWidget *swidget)
-{
-	GtkTreeView *tree;
-	GtkListStore *store;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
-	GtkCellRenderer *renderer;
-	GnomeKeyringAccessControl *ac;
-	GtkTreeViewColumn *column;
-	GList *acl;
-	gboolean valid;
-	gchar *display;
-
-	tree = GTK_TREE_VIEW (seahorse_widget_get_widget (swidget, "application-list"));
-	g_return_if_fail (tree);
-    
-	model = gtk_tree_view_get_model (tree);
-	if (!model) {
-		g_assert (2 == APPS_N_COLUMNS);
-		store = gtk_list_store_new (2, boxed_access_control_type (), G_TYPE_STRING);
-		model = GTK_TREE_MODEL (store);
-		gtk_tree_view_set_model (tree, model);
-
-		renderer = gtk_cell_renderer_text_new ();
-		column = gtk_tree_view_column_new_with_attributes ("name", renderer, "text", APPS_NAME, NULL);
-		gtk_tree_view_append_column (tree, column);
-	} else {
-		store = GTK_LIST_STORE (model);
-	}
-    
-	acl = seahorse_gkr_item_get_acl (git);
-    
-	/* Fill in the tree store, replacing any rows already present */
-	valid = gtk_tree_model_get_iter_first (model, &iter);
-	for ( ; acl; acl = g_list_next (acl)) {
-    
-		ac = (GnomeKeyringAccessControl*)acl->data;
-		g_return_if_fail (ac);
-        
-		if (!valid)
-			gtk_list_store_append (store, &iter);
-
-		display = gnome_keyring_item_ac_get_display_name (ac);
-		gtk_list_store_set (store, &iter, 
-		                    APPS_NAME, display ? display : "", 
-		                    APPS_ACCESS, ac,
-		                    -1);
-		g_free (display);
-        
-		if (valid)
-			valid = gtk_tree_model_iter_next (model, &iter);
-	}
-    
-	/* Remove all the remaining rows */
-	while (valid)
-		valid = gtk_list_store_remove (store, &iter);
-        
-	update_application_details (swidget);
-}
-
-static void 
-setup_application (SeahorseWidget *swidget)
-{
-	seahorse_bind_objects ("item-acl", SEAHORSE_OBJECT_WIDGET (swidget)->object,
-	                       (SeahorseTransfer)update_application, swidget);
-}
-
-/* -----------------------------------------------------------------------------
  * GENERAL
  */
 
@@ -770,11 +550,4 @@ seahorse_gkr_item_properties_show (SeahorseGkrItem *git, GtkWindow *parent)
 
     setup_main (swidget);
     setup_details (swidget);
-    setup_application (swidget);
-    
-    widget = seahorse_widget_get_widget (swidget, "application-list");
-    g_return_if_fail (GTK_IS_TREE_VIEW (widget));
-    
-    g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)), "changed", 
-                      G_CALLBACK (application_selection_changed), swidget);
 }
diff --git a/gkr/seahorse-gkr-item-properties.xml b/gkr/seahorse-gkr-item-properties.xml
index e4dbbef..7e38ecb 100644
--- a/gkr/seahorse-gkr-item-properties.xml
+++ b/gkr/seahorse-gkr-item-properties.xml
@@ -350,159 +350,6 @@
                 <property name="tab_fill">False</property>
               </packing>
             </child>
-            <child>
-              <object class="GtkVBox" id="vbox10">
-                <property name="visible">True</property>
-                <property name="border_width">12</property>
-                <property name="spacing">12</property>
-                <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow2">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="hscrollbar_policy">never</property>
-                    <property name="vscrollbar_policy">automatic</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="application-list">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="headers_visible">False</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkTable" id="application-details">
-                    <property name="visible">True</property>
-                    <property name="n_rows">2</property>
-                    <property name="n_columns">2</property>
-                    <property name="column_spacing">6</property>
-                    <property name="row_spacing">6</property>
-                    <child>
-                      <object class="GtkLabel" id="label22231">
-                        <property name="visible">True</property>
-                        <property name="xalign">1</property>
-                        <property name="label" translatable="yes">&lt;b&gt;Path:&lt;/b&gt;</property>
-                        <property name="use_markup">True</property>
-                      </object>
-                      <packing>
-                        <property name="x_options">GTK_FILL</property>
-                        <property name="y_options"></property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label22232">
-                        <property name="visible">True</property>
-                        <property name="xalign">1</property>
-                        <property name="label" translatable="yes">&lt;b&gt;Permissions:&lt;/b&gt;</property>
-                        <property name="use_markup">True</property>
-                      </object>
-                      <packing>
-                        <property name="top_attach">1</property>
-                        <property name="bottom_attach">2</property>
-                        <property name="x_options">GTK_FILL</property>
-                        <property name="y_options"></property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="application-path">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="xalign">0</property>
-                        <property name="selectable">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="right_attach">2</property>
-                        <property name="y_options"></property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkHBox" id="hbox62">
-                        <property name="visible">True</property>
-                        <property name="spacing">6</property>
-                        <child>
-                          <object class="GtkCheckButton" id="application-read">
-                            <property name="label" translatable="yes" comments="To translators: This is the infinitive not the imperative.">_Read</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="use_underline">True</property>
-                            <property name="draw_indicator">True</property>
-                            <signal name="toggled" handler="on_item_application_access_toggled"/>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkCheckButton" id="application-write">
-                            <property name="label" translatable="yes" comments="To translators: This is the infinitive not the imperative.">_Write</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="use_underline">True</property>
-                            <property name="draw_indicator">True</property>
-                            <signal name="toggled" handler="on_item_application_access_toggled"/>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkCheckButton" id="application-delete">
-                            <property name="label" translatable="yes" comments="To translators: This is the infinitive not the imperative.  This string refers to the ability of an application to delete this secret from its key ring." context="infinitive">_Delete</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="use_underline">True</property>
-                            <property name="draw_indicator">True</property>
-                            <signal name="toggled" handler="on_item_application_access_toggled"/>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">2</property>
-                          </packing>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="right_attach">2</property>
-                        <property name="top_attach">1</property>
-                        <property name="bottom_attach">2</property>
-                        <property name="x_options">GTK_FILL</property>
-                        <property name="y_options">GTK_FILL</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="position">2</property>
-              </packing>
-            </child>
-            <child type="tab">
-              <object class="GtkLabel" id="label22230">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">Applications</property>
-              </object>
-              <packing>
-                <property name="position">2</property>
-                <property name="tab_fill">False</property>
-              </packing>
-            </child>
           </object>
           <packing>
             <property name="position">1</property>
diff --git a/gkr/seahorse-gkr-item.c b/gkr/seahorse-gkr-item.c
index cf023ee..e953313 100644
--- a/gkr/seahorse-gkr-item.c
+++ b/gkr/seahorse-gkr-item.c
@@ -54,7 +54,6 @@ enum {
     PROP_ITEM_ID,
     PROP_ITEM_INFO,
     PROP_ITEM_ATTRIBUTES,
-    PROP_ITEM_ACL,
     PROP_HAS_SECRET,
     PROP_USE
 };
@@ -68,10 +67,6 @@ struct _SeahorseGkrItemPrivate {
 	
 	gpointer req_attrs;
 	GnomeKeyringAttributeList *item_attrs;
-	
-	gpointer req_acl;
-	gboolean got_acl;
-	GList *item_acl;
 
 	gpointer req_secret;
 	gchar *item_secret;
@@ -227,38 +222,6 @@ require_item_attrs (SeahorseGkrItem *self)
 	return self->pv->item_attrs != NULL;
 }
 
-static void
-received_item_acl (GnomeKeyringResult result, GList *acl, gpointer data)
-{
-	SeahorseGkrItem *self = SEAHORSE_GKR_ITEM (data);
-	self->pv->req_acl = NULL;
-	if (received_result (self, result)) {
-		self->pv->got_acl = TRUE;
-		seahorse_gkr_item_set_acl (self, acl);
-	}
-}
-
-static void
-load_item_acl (SeahorseGkrItem *self)
-{
-	/* Already in progress */
-	if (!self->pv->req_acl) {
-		g_object_ref (self);
-		self->pv->req_acl = gnome_keyring_item_get_acl (self->pv->keyring_name,
-		                                                self->pv->item_id,
-		                                                received_item_acl,
-		                                                self, g_object_unref);
-	}
-}
-
-static gboolean
-require_item_acl (SeahorseGkrItem *self)
-{
-	if (!self->pv->got_acl)
-		load_item_acl (self);
-	return self->pv->got_acl;
-}
-
 static guint32
 find_attribute_int (GnomeKeyringAttributeList *attrs, const gchar *name)
 {
@@ -503,7 +466,7 @@ seahorse_gkr_item_realize (SeahorseObject *obj)
 		      "markup", markup,
 		      "identifier", identifier,
 		      "description", description,
-		      "flags", 0,
+		      "flags", SEAHORSE_FLAG_DELETABLE,
 		      NULL);
 	
 	g_free (display);
@@ -525,21 +488,12 @@ seahorse_gkr_item_refresh (SeahorseObject *obj)
 		load_item_info (self);
 	if (self->pv->item_attrs)
 		load_item_attrs (self);
-	if (self->pv->got_acl)
-		load_item_acl (self);
 	if (self->pv->item_secret)
 		load_item_secret (self);
 
 	SEAHORSE_OBJECT_CLASS (seahorse_gkr_item_parent_class)->refresh (obj);
 }
 
-static SeahorseOperation*
-seahorse_gkr_item_delete (SeahorseObject *obj)
-{
-	SeahorseGkrItem *self = SEAHORSE_GKR_ITEM (obj);
-	return seahorse_gkr_operation_delete_item (self);
-}
-
 static void
 seahorse_gkr_item_init (SeahorseGkrItem *self)
 {
@@ -585,9 +539,6 @@ seahorse_gkr_item_get_property (GObject *object, guint prop_id,
 	case PROP_ITEM_ATTRIBUTES:
 		g_value_set_boxed (value, seahorse_gkr_item_get_attributes (self));
 		break;
-	case PROP_ITEM_ACL:
-		g_value_set_boxed (value, seahorse_gkr_item_get_acl (self));
-		break;
 	case PROP_HAS_SECRET:
 		g_value_set_boolean (value, self->pv->item_secret != NULL);
 		break;
@@ -621,9 +572,6 @@ seahorse_gkr_item_set_property (GObject *object, guint prop_id, const GValue *va
 	case PROP_ITEM_ATTRIBUTES:
 		seahorse_gkr_item_set_attributes (self, g_value_get_boxed (value));
 		break;
-	case PROP_ITEM_ACL:
-		seahorse_gkr_item_set_acl (self, g_value_get_boxed (value));
-		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -648,11 +596,6 @@ seahorse_gkr_item_finalize (GObject *gobject)
 	self->pv->item_attrs = NULL;
 	g_assert (self->pv->req_attrs == NULL);
 
-	gnome_keyring_acl_free (self->pv->item_acl);
-	self->pv->item_acl = NULL;
-	self->pv->got_acl = FALSE;
-	g_assert (self->pv->req_acl == NULL);
-
 	g_free (self->pv->item_secret);
 	self->pv->item_secret = NULL;
 	g_assert (self->pv->req_secret == NULL);
@@ -677,8 +620,7 @@ seahorse_gkr_item_class_init (SeahorseGkrItemClass *klass)
 	seahorse_class = SEAHORSE_OBJECT_CLASS (klass);
 	seahorse_class->realize = seahorse_gkr_item_realize;
 	seahorse_class->refresh = seahorse_gkr_item_refresh;
-	seahorse_class->delete = seahorse_gkr_item_delete;
-	
+
 	g_type_class_add_private (klass, sizeof (SeahorseGkrItemPrivate));
     
 	g_object_class_install_property (gobject_class, PROP_KEYRING_NAME,
@@ -697,10 +639,6 @@ seahorse_gkr_item_class_init (SeahorseGkrItemClass *klass)
                 g_param_spec_boxed ("item-attributes", "Item Attributes", "GNOME Keyring Item Attributes",
                                     boxed_attributes_type (), G_PARAM_READWRITE));
 
-	g_object_class_install_property (gobject_class, PROP_ITEM_ACL,
-                g_param_spec_boxed ("item-acl", "Item ACL", "GNOME Keyring Item ACL",
-                                    boxed_acl_type (),  G_PARAM_READWRITE));
-
 	g_object_class_install_property (gobject_class, PROP_USE,
 	        g_param_spec_uint ("use", "Use", "Item is used for", 
 	                           0, G_MAXUINT, 0, G_PARAM_READABLE));
@@ -747,7 +685,8 @@ void
 seahorse_gkr_item_set_info (SeahorseGkrItem *self, GnomeKeyringItemInfo* info)
 {
 	GObject *obj;
-	
+	gchar *secret;
+
 	g_return_if_fail (SEAHORSE_IS_GKR_ITEM (self));
 	
 	if (self->pv->item_info)
@@ -764,11 +703,13 @@ seahorse_gkr_item_set_info (SeahorseGkrItem *self, GnomeKeyringItemInfo* info)
 	g_object_notify (obj, "use");
 	
 	/* Get the secret out of the item info, if not already loaded */
-	if (!self->pv->item_secret && self->pv->item_info && !self->pv->req_secret) {
-		WITH_SECURE_MEM (self->pv->item_secret = gnome_keyring_item_info_get_secret (self->pv->item_info));
+	WITH_SECURE_MEM (secret = gnome_keyring_item_info_get_secret (self->pv->item_info));
+	if (secret != NULL) {
+		gnome_keyring_free_password (self->pv->item_secret);
+		self->pv->item_secret = secret;
 		g_object_notify (obj, "has-secret");
 	}
-		
+
 	g_object_thaw_notify (obj);
 }
 
@@ -844,35 +785,6 @@ seahorse_gkr_find_string_attribute (GnomeKeyringAttributeList *attrs, const gcha
 	return NULL;	
 }
 
-GList*
-seahorse_gkr_item_get_acl (SeahorseGkrItem *self)
-{
-	g_return_val_if_fail (SEAHORSE_IS_GKR_ITEM (self), NULL);
-	require_item_acl (self);
-	return self->pv->item_acl;
-}
-
-void
-seahorse_gkr_item_set_acl (SeahorseGkrItem *self, GList* acl)
-{
-	GObject *obj;
-	
-	g_return_if_fail (SEAHORSE_IS_GKR_ITEM (self));
-	
-	if (self->pv->item_acl)
-		gnome_keyring_acl_free (self->pv->item_acl);
-	if (acl)
-		self->pv->item_acl = gnome_keyring_acl_copy (acl);
-	else
-		self->pv->item_acl = NULL;
-	
-	obj = G_OBJECT (self);
-	g_object_freeze_notify (obj);
-	seahorse_gkr_item_realize (SEAHORSE_OBJECT (self));
-	g_object_notify (obj, "item-acl");
-	g_object_thaw_notify (obj);
-}
-
 GQuark
 seahorse_gkr_item_get_cannonical (const gchar *keyring_name, guint32 item_id)
 {
diff --git a/gkr/seahorse-gkr-item.h b/gkr/seahorse-gkr-item.h
index 875b497..f68f915 100644
--- a/gkr/seahorse-gkr-item.h
+++ b/gkr/seahorse-gkr-item.h
@@ -90,11 +90,6 @@ const gchar*                 seahorse_gkr_item_get_attribute      (SeahorseGkrIt
 const gchar* 		     seahorse_gkr_find_string_attribute   (GnomeKeyringAttributeList *attrs, 
              		                                           const gchar *name);
 
-GList*                       seahorse_gkr_item_get_acl            (SeahorseGkrItem *self);
-
-void                         seahorse_gkr_item_set_acl            (SeahorseGkrItem *self,
-                                                                   GList* acl);
-
 GQuark                       seahorse_gkr_item_get_cannonical     (const gchar *keyring_name, 
                                                                    guint32 item_id);
 
diff --git a/gkr/seahorse-gkr-keyring-commands.c b/gkr/seahorse-gkr-keyring-commands.c
index ef26d70..a909efb 100644
--- a/gkr/seahorse-gkr-keyring-commands.c
+++ b/gkr/seahorse-gkr-keyring-commands.c
@@ -26,10 +26,12 @@
 #include "seahorse-gkr.h"
 #include "seahorse-gkr-keyring.h"
 #include "seahorse-gkr-dialogs.h"
+#include "seahorse-gkr-operation.h"
 #include "seahorse-gkr-source.h"
 
 #include "common/seahorse-registry.h"
 
+#include "seahorse-progress.h"
 #include "seahorse-source.h"
 #include "seahorse-util.h"
 
@@ -62,9 +64,11 @@ static void on_view_selection_changed (SeahorseView *view, gpointer user_data);
  */
 
 static void
-on_refresh_done (SeahorseOperation *op, gpointer user_data)
+on_refresh_all_keyrings_complete (GObject *source,
+                                  GAsyncResult *result,
+                                  gpointer user_data)
 {
-	SeahorseCommands *self = user_data;
+	SeahorseCommands *self = SEAHORSE_COMMANDS (user_data);
 	SeahorseView *view;
 
 	g_return_if_fail (SEAHORSE_IS_COMMANDS (self));
@@ -79,19 +83,9 @@ on_refresh_done (SeahorseOperation *op, gpointer user_data)
 static void
 refresh_all_keyrings (SeahorseCommands *self)
 {
-	SeahorseOperation *op;
-
-	op = seahorse_source_load (SEAHORSE_SOURCE (seahorse_gkr_source_default ()));
-	
-	/* 
-	 * HACK: Major hack alert. This whole area needs some serious refactoring,
-	 * so for now we're just going to let any viewers listen in on this
-	 * operation like so:
-	 */
-	g_signal_emit_by_name (seahorse_context_instance (), "refreshing", op);
-
-	seahorse_operation_watch (op, on_refresh_done, g_object_ref (self), NULL, NULL);
-	g_object_unref (op);
+	seahorse_source_load_async (SEAHORSE_SOURCE (seahorse_gkr_source_default ()),
+	                            NULL, on_refresh_all_keyrings_complete,
+	                            g_object_ref (self));
 }
 
 /**
@@ -342,24 +336,50 @@ seahorse_gkr_keyring_commands_show_properties (SeahorseCommands* base, SeahorseO
 		g_return_if_reached ();
 }
 
-static SeahorseOperation* 
-seahorse_gkr_keyring_commands_delete_objects (SeahorseCommands* base, GList* objects) 
+static void
+on_delete_objects_complete (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+	SeahorseCommands *commands = SEAHORSE_COMMANDS (user_data);
+	GError *error = NULL;
+	GtkWidget *parent;
+
+	if (!seahorse_gkr_delete_finish (result, &error)) {
+		parent = GTK_WIDGET (seahorse_view_get_window (seahorse_commands_get_view (commands)));
+		seahorse_util_show_error (parent, _("Couldn't delete keyring"), error->message);
+		g_error_free (error);
+	}
+
+	g_object_unref (commands);
+}
+
+static gboolean
+seahorse_gkr_keyring_commands_delete_objects (SeahorseCommands* commands,
+                                              GList* objects)
 {
-	SeahorseOperation *oper = NULL;
+	GCancellable *cancellable;
 	gchar *prompt;
-	
+	gboolean ret;
+
 	if (!objects)
-		return NULL;
+		return TRUE;
 
 	prompt = g_strdup_printf (_ ("Are you sure you want to delete the password keyring '%s'?"), 
 	                          seahorse_object_get_label (objects->data));
 
-	if (seahorse_util_prompt_delete (prompt, GTK_WIDGET (seahorse_commands_get_window (base))))
-		oper = seahorse_object_delete (objects->data);
-		
+	ret = seahorse_util_prompt_delete (prompt, GTK_WIDGET (seahorse_commands_get_window (commands)));
+
+	if (ret) {
+		cancellable = g_cancellable_new ();
+		seahorse_gkr_delete_async (objects, cancellable,
+		                           on_delete_objects_complete,
+		                           g_object_ref (commands));
+		seahorse_progress_show (cancellable, ngettext (_("Deleting keyring"), _("Deleting keyrings"),
+		                                               g_list_length (objects)), TRUE);
+		g_object_unref (cancellable);
+	}
+
 	g_free (prompt);
-	
-	return oper;
+	return ret;
 }
 
 static GObject* 
@@ -427,7 +447,7 @@ seahorse_gkr_keyring_commands_class_init (SeahorseGkrKeyringCommandsClass *klass
 
 	cmd_class->show_properties = seahorse_gkr_keyring_commands_show_properties;
 	cmd_class->delete_objects = seahorse_gkr_keyring_commands_delete_objects;
-	
+
 	g_type_class_add_private (gobject_class, sizeof (SeahorseGkrKeyringCommandsPrivate));
 
 	/* Setup the predicate for these commands */
diff --git a/gkr/seahorse-gkr-keyring.c b/gkr/seahorse-gkr-keyring.c
index 8f13eee..a0ff623 100644
--- a/gkr/seahorse-gkr-keyring.c
+++ b/gkr/seahorse-gkr-keyring.c
@@ -25,244 +25,10 @@
 #include "seahorse-gkr-keyring.h"
 #include "seahorse-gkr-operation.h"
 
-#include <glib/gi18n.h>
-
-/* -----------------------------------------------------------------------------
- * LIST OPERATION 
- */
- 
-
-#define SEAHORSE_TYPE_GKR_LIST_OPERATION            (seahorse_gkr_list_operation_get_type ())
-#define SEAHORSE_GKR_LIST_OPERATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_GKR_LIST_OPERATION, SeahorseGkrListOperation))
-#define SEAHORSE_GKR_LIST_OPERATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_GKR_LIST_OPERATION, SeahorseGkrListOperationClass))
-#define SEAHORSE_IS_GKR_LIST_OPERATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_GKR_LIST_OPERATION))
-#define SEAHORSE_IS_GKR_LIST_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_GKR_LIST_OPERATION))
-#define SEAHORSE_GKR_LIST_OPERATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_GKR_LIST_OPERATION, SeahorseGkrListOperationClass))
-
-typedef struct _SeahorseGkrListOperation SeahorseGkrListOperation;
-typedef struct _SeahorseGkrListOperationClass SeahorseGkrListOperationClass;
-
-struct _SeahorseGkrListOperation {
-	SeahorseOperation parent;
-	SeahorseGkrKeyring *keyring;
-	gpointer request;
-};
-
-struct _SeahorseGkrListOperationClass {
-	SeahorseOperationClass parent_class;
-};
-
-G_DEFINE_TYPE (SeahorseGkrListOperation, seahorse_gkr_list_operation, SEAHORSE_TYPE_OPERATION);
-
-static void
-keyring_operation_failed (SeahorseGkrListOperation *self, GnomeKeyringResult result)
-{
-	SeahorseOperation *op = SEAHORSE_OPERATION (self);
-	GError *err = NULL;
-    
-	g_assert (result != GNOME_KEYRING_RESULT_OK);
-	g_assert (result != GNOME_KEYRING_RESULT_CANCELLED);
-    
-	if (!seahorse_operation_is_running (op))
-		return;
-    
-	if (self->request)
-	    gnome_keyring_cancel_request (self->request);
-	self->request = NULL;
-    
-	seahorse_gkr_operation_parse_error (result, &err);
-	g_assert (err != NULL);
-    
-	seahorse_operation_mark_done (op, FALSE, err);
-}
-
-/* Remove the given key from the context */
-static void
-remove_key_from_context (gpointer kt, SeahorseObject *dummy, SeahorseSource *sksrc)
-{
-	/* This function gets called as a GHFunc on the self->checks hashtable. */
-	GQuark keyid = GPOINTER_TO_UINT (kt);
-	SeahorseObject *sobj;
-    
-	sobj = seahorse_context_get_object (SCTX_APP (), sksrc, keyid);
-	if (sobj != NULL)
-		seahorse_context_remove_object (SCTX_APP (), sobj);
-}
-
-static void
-insert_id_hashtable (SeahorseObject *object, gpointer user_data)
-{
-	g_hash_table_insert ((GHashTable*)user_data, 
-	                     GUINT_TO_POINTER (seahorse_object_get_id (object)),
-	                     GUINT_TO_POINTER (TRUE));
-}
-
-static void 
-on_list_item_ids (GnomeKeyringResult result, GList *list, SeahorseGkrListOperation *self)
-{
-	SeahorseObjectPredicate pred;
-	SeahorseGkrItem *git;
-	const gchar *keyring_name;
-	GHashTable *checks;
-	guint32 item_id;
-	GQuark id;
-	
-	if (result == GNOME_KEYRING_RESULT_CANCELLED)
-		return;
-    
-	self->request = NULL;
-
-	if (result != GNOME_KEYRING_RESULT_OK) {
-		keyring_operation_failed (self, result);
-		return;
-	}
-	
-	keyring_name = seahorse_gkr_keyring_get_name (self->keyring);
-	g_return_if_fail (keyring_name);
-
-	/* When loading new keys prepare a list of current */
-	checks = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
-	seahorse_object_predicate_clear (&pred);
-	pred.source = SEAHORSE_SOURCE (self->keyring);
-	pred.type = SEAHORSE_TYPE_GKR_ITEM;
-	seahorse_context_for_objects_full (SCTX_APP (), &pred, insert_id_hashtable, checks);
-    
-	while (list) {
-		item_id = GPOINTER_TO_UINT (list->data);
-		id = seahorse_gkr_item_get_cannonical (keyring_name, item_id);
-		
-		git = SEAHORSE_GKR_ITEM (seahorse_context_get_object (SCTX_APP (), 
-		                                                      SEAHORSE_SOURCE (self->keyring), id));
-		if (!git) {
-			git = seahorse_gkr_item_new (SEAHORSE_SOURCE (self->keyring), keyring_name, item_id);
+#include "seahorse-progress.h"
+#include "seahorse-util.h"
 
-			/* Add to context */ 
-			seahorse_object_set_parent (SEAHORSE_OBJECT (git), SEAHORSE_OBJECT (self->keyring));
-			seahorse_context_take_object (SCTX_APP (), SEAHORSE_OBJECT (git));
-		}
-		
-		g_hash_table_remove (checks, GUINT_TO_POINTER (id));
-		list = g_list_next (list);
-	}
-	
-	g_hash_table_foreach (checks, (GHFunc)remove_key_from_context, 
-	                      SEAHORSE_SOURCE (self->keyring));
-	
-	g_hash_table_destroy (checks);
-        
-        seahorse_operation_mark_done (SEAHORSE_OPERATION (self), FALSE, NULL);
-}
-
-static void
-on_keyring_info (GnomeKeyringResult result, GnomeKeyringInfo *info, SeahorseGkrListOperation *self)
-{
-	if (result == GNOME_KEYRING_RESULT_CANCELLED)
-		return;
-    
-	self->request = NULL;
-
-	if (result != GNOME_KEYRING_RESULT_OK) {
-		keyring_operation_failed (self, result);
-		return;
-	}
-
-	seahorse_gkr_keyring_set_info (self->keyring, info);
-	if (gnome_keyring_info_get_is_locked (info)) {
-		/* Locked, no items... */
-		on_list_item_ids (GNOME_KEYRING_RESULT_OK, NULL, self);
-	} else {
-		g_object_ref (self);
-		self->request = gnome_keyring_list_item_ids (seahorse_gkr_keyring_get_name (self->keyring), 
-		                                            (GnomeKeyringOperationGetListCallback)on_list_item_ids, 
-		                                            self, g_object_unref);
-	}
-}
-
-static SeahorseOperation*
-start_gkr_list_operation (SeahorseGkrKeyring *keyring)
-{
-	SeahorseGkrListOperation *self;
-
-	g_assert (SEAHORSE_IS_GKR_KEYRING (keyring));
-
-	self = g_object_new (SEAHORSE_TYPE_GKR_LIST_OPERATION, NULL);
-	self->keyring = keyring;
-    
-	/* Start listing of ids */
-	seahorse_operation_mark_start (SEAHORSE_OPERATION (self));
-	seahorse_operation_mark_progress (SEAHORSE_OPERATION (self), _("Listing passwords"), -1);
-	
-	g_object_ref (self);
-	self->request = gnome_keyring_get_info (seahorse_gkr_keyring_get_name (keyring), 
-	                                        (GnomeKeyringOperationGetKeyringInfoCallback)on_keyring_info, 
-	                                        self, g_object_unref);
-    
-	return SEAHORSE_OPERATION (self);
-}
-
-static void 
-seahorse_gkr_list_operation_cancel (SeahorseOperation *operation)
-{
-	SeahorseGkrListOperation *self = SEAHORSE_GKR_LIST_OPERATION (operation);    
-
-	if (self->request)
-		gnome_keyring_cancel_request (self->request);
-	self->request = NULL;
-    
-	if (seahorse_operation_is_running (operation))
-		seahorse_operation_mark_done (operation, TRUE, NULL);
-}
-
-static void 
-seahorse_gkr_list_operation_init (SeahorseGkrListOperation *self)
-{	
-	/* Everything already set to zero */
-}
-
-static void 
-seahorse_gkr_list_operation_dispose (GObject *gobject)
-{
-	SeahorseGkrListOperation *self = SEAHORSE_GKR_LIST_OPERATION (gobject);
-    
-	/* Cancel it if it's still running */
-	if (seahorse_operation_is_running (SEAHORSE_OPERATION (self)))
-		seahorse_gkr_list_operation_cancel (SEAHORSE_OPERATION (self));
-	g_assert (!seahorse_operation_is_running (SEAHORSE_OPERATION (self)));
-    
-	/* The above cancel should have stopped this */
-	g_assert (self->request == NULL);
-
-	G_OBJECT_CLASS (seahorse_gkr_list_operation_parent_class)->dispose (gobject);
-}
-
-static void 
-seahorse_gkr_list_operation_finalize (GObject *gobject)
-{
-	SeahorseGkrListOperation *self = SEAHORSE_GKR_LIST_OPERATION (gobject);
-	g_assert (!seahorse_operation_is_running (SEAHORSE_OPERATION (self)));
-    
-	/* The above cancel should have stopped this */
-	g_assert (self->request == NULL);
-
-	G_OBJECT_CLASS (seahorse_gkr_list_operation_parent_class)->finalize (gobject);
-}
-
-static void
-seahorse_gkr_list_operation_class_init (SeahorseGkrListOperationClass *klass)
-{
-	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-	SeahorseOperationClass *operation_class = SEAHORSE_OPERATION_CLASS (klass);
-	
-	seahorse_gkr_list_operation_parent_class = g_type_class_peek_parent (klass);
-	gobject_class->dispose = seahorse_gkr_list_operation_dispose;
-	gobject_class->finalize = seahorse_gkr_list_operation_finalize;
-	operation_class->cancel = seahorse_gkr_list_operation_cancel;
-    
-}
-
-/* -----------------------------------------------------------------------------------------
- * KEYRING
- */
+#include <glib/gi18n.h>
 
 enum {
 	PROP_0,
@@ -360,7 +126,7 @@ seahorse_gkr_keyring_realize (SeahorseObject *obj)
 	              "nickname", self->pv->keyring_name,
 	              "identifier", "",
 	              "description", "",
-	              "flags", 0,
+	              "flags", SEAHORSE_FLAG_DELETABLE,
 	              "icon", "folder",
 	              "usage", SEAHORSE_USAGE_OTHER,
 	              NULL);
@@ -382,18 +148,197 @@ seahorse_gkr_keyring_refresh (SeahorseObject *obj)
 	SEAHORSE_OBJECT_CLASS (seahorse_gkr_keyring_parent_class)->refresh (obj);
 }
 
-static SeahorseOperation*
-seahorse_gkr_keyring_delete (SeahorseObject *obj)
+typedef struct {
+	SeahorseGkrKeyring *keyring;
+	gpointer request;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+} keyring_load_closure;
+
+static void
+keyring_load_free (gpointer data)
 {
-	SeahorseGkrKeyring *self = SEAHORSE_GKR_KEYRING (obj);
-	return seahorse_gkr_operation_delete_keyring (self);
+	keyring_load_closure *closure = data;
+	if (closure->cancellable && closure->cancelled_sig)
+		g_signal_handler_disconnect (closure->cancellable,
+		                             closure->cancelled_sig);
+	if (closure->cancellable)
+		g_object_unref (closure->cancellable);
+	g_clear_object (&closure->keyring);
+	g_assert (!closure->request);
+	g_free (closure);
 }
 
-static SeahorseOperation*
-seahorse_gkr_keyring_load (SeahorseSource *src)
+/* Remove the given key from the context */
+static void
+remove_key_from_context (gpointer kt, SeahorseObject *dummy, SeahorseSource *sksrc)
 {
-	SeahorseGkrKeyring *self = SEAHORSE_GKR_KEYRING (src);
-	return start_gkr_list_operation (self);
+	/* This function gets called as a GHFunc on the self->checks hashtable. */
+	GQuark keyid = GPOINTER_TO_UINT (kt);
+	SeahorseObject *sobj;
+
+	sobj = seahorse_context_get_object (SCTX_APP (), sksrc, keyid);
+	if (sobj != NULL)
+		seahorse_context_remove_object (SCTX_APP (), sobj);
+}
+
+static void
+insert_id_hashtable (SeahorseObject *object, gpointer user_data)
+{
+	g_hash_table_insert ((GHashTable*)user_data,
+	                     GUINT_TO_POINTER (seahorse_object_get_id (object)),
+	                     GUINT_TO_POINTER (TRUE));
+}
+
+static void
+on_keyring_load_list_item_ids (GnomeKeyringResult result,
+                               GList *list,
+                               gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	keyring_load_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseObjectPredicate pred;
+	SeahorseGkrItem *git;
+	const gchar *keyring_name;
+	GError *error = NULL;
+	GHashTable *checks;
+	guint32 item_id;
+	GQuark id;
+
+	closure->request = NULL;
+
+	if (seahorse_gkr_propagate_error (result, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		return;
+	}
+
+	keyring_name = seahorse_gkr_keyring_get_name (closure->keyring);
+	g_return_if_fail (keyring_name);
+
+	/* When loading new keys prepare a list of current */
+	checks = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+	seahorse_object_predicate_clear (&pred);
+	pred.source = SEAHORSE_SOURCE (closure->keyring);
+	pred.type = SEAHORSE_TYPE_GKR_ITEM;
+	seahorse_context_for_objects_full (SCTX_APP (), &pred, insert_id_hashtable, checks);
+
+	while (list) {
+		item_id = GPOINTER_TO_UINT (list->data);
+		id = seahorse_gkr_item_get_cannonical (keyring_name, item_id);
+
+		git = SEAHORSE_GKR_ITEM (seahorse_context_get_object (seahorse_context_instance (),
+		                                                      SEAHORSE_SOURCE (closure->keyring), id));
+		if (!git) {
+			git = seahorse_gkr_item_new (SEAHORSE_SOURCE (closure->keyring), keyring_name, item_id);
+
+			/* Add to context */
+			seahorse_object_set_parent (SEAHORSE_OBJECT (git), SEAHORSE_OBJECT (closure->keyring));
+			seahorse_context_take_object (seahorse_context_instance (), SEAHORSE_OBJECT (git));
+		}
+
+		g_hash_table_remove (checks, GUINT_TO_POINTER (id));
+		list = g_list_next (list);
+	}
+
+	g_hash_table_foreach (checks, (GHFunc)remove_key_from_context,
+	                      SEAHORSE_SOURCE (closure->keyring));
+
+	g_hash_table_destroy (checks);
+
+	seahorse_progress_end (closure->cancellable, res);
+	g_simple_async_result_complete_in_idle (res);
+}
+
+static void
+on_keyring_load_get_info (GnomeKeyringResult result,
+                          GnomeKeyringInfo *info,
+                          gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	keyring_load_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	const gchar *name;
+
+	closure->request = NULL;
+
+	if (seahorse_gkr_propagate_error (result, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+
+	} else {
+		seahorse_gkr_keyring_set_info (closure->keyring, info);
+
+		/* Locked, no items... */
+		if (gnome_keyring_info_get_is_locked (info)) {
+			on_keyring_load_list_item_ids (GNOME_KEYRING_RESULT_OK, NULL, res);
+
+		} else {
+			name = seahorse_gkr_keyring_get_name (closure->keyring);
+			closure->request = gnome_keyring_list_item_ids (name,
+			                                                on_keyring_load_list_item_ids,
+			                                                g_object_ref (res), g_object_unref);
+		}
+	}
+}
+
+static void
+on_keyring_load_cancelled (GCancellable *cancellable,
+                           gpointer user_data)
+{
+	keyring_load_closure *closure = user_data;
+
+	if (closure->request)
+		gnome_keyring_cancel_request (closure->request);
+}
+
+static void
+seahorse_gkr_keyring_load_async (SeahorseSource *source,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+	SeahorseGkrKeyring *self = SEAHORSE_GKR_KEYRING (source);
+	keyring_load_closure *closure;
+	GSimpleAsyncResult *res;
+#if TODO
+/* cancellable = g_cancellable_new ();
+g_cancellable_cancel (cancellable); */
+#endif
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_gkr_keyring_load_async);
+
+	closure = g_new0 (keyring_load_closure, 1);
+	closure->keyring = g_object_ref (self);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	g_simple_async_result_set_op_res_gpointer (res, closure, keyring_load_free);
+
+	closure->request = gnome_keyring_get_info (seahorse_gkr_keyring_get_name (self),
+	                                           on_keyring_load_get_info,
+	                                           g_object_ref (res), g_object_unref);
+
+	if (cancellable)
+		closure->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                G_CALLBACK (on_keyring_load_cancelled),
+		                                                closure, NULL);
+	seahorse_progress_prep_and_begin (cancellable, res, NULL);
+
+	g_object_unref (res);
+}
+
+static gboolean
+seahorse_gkr_keyring_load_finish (SeahorseSource *source,
+                                  GAsyncResult *result,
+                                  GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_gkr_keyring_load_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
 }
 
 static GObject* 
@@ -510,12 +455,11 @@ seahorse_gkr_keyring_class_init (SeahorseGkrKeyringClass *klass)
 	gobject_class->finalize = seahorse_gkr_keyring_finalize;
 	gobject_class->set_property = seahorse_gkr_keyring_set_property;
 	gobject_class->get_property = seahorse_gkr_keyring_get_property;
-    
+
 	seahorse_class = SEAHORSE_OBJECT_CLASS (klass);
 	seahorse_class->realize = seahorse_gkr_keyring_realize;
 	seahorse_class->refresh = seahorse_gkr_keyring_refresh;
-	seahorse_class->delete = seahorse_gkr_keyring_delete;
-	
+
 	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
 	g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
 
@@ -535,7 +479,8 @@ seahorse_gkr_keyring_class_init (SeahorseGkrKeyringClass *klass)
 static void 
 seahorse_source_iface (SeahorseSourceIface *iface)
 {
-	iface->load = seahorse_gkr_keyring_load;
+	iface->load_async = seahorse_gkr_keyring_load_async;
+	iface->load_finish = seahorse_gkr_keyring_load_finish;
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/gkr/seahorse-gkr-operation.c b/gkr/seahorse-gkr-operation.c
index 418eceb..d7ac952 100644
--- a/gkr/seahorse-gkr-operation.c
+++ b/gkr/seahorse-gkr-operation.c
@@ -28,128 +28,30 @@
 #include <glib/gi18n.h>
 
 #include "seahorse-gkr-operation.h"
+#include "seahorse-progress.h"
 #include "seahorse-util.h"
 #include "seahorse-passphrase.h"
 
 #include <gnome-keyring.h>
-
-/* -----------------------------------------------------------------------------
- * DEFINITIONS
- */
- 
-struct _SeahorseGkrOperationPrivate {
-	gpointer request;
-	SeahorseObject *object;   
-};
-
-G_DEFINE_TYPE (SeahorseGkrOperation, seahorse_gkr_operation, SEAHORSE_TYPE_OPERATION);
-
-/* -----------------------------------------------------------------------------
- * HELPERS 
- */
-
-static gboolean
-check_operation_result (SeahorseGkrOperation *self, GnomeKeyringResult result)
-{
-    GError *err = NULL;
-    gboolean success;
-    
-    /* This only gets called when we cancel, so ignore */
-    if (result == GNOME_KEYRING_RESULT_CANCELLED)
-        return FALSE;
-    
-    success = seahorse_gkr_operation_parse_error (result, &err);
-    g_assert (!success || !err);
-    
-    seahorse_operation_mark_done (SEAHORSE_OPERATION (self), FALSE, err);
-    return success;
-}
-
-/* -----------------------------------------------------------------------------
- * OBJECT 
- */
-
-static void 
-seahorse_gkr_operation_init (SeahorseGkrOperation *self)
-{
-	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, SEAHORSE_TYPE_GKR_OPERATION, SeahorseGkrOperationPrivate);
-
-}
-
-static void 
-seahorse_gkr_operation_dispose (GObject *gobject)
-{
-	SeahorseGkrOperation *self = SEAHORSE_GKR_OPERATION (gobject);
-
-	if (seahorse_operation_is_running (SEAHORSE_OPERATION (self)))
-		seahorse_operation_cancel (SEAHORSE_OPERATION (self));
-	g_assert (!seahorse_operation_is_running (SEAHORSE_OPERATION (self)));
-    
-	if (self->pv->object)
-		g_object_unref (self->pv->object);
-	self->pv->object = NULL;
-    
-	/* The above cancel should have stopped this */
-	g_assert (self->pv->request == NULL);
-    
-	G_OBJECT_CLASS (seahorse_gkr_operation_parent_class)->dispose (gobject);  
-}
-
-static void 
-seahorse_gkr_operation_finalize (GObject *gobject)
-{
-	SeahorseGkrOperation *self = SEAHORSE_GKR_OPERATION (gobject);
-    
-	g_assert (!self->pv->request);
-    
-	G_OBJECT_CLASS (seahorse_gkr_operation_parent_class)->finalize (gobject);  
-}
-
-static void 
-seahorse_gkr_operation_cancel (SeahorseOperation *operation)
-{
-	SeahorseGkrOperation *self = SEAHORSE_GKR_OPERATION (operation);    
-
-	if (self->pv->request)
-		gnome_keyring_cancel_request (self->pv->request);
-	self->pv->request = NULL;
-    
-	if (seahorse_operation_is_running (operation))
-		seahorse_operation_mark_done (operation, TRUE, NULL);    
-}
-
-static void
-seahorse_gkr_operation_class_init (SeahorseGkrOperationClass *klass)
-{
-	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-    
-	seahorse_gkr_operation_parent_class = g_type_class_peek_parent (klass);
-	g_type_class_add_private (klass, sizeof (SeahorseGkrOperationPrivate));
-
-	gobject_class->dispose = seahorse_gkr_operation_dispose;
-	gobject_class->finalize = seahorse_gkr_operation_finalize;
-	
-	SEAHORSE_OPERATION_CLASS (klass)->cancel = seahorse_gkr_operation_cancel;
-}
-
-/* -----------------------------------------------------------------------------
- * PUBLIC 
- */
+#include <gnome-keyring-memory.h>
 
 gboolean
-seahorse_gkr_operation_parse_error (GnomeKeyringResult result, GError **err)
+seahorse_gkr_propagate_error (GnomeKeyringResult result, GError **error)
 {
     static GQuark errorq = 0;
     const gchar *message = NULL;
+    gint code = (gint)result;
 
     if (result == GNOME_KEYRING_RESULT_OK)
-        return TRUE;
-    
-    /* These should be handled in the callbacks */
-    g_assert (result != GNOME_KEYRING_RESULT_CANCELLED);
-    
+        return FALSE;
+
     /* An error mark it as such */
     switch (result) {
+    case GNOME_KEYRING_RESULT_CANCELLED:
+        message = _("The operation was cancelled");
+        code = G_IO_ERROR_CANCELLED;
+        errorq = G_IO_ERROR;
+        break;
     case GNOME_KEYRING_RESULT_DENIED:
         message = _("Access to the key ring was denied");
         break;
@@ -178,137 +80,419 @@ seahorse_gkr_operation_parse_error (GnomeKeyringResult result, GError **err)
     
     if (!errorq) 
         errorq = g_quark_from_static_string ("seahorse-gnome-keyring");
-    
-    g_set_error (err, errorq, result, "%s", message);
-    return FALSE;
+
+    g_set_error (error, errorq, code, "%s", message);
+    return TRUE;
 }
 
-/* -----------------------------------------------------------------------------
- * UPDATE INFO OPERATION
- */
+typedef struct {
+	GnomeKeyringItemInfo *info;
+	gchar *secret;
+	SeahorseGkrItem *item;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+	gpointer request;
+} update_secret_closure;
 
-static void 
-basic_operation_done (GnomeKeyringResult result, SeahorseGkrOperation *self)
+static void
+update_secret_free (gpointer data)
 {
-	g_assert (SEAHORSE_IS_GKR_OPERATION (self));
-	self->pv->request = NULL;
+	update_secret_closure *closure = data;
+	gnome_keyring_free_password (closure->secret);
+	g_object_unref (closure->item);
+	if (closure->cancellable && closure->cancelled_sig)
+		g_signal_handler_disconnect (closure->cancellable,
+		                             closure->cancelled_sig);
+	g_clear_object (&closure->cancellable);
+	gnome_keyring_item_info_free (closure->info);
+	g_assert (closure->request == NULL);
+	g_free (closure);
+}
 
-	if (!check_operation_result (self, result))
-		return;
-    
-	/* When operation is successful reload the key */
-	seahorse_object_refresh (SEAHORSE_OBJECT (self->pv->object));
+static void
+on_update_secret_set_info_complete (GnomeKeyringResult result,
+                                    gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	update_secret_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	closure->request = NULL;
+	seahorse_progress_end (closure->cancellable, res);
+
+	if (seahorse_gkr_propagate_error (result, &error))
+		g_simple_async_result_take_error (res, error);
+	else
+		seahorse_gkr_item_set_info (closure->item, closure->info);
+
+	g_simple_async_result_complete_in_idle (res);
 }
 
-SeahorseOperation*
-seahorse_gkr_operation_update_info (SeahorseGkrItem *item, GnomeKeyringItemInfo *info)
+static void
+on_update_secret_get_info_complete (GnomeKeyringResult result,
+                                    GnomeKeyringItemInfo *info,
+                                    gpointer user_data)
 {
-	SeahorseGkrOperation *self;
-    
-	g_return_val_if_fail (SEAHORSE_IS_GKR_ITEM (item), NULL);
-    
-	self = g_object_new (SEAHORSE_TYPE_GKR_OPERATION, NULL);
-    
-	g_object_ref (item);
-	self->pv->object = SEAHORSE_OBJECT (item);
-    
-	/* Start actual save request */
-	g_object_ref (self);
-	self->pv->request = gnome_keyring_item_set_info (seahorse_gkr_item_get_keyring_name (item),
-	                                                 seahorse_gkr_item_get_item_id (item), info, 
-	                                                 (GnomeKeyringOperationDoneCallback)basic_operation_done,
-	                                                 self, g_object_unref);
-	g_return_val_if_fail (self->pv->request, NULL);
-    
-	seahorse_operation_mark_start (SEAHORSE_OPERATION (self));
-	seahorse_operation_mark_progress (SEAHORSE_OPERATION (self), _("Saving item..."), -1);
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	update_secret_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	closure->request = NULL;
+
+	/* Operation to get info failed */
+	if (seahorse_gkr_propagate_error (result, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		seahorse_progress_end (closure->cancellable, res);
+
+	/* Update the description */
+	} else {
+		closure->info = gnome_keyring_item_info_copy (info);
+		gnome_keyring_item_info_set_secret (closure->info, closure->secret);
+
+		closure->request = gnome_keyring_item_set_info (seahorse_gkr_item_get_keyring_name (closure->item),
+		                                                seahorse_gkr_item_get_item_id (closure->item),
+		                                                closure->info, on_update_secret_set_info_complete,
+		                                                g_object_ref (res), g_object_unref);
+	}
+
+	gnome_keyring_free_password (closure->secret);
+	closure->secret = NULL;
+}
 
-	return SEAHORSE_OPERATION (self);
+static void
+on_update_secret_cancelled (GCancellable *cancellable,
+                            gpointer user_data)
+{
+	update_secret_closure *closure = user_data;
+
+	if (closure->request)
+		gnome_keyring_cancel_request (closure->request);
 }
 
-SeahorseOperation*
-seahorse_gkr_operation_update_acl (SeahorseGkrItem *item, GList *acl)
+void
+seahorse_gkr_update_secret_async (SeahorseGkrItem *item,
+                                  const gchar *secret,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
 {
-	SeahorseGkrOperation *self;
-    
-	g_return_val_if_fail (SEAHORSE_IS_GKR_ITEM (item), NULL);
-    
-	self = g_object_new (SEAHORSE_TYPE_GKR_OPERATION, NULL);
+	GSimpleAsyncResult *res;
+	update_secret_closure *closure;
+
+	g_return_if_fail (SEAHORSE_IS_GKR_ITEM (item));
+	g_return_if_fail (secret);
+
+	res = g_simple_async_result_new (G_OBJECT (item), callback, user_data,
+	                                 seahorse_gkr_update_secret_async);
+
+	closure = g_new0 (update_secret_closure, 1);
+	closure->item = g_object_ref (item);
+	closure->secret = gnome_keyring_memory_strdup (secret);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	g_simple_async_result_set_op_res_gpointer (res, closure, update_secret_free);
+
+	seahorse_progress_prep_and_begin (cancellable, res, NULL);
+	closure->request = gnome_keyring_item_get_info (seahorse_gkr_item_get_keyring_name (item),
+	                                                seahorse_gkr_item_get_item_id (item),
+	                                                on_update_secret_get_info_complete,
+	                                                g_object_ref (res), g_object_unref);
+
+	if (cancellable)
+		closure->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                G_CALLBACK (on_update_secret_cancelled),
+		                                                closure, NULL);
+	g_object_unref (res);
+}
 
-	g_object_ref (item);
-	self->pv->object = SEAHORSE_OBJECT (item);
-    
-	/* Start actual save request */
-	g_object_ref (self);
-	self->pv->request = gnome_keyring_item_set_acl (seahorse_gkr_item_get_keyring_name (item), 
-	                                                seahorse_gkr_item_get_item_id (item), acl, 
-	                                                (GnomeKeyringOperationDoneCallback)basic_operation_done,
-	                                                self, g_object_unref);
-	g_return_val_if_fail (self->pv->request, NULL);
-    
-	seahorse_operation_mark_start (SEAHORSE_OPERATION (self));
-	seahorse_operation_mark_progress (SEAHORSE_OPERATION (self), _("Saving item..."), -1);
+gboolean
+seahorse_gkr_update_secret_finish (SeahorseGkrItem *item,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	g_return_val_if_fail (SEAHORSE_IS_GKR_ITEM (item), FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (item),
+	                      seahorse_gkr_update_secret_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
+
+typedef struct {
+	GnomeKeyringItemInfo *info;
+	gchar *description;
+	SeahorseGkrItem *item;
+	gpointer request;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+} update_description_closure;
+
+static void
+update_description_free (gpointer data)
+{
+	update_description_closure *closure = data;
+	g_free (closure->description);
+	g_object_unref (closure->item);
+	if (closure->cancellable && closure->cancelled_sig)
+		g_signal_handler_disconnect (closure->cancellable,
+		                             closure->cancelled_sig);
+	g_clear_object (&closure->cancellable);
+	gnome_keyring_item_info_free (closure->info);
+	g_assert (closure->request == NULL);
+	g_free (closure);
+}
+
+static void
+on_update_description_set_info_complete (GnomeKeyringResult result,
+                                         gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	update_description_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	closure->request = NULL;
+	seahorse_progress_end (closure->cancellable, res);
+
+	if (seahorse_gkr_propagate_error (result, &error))
+		g_simple_async_result_take_error (res, error);
+	else
+		seahorse_gkr_item_set_info (closure->item, closure->info);
+
+	g_simple_async_result_complete_in_idle (res);
+}
+
+static void
+on_update_description_get_info_complete (GnomeKeyringResult result,
+                                         GnomeKeyringItemInfo *info,
+                                         gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	update_description_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	closure->request = NULL;
+
+	/* Operation to get info failed */
+	if (seahorse_gkr_propagate_error (result, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		seahorse_progress_end (closure->cancellable, res);
+
+	/* The description hasn't changed */
+	} else if (g_str_equal (closure->description,
+	                        gnome_keyring_item_info_get_display_name (info))) {
+		g_simple_async_result_complete_in_idle (res);
+		seahorse_progress_end (closure->cancellable, res);
+
+	/* Update the description */
+	} else {
+		closure->info = gnome_keyring_item_info_copy (info);
+		gnome_keyring_item_info_set_display_name (closure->info, closure->description);
+
+		closure->request = gnome_keyring_item_set_info (seahorse_gkr_item_get_keyring_name (closure->item),
+		                                                seahorse_gkr_item_get_item_id (closure->item),
+		                                                closure->info, on_update_description_set_info_complete,
+		                                                g_object_ref (res), g_object_unref);
+	}
+}
+
+static void
+on_update_description_cancelled (GCancellable *cancellable,
+                                 gpointer user_data)
+{
+	update_description_closure *closure = user_data;
 
-	return SEAHORSE_OPERATION (self);
+	if (closure->request)
+		gnome_keyring_cancel_request (closure->request);
 }
 
+void
+seahorse_gkr_update_description_async (SeahorseGkrItem *item,
+                                       const gchar *description,
+                                       GCancellable *cancellable,
+                                       GAsyncReadyCallback callback,
+                                       gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+	update_description_closure *closure;
+
+	g_return_if_fail (SEAHORSE_IS_GKR_ITEM (item));
+	g_return_if_fail (description);
+
+	res = g_simple_async_result_new (G_OBJECT (item), callback, user_data,
+	                                 seahorse_gkr_update_description_async);
+
+	closure = g_new0 (update_description_closure, 1);
+	closure->item = g_object_ref (item);
+	closure->description = g_strdup (description);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	g_simple_async_result_set_op_res_gpointer (res, closure, update_description_free);
+
+	seahorse_progress_prep_and_begin (cancellable, res, NULL);
+	closure->request = gnome_keyring_item_get_info (seahorse_gkr_item_get_keyring_name (item),
+	                                                seahorse_gkr_item_get_item_id (item),
+	                                                on_update_description_get_info_complete,
+	                                                g_object_ref (res), g_object_unref);
+
+	if (cancellable)
+		closure->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                G_CALLBACK (on_update_description_cancelled),
+		                                                closure, NULL);
+	g_object_unref (res);
+}
+
+gboolean
+seahorse_gkr_update_description_finish (SeahorseGkrItem *item,
+                                        GAsyncResult *result,
+                                        GError **error)
+{
+	g_return_val_if_fail (SEAHORSE_IS_GKR_ITEM (item), FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (item),
+	                      seahorse_gkr_update_description_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
+
+typedef struct {
+	gpointer request;
+	GQueue *objects;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+} delete_gkr_closure;
+
+static void
+delete_gkr_free (gpointer data)
+{
+	delete_gkr_closure *closure = data;
+	g_queue_foreach (closure->objects, (GFunc)g_object_unref, NULL);
+	g_queue_free (closure->objects);
+	if (closure->cancellable && closure->cancelled_sig)
+		g_signal_handler_disconnect (closure->cancellable,
+		                             closure->cancelled_sig);
+	g_clear_object (&closure->cancellable);
+	g_assert (!closure->request);
+	g_free (closure);
+}
+
+static void            delete_gkr_one_object         (GSimpleAsyncResult *res);
+
 static void 
-delete_operation_done (GnomeKeyringResult result, SeahorseGkrOperation *self)
+on_delete_gkr_complete (GnomeKeyringResult result,
+                        gpointer user_data)
 {
-	g_assert (SEAHORSE_IS_GKR_OPERATION (self));
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	delete_gkr_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	SeahorseObject *object;
+
+	closure->request = NULL;
+	object = g_queue_pop_head (closure->objects);
+	seahorse_progress_end (closure->cancellable, object);
+
+	if (seahorse_gkr_propagate_error (result, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+
+	} else {
+		seahorse_context_remove_object (seahorse_context_instance (),
+		                                object);
+		delete_gkr_one_object (res);
+	}
+
+	g_object_unref (object);
+}
 
-	self->pv->request = NULL;
-	if (check_operation_result (self, result))
-		seahorse_context_remove_object (NULL, self->pv->object);
+static void
+on_delete_gkr_cancelled (GCancellable *cancellable,
+                         gpointer user_data)
+{
+	delete_gkr_closure *closure = user_data;
+
+	if (closure->request)
+		gnome_keyring_cancel_request (closure->request);
 }
 
-SeahorseOperation*
-seahorse_gkr_operation_delete_item (SeahorseGkrItem *item)
+static void
+delete_gkr_one_object (GSimpleAsyncResult *res)
 {
-	SeahorseGkrOperation *self;
-	    
-	g_return_val_if_fail (SEAHORSE_IS_GKR_ITEM (item), NULL);
-	    
-	self = g_object_new (SEAHORSE_TYPE_GKR_OPERATION, NULL);
-	    
-	g_object_ref (item);
-	self->pv->object = SEAHORSE_OBJECT (item);
-	    
-	/* Start actual save request */
-	g_object_ref (self);
-	self->pv->request = gnome_keyring_item_delete (seahorse_gkr_item_get_keyring_name (item), 
-	                                               seahorse_gkr_item_get_item_id (item), 
-	                                               (GnomeKeyringOperationDoneCallback)delete_operation_done,
-	                                               self, g_object_unref);
-	g_return_val_if_fail (self->pv->request, NULL);
-	
-	seahorse_operation_mark_start (SEAHORSE_OPERATION (self));
-	seahorse_operation_mark_progress (SEAHORSE_OPERATION (self), _("Deleting item..."), -1);
-	
-	return SEAHORSE_OPERATION (self);
+	delete_gkr_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseObject *object;
+	const gchar *keyring;
+	guint32 item;
+
+	if (g_queue_is_empty (closure->objects)) {
+		g_simple_async_result_complete_in_idle (res);
+		return;
+	}
+
+	g_assert (!closure->request);
+	object = g_queue_peek_head (closure->objects);
+
+	seahorse_progress_begin (closure->cancellable, object);
+	if (SEAHORSE_IS_GKR_ITEM (object)) {
+		keyring = seahorse_gkr_item_get_keyring_name (SEAHORSE_GKR_ITEM (object));
+		item = seahorse_gkr_item_get_item_id (SEAHORSE_GKR_ITEM (object));
+		closure->request = gnome_keyring_item_delete (keyring, item,
+		                                              on_delete_gkr_complete,
+		                                              g_object_ref (res), g_object_unref);
+	} else if (SEAHORSE_IS_GKR_KEYRING (object)) {
+		keyring = seahorse_gkr_keyring_get_name (SEAHORSE_GKR_KEYRING (object));
+		closure->request = gnome_keyring_delete (keyring,
+		                                         on_delete_gkr_complete,
+		                                         g_object_ref (res), g_object_unref);
+	} else {
+		g_assert_not_reached ();
+	}
 }
 
-SeahorseOperation*
-seahorse_gkr_operation_delete_keyring (SeahorseGkrKeyring *keyring)
+void
+seahorse_gkr_delete_async (GList *objects,
+                           GCancellable *cancellable,
+                           GAsyncReadyCallback callback,
+                           gpointer user_data)
 {
-	SeahorseGkrOperation *self;
-	    
-	g_return_val_if_fail (SEAHORSE_IS_GKR_KEYRING (keyring), NULL);
-	    
-	self = g_object_new (SEAHORSE_TYPE_GKR_OPERATION, NULL);
-	
-	g_object_ref (keyring);
-	self->pv->object = SEAHORSE_OBJECT (keyring);
-	    
-	/* Start actual save request */
-	g_object_ref (self);
-	self->pv->request = gnome_keyring_delete (seahorse_gkr_keyring_get_name (keyring), 
-	                                          (GnomeKeyringOperationDoneCallback)delete_operation_done,
-	                                          self, g_object_unref);
-	g_return_val_if_fail (self->pv->request, NULL);
-	
-	seahorse_operation_mark_start (SEAHORSE_OPERATION (self));
-	seahorse_operation_mark_progress (SEAHORSE_OPERATION (self), _("Deleting keyring..."), -1);
-	
-	return SEAHORSE_OPERATION (self);
+	GSimpleAsyncResult *res;
+	delete_gkr_closure *closure;
+	GList *l;
+
+	res = g_simple_async_result_new (NULL, callback, user_data,
+	                                 seahorse_gkr_delete_async);
+
+	closure = g_new0 (delete_gkr_closure, 1);
+	closure->objects = g_queue_new ();
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	g_simple_async_result_set_op_res_gpointer (res, closure, delete_gkr_free);
+
+	for (l = objects; l != NULL; l = g_list_next (l)) {
+		g_return_if_fail (SEAHORSE_IS_GKR_ITEM (l->data) || SEAHORSE_IS_GKR_KEYRING (l->data));
+		g_queue_push_tail (closure->objects, g_object_ref (l->data));
+		seahorse_progress_prep (cancellable, l->data, NULL);
+	}
+
+	delete_gkr_one_object (res);
+
+	if (cancellable)
+		closure->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                G_CALLBACK (on_delete_gkr_cancelled),
+		                                                closure, NULL);
+
+	g_object_unref (res);
+}
+
+gboolean
+seahorse_gkr_delete_finish (GAsyncResult *result,
+                            GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+	                      seahorse_gkr_delete_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
 }
diff --git a/gkr/seahorse-gkr-operation.h b/gkr/seahorse-gkr-operation.h
index 6e7cd9c..edce275 100644
--- a/gkr/seahorse-gkr-operation.h
+++ b/gkr/seahorse-gkr-operation.h
@@ -19,58 +19,42 @@
  * Boston, MA 02111-1307, USA.
  */
 
-/** 
- * SeahorseGkrOperation: Operations to be done on gnome-keyring items
- * 
- * - Derived from SeahorseOperation
- */
- 
 #ifndef __SEAHORSE_GKR_OPERATION_H__
 #define __SEAHORSE_GKR_OPERATION_H__
 
-#include "seahorse-operation.h"
 #include "seahorse-gkr-source.h"
 #include "seahorse-gkr-item.h"
 #include "seahorse-gkr-keyring.h"
 
-#define SEAHORSE_TYPE_GKR_OPERATION            (seahorse_gkr_operation_get_type ())
-#define SEAHORSE_GKR_OPERATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_GKR_OPERATION, SeahorseGkrOperation))
-#define SEAHORSE_GKR_OPERATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_GKR_OPERATION, SeahorseGkrOperationClass))
-#define SEAHORSE_IS_GKR_OPERATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_GKR_OPERATION))
-#define SEAHORSE_IS_GKR_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_GKR_OPERATION))
-#define SEAHORSE_GKR_OPERATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_GKR_OPERATION, SeahorseGkrOperationClass))
-
-typedef struct _SeahorseGkrOperation SeahorseGkrOperation;
-typedef struct _SeahorseGkrOperationClass SeahorseGkrOperationClass;
-typedef struct _SeahorseGkrOperationPrivate SeahorseGkrOperationPrivate;
-    
-struct _SeahorseGkrOperation {
-	SeahorseOperation parent;
-	SeahorseGkrOperationPrivate *pv;
-};
-
-struct _SeahorseGkrOperationClass {
-	SeahorseOperationClass parent_class;
-};
-
-GType                seahorse_gkr_operation_get_type               (void);
+gboolean      seahorse_gkr_propagate_error           (GnomeKeyringResult result,
+                                                      GError **err);
 
+void          seahorse_gkr_update_description_async  (SeahorseGkrItem *item,
+                                                      const gchar *description,
+                                                      GCancellable *cancellable,
+                                                      GAsyncReadyCallback callback,
+                                                      gpointer user_data);
 
-gboolean             seahorse_gkr_operation_parse_error       (GnomeKeyringResult result, 
-                                                               GError **err);
+gboolean      seahorse_gkr_update_description_finish (SeahorseGkrItem *item,
+                                                      GAsyncResult *result,
+                                                      GError **error);
 
-/* result: nothing */
-SeahorseOperation*   seahorse_gkr_operation_update_info       (SeahorseGkrItem *git,
-                                                               GnomeKeyringItemInfo *info);
+void          seahorse_gkr_update_secret_async       (SeahorseGkrItem *item,
+                                                      const gchar *secret,
+                                                      GCancellable *cancellable,
+                                                      GAsyncReadyCallback callback,
+                                                      gpointer user_data);
 
-/* result: nothing */
-SeahorseOperation*   seahorse_gkr_operation_update_acl        (SeahorseGkrItem *git,
-                                                               GList *acl);
+gboolean      seahorse_gkr_update_secret_finish      (SeahorseGkrItem *item,
+                                                      GAsyncResult *result,
+                                                      GError **error);
 
-/* result: nothing */
-SeahorseOperation*   seahorse_gkr_operation_delete_item       (SeahorseGkrItem *git);
+void          seahorse_gkr_delete_async              (GList *objects,
+                                                      GCancellable *cancellable,
+                                                      GAsyncReadyCallback callback,
+                                                      gpointer user_data);
 
-/* result: nothing */
-SeahorseOperation*   seahorse_gkr_operation_delete_keyring    (SeahorseGkrKeyring *git);
+gboolean      seahorse_gkr_delete_finish             (GAsyncResult *result,
+                                                      GError **error);
 
 #endif /* __SEAHORSE_GKR_OPERATION_H__ */
diff --git a/gkr/seahorse-gkr-source.c b/gkr/seahorse-gkr-source.c
index 0fa6bb6..82439ad 100644
--- a/gkr/seahorse-gkr-source.c
+++ b/gkr/seahorse-gkr-source.c
@@ -27,10 +27,10 @@
 
 #include <glib/gi18n.h>
 
-#include "seahorse-operation.h"
 #include "seahorse-util.h"
 #include "seahorse-secure-memory.h"
 #include "seahorse-passphrase.h"
+#include "seahorse-progress.h"
 
 #include "seahorse-gkr-item.h"
 #include "seahorse-gkr-keyring.h"
@@ -56,278 +56,139 @@ G_DEFINE_TYPE_EXTENDED (SeahorseGkrSource, seahorse_gkr_source, G_TYPE_OBJECT, 0
 static SeahorseGkrSource *default_source = NULL;
 
 /* -----------------------------------------------------------------------------
- * LIST OPERATION 
+ * OBJECT
  */
- 
-
-#define SEAHORSE_TYPE_LIST_OPERATION            (seahorse_list_operation_get_type ())
-#define SEAHORSE_LIST_OPERATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_LIST_OPERATION, SeahorseListOperation))
-#define SEAHORSE_LIST_OPERATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_LIST_OPERATION, SeahorseListOperationClass))
-#define SEAHORSE_IS_LIST_OPERATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_LIST_OPERATION))
-#define SEAHORSE_IS_LIST_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_LIST_OPERATION))
-#define SEAHORSE_LIST_OPERATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_LIST_OPERATION, SeahorseListOperationClass))
-
-typedef struct _SeahorseListOperation SeahorseListOperation;
-typedef struct _SeahorseListOperationClass SeahorseListOperationClass;
 
-struct _SeahorseListOperation {
-	SeahorseOperation parent;
-	SeahorseGkrSource *gsrc;
-	gpointer request;
-	SeahorseOperation *loads;
-};
 
-struct _SeahorseListOperationClass {
-	SeahorseOperationClass parent_class;
-};
-
-G_DEFINE_TYPE (SeahorseListOperation, seahorse_list_operation, SEAHORSE_TYPE_OPERATION);
-
-static void
-on_loads_complete (SeahorseOperation *op, gpointer user_data)
+static GObject* 
+seahorse_gkr_source_constructor (GType type, guint n_props, GObjectConstructParam *props)
 {
-	SeahorseListOperation *self = user_data;
-	GError *error = NULL;
-	
-	g_return_if_fail (SEAHORSE_IS_LIST_OPERATION (self));
-	g_return_if_fail (self->loads == op);
+	SeahorseGkrSource *self = SEAHORSE_GKR_SOURCE (G_OBJECT_CLASS (seahorse_gkr_source_parent_class)->constructor (type, n_props, props));
 	
-	seahorse_operation_copy_error (op, &error);
-	seahorse_operation_mark_done (SEAHORSE_OPERATION (self), 
-	                              seahorse_operation_is_cancelled (op),
-	                              error);
-}
-
-static void
-on_loads_progress (SeahorseOperation *op, const gchar *status, gdouble progress, gpointer user_data)
-{
-	SeahorseListOperation *self = user_data;
+	g_return_val_if_fail (SEAHORSE_IS_GKR_SOURCE (self), NULL);
 	
-	g_return_if_fail (SEAHORSE_IS_LIST_OPERATION (self));
-	g_return_if_fail (self->loads == op);
+	if (default_source == NULL)
+		default_source = self;
 
-	seahorse_operation_mark_progress (SEAHORSE_OPERATION (self),
-	                                  status, progress);
-}
+	return G_OBJECT (self);
 
-static void
-remove_each_keyring_from_context (const gchar *keyring_name, SeahorseObject *keyring, 
-                                  gpointer unused)
-{
-	seahorse_context_remove_object (NULL, keyring);
-	seahorse_context_remove_source (NULL, SEAHORSE_SOURCE (keyring));
 }
 
 static void
-insert_each_keyring_in_hashtable (SeahorseObject *object, gpointer user_data)
+seahorse_gkr_source_init (SeahorseGkrSource *self)
 {
-	g_hash_table_insert ((GHashTable*)user_data, 
-	                     g_strdup (seahorse_gkr_keyring_get_name (SEAHORSE_GKR_KEYRING (object))),
-	                     g_object_ref (object));
+	self->pv = NULL;
 }
 
 static void 
-on_keyring_names (GnomeKeyringResult result, GList *list, SeahorseListOperation *self)
+seahorse_gkr_source_get_property (GObject *object, guint prop_id, GValue *value, 
+                                       GParamSpec *pspec)
 {
-	SeahorseGkrKeyring *keyring;
-	SeahorseObjectPredicate pred;
-	SeahorseOperation *oper;
-	GError *err = NULL;
-	gchar *keyring_name;
-	GHashTable *checks;
-	GList *l;
-
-	if (result == GNOME_KEYRING_RESULT_CANCELLED)
-		return;
-
-	self->request = NULL;
-
-	if (!seahorse_operation_is_running (SEAHORSE_OPERATION (self)))
-		return;
-
-	if (result != GNOME_KEYRING_RESULT_OK) {
-	    
-		g_assert (result != GNOME_KEYRING_RESULT_OK);
-		g_assert (result != GNOME_KEYRING_RESULT_CANCELLED);
-	    
-		if (self->request)
-			gnome_keyring_cancel_request (self->request);
-		self->request = NULL;
-	    
-		seahorse_gkr_operation_parse_error (result, &err);
-		g_assert (err != NULL);
-		
-		seahorse_operation_mark_done (SEAHORSE_OPERATION (self), FALSE, err);
-		return;
-	}
-	
-	/* Load up a list of all the current names */
-	checks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-	seahorse_object_predicate_clear (&pred);
-	pred.source = SEAHORSE_SOURCE (self->gsrc);
-	pred.type = SEAHORSE_TYPE_GKR_KEYRING;
-	seahorse_context_for_objects_full (NULL, &pred, insert_each_keyring_in_hashtable, checks);
-
-	for (l = list; l; l = g_list_next (l)) {
-		keyring_name = l->data;
-		
-		/* Don't show the 'session' keyring */
-		if (g_str_equal (keyring_name, "session"))
-			continue;
-		
-		keyring = g_hash_table_lookup (checks, keyring_name);
-
-		/* Already have a keyring */
-		if (keyring != NULL) {
-			g_object_ref (keyring);
-			g_hash_table_remove (checks, keyring_name);
-			
-		/* Create a new keyring for this one */
-		} else {
-			keyring = seahorse_gkr_keyring_new (keyring_name);
-			g_object_set (keyring, "source", self->gsrc, NULL);
-			seahorse_context_add_source (NULL, SEAHORSE_SOURCE (keyring));
-			seahorse_context_add_object (NULL, SEAHORSE_OBJECT (keyring));
-		}
-		
-		/* Refresh the keyring as well, and track the load */
-		oper = seahorse_source_load (SEAHORSE_SOURCE (keyring));
-		seahorse_multi_operation_take (SEAHORSE_MULTI_OPERATION (self->loads), oper);
-		g_object_unref (keyring);
+	switch (prop_id) {
+	case PROP_SOURCE_TAG:
+		g_value_set_uint (value, SEAHORSE_GKR);
+		break;
+	case PROP_SOURCE_LOCATION:
+		g_value_set_enum (value, SEAHORSE_LOCATION_LOCAL);
+		break;
+	case PROP_FLAGS:
+		g_value_set_uint (value, 0);
+		break;
 	}
-	
-	g_hash_table_foreach (checks, (GHFunc)remove_each_keyring_from_context, NULL);
-	g_hash_table_destroy (checks);
-        
-	/* Watch the loads until they're done */
-	seahorse_operation_watch (self->loads, on_loads_complete, self, on_loads_progress, self);
 }
 
-static SeahorseOperation*
-start_list_operation (SeahorseGkrSource *gsrc)
+static void 
+seahorse_gkr_source_set_property (GObject *object, guint prop_id, const GValue *value, 
+                                  GParamSpec *pspec)
 {
-	SeahorseListOperation *self;
 
-	g_assert (SEAHORSE_IS_GKR_SOURCE (gsrc));
-
-	self = g_object_new (SEAHORSE_TYPE_LIST_OPERATION, NULL);
-	self->gsrc = g_object_ref (gsrc);
-    
-	seahorse_operation_mark_start (SEAHORSE_OPERATION (self));
-	seahorse_operation_mark_progress (SEAHORSE_OPERATION (self), _("Listing password keyrings"), -1);
-  
-	/* Start listing of ids */
-	g_object_ref (self);
-	self->request = gnome_keyring_list_keyring_names ((GnomeKeyringOperationGetListCallback)on_keyring_names, 
-	                                                  self, g_object_unref);
-    
-	return SEAHORSE_OPERATION (self);
 }
 
-static void 
-seahorse_list_operation_cancel (SeahorseOperation *operation)
+static void
+seahorse_gkr_source_finalize (GObject *obj)
 {
-	SeahorseListOperation *self = SEAHORSE_LIST_OPERATION (operation);    
+	SeahorseGkrSource *self = SEAHORSE_GKR_SOURCE (obj);
 
-	if (self->request)
-		gnome_keyring_cancel_request (self->request);
-	self->request = NULL;
+	if (default_source == self)
+		default_source = NULL;
 	
-	if (seahorse_operation_is_running (self->loads))
-		seahorse_operation_cancel (self->loads);
-    
-	if (seahorse_operation_is_running (operation))
-		seahorse_operation_mark_done (operation, TRUE, NULL);
-}
-
-static void 
-seahorse_list_operation_init (SeahorseListOperation *self)
-{
-	/* Everything already set to zero */
-	self->loads = SEAHORSE_OPERATION (seahorse_multi_operation_new ());
+	G_OBJECT_CLASS (seahorse_gkr_source_parent_class)->finalize (obj);
 }
 
-static void 
-seahorse_list_operation_dispose (GObject *gobject)
+static void
+seahorse_gkr_source_class_init (SeahorseGkrSourceClass *klass)
 {
-	SeahorseListOperation *self = SEAHORSE_LIST_OPERATION (gobject);
-    
-	/* Cancel it if it's still running */
-	if (seahorse_operation_is_running (SEAHORSE_OPERATION (self)))
-		seahorse_list_operation_cancel (SEAHORSE_OPERATION (self));
-	g_assert (!seahorse_operation_is_running (SEAHORSE_OPERATION (self)));
+	GObjectClass *gobject_class;
     
-	/* The above cancel should have stopped these */
-	g_assert (self->request == NULL);
-	g_return_if_fail (!seahorse_operation_is_running (self->loads));
-	
-	if (self->gsrc)
-		g_object_unref (self->gsrc);
-	self->gsrc = NULL;
-
-	G_OBJECT_CLASS (seahorse_list_operation_parent_class)->dispose (gobject);  
-}
+	seahorse_gkr_source_parent_class = g_type_class_peek_parent (klass);
 
-static void 
-seahorse_list_operation_finalize (GObject *gobject)
-{
-	SeahorseListOperation *self = SEAHORSE_LIST_OPERATION (gobject);
-	g_assert (!seahorse_operation_is_running (SEAHORSE_OPERATION (self)));
+	gobject_class = G_OBJECT_CLASS (klass);
+	gobject_class->constructor = seahorse_gkr_source_constructor;
+	gobject_class->set_property = seahorse_gkr_source_set_property;
+	gobject_class->get_property = seahorse_gkr_source_get_property;
+	gobject_class->finalize = seahorse_gkr_source_finalize;
     
-	/* The above cancel should have stopped this */
-	g_assert (self->request == NULL);
-	
-	g_object_unref (self->loads);
-	self->loads = NULL;
+	g_object_class_install_property (gobject_class, PROP_FLAGS,
+	         g_param_spec_uint ("flags", "Flags", "Object Source flags.", 
+	                            0, G_MAXUINT, 0, G_PARAM_READABLE));
 
-	G_OBJECT_CLASS (seahorse_list_operation_parent_class)->finalize (gobject);
+	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
+	g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
+    
+	seahorse_registry_register_type (NULL, SEAHORSE_TYPE_GKR_SOURCE, "source", "local", SEAHORSE_GKR_STR, NULL);
 }
 
+typedef struct {
+	SeahorseGkrSource *source;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+	gpointer request;
+	gint num_loads;
+} source_load_closure;
+
 static void
-seahorse_list_operation_class_init (SeahorseListOperationClass *klass)
+source_load_free (gpointer data)
 {
-	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-	SeahorseOperationClass *operation_class = SEAHORSE_OPERATION_CLASS (klass);
-	
-	seahorse_list_operation_parent_class = g_type_class_peek_parent (klass);
-	gobject_class->dispose = seahorse_list_operation_dispose;
-	gobject_class->finalize = seahorse_list_operation_finalize;
-	operation_class->cancel = seahorse_list_operation_cancel;   
+	source_load_closure *closure = data;
+	g_assert (closure->request == NULL);
+	g_assert (closure->num_loads == 0);
+	if (closure->cancellable && closure->cancelled_sig)
+		g_signal_handler_disconnect (closure->cancellable,
+		                             closure->cancelled_sig);
+	g_clear_object (&closure->cancellable);
+	g_clear_object (&closure->source);
+	g_free (closure);
 }
 
-/* -----------------------------------------------------------------------------
- * INTERNAL
- */
-
 static void
 update_each_default_keyring (SeahorseObject *object, gpointer user_data)
 {
 	const gchar *default_name = user_data;
-	const gchar *keyring_name; 
+	const gchar *keyring_name;
 	gboolean is_default;
-	
+
 	keyring_name = seahorse_gkr_keyring_get_name (SEAHORSE_GKR_KEYRING (object));
 	g_return_if_fail (keyring_name);
-	
+
 	/* Remember default keyring could be null in strange circumstances */
 	is_default = default_name && g_str_equal (keyring_name, default_name);
 	g_object_set (object, "is-default", is_default, NULL);
 }
 
 static void
-on_get_default_keyring (GnomeKeyringResult result, const gchar *default_name, gpointer user_data)
+on_source_load_default_keyring (GnomeKeyringResult result,
+                                const gchar *default_name,
+                                gpointer user_data)
 {
-	SeahorseGkrSource *self = user_data;
+	SeahorseGkrSource *self = SEAHORSE_GKR_SOURCE (user_data);
 	SeahorseObjectPredicate pred;
-	
-	g_return_if_fail (SEAHORSE_IS_GKR_SOURCE (self));
 
 	if (result != GNOME_KEYRING_RESULT_OK) {
 		if (result != GNOME_KEYRING_RESULT_CANCELLED)
 			g_warning ("couldn't get default keyring name: %s", gnome_keyring_result_to_message (result));
 		return;
 	}
-	
+
 	seahorse_object_predicate_clear (&pred);
 	pred.source = SEAHORSE_SOURCE (self);
 	pred.type = SEAHORSE_TYPE_GKR_KEYRING;
@@ -335,115 +196,171 @@ on_get_default_keyring (GnomeKeyringResult result, const gchar *default_name, gp
 }
 
 static void
-on_list_operation_done (SeahorseOperation *op, gpointer userdata)
+on_source_load_keyring_complete (GObject *source,
+                                 GAsyncResult *result,
+                                 gpointer user_data)
 {
-	SeahorseGkrSource *self = userdata;
-	g_return_if_fail (SEAHORSE_IS_GKR_SOURCE (self));
-	
-	gnome_keyring_get_default_keyring (on_get_default_keyring, g_object_ref (self), g_object_unref);
-}
-
-/* -----------------------------------------------------------------------------
- * OBJECT
- */
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_load_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
 
+	g_assert (closure->num_loads > 0);
+	closure->num_loads--;
+	seahorse_progress_end (closure->cancellable, source);
 
-static GObject* 
-seahorse_gkr_source_constructor (GType type, guint n_props, GObjectConstructParam *props)
-{
-	SeahorseGkrSource *self = SEAHORSE_GKR_SOURCE (G_OBJECT_CLASS (seahorse_gkr_source_parent_class)->constructor (type, n_props, props));
-	
-	g_return_val_if_fail (SEAHORSE_IS_GKR_SOURCE (self), NULL);
-	
-	if (default_source == NULL)
-		default_source = self;
+	if (!seahorse_source_load_finish (SEAHORSE_SOURCE (source), result, &error))
+		g_simple_async_result_take_error (res, error);
 
-	return G_OBJECT (self);
+	if (closure->num_loads == 0)
+		g_simple_async_result_complete (res);
 
+	g_object_unref (res);
 }
 
 static void
-seahorse_gkr_source_init (SeahorseGkrSource *self)
+remove_each_keyring_from_context (const gchar *keyring_name, SeahorseObject *keyring,
+                                  gpointer unused)
 {
-	self->pv = NULL;
+	seahorse_context_remove_object (NULL, keyring);
+	seahorse_context_remove_source (NULL, SEAHORSE_SOURCE (keyring));
 }
 
-static void 
-seahorse_gkr_source_get_property (GObject *object, guint prop_id, GValue *value, 
-                                       GParamSpec *pspec)
+static void
+insert_each_keyring_in_hashtable (SeahorseObject *object, gpointer user_data)
 {
-	switch (prop_id) {
-	case PROP_SOURCE_TAG:
-		g_value_set_uint (value, SEAHORSE_GKR);
-		break;
-	case PROP_SOURCE_LOCATION:
-		g_value_set_enum (value, SEAHORSE_LOCATION_LOCAL);
-		break;
-	case PROP_FLAGS:
-		g_value_set_uint (value, 0);
-		break;
-	}
+	g_hash_table_insert ((GHashTable*)user_data,
+	                     g_strdup (seahorse_gkr_keyring_get_name (SEAHORSE_GKR_KEYRING (object))),
+	                     g_object_ref (object));
 }
 
-static void 
-seahorse_gkr_source_set_property (GObject *object, guint prop_id, const GValue *value, 
-                                  GParamSpec *pspec)
+static void
+on_source_load_list_keyring_names_complete (GnomeKeyringResult result,
+                                            GList *list,
+                                            gpointer user_data)
 {
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_load_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseGkrKeyring *keyring;
+	SeahorseObjectPredicate pred;
+	GError *error = NULL;
+	gchar *keyring_name;
+	GHashTable *checks;
+	GList *l;
+
+	closure->request = NULL;
+
+	if (seahorse_gkr_propagate_error (result, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		return;
+	}
 
+	/* Load up a list of all the current names */
+	checks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+	seahorse_object_predicate_clear (&pred);
+	pred.source = SEAHORSE_SOURCE (closure->source);
+	pred.type = SEAHORSE_TYPE_GKR_KEYRING;
+	seahorse_context_for_objects_full (NULL, &pred, insert_each_keyring_in_hashtable, checks);
+
+	for (l = list; l; l = g_list_next (l)) {
+		keyring_name = l->data;
+
+		/* Don't show the 'session' keyring */
+		if (g_str_equal (keyring_name, "session"))
+			continue;
+
+		keyring = g_hash_table_lookup (checks, keyring_name);
+
+		/* Already have a keyring */
+		if (keyring != NULL) {
+			g_object_ref (keyring);
+			g_hash_table_remove (checks, keyring_name);
+
+		/* Create a new keyring for this one */
+		} else {
+			keyring = seahorse_gkr_keyring_new (keyring_name);
+			g_object_set (keyring, "source", closure->source, NULL);
+			seahorse_context_add_source (NULL, SEAHORSE_SOURCE (keyring));
+			seahorse_context_add_object (NULL, SEAHORSE_OBJECT (keyring));
+		}
+
+		/* Refresh the keyring as well, and track the load */
+		seahorse_source_load_async (SEAHORSE_SOURCE (keyring), closure->cancellable,
+		                            on_source_load_keyring_complete, g_object_ref (res));
+		seahorse_progress_prep_and_begin (closure->cancellable, keyring, NULL);
+		closure->num_loads++;
+		g_object_unref (keyring);
+	}
+
+	g_hash_table_foreach (checks, (GHFunc)remove_each_keyring_from_context, NULL);
+	g_hash_table_destroy (checks);
+
+	if (list == NULL)
+		g_simple_async_result_complete_in_idle (res);
+
+	/* Get the default keyring in the background */
+	gnome_keyring_get_default_keyring (on_source_load_default_keyring,
+	                                   g_object_ref (closure->source),
+	                                   g_object_unref);
 }
 
 static void
-seahorse_gkr_source_finalize (GObject *obj)
+on_source_load_cancelled (GCancellable *cancellable,
+                          gpointer user_data)
 {
-	SeahorseGkrSource *self = SEAHORSE_GKR_SOURCE (obj);
+	source_load_closure *closure = user_data;
 
-	if (default_source == self)
-		default_source = NULL;
-	
-	G_OBJECT_CLASS (seahorse_gkr_source_parent_class)->finalize (obj);
+	if (closure->request)
+		gnome_keyring_cancel_request (closure->request);
 }
 
 static void
-seahorse_gkr_source_class_init (SeahorseGkrSourceClass *klass)
+seahorse_gkr_source_load_async (SeahorseSource *source,
+                                GCancellable *cancellable,
+                                GAsyncReadyCallback callback,
+                                gpointer user_data)
 {
-	GObjectClass *gobject_class;
-    
-	seahorse_gkr_source_parent_class = g_type_class_peek_parent (klass);
-
-	gobject_class = G_OBJECT_CLASS (klass);
-	gobject_class->constructor = seahorse_gkr_source_constructor;
-	gobject_class->set_property = seahorse_gkr_source_set_property;
-	gobject_class->get_property = seahorse_gkr_source_get_property;
-	gobject_class->finalize = seahorse_gkr_source_finalize;
-    
-	g_object_class_install_property (gobject_class, PROP_FLAGS,
-	         g_param_spec_uint ("flags", "Flags", "Object Source flags.", 
-	                            0, G_MAXUINT, 0, G_PARAM_READABLE));
-
-	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
-	g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
-    
-	seahorse_registry_register_type (NULL, SEAHORSE_TYPE_GKR_SOURCE, "source", "local", SEAHORSE_GKR_STR, NULL);
+	SeahorseGkrSource *self = SEAHORSE_GKR_SOURCE (source);
+	source_load_closure *closure;
+	GSimpleAsyncResult *res;
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_gkr_source_load_async);
+	closure = g_new0 (source_load_closure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->source = g_object_ref (self);
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_load_free);
+
+	closure->request = gnome_keyring_list_keyring_names (on_source_load_list_keyring_names_complete,
+	                                                     g_object_ref (res), g_object_unref);
+
+	if (cancellable)
+		closure->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                G_CALLBACK (on_source_load_cancelled),
+		                                                closure, NULL);
+
+	g_object_unref (res);
 }
 
-static SeahorseOperation*
-seahorse_gkr_source_load (SeahorseSource *src)
+static gboolean
+seahorse_gkr_source_load_finish (SeahorseSource *source,
+                                 GAsyncResult *result,
+                                 GError **error)
 {
-	SeahorseGkrSource *self = SEAHORSE_GKR_SOURCE (src);
-	SeahorseOperation *op = start_list_operation (self);
-	
-	g_return_val_if_fail (op, NULL);
-	
-	/* Hook into the results of the above operation, and look for default */
-	seahorse_operation_watch (op, on_list_operation_done, src, NULL, NULL);
-	
-	return op;
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_gkr_source_load_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
 }
 
 static void 
 seahorse_source_iface (SeahorseSourceIface *iface)
 {
-	iface->load = seahorse_gkr_source_load;
+	iface->load_async = seahorse_gkr_source_load_async;
+	iface->load_finish = seahorse_gkr_source_load_finish;
 }
 
 /* -------------------------------------------------------------------------- 
diff --git a/libseahorse/Makefile.am b/libseahorse/Makefile.am
index d3c2206..988aa32 100644
--- a/libseahorse/Makefile.am
+++ b/libseahorse/Makefile.am
@@ -37,7 +37,6 @@ libseahorse_la_SOURCES = \
 	seahorse-object.c seahorse-object.h \
 	seahorse-object-model.c seahorse-object-model.h \
 	seahorse-object-widget.c seahorse-object-widget.h \
-	seahorse-operation.c seahorse-operation.h \
 	seahorse-passphrase.c seahorse-passphrase.h \
 	seahorse-prefs.c seahorse-prefs.h \
 	seahorse-progress.c seahorse-progress.h \
@@ -46,7 +45,7 @@ libseahorse_la_SOURCES = \
 	seahorse-set.c seahorse-set.h \
 	seahorse-set-model.c seahorse-set-model.h \
 	seahorse-source.c seahorse-source.h \
-	seahorse-transfer-operation.c seahorse-transfer-operation.h \
+	seahorse-transfer.c seahorse-transfer.h \
 	seahorse-types.c seahorse-types.h \
 	seahorse-unix-signal.c seahorse-unix-signal.h \
 	seahorse-unknown.c seahorse-unknown.h \
diff --git a/libseahorse/seahorse-commands.c b/libseahorse/seahorse-commands.c
index 9904b04..e4fc034 100644
--- a/libseahorse/seahorse-commands.c
+++ b/libseahorse/seahorse-commands.c
@@ -52,12 +52,12 @@ seahorse_commands_real_show_properties (SeahorseCommands* self, SeahorseObject*
 	return;
 }
 
-static SeahorseOperation* 
-seahorse_commands_real_delete_objects (SeahorseCommands* self, GList* obj) 
+static gboolean
+seahorse_commands_real_delete_objects (SeahorseCommands* self, GList* obj)
 {
-	g_critical ("Type `%s' does not implement abstract method `seahorse_commands_delete_objects'", 
+	g_critical ("Type `%s' does not implement abstract method `seahorse_commands_delete_objects'",
 	            g_type_name (G_TYPE_FROM_INSTANCE (self)));
-	return NULL;
+	return FALSE;
 }
 
 static void
@@ -135,10 +135,10 @@ seahorse_commands_class_init (SeahorseCommandsClass *klass)
 	gobject_class->finalize = seahorse_commands_finalize;
 	gobject_class->set_property = seahorse_commands_set_property;
 	gobject_class->get_property = seahorse_commands_get_property;
-    
+
 	SEAHORSE_COMMANDS_CLASS (klass)->show_properties = seahorse_commands_real_show_properties;
 	SEAHORSE_COMMANDS_CLASS (klass)->delete_objects = seahorse_commands_real_delete_objects;
-	
+
 	g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VIEW, 
 	         g_param_spec_object ("view", "view", "view", SEAHORSE_TYPE_VIEW, 
 	                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
@@ -167,11 +167,13 @@ seahorse_commands_show_properties (SeahorseCommands* self, SeahorseObject* obj)
 	SEAHORSE_COMMANDS_GET_CLASS (self)->show_properties (self, obj);
 }
 
-SeahorseOperation* 
-seahorse_commands_delete_objects (SeahorseCommands* self, GList* obj) 
+gboolean
+seahorse_commands_delete_objects (SeahorseCommands *self,
+                                  GList *objects)
 {
-	g_return_val_if_fail (SEAHORSE_IS_COMMANDS (self), NULL);
-	return SEAHORSE_COMMANDS_GET_CLASS (self)->delete_objects (self, obj);
+	g_return_val_if_fail (SEAHORSE_IS_COMMANDS (self), FALSE);
+	g_return_val_if_fail (SEAHORSE_COMMANDS_GET_CLASS (self)->delete_objects, FALSE);
+	return SEAHORSE_COMMANDS_GET_CLASS (self)->delete_objects (self, objects);
 }
 
 SeahorseView*
diff --git a/libseahorse/seahorse-commands.h b/libseahorse/seahorse-commands.h
index 21db0c8..9679cdf 100644
--- a/libseahorse/seahorse-commands.h
+++ b/libseahorse/seahorse-commands.h
@@ -25,7 +25,6 @@
 #include <glib.h>
 #include <glib-object.h>
 
-#include "seahorse-operation.h"
 #include "seahorse-object.h"
 #include "seahorse-view.h"
 
@@ -49,16 +48,19 @@ struct _SeahorseCommandsClass {
 	
 	/* Virtual methods */
 	
-	void                 (*show_properties)      (SeahorseCommands *self, SeahorseObject *obj);
-	
-	SeahorseOperation *  (*delete_objects)       (SeahorseCommands *self, GList *obj);
+	void        (*show_properties)         (SeahorseCommands *self,
+	                                        SeahorseObject *obj);
+
+	gboolean    (*delete_objects)          (SeahorseCommands *self,
+	                                        GList *obj);
 };
 
 GType                 seahorse_commands_get_type                 (void);
 
 void                  seahorse_commands_show_properties          (SeahorseCommands *self, SeahorseObject *obj);
 
-SeahorseOperation *   seahorse_commands_delete_objects           (SeahorseCommands *self, GList *obj);
+gboolean              seahorse_commands_delete_objects           (SeahorseCommands *self,
+                                                                  GList *obj);
 
 SeahorseView *        seahorse_commands_get_view                 (SeahorseCommands *self);
 
diff --git a/libseahorse/seahorse-context.c b/libseahorse/seahorse-context.c
index 950d791..9ba3591 100644
--- a/libseahorse/seahorse-context.c
+++ b/libseahorse/seahorse-context.c
@@ -29,8 +29,9 @@
 #include "seahorse-context.h"
 #include "seahorse-dns-sd.h"
 #include "seahorse-marshal.h"
+#include "seahorse-progress.h"
 #include "seahorse-servers.h"
-#include "seahorse-transfer-operation.h"
+#include "seahorse-transfer.h"
 #include "seahorse-unknown.h"
 #include "seahorse-unknown-source.h"
 #include "seahorse-util.h"
@@ -56,7 +57,6 @@ enum {
     ADDED,
     REMOVED,
     CHANGED,
-    REFRESHING,
     DESTROY,
     LAST_SIGNAL
 };
@@ -81,7 +81,6 @@ struct _SeahorseContextPrivate {
     GHashTable *auto_sources;               /* Automatically added sources (keyservers) */
     GHashTable *objects_by_source;          /* See explanation above */
     GHashTable *objects_by_type;            /* See explanation above */
-    SeahorseMultiOperation *refresh_ops;    /* Operations for refreshes going on */
     SeahorseServiceDiscovery *discovery;    /* Adds sources from DNS-SD */
     gboolean in_destruction;                /* In destroy signal */
     GSettings *seahorse_settings;
@@ -185,7 +184,6 @@ seahorse_context_constructed (GObject *obj)
 * klass: The class to initialise
 *
 * Inits the #SeahorseContextClass. Adds the signals "added", "removed", "changed"
-* and "refreshing"
 **/
 static void
 seahorse_context_class_init (SeahorseContextClass *klass)
@@ -208,9 +206,6 @@ seahorse_context_class_init (SeahorseContextClass *klass)
     signals[CHANGED] = g_signal_new ("changed", SEAHORSE_TYPE_CONTEXT, 
                 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (SeahorseContextClass, changed),
                 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, SEAHORSE_TYPE_OBJECT);    
-    signals[REFRESHING] = g_signal_new ("refreshing", SEAHORSE_TYPE_CONTEXT, 
-                G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (SeahorseContextClass, refreshing),
-                NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, SEAHORSE_TYPE_OPERATION);    
     signals[DESTROY] = g_signal_new ("destroy", SEAHORSE_TYPE_CONTEXT,
                 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (SeahorseContextClass, destroy),
                 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
@@ -302,10 +297,6 @@ seahorse_context_dispose (GObject *gobject)
         g_object_unref (SEAHORSE_SOURCE (l->data));
     g_list_free (sctx->pv->sources);
     sctx->pv->sources = NULL;
-    
-    if (sctx->pv->refresh_ops)
-	    g_object_unref (sctx->pv->refresh_ops);
-    sctx->pv->refresh_ops = NULL;
 
 	if (!sctx->pv->in_destruction) {
 		sctx->pv->in_destruction = TRUE;
@@ -338,7 +329,6 @@ seahorse_context_finalize (GObject *gobject)
     g_assert (sctx->pv->sources == NULL);
     g_assert (sctx->pv->auto_sources == NULL);
     g_assert (sctx->pv->discovery == NULL);
-    g_assert (sctx->pv->refresh_ops == NULL);
     g_free (sctx->pv);
     
     G_OBJECT_CLASS (seahorse_context_parent_class)->finalize (gobject);
@@ -1128,363 +1118,493 @@ seahorse_context_get_discovery (SeahorseContext *sctx)
     return sctx->pv->discovery;
 }
 
+static void
+on_source_refresh_load_ready (GObject *object, GAsyncResult *result, gpointer user_data)
+{
+	GError *error = NULL;
+
+	if (!seahorse_source_load_finish (SEAHORSE_SOURCE (object), result, &error)) {
+		g_message ("failed to refresh: %s", error->message);
+		g_clear_error (&error);
+	}
+}
+
 /**
  * seahorse_context_refresh_auto:
  * @sctx: A #SeahorseContext (can be NULL)
  *
- * Starts a new refresh operation and emits the "refreshing" signal
+ * Starts a new refresh operation
  *
  */
 void
 seahorse_context_refresh_auto (SeahorseContext *sctx)
 {
 	SeahorseSource *ks;
-	SeahorseOperation *op = NULL;
 	GList *l;
 
 	if (!sctx)
 		sctx = seahorse_context_instance ();
 	g_return_if_fail (SEAHORSE_IS_CONTEXT (sctx));
-	
-	if (!sctx->pv->refresh_ops)
-		sctx->pv->refresh_ops = seahorse_multi_operation_new ();
 
 	for (l = sctx->pv->sources; l; l = g_list_next (l)) {
 		ks = SEAHORSE_SOURCE (l->data);
-        
-		if (seahorse_source_get_location (ks) == SEAHORSE_LOCATION_LOCAL) {
-
-			op = seahorse_source_load (ks);
-			g_return_if_fail (op);
-			seahorse_multi_operation_take (sctx->pv->refresh_ops, op);
-		}
-		
+		if (seahorse_source_get_location (ks) == SEAHORSE_LOCATION_LOCAL)
+			seahorse_source_load_async (ks, NULL,
+			                            on_source_refresh_load_ready, NULL);
 	}
-	
-	g_signal_emit (sctx, signals[REFRESHING], 0, sctx->pv->refresh_ops);
 }
 
-/**
- * seahorse_context_search_remote:
- * @sctx: A #SeahorseContext (can be NULL)
- * @search: a keyword (name, email address...) to search for
- *
- * Searches for the key matching @search o the remote servers
- *
- * Returns: The created search operation
- */
-SeahorseOperation*  
-seahorse_context_search_remote (SeahorseContext *sctx, const gchar *search)
+typedef struct {
+	GCancellable *cancellable;
+	gint num_searches;
+	GList *objects;
+} seahorse_context_search_remote_closure;
+
+static void
+seahorse_context_search_remote_free (gpointer user_data)
 {
-    SeahorseSource *ks;
-    SeahorseMultiOperation *mop = NULL;
-    SeahorseOperation *op = NULL;
-    gchar **names;
-    GHashTable *servers = NULL;
-    gchar *uri;
-    GList *l;
-    guint i;
+	seahorse_context_search_remote_closure *closure = user_data;
+	g_clear_object (&closure->cancellable);
+	g_list_free (closure->objects);
+	g_free (closure);
+}
 
-    if (!sctx)
-        sctx = seahorse_context_instance ();
-    g_return_val_if_fail (SEAHORSE_IS_CONTEXT (sctx), NULL);
+static void
+on_source_search_ready (GObject *source,
+                        GAsyncResult *result,
+                        gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	seahorse_context_search_remote_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	GList *objects;
+
+	g_return_if_fail (closure->num_searches > 0);
+
+	objects = seahorse_source_search_finish (SEAHORSE_SOURCE (source), result, &error);
+	closure->objects = g_list_concat (closure->objects, objects);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (res, error);
+
+	closure->num_searches--;
+	seahorse_progress_end (closure->cancellable, GINT_TO_POINTER (closure->num_searches));
+
+	if (closure->num_searches == 0)
+		g_simple_async_result_complete (res);
+
+	g_object_unref (user_data);
+}
+
+void
+seahorse_context_search_remote_async (SeahorseContext *self,
+                                      const gchar *search,
+                                      GCancellable *cancellable,
+                                      GAsyncReadyCallback callback,
+                                      gpointer user_data)
+{
+	seahorse_context_search_remote_closure *closure;
+	GSimpleAsyncResult *res;
+	SeahorseSource *source;
+	GHashTable *servers = NULL;
+	gchar **names;
+	gchar *uri;
+	GList *l;
+	guint i;
+
+	if (self == NULL)
+		self = seahorse_context_instance ();
+
+	g_return_if_fail (SEAHORSE_IS_CONTEXT (self));
 
 	/* Get a list of all selected key servers */
-	names = g_settings_get_strv (sctx->pv->seahorse_settings, "last-search-servers");
-	if (names != NULL) {
+	names = g_settings_get_strv (self->pv->seahorse_settings, "last-search-servers");
+	if (names != NULL && names[0] != NULL) {
 		servers = g_hash_table_new (g_str_hash, g_str_equal);
 		for (i = 0; names[i] != NULL; i++)
 			g_hash_table_insert (servers, names[i], GINT_TO_POINTER (TRUE));
 		g_strfreev (names);
 	}
 
-    for (l = sctx->pv->sources; l; l = g_list_next (l)) {
-        ks = SEAHORSE_SOURCE (l->data);
-        
-        if (seahorse_source_get_location (ks) != SEAHORSE_LOCATION_REMOTE)
-            continue;
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_context_search_remote_async);
+	closure = g_new0 (seahorse_context_search_remote_closure, 1);
+	g_simple_async_result_set_op_res_gpointer (res, closure,
+	                                           seahorse_context_search_remote_free);
+	if (cancellable)
+		closure->cancellable = g_object_ref (cancellable);
+
+	for (l = self->pv->sources; l; l = g_list_next (l)) {
+		source = SEAHORSE_SOURCE (l->data);
+
+		if (seahorse_source_get_location (source) != SEAHORSE_LOCATION_REMOTE)
+			continue;
+
+		if (servers) {
+			g_object_get (source, "uri", &uri, NULL);
+			if (!g_hash_table_lookup (servers, uri)) {
+				g_free (uri);
+				continue;
+			}
+			g_free (uri);
+		}
 
-        if (servers) {
-            g_object_get (ks, "uri", &uri, NULL);
-            if (!g_hash_table_lookup (servers, uri)) {
-                g_free (uri);
-                continue;
-            }
-            
-            g_free (uri);
-        }
+		seahorse_progress_prep_and_begin (closure->cancellable, GINT_TO_POINTER (closure->num_searches), NULL);
+		seahorse_source_search_async (source, search, closure->cancellable,
+		                              on_source_search_ready, g_object_ref (res));
+		closure->num_searches++;
+	}
 
-        if (mop == NULL && op != NULL) {
-            mop = seahorse_multi_operation_new ();
-            seahorse_multi_operation_take (mop, op);
-        }
-            
-        op = seahorse_source_search (ks, search);
-            
-        if (mop != NULL)
-            seahorse_multi_operation_take (mop, op);
-    }   
+	if (closure->num_searches == 0)
+		g_simple_async_result_complete_in_idle (res);
 
-    return mop ? SEAHORSE_OPERATION (mop) : op;  
+	g_object_unref (res);
 }
 
-/**
- * seahorse_context_transfer_objects:
- * @sctx: The #SeahorseContext (can be NULL)
- * @objects: the objects to import
- * @to: a source to import to (can be NULL)
- *
- *
- *
- * Returns: A transfer operation
- */
-SeahorseOperation*
-seahorse_context_transfer_objects (SeahorseContext *sctx, GList *objects, 
-                                   SeahorseSource *to)
+GList *
+seahorse_context_search_remote_finish (SeahorseContext *self,
+                                       GAsyncResult *result,
+                                       GError **error)
 {
-    SeahorseSource *from;
-    SeahorseOperation *op = NULL;
-    SeahorseMultiOperation *mop = NULL;
-    SeahorseObject *sobj;
-    GList *ids = NULL;
-    GList *next, *l;
-    GQuark ktype;
+	seahorse_context_search_remote_closure *closure;
+	GSimpleAsyncResult *res;
+	GList *results;
 
-    if (!sctx)
-        sctx = seahorse_context_instance ();
-    g_return_val_if_fail (SEAHORSE_IS_CONTEXT (sctx), NULL);
+	if (self == NULL)
+		self = seahorse_context_instance ();
+	g_return_val_if_fail (SEAHORSE_IS_CONTEXT (self), NULL);
 
-    objects = g_list_copy (objects);
-    
-    /* Sort by key source */
-    objects = seahorse_util_objects_sort (objects);
-    
-    while (objects) {
-        
-        /* break off one set (same keysource) */
-        next = seahorse_util_objects_splice (objects);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	                      seahorse_context_search_remote_async), NULL);
 
-        g_assert (SEAHORSE_IS_OBJECT (objects->data));
-        sobj = SEAHORSE_OBJECT (objects->data);
+	res = G_SIMPLE_ASYNC_RESULT (result);
 
-        /* Export from this key source */
-        from = seahorse_object_get_source (sobj);
-        g_return_val_if_fail (from != NULL, FALSE);
-        ktype = seahorse_source_get_tag (from);
-        
-        /* Find a local keysource to import to */
-        if (!to) {
-            to = seahorse_context_find_source (sctx, ktype, SEAHORSE_LOCATION_LOCAL);
-            if (!to) {
-                /* TODO: How can we warn caller about this. Do we need to? */
-                g_warning ("couldn't find a local source for: %s", 
-                           g_quark_to_string (ktype));
-            }
-        }
-        
-        /* Make sure it's the same type */
-        if (ktype != seahorse_source_get_tag (to)) {
-            /* TODO: How can we warn caller about this. Do we need to? */
-            g_warning ("destination is not of type: %s", 
-                       g_quark_to_string (ktype));
-        }
-        
-        if (to != NULL && from != to) {
-            
-            if (op != NULL) {
-                if (mop == NULL)
-                    mop = seahorse_multi_operation_new ();
-                seahorse_multi_operation_take (mop, op);
-            }
-            
-            /* Build id list */
-            for (l = objects; l; l = g_list_next (l)) 
-                ids = g_list_prepend (ids, GUINT_TO_POINTER (seahorse_object_get_id (l->data)));
-            ids = g_list_reverse (ids);
-        
-            /* Start a new transfer operation between the two sources */
-            op = seahorse_transfer_operation_new (NULL, from, to, ids);
-            g_return_val_if_fail (op != NULL, FALSE);
-            
-            g_list_free (ids);
-            ids = NULL;
-        }
+	if (g_simple_async_result_propagate_error (res, error))
+		return NULL;
 
-        g_list_free (objects);
-        objects = next;
-    } 
-    
-    /* No objects done, just return success */
-    if (!mop && !op) {
-        g_warning ("no valid objects to transfer found");
-        return seahorse_operation_new_complete (NULL);
-    }
-    
-    return mop ? SEAHORSE_OPERATION (mop) : op;
+	closure = g_simple_async_result_get_op_res_gpointer (res);
+	results = closure->objects;
+	closure->objects = NULL;
+
+	return results;
 }
 
-/**
- * seahorse_context_retrieve_objects:
- * @sctx: A #SeahorsecContext
- * @ktype: The type of the keys to transfer
- * @ids: The key ids to transfer
- * @to: A #SeahorseSource. If NULL, it will use @ktype to find a source
- *
- * Copies remote objects to a local source
- *
- * Returns: A #SeahorseOperation
- */
-SeahorseOperation*
-seahorse_context_retrieve_objects (SeahorseContext *sctx, GQuark ktype, 
-                                   GList *ids, SeahorseSource *to)
+typedef struct {
+	GCancellable *cancellable;
+	gint num_transfers;
+} seahorse_context_transfer_closure;
+
+static void
+seahorse_context_transfer_free (gpointer user_data)
 {
-    SeahorseMultiOperation *mop = NULL;
-    SeahorseOperation *op = NULL;
-    SeahorseSource *sksrc;
-    GList *sources, *l;
-    
-    if (!sctx)
-        sctx = seahorse_context_instance ();
-    g_return_val_if_fail (SEAHORSE_IS_CONTEXT (sctx), NULL);
+	seahorse_context_search_remote_closure *closure = user_data;
+	g_clear_object (&closure->cancellable);
+	g_free (closure);
+}
 
-    if (!to) {
-        to = seahorse_context_find_source (sctx, ktype, SEAHORSE_LOCATION_LOCAL);
-        if (!to) {
-            /* TODO: How can we warn caller about this. Do we need to? */
-            g_warning ("couldn't find a local source for: %s", 
-                       g_quark_to_string (ktype));
-            return seahorse_operation_new_complete (NULL);
-        }
-    }
-    
-    sources = seahorse_context_find_sources (sctx, ktype, SEAHORSE_LOCATION_REMOTE);
-    if (!sources) {
-        g_warning ("no sources found for type: %s", g_quark_to_string (ktype));
-        return seahorse_operation_new_complete (NULL);
-    }
+static void
+on_source_transfer_ready (GObject *source,
+                          GAsyncResult *result,
+                          gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	seahorse_context_transfer_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
 
-    for (l = sources; l; l = g_list_next (l)) {
-        
-        sksrc = SEAHORSE_SOURCE (l->data);
-        g_return_val_if_fail (SEAHORSE_IS_SOURCE (sksrc), NULL);
-        
-        if (op != NULL) {
-            if (mop == NULL)
-                mop = seahorse_multi_operation_new ();
-            seahorse_multi_operation_take (mop, op);
-        }
-        
-        /* Start a new transfer operation between the two key sources */
-        op = seahorse_transfer_operation_new (NULL, sksrc, to, ids);
-        g_return_val_if_fail (op != NULL, FALSE);
-    }
-    
-    return mop ? SEAHORSE_OPERATION (mop) : op;
+	g_return_if_fail (closure->num_transfers > 0);
+
+	seahorse_transfer_finish (result, &error);
+	if (error != NULL)
+		g_simple_async_result_take_error (res, error);
+
+	closure->num_transfers--;
+	seahorse_progress_end (closure->cancellable, GINT_TO_POINTER (closure->num_transfers));
+
+	if (closure->num_transfers == 0) {
+		g_simple_async_result_complete (res);
+	}
+
+	g_object_unref (user_data);
 }
 
 
-/**
- * seahorse_context_discover_objects:
- * @sctx: the context to work with (can be NULL)
- * @ktype: the type of key to discover
- * @rawids: a list of ids to discover
- *
- * Downloads a list of keys from the keyserver
- *
- * Returns: The imported keys
- */
+void
+seahorse_context_transfer_objects_async (SeahorseContext *self,
+                                         GList *objects,
+                                         SeahorseSource *to,
+                                         GCancellable *cancellable,
+                                         GAsyncReadyCallback callback,
+                                         gpointer user_data)
+{
+	seahorse_context_transfer_closure *closure;
+	SeahorseObject *object;
+	GSimpleAsyncResult *res;
+	SeahorseSource *from;
+	GQuark ktype;
+	GList *next, *l;
+	GList *ids = NULL;
+
+	if (self == NULL)
+		self = seahorse_context_instance ();
+	g_return_if_fail (SEAHORSE_IS_CONTEXT (self));
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_context_transfer_objects_async);
+	closure = g_new0 (seahorse_context_transfer_closure, 1);
+	g_simple_async_result_set_op_res_gpointer (res, closure,
+	                                           seahorse_context_transfer_free);
+	if (cancellable)
+		closure->cancellable = g_object_ref (cancellable);
+
+	objects = g_list_copy (objects);
+
+	/* Sort by key source */
+	objects = seahorse_util_objects_sort (objects);
+
+	while (objects) {
+
+		/* break off one set (same keysource) */
+		next = seahorse_util_objects_splice (objects);
+
+		g_assert (SEAHORSE_IS_OBJECT (objects->data));
+		object = SEAHORSE_OBJECT (objects->data);
+
+		/* Export from this key source */
+		from = seahorse_object_get_source (object);
+		g_return_if_fail (from != NULL);
+		ktype = seahorse_source_get_tag (from);
+
+		/* Find a local keysource to import to */
+		if (!to) {
+			to = seahorse_context_find_source (self, ktype, SEAHORSE_LOCATION_LOCAL);
+			if (!to) {
+				/* TODO: How can we warn caller about this. Do we need to? */
+				g_warning ("couldn't find a local source for: %s",
+				           g_quark_to_string (ktype));
+			}
+		}
+
+		/* Make sure it's the same type */
+		if (ktype != seahorse_source_get_tag (to)) {
+			/* TODO: How can we warn caller about this. Do we need to? */
+			g_warning ("destination is not of type: %s",
+			           g_quark_to_string (ktype));
+		}
+
+		if (to != NULL && from != to) {
+
+			/* Build id list */
+			for (l = objects; l; l = g_list_next (l))
+				ids = g_list_prepend (ids, GUINT_TO_POINTER (seahorse_object_get_id (l->data)));
+			ids = g_list_reverse (ids);
+
+			/* Start a new transfer operation between the two sources */
+			seahorse_progress_prep_and_begin (cancellable, GINT_TO_POINTER (closure->num_transfers), NULL);
+			seahorse_transfer_async (from, to, ids, cancellable,
+			                         on_source_transfer_ready, g_object_ref (res));
+			closure->num_transfers++;
+
+			g_list_free (ids);
+			ids = NULL;
+		}
+
+		g_list_free (objects);
+		objects = next;
+	}
+
+	if (closure->num_transfers == 0)
+		g_simple_async_result_complete_in_idle (res);
+
+	g_object_unref (res);
+}
+
+gboolean
+seahorse_context_transfer_objects_finish (SeahorseContext *self,
+                                          GAsyncResult *result,
+                                          GError **error)
+{
+	GSimpleAsyncResult *res;
+
+	if (self == NULL)
+		self = seahorse_context_instance ();
+	g_return_val_if_fail (SEAHORSE_IS_CONTEXT (self), FALSE);
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	                      seahorse_context_transfer_objects_async), FALSE);
+
+	res = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (res, error))
+		return FALSE;
+
+	return TRUE;
+}
+
+void
+seahorse_context_retrieve_objects_async (SeahorseContext *self,
+                                         GQuark ktype,
+                                         GList *ids,
+                                         SeahorseSource *to,
+                                         GCancellable *cancellable,
+                                         GAsyncReadyCallback callback,
+                                         gpointer user_data)
+{
+	seahorse_context_transfer_closure *closure;
+	GSimpleAsyncResult *res;
+	SeahorseSource *source;
+	GList *sources, *l;
+
+	if (self == NULL)
+		self = seahorse_context_instance ();
+	g_return_if_fail (SEAHORSE_IS_CONTEXT (self));
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_context_retrieve_objects_async);
+	closure = g_new0 (seahorse_context_transfer_closure, 1);
+	g_simple_async_result_set_op_res_gpointer (res, closure,
+	                                           seahorse_context_transfer_free);
+	if (cancellable)
+		closure->cancellable = g_object_ref (cancellable);
+
+	if (to == NULL) {
+		to = seahorse_context_find_source (self, ktype, SEAHORSE_LOCATION_LOCAL);
+		if (to == NULL) {
+			/* TODO: How can we warn caller about this. Do we need to? */
+			g_warning ("couldn't find a local source for: %s",
+			           g_quark_to_string (ktype));
+		}
+	}
+
+	sources = seahorse_context_find_sources (self, ktype, SEAHORSE_LOCATION_REMOTE);
+	for (l = sources; to != NULL && l != NULL; l = g_list_next (l)) {
+		source = SEAHORSE_SOURCE (l->data);
+
+		/* Start a new transfer operation between the two key sources */
+		seahorse_progress_prep_and_begin (cancellable, GINT_TO_POINTER (closure->num_transfers), NULL);
+		seahorse_transfer_async (source, to, ids, cancellable,
+		                         on_source_transfer_ready, g_object_ref (res));
+		closure->num_transfers++;
+	}
+
+	if (closure->num_transfers == 0)
+		g_simple_async_result_complete_in_idle (res);
+
+	g_object_unref (res);
+}
+
+
+gboolean
+seahorse_context_retrieve_objects_finish  (SeahorseContext *self,
+                                           GAsyncResult *result,
+                                           GError **error)
+{
+	GSimpleAsyncResult *res;
+
+	if (self == NULL)
+		self = seahorse_context_instance ();
+	g_return_val_if_fail (SEAHORSE_IS_CONTEXT (self), FALSE);
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	                      seahorse_context_retrieve_objects_async), FALSE);
+
+	res = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (res, error))
+		return FALSE;
+
+	return TRUE;
+}
+
 GList*
-seahorse_context_discover_objects (SeahorseContext *sctx, GQuark ktype, 
-                                   GList *rawids)
+seahorse_context_discover_objects (SeahorseContext *self,
+                                   GQuark ktype,
+                                   GList *rawids,
+                                   GCancellable *cancellable)
 {
-    SeahorseOperation *op = NULL;
-    GList *robjects = NULL;
-    GQuark id = 0;
-    GList *todiscover = NULL;
-    GList *toimport = NULL;
-    SeahorseSource *sksrc;
-    SeahorseObject* sobj;
-    SeahorseLocation loc;
-    GList *l;
+	GList *robjects = NULL;
+	GQuark id = 0;
+	GList *todiscover = NULL;
+	GList *toimport = NULL;
+	SeahorseSource *source;
+	SeahorseObject* object;
+	SeahorseLocation loc;
+	GList *l;
 
-    if (!sctx)
-        sctx = seahorse_context_instance ();
-    g_return_val_if_fail (SEAHORSE_IS_CONTEXT (sctx), NULL);
+	if (self == NULL)
+		self = seahorse_context_instance ();
+	g_return_val_if_fail (SEAHORSE_IS_CONTEXT (self), NULL);
 
-    /* Check all the ids */
-    for (l = rawids; l; l = g_list_next (l)) {
-        
-        id = seahorse_context_canonize_id (ktype, (gchar*)l->data);
-        if (!id) {
-            /* TODO: Try and match this partial id */
-            g_warning ("invalid id: %s", (gchar*)l->data);
-            continue;
-        }
-        
-        /* Do we know about this object? */
-        sobj = seahorse_context_find_object (sctx, id, SEAHORSE_LOCATION_INVALID);
+	/* Check all the ids */
+	for (l = rawids; l != NULL; l = g_list_next (l)) {
 
-        /* No such object anywhere, discover it */
-        if (!sobj) {
-            todiscover = g_list_prepend (todiscover, GUINT_TO_POINTER (id));
-            id = 0;
-            continue;
-        }
-        
-        /* Our return value */
-        robjects = g_list_prepend (robjects, sobj);
-        
-        /* We know about this object, check where it is */
-        loc = seahorse_object_get_location (sobj);
-        g_assert (loc != SEAHORSE_LOCATION_INVALID);
-        
-        /* Do nothing for local objects */
-        if (loc >= SEAHORSE_LOCATION_LOCAL)
-            continue;
-        
-        /* Remote objects get imported */
-        else if (loc >= SEAHORSE_LOCATION_REMOTE)
-            toimport = g_list_prepend (toimport, sobj);
-        
-        /* Searching objects are ignored */
-        else if (loc >= SEAHORSE_LOCATION_SEARCHING)
-            continue;
-        
-        /* TODO: Should we try SEAHORSE_LOCATION_MISSING objects again? */
-    }
-    
-    /* Start an import process on all toimport */
-    if (toimport) {
-        op = seahorse_context_transfer_objects (sctx, toimport, NULL);
-        
-        g_list_free (toimport);
-        
-        /* Running operations ref themselves */
-        g_object_unref (op);
-    }
+		id = seahorse_context_canonize_id (ktype, (gchar*)l->data);
+		if (!id) {
+			/* TODO: Try and match this partial id */
+			g_warning ("invalid id: %s", (gchar*)l->data);
+			continue;
+		}
+
+		/* Do we know about this object? */
+		object = seahorse_context_find_object (self, id, SEAHORSE_LOCATION_INVALID);
+
+		/* No such object anywhere, discover it */
+		if (object == NULL) {
+			todiscover = g_list_prepend (todiscover, GUINT_TO_POINTER (id));
+			id = 0;
+			continue;
+		}
+
+		/* Our return value */
+		robjects = g_list_prepend (robjects, object);
+
+		/* We know about this object, check where it is */
+		loc = seahorse_object_get_location (object);
+		g_assert (loc != SEAHORSE_LOCATION_INVALID);
+
+		/* Do nothing for local objects */
+		if (loc >= SEAHORSE_LOCATION_LOCAL)
+			continue;
+
+		/* Remote objects get imported */
+		else if (loc >= SEAHORSE_LOCATION_REMOTE)
+			toimport = g_list_prepend (toimport, object);
+
+		/* Searching objects are ignored */
+		else if (loc >= SEAHORSE_LOCATION_SEARCHING)
+			continue;
+
+		/* TODO: Should we try SEAHORSE_LOCATION_MISSING objects again? */
+	}
+
+	/* Start an import process on all toimport */
+	if (toimport) {
+		seahorse_context_transfer_objects_async (self, toimport, NULL,
+		                                         cancellable, NULL, NULL);
+
+		g_list_free (toimport);
+	}
 
 	/* Start a discover process on all todiscover */
 	if (todiscover != NULL &&
-	    g_settings_get_boolean (sctx->pv->seahorse_settings, "server-auto-retrieve")) {
-
-		op = seahorse_context_retrieve_objects (sctx, ktype, todiscover, NULL);
-		/* Running operations ref themselves */
-		g_object_unref (op);
+	    g_settings_get_boolean (self->pv->seahorse_settings, "server-auto-retrieve")) {
+		seahorse_context_retrieve_objects_async (self, ktype, todiscover, NULL,
+		                                         cancellable, NULL, NULL);
 	}
 
-    /* Add unknown objects for all these */
-    sksrc = seahorse_context_find_source (sctx, ktype, SEAHORSE_LOCATION_MISSING);
-    for (l = todiscover; l; l = g_list_next (l)) {
-        if (sksrc) {
-            sobj = seahorse_unknown_source_add_object (SEAHORSE_UNKNOWN_SOURCE (sksrc), 
-                                                       GPOINTER_TO_UINT (l->data), op);
-            robjects = g_list_prepend (robjects, sobj);
-        }
-    }
+	/* Add unknown objects for all these */
+	source = seahorse_context_find_source (self, ktype, SEAHORSE_LOCATION_MISSING);
+	for (l = todiscover; l != NULL; l = g_list_next (l)) {
+		if (source) {
+			object = seahorse_unknown_source_add_object (SEAHORSE_UNKNOWN_SOURCE (source),
+			                                             GPOINTER_TO_UINT (l->data),
+			                                             cancellable);
+			robjects = g_list_prepend (robjects, object);
+		}
+	}
 
-    g_list_free (todiscover);
+	g_list_free (todiscover);
 
-    return robjects;
+	return robjects;
 }
 
 /**
@@ -1502,11 +1622,11 @@ seahorse_context_canonize_id (GQuark ktype, const gchar *id)
 	SeahorseCanonizeFunc canonize;
 
 	g_return_val_if_fail (id != NULL, 0);
-    
+
 	canonize = seahorse_registry_lookup_function (NULL, "canonize", g_quark_to_string (ktype), NULL);
-	if (!canonize) 
+	if (!canonize)
 		return 0;
-	
+
 	return (canonize) (id);
 }
 
diff --git a/libseahorse/seahorse-context.h b/libseahorse/seahorse-context.h
index 8156e36..f02bfcd 100644
--- a/libseahorse/seahorse-context.h
+++ b/libseahorse/seahorse-context.h
@@ -78,120 +78,143 @@ struct _SeahorseContext {
 struct _SeahorseContextClass {
 	GObjectClass parent_class;
 
-    /* signals --------------------------------------------------------- */
-    
-    /* A object was added to this source */
-    void (*added) (SeahorseContext *sctx, struct _SeahorseObject *sobj);
-
-    /* Removed a object from this source */
-    void (*removed) (SeahorseContext *sctx, struct _SeahorseObject *sobj);
-    
-    /* This object has changed */
-    void (*changed) (SeahorseContext *sctx, struct _SeahorseObject *sobj);
-    
-    /* The source is being refreshed */
-    void (*refreshing) (SeahorseContext *sctx, SeahorseOperation *op);
-
-	void (*destroy) (SeahorseContext *sctx);
-};
+	/* signals --------------------------------------------------------- */
 
-typedef void (*SeahorseObjectFunc) (struct _SeahorseObject *obj, gpointer user_data);
+	/* A object was added to this source */
+	void     (*added)              (SeahorseContext *self,
+	                                struct _SeahorseObject *sobj);
 
-#define             SCTX_APP()                          (seahorse_context_instance ())
+	/* Removed a object from this source */
+	void     (*removed)            (SeahorseContext *self,
+	                                struct _SeahorseObject *sobj);
 
-GType               seahorse_context_get_type           (void);
+	/* This object has changed */
+	void     (*changed)            (SeahorseContext *self,
+	                                struct _SeahorseObject *sobj);
 
-SeahorseContext*    seahorse_context_instance           (void);
+	void     (*destroy)            (SeahorseContext *self);
+};
 
-void                seahorse_context_create             (void);
+typedef void       (*SeahorseObjectFunc)                     (struct _SeahorseObject *obj,
+                                                              gpointer user_data);
 
-void                seahorse_context_destroy            (SeahorseContext    *sctx);
+#define             SCTX_APP()                               (seahorse_context_instance ())
 
-#define             seahorse_context_is_daemon(ctx)     ((ctx)->is_daemon)
+GType               seahorse_context_get_type                (void);
 
-void                seahorse_context_add_source         (SeahorseContext    *sctx,
-                                                         SeahorseSource  *sksrc);
+SeahorseContext*    seahorse_context_instance                (void);
 
-void                seahorse_context_take_source        (SeahorseContext    *sctx,
-                                                         SeahorseSource  *sksrc);
+void                seahorse_context_create                  (void);
 
-void                seahorse_context_remove_source      (SeahorseContext    *sctx,
-                                                         SeahorseSource  *sksrc);
+void                seahorse_context_destroy                 (SeahorseContext *self);
 
-SeahorseSource*     seahorse_context_find_source        (SeahorseContext    *sctx,
-                                                         GQuark             ktype,
-                                                         SeahorseLocation   location);
+#define             seahorse_context_is_daemon(ctx)          ((ctx)->is_daemon)
 
-GList*             seahorse_context_find_sources       (SeahorseContext    *sctx,
-                                                         GQuark             ktype,
-                                                         SeahorseLocation   location);
-                                                         
+void                seahorse_context_add_source              (SeahorseContext *self,
+                                                              SeahorseSource *sksrc);
 
-SeahorseSource*     seahorse_context_remote_source      (SeahorseContext    *sctx,
-                                                         const gchar        *uri);
+void                seahorse_context_take_source             (SeahorseContext *self,
+                                                              SeahorseSource *sksrc);
 
-void                seahorse_context_add_object         (SeahorseContext    *sctx,
-                                                         struct _SeahorseObject     *sobj);
+void                seahorse_context_remove_source           (SeahorseContext *self,
+                                                              SeahorseSource *sksrc);
 
-void                seahorse_context_take_object        (SeahorseContext    *sctx, 
-                                                         struct _SeahorseObject     *sobj);
+SeahorseSource*     seahorse_context_find_source             (SeahorseContext *self,
+                                                              GQuark ktype,
+                                                              SeahorseLocation location);
 
-guint               seahorse_context_get_count          (SeahorseContext    *sctx);
+GList*             seahorse_context_find_sources             (SeahorseContext    *sctx,
+                                                              GQuark             ktype,
+                                                              SeahorseLocation   location);
 
-struct _SeahorseObject*     seahorse_context_get_object  (SeahorseContext    *sctx,
-                                                         SeahorseSource  *sksrc,
-                                                         GQuark             id);
+SeahorseSource*     seahorse_context_remote_source           (SeahorseContext *self,
+                                                              const gchar *uri);
 
-GList*              seahorse_context_get_objects        (SeahorseContext    *sctx, 
-                                                         SeahorseSource  *sksrc);
+void                seahorse_context_add_object              (SeahorseContext *self,
+                                                              struct _SeahorseObject *sobj);
 
-struct _SeahorseObject*     seahorse_context_find_object (SeahorseContext    *sctx,
-                                                         GQuark             id,
-                                                         SeahorseLocation   location);
+void                seahorse_context_take_object             (SeahorseContext *self,
+                                                              struct _SeahorseObject *sobj);
 
-GList*              seahorse_context_find_objects       (SeahorseContext    *sctx,
-                                                         GQuark             ktype,
-                                                         SeahorseUsage      usage,
-                                                         SeahorseLocation   location);
+guint               seahorse_context_get_count               (SeahorseContext *self);
 
-GList*              seahorse_context_find_objects_full  (SeahorseContext *self,
-                                                         struct _SeahorseObjectPredicate *skpred);
+struct _SeahorseObject*     seahorse_context_get_object      (SeahorseContext *self,
+                                                              SeahorseSource *sksrc,
+                                                              GQuark id);
 
-void                seahorse_context_for_objects_full   (SeahorseContext *self,
-                                                         struct _SeahorseObjectPredicate *skpred,
-                                                         SeahorseObjectFunc func,
-                                                         gpointer user_data);
+GList*              seahorse_context_get_objects             (SeahorseContext *self,
+                                                              SeahorseSource *sksrc);
 
-void                seahorse_context_remove_object      (SeahorseContext *sctx,
-                                                         struct _SeahorseObject *sobj);
+struct _SeahorseObject*     seahorse_context_find_object     (SeahorseContext *self,
+                                                              GQuark id,
+                                                              SeahorseLocation location);
 
-SeahorseServiceDiscovery*
-                    seahorse_context_get_discovery      (SeahorseContext    *sctx);
-
-struct _SeahorseObject*   
-                    seahorse_context_get_default_key    (SeahorseContext    *sctx);
+GList*              seahorse_context_find_objects            (SeahorseContext *self,
+                                                              GQuark ktype,
+                                                              SeahorseUsage usage,
+                                                              SeahorseLocation location);
 
-void                seahorse_context_refresh_auto       (SeahorseContext *sctx);
+GList*              seahorse_context_find_objects_full       (SeahorseContext *self,
+                                                              struct _SeahorseObjectPredicate *skpred);
 
-SeahorseOperation*  seahorse_context_search_remote      (SeahorseContext    *sctx,
-                                                         const gchar        *search);
+void                seahorse_context_for_objects_full        (SeahorseContext *self,
+                                                              struct _SeahorseObjectPredicate *skpred,
+                                                              SeahorseObjectFunc func,
+                                                              gpointer user_data);
 
-SeahorseOperation*  seahorse_context_transfer_objects   (SeahorseContext    *sctx, 
-                                                         GList              *objs, 
-                                                         SeahorseSource  *to);
+void                seahorse_context_remove_object           (SeahorseContext *self,
+                                                              struct _SeahorseObject *sobj);
 
-SeahorseOperation*  seahorse_context_retrieve_objects   (SeahorseContext    *sctx, 
-                                                         GQuark             ktype, 
-                                                         GList             *ids,
-                                                         SeahorseSource  *to);
-
-GList*              seahorse_context_discover_objects   (SeahorseContext    *sctx, 
-                                                         GQuark             ktype, 
-                                                         GList             *ids);
-
-typedef GQuark (*SeahorseCanonizeFunc) (const gchar *id);
+SeahorseServiceDiscovery*
+                    seahorse_context_get_discovery           (SeahorseContext    *self);
 
-GQuark              seahorse_context_canonize_id        (GQuark ktype, const gchar *id);
+struct _SeahorseObject*   
+                    seahorse_context_get_default_key         (SeahorseContext    *self);
+
+void                seahorse_context_refresh_auto            (SeahorseContext *self);
+
+void                seahorse_context_search_remote_async     (SeahorseContext *self,
+                                                              const gchar *search,
+                                                              GCancellable *cancellable,
+                                                              GAsyncReadyCallback callback,
+                                                              gpointer user_data);
+
+GList *             seahorse_context_search_remote_finish    (SeahorseContext *self,
+                                                              GAsyncResult *result,
+                                                              GError **error);
+
+void                seahorse_context_transfer_objects_async  (SeahorseContext *self,
+                                                              GList *objects,
+                                                              SeahorseSource *to,
+                                                              GCancellable *cancellable,
+                                                              GAsyncReadyCallback callback,
+                                                              gpointer user_data);
+
+gboolean            seahorse_context_transfer_objects_finish (SeahorseContext *self,
+                                                              GAsyncResult *result,
+                                                              GError **error);
+
+void                seahorse_context_retrieve_objects_async  (SeahorseContext *self,
+                                                              GQuark ktype,
+                                                              GList *ids,
+                                                              SeahorseSource *to,
+                                                              GCancellable *cancellable,
+                                                              GAsyncReadyCallback callback,
+                                                              gpointer user_data);
+
+gboolean            seahorse_context_retrieve_objects_finish (SeahorseContext *self,
+                                                              GAsyncResult *result,
+                                                              GError **error);
+
+GList*              seahorse_context_discover_objects        (SeahorseContext *self,
+                                                              GQuark ktype,
+                                                              GList *rawids,
+                                                              GCancellable *cancellable);
+
+typedef GQuark     (*SeahorseCanonizeFunc)                   (const gchar *id);
+
+GQuark              seahorse_context_canonize_id             (GQuark ktype,
+                                                              const gchar *id);
 
 GSettings *         seahorse_context_settings           (SeahorseContext *self);
 
diff --git a/libseahorse/seahorse-object.c b/libseahorse/seahorse-object.c
index 7adf2d0..df3c7f1 100644
--- a/libseahorse/seahorse-object.c
+++ b/libseahorse/seahorse-object.c
@@ -643,10 +643,6 @@ seahorse_object_set_property (GObject *obj, guint prop_id, const GValue *value,
 		break;
 	case PROP_FLAGS:
 		flags = g_value_get_uint (value);
-		if (SEAHORSE_OBJECT_GET_CLASS (obj)->delete)
-			flags |= SEAHORSE_FLAG_DELETABLE;
-		else 
-			flags &= ~SEAHORSE_FLAG_DELETABLE;
 		if (flags != self->pv->flags) {
 			self->pv->flags = flags;
 			g_object_notify (obj, "flags");
@@ -1191,24 +1187,6 @@ seahorse_object_refresh (SeahorseObject *self)
 }
 
 /**
- * seahorse_object_delete:
- * @self: object to delete
- *
- * calls the class delete function
- *
- * Returns: NULL on error
- */
-SeahorseOperation*
-seahorse_object_delete (SeahorseObject *self)
-{
-	SeahorseObjectClass *klass;
-	g_return_val_if_fail (SEAHORSE_IS_OBJECT (self), NULL);
-	klass = SEAHORSE_OBJECT_GET_CLASS (self);
-	g_return_val_if_fail (klass->delete, NULL);
-	return (klass->delete) (self);
-}
-
-/**
  * seahorse_object_predicate_match:
  * @self: the object to test
  * @obj: The predicate to match
diff --git a/libseahorse/seahorse-object.h b/libseahorse/seahorse-object.h
index 0639b51..b1c25c9 100644
--- a/libseahorse/seahorse-object.h
+++ b/libseahorse/seahorse-object.h
@@ -73,8 +73,6 @@ struct _SeahorseObjectClass {
 	void (*realize) (SeahorseObject *self);
 	
 	void (*refresh) (SeahorseObject *self);
-	
-	SeahorseOperation* (*delete) (SeahorseObject *self);
 };
 
 GType               seahorse_object_get_type               (void);
@@ -85,8 +83,6 @@ void                seahorse_object_realize                (SeahorseObject *self
 
 void                seahorse_object_refresh                (SeahorseObject *self);
 
-SeahorseOperation*  seahorse_object_delete                 (SeahorseObject *self);
-
 GQuark              seahorse_object_get_id                 (SeahorseObject *self);
 
 GQuark              seahorse_object_get_tag                (SeahorseObject *self);
diff --git a/libseahorse/seahorse-passphrase.c b/libseahorse/seahorse-passphrase.c
index 44eec78..39a9c78 100644
--- a/libseahorse/seahorse-passphrase.c
+++ b/libseahorse/seahorse-passphrase.c
@@ -159,24 +159,6 @@ window_state_changed (GtkWidget *win, GdkEventWindowState *event, gpointer data)
 	return FALSE;
 }
 
-static void
-constrain_size (GtkWidget *win, GtkRequisition *req, gpointer data)
-{
-    static gint width, height;
-    GdkGeometry geo;
-
-    if (req->width == width && req->height == height)
-        return;
-
-    width = req->width;
-    height = req->height;
-    geo.min_width = width;
-    geo.max_width = 10000;  /* limit is arbitrary, INT_MAX breaks other things */
-    geo.min_height = geo.max_height = height;
-    gtk_window_set_geometry_hints (GTK_WINDOW (win), NULL, &geo,
-                                   GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
-}
-
 GtkDialog*
 seahorse_passphrase_prompt_show (const gchar *title, const gchar *description, 
                                  const gchar *prompt, const gchar *check,
@@ -203,7 +185,6 @@ seahorse_passphrase_prompt_show (const gchar *title, const gchar *description,
 
     dialog = GTK_DIALOG (w);
 
-    g_signal_connect (G_OBJECT (dialog), "size-request", G_CALLBACK (constrain_size), NULL);
     g_signal_connect (G_OBJECT (dialog), "map-event", G_CALLBACK (grab_keyboard), NULL);
     g_signal_connect (G_OBJECT (dialog), "unmap-event", G_CALLBACK (ungrab_keyboard), NULL);
     g_signal_connect (G_OBJECT (dialog), "window-state-event", G_CALLBACK (window_state_changed), NULL); 
@@ -294,8 +275,6 @@ seahorse_passphrase_prompt_show (const gchar *title, const gchar *description,
     w = gtk_button_new_from_stock (GTK_STOCK_OK);
     gtk_dialog_add_action_widget (dialog, w, GTK_RESPONSE_ACCEPT);
     gtk_widget_set_can_default (w, TRUE);
-    g_signal_connect_object (G_OBJECT (entry), "focus_in_event",
-                             G_CALLBACK (gtk_widget_grab_default), G_OBJECT (w), 0);
     gtk_widget_grab_default (w);
     
     g_signal_connect (dialog, "key_press_event", G_CALLBACK (key_press), NULL);
diff --git a/libseahorse/seahorse-progress.c b/libseahorse/seahorse-progress.c
index e77547c..67701d6 100644
--- a/libseahorse/seahorse-progress.c
+++ b/libseahorse/seahorse-progress.c
@@ -19,431 +19,608 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include "config.h"
+
 #include "seahorse-progress.h"
 #include "seahorse-widget.h"
 
-/* -----------------------------------------------------------------------------
- *  GENERIC PROGRESS BAR HANDLING 
- */
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
 
-/**
- * SECTION:seahorse-progress
- * @short_description: Progress bar handling
- *
- **/
+typedef enum {
+	TASK_PART_PREPPED = 1,
+	TASK_PART_BEGUN,
+	TASK_PART_ENDED
+} TrackedState;
 
-static void     disconnect_progress     (SeahorseWidget *widget, SeahorseOperation *op);
+typedef struct {
+	gconstpointer progress_tag;
+	gchar *details;
+	TrackedState state;
+} TrackedPart;
 
-/**
-* progress: The progress bar to pulse
-*
-* Called to pulse the progress bar when we're in pulse mode
-*
-* Returns TRUE if the bar pulsed
-**/
-static gboolean
-pulse_timer (GtkProgressBar *progress)
+typedef struct {
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+
+	SeahorseWidget *swidget;
+	gchar *title;
+	gboolean showing;
+
+	GQueue *parts;
+	gint parts_prepped;
+	gint parts_begun;
+	gint parts_ended;
+} TrackedTask;
+
+static GHashTable *tracked_tasks = NULL;
+
+static void
+tracked_part_free (gpointer data)
 {
-    g_assert (GTK_IS_PROGRESS_BAR (progress));
-    
-    if (gtk_progress_bar_get_pulse_step (progress) != 0) {
-        gtk_progress_bar_pulse (progress);
-         return TRUE;
-    }
-    
-    return FALSE;
+	TrackedPart *part = data;
+	g_free (part->details);
+	g_free (part);
 }
 
-/**
-* progress: The progress bar to init
-*
-* Inits the progress bar and sets a timer function.
-*
-**/
-static void
-start_pulse (GtkProgressBar *progress)
+static gint
+find_part_progress_tag (gconstpointer part_data,
+                        gconstpointer progress_tag)
 {
-    guint stag;
-   
-    gtk_progress_bar_set_pulse_step (progress, 0.05);
-    gtk_progress_bar_pulse (progress);
-        
-    stag = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (progress), "pulse-timer"));    
-    if (stag == 0) {
-        /* Start a pulse timer */
-        stag = g_timeout_add (100, (GSourceFunc)pulse_timer, progress); 
-        g_object_set_data_full (G_OBJECT (progress), "pulse-timer", 
-                                GINT_TO_POINTER (stag), (GDestroyNotify)g_source_remove);
-    }   
+	TrackedPart *part = (TrackedPart *)part_data;
+	return (part->progress_tag == progress_tag) ? 0 : 1;
 }
 
-/**
-* progress: The progress bar
-*
-* Stops progress bar pulsing
-*
-**/
-static void
-stop_pulse (GtkProgressBar *progress)
+static gint
+find_part_begun_with_details (gconstpointer part_data,
+                              gconstpointer unused)
 {
-    gtk_progress_bar_set_pulse_step (progress, 0.0);
-    
-    /* This causes the destroy callback to be called */
-    g_object_set_data (G_OBJECT (progress), "pulse-timer", NULL);
+	TrackedPart *part = (TrackedPart *)part_data;
+	return (part->state == TASK_PART_BEGUN && part->details) ? 0 : 1;
 }
 
+static TrackedPart *
+tracked_part_find (TrackedTask *task,
+                   GCompareFunc func,
+                   gconstpointer user_data)
+{
+	GList *part = g_queue_find_custom (task->parts, user_data, func);
+	return part ? part->data : NULL;
+}
 
-/**
-* operation: The operation to process
-* message: The message that will be pushed to the status bar
-* fract: The fraction of the progress bar to fill
-* swidget: The SeahorseWidget to extract the gtk widgets from
-*
-* This gets called whenever an operation updates it's progress status thingy.
-* We update the appbar as appropriate. If operation != NULL then we only
-* display the latest operation in our special list
-*
-**/
 static void
-operation_progress (SeahorseOperation *operation, const gchar *message, 
-                    gdouble fract, SeahorseWidget *swidget)
+on_cancellable_gone (gpointer user_data,
+                     GObject *where_the_object_was)
 {
-    GtkProgressBar *progress;
-    GtkStatusbar *status;
-    guint id; 
-    
-    progress = GTK_PROGRESS_BAR (seahorse_widget_get_widget (swidget, "progress"));
-    status = GTK_STATUSBAR (seahorse_widget_get_widget (swidget, "status"));
-    
-    if (!seahorse_operation_is_running (operation))
-        fract = 0.0;
-    
-    if (message != NULL && status) {
-        g_return_if_fail (GTK_IS_STATUSBAR (status));
-        id = gtk_statusbar_get_context_id (status, "operation-progress");
-        gtk_statusbar_pop (status, id);
-        if (message[0])
-            gtk_statusbar_push (status, id, message);
-    }
-
-    if(progress) {
-        g_return_if_fail (GTK_IS_PROGRESS_BAR (progress));
-        if (fract >= 0.0) {
-            stop_pulse (progress);
-            gtk_progress_bar_set_fraction (progress, fract);        
-        } else { 
-            start_pulse (progress);
-        }
-    }
+	TrackedTask *task;
+
+	g_assert (tracked_tasks);
+	task = g_hash_table_lookup (tracked_tasks, where_the_object_was);
+	g_assert ((gpointer)task->cancellable == (gpointer)where_the_object_was);
+	task->cancellable = NULL;
+	task->cancelled_sig = 0;
+
+	if (!g_hash_table_remove (tracked_tasks, where_the_object_was))
+		g_assert_not_reached ();
 }
 
-/**
-* operation: The finished operation
-* swidget: The SeahorseWidget to get the progress bar from
-*
-* Handles the progress bar display of finished operations.
-* If there is an error in the operation, it will be displayed.
-*
-**/
 static void
-operation_done (SeahorseOperation *operation, SeahorseWidget *swidget)
+on_cancellable_cancelled (GCancellable *cancellable,
+                          gpointer user_data)
 {
-    GError *err = NULL;
-
-    if (!seahorse_operation_is_successful (operation)) {
-        seahorse_operation_copy_error (operation, &err);
-        if (err) {
-            operation_progress (operation, err->message, 0.0, swidget);
-            g_error_free (err);
-        }
-    } else {
-	    operation_progress (operation, "", 0.0, swidget);
-    }
-    
-    g_signal_handlers_disconnect_by_func (swidget, disconnect_progress, operation);
-    g_object_set_data (G_OBJECT (swidget), "operation", NULL);
+	TrackedTask *task = user_data;
+
+	g_assert (tracked_tasks);
+	g_assert (task->cancellable == cancellable);
+	if (!g_hash_table_remove (tracked_tasks, cancellable))
+		g_assert_not_reached ();
 }
 
-/**
-* widget: SeahorseWidget that is used for display
-* op: SeahorseOperation to disconnect
-*
-* Disconnect the operation_progress and the operation_done functions from the
-* operation
-*
-**/
 static void
-disconnect_progress (SeahorseWidget *widget, SeahorseOperation *op)
+tracked_task_free (gpointer data)
 {
-    g_signal_handlers_disconnect_by_func (op, operation_progress, widget);
-    g_signal_handlers_disconnect_by_func (op, operation_done, widget);
+	TrackedTask *task = data;
+	if (task->cancellable) {
+		g_object_weak_unref (G_OBJECT (task->cancellable),
+		                     on_cancellable_gone, task);
+
+		/* Use this because g_cancellable_disconnect() deadlocks */
+		if (task->cancelled_sig)
+			g_signal_handler_disconnect (task->cancellable,
+			                             task->cancelled_sig);
+	}
+
+	g_queue_foreach (task->parts, (GFunc)tracked_part_free, NULL);
+	g_queue_free (task->parts);
+	g_free (task->title);
+	if (task->swidget)
+		g_object_unref (task->swidget);
+	g_free (task);
 }
 
-/**
- * seahorse_progress_status_set_operation:
- * @swidget: The SeahorseWidget to add the operation to
- * @operation: The operation to add
- *
- * Adds the operation to the widget.
- *
- */
-void 
-seahorse_progress_status_set_operation (SeahorseWidget *swidget, 
-                                        SeahorseOperation *operation)
+static gboolean
+on_pulse_timeout (gpointer user_data)
 {
-    SeahorseOperation *prev;
-    
-    /* 
-     * Note that this is not one off, the operation is monitored until it is 
-     * replaced, so if the operation starts up again the progress will be 
-     * displayed 
-     */
-    
-    g_return_if_fail (SEAHORSE_IS_WIDGET (swidget));
-    g_return_if_fail (SEAHORSE_IS_OPERATION (operation));
-    
-    prev = SEAHORSE_OPERATION (g_object_get_data (G_OBJECT (swidget), "operation"));
-    if (prev) {
-	    
-        /* If it's the same operation, just ignore */
-        if (prev == operation)
-            return;
-        
-        /* If the previous one was a multi operation, just piggy back this one in */
-        if (SEAHORSE_IS_MULTI_OPERATION (prev)) {
-       	    g_object_ref (operation);
-            seahorse_multi_operation_take (SEAHORSE_MULTI_OPERATION (prev), operation);
-            return;
-        }
-
-        /* Otherwise disconnect old progress, replace with new */
-        disconnect_progress (swidget, prev);
-    }
-        
-    g_object_ref (operation);
-    g_object_set_data_full (G_OBJECT (swidget), "operation", operation, 
-                            (GDestroyNotify)g_object_unref);
-    g_signal_connect (swidget, "destroy", 
-                      G_CALLBACK (disconnect_progress), operation);
-    
-    if (!seahorse_operation_is_running (operation))
-        operation_done (operation, swidget);
-
-    operation_progress (operation, seahorse_operation_get_message (operation),
-                        seahorse_operation_get_progress (operation), swidget);
-    
-    g_signal_connect (operation, "done", G_CALLBACK (operation_done), swidget);
-    g_signal_connect (operation, "progress", G_CALLBACK (operation_progress), swidget);
+	GtkProgressBar *progress = GTK_PROGRESS_BAR (user_data);
+
+	if (gtk_progress_bar_get_pulse_step (progress) != 0) {
+		gtk_progress_bar_pulse (progress);
+		return TRUE;
+	}
+
+	return FALSE;
 }
 
-/**
- * seahorse_progress_status_get_operation:
- * @swidget: The SeahorseWidget to extract the operation from
- *
- *
- *
- * Returns: The operation stored in the widget
- */
-SeahorseOperation*
-seahorse_progress_status_get_operation (SeahorseWidget *swidget)
+static void
+start_pulse (GtkProgressBar *progress)
 {
-    return SEAHORSE_OPERATION (g_object_get_data (G_OBJECT (swidget), "operation"));
+	guint stag;
+
+	gtk_progress_bar_set_pulse_step (progress, 0.05);
+	gtk_progress_bar_pulse (progress);
+
+	stag = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (progress), "pulse-timer"));
+
+	/* Start a pulse timer */
+	if (stag == 0) {
+		stag = g_timeout_add (100, on_pulse_timeout, progress);
+		g_object_set_data_full (G_OBJECT (progress), "pulse-timer",
+		                        GINT_TO_POINTER (stag), (GDestroyNotify)g_source_remove);
+	}
 }
 
-/* -----------------------------------------------------------------------------
- *  PROGRESS WINDOWS 
- */
+static void
+stop_pulse (GtkProgressBar *progress)
+{
+	gtk_progress_bar_set_pulse_step (progress, 0.0);
+
+	/* This causes the destroy callback to be called */
+	g_object_set_data (G_OBJECT (progress), "pulse-timer", NULL);
+}
 
-/**
-* operation: The SeahorseOperation to use
-* message: An optional message to display
-* fract: The fraction finished
-* swidget: the SeahorseWidget to get the widgets from
-*
-* Progress window update. Similar to operation_progress
-*
-**/
 static void
-progress_operation_update (SeahorseOperation *operation, const gchar *message, 
-                           gdouble fract, SeahorseWidget *swidget)
+progress_update_display (TrackedTask *task)
 {
-    GtkProgressBar *progress;
-    GtkWidget *w;
-    const gchar *t;
-    
-    w = GTK_WIDGET (seahorse_widget_get_widget (swidget, "operation-details"));
-    g_return_if_fail (w != NULL);
-    
-    t = seahorse_operation_get_message (operation);
-    gtk_label_set_text (GTK_LABEL (w), t ? t : "");
-    
-    progress = GTK_PROGRESS_BAR (seahorse_widget_get_widget (swidget, "operation-bar"));
-    g_return_if_fail (w != NULL);
-    
-    if (fract >= 0.0) {
-        stop_pulse (progress);
-        gtk_progress_bar_set_fraction (progress, fract);        
-    } else { 
-        start_pulse (progress);
-    }
+	GtkProgressBar *progress = NULL;
+	GtkStatusbar *status = NULL;
+	GtkLabel *label = NULL;
+	GtkWidget *widget;
+	TrackedPart *part;
+	gdouble fraction;
+	guint id;
+
+	if (task->swidget == NULL)
+		return;
+
+	/* Dig out our progress display stuff */
+	widget = seahorse_widget_get_widget (task->swidget, "progress-bar");
+	if (widget == NULL)
+		g_warning ("cannot display progress because seahorse window '%s' has no progress widget",
+		           task->swidget->name);
+	else
+		progress = GTK_PROGRESS_BAR (widget);
+	widget = GTK_WIDGET (gtk_builder_get_object (task->swidget->gtkbuilder, "status"));
+	if (GTK_IS_STATUSBAR (widget)) {
+		status = GTK_STATUSBAR (widget);
+	} else {
+		widget = GTK_WIDGET (gtk_builder_get_object (task->swidget->gtkbuilder, "progress-details"));
+		if (GTK_IS_LABEL (widget))
+			label = GTK_LABEL (widget);
+	}
+
+	/* The details is the first on a begun part */
+	part = tracked_part_find (task, find_part_begun_with_details, NULL);
+	if (status) {
+		id = gtk_statusbar_get_context_id (status, "operation-progress");
+		gtk_statusbar_pop (status, id);
+		if (part != NULL)
+			gtk_statusbar_push (status, id, part->details);
+	} else if (label) {
+		gtk_label_set_text (label, part ? part->details : "");
+	}
+
+	/* If all parts are running simultaneously then indeterminate */
+	if (task->parts_prepped == 0 && task->parts_ended == 0) {
+		fraction = -1;
+	} else {
+		fraction = (gdouble)task->parts_ended /
+		           (gdouble)task->parts->length;
+	}
+
+	if (progress) {
+		if (fraction >= 0.0) {
+			stop_pulse (progress);
+			gtk_progress_bar_set_fraction (progress, fraction);
+		} else {
+			start_pulse (progress);
+		}
+	}
 }
 
-/**
- * on_progress_operation_cancel:
- * @button: ignored
- * @operation: The operation to cancel
- *
- * Cancels an operation
- *
- */
-G_MODULE_EXPORT void
-on_progress_operation_cancel (GtkButton *button, SeahorseOperation *operation)
+static TrackedTask *
+progress_lookup_or_create_task (GCancellable *cancellable)
 {
-    if (seahorse_operation_is_running (operation))
-        seahorse_operation_cancel (operation);
+	TrackedTask *task;
+
+	if (tracked_tasks == NULL)
+		tracked_tasks = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+		                                       NULL, tracked_task_free);
+
+	task = g_hash_table_lookup (tracked_tasks, cancellable);
+	if (task == NULL) {
+		if (g_cancellable_is_cancelled (cancellable))
+			return NULL;
+
+		task = g_new0 (TrackedTask, 1);
+		task->cancellable = cancellable;
+		g_object_weak_ref (G_OBJECT (task->cancellable),
+		                   on_cancellable_gone, task);
+		task->parts = g_queue_new ();
+
+		g_hash_table_insert (tracked_tasks, cancellable, task);
+		task->cancelled_sig = g_cancellable_connect (cancellable,
+		                                             G_CALLBACK (on_cancellable_cancelled),
+		                                             task, NULL);
+	}
+
+	return task;
 }
 
-/**
-* operation: ignored
-* swidget: The SeahorseWidget to destroy
-*
-* Cleans up after the operation is done
-*
-**/
 static void
-progress_operation_done (SeahorseOperation *operation, SeahorseWidget *swidget)
+progress_prep_va (GCancellable *cancellable,
+                  gconstpointer progress_tag,
+                  const gchar *details,
+                  va_list va)
 {
-    seahorse_widget_destroy (swidget);
+	TrackedTask *task;
+	TrackedPart *part;
+
+	task = progress_lookup_or_create_task (cancellable);
+
+	/* Perhaps already cancelled? */
+	if (task == NULL)
+		return;
+
+	part = tracked_part_find (task, find_part_progress_tag, progress_tag);
+	if (part == NULL) {
+		part = g_new0 (TrackedPart, 1);
+		if (details && details[0])
+			part->details = g_strdup_vprintf (details, va);
+		part->progress_tag = progress_tag;
+		part->state = TASK_PART_PREPPED;
+		g_queue_push_tail (task->parts, part);
+		task->parts_prepped++;
+	} else {
+		g_warning ("already tracking progress for this part of the operation");
+	}
+
+	/* If the dialog is being displayed, update it */
+	g_assert (task->parts_prepped + task->parts_begun + task->parts_ended == (gint)task->parts->length);
+	progress_update_display (task);
+}
+
+void
+seahorse_progress_prep (GCancellable *cancellable,
+                        gconstpointer progress_tag,
+                        const gchar *details,
+                        ...)
+{
+	va_list va;
+
+	if (!cancellable)
+		return;
+
+	g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+
+	va_start (va, details);
+	progress_prep_va (cancellable, progress_tag, details, va);
+	va_end (va);
+}
+
+void
+seahorse_progress_begin (GCancellable *cancellable,
+                         gconstpointer progress_tag)
+{
+	TrackedTask *task = NULL;
+	TrackedPart *part;
+
+	if (!cancellable)
+		return;
+
+	g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	if (tracked_tasks)
+		task = g_hash_table_lookup (tracked_tasks, cancellable);
+	if (task == NULL) {
+		g_warning ("caller is trying to begin part for task that does not exist");
+		return;
+	}
+
+	part = tracked_part_find (task, find_part_progress_tag, progress_tag);
+	if (part == NULL) {
+		g_warning ("caller is trying to begin part of task that does not exist");
+		return;
+	}
+
+	switch (part->state) {
+	case TASK_PART_PREPPED:
+		part->state = TASK_PART_BEGUN;
+		task->parts_begun++;
+		task->parts_prepped--;
+		break;
+	case TASK_PART_BEGUN:
+		g_warning ("caller is trying to begin part of task that has already begun");
+		return;
+	case TASK_PART_ENDED:
+		g_warning ("caller is trying to begin part of task that has already ended");
+		return;
+	default:
+		g_assert_not_reached ();
+		break;
+	}
+
+	g_assert (task->parts_prepped + task->parts_begun + task->parts_ended == (gint)task->parts->length);
+	progress_update_display (task);
+}
+
+void
+seahorse_progress_prep_and_begin (GCancellable *cancellable,
+                                  gconstpointer progress_tag,
+                                  const gchar *details,
+                                  ...)
+{
+	va_list va;
+
+	if (!cancellable)
+		return;
+
+	g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+
+	va_start (va, details);
+	progress_prep_va (cancellable, progress_tag, details, va);
+	seahorse_progress_begin (cancellable, progress_tag);
+	va_end (va);
+}
+
+void
+seahorse_progress_update (GCancellable *cancellable,
+                          gconstpointer progress_tag,
+                          const gchar *details,
+                          ...)
+{
+	TrackedTask *task = NULL;
+	TrackedPart *part;
+	va_list va;
+
+	if (!cancellable)
+		return;
+
+	g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	if (tracked_tasks)
+		task = g_hash_table_lookup (tracked_tasks, cancellable);
+	if (task == NULL) {
+		g_warning ("caller is trying to update part for task that does not exist");
+		return;
+	}
+
+	part = tracked_part_find (task, find_part_progress_tag, progress_tag);
+	if (part == NULL) {
+		g_warning ("caller is trying to update part of task that does not exist");
+		return;
+	}
+
+	switch (part->state) {
+	case TASK_PART_PREPPED:
+	case TASK_PART_BEGUN:
+		g_free (part->details);
+		if (details && details[0]) {
+			va_start (va, details);
+			part->details = g_strdup_vprintf (details, va);
+			va_end (va);
+		}
+		break;
+	case TASK_PART_ENDED:
+		g_warning ("caller is trying to update part of task that has already ended");
+		return;
+	default:
+		g_assert_not_reached ();
+		return;
+	}
+
+	g_assert (task->parts_prepped + task->parts_begun + task->parts_ended == (gint)task->parts->length);
+	progress_update_display (task);
+}
+
+void
+seahorse_progress_end (GCancellable *cancellable,
+                       gconstpointer progress_tag)
+{
+	TrackedTask *task = NULL;
+	TrackedPart *part;
+
+	if (!cancellable)
+		return;
+
+	g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	if (tracked_tasks)
+		task = g_hash_table_lookup (tracked_tasks, cancellable);
+	if (task == NULL) {
+		g_warning ("caller is trying to end part for task that does not exist");
+		return;
+	}
+
+	part = tracked_part_find (task, find_part_progress_tag, progress_tag);
+	if (part == NULL) {
+		g_warning ("caller is trying to end part of task that does not exist");
+		return;
+	}
+
+	switch (part->state) {
+	case TASK_PART_PREPPED:
+		g_warning ("caller is trying to end part of task that has not begun");
+		return;
+	case TASK_PART_BEGUN:
+		part->state = TASK_PART_ENDED;
+		task->parts_begun--;
+		task->parts_ended++;
+		break;
+	case TASK_PART_ENDED:
+		g_warning ("caller is trying to end part of task that has already ended");
+		return;
+	default:
+		g_assert_not_reached ();
+		break;
+	}
+
+	g_assert (task->parts_prepped + task->parts_begun + task->parts_ended == (gint)task->parts->length);
+	progress_update_display (task);
 }
 
-/**
-* widget:
-* event: ignored
-* operation: The operation
-*
-* Closing the windows cancels the operation
-*
-* Returns TRUE
-**/
 static int
-progress_delete_event (GtkWidget *widget, GdkEvent *event, 
-                       SeahorseOperation *operation)
+on_window_delete_event (GtkWidget *widget,
+                        GdkEvent *event,
+                        gpointer user_data)
 {
-    /* When window close we simulate a cancel */
-    on_progress_operation_cancel (NULL, operation);
-    
-    /* Allow window to close regardless of outcome */
-    return TRUE;
+	TrackedTask *task = NULL;
+
+	/* Guard against going away before we display */
+	if (tracked_tasks)
+		task = g_hash_table_lookup (tracked_tasks, user_data);
+	if (task != NULL)
+		g_cancellable_cancel (task->cancellable);
+
+	return TRUE; /* allow window to close */
 }
 
-/**
-* swidget: The SeahorseWidget relevant
-* operation: The operation to disconnect handlers from
-*
-* Disconnects the handlers from the functions
-*
-**/
-static void        
-progress_destroy (SeahorseWidget *swidget, SeahorseOperation *operation)
+static void
+on_cancel_button_clicked (GtkButton *button,
+                          gpointer user_data)
 {
-    /* 
-     * Since we allow the window to close (user forces it) even when the 
-     * operation is not complete, we have to take care to cleanup these
-     * signal handlers. 
-     */     
-    g_signal_handlers_disconnect_by_func (operation, operation_done, swidget);
-    g_signal_handlers_disconnect_by_func (operation, operation_progress, swidget);
+	TrackedTask *task = NULL;
+
+	/* Guard against going away before we display */
+	if (tracked_tasks)
+		task = g_hash_table_lookup (tracked_tasks, user_data);
+	if (task != NULL)
+		g_cancellable_cancel (task->cancellable);
 }
 
-/**
-* operation: The operation to create a new progress window for
-*
-* Creates a new progress window and adds the operation to it.
-*
-* Returns FALSE
-**/
 static gboolean
-progress_show (SeahorseOperation *operation)
+on_timeout_show_progress (gpointer user_data)
 {
-    SeahorseWidget *swidget;
-    GtkWidget *w;
-    const gchar *title;
-    gchar *t;
-
-    if (!seahorse_operation_is_running (operation)) {
-        /* Matches the ref in seahorse_progress_show */
-        g_object_unref (operation);
-        return FALSE;
-    }
-        
-    swidget = seahorse_widget_new_allow_multiple ("progress", NULL);
-    g_return_val_if_fail (swidget != NULL, FALSE);
-
-    /* Release our reference on the operation when this window is destroyed */    
-    g_object_set_data_full (G_OBJECT (swidget), "operation", operation, 
-                            (GDestroyNotify)g_object_unref);    
-
-    w = GTK_WIDGET (seahorse_widget_get_widget (swidget, swidget->name));
-    gtk_window_move (GTK_WINDOW (w), 10, 10);
-
-    /* Setup the title */
-    title = (const gchar*)g_object_get_data (G_OBJECT (operation), "progress-title");
-    if (title) {
-            
-        /* The window title */
-        w = GTK_WIDGET (seahorse_widget_get_widget (swidget, swidget->name));
-        g_return_val_if_fail (w != NULL, FALSE);
-        gtk_window_set_title (GTK_WINDOW (w), title);
-            
-        /* The main message title */
-        w = GTK_WIDGET (seahorse_widget_get_widget (swidget, "operation-title"));
-        g_return_val_if_fail (w != NULL, FALSE);
-        t = g_strdup_printf ("<b>%s</b>", title);
-        gtk_label_set_markup (GTK_LABEL (w), t);
-        g_free (t);
-    }
-
-    /* The details */        
-    progress_operation_update (operation, NULL, 
-                                seahorse_operation_get_progress (operation), swidget);
-    g_signal_connect (operation, "progress", 
-                      G_CALLBACK (progress_operation_update), swidget);
-
-    /* Cancel events */
-    g_signal_connect (seahorse_widget_get_toplevel (swidget), "delete_event",
-                      G_CALLBACK (progress_delete_event), operation);
-    
-    /* Done and cleanup */
-    w = GTK_WIDGET (seahorse_widget_get_widget (swidget, swidget->name));
-    g_signal_connect (w, "destroy", G_CALLBACK (progress_destroy), operation);
-    g_signal_connect (operation, "done", G_CALLBACK (progress_operation_done), swidget);
-
-    return FALSE;
+	TrackedTask *task = NULL;
+	SeahorseWidget *swidget;
+	GtkWidget *widget;
+	GtkWindow *window;
+	gchar *text;
+
+	/* Guard against going away before we display */
+	if (tracked_tasks)
+		task = g_hash_table_lookup (tracked_tasks, user_data);
+	if (task == NULL)
+		return FALSE; /* don't call again */
+
+	swidget = seahorse_widget_new_allow_multiple ("progress", NULL);
+	g_return_val_if_fail (swidget != NULL, FALSE);
+
+	window = GTK_WINDOW (seahorse_widget_get_toplevel (swidget));
+	g_signal_connect (window, "delete_event",
+	                  G_CALLBACK (on_window_delete_event), task->cancellable);
+	gtk_window_move (window, 10, 10);
+
+	/* Setup the title */
+	if (task->title) {
+		gtk_window_set_title (window, task->title);
+
+		/* The main message title */
+		widget = seahorse_widget_get_widget (swidget, "progress-title");
+		text = g_strdup_printf ("<b>%s</b>", task->title);
+		gtk_label_set_markup (GTK_LABEL (widget), text);
+		g_free (text);
+	}
+
+	/* Setup the cancel button */
+	widget = seahorse_widget_get_widget (swidget, "progress-cancel");
+	g_signal_connect (widget, "clicked", G_CALLBACK (on_cancel_button_clicked),
+	                  task->cancellable);
+
+	/* Allow attach to work */
+	task->showing = FALSE;
+	seahorse_progress_attach (task->cancellable, swidget);
+	gtk_widget_show (GTK_WIDGET (window));
+	g_object_unref (swidget);
+
+	return FALSE; /* don't call again */
 }
 
-/**
- * seahorse_progress_show:
- * @operation: The operation to create a progress window for
- * @title: Optional title of this window
- * @delayed: TRUE: wait 1 second before displaying the window
- *
- * Displays a progress window and adds an operation to it.
- *
- */
 void
-seahorse_progress_show (SeahorseOperation *operation, const gchar *title, 
+seahorse_progress_show (GCancellable *cancellable,
+                        const gchar *title,
                         gboolean delayed)
-{    
-    /* Unref in the timeout callback */
-    g_object_ref (operation);
-    g_object_set_data_full (G_OBJECT (operation), "progress-title", 
-                title ? g_strdup (title) : NULL, (GDestroyNotify)g_free);
-    
-    /* Show the progress, after one second */
-    if (delayed)
-        g_timeout_add_seconds (1, (GSourceFunc)progress_show, operation);
-    
-    /* Right away */
-    else
-        progress_show (operation);
+{
+	TrackedTask *task;
+
+	g_return_if_fail (title != NULL && title[0] != '\0');
+
+	if (!cancellable)
+		return;
+
+	g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+
+	task = progress_lookup_or_create_task (cancellable);
+
+	/* Perhaps already cancelled? */
+	if (task == NULL)
+		return;
+
+	if (task->showing) {
+		g_warning ("caller is trying to show progress for a task which already has displayed progress");
+		return;
+	}
+
+	g_free (task->title);
+	task->title = g_strdup (title);
+	task->showing = TRUE;
+
+	if (delayed)
+		g_timeout_add_seconds (2, on_timeout_show_progress, cancellable);
+	else
+		on_timeout_show_progress (cancellable);
+}
+
+void
+seahorse_progress_attach (GCancellable *cancellable,
+                          SeahorseWidget *swidget)
+{
+	TrackedTask *task;
+
+	if (!cancellable)
+		return;
+
+	g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+
+	task = progress_lookup_or_create_task (cancellable);
+
+	/* Perhaps already cancelled? */
+	if (task == NULL)
+		return;
+
+	if (task->showing) {
+		g_warning ("caller is trying to show progress for a task which already has displayed progress");
+		return;
+	}
+
+	task->showing = TRUE;
+	task->swidget = g_object_ref (swidget);
+
+	progress_update_display (task);
 }
diff --git a/libseahorse/seahorse-progress.h b/libseahorse/seahorse-progress.h
index 7587292..d3bf910 100644
--- a/libseahorse/seahorse-progress.h
+++ b/libseahorse/seahorse-progress.h
@@ -2,6 +2,7 @@
  * Seahorse
  *
  * Copyright (C) 2004 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
@@ -19,31 +20,41 @@
  * Boston, MA 02111-1307, USA.
  */
 
-/**
- * Functions for tying SeahorseOperation objects to the UI.
- */
- 
+/* Parts from evolution-data-server */
+
 #ifndef __SEAHORSE_PROGRESS_H__
 #define __SEAHORSE_PROGRESS_H__
 
-#include "seahorse-operation.h"
+#include <gio/gio.h>
+
 #include "seahorse-widget.h"
-#include "seahorse-context.h"
 
-/* -----------------------------------------------------------------------------
- * SEAHORSE APPBAR HOOKS
- */
+void          seahorse_progress_prep            (GCancellable *cancellable,
+                                                 gconstpointer progress_tag,
+                                                 const gchar *detail,
+                                                 ...);
+
+void          seahorse_progress_begin           (GCancellable *cancellable,
+                                                 gconstpointer progress_tag);
+
+void          seahorse_progress_prep_and_begin  (GCancellable *cancellable,
+                                                 gconstpointer progress_tag,
+                                                 const gchar *detail,
+                                                 ...);
+
+void          seahorse_progress_update          (GCancellable *cancellable,
+                                                 gconstpointer progress_tag,
+                                                 const gchar *detail,
+                                                 ...);
 
-/* Updates two glade widgets 'status' and 'progress' in the SeahorseWidget */
-void                seahorse_progress_status_set_operation      (SeahorseWidget *swidget,
-                                                                 SeahorseOperation *operation);
+void          seahorse_progress_end             (GCancellable *cancellable,
+                                                 gconstpointer progress_tag);
 
-/* Gets the operation set with above function */
-SeahorseOperation*  seahorse_progress_status_get_operation      (SeahorseWidget *swidget);
+void          seahorse_progress_show            (GCancellable *cancellable,
+                                                 const gchar *title,
+                                                 gboolean delayed);
 
-/* Keeps operation refed until progress dialog goes away */
-void                seahorse_progress_show                      (SeahorseOperation *operation,
-                                                                 const gchar *title,
-                                                                 gboolean delayed);
+void          seahorse_progress_attach          (GCancellable *cancellable,
+                                                 SeahorseWidget *swidget);
 
 #endif /* __SEAHORSE_PROGRESS_H__ */
diff --git a/libseahorse/seahorse-progress.xml b/libseahorse/seahorse-progress.xml
index 65b274c..ea61444 100644
--- a/libseahorse/seahorse-progress.xml
+++ b/libseahorse/seahorse-progress.xml
@@ -1,46 +1,81 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <requires lib="gtk+" version="2.16"/>
-  <!-- interface-naming-policy toplevel-contextual -->
   <object class="GtkDialog" id="progress">
     <property name="visible">True</property>
+    <property name="can_focus">False</property>
     <property name="border_width">5</property>
-    <property name="title" translatable="yes">Progress Title</property>
     <property name="window_position">center-on-parent</property>
     <property name="default_width">400</property>
     <property name="type_hint">dialog</property>
     <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox1">
+      <object class="GtkBox" id="dialog-vbox1">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
         <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="progress-cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
         <child>
           <object class="GtkVBox" id="vbox1">
             <property name="visible">True</property>
+            <property name="can_focus">False</property>
             <property name="border_width">5</property>
             <property name="spacing">12</property>
             <child>
               <object class="GtkHBox" id="hbox1">
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="spacing">12</property>
                 <child>
                   <object class="GtkImage" id="image1">
                     <property name="visible">True</property>
+                    <property name="can_focus">False</property>
                     <property name="stock">gtk-dialog-authentication</property>
                     <property name="icon-size">6</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
+                    <property name="fill">True</property>
                     <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
                   <object class="GtkVBox" id="vbox2">
                     <property name="visible">True</property>
+                    <property name="can_focus">False</property>
                     <child>
-                      <object class="GtkLabel" id="operation-title">
+                      <object class="GtkLabel" id="progress-title">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="xalign">0</property>
-                        <property name="label">&lt;b&gt;Progress Message&lt;/b&gt;</property>
                         <property name="use_markup">True</property>
                       </object>
                       <packing>
@@ -50,8 +85,9 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkLabel" id="operation-details">
+                      <object class="GtkLabel" id="progress-details">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="xalign">0</property>
                         <property name="label">Progress Status</property>
                       </object>
@@ -66,17 +102,22 @@
                     </child>
                   </object>
                   <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
               </object>
               <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
                 <property name="position">0</property>
               </packing>
             </child>
             <child>
-              <object class="GtkProgressBar" id="operation-bar">
+              <object class="GtkProgressBar" id="progress-bar">
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="pulse_step">0.10000000149</property>
               </object>
               <packing>
@@ -87,41 +128,15 @@
             </child>
           </object>
           <packing>
-            <property name="expand">False</property>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
             <property name="position">1</property>
           </packing>
         </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area1">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="cancel">
-                <property name="label">gtk-cancel</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <signal name="clicked" handler="on_progress_operation_cancel"/>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
       </object>
     </child>
     <action-widgets>
-      <action-widget response="-6">cancel</action-widget>
+      <action-widget response="0">progress-cancel</action-widget>
     </action-widgets>
   </object>
 </interface>
diff --git a/libseahorse/seahorse-source.c b/libseahorse/seahorse-source.c
index 1baf3c7..bb8d173 100644
--- a/libseahorse/seahorse-source.c
+++ b/libseahorse/seahorse-source.c
@@ -100,316 +100,331 @@ seahorse_source_get_type (void)
  * PUBLIC
  */
 
-/**
- * seahorse_source_load:
- * @sksrc: A #SeahorseSource object
- *
- * Refreshes the #SeahorseSource's internal object listing.
- *
- * Returns: the asynchronous refresh operation.
- **/
-SeahorseOperation*
-seahorse_source_load (SeahorseSource *sksrc)
+void
+seahorse_source_load_async (SeahorseSource *source,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
 {
-    SeahorseSourceIface *klass;
-    
-    g_return_val_if_fail (SEAHORSE_IS_SOURCE (sksrc), NULL);
-    klass = SEAHORSE_SOURCE_GET_INTERFACE (sksrc);
-    g_return_val_if_fail (klass->load != NULL, NULL);
-    
-    return (*klass->load) (sksrc);
+	g_return_if_fail (SEAHORSE_IS_SOURCE (source));
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+	g_return_if_fail (SEAHORSE_SOURCE_GET_INTERFACE (source)->load_async);
+	SEAHORSE_SOURCE_GET_INTERFACE (source)->load_async (source, cancellable,
+	                                                  callback, user_data);
+}
+
+gboolean
+seahorse_source_load_finish (SeahorseSource *source,
+                             GAsyncResult *result,
+                             GError **error)
+{
+	g_return_val_if_fail (SEAHORSE_IS_SOURCE (source), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	g_return_val_if_fail (SEAHORSE_SOURCE_GET_INTERFACE (source)->load_finish, FALSE);
+	return SEAHORSE_SOURCE_GET_INTERFACE (source)->load_finish (source, result, error);
 }
 
-/**
- * seahorse_source_load_sync:
- * @sksrc: A #SeahorseSource object
- * 
- * Refreshes the #SeahorseSource's internal object listing, and waits for it to complete.
- **/
 void
-seahorse_source_load_sync (SeahorseSource *sksrc)
+seahorse_source_search_async (SeahorseSource *source,
+                              const gchar *match,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
 {
-    SeahorseOperation *op = seahorse_source_load (sksrc);
-    g_return_if_fail (op != NULL);
-    seahorse_operation_wait (op);
-    g_object_unref (op);
+	g_return_if_fail (SEAHORSE_IS_SOURCE (source));
+	g_return_if_fail (match != NULL);
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+	g_return_if_fail (SEAHORSE_SOURCE_GET_INTERFACE (source)->search_async);
+	SEAHORSE_SOURCE_GET_INTERFACE (source)->search_async (source, match, cancellable,
+	                                                    callback, user_data);
+}
+
+GList *
+seahorse_source_search_finish (SeahorseSource *source, GAsyncResult *result,
+                               GError **error)
+{
+	g_return_val_if_fail (SEAHORSE_IS_SOURCE (source), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+	g_return_val_if_fail (SEAHORSE_SOURCE_GET_INTERFACE (source)->search_finish, NULL);
+	return SEAHORSE_SOURCE_GET_INTERFACE (source)->search_finish (source, result, error);
 }
 
-/**
- * seahorse_source_load_sync:
- * @sksrc: A #SeahorseSource object
- * 
- * Refreshes the #SeahorseSource's internal object listing. Completes in the background.
- **/
 void
-seahorse_source_load_async (SeahorseSource *sksrc)
+seahorse_source_import_async (SeahorseSource *source,
+                              GInputStream *input,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
 {
-    SeahorseOperation *op = seahorse_source_load (sksrc);
-    g_return_if_fail (op != NULL);
-    g_object_unref (op);
+	g_return_if_fail (SEAHORSE_IS_SOURCE (source));
+	g_return_if_fail (G_IS_INPUT_STREAM (input));
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+	g_return_if_fail (SEAHORSE_SOURCE_GET_INTERFACE (source)->import_async);
+	SEAHORSE_SOURCE_GET_INTERFACE (source)->import_async (source, input, cancellable,
+	                                                    callback, user_data);
 }
 
-/**
- * seahorse_source_search:
- * @sksrc: A #SeahorseSource object
- * @match: Text to search for
- * 
- * Refreshes the #SeahorseSource's internal listing. 
- * 
- * Returns: the asynchronous refresh operation.
- **/
-SeahorseOperation*
-seahorse_source_search (SeahorseSource *sksrc, const gchar *match)
+GList *
+seahorse_source_import_finish (SeahorseSource *source,
+                               GAsyncResult *result,
+                               GError **error)
 {
-    SeahorseSourceIface *klass;
-    
-    g_return_val_if_fail (SEAHORSE_IS_SOURCE (sksrc), NULL);
-    klass = SEAHORSE_SOURCE_GET_INTERFACE (sksrc);
-    g_return_val_if_fail (klass->search != NULL, NULL);
-    
-    return (*klass->search) (sksrc, match);
+	g_return_val_if_fail (SEAHORSE_IS_SOURCE (source), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+	g_return_val_if_fail (SEAHORSE_SOURCE_GET_INTERFACE (source)->import_finish, NULL);
+	return SEAHORSE_SOURCE_GET_INTERFACE (source)->import_finish (source, result, error);
 }
 
-/**
- * seahorse_source_import:
- * @sksrc: A #SeahorseSource object
- * @input: A stream of data to import
- *
- * Imports data from the stream
- *
- * Returns: the asynchronous import operation
- */
-SeahorseOperation* 
-seahorse_source_import (SeahorseSource *sksrc, GInputStream *input)
+void
+seahorse_source_export_async (SeahorseSource *source,
+                              GList *objects,
+                              GOutputStream *output,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
 {
-	SeahorseSourceIface *klass;
-    
-	g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
-    
-	g_return_val_if_fail (SEAHORSE_IS_SOURCE (sksrc), NULL);
-	klass = SEAHORSE_SOURCE_GET_INTERFACE (sksrc);   
-	g_return_val_if_fail (klass->import != NULL, NULL);
-    
-	return (*klass->import) (sksrc, input);  
+	SeahorseSourceIface *iface;
+	GList *l;
+	GList *ids;
+
+	g_return_if_fail (SEAHORSE_IS_SOURCE (source));
+	g_return_if_fail (G_IS_OUTPUT_STREAM (output));
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+	iface = SEAHORSE_SOURCE_GET_INTERFACE (source);
+	g_return_if_fail (iface->export_async != NULL || iface->export_raw_async != NULL);
+
+	if (iface->export_async) {
+		iface->export_async (source, objects, output,
+		                     cancellable, callback, user_data);
+		return;
+	}
+
+	for (l = objects; l != NULL; l = g_list_next (l))
+		ids = g_list_prepend (ids, GUINT_TO_POINTER (seahorse_object_get_id (l->data)));
+
+	ids = g_list_reverse (ids);
+	(iface->export_raw_async) (source, ids, output, cancellable, callback, user_data);
+	g_list_free (ids);
 }
 
-/**
- * seahorse_source_import_sync:
- * @sksrc: The #SeahorseSource
- * @input: the input data
- * @err: error
- *
- * Imports data from the stream
- *
- * Returns: Imports the stream, synchronous
- */
-gboolean            
-seahorse_source_import_sync (SeahorseSource *sksrc, GInputStream *input,
-                             GError **err)
+GOutputStream *
+seahorse_source_export_finish (SeahorseSource *source,
+                               GAsyncResult *result,
+                               GError **error)
 {
-	SeahorseOperation *op;
-    	gboolean ret;
-
-	g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE);
-
-	op = seahorse_source_import (sksrc, input);
-	g_return_val_if_fail (op != NULL, FALSE);
-    
-	seahorse_operation_wait (op);
-	ret = seahorse_operation_is_successful (op);
-	if (!ret)
-		seahorse_operation_copy_error (op, err);
-    
-	g_object_unref (op);
-	return ret;    
+	SeahorseSourceIface *iface;
+
+	g_return_val_if_fail (SEAHORSE_IS_SOURCE (source), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	iface = SEAHORSE_SOURCE_GET_INTERFACE (source);
+	g_return_val_if_fail (iface->export_async != NULL || iface->export_raw_async != NULL, NULL);
+
+	if (iface->export_async) {
+		g_return_val_if_fail (iface->export_finish, NULL);
+		return (iface->export_finish) (source, result, error);
+	} else {
+		g_return_val_if_fail (iface->export_raw_finish, NULL);
+		return (iface->export_raw_finish) (source, result, error);
+	}
 }
 
-/**
- * seahorse_source_export_objects:
- * @objects: The objects to export
- * @output: The output stream to export the objects to
- *
- * Exports objects. The objects are sorted by source.
- *
- * Returns: The #SeahorseOperation created to export the data
- */
-SeahorseOperation*
-seahorse_source_export_objects (GList *objects, GOutputStream *output)
+typedef struct {
+	GOutputStream *output;
+	guint exports;
+} export_auto_closure;
+
+static void
+export_auto_free (gpointer data)
 {
-    SeahorseOperation *op = NULL;
-    SeahorseMultiOperation *mop = NULL;
-    SeahorseSource *sksrc;
-    SeahorseObject *sobj;
-    GList *next;
-    
-	g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), NULL);
-	g_object_ref (output);
-
-    /* Sort by object source */
-    objects = g_list_copy (objects);
-    objects = seahorse_util_objects_sort (objects);
-    
-    while (objects) {
-     
-        /* Break off one set (same source) */
-        next = seahorse_util_objects_splice (objects);
-
-        g_assert (SEAHORSE_IS_OBJECT (objects->data));
-        sobj = SEAHORSE_OBJECT (objects->data);
-
-        /* Export from this object source */        
-        sksrc = seahorse_object_get_source (sobj);
-        g_return_val_if_fail (sksrc != NULL, FALSE);
-        
-        if (op != NULL) {
-            if (mop == NULL)
-                mop = seahorse_multi_operation_new ();
-            seahorse_multi_operation_take (mop, op);
-        }
-        
-        /* We pass our own data object, to which data is appended */
-        op = seahorse_source_export (sksrc, objects, output);
-        g_return_val_if_fail (op != NULL, FALSE);
-
-        g_list_free (objects);
-        objects = next;
-    }
-    
-    if (mop) {
-        op = SEAHORSE_OPERATION (mop);
-        
-        /* 
-         * Setup the result data properly, as we would if it was a 
-         * single export operation.
-         */
-        seahorse_operation_mark_result (op, output, g_object_unref);
-    }
-    
-    if (!op) 
-        op = seahorse_operation_new_complete (NULL);
-    
-    return op;
+	export_auto_closure *closure = data;
+	g_object_unref (closure->output);
+	g_free (closure);
 }
 
-/**
- * seahorse_source_delete_objects:
- * @objects: A list of objects to delete
- *
- * Deletes a list of objects
- *
- * Returns: The #SeahorseOperation to delete the objects
- */
-SeahorseOperation*
-seahorse_source_delete_objects (GList *objects)
+static void
+on_export_auto_complete (GObject *source,
+                         GAsyncResult *result,
+                         gpointer user_data)
 {
-	SeahorseOperation *op = NULL;
-	SeahorseMultiOperation *mop = NULL;
-	SeahorseObject *sobj;
-	GList *l;
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	export_auto_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
 
-	for (l = objects; l; l = g_list_next (l)) {
-		
-		sobj = SEAHORSE_OBJECT (l->data);
-		g_return_val_if_fail (SEAHORSE_IS_OBJECT (sobj), NULL);;
-		
-		if (op != NULL) {
-			if (mop == NULL)
-				mop = seahorse_multi_operation_new ();
-			seahorse_multi_operation_take (mop, op);
-		}
-
-		op = seahorse_object_delete (sobj);
-		g_return_val_if_fail (op != NULL, NULL);
+	if (!seahorse_source_export_finish (SEAHORSE_SOURCE (source), result, &error))
+		g_simple_async_result_take_error (res, error);
+
+	g_assert (closure->exports > 0);
+	closure->exports--;
+
+	if (closure->exports == 0)
+		g_simple_async_result_complete (res);
+
+	g_object_unref (res);
+}
+
+void
+seahorse_source_export_auto_async (GList *objects,
+                                   GOutputStream *output,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+	export_auto_closure *closure;
+	SeahorseSource *source;
+	SeahorseObject *object;
+	GList *next;
+
+	res = g_simple_async_result_new (NULL, callback, user_data,
+	                                 seahorse_source_export_auto_async);
+	closure = g_new0 (export_auto_closure, 1);
+	closure->output = g_object_ref (output);
+	g_simple_async_result_set_op_res_gpointer (res, closure, export_auto_free);
+
+	/* Sort by object source */
+	objects = g_list_copy (objects);
+	objects = seahorse_util_objects_sort (objects);
+
+	while (objects) {
+
+		/* Break off one set (same source) */
+		next = seahorse_util_objects_splice (objects);
+
+		g_assert (SEAHORSE_IS_OBJECT (objects->data));
+		object = SEAHORSE_OBJECT (objects->data);
+
+		/* Export from this object source */
+		source = seahorse_object_get_source (object);
+		g_return_if_fail (source != NULL);
+
+		/* We pass our own data object, to which data is appended */
+		seahorse_source_export_async (source, objects, output, cancellable,
+		                              on_export_auto_complete, g_object_ref (res));
+		closure->exports++;
+
+		g_list_free (objects);
+		objects = next;
 	}
-    
-	if (mop) 
-		op = SEAHORSE_OPERATION (mop);
-    
-	if (!op) 
-		op = seahorse_operation_new_complete (NULL);
-    
-	return op;
+
+	if (closure->exports == 0)
+		g_simple_async_result_complete_in_idle (res);
+
+	g_object_unref (res);
 }
 
-/**
- * seahorse_source_export:
- * @sksrc: The SeahorseSource
- * @objects: The objects to export
- * @output: The resulting output stream
- *
- *
- *
- * Returns: An export Operation (#SeahorseOperation)
- */
-SeahorseOperation* 
-seahorse_source_export (SeahorseSource *sksrc, GList *objects, GOutputStream *output)
+GOutputStream *
+seahorse_source_export_auto_finish (GAsyncResult *result,
+                                    GError **error)
 {
-	SeahorseSourceIface *klass;
-	SeahorseOperation *op;
-	GList *ids = NULL;
-	GList *l;
-    
-	g_return_val_if_fail (SEAHORSE_IS_SOURCE (sksrc), NULL);
-	g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), NULL);
-	
-	klass = SEAHORSE_SOURCE_GET_INTERFACE (sksrc);   
-	if (klass->export)
-		return (*klass->export) (sksrc, objects, output);
+	export_auto_closure *closure;
 
-	/* Either export or export_raw must be implemented */
-	g_return_val_if_fail (klass->export_raw != NULL, NULL);
-    
-	for (l = objects; l; l = g_list_next (l)) 
-		ids = g_list_prepend (ids, GUINT_TO_POINTER (seahorse_object_get_id (l->data)));
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+	                      seahorse_source_export_auto_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	return closure->output;
 
-	ids = g_list_reverse (ids);
-	op = (*klass->export_raw) (sksrc, ids, output);	
-	g_list_free (ids);
-	return op;
 }
 
-/**
- * seahorse_source_export_raw:
- * @sksrc: The SeahorseSource
- * @ids: A list of IDs to export
- * @output: The resulting output stream
- *
- *
- *
- * Returns: An export Operation (#SeahorseOperation)
- */
-SeahorseOperation* 
-seahorse_source_export_raw (SeahorseSource *sksrc, GList *ids, GOutputStream *output)
+static void
+on_export_auto_wait_complete (GObject *source,
+                              GAsyncResult *result,
+                              gpointer user_data)
+{
+	GAsyncResult **ret = user_data;
+	*ret = g_object_ref (result);
+}
+
+gboolean
+seahorse_source_export_auto_wait (GList *objects,
+                                  GOutputStream *output,
+                                  GError **error)
+{
+	GAsyncResult *result = NULL;
+	gboolean ret;
+
+	seahorse_source_export_auto_async (objects, output, NULL,
+	                                   on_export_auto_wait_complete,
+	                                   &result);
+
+	seahorse_util_wait_until (result != NULL);
+
+	ret = seahorse_source_export_auto_finish (result, error) != NULL;
+	g_object_unref (result);
+	return ret;
+}
+
+void
+seahorse_source_export_raw_async (SeahorseSource *source,
+                                  GList *ids,
+                                  GOutputStream *output,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
 {
-	SeahorseSourceIface *klass;
-	SeahorseOperation *op;
-	SeahorseObject *sobj;
+	SeahorseSourceIface *iface;
+	SeahorseObject *object;
 	GList *objects = NULL;
 	GList *l;
 
-	g_return_val_if_fail (SEAHORSE_IS_SOURCE (sksrc), NULL);
-	g_return_val_if_fail (output == NULL || G_IS_OUTPUT_STREAM (output), NULL);
+	g_return_if_fail (SEAHORSE_IS_SOURCE (source));
+	g_return_if_fail (output == NULL || G_IS_OUTPUT_STREAM (output));
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+	iface = SEAHORSE_SOURCE_GET_INTERFACE (source);
 
-	klass = SEAHORSE_SOURCE_GET_INTERFACE (sksrc);   
-    
 	/* Either export or export_raw must be implemented */
-	if (klass->export_raw)
-		return (*klass->export_raw)(sksrc, ids, output);
-    
-	g_return_val_if_fail (klass->export != NULL, NULL);
-
-	for (l = ids; l; l = g_list_next (l)) {
-		sobj = seahorse_context_get_object (SCTX_APP (), sksrc, GPOINTER_TO_UINT (l->data));
-        
+	if (iface->export_raw_async) {
+		(iface->export_raw_async) (source, ids, output, cancellable, callback, user_data);
+		return;
+	}
+
+	g_return_if_fail (iface->export_async != NULL);
+
+	for (l = ids; l != NULL; l = g_list_next (l)) {
+		object = seahorse_context_get_object (seahorse_context_instance (),
+		                                      source, GPOINTER_TO_UINT (l->data));
+
 		/* TODO: A proper error message here 'not found' */
-		if (sobj)
-			objects = g_list_prepend (objects, sobj);
+		if (object != NULL)
+			objects = g_list_prepend (objects, object);
 	}
-    
+
 	objects = g_list_reverse (objects);
-	op = (*klass->export) (sksrc, objects, output);
+	(iface->export_async) (source, objects, output, cancellable, callback, user_data);
 	g_list_free (objects);
-	return op;
+}
+
+GOutputStream *
+seahorse_source_export_raw_finish (SeahorseSource *source,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	SeahorseSourceIface *iface;
+
+	g_return_val_if_fail (SEAHORSE_IS_SOURCE (source), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	iface = SEAHORSE_SOURCE_GET_INTERFACE (source);
+	g_return_val_if_fail (iface->export_async != NULL || iface->export_raw_async != NULL, NULL);
+
+	if (iface->export_raw_async) {
+		g_return_val_if_fail (iface->export_raw_finish, NULL);
+		return (iface->export_raw_finish) (source, result, error);
+	} else {
+		g_return_val_if_fail (iface->export_finish, NULL);
+		return (iface->export_finish) (source, result, error);
+	}
 }
 
 /**
diff --git a/libseahorse/seahorse-source.h b/libseahorse/seahorse-source.h
index 3f9e85a..28854db 100644
--- a/libseahorse/seahorse-source.h
+++ b/libseahorse/seahorse-source.h
@@ -41,7 +41,6 @@
 #ifndef __SEAHORSE_SOURCE_H__
 #define __SEAHORSE_SOURCE_H__
 
-#include "seahorse-operation.h"
 #include "seahorse-types.h"
 
 #include <gio/gio.h>
@@ -59,110 +58,131 @@ typedef struct _SeahorseSourceIface SeahorseSourceIface;
 
 struct _SeahorseSourceIface {
 	GTypeInterface parent;
-    
+
 	/* virtual methods ------------------------------------------------- */
 
-	/**
-	 * load
-	 * @sksrc: The #SeahorseSource.
-	 * 
-	 * Loads the requested objects, and add the objects to SeahorseContext. 
-	 * 
-	 * Returns: The load operation.
-	 */
-	SeahorseOperation* (*load) (SeahorseSource *sksrc);
-
-	/**
-	 * search
-	 * @sksrc: The #SeahorseSource 
-	 * @match: Match text
-	 *
-	 * Searches for objects in the source.
-	 *
-	 * Returns: The search operation.
-	 */
-	SeahorseOperation* (*search) (SeahorseSource *sksrc, const gchar *match);
-
-    
-	/**
-	 * import
-	 * @sksrc: The #SeahorseSource to import into.
-	 * @input: The data to import.
-	 *
-	 * Import objects into the source. When operation is 'done' a GList of 
-	 * updated objects may be found as the operation result. 
-	 * 
-	 * Returns: The import operation
-	 */
-	SeahorseOperation* (*import) (SeahorseSource *sksrc, GInputStream *input);
-
-	/**
-	 * export
-	 * @sksrc: The #SeahorseSource to export from.
-	 * @objects: A list of objects to export.
-	 * @output: Output stream to export to.
-	 *
-	 * Import objects into the object source. When operation is 'done' the result
-	 * of the operation will be a GOutputStream
-	 * 
-	 * Returns: The export operation
-	 */
-	SeahorseOperation* (*export) (SeahorseSource *sksrc, GList *objects, GOutputStream *output);
-
-	/**
-	 * export_raw
-	 * @sksrc: The #SeahorseSource to export from.
-	 * @ids: A list of ids to export.
-	 * @data: output stream to export to.
-	 *
-	 * Import objects into the source. When operation is 'done' the result
-	 * of the operation will be a GOutputStream
-	 * 
-	 * Returns: The export operation
-	 */
-	SeahorseOperation* (*export_raw) (SeahorseSource *sksrc, GList *ids,
-	                                  GOutputStream *output);
-    
+	void            (*load_async)                (SeahorseSource *source,
+	                                              GCancellable *cancellable,
+	                                              GAsyncReadyCallback callback,
+	                                              gpointer user_data);
+
+	gboolean        (*load_finish)               (SeahorseSource *source,
+	                                              GAsyncResult *result,
+	                                              GError **error);
+
+	void            (*search_async)              (SeahorseSource *source,
+	                                              const gchar *match,
+	                                              GCancellable *cancellable,
+	                                              GAsyncReadyCallback callback,
+	                                              gpointer user_data);
+
+	GList *         (*search_finish)             (SeahorseSource *source,
+	                                              GAsyncResult *result,
+	                                              GError **error);
+
+	void            (*import_async)              (SeahorseSource *source,
+	                                              GInputStream *input,
+	                                              GCancellable *cancellable,
+	                                              GAsyncReadyCallback callback,
+	                                              gpointer user_data);
+
+	GList *         (*import_finish)             (SeahorseSource *source,
+	                                              GAsyncResult *result,
+	                                              GError **error);
+
+	void            (*export_async)              (SeahorseSource *source,
+	                                              GList *objects,
+	                                              GOutputStream *output,
+	                                              GCancellable *cancellable,
+	                                              GAsyncReadyCallback callback,
+	                                              gpointer user_data);
+
+	GOutputStream * (*export_finish)             (SeahorseSource *source,
+	                                              GAsyncResult *result,
+	                                              GError **error);
+
+	void            (*export_raw_async)          (SeahorseSource *source,
+	                                              GList *ids,
+	                                              GOutputStream *output,
+	                                              GCancellable *cancellable,
+	                                              GAsyncReadyCallback callback,
+	                                              gpointer user_data);
+
+	GOutputStream * (*export_raw_finish)         (SeahorseSource *source,
+	                                              GAsyncResult *result,
+	                                              GError **error);
 };
 
-GType               seahorse_source_get_type             (void) G_GNUC_CONST;
+GType            seahorse_source_get_type             (void) G_GNUC_CONST;
 
 /* Method helper functions ------------------------------------------- */
 
-
-SeahorseOperation*  seahorse_source_load                  (SeahorseSource *sksrc);
-                                                          
-void                seahorse_source_load_sync             (SeahorseSource *sksrc);
-
-void                seahorse_source_load_async            (SeahorseSource *sksrc);
-
-SeahorseOperation*  seahorse_source_search                (SeahorseSource *sksrc,
-                                                           const gchar *match);
-
-/* Takes ownership of |data| */
-SeahorseOperation*  seahorse_source_import                (SeahorseSource *sksrc,
-                                                           GInputStream *input);
-
-/* Takes ownership of |data| */
-gboolean            seahorse_source_import_sync           (SeahorseSource *sksrc,
-                                                           GInputStream *input,
-                                                           GError **err);
-
-SeahorseOperation*  seahorse_source_export_objects        (GList *objects, 
-                                                           GOutputStream *output);
-
-SeahorseOperation*  seahorse_source_delete_objects        (GList *objects);
-
-SeahorseOperation*  seahorse_source_export                (SeahorseSource *sksrc,
-                                                           GList *objects,
-                                                           GOutputStream *output);
-
-SeahorseOperation*  seahorse_source_export_raw            (SeahorseSource *sksrc, 
-                                                           GList *ids,
-                                                           GOutputStream *output);
-
-GQuark              seahorse_source_get_tag               (SeahorseSource *sksrc);
-
-SeahorseLocation    seahorse_source_get_location          (SeahorseSource *sksrc);
+void             seahorse_source_load_async           (SeahorseSource *source,
+                                                       GCancellable *cancellable,
+                                                       GAsyncReadyCallback callback,
+                                                       gpointer user_data);
+
+gboolean         seahorse_source_load_finish          (SeahorseSource *source,
+                                                       GAsyncResult *result,
+                                                       GError **error);
+
+void             seahorse_source_search_async         (SeahorseSource *source,
+                                                       const gchar *match,
+                                                       GCancellable *cancellable,
+                                                       GAsyncReadyCallback callback,
+                                                       gpointer user_data);
+
+GList *          seahorse_source_search_finish        (SeahorseSource *source,
+                                                       GAsyncResult *result,
+                                                       GError **error);
+
+void             seahorse_source_import_async         (SeahorseSource *source,
+                                                       GInputStream *input,
+                                                       GCancellable *cancellable,
+                                                       GAsyncReadyCallback callback,
+                                                       gpointer user_data);
+
+GList *          seahorse_source_import_finish        (SeahorseSource *source,
+                                                       GAsyncResult *result,
+                                                       GError **error);
+
+void             seahorse_source_export_async         (SeahorseSource *source,
+                                                       GList *objects,
+                                                       GOutputStream *output,
+                                                       GCancellable *cancellable,
+                                                       GAsyncReadyCallback callback,
+                                                       gpointer user_data);
+
+GOutputStream *  seahorse_source_export_finish        (SeahorseSource *source,
+                                                       GAsyncResult *result,
+                                                       GError **error);
+
+void             seahorse_source_export_auto_async    (GList *objects,
+                                                       GOutputStream *output,
+                                                       GCancellable *cancellable,
+                                                       GAsyncReadyCallback callback,
+                                                       gpointer user_data);
+
+GOutputStream *  seahorse_source_export_auto_finish   (GAsyncResult *result,
+                                                       GError **error);
+
+gboolean         seahorse_source_export_auto_wait     (GList *objects,
+                                                       GOutputStream *output,
+                                                       GError **error);
+
+void             seahorse_source_export_raw_async     (SeahorseSource *source,
+                                                       GList *ids,
+                                                       GOutputStream *output,
+                                                       GCancellable *cancellable,
+                                                       GAsyncReadyCallback callback,
+                                                       gpointer user_data);
+
+GOutputStream *  seahorse_source_export_raw_finish    (SeahorseSource *source,
+                                                       GAsyncResult *result,
+                                                       GError **error);
+
+GQuark           seahorse_source_get_tag              (SeahorseSource *source);
+
+SeahorseLocation seahorse_source_get_location         (SeahorseSource *source);
 
 #endif /* __SEAHORSE_SOURCE_H__ */
diff --git a/libseahorse/seahorse-transfer.c b/libseahorse/seahorse-transfer.c
new file mode 100644
index 0000000..c5636c6
--- /dev/null
+++ b/libseahorse/seahorse-transfer.c
@@ -0,0 +1,204 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2006 Stefan Walter
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <glib/gi18n.h>
+
+#include "seahorse-transfer.h"
+#include "seahorse-progress.h"
+#include "seahorse-util.h"
+
+#define DEBUG_FLAG SEAHORSE_DEBUG_OPERATION
+#include "seahorse-debug.h"
+
+typedef struct {
+	GCancellable *cancellable;
+	SeahorseSource *from;
+	SeahorseSource *to;
+	GOutputStream *output;
+	GList *keyids;
+} transfer_closure;
+
+static void
+transfer_closure_free (gpointer user_data)
+{
+	transfer_closure *closure = user_data;
+
+	g_clear_object (&closure->from);
+	g_clear_object (&closure->to);
+	g_clear_object (&closure->output);
+	g_clear_object (&closure->cancellable);
+	g_list_free (closure->keyids);
+	g_free (closure);
+}
+
+static void
+on_source_import_ready (GObject *object,
+                        GAsyncResult *result,
+                        gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	transfer_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	seahorse_debug ("[transfer] import done");
+	seahorse_progress_end (closure->cancellable, &closure->to);
+
+	if (seahorse_source_import_finish (closure->to, result, &error))
+		g_cancellable_set_error_if_cancelled (closure->cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (res, error);
+
+	g_simple_async_result_complete (res);
+	g_object_unref (user_data);
+}
+
+static void
+on_source_export_ready (GObject *object,
+                        GAsyncResult *result,
+                        gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	transfer_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	gpointer stream_data;
+	gsize stream_size;
+	GInputStream *input;
+
+	seahorse_debug ("[transfer] export done");
+	seahorse_progress_end (closure->cancellable, &closure->from);
+
+	if (seahorse_source_export_raw_finish (closure->from, result, &error))
+		g_cancellable_set_error_if_cancelled (closure->cancellable, &error);
+
+	if (error == NULL) {
+		seahorse_progress_begin (closure->cancellable, &closure->to);
+
+		stream_data = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (closure->output));
+		stream_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (closure->output));
+
+		if (!stream_size) {
+			seahorse_debug ("[transfer] nothing to import");
+			seahorse_progress_end (closure->cancellable, &closure->to);
+			g_simple_async_result_complete (res);
+
+		} else {
+			input = g_memory_input_stream_new_from_data (g_memdup (stream_data, stream_size),
+			                                             stream_size, g_free);
+
+			seahorse_debug ("[transfer] starting import");
+			seahorse_source_import_async (closure->to, input, closure->cancellable,
+			                              on_source_import_ready, g_object_ref (res));
+			g_object_unref (input);
+		}
+
+	} else {
+		seahorse_debug ("[transfer] stopped after export");
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+	}
+
+	g_object_unref (user_data);
+}
+
+static gboolean
+on_timeout_start_transfer (gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	transfer_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+
+	g_assert (SEAHORSE_IS_SOURCE (closure->from));
+	g_assert (closure->keyids);
+
+	seahorse_progress_begin (closure->cancellable, &closure->from);
+	seahorse_source_export_raw_async (closure->from, closure->keyids, closure->output,
+	                                  closure->cancellable, on_source_export_ready,
+	                                  g_object_ref (res));
+
+	return FALSE; /* Don't run again */
+}
+
+void
+seahorse_transfer_async (SeahorseSource *from,
+                         SeahorseSource *to,
+                         GList *keyids,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+	transfer_closure *closure = NULL;
+	SeahorseLocation location;
+
+	g_return_if_fail (SEAHORSE_SOURCE (from));
+	g_return_if_fail (SEAHORSE_SOURCE (to));
+
+	res = g_simple_async_result_new (NULL, callback, user_data,
+	                                 seahorse_transfer_async);
+
+	if (!keyids) {
+		g_simple_async_result_complete_in_idle (res);
+		g_object_unref (res);
+		return;
+	}
+
+	closure = g_new0 (transfer_closure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable;
+	closure->from = g_object_ref (from);
+	closure->to = g_object_ref (to);
+	closure->keyids = g_list_copy (keyids);
+	closure->output = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+	g_simple_async_result_set_op_res_gpointer (res, closure, transfer_closure_free);
+
+	location = seahorse_source_get_location (from);
+	seahorse_progress_prep (cancellable, &closure->from,
+	                        (location == SEAHORSE_LOCATION_REMOTE) ?
+	                        _("Retrieving data") : _("Exporting data"));
+	location = seahorse_source_get_location (to);
+	seahorse_progress_prep (cancellable, &closure->to,
+	                        (location == SEAHORSE_LOCATION_REMOTE) ?
+	                        _("Importing data") : _("Sending data"));
+
+	seahorse_debug ("starting export");
+
+	/* We delay and continue from a callback */
+	g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, 0,
+	                            on_timeout_start_transfer,
+	                            g_object_ref (res), g_object_unref);
+
+	g_object_unref (res);
+}
+
+gboolean
+seahorse_transfer_finish (GAsyncResult *result,
+                          GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+	                      seahorse_transfer_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
diff --git a/libseahorse/seahorse-transfer.h b/libseahorse/seahorse-transfer.h
new file mode 100644
index 0000000..fe8780b
--- /dev/null
+++ b/libseahorse/seahorse-transfer.h
@@ -0,0 +1,37 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2006 Stefan Walter
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SEAHORSE_TRANSFER_H__
+#define __SEAHORSE_TRANSFER_H__
+
+#include "seahorse-source.h"
+
+void            seahorse_transfer_async         (SeahorseSource *from,
+                                                 SeahorseSource *to,
+                                                 GList *keyids,
+                                                 GCancellable *cancellable,
+                                                 GAsyncReadyCallback callback,
+                                                 gpointer user_data);
+
+gboolean        seahorse_transfer_finish        (GAsyncResult *result,
+                                                 GError **error);
+
+#endif /* __SEAHORSE_TRANSFER_H__ */
diff --git a/libseahorse/seahorse-unknown-source.c b/libseahorse/seahorse-unknown-source.c
index c78d52f..d24b731 100644
--- a/libseahorse/seahorse-unknown-source.c
+++ b/libseahorse/seahorse-unknown-source.c
@@ -37,31 +37,15 @@ enum {
     PROP_CONSTRUCT_TAG,
 };
 
-static void seahorse_source_iface (SeahorseSourceIface *iface);
+static void     seahorse_source_iface    (SeahorseSourceIface *iface);
 
 G_DEFINE_TYPE_EXTENDED (SeahorseUnknownSource, seahorse_unknown_source, G_TYPE_OBJECT, 0,
                         G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_SOURCE, seahorse_source_iface));
 
 /* -----------------------------------------------------------------------------
- * INTERNAL
- */
-
-static void
-search_done (SeahorseOperation *op, SeahorseObject *sobj)
-{
-	g_object_set (sobj, "location", SEAHORSE_LOCATION_MISSING, NULL);
-}
-
-/* -----------------------------------------------------------------------------
  * OBJECT
  */
 
-static SeahorseOperation*
-seahorse_unknown_source_load (SeahorseSource *src)
-{ 
-	return seahorse_operation_new_complete (NULL);
-}
-
 static void 
 seahorse_unknown_source_set_property (GObject *object, guint prop_id, const GValue *value, 
                                       GParamSpec *pspec)
@@ -125,42 +109,83 @@ seahorse_unknown_source_class_init (SeahorseUnknownSourceClass *klass)
 	seahorse_registry_register_type (NULL, SEAHORSE_TYPE_UNKNOWN_SOURCE, "source", NULL);
 }
 
+
+static void
+seahorse_unknown_source_load_async (SeahorseSource *source,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_unknown_source_load_async);
+
+	g_simple_async_result_complete_in_idle (res);
+	g_object_unref (res);
+}
+
+static gboolean
+seahorse_unknown_source_load_finish (SeahorseSource *source,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_unknown_source_load_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
+
 static void 
 seahorse_source_iface (SeahorseSourceIface *iface)
 {
-	iface->load = seahorse_unknown_source_load;
+	iface->load_async = seahorse_unknown_source_load_async;
+	iface->load_finish = seahorse_unknown_source_load_finish;
 }
 
-/* -----------------------------------------------------------------------------
- * PUBLIC 
- */
-
 SeahorseUnknownSource*
 seahorse_unknown_source_new (GQuark ktype)
 {
-   return g_object_new (SEAHORSE_TYPE_UNKNOWN_SOURCE, "construct-tag", ktype, NULL);
+	return g_object_new (SEAHORSE_TYPE_UNKNOWN_SOURCE,
+	                     "construct-tag", ktype,
+	                     NULL);
 }
 
-SeahorseObject*                     
-seahorse_unknown_source_add_object (SeahorseUnknownSource *usrc, GQuark id,
-                                    SeahorseOperation *search)
+static void
+on_cancellable_gone (gpointer user_data,
+                     GObject *where_the_object_was)
 {
-    SeahorseObject *sobj;
-
-    g_return_val_if_fail (id != 0, NULL);
+	SeahorseObject *object = SEAHORSE_OBJECT (user_data);
+	g_object_set (object, "location", SEAHORSE_LOCATION_MISSING, NULL);
+}
 
-    sobj = seahorse_context_get_object (SCTX_APP (), SEAHORSE_SOURCE (usrc), id);
-    if (!sobj) {
-        sobj = SEAHORSE_OBJECT (seahorse_unknown_new (usrc, id, NULL));
-        seahorse_context_add_object (SCTX_APP (), sobj);
-    }
-    
-    if (search) {
-        g_object_set (sobj, "location", SEAHORSE_LOCATION_SEARCHING, NULL);
-        seahorse_operation_watch (search, (SeahorseDoneFunc) search_done, sobj, NULL, NULL);
-    } else {
-        g_object_set (sobj, "location", SEAHORSE_LOCATION_MISSING, NULL);
-    }
-    
-    return sobj;
+SeahorseObject *
+seahorse_unknown_source_add_object (SeahorseUnknownSource *self,
+                                    GQuark id,
+                                    GCancellable *cancellable)
+{
+	SeahorseObject *object;
+	SeahorseContext *context;
+
+	g_return_val_if_fail (id != 0, NULL);
+	g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
+
+	context = seahorse_context_instance ();
+	object = seahorse_context_get_object (context, SEAHORSE_SOURCE (self), id);
+	if (!object) {
+		object = SEAHORSE_OBJECT (seahorse_unknown_new (self, id, NULL));
+		seahorse_context_add_object (context, object);
+	}
+
+	if (cancellable) {
+		g_object_set (object, "location", SEAHORSE_LOCATION_SEARCHING, NULL);
+		g_object_weak_ref (G_OBJECT (cancellable), on_cancellable_gone, object);
+	} else {
+		g_object_set (object, "location", SEAHORSE_LOCATION_MISSING, NULL);
+	}
+
+	return object;
 }
diff --git a/libseahorse/seahorse-unknown-source.h b/libseahorse/seahorse-unknown-source.h
index fb25d86..295c4ba 100644
--- a/libseahorse/seahorse-unknown-source.h
+++ b/libseahorse/seahorse-unknown-source.h
@@ -66,8 +66,8 @@ GType                    seahorse_unknown_source_get_type      (void);
 
 SeahorseUnknownSource*   seahorse_unknown_source_new           (GQuark ktype);
 
-SeahorseObject*          seahorse_unknown_source_add_object    (SeahorseUnknownSource *usrc,
+SeahorseObject*          seahorse_unknown_source_add_object    (SeahorseUnknownSource *self,
                                                                 GQuark id,
-                                                                SeahorseOperation *search);
+                                                                GCancellable *cancellable);
 
 #endif /* __SEAHORSE_UNKNOWN_SOURCE_H__ */
diff --git a/libseahorse/seahorse-unknown.c b/libseahorse/seahorse-unknown.c
index 0361e82..f7c17cb 100644
--- a/libseahorse/seahorse-unknown.c
+++ b/libseahorse/seahorse-unknown.c
@@ -34,13 +34,6 @@ G_DEFINE_TYPE (SeahorseUnknown, seahorse_unknown, SEAHORSE_TYPE_OBJECT);
  */
 
 
-static SeahorseOperation*           
-seahorse_unknown_delete (SeahorseObject *sobj)
-{
-    seahorse_context_remove_object (SCTX_APP (), sobj);
-    return seahorse_operation_new_complete (NULL);
-}
-
 static void
 seahorse_unknown_init (SeahorseUnknown *self)
 {
@@ -50,8 +43,7 @@ seahorse_unknown_init (SeahorseUnknown *self)
 static void
 seahorse_unknown_class_init (SeahorseUnknownClass *klass)
 {
-	seahorse_unknown_parent_class = g_type_class_peek_parent (klass);
-	SEAHORSE_OBJECT_CLASS (klass)->delete = seahorse_unknown_delete;
+
 }
 
 /* -----------------------------------------------------------------------------
@@ -62,10 +54,10 @@ SeahorseUnknown*
 seahorse_unknown_new (SeahorseUnknownSource *source, GQuark id, const gchar *display)
 {
 	SeahorseUnknown *self;
-    
+
 	if (!display)
 		display = _("Unavailable");
-    
+
 	self = g_object_new (SEAHORSE_TYPE_UNKNOWN, "source", source, 
 	                     "label", display, "id", id, NULL);
 	return self;
diff --git a/libseahorse/seahorse-util.c b/libseahorse/seahorse-util.c
index 0e9ca88..1cdae53 100644
--- a/libseahorse/seahorse-util.c
+++ b/libseahorse/seahorse-util.c
@@ -24,6 +24,7 @@
 
 #include "seahorse-object.h"
 #include "seahorse-util.h"
+#include "seahorse-widget.h"
 
 #include "pgp/seahorse-pgp-module.h"
 
@@ -67,11 +68,11 @@ void
 seahorse_util_show_error (GtkWidget *parent, const gchar *heading, const gchar *message)
 {
 	GtkWidget *dialog;
-    
+
 	g_return_if_fail (message || heading);
 	if (!message)
 		message = "";
-    
+
 	if (parent) {
 		if (!GTK_IS_WIDGET (parent)) {
 			g_warn_if_reached ();
@@ -104,32 +105,50 @@ seahorse_util_show_error (GtkWidget *parent, const gchar *heading, const gchar *
 
 /**
  * seahorse_util_handle_error:
- * @err: The #GError to print.
+ * @error: The #GError to print, and clear
  * @desc: The heading of the box
  * @...: Parameters to insert into the format string desc.
  *
  * Displays an error box. The message is the error message.
+ * Won't display cancel errors.
  */
 void
-seahorse_util_handle_error (GError* err, const char* desc, ...)
+seahorse_util_handle_error (GError **error,
+                            gpointer parent,
+                            const char* description,
+                            ...)
 {
-    gchar *t = NULL;
-    
-    va_list ap;
-    
-    if(!err)
-        return;
+	gchar *text = NULL;
+	GtkWidget *widget = NULL;
+	va_list ap;
+
+	if (!error || !(*error) ||
+	    g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		g_clear_error (error);
+		return;
+	}
 
-    va_start(ap, desc);
-  
-    if (desc)
-        t = g_strdup_vprintf (desc, ap);
-    
-    va_end(ap);        
-    
-    seahorse_util_show_error (NULL, t, err->message ? err->message : "");
-    g_free(t);
-}    
+	va_start (ap, description);
+	if (description)
+		text = g_strdup_vprintf (description, ap);
+	va_end (ap);
+
+	if (parent == NULL)
+		widget = NULL;
+	else if (GTK_IS_WIDGET (parent))
+		widget = GTK_WIDGET (parent);
+	else if (GTK_IS_WINDOW (parent))
+		widget = GTK_WIDGET (parent);
+	else if (SEAHORSE_IS_WIDGET (parent))
+		widget = seahorse_widget_get_toplevel (parent);
+	else
+		g_warning ("unsupported 'parent' argument passed to seahorse_util_handle_error() ");
+
+	seahorse_util_show_error (widget, text,
+	                          (*error)->message ? (*error)->message : "");
+	g_free (text);
+	g_clear_error (error);
+}
 
 /**
  * seahorse_util_prompt_delete:
diff --git a/libseahorse/seahorse-util.h b/libseahorse/seahorse-util.h
index b27c66c..84af13b 100644
--- a/libseahorse/seahorse-util.h
+++ b/libseahorse/seahorse-util.h
@@ -56,8 +56,10 @@ void        seahorse_util_show_error            (GtkWidget          *parent,
                                                  const gchar        *heading,
                                                  const gchar        *message);
 
-void        seahorse_util_handle_error          (GError*            err,
-                                                 const char*        desc, ...);
+void        seahorse_util_handle_error          (GError **error,
+                                                 gpointer parent,
+                                                 const gchar* description,
+                                                 ...);
 
 gboolean    seahorse_util_prompt_delete         (const gchar *text,
                                                  GtkWidget *parent);
diff --git a/pgp/Makefile.am b/pgp/Makefile.am
index 0837e8b..dcdfd2b 100644
--- a/pgp/Makefile.am
+++ b/pgp/Makefile.am
@@ -45,7 +45,6 @@ libseahorse_pgp_la_SOURCES = \
 	seahorse-gpgme-generate.c \
 	seahorse-gpgme-key.c seahorse-gpgme-key.h \
 	seahorse-gpgme-key-op.c seahorse-gpgme-key-op.h \
-	seahorse-gpgme-operation.c seahorse-gpgme-operation.h \
 	seahorse-gpgme-photo.c seahorse-gpgme-photo.h \
 	seahorse-gpgme-photos.c \
 	seahorse-gpgme-revoke.c \
diff --git a/pgp/seahorse-gpg-options.c b/pgp/seahorse-gpg-options.c
index d4a69bc..1d06397 100644
--- a/pgp/seahorse-gpg-options.c
+++ b/pgp/seahorse-gpg-options.c
@@ -246,7 +246,7 @@ gpg_options_init (GError **err)
 
         gerr = gpgme_get_engine_info (&engine);
         g_return_val_if_fail (GPG_IS_OK (gerr),
-                              (seahorse_gpgme_to_error (gerr, err), FALSE));
+                              (seahorse_gpgme_propagate_error (gerr, err), FALSE));
 
         /* Look for the OpenPGP engine */
         while (engine && engine->protocol != GPGME_PROTOCOL_OpenPGP)
@@ -259,7 +259,7 @@ gpg_options_init (GError **err)
         g_return_val_if_fail (engine && engine->version && engine->file_name &&
                               (g_str_has_prefix (engine->version, GPG_VERSION_PREFIX1) ||
                                g_str_has_prefix (engine->version, GPG_VERSION_PREFIX2)),
-                              (seahorse_gpgme_to_error (GPG_E (GPG_ERR_INV_ENGINE), err), FALSE));
+                              (seahorse_gpgme_propagate_error (GPG_E (GPG_ERR_INV_ENGINE), err), FALSE));
 
         /* Now run the binary and read in the home directory */
         if (!parse_home_directory (engine, err))
diff --git a/pgp/seahorse-gpgme-generate.c b/pgp/seahorse-gpgme-generate.c
index 95beb7b..587d36c 100644
--- a/pgp/seahorse-gpgme-generate.c
+++ b/pgp/seahorse-gpgme-generate.c
@@ -126,17 +126,6 @@ static AlgorithmDesc available_algorithms[] = {
  *
  * If the key generation caused errors, these will be displayed in this function
  */
-static void
-completion_handler (SeahorseOperation *op, gpointer data)
-{
-    GError *error = NULL;
-    if (!seahorse_operation_is_successful (op)) {
-        seahorse_operation_copy_error (op, &error);
-        seahorse_util_handle_error (error, _("Couldn't generate PGP key"));
-        g_clear_error (&error);
-    }
-}
-
 
 /**
  * get_expiry_date:
@@ -166,6 +155,16 @@ get_expiry_date (SeahorseWidget *swidget)
     return widget;
 }
 
+static void
+on_generate_key_complete (GObject *source,
+                          GAsyncResult *result,
+                          gpointer user_data)
+{
+	GError *error = NULL;
+
+	if (!seahorse_gpgme_key_op_generate_finish (SEAHORSE_GPGME_SOURCE (source), result, &error))
+		seahorse_util_handle_error (&error, NULL, _("Couldn't generate PGP key"));
+}
 
 /**
  * gpgme_generate_key:
@@ -182,34 +181,34 @@ get_expiry_date (SeahorseWidget *swidget)
  * @expire sets the expiry date
  *
  */
-void seahorse_gpgme_generate_key (SeahorseGpgmeSource *sksrc, const gchar *name, const gchar *email,
-                            const gchar *comment, guint type, guint bits, time_t expires)
+void
+seahorse_gpgme_generate_key (SeahorseGpgmeSource *source,
+                             const gchar *name,
+                             const gchar *email,
+                             const gchar *comment,
+                             guint type,
+                             guint bits,
+                             time_t expires)
 {
-    SeahorseOperation *op;
-    const gchar *pass;
-    gpgme_error_t gerr;
-    GtkDialog *dialog;
-
-
-
-    dialog = seahorse_passphrase_prompt_show (_("Passphrase for New PGP Key"),
-                                              _("Enter the passphrase for your new key twice."),
-                                              NULL, NULL, TRUE);
-    if (gtk_dialog_run (dialog) == GTK_RESPONSE_ACCEPT)
-    {
-        pass = seahorse_passphrase_prompt_get (dialog);
-        op = seahorse_gpgme_key_op_generate (sksrc, name, email, comment,
-                                             pass, type, bits, expires, &gerr);
-
-        if (!GPG_IS_OK (gerr)) {
-            seahorse_gpgme_handle_error (gerr, _("Couldn't generate key"));
-        } else {
-            seahorse_progress_show (op, _("Generating key"), TRUE);
-            seahorse_operation_watch (op, (SeahorseDoneFunc)completion_handler, NULL, NULL, NULL);
-            g_object_unref (op);
-        }
-    }
-    gtk_widget_destroy (GTK_WIDGET (dialog));
+	GCancellable *cancellable;
+	const gchar *pass;
+	GtkDialog *dialog;
+
+	dialog = seahorse_passphrase_prompt_show (_("Passphrase for New PGP Key"),
+	                                          _("Enter the passphrase for your new key twice."),
+	                                          NULL, NULL, TRUE);
+	if (gtk_dialog_run (dialog) == GTK_RESPONSE_ACCEPT) {
+		pass = seahorse_passphrase_prompt_get (dialog);
+		cancellable = g_cancellable_new ();
+		seahorse_gpgme_key_op_generate_async (source, name, email, comment,
+		                                      pass, type, bits, expires,
+		                                      cancellable, on_generate_key_complete,
+		                                      NULL);
+		seahorse_progress_show (cancellable, _("Generating key"), FALSE);
+		g_object_unref (cancellable);
+	}
+
+	gtk_widget_destroy (GTK_WIDGET (dialog));
 }
 
 
diff --git a/pgp/seahorse-gpgme-key-op.c b/pgp/seahorse-gpgme-key-op.c
index 0988256..18f2e72 100644
--- a/pgp/seahorse-gpgme-key-op.c
+++ b/pgp/seahorse-gpgme-key-op.c
@@ -31,6 +31,7 @@
 #include <glib/gstdio.h>
 #include <glib/gi18n.h>
 
+#include "seahorse-progress.h"
 #include "seahorse-util.h"
 
 #include "common/seahorse-object-list.h"
@@ -39,7 +40,6 @@
 #include "pgp/seahorse-gpgme-data.h"
 #include "pgp/seahorse-gpg-op.h"
 #include "pgp/seahorse-gpgme-key-op.h"
-#include "pgp/seahorse-gpgme-operation.h"
 
 #define DEBUG_FLAG SEAHORSE_DEBUG_KEYS
 #include "seahorse-debug.h"
@@ -59,6 +59,50 @@
 #define GPG_FULL        4
 #define GPG_ULTIMATE    5
 
+typedef struct {
+	GCancellable *cancellable;
+	gpgme_ctx_t gctx;
+} key_op_generate_closure;
+
+static void
+key_op_generate_free (gpointer data)
+{
+	key_op_generate_closure *closure = data;
+	g_clear_object (&closure->cancellable);
+	gpgme_release (closure->gctx);
+	g_free (closure);
+}
+
+static void
+on_key_op_generate_progress (void *opaque,
+                             const char *what,
+                             int type,
+                             int current,
+                             int total)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (opaque);
+	key_op_generate_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	seahorse_progress_update (closure->cancellable, res, "%s", what);
+}
+
+static gboolean
+on_key_op_generate_complete (gpgme_error_t gerr,
+                             gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	key_op_generate_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	if (seahorse_gpgme_propagate_error (gerr, &error)) {
+		g_simple_async_result_take_error (res, error);
+	}
+
+	seahorse_progress_end (closure->cancellable, res);
+	g_simple_async_result_complete (res);
+	return FALSE; /* don't call again */
+}
+
+
 /**
  * seahorse_gpgme_key_op_generate:
  * @sksrc: #SeahorseSource
@@ -69,88 +113,126 @@
  * @type: Key type. Supported types are #DSA_ELGAMAL, #DSA, #RSA_SIGN, and #RSA_RSA
  * @length: Length of key, must be within the range of @type specified by #SeahorseKeyLength
  * @expires: Expiration date of key
- * @err: Catches errors in the params
  * 
  * Tries to generate a new key based on given parameters.
- *
- * Returns: SeahorseOperation*
  **/
-SeahorseOperation*
-seahorse_gpgme_key_op_generate (SeahorseGpgmeSource *psrc, const gchar *name,
-                                const gchar *email, const gchar *comment,
-                                const gchar *passphrase, const SeahorseKeyEncType type,
-                                const guint length, const time_t expires, gpgme_error_t *err)
-{
-    SeahorseGpgmeOperation *pop = NULL;
-    gchar *common, *key_type, *start, *expires_date;
-    const gchar *parms;
-    
-    *err = GPG_OK;
+void
+seahorse_gpgme_key_op_generate_async (SeahorseGpgmeSource *source,
+                                      const gchar *name,
+                                      const gchar *email,
+                                      const gchar *comment,
+                                      const gchar *passphrase,
+                                      const SeahorseKeyEncType type,
+                                      const guint length,
+                                      const time_t expires,
+                                      GCancellable *cancellable,
+                                      GAsyncReadyCallback callback,
+                                      gpointer user_data)
+{
+	gchar *common, *key_type, *start, *expires_date;
+	key_op_generate_closure *closure;
+	GSimpleAsyncResult *res;
+	GError *error = NULL;
+	const gchar *parms;
+	gpgme_error_t gerr;
+	GSource *gsource;
 
-    if (strlen (name) < 5)
-        *err = GPG_E (GPG_ERR_INV_VALUE);
+	g_return_if_fail (SEAHORSE_IS_GPGME_SOURCE (source));
+	g_return_if_fail (name);
+	g_return_if_fail (strlen (name) > 4);
+	g_return_if_fail (passphrase);
 
-    /* Check lengths for each type */
-    switch (type) {
-    case DSA_ELGAMAL:
-        if (length < ELGAMAL_MIN || length > LENGTH_MAX)
-            *err = GPG_E (GPG_ERR_INV_VALUE);
-        break;
-    case DSA:
-        if (length < DSA_MIN || length > DSA_MAX)
-            *err = GPG_E (GPG_ERR_INV_VALUE);
-        break;
-    case RSA_RSA:
-    case RSA_SIGN:
-        if (length < RSA_MIN || length > LENGTH_MAX)
-            *err = GPG_E (GPG_ERR_INV_VALUE);
-        break;
-    default:
-        *err = GPG_E (GPG_ERR_INV_VALUE);
-        break;
-    }
+	/* Check lengths for each type */
+	switch (type) {
+	case DSA_ELGAMAL:
+		g_return_if_fail (length >= ELGAMAL_MIN || length <= LENGTH_MAX);
+		break;
+	case DSA:
+		g_return_if_fail (length >= DSA_MIN || length <= DSA_MAX);
+		break;
+	case RSA_RSA:
+	case RSA_SIGN:
+		g_return_if_fail (length >= RSA_MIN || length <= LENGTH_MAX);
+		break;
+	default:
+		g_return_if_reached ();
+		break;
+	}
+
+	if (expires != 0)
+		expires_date = seahorse_util_get_date_string (expires);
+	else
+		expires_date = g_strdup ("0");
+
+	/* Common xml */
+	common = g_strdup_printf ("Name-Real: %s\nExpire-Date: %s\nPassphrase: %s\n"
+			"</GnupgKeyParms>", name, expires_date, passphrase);
+	if (email != NULL && strlen (email) > 0)
+		common = g_strdup_printf ("Name-Email: %s\n%s", email, common);
+	if (comment != NULL && strlen (comment) > 0)
+		common = g_strdup_printf ("Name-Comment: %s\n%s", comment, common);
+
+	if (type == DSA || type == DSA_ELGAMAL)
+		key_type = "Key-Type: DSA\nKey-Usage: sign";
+	else
+		key_type = "Key-Type: RSA\nKey-Usage: sign";
+
+	start = g_strdup_printf ("<GnupgKeyParms format=\"internal\">\n%s\nKey-Length: ", key_type);
+
+	/* Subkey xml */
+	if (type == DSA_ELGAMAL)
+		parms = g_strdup_printf ("%s%d\nSubkey-Type: ELG-E\nSubkey-Length: %d\nSubkey-Usage: encrypt\n%s",
+		                         start, (length < DSA_MAX) ? length : DSA_MAX, length, common);
+	else if (type == RSA_RSA)
+		parms = g_strdup_printf ("%s%d\nSubkey-Type: RSA\nSubkey-Length: %d\nSubkey-Usage: encrypt\n%s",
+		                         start, length, length, common);
+	else
+		parms = g_strdup_printf ("%s%d\n%s", start, length, common);
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_gpgme_key_op_generate_async);
+
+	closure = g_new0 (key_op_generate_closure, 1);
+	closure->gctx = seahorse_gpgme_source_new_context ();
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	gpgme_set_progress_cb (closure->gctx, on_key_op_generate_progress, res);
+	g_simple_async_result_set_op_res_gpointer (res, closure, key_op_generate_free);
+
+	seahorse_progress_prep_and_begin (cancellable, res, NULL);
+	gsource = seahorse_gpgme_gsource_new (closure->gctx, cancellable);
+	g_source_set_callback (gsource, (GSourceFunc)on_key_op_generate_complete,
+	                       g_object_ref (res), g_object_unref);
+
+	gerr = gpgme_op_genkey_start (closure->gctx, parms, NULL, NULL);
+	if (seahorse_gpgme_propagate_error (gerr, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+	} else {
+		g_source_attach (gsource, g_main_context_default ());
+	}
+
+	g_source_unref (gsource);
+
+	/* Free xmls */
+	g_free (start);
+	g_free (common);
+	g_free (expires_date);
+
+	g_object_unref (res);
+}
+
+gboolean
+seahorse_gpgme_key_op_generate_finish (SeahorseGpgmeSource *source,
+                                       GAsyncResult *result,
+                                       GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_gpgme_key_op_generate_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
 
-    if (0 != expires)
-        expires_date = seahorse_util_get_date_string (expires);
-    else
-        expires_date = g_strdup ("0");
-
-    /* Common xml */
-    common = g_strdup_printf ("Name-Real: %s\nExpire-Date: %s\nPassphrase: %s\n"
-                              "</GnupgKeyParms>", name, expires_date, passphrase);
-    if (email != NULL && strlen (email) > 0)
-        common = g_strdup_printf ("Name-Email: %s\n%s", email, common);
-    if (comment != NULL && strlen (comment) > 0)
-        common = g_strdup_printf ("Name-Comment: %s\n%s", comment, common);
-
-    if (type == DSA || type == DSA_ELGAMAL)
-        key_type = "Key-Type: DSA\nKey-Usage: sign";
-    else
-        key_type = "Key-Type: RSA\nKey-Usage: sign";
-
-    start = g_strdup_printf ("<GnupgKeyParms format=\"internal\">\n%s\nKey-Length: ", key_type);
-
-    /* Subkey xml */
-    if (type == DSA_ELGAMAL)
-        parms = g_strdup_printf ("%s%d\nSubkey-Type: ELG-E\nSubkey-Length: %d\nSubkey-Usage: encrypt\n%s",
-                                 start, (length < DSA_MAX) ? length : DSA_MAX, length, common);
-    else if (type == RSA_RSA)
-        parms = g_strdup_printf ("%s%d\nSubkey-Type: RSA\nSubkey-Length: %d\nSubkey-Usage: encrypt\n%s",
-                                 start, length, length, common);
-    else
-        parms = g_strdup_printf ("%s%d\n%s", start, length, common);
-
-    if (GPG_IS_OK (*err)) {
-        pop = seahorse_gpgme_operation_new (NULL);
-        *err = gpgme_op_genkey_start (pop->gctx, parms, NULL, NULL);
-     }
-
-    /* Free xmls */
-    g_free (start);
-    g_free (common);
-    g_free (expires_date);
-
-    return pop ? SEAHORSE_OPERATION (pop) : NULL;
+	return TRUE;
 }
 
 /* helper function for deleting @skey */
diff --git a/pgp/seahorse-gpgme-key-op.h b/pgp/seahorse-gpgme-key-op.h
index 8b791a3..39017f9 100644
--- a/pgp/seahorse-gpgme-key-op.h
+++ b/pgp/seahorse-gpgme-key-op.h
@@ -26,8 +26,6 @@
 #include <gpgme.h>
 #include <time.h>
 
-#include "seahorse-operation.h"
-
 #include "pgp/seahorse-gpgme-key.h"
 #include "pgp/seahorse-gpgme-subkey.h"
 #include "pgp/seahorse-gpgme-uid.h"
@@ -137,7 +135,7 @@ typedef enum {
 	REVOKE_NOT_USED = 3
 } SeahorseRevokeReason;
 
-SeahorseOperation*    seahorse_gpgme_key_op_generate         (SeahorseGpgmeSource  *sksrc,
+void                  seahorse_gpgme_key_op_generate_async   (SeahorseGpgmeSource *source,
                                                               const gchar *name,
                                                               const gchar *email,
                                                               const gchar *comment,
@@ -145,7 +143,13 @@ SeahorseOperation*    seahorse_gpgme_key_op_generate         (SeahorseGpgmeSourc
                                                               SeahorseKeyEncType type,
                                                               guint length,
                                                               time_t expires,
-                                                              gpgme_error_t *err);
+                                                              GCancellable *cancellable,
+                                                              GAsyncReadyCallback callback,
+                                                              gpointer user_data);
+
+gboolean              seahorse_gpgme_key_op_generate_finish  (SeahorseGpgmeSource *source,
+                                                              GAsyncResult *Result,
+                                                              GError **error);
 
 gpgme_error_t         seahorse_gpgme_key_op_delete           (SeahorseGpgmeKey *pkey);
 
diff --git a/pgp/seahorse-gpgme-key.c b/pgp/seahorse-gpgme-key.c
index e9bba72..87a2e88 100644
--- a/pgp/seahorse-gpgme-key.c
+++ b/pgp/seahorse-gpgme-key.c
@@ -68,7 +68,7 @@ struct _SeahorseGpgmeKeyPrivate {
 static gboolean 
 load_gpgme_key (GQuark id, int mode, int secret, gpgme_key_t *key)
 {
-	GError *err = NULL;
+	GError *error = NULL;
 	gpgme_ctx_t ctx;
 	gpgme_error_t gerr;
 	
@@ -81,10 +81,10 @@ load_gpgme_key (GQuark id, int mode, int secret, gpgme_key_t *key)
 	}
 
 	gpgme_release (ctx);
-	
-	if (!GPG_IS_OK (gerr)) {
-		seahorse_gpgme_to_error (gerr, &err);
-		g_message ("couldn't load GPGME key: %s", err->message);
+
+	if (seahorse_gpgme_propagate_error (gerr, &error)) {
+		g_message ("couldn't load GPGME key: %s", error->message);
+		g_clear_error (&error);
 		return FALSE;
 	}
 	
@@ -324,7 +324,7 @@ seahorse_gpgme_key_realize (SeahorseObject *obj)
 	realize_subkeys (self);
 
 	/* The flags */
-	flags = SEAHORSE_FLAG_EXPORTABLE;
+	flags = SEAHORSE_FLAG_EXPORTABLE | SEAHORSE_FLAG_DELETABLE;
 
 	if (!self->pv->pubkey->disabled && !self->pv->pubkey->expired && 
 	    !self->pv->pubkey->revoked && !self->pv->pubkey->invalid) {
@@ -380,24 +380,6 @@ seahorse_gpgme_key_refresh (SeahorseObject *obj)
 	SEAHORSE_OBJECT_CLASS (seahorse_gpgme_key_parent_class)->refresh (obj);
 }
 
-static SeahorseOperation*
-seahorse_gpgme_key_delete (SeahorseObject *obj)
-{
-	SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (obj);
-	gpgme_error_t gerr;
-	GError *err = NULL;
-	
-	if (self->pv->seckey)
-		gerr = seahorse_gpgme_key_op_delete_pair (self);
-	else
-		gerr = seahorse_gpgme_key_op_delete (self);
-	
-	if (!GPG_IS_OK (gerr))
-		seahorse_gpgme_to_error (gerr, &err);
-	
-	return seahorse_operation_new_complete (err);
-}
-
 static GList*
 seahorse_gpgme_key_get_uids (SeahorsePgpKey *base)
 {
@@ -550,8 +532,7 @@ seahorse_gpgme_key_class_init (SeahorseGpgmeKeyClass *klass)
 	
 	seahorse_class->refresh = seahorse_gpgme_key_refresh;
 	seahorse_class->realize = seahorse_gpgme_key_realize;
-	seahorse_class->delete = seahorse_gpgme_key_delete;
-	
+
 	pgp_class->get_uids = seahorse_gpgme_key_get_uids;
 	pgp_class->set_uids = seahorse_gpgme_key_set_uids;
 	pgp_class->get_subkeys = seahorse_gpgme_key_get_subkeys;
diff --git a/pgp/seahorse-gpgme-photos.c b/pgp/seahorse-gpgme-photos.c
index ea0ff57..feb0892 100644
--- a/pgp/seahorse-gpgme-photos.c
+++ b/pgp/seahorse-gpgme-photos.c
@@ -274,10 +274,8 @@ seahorse_gpgme_photo_add (SeahorseGpgmeKey *pkey, GtkWindow *parent, const gchar
     }
     
     if (!prepare_photo_id (parent, filename, &tempfile, &error)) {
-        if (error) {
-            seahorse_util_handle_error (error, "Couldn't prepare photo");
-            g_clear_error (&error);
-        }
+        if (error)
+            seahorse_util_handle_error (&error, NULL, _("Couldn't prepare photo"));
         return FALSE;
     }
     
diff --git a/pgp/seahorse-gpgme-source.c b/pgp/seahorse-gpgme-source.c
index f08c27e..d34fdec 100644
--- a/pgp/seahorse-gpgme-source.c
+++ b/pgp/seahorse-gpgme-source.c
@@ -28,11 +28,10 @@
 #include "seahorse-gpgme-data.h"
 #include "seahorse-gpgme.h"
 #include "seahorse-gpgme-key-op.h"
-#include "seahorse-gpgme-operation.h"
 #include "seahorse-gpg-options.h"
 #include "seahorse-pgp-key.h"
 
-#include "seahorse-operation.h"
+#include "seahorse-progress.h"
 #include "seahorse-util.h"
 #include "seahorse-passphrase.h"
 
@@ -143,99 +142,10 @@ init_gpgme (gpgme_ctx_t *ctx)
     return err;
 }
 
-/* -----------------------------------------------------------------------------
- * LOAD OPERATION 
- */
- 
-
-#define SEAHORSE_TYPE_LOAD_OPERATION            (seahorse_load_operation_get_type ())
-#define SEAHORSE_LOAD_OPERATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_LOAD_OPERATION, SeahorseLoadOperation))
-#define SEAHORSE_LOAD_OPERATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_LOAD_OPERATION, SeahorseLoadOperationClass))
-#define SEAHORSE_IS_LOAD_OPERATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_LOAD_OPERATION))
-#define SEAHORSE_IS_LOAD_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_LOAD_OPERATION))
-#define SEAHORSE_LOAD_OPERATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_LOAD_OPERATION, SeahorseLoadOperationClass))
-
-DECLARE_OPERATION (Load, load)
-    /*< private >*/
-    SeahorseGpgmeSource *psrc;        /* Key source to add keys to when found */
-    gpgme_ctx_t ctx;                /* GPGME context we're loading from */
-    gboolean secret;                /* Loading secret keys */
-    guint loaded;                   /* Number of keys we've loaded */
-    guint batch;                    /* Number to load in a batch, or 0 for synchronous */
-    guint stag;                     /* The event source handler id (for stopping a load) */
-    guint parts;                    /* Parts to load*/
-    GHashTable *checks;             /* When refreshing this is our set of missing keys */
-END_DECLARE_OPERATION        
-
-IMPLEMENT_OPERATION (Load, load)
-
-static SeahorseLoadOperation*   seahorse_load_operation_start   (SeahorseGpgmeSource *psrc, 
-                                                                 const gchar **pattern, 
-                                                                 guint parts,
-                                                                 gboolean secret);
-
-static gboolean                 scheduled_dummy                 (gpointer data);
-
-/* -----------------------------------------------------------------------------
- * EXPORT 
- */
- 
-typedef struct _ExportContext {
-    GArray *keyids;
-    guint at;
-    gpgme_data_t data;
-} ExportContext;
-
-static void
-free_export_context (gpointer p)
-{
-    ExportContext *ctx = (ExportContext*)p;
-    if (!ctx)
-        return;
-    gpgme_data_release (ctx->data);
-    g_array_free (ctx->keyids, TRUE);
-    g_free (ctx);
-}
-
-static void
-export_key_callback (SeahorseGpgmeOperation *pop, ExportContext *ctx)
-{
-    gpgme_error_t gerr;
-    GError *err = NULL;
-    GOutputStream *output;
-    
-    if (seahorse_operation_is_running (SEAHORSE_OPERATION (pop)))
-        seahorse_operation_mark_progress_full (SEAHORSE_OPERATION (pop), NULL, 
-                                               ctx->at, ctx->keyids->len);
-    
-    /* Done, close the output stream */
-    if (ctx->at >= ctx->keyids->len) {
-	    output = seahorse_operation_get_result (SEAHORSE_OPERATION (pop));
-	    g_return_if_fail (G_IS_OUTPUT_STREAM (output));
-	    if (!g_output_stream_close (output, NULL, &err))
-		    seahorse_operation_mark_done (SEAHORSE_OPERATION (pop), FALSE, err);
-	    return;
-    }
-    
-    /* Do the next key in the list */
-    gerr = gpgme_op_export_start (pop->gctx, g_array_index (ctx->keyids, const char*, ctx->at), 
-                                  0, ctx->data);
-    ctx->at++;
-    
-    if (!GPG_IS_OK (gerr))
-        seahorse_gpgme_operation_mark_failed (pop, gerr);
-}
-
-
-/* -----------------------------------------------------------------------------
- * PGP Source
- */
-    
 struct _SeahorseGpgmeSourcePrivate {
-    guint scheduled_refresh;                /* Source for refresh timeout */
-    GFileMonitor *monitor_handle;           /* For monitoring the .gnupg directory */
-    SeahorseMultiOperation *operations;     /* A list of all current operations */    
-    GList *orphan_secret;                   /* Orphan secret keys */
+	guint scheduled_refresh;                /* Source for refresh timeout */
+	GFileMonitor *monitor_handle;           /* For monitoring the .gnupg directory */
+	GList *orphan_secret;                   /* Orphan secret keys */
 };
 
 static void seahorse_source_iface (SeahorseSourceIface *iface);
@@ -243,209 +153,34 @@ static void seahorse_source_iface (SeahorseSourceIface *iface);
 G_DEFINE_TYPE_EXTENDED (SeahorseGpgmeSource, seahorse_gpgme_source, G_TYPE_OBJECT, 0,
                         G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_SOURCE, seahorse_source_iface));
 
-/* GObject handlers */
-static void seahorse_gpgme_source_dispose         (GObject *gobject);
-static void seahorse_gpgme_source_finalize        (GObject *gobject);
-static void seahorse_gpgme_source_set_property    (GObject *object, guint prop_id, 
-                                                 const GValue *value, GParamSpec *pspec);
-static void seahorse_gpgme_source_get_property    (GObject *object, guint prop_id,
-                                                 GValue *value, GParamSpec *pspec);
-
-/* SeahorseSource methods */
-static SeahorseOperation*  seahorse_gpgme_source_load             (SeahorseSource *src);
-
-static SeahorseOperation*  seahorse_gpgme_source_import           (SeahorseSource *sksrc, 
-                                                                 GInputStream *input);
-static SeahorseOperation*  seahorse_gpgme_source_export           (SeahorseSource *sksrc, 
-                                                                 GList *keys,
-                                                                 GOutputStream *output);
-
-/* Other forward decls */
-static void                monitor_gpg_homedir                  (GFileMonitor *handle, 
-                                                                 GFile *file,
-                                                                 GFile *other_file,
-                                                                 GFileMonitorEvent event_type,
-                                                                 gpointer user_data);
-static void                cancel_scheduled_refresh             (SeahorseGpgmeSource *psrc);
-                                                                 
-static GObjectClass *parent_class = NULL;
-
-/* Initialize the basic class stuff */
-static void
-seahorse_gpgme_source_class_init (SeahorseGpgmeSourceClass *klass)
-{
-    GObjectClass *gobject_class;
-    
-    g_message ("init gpgme version %s", gpgme_check_version (NULL));
-    
-#ifdef ENABLE_NLS
-    gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
-    gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
-#endif
-   
-    parent_class = g_type_class_peek_parent (klass);
-    gobject_class = G_OBJECT_CLASS (klass);
-    gobject_class->dispose = seahorse_gpgme_source_dispose;
-    gobject_class->finalize = seahorse_gpgme_source_finalize;
-    gobject_class->set_property = seahorse_gpgme_source_set_property;
-    gobject_class->get_property = seahorse_gpgme_source_get_property;
- 
-	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
-	g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
-	
-	seahorse_registry_register_type (NULL, SEAHORSE_TYPE_GPGME_SOURCE, "source", "local", SEAHORSE_PGP_STR, NULL);
-
-	seahorse_registry_register_function (NULL, seahorse_pgp_key_canonize_id, "canonize", SEAHORSE_PGP_STR, NULL);
-}
-
-static void 
-seahorse_source_iface (SeahorseSourceIface *iface)
-{
-	iface->load = seahorse_gpgme_source_load;
-	iface->import = seahorse_gpgme_source_import;
-	iface->export = seahorse_gpgme_source_export;
-}
+typedef struct {
+	SeahorseGpgmeSource *source;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+	gpgme_ctx_t gctx;
+	GHashTable *checks;
+	gint parts;
+	gint loaded;
+} source_list_closure;
 
-
-/* init context, private vars, set prefs, connect signals */
 static void
-seahorse_gpgme_source_init (SeahorseGpgmeSource *psrc)
+source_list_free (gpointer data)
 {
-	gpgme_error_t gerr;
-	GError *err = NULL;
-	const gchar *gpg_homedir;
-	GFile *file;
-    
-	gerr = init_gpgme (&(psrc->gctx));
-	g_return_if_fail (GPG_IS_OK (gerr));
-    
-	/* init private vars */
-	psrc->pv = g_new0 (SeahorseGpgmeSourcePrivate, 1);
-    
-	psrc->pv->operations = seahorse_multi_operation_new ();
-    
-	psrc->pv->scheduled_refresh = 0;
-	psrc->pv->monitor_handle = NULL;
-    
-	gpg_homedir = seahorse_gpg_homedir ();
-	file = g_file_new_for_path (gpg_homedir);
-	g_return_if_fail (file != NULL);
-    
-	psrc->pv->monitor_handle = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, &err);
-	g_object_unref (file);
-	
-	if (psrc->pv->monitor_handle) {
-		g_signal_connect (psrc->pv->monitor_handle, "changed", 
-		                  G_CALLBACK (monitor_gpg_homedir), psrc);
-	} else {
-		g_warning ("couldn't monitor the GPG home directory: %s: %s", 
-		           gpg_homedir, err && err->message ? err->message : "");
-	}
-}
-
-/* dispose of all our internal references */
-static void
-seahorse_gpgme_source_dispose (GObject *gobject)
-{
-    SeahorseGpgmeSource *psrc;
-    GList *l;
-    
-    /*
-     * Note that after this executes the rest of the object should
-     * still work without a segfault. This basically nullifies the 
-     * object, but doesn't free it.
-     * 
-     * This function should also be able to run multiple times.
-     */
-  
-    psrc = SEAHORSE_GPGME_SOURCE (gobject);
-    g_assert (psrc->pv);
-    
-    /* Clear out all operations */
-    if (psrc->pv->operations) {
-        if(seahorse_operation_is_running (SEAHORSE_OPERATION (psrc->pv->operations)))
-            seahorse_operation_cancel (SEAHORSE_OPERATION (psrc->pv->operations));
-        g_object_unref (psrc->pv->operations);
-        psrc->pv->operations = NULL;
-    }
-
-    cancel_scheduled_refresh (psrc);    
-    
-	if (psrc->pv->monitor_handle) {
-		g_object_unref (psrc->pv->monitor_handle);
-		psrc->pv->monitor_handle = NULL;
-	}
-    
-    for (l = psrc->pv->orphan_secret; l; l = g_list_next (l)) 
-        g_object_unref (l->data);
-    g_list_free (psrc->pv->orphan_secret);
-    psrc->pv->orphan_secret = NULL;
-    
-    if (psrc->gctx)
-        gpgme_release (psrc->gctx);
-    
-    G_OBJECT_CLASS (parent_class)->dispose (gobject);
-}
-
-/* free private vars */
-static void
-seahorse_gpgme_source_finalize (GObject *gobject)
-{
-    SeahorseGpgmeSource *psrc;
-  
-    psrc = SEAHORSE_GPGME_SOURCE (gobject);
-    g_assert (psrc->pv);
-    
-    /* All monitoring and scheduling should be done */
-    g_assert (psrc->pv->scheduled_refresh == 0);
-    g_assert (psrc->pv->monitor_handle == 0);
-    
-    g_free (psrc->pv);
- 
-    G_OBJECT_CLASS (parent_class)->finalize (gobject);
-}
-
-static void 
-seahorse_gpgme_source_set_property (GObject *object, guint prop_id, const GValue *value, 
-                                  GParamSpec *pspec)
-{
-    
-}
-
-static void 
-seahorse_gpgme_source_get_property (GObject *object, guint prop_id, GValue *value, 
-                                  GParamSpec *pspec)
-{
-    switch (prop_id) {
-    case PROP_SOURCE_TAG:
-        g_value_set_uint (value, SEAHORSE_PGP);
-        break;
-    case PROP_SOURCE_LOCATION:
-        g_value_set_enum (value, SEAHORSE_LOCATION_LOCAL);
-        break;
-    }
-}
-
-/* --------------------------------------------------------------------------
- * HELPERS 
- */
-
-/* Remove the given key from the context */
-static void
-remove_key_from_context (gpointer kt, SeahorseObject *dummy, SeahorseGpgmeSource *psrc)
-{
-    /* This function gets called as a GHRFunc on the lctx->checks hashtable. */
-    GQuark keyid = GPOINTER_TO_UINT (kt);
-    SeahorseObject *sobj;
-    
-    sobj = seahorse_context_get_object (SCTX_APP (), SEAHORSE_SOURCE (psrc), keyid);
-    if (sobj != NULL)
-        seahorse_context_remove_object (SCTX_APP (), sobj);
+	source_list_closure *closure = data;
+	gpgme_release (closure->gctx);
+	if (closure->checks)
+		g_hash_table_destroy (closure->checks);
+	g_cancellable_disconnect (closure->cancellable,
+	                          closure->cancelled_sig);
+	g_clear_object (&closure->cancellable);
+	g_clear_object (&closure->source);
+	g_free (closure);
 }
 
 /* Add a key to the context  */
 static SeahorseGpgmeKey*
-add_key_to_context (SeahorseGpgmeSource *psrc, gpgme_key_t key)
+add_key_to_context (SeahorseGpgmeSource *self,
+                    gpgme_key_t key)
 {
 	SeahorseGpgmeKey *pkey = NULL;
 	SeahorseGpgmeKey *prev;
@@ -453,525 +188,844 @@ add_key_to_context (SeahorseGpgmeSource *psrc, gpgme_key_t key)
 	gpgme_key_t seckey;
 	GQuark keyid;
 	GList *l;
-    
+
 	g_return_val_if_fail (key->subkeys && key->subkeys->keyid, NULL);
-    
+
 	id = key->subkeys->keyid;
 	keyid = seahorse_pgp_key_canonize_id (id);
 	g_return_val_if_fail (keyid, NULL);
-    
-	g_assert (SEAHORSE_IS_GPGME_SOURCE (psrc));
-	prev = SEAHORSE_GPGME_KEY (seahorse_context_get_object (SCTX_APP (), SEAHORSE_SOURCE (psrc), keyid));
-    
+
+	g_assert (SEAHORSE_IS_GPGME_SOURCE (self));
+	prev = SEAHORSE_GPGME_KEY (seahorse_context_get_object (seahorse_context_instance (),
+	                                                        SEAHORSE_SOURCE (self), keyid));
+
 	/* Check if we can just replace the key on the object */
 	if (prev != NULL) {
-		if (key->secret) 
+		if (key->secret)
 			g_object_set (prev, "seckey", key, NULL);
 		else
 			g_object_set (prev, "pubkey", key, NULL);
 		return prev;
 	}
-    
-	/* Create a new key with secret */    
+
+	/* Create a new key with secret */
 	if (key->secret) {
-		pkey = seahorse_gpgme_key_new (SEAHORSE_SOURCE (psrc), NULL, key);
-        
+		pkey = seahorse_gpgme_key_new (SEAHORSE_SOURCE (self), NULL, key);
+
 		/* Since we don't have a public key yet, save this away */
-		psrc->pv->orphan_secret = g_list_append (psrc->pv->orphan_secret, pkey);
-        
+		self->pv->orphan_secret = g_list_append (self->pv->orphan_secret, pkey);
+
 		/* No key was loaded as far as everyone is concerned */
 		return NULL;
 	}
- 
+
 	/* Just a new public key */
 
 	/* Check for orphans */
-	for (l = psrc->pv->orphan_secret; l; l = g_list_next (l)) {
-        
+	for (l = self->pv->orphan_secret; l; l = g_list_next (l)) {
+
 		seckey = seahorse_gpgme_key_get_private (l->data);
 		g_return_val_if_fail (seckey && seckey->subkeys && seckey->subkeys->keyid, NULL);
 		g_assert (seckey);
-		
+
 		/* Look for a matching key */
 		if (g_str_equal (id, seckey->subkeys->keyid)) {
-            
+
 			/* Set it up properly */
 			pkey = SEAHORSE_GPGME_KEY (l->data);
 			g_object_set (pkey, "pubkey", key, NULL);
-            
+
 			/* Remove item from orphan list cleanly */
-			psrc->pv->orphan_secret = g_list_remove_link (psrc->pv->orphan_secret, l);
+			self->pv->orphan_secret = g_list_remove_link (self->pv->orphan_secret, l);
 			g_list_free (l);
 			break;
 		}
 	}
 
 	if (pkey == NULL)
-		pkey = seahorse_gpgme_key_new (SEAHORSE_SOURCE (psrc), key, NULL);
-    
-	/* Add to context */ 
+		pkey = seahorse_gpgme_key_new (SEAHORSE_SOURCE (self), key, NULL);
+
+	/* Add to context */
 	seahorse_context_take_object (SCTX_APP (), SEAHORSE_OBJECT (pkey));
 
-	return pkey; 
+	return pkey;
 }
 
-/* -----------------------------------------------------------------------------
- *  GPG HOME DIR MONITORING
- */
-
-static gboolean
-scheduled_refresh (gpointer data)
+/* Remove the given key from the context */
+static void
+remove_key_from_context (gpointer hash_key,
+                         SeahorseObject *dummy,
+                         SeahorseGpgmeSource *self)
 {
-    SeahorseGpgmeSource *psrc = SEAHORSE_GPGME_SOURCE (data);
+	/* This function gets called as a GHRFunc on the lctx->checks hashtable. */
+	GQuark keyid = GPOINTER_TO_UINT (hash_key);
+	SeahorseObject *object;
 
-    seahorse_debug ("scheduled refresh event ocurring now");
-    cancel_scheduled_refresh (psrc);
-    seahorse_source_load_async (SEAHORSE_SOURCE (psrc));
-    
-    return FALSE; /* don't run again */
+	object = seahorse_context_get_object (seahorse_context_instance (),
+	                                      SEAHORSE_SOURCE (self), keyid);
+	if (object != NULL)
+		seahorse_context_remove_object (seahorse_context_instance (), object);
 }
 
+/* Completes one batch of key loading */
 static gboolean
-scheduled_dummy (gpointer data)
+on_idle_list_batch_of_keys (gpointer data)
 {
-    SeahorseGpgmeSource *psrc = SEAHORSE_GPGME_SOURCE (data);
-    seahorse_debug ("dummy refresh event occurring now");
-    psrc->pv->scheduled_refresh = 0;
-    return FALSE; /* don't run again */    
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (data);
+	source_list_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseGpgmeKey *pkey;
+	gpgme_key_t key;
+	guint batch;
+	GQuark keyid;
+	gchar *detail;
+
+	/* We load until done if batch is zero */
+	batch = DEFAULT_LOAD_BATCH;
+
+	while (batch-- > 0) {
+
+		if (!GPG_IS_OK (gpgme_op_keylist_next (closure->gctx, &key))) {
+
+			gpgme_op_keylist_end (closure->gctx);
+
+			/* If we were a refresh loader, then we remove the keys we didn't find */
+			if (closure->checks)
+				g_hash_table_foreach (closure->checks, (GHFunc)remove_key_from_context,
+				                      closure->source);
+
+			seahorse_progress_end (closure->cancellable, res);
+			g_simple_async_result_complete (res);
+			return FALSE; /* Remove event handler */
+		}
+
+		g_return_val_if_fail (key->subkeys && key->subkeys->keyid, FALSE);
+		keyid = seahorse_pgp_key_canonize_id (key->subkeys->keyid);
+
+		/* Invalid id from GPG ? */
+		if (keyid == 0) {
+			gpgme_key_unref (key);
+			continue;
+		}
+
+		/* During a refresh if only new or removed keys */
+		if (closure->checks) {
+
+			/* Make note that this key exists in key ring */
+			g_hash_table_remove (closure->checks, GUINT_TO_POINTER (keyid));
+
+		}
+
+		pkey = add_key_to_context (closure->source, key);
+
+		/* Load additional info */
+		if (pkey && closure->parts & LOAD_PHOTOS)
+			seahorse_gpgme_key_op_photos_load (pkey);
+
+		gpgme_key_unref (key);
+		closure->loaded++;
+	}
+
+	detail = g_strdup_printf (ngettext("Loaded %d key", "Loaded %d keys", closure->loaded), closure->loaded);
+	seahorse_progress_update (closure->cancellable, res, detail);
+	g_free (detail);
+
+	return TRUE;
 }
 
 static void
-cancel_scheduled_refresh (SeahorseGpgmeSource *psrc)
+on_source_list_cancelled (GCancellable *cancellable, gpointer user_data)
 {
-    if (psrc->pv->scheduled_refresh != 0) {
-        seahorse_debug ("cancelling scheduled refresh event");
-        g_source_remove (psrc->pv->scheduled_refresh);
-        psrc->pv->scheduled_refresh = 0;
-    }
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_list_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+
+	gpgme_op_keylist_end (closure->gctx);
 }
-        
+
 static void
-monitor_gpg_homedir (GFileMonitor *handle, GFile *file, GFile *other_file,
-                     GFileMonitorEvent event_type, gpointer user_data)
+seahorse_gpgme_source_list_async (SeahorseGpgmeSource *self,
+                                  const gchar **patterns,
+                                  gint parts,
+                                  gboolean secret,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
 {
-	SeahorseGpgmeSource *psrc = SEAHORSE_GPGME_SOURCE (user_data);
-	gchar *name;
-	
-	if (event_type == G_FILE_MONITOR_EVENT_CHANGED || 
-	    event_type == G_FILE_MONITOR_EVENT_DELETED ||
-	    event_type == G_FILE_MONITOR_EVENT_CREATED) {
+	source_list_closure *closure;
+	GSimpleAsyncResult *res;
+	SeahorseObject *object;
+	gpgme_error_t gerr;
+	GList *keys, *l;
 
-		name = g_file_get_basename (file);
-		if (g_str_has_suffix (name, SEAHORSE_EXT_GPG)) {
-			if (psrc->pv->scheduled_refresh == 0) {
-				seahorse_debug ("scheduling refresh event due to file changes");
-				psrc->pv->scheduled_refresh = g_timeout_add (500, scheduled_refresh, psrc);
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_gpgme_source_list_async);
+
+	closure = g_new0 (source_list_closure, 1);
+	closure->parts = parts;
+	closure->gctx = seahorse_gpgme_source_new_context ();
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->source = g_object_ref (self);
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_list_free);
+
+	if (parts & LOAD_FULL) {
+		gpgme_set_keylist_mode (closure->gctx, GPGME_KEYLIST_MODE_SIGS |
+		                        gpgme_get_keylist_mode (closure->gctx));
+	}
+
+	/* Start the key listing */
+	if (patterns)
+		gerr = gpgme_op_keylist_ext_start (closure->gctx, patterns, secret, 0);
+	else
+		gerr = gpgme_op_keylist_start (closure->gctx, NULL, secret);
+	g_return_if_fail (GPG_IS_OK (gerr));
+
+	/* Loading all the keys? */
+	if (patterns == NULL) {
+
+		closure->checks = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+		keys = seahorse_context_get_objects (seahorse_context_instance (),
+		                                     SEAHORSE_SOURCE (self));
+		for (l = keys; l != NULL; l = g_list_next (l)) {
+			object = SEAHORSE_OBJECT (l->data);
+			if ((secret && seahorse_object_get_usage (object) == SEAHORSE_USAGE_PRIVATE_KEY) ||
+			    (!secret && seahorse_object_get_usage (object) == SEAHORSE_USAGE_PUBLIC_KEY)) {
+				g_hash_table_insert (closure->checks,
+				                     GUINT_TO_POINTER (seahorse_object_get_id (l->data)),
+				                     GUINT_TO_POINTER (TRUE));
 			}
 		}
+		g_list_free (keys);
+
 	}
+
+	seahorse_progress_prep_and_begin (cancellable, res, NULL);
+	if (cancellable)
+		closure->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                G_CALLBACK (on_source_list_cancelled),
+		                                                res, NULL);
+
+	g_idle_add_full (G_PRIORITY_DEFAULT, on_idle_list_batch_of_keys,
+	                 g_object_ref (res), g_object_unref);
+
+	g_object_unref (res);
 }
 
-/* --------------------------------------------------------------------------
- *  OPERATION STUFF 
- */
- 
-static void 
-seahorse_load_operation_init (SeahorseLoadOperation *lop)
+static gboolean
+seahorse_gpgme_source_list_finish (SeahorseGpgmeSource *source,
+                                   GAsyncResult *result,
+                                   GError **error)
 {
-    gpgme_error_t err;
-    
-    err = init_gpgme (&(lop->ctx));
-    if (!GPG_IS_OK (err)) 
-        g_return_if_reached ();
-    
-    lop->checks = NULL;
-    lop->batch = DEFAULT_LOAD_BATCH;
-    lop->stag = 0;
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_gpgme_source_list_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
 }
 
-static void 
-seahorse_load_operation_dispose (GObject *gobject)
+static void
+cancel_scheduled_refresh (SeahorseGpgmeSource *self)
 {
-    SeahorseLoadOperation *lop = SEAHORSE_LOAD_OPERATION (gobject);
-    
-    /*
-     * Note that after this executes the rest of the object should
-     * still work without a segfault. This basically nullifies the 
-     * object, but doesn't free it.
-     * 
-     * This function should also be able to run multiple times.
-     */
-  
-    if (lop->stag) {
-        g_source_remove (lop->stag);
-        lop->stag = 0;
-    }
+	if (self->pv->scheduled_refresh != 0) {
+		seahorse_debug ("cancelling scheduled refresh event");
+		g_source_remove (self->pv->scheduled_refresh);
+		self->pv->scheduled_refresh = 0;
+	}
+}
 
-    if (lop->psrc) {
-        g_object_unref (lop->psrc);
-        lop->psrc = NULL;
-    }
+static gboolean
+scheduled_dummy (gpointer user_data)
+{
+	SeahorseGpgmeSource *self = SEAHORSE_GPGME_SOURCE (user_data);
+	seahorse_debug ("dummy refresh event occurring now");
+	self->pv->scheduled_refresh = 0;
+	return FALSE; /* don't run again */
+}
+
+typedef struct {
+	gboolean public_done;
+	gboolean secret_done;
+} source_load_closure;
 
-    G_OBJECT_CLASS (load_operation_parent_class)->dispose (gobject);
+static void
+on_source_secret_list_complete (GObject *source,
+                                GAsyncResult *result,
+                                gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_load_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	if (!seahorse_gpgme_source_list_finish (SEAHORSE_GPGME_SOURCE (source),
+	                                        result, &error))
+		g_simple_async_result_take_error (res, error);
+
+	closure->secret_done = TRUE;
+	if (closure->public_done)
+		g_simple_async_result_complete (res);
+
+	g_object_unref (res);
 }
 
-static void 
-seahorse_load_operation_finalize (GObject *gobject)
+static void
+on_source_public_list_complete (GObject *source,
+                                GAsyncResult *result,
+                                gpointer user_data)
 {
-    SeahorseLoadOperation *lop = SEAHORSE_LOAD_OPERATION (gobject);
-    
-    if (lop->checks)    
-        g_hash_table_destroy (lop->checks);
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_load_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	if (!seahorse_gpgme_source_list_finish (SEAHORSE_GPGME_SOURCE (source),
+	                                        result, &error))
+		g_simple_async_result_take_error (res, error);
 
-    g_assert (lop->stag == 0);
-    g_assert (lop->psrc == NULL);
+	closure->public_done = TRUE;
+	if (closure->secret_done)
+		g_simple_async_result_complete (res);
 
-    if (lop->ctx)
-        gpgme_release (lop->ctx);
-        
-    G_OBJECT_CLASS (load_operation_parent_class)->finalize (gobject);
+	g_object_unref (res);
 }
 
-static void 
-seahorse_load_operation_cancel (SeahorseOperation *operation)
+static void
+seahorse_gpgme_source_load_full_async (SeahorseGpgmeSource *source,
+                                       const gchar **patterns,
+                                       gint parts,
+                                       GCancellable *cancellable,
+                                       GAsyncReadyCallback callback,
+                                       gpointer user_data)
+{
+	SeahorseGpgmeSource *self = SEAHORSE_GPGME_SOURCE (source);
+	GSimpleAsyncResult *res;
+	source_load_closure *closure;
+
+	/* Schedule a dummy refresh. This blocks all monitoring for a while */
+	cancel_scheduled_refresh (self);
+	self->pv->scheduled_refresh = g_timeout_add (500, scheduled_dummy, self);
+	seahorse_debug ("scheduled a dummy refresh");
+
+	seahorse_debug ("refreshing keys...");
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_gpgme_source_load_full_async);
+	closure = g_new0 (source_load_closure, 1);
+	g_simple_async_result_set_op_res_gpointer (res, closure, g_free);
+
+	/* Secret keys */
+	seahorse_gpgme_source_list_async (self, patterns, 0, TRUE, cancellable,
+	                                  on_source_secret_list_complete,
+	                                  g_object_ref (res));
+
+	/* Public keys */
+	seahorse_gpgme_source_list_async (self, patterns, 0, FALSE, cancellable,
+	                                  on_source_public_list_complete,
+	                                  g_object_ref (res));
+
+	g_object_unref (res);
+}
+
+static void
+seahorse_gpgme_source_load_async (SeahorseSource *source,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
 {
-    SeahorseLoadOperation *lop = SEAHORSE_LOAD_OPERATION (operation);    
+	seahorse_gpgme_source_load_full_async (SEAHORSE_GPGME_SOURCE (source),
+	                                       NULL, 0, cancellable, callback,
+	                                       user_data);
+}
 
-    gpgme_op_keylist_end (lop->ctx);
-    seahorse_operation_mark_done (operation, TRUE, NULL);
+static gboolean
+seahorse_gpgme_source_load_finish (SeahorseSource *source,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_gpgme_source_load_full_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
+
+typedef struct {
+	GCancellable *cancellable;
+	SeahorseGpgmeSource *source;
+	gpgme_ctx_t gctx;
+	gpgme_data_t data;
+	gchar **patterns;
+	GList *keys;
+} source_import_closure;
+
+static void
+source_import_free (gpointer data)
+{
+	source_import_closure *closure = data;
+	g_clear_object (&closure->cancellable);
+	gpgme_release (closure->gctx);
+	gpgme_data_release (closure->data);
+	g_object_unref (closure->source);
+	g_strfreev (closure->patterns);
+	g_list_free (closure->keys);
+	g_free (closure);
+}
+
+static void
+on_source_import_loaded (GObject *source,
+                         GAsyncResult *result,
+                         gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseObject *object;
+	GQuark keyid;
+	guint i;
+
+	for (i = 0; closure->patterns[i] != NULL; i++) {
+		keyid = seahorse_pgp_key_canonize_id (closure->patterns[i]);
+		if (!keyid) {
+			g_warning ("imported non key with strange keyid: %s",
+			           closure->patterns[i]);
+			continue;
+		}
+
+		object = seahorse_context_get_object (seahorse_context_instance (),
+		                                      SEAHORSE_SOURCE (closure->source),
+		                                      keyid);
+		if (object == NULL) {
+			g_warning ("imported key but then couldn't find it in keyring: %s",
+			           closure->patterns[i]);
+			continue;
+		}
+
+		closure->keys = g_list_prepend (closure->keys, object);
+	}
+
+	seahorse_progress_end (closure->cancellable, res);
+	g_simple_async_result_complete (res);
+	g_object_unref (res);
 }
 
-/* Completes one batch of key loading */
 static gboolean
-keyload_handler (SeahorseLoadOperation *lop)
+on_source_import_complete (gpgme_error_t gerr,
+                           gpointer user_data)
 {
-    SeahorseGpgmeKey *pkey;
-    gpgme_key_t key;
-    guint batch;
-    GQuark keyid;
-    gchar *t;
-    
-    g_assert (SEAHORSE_IS_LOAD_OPERATION (lop));
-    
-    /* We load until done if batch is zero */
-    batch = lop->batch == 0 ? ~0 : lop->batch;
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	gpgme_import_result_t results;
+	gpgme_import_status_t import;
+	GError *error = NULL;
+	const gchar *msg;
+	guint i;
+
+	if (seahorse_gpgme_propagate_error (gerr, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+		return FALSE; /* don't call again */
+	}
 
-    while (batch-- > 0) {
-    
-        if (!GPG_IS_OK (gpgme_op_keylist_next (lop->ctx, &key))) {
-        
-            gpgme_op_keylist_end (lop->ctx);
-        
-            /* If we were a refresh loader, then we remove the keys we didn't find */
-            if (lop->checks) 
-                g_hash_table_foreach (lop->checks, (GHFunc)remove_key_from_context, lop->psrc);
-            
-            seahorse_operation_mark_done (SEAHORSE_OPERATION (lop), FALSE, NULL);         
-            return FALSE; /* Remove event handler */
-        }
-        
-        g_return_val_if_fail (key->subkeys && key->subkeys->keyid, FALSE);
-        keyid = seahorse_pgp_key_canonize_id (key->subkeys->keyid);
-        
-        /* Invalid id from GPG ? */
-        if (!keyid) {
-            gpgme_key_unref (key);
-            continue;
-        }
-        
-        /* During a refresh if only new or removed keys */
-        if (lop->checks) {
-
-            /* Make note that this key exists in key ring */
-            g_hash_table_remove (lop->checks, GUINT_TO_POINTER (keyid));
-
-        }
-        
-        pkey = add_key_to_context (lop->psrc, key);
-
-        /* Load additional info */
-        if (pkey && lop->parts & LOAD_PHOTOS)
-        	seahorse_gpgme_key_op_photos_load (pkey);
-
-        gpgme_key_unref (key);
-        lop->loaded++;
-    }
-    
-    /* More to do, so queue for next round */        
-    if (lop->stag == 0) {
-    
-        /* If it returns TRUE (like any good GSourceFunc) it means
-         * it needs to stick around, so we register an idle handler */
-        lop->stag = g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc)keyload_handler, 
-                                     lop, NULL);
-    }
-    
-    /* TODO: We can use the GPGME progress to make this more accurate */
-    t = g_strdup_printf (ngettext("Loaded %d key", "Loaded %d keys", lop->loaded), lop->loaded);
-    seahorse_operation_mark_progress (SEAHORSE_OPERATION (lop), t, 0.0);
-    g_free (t);
-    
-    return TRUE; 
+	/* Figure out which keys were imported */
+	results = gpgme_op_import_result (closure->gctx);
+	if (results == NULL) {
+		g_simple_async_result_complete (res);
+		return FALSE; /* don't call again */
+	}
+
+	/* Dig out all the fingerprints for use as load patterns */
+	closure->patterns = g_new0 (gchar*, results->considered + 1);
+	for (i = 0, import = results->imports;
+	     i < results->considered && import;
+	     import = import->next) {
+		if (GPG_IS_OK (import->result))
+			closure->patterns[i++] = g_strdup (import->fpr);
+	}
+
+	/* See if we've managed to import any ... */
+	if (closure->patterns[0] == NULL) {
+
+		/* ... try and find out why */
+		if (results->considered > 0 && results->no_user_id) {
+			msg = _("Invalid key data (missing UIDs). This may be due to a computer with a date set in the future or a missing self-signature.");
+			g_simple_async_result_set_error (res, SEAHORSE_ERROR, -1, "%s", msg);
+		}
+
+		g_simple_async_result_complete (res);
+		return FALSE; /* don't call again */
+	}
+
+	/* Reload public keys */
+	seahorse_gpgme_source_load_full_async (closure->source, (const gchar **)closure->patterns,
+	                                       LOAD_FULL, closure->cancellable,
+	                                       on_source_import_loaded, g_object_ref (res));
+
+	return FALSE; /* don't call again */
 }
 
-static SeahorseLoadOperation*
-seahorse_load_operation_start (SeahorseGpgmeSource *psrc, const gchar **pattern, 
-                               guint parts, gboolean secret)
+static void
+seahorse_gpgme_source_import_async (SeahorseSource *source,
+                                    GInputStream *input,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
 {
-    SeahorseLoadOperation *lop;
-    gpgme_error_t err;
-    GList *keys, *l;
-    SeahorseObject *sobj;
-    
-    g_assert (SEAHORSE_IS_GPGME_SOURCE (psrc));
+	SeahorseGpgmeSource *self = SEAHORSE_GPGME_SOURCE (source);
+	GSimpleAsyncResult *res;
+	source_import_closure *closure;
+	gpgme_error_t gerr;
+	GError *error = NULL;
+	GSource *gsource;
 
-    lop = g_object_new (SEAHORSE_TYPE_LOAD_OPERATION, NULL);    
-    lop->psrc = psrc;
-    lop->secret = secret;
-    g_object_ref (psrc);
-    
-    /* See which extra parts we should load */
-    lop->parts = parts;
-    if (parts & LOAD_FULL) 
-        gpgme_set_keylist_mode (lop->ctx, GPGME_KEYLIST_MODE_SIGS | 
-                gpgme_get_keylist_mode (lop->ctx));
-    
-    /* Start the key listing */
-    if (pattern)
-        err = gpgme_op_keylist_ext_start (lop->ctx, pattern, secret, 0);
-    else
-        err = gpgme_op_keylist_start (lop->ctx, NULL, secret);
-    g_return_val_if_fail (GPG_IS_OK (err), lop);
-    
-    /* Loading all the keys? */
-    if (!pattern) {
-     
-        lop->checks = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
-        keys = seahorse_context_get_objects (SCTX_APP (), SEAHORSE_SOURCE (psrc));
-        for (l = keys; l; l = g_list_next (l)) {
-            sobj = SEAHORSE_OBJECT (l->data);
-            if (secret && seahorse_object_get_usage (sobj) != SEAHORSE_USAGE_PRIVATE_KEY) 
-                continue;
-            g_hash_table_insert (lop->checks, GUINT_TO_POINTER (seahorse_object_get_id (l->data)), 
-                                              GUINT_TO_POINTER (TRUE));
-        }
-        g_list_free (keys);
-        
-    }
-    
-    seahorse_operation_mark_start (SEAHORSE_OPERATION (lop));
-    seahorse_operation_mark_progress (SEAHORSE_OPERATION (lop), _("Loading Keys..."), 0.0);
-    
-    /* Run one iteration of the handler */
-    keyload_handler (lop);
- 
-    return lop;
-}    
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_gpgme_source_import_async);
+	closure = g_new0 (source_import_closure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->gctx = seahorse_gpgme_source_new_context ();
+	closure->data = seahorse_gpgme_data_input (input);
+	closure->source = g_object_ref (self);
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_import_free);
+
+	seahorse_progress_prep_and_begin (cancellable, res, NULL);
+	gsource = seahorse_gpgme_gsource_new (closure->gctx, cancellable);
+	g_source_set_callback (gsource, (GSourceFunc)on_source_import_complete,
+	                       g_object_ref (res), g_object_unref);
+
+	gerr = gpgme_op_import_start (closure->gctx, closure->data);
+
+	if (seahorse_gpgme_propagate_error (gerr, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+
+	} else {
+		g_source_attach (gsource, g_main_context_default ());
+	}
+
+	g_source_unref (gsource);
+	g_object_unref (res);
+}
+
+static GList *
+seahorse_gpgme_source_import_finish (SeahorseSource *source,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	source_import_closure *closure;
+	GList *results;
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_gpgme_source_import_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	results = closure->keys;
+	closure->keys = NULL;
+	return results;
+}
+
+typedef struct {
+	GPtrArray *keyids;
+	gint at;
+	gpgme_data_t data;
+	gpgme_ctx_t gctx;
+	GOutputStream *output;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+} source_export_closure;
 
 static void
-prepare_import_results (SeahorseGpgmeOperation *pop, SeahorseGpgmeSource *psrc)
-{
-    SeahorseObject *sobj;
-    SeahorseLoadOperation *lop;
-    gpgme_import_result_t results;
-    gpgme_import_status_t import;
-    SeahorseSource *sksrc;
-    GList *keys = NULL;
-    const gchar **patterns = NULL;
-    GError *err = NULL;
-    gchar *msg;
-    GQuark keyid;
-    guint i;
-    
-    sksrc = SEAHORSE_SOURCE (psrc);
-
-    /* Figure out which keys were imported */
-    results = gpgme_op_import_result (pop->gctx);
-    if (results) {
-            
-        /* Dig out all the fingerprints for use as load patterns */
-        patterns = (const gchar**)g_new0(gchar*, results->considered + 1);
-        for (i = 0, import = results->imports; 
-             i < results->considered && import; 
-             import = import->next) {
-            if (GPG_IS_OK (import->result))
-                patterns[i++] = import->fpr;
-        }
-        
-        /* See if we've managed to import any ... */
-        if (!patterns[0] && results->considered > 0) {
-            
-            /* ... try and find out why */
-            if (results->no_user_id) {
-                msg = _("Invalid key data (missing UIDs). This may be due to a computer with a date set in the future or a missing self-signature.");
-                g_set_error (&err, SEAHORSE_ERROR, -1, "%s", msg);
-                seahorse_operation_mark_done (SEAHORSE_OPERATION (pop), FALSE, err);
-                return;
-            }
-        }
-
-        /* Reload public keys */
-        lop = seahorse_load_operation_start (psrc, patterns, LOAD_FULL, FALSE);
-        seahorse_operation_wait (SEAHORSE_OPERATION (lop));
-        g_object_unref (lop);
-
-        /* Reload secret keys */
-        lop = seahorse_load_operation_start (psrc, patterns, LOAD_FULL, TRUE);
-        seahorse_operation_wait (SEAHORSE_OPERATION (lop));
-        g_object_unref (lop);
-            
-        g_free (patterns);
-            
-        /* Now get a list of the new keys */
-        for (import = results->imports; import; import = import->next) {
-            if (!GPG_IS_OK (import->result))
-                continue;
-            
-            keyid = seahorse_pgp_key_canonize_id (import->fpr);
-            if (!keyid) {
-                g_warning ("imported non key with strange keyid: %s", import->fpr);
-                continue;
-            }
-            
-            sobj = seahorse_context_get_object (SCTX_APP (), sksrc, keyid);
-            if (sobj == NULL) {
-                g_warning ("imported key but then couldn't find it in keyring: %s", 
-                           import->fpr);
-                continue;
-            }
-            
-            keys = g_list_prepend (keys, sobj);
-        }
-    }
-    
-    seahorse_operation_mark_result (SEAHORSE_OPERATION (pop), keys, 
-                                    (GDestroyNotify)g_list_free);
+source_export_free (gpointer data)
+{
+	source_export_closure *closure = data;
+	g_cancellable_disconnect (closure->cancellable, closure->cancelled_sig);
+	g_clear_object (&closure->cancellable);
+	gpgme_data_release (closure->data);
+	gpgme_release (closure->gctx);
+	g_ptr_array_free (closure->keyids, TRUE);
+	g_object_unref (closure->output);
+	g_free (closure);
 }
 
-/* --------------------------------------------------------------------------
- * METHODS
- */
+static gboolean
+on_source_export_complete (gpgme_error_t gerr,
+                           gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_export_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	if (seahorse_gpgme_propagate_error (gerr, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+		return FALSE; /* don't call again */
+	}
+
+	if (closure->at >= 0)
+		seahorse_progress_end (closure->cancellable,
+		                       closure->keyids->pdata[closure->at]);
+
+	g_assert (closure->at < (gint)closure->keyids->len);
+	closure->at++;
+
+	if (closure->at == closure->keyids->len) {
+		g_simple_async_result_complete (res);
+		return FALSE; /* don't run this again */
+	}
 
-static SeahorseOperation*
-seahorse_gpgme_source_load (SeahorseSource *src)
+	/* Do the next key in the list */
+	gerr = gpgme_op_export_start (closure->gctx, closure->keyids->pdata[closure->at],
+	                              0, closure->data);
+
+	if (seahorse_gpgme_propagate_error (gerr, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+		return FALSE; /* don't run this again */
+	}
+
+	seahorse_progress_begin (closure->cancellable,
+	                         closure->keyids->pdata[closure->at]);
+	return TRUE; /* call this source again */
+}
+
+static void
+seahorse_gpgme_source_export_async (SeahorseSource *source,
+                                    GList *objects,
+                                    GOutputStream *output,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
 {
-    SeahorseGpgmeSource *psrc;
-    SeahorseLoadOperation *lop;
-    
-    g_assert (SEAHORSE_IS_SOURCE (src));
-    psrc = SEAHORSE_GPGME_SOURCE (src);
-    
-    /* Schedule a dummy refresh. This blocks all monitoring for a while */
-    cancel_scheduled_refresh (psrc);
-    psrc->pv->scheduled_refresh = g_timeout_add (500, scheduled_dummy, psrc);
-    seahorse_debug ("scheduled a dummy refresh");
- 
-    seahorse_debug ("refreshing keys...");
+	GSimpleAsyncResult *res;
+	source_export_closure *closure;
+	SeahorsePgpKey *key;
+	gchar *keyid;
+	GSource *gsource;
+	GList *l;
 
-    /* Secret keys */
-    lop = seahorse_load_operation_start (psrc, NULL, 0, FALSE);
-    seahorse_multi_operation_take (psrc->pv->operations, SEAHORSE_OPERATION (lop));
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_gpgme_source_export_async);
+	closure = g_new0 (source_export_closure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->gctx = seahorse_gpgme_source_new_context ();
+	closure->data = seahorse_gpgme_data_output (output);
+	closure->keyids = g_ptr_array_new_with_free_func (g_free);
+	closure->output = g_object_ref (output);
+	closure->at = -1;
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_export_free);
+
+	gpgme_set_armor (closure->gctx, TRUE);
+	gpgme_set_textmode (closure->gctx, TRUE);
+
+	for (l = objects; l != NULL; l = g_list_next (l)) {
+
+		/* Ignore PGP Uids */
+		if (SEAHORSE_IS_PGP_UID (l->data))
+			continue;
+
+		g_return_if_fail (SEAHORSE_IS_PGP_KEY (l->data));
+		key = SEAHORSE_PGP_KEY (l->data);
+		g_return_if_fail (seahorse_object_get_source (SEAHORSE_OBJECT (key)) == source);
+
+		/* Building list */
+		keyid = g_strdup (seahorse_pgp_key_get_keyid (key));
+		seahorse_progress_prep (closure->cancellable, keyid, NULL);
+		g_ptr_array_add (closure->keyids, keyid);
+	}
+
+	gsource = seahorse_gpgme_gsource_new (closure->gctx, cancellable);
+	g_source_set_callback (gsource, (GSourceFunc)on_source_export_complete,
+	                       g_object_ref (res), g_object_unref);
 
-    /* Public keys */
-    lop = seahorse_load_operation_start (psrc, NULL, 0, TRUE);
-    seahorse_multi_operation_take (psrc->pv->operations, SEAHORSE_OPERATION (lop));
+	/* Get things started */
+	if (on_source_export_complete (0, res))
+		g_source_attach (gsource, g_main_context_default ());
 
-    g_object_ref (psrc->pv->operations);
-    return SEAHORSE_OPERATION (psrc->pv->operations);
+	g_source_unref (gsource);
+	g_object_unref (res);
 }
 
-static SeahorseOperation* 
-seahorse_gpgme_source_import (SeahorseSource *sksrc, GInputStream *input)
+static GOutputStream *
+seahorse_gpgme_source_export_finish (SeahorseSource *source,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	source_export_closure *closure;
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_gpgme_source_export_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	return closure->output;
+}
+
+static gboolean
+scheduled_refresh (gpointer user_data)
+{
+	SeahorseGpgmeSource *self = SEAHORSE_GPGME_SOURCE (user_data);
+
+	seahorse_debug ("scheduled refresh event ocurring now");
+	cancel_scheduled_refresh (self);
+	seahorse_source_load_async (SEAHORSE_SOURCE (self), NULL, NULL, NULL);
+
+	return FALSE; /* don't run again */
+}
+
+static void
+monitor_gpg_homedir (GFileMonitor *handle, GFile *file, GFile *other_file,
+                     GFileMonitorEvent event_type, gpointer user_data)
+{
+	SeahorseGpgmeSource *self = SEAHORSE_GPGME_SOURCE (user_data);
+	gchar *name;
+
+	if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
+	    event_type == G_FILE_MONITOR_EVENT_DELETED ||
+	    event_type == G_FILE_MONITOR_EVENT_CREATED) {
+
+		name = g_file_get_basename (file);
+		if (g_str_has_suffix (name, SEAHORSE_EXT_GPG)) {
+			if (self->pv->scheduled_refresh == 0) {
+				seahorse_debug ("scheduling refresh event due to file changes");
+				self->pv->scheduled_refresh = g_timeout_add (500, scheduled_refresh, self);
+			}
+		}
+	}
+}
+
+static void
+seahorse_gpgme_source_init (SeahorseGpgmeSource *self)
 {
-	SeahorseGpgmeOperation *pop;
-	SeahorseGpgmeSource *psrc;
 	gpgme_error_t gerr;
-	gpgme_data_t data;
-    
-    	g_return_val_if_fail (SEAHORSE_IS_GPGME_SOURCE (sksrc), NULL);
-    	psrc = SEAHORSE_GPGME_SOURCE (sksrc);
-    
-    	g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
-    
-    	pop = seahorse_gpgme_operation_new (_("Importing Keys"));
-    	g_return_val_if_fail (pop != NULL, NULL);
-    
-	data = seahorse_gpgme_data_input (input);
-	g_return_val_if_fail (data, NULL);
-    
-	gerr = gpgme_op_import_start (pop->gctx, data);
-    
-	g_signal_connect (pop, "results", G_CALLBACK (prepare_import_results), psrc);
-	g_object_set_data_full (G_OBJECT (pop), "source-data", data, 
-	                        (GDestroyNotify)gpgme_data_release);
-    
-	/* Couldn't start import */
-	if (!GPG_IS_OK (gerr))
-		seahorse_gpgme_operation_mark_failed (pop, gerr);
-    
-	return SEAHORSE_OPERATION (pop);
+	GError *err = NULL;
+	const gchar *gpg_homedir;
+	GFile *file;
+
+	gerr = init_gpgme (&self->gctx);
+	g_return_if_fail (GPG_IS_OK (gerr));
+
+	/* init private vars */
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, SEAHORSE_TYPE_GPGME_SOURCE, SeahorseGpgmeSourcePrivate);
+
+	self->pv->scheduled_refresh = 0;
+	self->pv->monitor_handle = NULL;
+
+	gpg_homedir = seahorse_gpg_homedir ();
+	file = g_file_new_for_path (gpg_homedir);
+	g_return_if_fail (file != NULL);
+
+	self->pv->monitor_handle = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, &err);
+	g_object_unref (file);
+
+	if (self->pv->monitor_handle) {
+		g_signal_connect (self->pv->monitor_handle, "changed",
+		                  G_CALLBACK (monitor_gpg_homedir), self);
+	} else {
+		g_warning ("couldn't monitor the GPG home directory: %s: %s", 
+		           gpg_homedir, err && err->message ? err->message : "");
+	}
 }
 
-static SeahorseOperation* 
-seahorse_gpgme_source_export (SeahorseSource *sksrc, GList *keys, GOutputStream *output)
+static void
+seahorse_gpgme_source_dispose (GObject *object)
 {
-	SeahorseGpgmeOperation *pop;
-	SeahorseGpgmeKey *pkey;
-	SeahorseObject *object;
-	ExportContext *ctx;
-	gpgme_data_t data;
-	const gchar *keyid;
+	SeahorseGpgmeSource *self = SEAHORSE_GPGME_SOURCE (object);
 	GList *l;
-    
-    	g_return_val_if_fail (SEAHORSE_IS_GPGME_SOURCE (sksrc), NULL);
-    	g_return_val_if_fail (output == NULL || G_IS_OUTPUT_STREAM (output), NULL);
-
-    	pop = seahorse_gpgme_operation_new (_("Exporting Keys"));
-    	g_return_val_if_fail (pop != NULL, NULL);
-
-	g_object_ref (output);
-        seahorse_operation_mark_result (SEAHORSE_OPERATION (pop), output, 
-                                        (GDestroyNotify)g_object_unref);
-    	
-        gpgme_set_armor (pop->gctx, TRUE);
-        gpgme_set_textmode (pop->gctx, TRUE);
-        
-        data = seahorse_gpgme_data_output (output);
-        g_return_val_if_fail (data, NULL);
-
-        /* Export context for asynchronous export */
-        ctx = g_new0 (ExportContext, 1);
-        ctx->keyids = g_array_new (TRUE, TRUE, sizeof (gchar*));
-        ctx->at = 0;
-        ctx->data = data;
-        g_object_set_data_full (G_OBJECT (pop), "export-context", ctx, free_export_context);
-    
-        for (l = keys; l != NULL; l = g_list_next (l)) {
-        	
-        	/* Ignore PGP Uids */
-        	if (SEAHORSE_IS_PGP_UID (l->data))
-        		continue;
-        
-        	g_return_val_if_fail (SEAHORSE_IS_PGP_KEY (l->data), NULL);
-        	pkey = SEAHORSE_GPGME_KEY (l->data);
-        
-        	object = SEAHORSE_OBJECT (l->data);
-        	g_return_val_if_fail (seahorse_object_get_source (object) == sksrc, NULL);
-        
-        	/* Building list */
-        	keyid = seahorse_pgp_key_get_keyid (SEAHORSE_PGP_KEY (pkey));
-        	g_array_append_val (ctx->keyids, keyid);
-        }
-
-        g_signal_connect (pop, "results", G_CALLBACK (export_key_callback), ctx);
-        export_key_callback (pop, ctx);
-    
-        return SEAHORSE_OPERATION (pop);
+
+	/*
+	 * Note that after this executes the rest of the object should
+	 * still work without a segfault. This basically nullifies the
+	 * object, but doesn't free it.
+	 *
+	 * This function should also be able to run multiple times.
+	 */
+
+	cancel_scheduled_refresh (self);
+	if (self->pv->monitor_handle) {
+		g_object_unref (self->pv->monitor_handle);
+		self->pv->monitor_handle = NULL;
+	}
+
+	for (l = self->pv->orphan_secret; l != NULL; l = g_list_next (l))
+		g_object_unref (l->data);
+	g_list_free (self->pv->orphan_secret);
+	self->pv->orphan_secret = NULL;
+
+	if (self->gctx)
+		gpgme_release (self->gctx);
+
+	G_OBJECT_CLASS (seahorse_gpgme_source_parent_class)->dispose (object);
 }
 
-/* -------------------------------------------------------------------------- 
- * FUNCTIONS
- */
+static void
+seahorse_gpgme_source_finalize (GObject *object)
+{
+	SeahorseGpgmeSource *self = SEAHORSE_GPGME_SOURCE (object);
+
+	/* All monitoring and scheduling should be done */
+	g_assert (self->pv->scheduled_refresh == 0);
+	g_assert (self->pv->monitor_handle == 0);
+
+	G_OBJECT_CLASS (seahorse_gpgme_source_parent_class)->finalize (object);
+}
+
+static void 
+seahorse_gpgme_source_get_property (GObject *object,
+                                    guint prop_id,
+                                    GValue *value,
+                                    GParamSpec *pspec)
+{
+	switch (prop_id) {
+	case PROP_SOURCE_TAG:
+		g_value_set_uint (value, SEAHORSE_PGP);
+		break;
+	case PROP_SOURCE_LOCATION:
+		g_value_set_enum (value, SEAHORSE_LOCATION_LOCAL);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+seahorse_gpgme_source_class_init (SeahorseGpgmeSourceClass *klass)
+{
+	GObjectClass *gobject_class;
+
+	g_message ("init gpgme version %s", gpgme_check_version (NULL));
+
+#ifdef ENABLE_NLS
+	gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
+	gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
+#endif
+
+	gobject_class = G_OBJECT_CLASS (klass);
+	gobject_class->dispose = seahorse_gpgme_source_dispose;
+	gobject_class->finalize = seahorse_gpgme_source_finalize;
+	gobject_class->get_property = seahorse_gpgme_source_get_property;
+
+	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
+	g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
+
+	g_type_class_add_private (klass, sizeof (SeahorseGpgmeSourcePrivate));
+
+	seahorse_registry_register_type (NULL, SEAHORSE_TYPE_GPGME_SOURCE, "source", "local", SEAHORSE_PGP_STR, NULL);
+	seahorse_registry_register_function (NULL, seahorse_pgp_key_canonize_id, "canonize", SEAHORSE_PGP_STR, NULL);
+}
+
+static void
+seahorse_source_iface (SeahorseSourceIface *iface)
+{
+	iface->load_async = seahorse_gpgme_source_load_async;
+	iface->load_finish = seahorse_gpgme_source_load_finish;
+	iface->import_async = seahorse_gpgme_source_import_async;
+	iface->import_finish = seahorse_gpgme_source_import_finish;
+	iface->export_async = seahorse_gpgme_source_export_async;
+	iface->export_finish = seahorse_gpgme_source_export_finish;
+}
 
 /**
  * seahorse_gpgme_source_new
@@ -980,16 +1034,16 @@ seahorse_gpgme_source_export (SeahorseSource *sksrc, GList *keys, GOutputStream
  * 
  * Returns: The key source.
  **/
-SeahorseGpgmeSource*
+SeahorseGpgmeSource *
 seahorse_gpgme_source_new (void)
 {
-   return g_object_new (SEAHORSE_TYPE_GPGME_SOURCE, NULL);
-}   
+	return g_object_new (SEAHORSE_TYPE_GPGME_SOURCE, NULL);
+}
 
-gpgme_ctx_t          
-seahorse_gpgme_source_new_context ()
+gpgme_ctx_t
+seahorse_gpgme_source_new_context (void)
 {
-    gpgme_ctx_t ctx = NULL;
-    g_return_val_if_fail (GPG_IS_OK (init_gpgme (&ctx)), NULL);
-    return ctx;
+	gpgme_ctx_t ctx = NULL;
+	g_return_val_if_fail (GPG_IS_OK (init_gpgme (&ctx)), NULL);
+	return ctx;
 }
diff --git a/pgp/seahorse-gpgme.c b/pgp/seahorse-gpgme.c
index dbe39e4..b2a7695 100644
--- a/pgp/seahorse-gpgme.c
+++ b/pgp/seahorse-gpgme.c
@@ -23,6 +23,8 @@
 
 #include "seahorse-gpgme.h"
 
+#define DEBUG_FLAG SEAHORSE_DEBUG_OPERATION
+#include "seahorse-debug.h"
 #include "seahorse-util.h"
 
 #include <glib/gi18n.h>
@@ -49,31 +51,33 @@ seahorse_gpgme_error_domain (void)
 	return q;
 }
 
-/**
- * seahorse_gpgme_to_error:
- * @gerr: The gpgme error
- * @err: The glib error to create
- *
- * Creates a glib error out of a gpgme error
- *
- */
-void    
-seahorse_gpgme_to_error (gpgme_error_t gerr, GError** err)
+gboolean
+seahorse_gpgme_propagate_error (gpgme_error_t gerr, GError** error)
 {
 	gpgme_err_code_t code;
-    
-    	/* Make sure this is actually an error */
-    	code = gpgme_err_code (gerr);
-   	g_return_if_fail (code != 0);
-    
-    	/* Special case some error messages */
-    	if (code == GPG_ERR_DECRYPT_FAILED) {
-    		g_set_error (err, SEAHORSE_GPGME_ERROR, code, "%s", 
-    		             _("Decryption failed. You probably do not have the decryption key."));
-    	} else {
-    		g_set_error (err, SEAHORSE_GPGME_ERROR, code, "%s", 
-    		             gpgme_strerror (gerr));
-    	}
+
+	/* Make sure this is actually an error */
+	code = gpgme_err_code (gerr);
+	if (code == 0)
+		return FALSE;
+
+	/* Special case some error messages */
+	switch (code) {
+	case GPG_ERR_DECRYPT_FAILED:
+		g_set_error_literal (error, SEAHORSE_GPGME_ERROR, code,
+		             _("Decryption failed. You probably do not have the decryption key."));
+		break;
+	case GPG_ERR_CANCELED:
+		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+		                     _("The operation was cancelled"));
+		break;
+	default:
+		g_set_error_literal (error, SEAHORSE_GPGME_ERROR, code,
+		                     gpgme_strerror (gerr));
+		break;
+	}
+
+	return TRUE;
 }
 
 /**
@@ -240,3 +244,262 @@ seahorse_gpgme_get_keytype_table (SeahorseKeyTypeTable *table)
 	return gerr;
 }
 
+typedef struct _WatchData {
+	GSource *gsource;
+	gboolean registered;
+	GPollFD poll_fd;
+
+	/* GPGME watch info */
+	gpgme_io_cb_t fnc;
+	void *fnc_data;
+
+} WatchData;
+
+typedef gboolean (*SeahorseGpgmeCallback)   (gpgme_error_t status,
+                                             gpointer user_data);
+
+typedef struct {
+	GSource source;
+	gpgme_ctx_t gctx;
+	struct gpgme_io_cbs io_cbs;
+	gboolean busy;
+	GList *watches;
+	GCancellable *cancellable;
+	gint cancelled_sig;
+	gboolean finished;
+	gpgme_error_t status;
+} SeahorseGpgmeGSource;
+
+static gboolean
+seahorse_gpgme_gsource_prepare (GSource *gsource,
+                                gint *timeout)
+{
+	SeahorseGpgmeGSource *gpgme_gsource = (SeahorseGpgmeGSource *)gsource;
+
+	if (gpgme_gsource->finished)
+		return TRUE;
+
+	/* No other way, but to poll */
+	*timeout = -1;
+	return FALSE;
+}
+
+static gboolean
+seahorse_gpgme_gsource_check (GSource *gsource)
+{
+	SeahorseGpgmeGSource *gpgme_gsource = (SeahorseGpgmeGSource *)gsource;
+	WatchData *watch;
+	GList *l;
+
+	for (l = gpgme_gsource->watches; l != NULL; l = g_list_next (l)) {
+		watch = l->data;
+		if (watch->registered && watch->poll_fd.revents)
+			return TRUE;
+	}
+
+	if (gpgme_gsource->finished)
+		return TRUE;
+
+	return FALSE;
+}
+
+static gboolean
+seahorse_gpgme_gsource_dispatch (GSource *gsource,
+                                GSourceFunc callback,
+                                gpointer user_data)
+{
+	SeahorseGpgmeGSource *gpgme_gsource = (SeahorseGpgmeGSource *)gsource;
+	WatchData *watch;
+	GList *l, *watches;
+
+	watches = g_list_copy (gpgme_gsource->watches);
+	for (l = watches; l != NULL; l = g_list_next (l)) {
+		watch = l->data;
+		if (watch->registered && watch->poll_fd.revents) {
+			seahorse_debug ("GPGME OP: io for GPGME on %d", watch->poll_fd.fd);
+			g_assert (watch->fnc);
+			(watch->fnc) (watch->fnc_data, watch->poll_fd.fd);
+			watch->poll_fd.revents = 0;
+		}
+	}
+	g_list_free (watches);
+
+	if (gpgme_gsource->finished)
+		return ((SeahorseGpgmeCallback)callback) (gpgme_gsource->status,
+		                                          user_data);
+
+	return TRUE;
+}
+
+static void
+seahorse_gpgme_gsource_finalize (GSource *gsource)
+{
+	SeahorseGpgmeGSource *gpgme_gsource = (SeahorseGpgmeGSource *)gsource;
+	g_cancellable_disconnect (gpgme_gsource->cancellable,
+	                          gpgme_gsource->cancelled_sig);
+	g_clear_object (&gpgme_gsource->cancellable);
+	gpgme_set_io_cbs (gpgme_gsource->gctx, NULL);
+}
+
+static GSourceFuncs seahorse_gpgme_gsource_funcs = {
+	seahorse_gpgme_gsource_prepare,
+	seahorse_gpgme_gsource_check,
+	seahorse_gpgme_gsource_dispatch,
+	seahorse_gpgme_gsource_finalize,
+};
+
+static void
+register_watch (WatchData *watch)
+{
+	if (watch->registered)
+		return;
+
+	seahorse_debug ("GPGME OP: registering watch %d", watch->poll_fd.fd);
+
+	watch->registered = TRUE;
+	g_source_add_poll (watch->gsource, &watch->poll_fd);
+}
+
+static void
+unregister_watch (WatchData *watch)
+{
+	if (!watch->registered)
+		return;
+
+	seahorse_debug ("GPGME OP: unregistering watch %d", watch->poll_fd.fd);
+
+	watch->registered = FALSE;
+	g_source_remove_poll (watch->gsource, &watch->poll_fd);
+}
+
+/* Register a callback. */
+static gpg_error_t
+on_gpgme_add_watch (void *user_data,
+                    int fd,
+                    int dir,
+                    gpgme_io_cb_t fnc,
+                    void *fnc_data,
+                    void **tag)
+{
+	SeahorseGpgmeGSource *gpgme_gsource = user_data;
+	WatchData *watch;
+
+	seahorse_debug ("PGPOP: request to register watch %d", fd);
+
+	watch = g_new0 (WatchData, 1);
+	watch->registered = FALSE;
+	watch->poll_fd.fd = fd;
+	if (dir)
+		watch->poll_fd.events = (G_IO_IN | G_IO_HUP | G_IO_ERR);
+	else
+		watch->poll_fd.events = (G_IO_OUT | G_IO_ERR);
+	watch->fnc = fnc;
+	watch->fnc_data = fnc_data;
+	watch->gsource = (GSource*)gpgme_gsource;
+
+	/*
+	 * If the context is busy, we already have a START event, and can
+	 * register watches freely.
+	 */
+	if (gpgme_gsource->busy)
+		register_watch (watch);
+
+	gpgme_gsource->watches = g_list_append (gpgme_gsource->watches, watch);
+	*tag = watch;
+
+	return GPG_OK;
+}
+
+static void
+on_gpgme_remove_watch (void *tag)
+{
+	WatchData *watch = (WatchData*)tag;
+	SeahorseGpgmeGSource *gpgme_gsource = (SeahorseGpgmeGSource*)watch->gsource;
+
+	gpgme_gsource->watches = g_list_remove (gpgme_gsource->watches, watch);
+	unregister_watch (watch);
+	g_free (watch);
+}
+
+static void
+on_gpgme_event (void *user_data,
+                gpgme_event_io_t type,
+                void *type_data)
+{
+	SeahorseGpgmeGSource *gpgme_gsource = user_data;
+	gpg_error_t *gerr;
+	GList *l;
+
+	switch (type) {
+
+	/* Called when the GPGME context starts an operation */
+	case GPGME_EVENT_START:
+		gpgme_gsource->busy = TRUE;
+		gpgme_gsource->finished = FALSE;
+		seahorse_debug ("PGPOP: start event");
+
+		/* Since we weren't supposed to register these before, do it now */
+		for (l = gpgme_gsource->watches; l != NULL; l= g_list_next (l))
+			register_watch (l->data);
+		break;
+
+	/* Called when the GPGME context is finished with an op */
+	case GPGME_EVENT_DONE:
+		gpgme_gsource->busy = FALSE;
+		gerr = (gpgme_error_t *)type_data;
+		seahorse_debug ("PGPOP: done event (err: %d)", *gerr);
+
+		/* Make sure we have no extra watches left over */
+		for (l = gpgme_gsource->watches; l != NULL; l = g_list_next (l))
+			unregister_watch (l->data);
+
+		/* And try to figure out a good response */
+		gpgme_gsource->finished = TRUE;
+		gpgme_gsource->status = *gerr;
+		break;
+
+	case GPGME_EVENT_NEXT_KEY:
+	case GPGME_EVENT_NEXT_TRUSTITEM:
+	default:
+		/* Ignore unsupported event types */
+		break;
+	}
+}
+
+static void
+on_gpgme_gsource_cancelled (GCancellable *cancellable,
+                            gpointer user_data)
+{
+	SeahorseGpgmeGSource *gpgme_gsource = user_data;
+	if (gpgme_gsource->busy)
+		gpgme_cancel (gpgme_gsource->gctx);
+}
+
+GSource *
+seahorse_gpgme_gsource_new (gpgme_ctx_t gctx,
+                            GCancellable *cancellable)
+{
+	SeahorseGpgmeGSource *gpgme_gsource;
+	GSource *gsource;
+
+	gsource = g_source_new (&seahorse_gpgme_gsource_funcs,
+	                        sizeof (SeahorseGpgmeGSource));
+
+	gpgme_gsource = (SeahorseGpgmeGSource *)gsource;
+	gpgme_gsource->gctx = gctx;
+	gpgme_gsource->io_cbs.add = on_gpgme_add_watch;
+	gpgme_gsource->io_cbs.add_priv = gsource;
+	gpgme_gsource->io_cbs.remove = on_gpgme_remove_watch;
+	gpgme_gsource->io_cbs.event = on_gpgme_event;
+	gpgme_gsource->io_cbs.event_priv = gsource;
+	gpgme_set_io_cbs (gctx, &gpgme_gsource->io_cbs);
+
+	if (cancellable) {
+		gpgme_gsource->cancellable = g_object_ref (cancellable);
+		gpgme_gsource->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                      G_CALLBACK (on_gpgme_gsource_cancelled),
+		                                                      gpgme_gsource, NULL);
+	}
+
+	return gsource;
+}
diff --git a/pgp/seahorse-gpgme.h b/pgp/seahorse-gpgme.h
index 45833a6..d667946 100644
--- a/pgp/seahorse-gpgme.h
+++ b/pgp/seahorse-gpgme.h
@@ -44,7 +44,8 @@ struct _SeahorseKeyTypeTable {
 
 GQuark             seahorse_gpgme_error_domain      (void);
 
-void               seahorse_gpgme_to_error          (gpgme_error_t gerr, GError** err);
+gboolean           seahorse_gpgme_propagate_error   (gpgme_error_t gerr,
+                                                     GError** error);
 
 void               seahorse_gpgme_handle_error      (gpgme_error_t err, 
                                                      const gchar* desc, ...);
@@ -57,4 +58,7 @@ SeahorseValidity   seahorse_gpgme_convert_validity  (gpgme_validity_t validity);
 
 gpgme_error_t      seahorse_gpgme_get_keytype_table (SeahorseKeyTypeTable *table);
 
+GSource *          seahorse_gpgme_gsource_new       (gpgme_ctx_t gctx,
+                                                     GCancellable *cancellable);
+
 #endif /* SEAHORSEGPGME_H_ */
diff --git a/pgp/seahorse-hkp-source.c b/pgp/seahorse-hkp-source.c
index 82d4ac7..9850a34 100644
--- a/pgp/seahorse-hkp-source.c
+++ b/pgp/seahorse-hkp-source.c
@@ -31,9 +31,9 @@
 #include "seahorse-pgp-key.h"
 #include "seahorse-pgp-subkey.h"
 #include "seahorse-pgp-uid.h"
-
-#include "seahorse-operation.h"
 #include "seahorse-servers.h"
+
+#include "seahorse-progress.h"
 #include "seahorse-util.h"
 
 #include "common/seahorse-registry.h"
@@ -70,7 +70,7 @@
 *
 **/
 static GQuark
-get_hkp_error_domain ()
+get_hkp_error_domain (void)
 {
     static GQuark q = 0;
     if(q == 0)
@@ -87,12 +87,12 @@ get_hkp_error_domain ()
 * Returns A Soup uri with server, port and paths
 **/
 static SoupURI*
-get_http_server_uri (SeahorseSource *src, const char *path)
+get_http_server_uri (SeahorseHKPSource *self, const char *path)
 {
     SoupURI *uri;
     gchar *server, *port;
 
-    g_object_get (src, "key-server", &server, NULL);
+    g_object_get (self, "key-server", &server, NULL);
     g_return_val_if_fail (server != NULL, NULL);
 
     uri = soup_uri_new (NULL);
@@ -115,29 +115,6 @@ get_http_server_uri (SeahorseSource *src, const char *path)
     return uri;
 }
 
-/* -----------------------------------------------------------------------------
- *  HKP OPERATION     
- */
- 
-#define SEAHORSE_TYPE_HKP_OPERATION            (seahorse_hkp_operation_get_type ())
-#define SEAHORSE_HKP_OPERATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_HKP_OPERATION, SeahorseHKPOperation))
-#define SEAHORSE_HKP_OPERATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_HKP_OPERATION, SeahorseHKPOperationClass))
-#define SEAHORSE_IS_HKP_OPERATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_HKP_OPERATION))
-#define SEAHORSE_IS_HKP_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_HKP_OPERATION))
-#define SEAHORSE_HKP_OPERATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_HKP_OPERATION, SeahorseHKPOperationClass))
-
-typedef gboolean (*OpHKPCallback)   (SeahorseOperation *op, SoupMessage *message);
-    
-DECLARE_OPERATION (HKP, hkp)
-    SeahorseHKPSource *hsrc;        /* The source  */
-    SoupSession *session;           /* The HTTP session */
-    guint total;                    /* Number of requests queued */
-    guint requests;                 /* Number of requests remaining */
-    gboolean cancelling;            /* Cancelling the request, don't process */
-END_DECLARE_OPERATION
-
-IMPLEMENT_OPERATION (HKP, hkp)
-
 static gboolean
 check_for_http_proxy_schema__with_love_to_ryan ()
 {
@@ -206,97 +183,31 @@ create_proxy_session (void)
 	return session;
 }
 
-/**
-* hop: A SeahorseHKPOperation to init
-*
-* Reads settings and creates a new operation with a running Soup
-*
-**/
-static void 
-seahorse_hkp_operation_init (SeahorseHKPOperation *hop)
+static SoupSession *
+create_hkp_soup_session (void)
 {
+	SoupSession *session;
 #if WITH_DEBUG
 	SoupLogger *logger;
 #endif
 
-	hop->session = create_proxy_session ();
+	session = create_proxy_session ();
 
 	/* Without a proxy */
-	if (hop->session == NULL)
-		hop->session = soup_session_async_new ();
+	if (session == NULL)
+		session = soup_session_async_new ();
 
 #if WITH_DEBUG
 	if (seahorse_debugging) {
 		logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
-		soup_logger_attach (logger, hop->session);
+		soup_logger_attach (logger, session);
 		g_object_unref (logger);
 	}
 #endif
-}
-
-/**
-* gobject: A SeahorseHKPOperation to dispose
-*
-*
-*
-**/
-static void 
-seahorse_hkp_operation_dispose (GObject *gobject)
-{
-    SeahorseHKPOperation *hop = SEAHORSE_HKP_OPERATION (gobject);
-    
-    if (hop->hsrc) {
-        g_object_unref (hop->hsrc);
-        hop->hsrc = NULL;
-    }
 
-    if (hop->session) {
-        g_object_unref (hop->session);
-        hop->session = NULL;
-    }
-    
-    G_OBJECT_CLASS (hkp_operation_parent_class)->dispose (gobject);  
+	return session;
 }
 
-/**
-* gobject: A SeahorseHKPOperation to finalize
-*
-*
-*
-**/
-static void 
-seahorse_hkp_operation_finalize (GObject *gobject)
-{
-    SeahorseHKPOperation *hop = SEAHORSE_HKP_OPERATION (gobject);
-
-    g_assert (hop->hsrc == NULL);
-    g_assert (hop->session == NULL);
-    
-    G_OBJECT_CLASS (hkp_operation_parent_class)->finalize (gobject);  
-}
-
-/**
-* operation: A SeahorseHKPOperation
-*
-* Cancels the operation, aborts the soup session
-*
-**/
-static void 
-seahorse_hkp_operation_cancel (SeahorseOperation *operation)
-{
-    SeahorseHKPOperation *hop;
-    
-    g_assert (SEAHORSE_IS_HKP_OPERATION (operation));
-    hop = SEAHORSE_HKP_OPERATION (operation);
-    
-    g_return_if_fail (seahorse_operation_is_running (operation));
-    hop->cancelling = TRUE;
-    
-    if (hop->session != NULL) 
-        soup_session_abort (hop->session);
-    
-    seahorse_operation_mark_done (operation, TRUE, NULL);
-}
 
 /* Thanks to GnuPG */
 /**
@@ -372,77 +283,6 @@ dehtmlize(gchar *line)
 }
 
 /**
-* hop: The running SeahorseHKPOperation
-* msg: The optional Soup error message
-* text: The optional error text
-*
-* Either text or msg is needed
-*
-* Cancels operation and marks the HKP operation as failed
-**/
-static void
-fail_hkp_operation (SeahorseHKPOperation *hop, SoupMessage *msg, const gchar *text)
-{
-    gchar *t, *server;
-    GError *error = NULL;
-    
-    if (!seahorse_operation_is_running (SEAHORSE_OPERATION (hop)))
-        return;
-
-    g_object_get (hop->hsrc, "key-server", &server, NULL);
-
-    if (text) {
-        error = g_error_new (HKP_ERROR_DOMAIN, msg ? msg->status_code : 0, "%s", text);
-
-    } else if (msg) {
-        /* Make the body lower case, and no tags */
-        t = g_strndup (msg->response_body->data, msg->response_body->length);
-        if (t != NULL) {
-            dehtmlize (t);        
-            seahorse_util_string_lower (t);
-        }
-
-        if (t && strstr (t, "no keys"))
-            error = NULL; /* not found is not an error */
-        else if (t && strstr (t, "too many"))
-            error = g_error_new (HKP_ERROR_DOMAIN, 0, _("Search was not specific enough. Server '%s' found too many keys."), server);
-        else 
-            error = g_error_new (HKP_ERROR_DOMAIN, msg->status_code, _("Couldn't communicate with server '%s': %s"),
-                                 server, msg->reason_phrase);
-        g_free (t);
-    } else {
-
-        /* We should always have msg or text */
-        g_assert (FALSE);
-    }        
-
-    seahorse_operation_mark_done (SEAHORSE_OPERATION (hop), FALSE, error);
-    g_free (server);
-}
-
-/**
-* hsrc: The SeahorseHKPSource to set in the new object
-*
-*
-*
-* Returns A new SeahorseHKPOperation
-**/
-static SeahorseHKPOperation*
-setup_hkp_operation (SeahorseHKPSource *hsrc)
-{
-    SeahorseHKPOperation *hop;
-
-    g_return_val_if_fail (SEAHORSE_IS_HKP_SOURCE (hsrc), NULL);
-    
-    hop = g_object_new (SEAHORSE_TYPE_HKP_OPERATION, NULL);
-    hop->hsrc = hsrc;
-    g_object_ref (hsrc);
-
-    seahorse_operation_mark_start (SEAHORSE_OPERATION (hop));
-    return hop;    
-}
-
-/**
  * parse_hkp_date:
  * @text: The date string to parse, YYYY-MM-DD
  *
@@ -658,41 +498,6 @@ add_key (SeahorseHKPSource *ssrc, SeahorsePgpKey *key)
 }
 
 /**
-* session: The soup session
-* msg: The soup message
-* hop: The SeahorseHKPOperation involved
-*
-* Called from soup_session_queue_message-when a soup message got completed
-* Adds the new keys to the application context.
-*
-**/
-static void 
-refresh_callback (SoupSession *session, SoupMessage *msg, SeahorseHKPOperation *hop) 
-{
-    GList *keys, *k;
-    
-    if (hop->cancelling)
-        return;
-    
-    if (SOUP_MESSAGE_IS_ERROR (msg)) {
-        fail_hkp_operation (hop, msg, NULL);
-        return;
-    }
-    
-    keys = parse_hkp_index (msg->response_body->data);
-    
-    for (k = keys; k; k = g_list_next (k))
-        add_key (hop->hsrc, SEAHORSE_PGP_KEY (k->data));
-    seahorse_object_list_free (keys);
-
-    if (--hop->requests <= 0)
-        seahorse_operation_mark_done (SEAHORSE_OPERATION (hop), FALSE, NULL);
-    else
-        seahorse_operation_mark_progress_full (SEAHORSE_OPERATION (hop), _("Searching for keys..."), 
-                                               hop->requests, hop->total);
-}
-
-/**
 * response: The server response
 *
 * Parses the response and extracts an error message
@@ -743,44 +548,6 @@ get_send_result (const gchar *response)
 }
 
 /**
-* session: The soup session the message belongs to
-* msg: The message that has finished
-* hop: The SeahorseHKPOperation associated
-*
-* Callback for soup_session_queue_message from seahorse_hkp_source_import
-*
-**/
-static void 
-send_callback (SoupSession *session, SoupMessage *msg, SeahorseHKPOperation *hop) 
-{
-    gchar *errmsg;
-
-    if (hop->cancelling)
-        return;
-
-    if (SOUP_MESSAGE_IS_ERROR (msg)) {
-        fail_hkp_operation (hop, msg, NULL);
-        return;
-    }
-    
-    errmsg = get_send_result (msg->response_body->data);
-    if (errmsg) {
-        fail_hkp_operation (hop, NULL, errmsg);
-        g_free (errmsg);
-        return;
-    }
-    
-    /* A successful status from the server is all we want
-       in this case */
-    
-    if (--hop->requests <= 0)
-        seahorse_operation_mark_done (SEAHORSE_OPERATION (hop), FALSE, NULL);
-    else
-        seahorse_operation_mark_progress_full (SEAHORSE_OPERATION (hop), _("Uploading keys..."), 
-                                               hop->requests, hop->total);
-}
-
-/**
  * detect_key:
  * @text: The ASCII armoured key
  * @len: Length of the ASCII block or -1
@@ -814,72 +581,6 @@ detect_key (const gchar *text, gint len, const gchar **start, const gchar **end)
     return TRUE; 
 }
 
-/**
-* session: The associated soup session
-* msg: The message received
-* hop: SeahorseHKPOperation associated
-*
-* Callback for soup_session_queue_message from seahorse_hkp_source_export_raw
-* Extracts keys from the message and writes them to the results of the SeahorseOperation
-*
-**/
-static void 
-get_callback (SoupSession *session, SoupMessage *msg, SeahorseHKPOperation *hop) 
-{
-    GError *err = NULL;
-    const gchar *start;
-    const gchar *end;
-    GOutputStream *output;
-    const gchar *text;
-    gboolean ret;
-    guint len;
-    gsize written;
-    
-    if (hop->cancelling)
-        return;
-    
-    if (SOUP_MESSAGE_IS_ERROR (msg)) {
-        fail_hkp_operation (hop, msg, NULL);
-        return;
-    }
-    
-    end = text = msg->response_body->data;
-    len = msg->response_body->length;
-    
-    for (;;) {
-
-        len -= end - text;
-        text = end;
-        
-        if(!detect_key (text, len, &start, &end))
-            break;
-        
-		/* Any key blocks get written to our result data */
-		output = seahorse_operation_get_result (SEAHORSE_OPERATION (hop));
-		g_return_if_fail (G_IS_OUTPUT_STREAM (output));
-
-		ret = g_output_stream_write_all (output, start, end - start, &written, NULL, &err) &&
-		      g_output_stream_write_all (output, "\n", 1, &written, NULL, &err) &&
-		      g_output_stream_flush (output, NULL, &err);
-
-		if (!ret) {
-			seahorse_operation_mark_done (SEAHORSE_OPERATION (hop), FALSE, err);
-			return;
-		}
-    	}
-        
-    	if (--hop->requests <= 0) {
-    		output = seahorse_operation_get_result (SEAHORSE_OPERATION (hop));
-    		g_return_if_fail (G_IS_OUTPUT_STREAM (output));
-    		g_output_stream_close (output, NULL, &err);
-    		seahorse_operation_mark_done (SEAHORSE_OPERATION (hop), FALSE, err);
-    	} else {
-    		seahorse_operation_mark_progress_full (SEAHORSE_OPERATION (hop), _("Retrieving keys..."), 
-    		                                       hop->requests, hop->total);
-    	}
-}
-
- 
 /* -----------------------------------------------------------------------------
  *  SEAHORSE HKP SOURCE
  */
@@ -924,96 +625,270 @@ seahorse_hkp_source_get_property (GObject *object, guint prop_id, GValue *value,
     };
 }
 
-static void 
-seahorse_hkp_source_set_property (GObject *object, guint prop_id, const GValue *value,
-                                   GParamSpec *pspec)
-{
-
-}
-
 /**
-* match: the \0 terminated string to test
-*
+* klass:
 *
+* Initialize the basic class stuff
 *
-* Returns TRUE if it is a hex keyid
 **/
+static void
+seahorse_hkp_source_class_init (SeahorseHKPSourceClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	gobject_class->get_property = seahorse_hkp_source_get_property;
+
+	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
+	g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
+
+	seahorse_registry_register_type (NULL, SEAHORSE_TYPE_HKP_SOURCE, "source", "remote", SEAHORSE_PGP_STR, NULL);
+	seahorse_servers_register_type ("hkp", _("HTTP Key Server"), seahorse_hkp_is_valid_uri);
+
+	seahorse_registry_register_function (NULL, seahorse_pgp_key_canonize_id, "canonize", SEAHORSE_PGP_STR, NULL);
+}
+
+static gboolean
+hkp_message_propagate_error (SeahorseHKPSource *self,
+                             SoupMessage *message,
+                             GError **error)
+{
+	gchar *text, *server;
+
+	if (!SOUP_MESSAGE_IS_ERROR (message))
+		return FALSE;
+
+	if (message->status_code == SOUP_STATUS_CANCELLED) {
+		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+		                     _("The operation was cancelled"));
+		return TRUE;
+	}
+
+	g_object_get (self, "key-server", &server, NULL);
+
+	/* Make the body lower case, and no tags */
+	text = g_strndup (message->response_body->data, message->response_body->length);
+	if (text != NULL) {
+		dehtmlize (text);
+		seahorse_util_string_lower (text);
+	}
+
+	if (text && strstr (text, "no keys")) {
+		g_free (text);
+		return FALSE; /* not found is not an error */
+	} else if (text && strstr (text, "too many")) {
+		g_set_error (error, HKP_ERROR_DOMAIN, 0,
+		             _("Search was not specific enough. Server '%s' found too many keys."), server);
+	} else {
+		g_set_error (error, HKP_ERROR_DOMAIN, message->status_code,
+		             _("Couldn't communicate with server '%s': %s"),
+		             server, message->reason_phrase);
+	}
+
+	g_free (text);
+	return TRUE;
+}
+
+static void
+on_session_cancelled (GCancellable *cancellable,
+                     gpointer user_data)
+{
+	SoupSession *session = user_data;
+	soup_session_abort (session);
+}
+
+typedef struct {
+	SeahorseHKPSource *source;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+	SoupSession *session;
+	gint requests;
+	GList *keys;
+} source_search_closure;
+
+static void
+source_search_free (gpointer data)
+{
+	source_search_closure *closure = data;
+	g_object_unref (closure->source);
+	g_cancellable_disconnect (closure->cancellable, closure->cancelled_sig);
+	g_clear_object (&closure->cancellable);
+	g_object_unref (closure->session);
+	seahorse_object_list_free (closure->keys);
+	g_free (closure);
+}
+
+static void
+on_search_message_complete (SoupSession *session,
+                            SoupMessage *message,
+                            gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_search_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	GList *keys, *l;
+
+	seahorse_progress_end (closure->cancellable, message);
+
+	if (hkp_message_propagate_error (closure->source, message, &error)) {
+		g_simple_async_result_take_error (res, error);
+
+	} else {
+		keys = parse_hkp_index (message->response_body->data);
+		for (l = keys; l; l = g_list_next (l))
+			add_key (closure->source, SEAHORSE_PGP_KEY (l->data));
+		closure->keys = keys;
+	}
+
+	g_simple_async_result_complete_in_idle (res);
+	g_object_unref (res);
+}
+
 static gboolean
 is_hex_keyid (const gchar *match)
 {
-    const gchar *t;
-    
-    t = match;
-    
-    if (strlen (match) != 8)
-        return FALSE;
-    
-    while (*t != '\0') {
-        if (!((*t >= 0x30 && *t <= 0x39) || (*t >= 0x41 && *t <= 0x46) || (*t >= 0x61 && *t <= 0x66)))
-            return FALSE;
-            
-        t++;
-    }
-    
-    return TRUE;
+	const gchar *text = match;
+
+	if (strlen (match) != 8)
+		return FALSE;
+
+	while (*text != '\0') {
+		if (!((*text >= 0x30 && *text <= 0x39) ||
+		      (*text >= 0x41 && *text <= 0x46) ||
+		      (*text >= 0x61 && *text <= 0x66)))
+			return FALSE;
+		text++;
+	}
+
+	return TRUE;
 }
+static void
+seahorse_hkp_source_search_async (SeahorseSource *source,
+                                  const gchar *match,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
+{
+	SeahorseHKPSource *self = SEAHORSE_HKP_SOURCE (source);
+	source_search_closure *closure;
+	GSimpleAsyncResult *res;
+	SoupMessage *message;
+	GHashTable *form;
+	SoupURI *uri;
+	gchar hexfpr[11];
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_hkp_source_search_async);
+	closure = g_new0 (source_search_closure, 1);
+	closure->source = g_object_ref (self);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->session = create_hkp_soup_session ();
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_search_free);
+
+	uri = get_http_server_uri (self, "/pks/lookup");
+	g_return_if_fail (uri);
+
+	form = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (form, "op", "index");
+
+	if (is_hex_keyid (match)) {
+		strncpy (hexfpr, "0x", 3);
+		strncpy (hexfpr + 2, match, 9);
+		g_hash_table_insert (form, "search", hexfpr);
+	} else {
+		g_hash_table_insert (form, "search", (char *)match);
+	}
 
-/**
-* src: The HKP source to search in
-* match: The value to match (keyid or anything else)
-*
-* Creates a search operation, finds data on the keyserver
-*
-* Returns A running Seahorse search operation
-**/
-static SeahorseOperation*
-seahorse_hkp_source_search (SeahorseSource *src, const gchar *match)
+	soup_uri_set_query_from_form (uri, form);
+	g_hash_table_destroy (form);
+
+	message = soup_message_new_from_uri ("GET", uri);
+	soup_session_queue_message (closure->session, message,
+	                            on_search_message_complete, g_object_ref (res));
+
+	seahorse_progress_prep_and_begin (cancellable, message, NULL);
+
+	if (cancellable)
+		closure->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                G_CALLBACK (on_session_cancelled),
+		                                                closure->session, NULL);
+
+	soup_uri_free (uri);
+	g_object_unref (res);
+}
+
+static GList *
+seahorse_hkp_source_search_finish (SeahorseSource *source,
+                                   GAsyncResult *result,
+                                   GError **error)
 {
-    SeahorseHKPOperation *hop;
-    SoupMessage *message;
-    GHashTable *form;
-    gchar *t;
-    SoupURI *uri;
-    gchar hexfpr[11];
-    
-    g_assert (SEAHORSE_IS_SOURCE (src));
-    g_assert (SEAHORSE_IS_HKP_SOURCE (src));
+	source_search_closure *closure;
+	GList *keys;
 
-    hop = setup_hkp_operation (SEAHORSE_HKP_SOURCE (src));
-    
-    uri = get_http_server_uri (src, "/pks/lookup");
-    g_return_val_if_fail (uri, FALSE);
-    
-    form = g_hash_table_new (g_str_hash, g_str_equal);
-    g_hash_table_insert (form, "op", "index");
-    
-    if (is_hex_keyid (match)) {
-        strncpy (hexfpr, "0x", 3);
-        strncpy (hexfpr + 2, match, 9);
-        
-        g_hash_table_insert (form, "search", hexfpr);
-    } else 
-        g_hash_table_insert (form, "search", (char *)match);
-        
-    soup_uri_set_query_from_form (uri, form);
-    g_hash_table_destroy (form);
-    
-    message = soup_message_new_from_uri ("GET", uri);
-    
-    soup_session_queue_message (hop->session, message, 
-                                (SoupSessionCallback)refresh_callback, hop);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_hkp_source_search_async), NULL);
 
-    hop->total = hop->requests = 1;
-    t = g_strdup_printf (_("Searching for keys on: %s"), uri->host);
-    seahorse_operation_mark_progress (SEAHORSE_OPERATION (hop), t, -1);
-    g_free (t);
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
 
-    soup_uri_free (uri);
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	keys = closure->keys;
+	closure->keys = NULL;
+	return keys;
+}
 
-    seahorse_server_source_take_operation (SEAHORSE_SERVER_SOURCE (src), 
-                                           SEAHORSE_OPERATION (hop));
-    g_object_ref (hop);
-    return SEAHORSE_OPERATION (hop);
+typedef struct {
+	SeahorseHKPSource *source;
+	GInputStream *input;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+	SoupSession *session;
+	gint requests;
+} source_import_closure;
+
+static void
+source_import_free (gpointer data)
+{
+	source_import_closure *closure = data;
+	g_object_unref (closure->source);
+	g_object_unref (closure->input);
+	g_cancellable_disconnect (closure->cancellable, closure->cancelled_sig);
+	g_clear_object (&closure->cancellable);
+	g_object_unref (closure->session);
+	g_free (closure);
+}
+
+static void
+on_import_message_complete (SoupSession *session,
+                            SoupMessage *message,
+                            gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	gchar *errmsg;
+
+	seahorse_progress_end (closure->cancellable, message);
+
+	if (hkp_message_propagate_error (closure->source, message, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+
+	} else if ((errmsg = get_send_result (message->response_body->data)) != NULL) {
+		g_set_error (&error, HKP_ERROR_DOMAIN, message->status_code, "%s", errmsg);
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		g_free (errmsg);
+
+	/* A successful status from the server is all we want in this case */
+	} else {
+		g_assert (closure->requests > 0);
+		closure->requests--;
+
+		if (closure->requests == 0)
+			g_simple_async_result_complete_in_idle (res);
+	}
+
+	g_object_unref (res);
 }
 
 /**
@@ -1021,86 +896,188 @@ seahorse_hkp_source_search (SeahorseSource *src, const gchar *match)
 * input: The input stream to add
 *
 * Imports a list of keys from the input stream to the keyserver
-*
-* Returns A running input operation (or NULL on error)
 **/
-static SeahorseOperation* 
-seahorse_hkp_source_import (SeahorseSource *sksrc, GInputStream *input)
+static void
+seahorse_hkp_source_import_async (SeahorseSource *source,
+                                  GInputStream *input,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
 {
-    SeahorseHKPOperation *hop;
-    SeahorseHKPSource *hsrc;
-    SoupMessage *message;
-    GList *keydata = NULL;
-    GString *buf = NULL;
-    GHashTable *form;
-    gchar *key, *t;
-    SoupURI *uri;
-    GList *l;
-    guint len;
-    
-    g_return_val_if_fail (SEAHORSE_IS_HKP_SOURCE (sksrc), NULL);
-    hsrc = SEAHORSE_HKP_SOURCE (sksrc);
-    
-    g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
-    g_object_ref (input);
-    
-    for (;;) {
-     
-        buf = g_string_sized_new (2048);
-        len = seahorse_util_read_data_block (buf, input, "-----BEGIN PGP PUBLIC KEY BLOCK-----",
-                                             "-----END PGP PUBLIC KEY BLOCK-----");
-    
-        if (len > 0) {
-            keydata = g_list_prepend (keydata, g_string_free (buf, FALSE));
-        } else {
-            g_string_free (buf, TRUE);
-            break;
-        }
-    }
-    
+	SeahorseHKPSource *self = SEAHORSE_HKP_SOURCE (source);
+	GSimpleAsyncResult *res;
+	source_import_closure *closure;
+	SoupMessage *message;
+	GList *keydata = NULL;
+	GString *buf = NULL;
+	GHashTable *form;
+	gchar *key;
+	SoupURI *uri;
+	GList *l;
+	guint len;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_hkp_source_import_async);
+	closure = g_new0 (source_import_closure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->input = g_object_ref (input);
+	closure->source = g_object_ref (self);
+	closure->session = create_hkp_soup_session ();
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_import_free);
+
+	for (;;) {
+
+		buf = g_string_sized_new (2048);
+		len = seahorse_util_read_data_block (buf, input,
+		                                     "-----BEGIN PGP PUBLIC KEY BLOCK-----",
+		                                     "-----END PGP PUBLIC KEY BLOCK-----");
+
+		if (len > 0) {
+			keydata = g_list_prepend (keydata, g_string_free (buf, FALSE));
+		} else {
+			g_string_free (buf, TRUE);
+			break;
+		}
+	}
+
 	if (g_list_length (keydata) == 0) {
-    		g_object_unref (input);
-    		return seahorse_operation_new_complete (NULL);
-    	}
-    
-    /* Figure out the URI we're sending to */    
-    uri = get_http_server_uri (sksrc, "/pks/add");
-    g_return_val_if_fail (uri, FALSE);
+		g_simple_async_result_complete_in_idle (res);
+		g_object_unref (res);
+		return;
+	}
 
-    /* New operation and away we go */
-    keydata = g_list_reverse (keydata);
-    hop = setup_hkp_operation (hsrc);
-    
-    form = g_hash_table_new (g_str_hash, g_str_equal);
-    for (l = keydata; l; l = g_list_next (l)) {
-        g_assert (l->data != NULL);
+	/* Figure out the URI we're sending to */
+	uri = get_http_server_uri (self, "/pks/add");
+	g_return_if_fail (uri);
 
-        g_hash_table_insert (form, "keytext", l->data);
-        key = soup_form_encode_urlencoded (form);
+	/* New operation and away we go */
+	keydata = g_list_reverse (keydata);
 
-        message = soup_message_new_from_uri ("POST", uri);
-        soup_message_set_request (message, "application/x-www-form-urlencoded",
-                                  SOUP_MEMORY_TAKE, key, strlen (key));
-        
-        soup_session_queue_message (hop->session, message, 
-                                    (SoupSessionCallback)send_callback, hop);
-        hop->requests++;
-    }
-    g_hash_table_destroy (form);
+	form = g_hash_table_new (g_str_hash, g_str_equal);
+	for (l = keydata; l; l = g_list_next (l)) {
+		g_assert (l->data != NULL);
+		g_hash_table_remove_all (form);
+
+		g_hash_table_insert (form, "keytext", l->data);
+		key = soup_form_encode_urlencoded (form);
+
+		message = soup_message_new_from_uri ("POST", uri);
+		soup_message_set_request (message, "application/x-www-form-urlencoded",
+		                          SOUP_MEMORY_TAKE, key, strlen (key));
+
+		soup_session_queue_message (closure->session, message,
+		                            on_import_message_complete, g_object_ref (res));
+
+		closure->requests++;
+		seahorse_progress_prep_and_begin (cancellable, message, NULL);
+	}
+	g_hash_table_destroy (form);
+
+	if (cancellable)
+		closure->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                G_CALLBACK (on_session_cancelled),
+		                                                closure->session, NULL);
+
+	soup_uri_free (uri);
+
+	for (l = keydata; l != NULL; l = g_list_next (l))
+		g_free (l->data);
+	g_list_free (keydata);
+
+	g_object_unref (res);
+}
+
+static GList *
+seahorse_hkp_source_import_finish (SeahorseSource *source,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_hkp_source_import_async), NULL);
 
-    hop->total = hop->requests;
-    t = g_strdup_printf (_("Connecting to: %s"), uri->host);
-    seahorse_operation_mark_progress (SEAHORSE_OPERATION (hop), t, -1);
-    g_free (t);
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
 
-    soup_uri_free (uri);
+	/* We don't know which keys got imported, so just return NULL */
+	return NULL;
+}
 
-    for (l = keydata; l != NULL; l = g_list_next (l))
-        g_free (l->data);
-    g_list_free (keydata);
-    g_object_unref (input);
 
-    return SEAHORSE_OPERATION (hop);
+typedef struct {
+	SeahorseHKPSource *source;
+	GOutputStream *output;
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+	SoupSession *session;
+	gint requests;
+} source_export_raw_closure;
+
+static void
+source_export_raw_free (gpointer data)
+{
+	source_export_raw_closure *closure = data;
+	g_object_unref (closure->source);
+	g_object_unref (closure->output);
+	g_cancellable_disconnect (closure->cancellable, closure->cancelled_sig);
+	g_clear_object (&closure->cancellable);
+	g_object_unref (closure->session);
+	g_free (closure);
+}
+
+static void
+on_export_message_complete (SoupSession *session,
+                            SoupMessage *message,
+                            gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_export_raw_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	const gchar *start;
+	const gchar *end;
+	const gchar *text;
+	gboolean ret;
+	guint len;
+	gsize written;
+
+	seahorse_progress_end (closure->cancellable, message);
+
+	if (hkp_message_propagate_error (closure->source, message, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		g_object_unref (res);
+		return;
+	}
+
+	end = text = message->response_body->data;
+	len = message->response_body->length;
+
+	for (;;) {
+
+		len -= end - text;
+		text = end;
+
+		if (!detect_key (text, len, &start, &end))
+			break;
+
+		ret = g_output_stream_write_all (closure->output, start, end - start, &written, NULL, &error) &&
+		      g_output_stream_write_all (closure->output, "\n", 1, &written, NULL, &error) &&
+		      g_output_stream_flush (closure->output, NULL, &error);
+
+		if (!ret) {
+			g_simple_async_result_take_error (res, error);
+			g_simple_async_result_complete_in_idle (res);
+			g_object_unref (res);
+			return;
+		}
+	}
+
+	g_assert (closure->requests > 0);
+	closure->requests--;
+
+	if (closure->requests == 0)
+		g_simple_async_result_complete_in_idle (res);
+
+	g_object_unref (res);
 }
 
 /**
@@ -1109,103 +1086,99 @@ seahorse_hkp_source_import (SeahorseSource *sksrc, GInputStream *input)
 * output: The output stream the data will end in
 *
 * Gets data from the keyserver, writes it to the output stream
-*
-* Returns A new Seahorse operation
 **/
-static SeahorseOperation*  
-seahorse_hkp_source_export_raw (SeahorseSource *sksrc, GList *keyids,
-                                GOutputStream *output)
+static void
+seahorse_hkp_source_export_raw_async (SeahorseSource *source,
+                                      GList *keyids,
+                                      GOutputStream *output,
+                                      GCancellable *cancellable,
+                                      GAsyncReadyCallback callback,
+                                      gpointer user_data)
 {
-    SeahorseHKPOperation *hop;
-    SeahorseHKPSource *hsrc;
-    SoupMessage *message;
-    gchar *t;
-    SoupURI *uri;
-    const gchar *fpr;
-    gchar hexfpr[11];
-    GHashTable *form;
-    guint len;
-    GList *l;
-    
-    g_return_val_if_fail (SEAHORSE_IS_HKP_SOURCE (sksrc), NULL);
-    g_return_val_if_fail (output == NULL || G_IS_OUTPUT_STREAM (output), NULL);
+	SeahorseHKPSource *self = SEAHORSE_HKP_SOURCE (source);
+	source_export_raw_closure *closure;
+	GSimpleAsyncResult *res;
+	SoupMessage *message;
+	SoupURI *uri;
+	const gchar *fpr;
+	gchar hexfpr[11];
+	GHashTable *form;
+	guint len;
+	GList *l;
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_hkp_source_export_raw_async);
+	closure = g_new0 (source_export_raw_closure, 1);
+	closure->source = g_object_ref (self);
+	closure->output = g_object_ref (output);
+	closure->session = create_hkp_soup_session ();
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_export_raw_free);
+
+	if (g_list_length (keyids) == 0) {
+		g_simple_async_result_complete_in_idle (res);
+		g_object_unref (res);
+		return;
+	}
 
-    hsrc = SEAHORSE_HKP_SOURCE (sksrc);
-    
-    if (g_list_length (keyids) == 0)
-        return seahorse_operation_new_complete (NULL);
+	uri = get_http_server_uri (self, "/pks/lookup");
+	g_return_if_fail (uri);
 
-    uri = get_http_server_uri (sksrc, "/pks/lookup");
-    g_return_val_if_fail (uri, FALSE);
+	/* prepend the hex prefix (0x) to make keyservers happy */
+	strncpy (hexfpr, "0x", 3);
 
-    /* New operation started */    
-    hop = setup_hkp_operation (hsrc);
+	form = g_hash_table_new (g_str_hash, g_str_equal);
+	for (l = keyids; l; l = g_list_next (l)) {
 
-	g_object_ref (output);
-	seahorse_operation_mark_result (SEAHORSE_OPERATION (hop), output, g_object_unref);
+		g_hash_table_remove_all (form);
 
-    /* prepend the hex prefix (0x) to make keyservers happy */
-    strncpy(hexfpr, "0x", 3);
+		/* Get the key id and limit it to 8 characters */
+		fpr = seahorse_pgp_key_calc_rawid (GPOINTER_TO_UINT (l->data));
+		len = strlen (fpr);
+		if (len > 8)
+			fpr += (len - 8);
+	
+		strncpy (hexfpr + 2, fpr, 9);
 
-    form = g_hash_table_new (g_str_hash, g_str_equal);
-    for (l = keyids; l; l = g_list_next (l)) {
+		/* The get key URI */
+		g_hash_table_insert (form, "op", "get");
+		g_hash_table_insert (form, "search", (char *)hexfpr);
+		soup_uri_set_query_from_form (uri, form);
 
-        /* Get the key id and limit it to 8 characters */
-        fpr = seahorse_pgp_key_calc_rawid (GPOINTER_TO_UINT (l->data));
-        len = strlen (fpr);
-        if (len > 8)
-            fpr += (len - 8);
-	
-        strncpy(hexfpr + 2, fpr, 9);
+		message = soup_message_new_from_uri ("GET", uri);
 
-        /* The get key URI */
-        g_hash_table_insert (form, "op", "get");
-        g_hash_table_insert (form, "search", (char *)hexfpr);
-        soup_uri_set_query_from_form (uri, form);
+		soup_session_queue_message (closure->session, message,
+		                            on_export_message_complete,
+		                            g_object_ref (res));
 
-        message = soup_message_new_from_uri ("GET", uri);
-        
-        soup_session_queue_message (hop->session, message, 
-                                    (SoupSessionCallback)get_callback, hop);
+		closure->requests++;
+		seahorse_progress_prep_and_begin (cancellable, message, NULL);
+	}
 
-        hop->requests++;
-    }
-    g_hash_table_destroy (form);
-    
-    hop->total = hop->requests;
-    t = g_strdup_printf (_("Connecting to: %s"), uri->host);
-    seahorse_operation_mark_progress (SEAHORSE_OPERATION (hop), t, -1);
-    g_free (t);
+	if (cancellable)
+		closure->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                G_CALLBACK (on_session_cancelled),
+		                                                closure->session, NULL);
 
-    soup_uri_free (uri);
-    return SEAHORSE_OPERATION (hop);    
+	g_hash_table_destroy (form);
+	g_object_unref (res);
 }
 
-
-/**
-* klass:
-*
-* Initialize the basic class stuff
-*
-**/
-static void
-seahorse_hkp_source_class_init (SeahorseHKPSourceClass *klass)
+static GOutputStream *
+seahorse_hkp_source_export_raw_finish (SeahorseSource *source,
+                                       GAsyncResult *result,
+                                       GError **error)
 {
-	GObjectClass *gobject_class;
-   
-	gobject_class = G_OBJECT_CLASS (klass);
-	gobject_class->get_property = seahorse_hkp_source_get_property;
-	gobject_class->set_property = seahorse_hkp_source_set_property;
-	
-	seahorse_hkp_source_parent_class = g_type_class_peek_parent (klass);
+	source_export_raw_closure *closure;
 
-	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
-	g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_hkp_source_export_raw_async), NULL);
 
-	seahorse_registry_register_type (NULL, SEAHORSE_TYPE_HKP_SOURCE, "source", "remote", SEAHORSE_PGP_STR, NULL);
-	seahorse_servers_register_type ("hkp", _("HTTP Key Server"), seahorse_hkp_is_valid_uri);
-	
-	seahorse_registry_register_function (NULL, seahorse_pgp_key_canonize_id, "canonize", SEAHORSE_PGP_STR, NULL);
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	return closure->output;
 }
 
 /**
@@ -1217,9 +1190,12 @@ seahorse_hkp_source_class_init (SeahorseHKPSourceClass *klass)
 static void 
 seahorse_source_iface (SeahorseSourceIface *iface)
 {
-	iface->search = seahorse_hkp_source_search;
-	iface->import = seahorse_hkp_source_import;
-	iface->export_raw = seahorse_hkp_source_export_raw;
+	iface->search_async = seahorse_hkp_source_search_async;
+	iface->search_finish = seahorse_hkp_source_search_finish;
+	iface->import_async = seahorse_hkp_source_import_async;
+	iface->import_finish = seahorse_hkp_source_import_finish;
+	iface->export_raw_async = seahorse_hkp_source_export_raw_async;
+	iface->export_raw_finish = seahorse_hkp_source_export_raw_finish;
 }
 
 /**
diff --git a/pgp/seahorse-ldap-source.c b/pgp/seahorse-ldap-source.c
index ed61412..77c958f 100644
--- a/pgp/seahorse-ldap-source.c
+++ b/pgp/seahorse-ldap-source.c
@@ -33,7 +33,7 @@
 #include "seahorse-pgp-subkey.h"
 #include "seahorse-pgp-uid.h"
 
-#include "seahorse-operation.h"
+#include "seahorse-progress.h"
 #include "seahorse-servers.h"
 #include "seahorse-util.h"
 
@@ -302,439 +302,515 @@ escape_ldap_value (const gchar *v)
     return result;
 }
 
-/* -----------------------------------------------------------------------------
- *  LDAP OPERATION     
- */
- 
-#define SEAHORSE_TYPE_LDAP_OPERATION            (seahorse_ldap_operation_get_type ())
-#define SEAHORSE_LDAP_OPERATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_LDAP_OPERATION, SeahorseLDAPOperation))
-#define SEAHORSE_LDAP_OPERATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_LDAP_OPERATION, SeahorseLDAPOperationClass))
-#define SEAHORSE_IS_LDAP_OPERATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_LDAP_OPERATION))
-#define SEAHORSE_IS_LDAP_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_LDAP_OPERATION))
-#define SEAHORSE_LDAP_OPERATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_LDAP_OPERATION, SeahorseLDAPOperationClass))
-
-typedef gboolean (*OpLDAPCallback)   (SeahorseOperation *op, LDAPMessage *result);
-    
-DECLARE_OPERATION (LDAP, ldap)
-#ifdef WITH_SOUP
-    SoupAddress *addr;              /* For async DNS lookup */
-#endif
-    SeahorseLDAPSource *lsrc;       /* The source */
-    LDAP *ldap;                     /* The LDAP connection */
-    int ldap_op;                    /* The current LDAP async msg */
-    guint stag;                     /* The tag for the idle event source */
-    OpLDAPCallback ldap_cb;         /* Callback for next async result */
-    OpLDAPCallback chain_cb;        /* Callback when connection is done */
-END_DECLARE_OPERATION
+typedef gboolean (*SeahorseLdapCallback)   (LDAPMessage *result,
+                                            gpointer user_data);
 
-IMPLEMENT_OPERATION (LDAP, ldap)
+typedef struct {
+	GSource source;
+	LDAP *ldap;
+	int ldap_op;
+	GCancellable *cancellable;
+	gboolean cancelled;
+	gint cancelled_sig;
+} SeahorseLdapGSource;
 
+static gboolean
+seahorse_ldap_gsource_prepare (GSource *gsource,
+                               gint *timeout)
+{
+	SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
 
-/* -----------------------------------------------------------------------------
- *  SEARCH OPERATION STUFF 
- */
- 
-static const char *kServerAttributes[] = {
-    "basekeyspacedn",
-    "pgpbasekeyspacedn",
-    "version",
-    NULL
-};
+	if (ldap_gsource->cancelled)
+		return TRUE;
 
-static void 
-seahorse_ldap_operation_init (SeahorseLDAPOperation *sop)
+	/* No other way, but to poll */
+	*timeout = 50;
+	return FALSE;
+}
+
+static gboolean
+seahorse_ldap_gsource_check (GSource *gsource)
 {
-    sop->ldap_op = -1;
+	return TRUE;
 }
 
-static void 
-seahorse_ldap_operation_dispose (GObject *gobject)
+static gboolean
+seahorse_ldap_gsource_dispatch (GSource *gsource,
+                                GSourceFunc callback,
+                                gpointer user_data)
 {
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (gobject);
+	SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
+	struct timeval timeout;
+	LDAPMessage *result;
+	gboolean ret;
+	int rc, i;
+
+	if (ldap_gsource->cancelled) {
+		((SeahorseLdapCallback)callback) (NULL, user_data);
+		return FALSE;
+	}
 
-#ifdef WITH_SOUP
-    if (lop->addr)
-        g_object_unref (lop->addr);
-    lop->addr = NULL;
-#endif 
-        
-    if (lop->lsrc) {
-        g_object_unref (lop->lsrc);
-        lop->lsrc = NULL;
-    }
-    
-    if (lop->ldap_op != -1) {
-        if (lop->ldap)
-            ldap_abandon_ext (lop->ldap, lop->ldap_op, NULL, NULL);
-        lop->ldap_op = -1;
-    }
+	for (i = 0; i < DEFAULT_LOAD_BATCH; i++) {
 
-    if (lop->ldap) {
-        ldap_unbind_ext (lop->ldap, NULL, NULL);
-        lop->ldap = NULL;
-    }
-    
-    if (lop->stag) {
-        g_source_remove (lop->stag);
-        lop->stag = 0;
-    }
-        
-    G_OBJECT_CLASS (ldap_operation_parent_class)->dispose (gobject);  
-}
+		/* This effects a poll */
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 0;
 
-static void 
-seahorse_ldap_operation_finalize (GObject *gobject)
-{
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (gobject);
+		rc = ldap_result (ldap_gsource->ldap, ldap_gsource->ldap_op,
+		                  0, &timeout, &result);
+		if (rc == -1) {
+			g_warning ("ldap_result failed with rc = %d, errno = %s",
+			           rc, g_strerror (errno));
+			return FALSE;
 
-    g_assert (lop->lsrc == NULL);
-    g_assert (lop->ldap_op == -1);
-    g_assert (lop->stag == 0);
-    g_assert (lop->ldap == NULL);
-    
-    G_OBJECT_CLASS (ldap_operation_parent_class)->finalize (gobject);  
+		/* Timeout */
+		} else if (rc == 0) {
+			return TRUE;
+		}
+
+		ret = ((SeahorseLdapCallback)callback) (result, user_data);
+		ldap_msgfree (result);
+
+		if (!ret)
+			return FALSE;
+	}
+
+	return TRUE;
 }
 
-static void 
-seahorse_ldap_operation_cancel (SeahorseOperation *operation)
+static void
+seahorse_ldap_gsource_finalize (GSource *gsource)
 {
-    SeahorseLDAPOperation *lop;
-    
-    g_assert (SEAHORSE_IS_LDAP_OPERATION (operation));
-    lop = SEAHORSE_LDAP_OPERATION (operation);
-    
-#ifdef WITH_SOUP
-    /* This cancels lookup */
-    if (lop->addr)
-        g_object_unref (lop->addr);
-    lop->addr = NULL;
-#endif
-    
-    if (lop->ldap_op != -1) {
-        if (lop->ldap)
-            ldap_abandon_ext (lop->ldap, lop->ldap_op, NULL, NULL);
-        lop->ldap_op = -1;
-    }
+	SeahorseLdapGSource *ldap_gsource = (SeahorseLdapGSource *)gsource;
+	g_cancellable_disconnect (ldap_gsource->cancellable,
+	                          ldap_gsource->cancelled_sig);
+	g_clear_object (&ldap_gsource->cancellable);
+}
 
-    if (lop->ldap) {
-        ldap_unbind_ext (lop->ldap, NULL, NULL);
-        lop->ldap = NULL;
-    }
+static GSourceFuncs seahorse_ldap_gsource_funcs = {
+	seahorse_ldap_gsource_prepare,
+	seahorse_ldap_gsource_check,
+	seahorse_ldap_gsource_dispatch,
+	seahorse_ldap_gsource_finalize,
+};
 
-    if (lop->stag) {
-        g_source_remove (lop->stag);
-        lop->stag = 0;
-    }
-        
-    seahorse_operation_mark_done (operation, TRUE, NULL);
+static void
+on_ldap_gsource_cancelled (GCancellable *cancellable,
+                           gpointer user_data)
+{
+	SeahorseLdapGSource *ldap_gsource = user_data;
+	ldap_gsource->cancelled = TRUE;
 }
 
-/* Cancels operation and marks the LDAP operation as failed */
-static void
-fail_ldap_operation (SeahorseLDAPOperation *lop, int code)
+static GSource *
+seahorse_ldap_gsource_new (LDAP *ldap,
+                           int ldap_op,
+                           GCancellable *cancellable)
 {
-    gchar *t;
-    
-    if (code == 0)
-        ldap_get_option (lop->ldap, LDAP_OPT_ERROR_NUMBER, &code);
-    
-    g_object_get (lop->lsrc, "key-server", &t, NULL);
-    seahorse_operation_mark_done (SEAHORSE_OPERATION (lop), FALSE, 
-            g_error_new (LDAP_ERROR_DOMAIN, code, _("Couldn't communicate with '%s': %s"), 
-                         t, ldap_err2string(code)));
-    g_free (t);
+	GSource *gsource;
+	SeahorseLdapGSource *ldap_gsource;
+
+	gsource = g_source_new (&seahorse_ldap_gsource_funcs,
+	                        sizeof (SeahorseLdapGSource));
+
+	ldap_gsource = (SeahorseLdapGSource *)gsource;
+	ldap_gsource->ldap = ldap;
+	ldap_gsource->ldap_op = ldap_op;
+
+	if (cancellable) {
+		ldap_gsource->cancellable = g_object_ref (cancellable);
+		ldap_gsource->cancelled_sig = g_cancellable_connect (cancellable,
+		                                                     G_CALLBACK (on_ldap_gsource_cancelled),
+		                                                     ldap_gsource, NULL);
+	}
+
+	return gsource;
 }
 
-/* Gets called regularly to check for results of LDAP async work */
 static gboolean
-result_callback (SeahorseLDAPOperation *lop)
+seahorse_ldap_source_propagate_error (SeahorseLDAPSource *self,
+                                      int rc, GError **error)
 {
-    struct timeval timeout;
-    LDAPMessage *result;
-    gboolean ret;
-    int r, i;
-    
-    for (i = 0; i < DEFAULT_LOAD_BATCH; i++) {
+	gchar *server;
 
-        g_assert (SEAHORSE_IS_LDAP_OPERATION (lop));
-        g_assert (lop->ldap != NULL);
-        g_assert (lop->ldap_op != -1);
-        
-        /* This effects a poll */
-        timeout.tv_sec = 0;
-        timeout.tv_usec = 0;
-
-        r = ldap_result (lop->ldap, lop->ldap_op, 0, &timeout, &result);
-        switch (r) {   
-        case -1: /* Strange system error */
-            seahorse_operation_mark_done (SEAHORSE_OPERATION (lop), FALSE, 
-                g_error_new (LDAP_ERROR_DOMAIN, errno, "%s", g_strerror (errno)));
-            return FALSE;
-        
-        case 0: /* Timeout exceeded */
-            return TRUE;
-        };
-        
-        ret = (lop->ldap_cb) (SEAHORSE_OPERATION (lop), result);
-        ldap_msgfree (result);
-        
-        if(!ret)
-            break;
-    }
+	if (rc == LDAP_SUCCESS)
+		return FALSE;
 
-    /* We can't access lop at this point if not continuing. 
-     * It could have been freed */
-    if (ret) {
-        /* We always need a callback if we're continuing */
-        g_assert (lop->ldap_cb);
+	g_object_get (self, "key-server", &server, NULL);
+	g_set_error (error, LDAP_ERROR_DOMAIN, rc, _("Couldn't communicate with '%s': %s"),
+	             server, ldap_err2string (rc));
+	g_free (server);
 
-        /* Should not be marked as done. */
-        g_assert (seahorse_operation_is_running (SEAHORSE_OPERATION (lop)));
-    }    
-        
-    return ret;
+	return TRUE;
+}
+
+typedef struct {
+	GCancellable *cancellable;
+	LDAP *ldap;
+} source_connect_closure;
+
+static void
+source_connect_free (gpointer data)
+{
+	source_connect_closure *closure = data;
+	g_clear_object (&closure->cancellable);
+	if (closure->ldap)
+		ldap_unbind_ext (closure->ldap, NULL, NULL);
+	g_free (closure);
 }
 
-/* Called when retrieving server info is done, and we need to start work */
 static gboolean
-done_info_start_op (SeahorseOperation *op, LDAPMessage *result)
+on_connect_server_info_completed (LDAPMessage *result,
+                                  gpointer user_data)
 {
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (op);
-    LDAPServerInfo *sinfo;
-    char *message;
-    int code;
-    int r;
-    
-    g_assert (SEAHORSE_IS_LDAP_OPERATION (lop));
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_connect_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
+	LDAPServerInfo *sinfo;
+	char *message;
+	int code;
+	int type;
+	int rc;
 
-    /* This can be null when we short-circuit the server info */
-    if (result) {
-        r = ldap_msgtype (result);
-        g_return_val_if_fail (r == LDAP_RES_SEARCH_ENTRY || r == LDAP_RES_SEARCH_RESULT, FALSE);
-        
-        /* If we have results then fill in the server info */
-        if (r == LDAP_RES_SEARCH_ENTRY) {
+	type = ldap_msgtype (result);
+	g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
+
+	/* If we have results then fill in the server info */
+	if (type == LDAP_RES_SEARCH_ENTRY) {
 
-			seahorse_debug ("Server Info Result:");
+		seahorse_debug ("Server Info Result:");
 #ifdef WITH_DEBUG
-			if (seahorse_debugging)
-				dump_ldap_entry (lop->ldap, result);
+		if (seahorse_debugging)
+			dump_ldap_entry (closure->ldap, result);
 #endif
 
-            /* NOTE: When adding attributes here make sure to add them to kServerAttributes */
-            sinfo = g_new0 (LDAPServerInfo, 1);
-            sinfo->version = get_int_attribute (lop->ldap, result, "version");
-            sinfo->base_dn = get_string_attribute (lop->ldap, result, "basekeyspacedn");
-            if (!sinfo->base_dn)
-                sinfo->base_dn = get_string_attribute (lop->ldap, result, "pgpbasekeyspacedn");
-            sinfo->key_attr = g_strdup (sinfo->version > 1 ? "pgpkeyv2" : "pgpkey");
-            set_ldap_server_info (lop->lsrc, sinfo);
-            
-            ldap_abandon_ext (lop->ldap, lop->ldap_op, NULL, NULL);
-            lop->ldap_op = -1;
-            
-        } else {
-            lop->ldap_op = -1;
-            r = ldap_parse_result (lop->ldap, result, &code, NULL, &message, NULL, NULL, 0);
-            g_return_val_if_fail (r == LDAP_SUCCESS, FALSE);
-
-            if (code != LDAP_SUCCESS) 
-                g_warning ("operation to get LDAP server info failed: %s", message);
-            
-            ldap_memfree (message);
-        }
-    }
-    
-    /* Call the main operation callback */
-    return (lop->chain_cb) (op, NULL);
+		/* NOTE: When adding attributes here make sure to add them to kServerAttributes */
+		sinfo = g_new0 (LDAPServerInfo, 1);
+		sinfo->version = get_int_attribute (closure->ldap, result, "version");
+		sinfo->base_dn = get_string_attribute (closure->ldap, result, "basekeyspacedn");
+		if (!sinfo->base_dn)
+			sinfo->base_dn = get_string_attribute (closure->ldap, result, "pgpbasekeyspacedn");
+		sinfo->key_attr = g_strdup (sinfo->version > 1 ? "pgpkeyv2" : "pgpkey");
+		set_ldap_server_info (self, sinfo);
+
+		return TRUE; /* callback again */
+
+	} else {
+		rc = ldap_parse_result (closure->ldap, result, &code, NULL,
+		                        &message, NULL, NULL, 0);
+		g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
+
+		if (code != LDAP_SUCCESS)
+			g_warning ("operation to get LDAP server info failed: %s", message);
+
+		ldap_memfree (message);
+
+		g_simple_async_result_complete_in_idle (res);
+		seahorse_progress_end (closure->cancellable, res);
+		return FALSE; /* don't callback again */
+	}
 }
 
-/* Called when LDAP bind is done, and we need to retrieve server info */
+static const char *SERVER_ATTRIBUTES[] = {
+	"basekeyspacedn",
+	"pgpbasekeyspacedn",
+	"version",
+	NULL
+};
+
 static gboolean
-done_bind_start_info (SeahorseOperation *op, LDAPMessage *result)
+on_connect_bind_completed (LDAPMessage *result,
+                           gpointer user_data)
 {
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (op);
-    LDAPServerInfo *sinfo;
-    char *message;
-    int code;
-    int r;
-    
-    /* Always do this first, because we're done with the 
-     * operation regardless of the result */
-    lop->ldap_op = -1;
-
-    g_return_val_if_fail (SEAHORSE_IS_LDAP_OPERATION (lop), FALSE);
-    g_return_val_if_fail (result != NULL, FALSE);
-    g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_BIND, FALSE);
-
-    /* The result of the bind operation */
-    r = ldap_parse_result (lop->ldap, result, &code, NULL, &message, NULL, NULL, 0);
-    g_return_val_if_fail (r == LDAP_SUCCESS, FALSE);
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_connect_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
+	LDAPServerInfo *sinfo;
+	GError *error = NULL;
+	char *message;
+	int ldap_op;
+	int code;
+	int rc;
+
+	g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_BIND, FALSE);
+
+	/* The result of the bind operation */
+	rc = ldap_parse_result (closure->ldap, result, &code, NULL, &message, NULL, NULL, 0);
+	g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
+	ldap_memfree (message);
+
+	if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		return FALSE; /* don't call this callback again */
+	}
 
-    if (code != LDAP_SUCCESS) {
-        seahorse_operation_mark_done (op, FALSE, 
-                g_error_new_literal (LDAP_ERROR_DOMAIN, code, message));
-        return FALSE;
-    }
+	/* Check if we need server info */
+	sinfo = get_ldap_server_info (self, FALSE);
+	if (sinfo != NULL) {
+		g_simple_async_result_complete_in_idle (res);
+		seahorse_progress_end (closure->cancellable, res);
+		return FALSE; /* don't call this callback again */
+	}
 
-    ldap_memfree (message);
-     
-    /* Check if we need server info */
-    sinfo = get_ldap_server_info (lop->lsrc, FALSE);
-    if (sinfo != NULL)
-        return done_info_start_op (op, NULL);
-        
-    /* Retrieve the server info */
-    r = ldap_search_ext (lop->ldap, "cn=PGPServerInfo", LDAP_SCOPE_BASE,
-                         "(objectclass=*)", (char**)kServerAttributes, 0,
-                         NULL, NULL, NULL, 0, &(lop->ldap_op));    
-    if (r != LDAP_SUCCESS) {
-        fail_ldap_operation (lop, r);
-        return FALSE;
-    }
+	/* Retrieve the server info */
+	rc = ldap_search_ext (closure->ldap, "cn=PGPServerInfo", LDAP_SCOPE_BASE,
+	                      "(objectclass=*)", (char **)SERVER_ATTRIBUTES, 0,
+	                      NULL, NULL, NULL, 0, &ldap_op);
+
+	if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		return FALSE; /* don't call this callback again */
+
+	} else {
+		GSource *gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
+		                                              closure->cancellable);
+		g_source_set_callback (gsource, (GSourceFunc)on_connect_server_info_completed,
+		                       g_object_ref (res), g_object_unref);
+		g_source_attach (gsource, g_main_context_default ());
+		g_source_unref (gsource);
+	}
 
-    lop->ldap_cb = done_info_start_op;
-    return TRUE;
+	return FALSE; /* don't call this callback again */
 }
 
-/* Once the DNS name is resolved, we end up here */
 static void
-resolved_callback (gpointer unused, guint status, SeahorseLDAPOperation *lop)
+once_resolved_start_connect (SeahorseLDAPSource *self,
+                             GSimpleAsyncResult *res,
+                             const gchar *address)
 {
-    guint port = LDAP_PORT;
-    gchar *server = NULL;
-    struct berval cred;
-    gchar *t;
-    int rc;
-    
-    g_object_get (lop->lsrc, "key-server", &server, NULL);
-    g_return_if_fail (server && server[0]);
-    
-    if ((t = strchr (server, ':')) != NULL) {
-        *t = 0;
-        t++;
-        port = atoi (t);
-        if (port <= 0 || port >= G_MAXUINT16) {
-            g_warning ("invalid port number: %s (using default)", t);
-            port = LDAP_PORT;
-        }
-    }
+	source_connect_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	gchar *server = NULL;
+	GError *error = NULL;
+	gint port = LDAP_PORT;
+	struct berval cred;
+	int ldap_op;
+	gchar *url;
+	gchar *text;
+	int rc;
+
+	/* Now that we've resolved our address, connect via IP */
+	g_object_get (self, "key-server", &server, NULL);
+	g_return_if_fail (server && server[0]);
+
+	if ((text = strchr (server, ':')) != NULL) {
+		*text = 0;
+		text++;
+		port = atoi (text);
+		if (port <= 0 || port >= G_MAXUINT16) {
+			g_warning ("invalid port number: %s (using default)", text);
+			port = LDAP_PORT;
+		}
+	}
+
+	url = g_strdup_printf ("ldap://%s:%u";, address, port);
+	rc = ldap_initialize (&closure->ldap, url);
+	g_free (url);
+
+	if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+
+	/* Start the bind operation */
+	} else {
+		cred.bv_val = "";
+		cred.bv_len = 0;
+
+		rc = ldap_sasl_bind (closure->ldap, NULL, LDAP_SASL_SIMPLE, &cred,
+		                     NULL, NULL, &ldap_op);
+		if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
+			g_simple_async_result_take_error (res, error);
+			g_simple_async_result_complete_in_idle (res);
+
+		} else {
+			GSource *gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
+			                                     closure->cancellable);
+			g_source_set_callback (gsource, (GSourceFunc)on_connect_bind_completed,
+			                       g_object_ref (res), g_object_unref);
+			g_source_attach (gsource, g_main_context_default ());
+			g_source_unref (gsource);
+		}
+	}
+}
 
 #ifdef WITH_SOUP
-    
-    /* DNS failed */
-    if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
-        seahorse_operation_mark_done (SEAHORSE_OPERATION (lop), FALSE, 
-            g_error_new (SEAHORSE_ERROR, -1, _("Couldn't resolve address: %s"), server));
-        g_free (server);
-        return;
-    } 
-    
-    g_assert (lop->addr);
-    
-    {
-        /* Now that we've resolved our address, connect via IP */
-        gchar *url;
-
-        url = g_strdup_printf ("ldap://%s:%u";, soup_address_get_physical (lop->addr), port);
-        ldap_initialize (&(lop->ldap), url);
-        g_free (url);
-        g_return_if_fail (lop->ldap != NULL);
-    }
-    
-#else /* WITH_SOUP */
-    
-    /* No async DNS resolve, let libldap handle resolving synchronously */
-    ldap_initialize (&(lop->ldap), server);
-    g_return_if_fail (lop->ldap != NULL);    
-    
-#endif /* WITH_SOUP */
-    
-    /* The ldap_cb and chain_cb were set in seahorse_ldap_operation_start */
-    
-    t = g_strdup_printf (_("Connecting to: %s"), server);
-    seahorse_operation_mark_progress (SEAHORSE_OPERATION (lop), t, -1);
-    g_free (t);
 
-    g_free (server);
-    
-    /* Start the bind operation */
-    cred.bv_val = "";
-    cred.bv_len = 0;
-    rc = ldap_sasl_bind (lop->ldap, NULL, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &(lop->ldap_op));
-    if (rc != LDAP_SUCCESS) 
-        fail_ldap_operation (lop, rc);
-        
-    else   /* This starts looking for results */
-        lop->stag = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, 
-                        (GSourceFunc)result_callback, lop, NULL);
+static void
+on_address_resolved_complete (SoupAddress *address,
+                              guint status,
+                              gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
+	source_connect_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	gchar *server;
+
+	g_object_get (self, "key-server", &server, NULL);
+	g_return_if_fail (server && server[0]);
+	seahorse_progress_update (closure->cancellable, res, _("Connecting to: %s"), server);
+	g_free (server);
+
+	/* DNS failed */
+	if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+		g_simple_async_result_set_error (res, SEAHORSE_ERROR, -1,
+		                                 _("Couldn't resolve address: %s"),
+		                                 soup_address_get_name (address));
+		g_simple_async_result_complete_in_idle (res);
+
+	/* Yay resolved */
+	} else {
+		once_resolved_start_connect (self, res, soup_address_get_physical (address));
+	}
+
+	g_object_unref (res);
 }
 
-/* Start an LDAP (bind, server info) request */
-static SeahorseLDAPOperation*
-seahorse_ldap_operation_start (SeahorseLDAPSource *lsrc, OpLDAPCallback cb,
-                               guint total)
+#endif /* WITH_SOUP */
+
+static void
+seahorse_ldap_source_connect_async (SeahorseLDAPSource *source,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
 {
-    SeahorseLDAPOperation *lop;
+	GSimpleAsyncResult *res;
+	source_connect_closure *closure;
 #ifdef WITH_SOUP
-    gchar *server = NULL;
-    gchar *t;
+	SoupAddress *address;
+	gchar *server = NULL;
+	gchar *pos;
 #endif
 
-    g_assert (SEAHORSE_IS_LDAP_SOURCE (lsrc));
-    
-    lop = g_object_new (SEAHORSE_TYPE_LDAP_OPERATION, NULL);
-    lop->lsrc = lsrc;
-    g_object_ref (lsrc);
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ldap_source_connect_async);
+	closure = g_new0 (source_connect_closure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_connect_free);
 
-    /* Not used until step after resolve */
-    lop->ldap_cb = done_bind_start_info;
-    lop->chain_cb = cb;
-    
-    seahorse_operation_mark_start (SEAHORSE_OPERATION (lop));
-    
+	g_object_get (source, "key-server", &server, NULL);
+	g_return_if_fail (server && server[0]);
+	if ((pos = strchr (server, ':')) != NULL)
+		*pos = 0;
+
+	seahorse_progress_prep_and_begin (cancellable, res, NULL);
+
+	/* If we have libsoup, try and resolve asynchronously */
 #ifdef WITH_SOUP
-    
-    /* Try and resolve asynchronously */
-    g_object_get (lsrc, "key-server", &server, NULL);
-    g_return_val_if_fail (server && server[0], NULL);
+	address = soup_address_new (server, LDAP_PORT);
+	seahorse_progress_update (cancellable, res, _("Resolving server address: %s"), server);
 
-    if ((t = strchr (server, ':')) != NULL)
-        *t = 0;
-    lop->addr = soup_address_new (server, LDAP_PORT);
-    
-    t = g_strdup_printf (_("Resolving server address: %s"), server);
-    seahorse_operation_mark_progress (SEAHORSE_OPERATION (lop), t, -1);
-    g_free (t);
+	soup_address_resolve_async (address, NULL, cancellable,
+	                            on_address_resolved_complete,
+	                            g_object_ref (res));
+	g_object_unref (address);
+
+#else /* !WITH_SOUP */
+
+	once_resolved_start_connect (self, res, server);
 
-    g_free (server);
-    
-    soup_address_resolve_async (lop->addr, NULL, NULL,
-                                (SoupAddressCallback)resolved_callback, lop);
-    
-#else /* no WITH_SOUP */
-    
-    resolved_callback (NULL, 0, lop);
-    
 #endif
-    
-    return lop;
+
+	g_free (server);
+	g_object_unref (res);
 }
 
-/* -----------------------------------------------------------------------------
- *  SEARCH OPERATION 
- */
+static LDAP *
+seahorse_ldap_source_connect_finish (SeahorseLDAPSource *source,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	source_connect_closure *closure;
+	LDAP *ldap;
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ldap_source_connect_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	ldap = closure->ldap;
+	closure->ldap = NULL;
+	return ldap;
+}
+
+enum {
+	PROP_0,
+	PROP_SOURCE_TAG,
+	PROP_SOURCE_LOCATION
+};
+
+static void seahorse_source_iface (SeahorseSourceIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (SeahorseLDAPSource, seahorse_ldap_source, SEAHORSE_TYPE_SERVER_SOURCE, 0,
+                        G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_SOURCE, seahorse_source_iface));
+
+static void 
+seahorse_ldap_source_init (SeahorseLDAPSource *lsrc)
+{
+
+}
+
+static void 
+seahorse_ldap_source_get_property (GObject *object, guint prop_id, GValue *value,
+                                   GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_SOURCE_TAG:
+        g_value_set_uint (value, SEAHORSE_PGP);
+        break;
+    case PROP_SOURCE_LOCATION:
+        g_value_set_enum (value, SEAHORSE_LOCATION_REMOTE);
+        break;
+    };        
+}
+
+/* Initialize the basic class stuff */
+static void
+seahorse_ldap_source_class_init (SeahorseLDAPSourceClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	gobject_class->get_property = seahorse_ldap_source_get_property;
+
+	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
+	g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
+
+	seahorse_registry_register_type (NULL, SEAHORSE_TYPE_LDAP_SOURCE, "source", "remote", SEAHORSE_PGP_STR, NULL);
+	seahorse_servers_register_type ("ldap", _("LDAP Key Server"), seahorse_ldap_is_valid_uri);
+	seahorse_registry_register_function (NULL, seahorse_pgp_key_canonize_id, "canonize", SEAHORSE_PGP_STR, NULL);
+}
+
+typedef struct {
+	GCancellable *cancellable;
+	gchar *filter;
+	LDAP *ldap;
+	GList *results;
+} source_search_closure;
+
+static void
+source_search_free (gpointer data)
+{
+	source_search_closure *closure = data;
+	g_clear_object (&closure->cancellable);
+	g_list_free (closure->results);
+	g_free (closure->filter);
+	if (closure->ldap)
+		ldap_unbind_ext (closure->ldap, NULL, NULL);
+	g_free (closure);
+}
 
-static const char *kPGPAttributes[] = {
-    "pgpcertid",
-    "pgpuserid",
-    "pgprevoked",
-    "pgpdisabled",
-    "pgpkeycreatetime",
-    "pgpkeyexpiretime"
-    "pgpkeysize",
-    "pgpkeytype",
-    NULL
+static const char *PGP_ATTRIBUTES[] = {
+	"pgpcertid",
+	"pgpuserid",
+	"pgprevoked",
+	"pgpdisabled",
+	"pgpkeycreatetime",
+	"pgpkeyexpiretime"
+	"pgpkeysize",
+	"pgpkeytype",
+	NULL
 };
 
 static void
@@ -745,7 +821,7 @@ add_key (SeahorseLDAPSource *ssrc, SeahorsePgpKey *key)
 
 	keyid = seahorse_pgp_key_canonize_id (seahorse_pgp_key_get_keyid (key));
 	prev = seahorse_context_get_object (SCTX_APP (), SEAHORSE_SOURCE (ssrc), keyid);
-    
+
 	if (prev != NULL) {
 		g_return_if_fail (SEAHORSE_IS_PGP_KEY (prev));
 		seahorse_pgp_key_set_uids (SEAHORSE_PGP_KEY (prev), seahorse_pgp_key_get_uids (key));
@@ -753,677 +829,677 @@ add_key (SeahorseLDAPSource *ssrc, SeahorsePgpKey *key)
 		return;
 	}
 
-	/* Add to context */ 
+	/* Add to context */
 	seahorse_object_set_source (SEAHORSE_OBJECT (key), SEAHORSE_SOURCE (ssrc));
 	seahorse_context_add_object (SCTX_APP (), SEAHORSE_OBJECT (key));
 }
 
 /* Add a key to the key source from an LDAP entry */
-static void
-parse_key_from_ldap_entry (SeahorseLDAPOperation *lop, LDAPMessage *res)
+static SeahorseObject *
+search_parse_key_from_ldap_entry (SeahorseLDAPSource *self,
+                                  LDAP *ldap,
+                                  LDAPMessage *res)
 {
+	SeahorseObject *result = NULL;
 	const gchar *algo;
 	long int timestamp;
 	long int expires;
-        gchar *fpr, *fingerprint;
-        gchar *uidstr;
-        gboolean revoked;
-        gboolean disabled;
-        int length;
-        
-        g_assert (SEAHORSE_IS_LDAP_OPERATION (lop));
-        g_return_if_fail (res && ldap_msgtype (res) == LDAP_RES_SEARCH_ENTRY);  
-    
-        fpr = get_string_attribute (lop->ldap, res, "pgpcertid");
-        uidstr = get_string_attribute (lop->ldap, res, "pgpuserid");
-        revoked = get_boolean_attribute (lop->ldap, res, "pgprevoked");
-        disabled = get_boolean_attribute (lop->ldap, res, "pgpdisabled");
-        timestamp = get_date_attribute (lop->ldap, res, "pgpkeycreatetime");
-        expires = get_date_attribute (lop->ldap, res, "pgpkeyexpiretime");
-        algo = get_algo_attribute (lop->ldap, res, "pgpkeytype");
-        length = get_int_attribute (lop->ldap, res, "pgpkeysize");
-    
-        if (fpr && uidstr) {
-
-        	SeahorsePgpSubkey *subkey;
-        	SeahorsePgpKey *key;
-        	SeahorsePgpUid *uid;
-                GList *list;
-                guint flags;
-
-        	/* Build up a subkey */
-        	subkey = seahorse_pgp_subkey_new ();
-        	seahorse_pgp_subkey_set_keyid (subkey, fpr);
-        	fingerprint = seahorse_pgp_subkey_calc_fingerprint (fpr);
-        	seahorse_pgp_subkey_set_fingerprint (subkey, fingerprint);
-        	g_free (fingerprint);
-        	seahorse_pgp_subkey_set_created (subkey, timestamp);
-        	seahorse_pgp_subkey_set_expires (subkey, expires);
-        	seahorse_pgp_subkey_set_algorithm (subkey, algo);
-        	seahorse_pgp_subkey_set_length (subkey, length);
-
-        	flags = SEAHORSE_FLAG_EXPORTABLE;
-        	if (revoked)
-        		flags |= SEAHORSE_FLAG_REVOKED;
-        	if (disabled)
-        		flags |= SEAHORSE_FLAG_DISABLED;
-       		seahorse_pgp_subkey_set_flags (subkey, flags);
-
-        	/* Build up a uid */
-        	uid = seahorse_pgp_uid_new (uidstr);
-        	if (revoked)
-        		seahorse_pgp_uid_set_validity (uid, SEAHORSE_VALIDITY_REVOKED);
-        	
-        	/* Now build them into a key */
-        	key = seahorse_pgp_key_new ();
-        	list = g_list_prepend (NULL, uid);
-        	seahorse_pgp_key_set_uids (key, list);
-        	seahorse_object_list_free (list);
-        	list = g_list_prepend (NULL, subkey);
-        	seahorse_pgp_key_set_subkeys (key, list);
-        	seahorse_object_list_free (list);
-        	g_object_set (key, "location", SEAHORSE_LOCATION_REMOTE, 
-        	              "flags", flags, NULL);
-        
-        	add_key (lop->lsrc, key);
-        	g_object_unref (key);
-        }
-    
-        g_free (fpr);
-        g_free (uidstr);
+	gchar *fpr, *fingerprint;
+	gchar *uidstr;
+	gboolean revoked;
+	gboolean disabled;
+	int length;
+
+	g_return_val_if_fail (ldap_msgtype (res) == LDAP_RES_SEARCH_ENTRY, NULL);
+
+	fpr = get_string_attribute (ldap, res, "pgpcertid");
+	uidstr = get_string_attribute (ldap, res, "pgpuserid");
+	revoked = get_boolean_attribute (ldap, res, "pgprevoked");
+	disabled = get_boolean_attribute (ldap, res, "pgpdisabled");
+	timestamp = get_date_attribute (ldap, res, "pgpkeycreatetime");
+	expires = get_date_attribute (ldap, res, "pgpkeyexpiretime");
+	algo = get_algo_attribute (ldap, res, "pgpkeytype");
+	length = get_int_attribute (ldap, res, "pgpkeysize");
+
+	if (fpr && uidstr) {
+		SeahorsePgpSubkey *subkey;
+		SeahorsePgpKey *key;
+		SeahorsePgpUid *uid;
+		GList *list;
+		guint flags;
+
+		/* Build up a subkey */
+		subkey = seahorse_pgp_subkey_new ();
+		seahorse_pgp_subkey_set_keyid (subkey, fpr);
+		fingerprint = seahorse_pgp_subkey_calc_fingerprint (fpr);
+		seahorse_pgp_subkey_set_fingerprint (subkey, fingerprint);
+		g_free (fingerprint);
+		seahorse_pgp_subkey_set_created (subkey, timestamp);
+		seahorse_pgp_subkey_set_expires (subkey, expires);
+		seahorse_pgp_subkey_set_algorithm (subkey, algo);
+		seahorse_pgp_subkey_set_length (subkey, length);
+
+		flags = SEAHORSE_FLAG_EXPORTABLE;
+		if (revoked)
+			flags |= SEAHORSE_FLAG_REVOKED;
+		if (disabled)
+			flags |= SEAHORSE_FLAG_DISABLED;
+		seahorse_pgp_subkey_set_flags (subkey, flags);
+
+		/* Build up a uid */
+		uid = seahorse_pgp_uid_new (uidstr);
+		if (revoked)
+			seahorse_pgp_uid_set_validity (uid, SEAHORSE_VALIDITY_REVOKED);
+
+		/* Now build them into a key */
+		key = seahorse_pgp_key_new ();
+		list = g_list_prepend (NULL, uid);
+		seahorse_pgp_key_set_uids (key, list);
+		seahorse_object_list_free (list);
+		list = g_list_prepend (NULL, subkey);
+		seahorse_pgp_key_set_subkeys (key, list);
+		seahorse_object_list_free (list);
+		g_object_set (key, "location", SEAHORSE_LOCATION_REMOTE,
+		              "flags", flags, NULL);
+
+		add_key (self, key);
+		g_object_unref (key);
+		result = SEAHORSE_OBJECT (key);
+	}
+
+	g_free (fpr);
+	g_free (uidstr);
+
+	return result;
 }
 
-/* Got a search result */
-static gboolean 
-search_entry (SeahorseOperation *op, LDAPMessage *result)
+static gboolean
+on_search_search_completed (LDAPMessage *result,
+                            gpointer user_data)
 {
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (op);
-    char *message;
-    int code;
-    int r;
-  
-    r = ldap_msgtype (result);
-    g_return_val_if_fail (r == LDAP_RES_SEARCH_ENTRY || r == LDAP_RES_SEARCH_RESULT, FALSE);
-     
-    /* An LDAP entry */
-    if (r == LDAP_RES_SEARCH_ENTRY) {
-
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_search_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
+	GError *error = NULL;
+	SeahorseObject *key;
+	char *message;
+	int code;
+	int type;
+	int rc;
+
+	type = ldap_msgtype (result);
+	g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
+
+	/* An LDAP entry */
+	if (type == LDAP_RES_SEARCH_ENTRY) {
 		seahorse_debug ("Retrieved Key Entry:");
 #ifdef WITH_DEBUG
 		if (seahorse_debugging)
-			dump_ldap_entry (lop->ldap, result);
+			dump_ldap_entry (closure->ldap, result);
 #endif
 
-        parse_key_from_ldap_entry (lop, result);
-        return TRUE;
-        
-    /* All entries done */
-    } else {
-        lop->ldap_op = -1;
-        r = ldap_parse_result (lop->ldap, result, &code, NULL, &message, NULL, NULL, 0);
-        g_return_val_if_fail (r == LDAP_SUCCESS, FALSE);
-        
-        /* Error codes that we ignore */
-        switch (code) {
-        case LDAP_SIZELIMIT_EXCEEDED:
-            code = LDAP_SUCCESS;
-            break;
-        };
-        
-        /* Failure */
-        if (code != LDAP_SUCCESS) {
-            if (!message || !message[0]) 
-                fail_ldap_operation (lop, code);
-            else
-                seahorse_operation_mark_done (SEAHORSE_OPERATION (lop), FALSE, 
-                            g_error_new_literal (LDAP_ERROR_DOMAIN, code, message));
-            
-        /* Success */
-        } else {
-            seahorse_operation_mark_done (SEAHORSE_OPERATION (lop), FALSE, NULL);
-        }
-        ldap_memfree (message);
-
-        return FALSE;
-    }       
+		key = search_parse_key_from_ldap_entry (self, closure->ldap, result);
+		if (key != NULL)
+			closure->results = g_list_prepend (closure->results, key);
+		return TRUE; /* keep calling this callback */
+
+	/* All entries done */
+	} else {
+		rc = ldap_parse_result (closure->ldap, result, &code, NULL,
+		                        &message, NULL, NULL, 0);
+		g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
+
+		/* Error codes that we ignore */
+		switch (code) {
+		case LDAP_SIZELIMIT_EXCEEDED:
+			code = LDAP_SUCCESS;
+			break;
+		};
+
+		/* Failure */
+		if (code != LDAP_SUCCESS)
+			g_simple_async_result_set_error (res, LDAP_ERROR_DOMAIN,
+			                                 code, "%s", message);
+		else if (seahorse_ldap_source_propagate_error (self, code, &error))
+			g_simple_async_result_take_error (res, error);
+
+		ldap_memfree (message);
+		seahorse_progress_end (closure->cancellable, res);
+		g_simple_async_result_complete (res);
+		return FALSE;
+	}
 }
 
-/* Performs a search on an open LDAP connection */
-static gboolean
-start_search (SeahorseOperation *op, LDAPMessage *result)
+static void
+on_search_connect_completed (GObject *source,
+                             GAsyncResult *result,
+                             gpointer user_data)
 {
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (op);  
-    LDAPServerInfo *sinfo;
-    gchar *filter, *t;
-    int r;
-    
-    g_return_val_if_fail (lop->ldap != NULL, FALSE);
-    g_assert (lop->ldap_op == -1);
-    
-    filter = (gchar*)g_object_get_data (G_OBJECT (lop), "filter");
-    g_return_val_if_fail (filter != NULL, FALSE);
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_search_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
+	GError *error = NULL;
+	LDAPServerInfo *sinfo;
+	int ldap_op;
+	int rc;
+
+	closure->ldap = seahorse_ldap_source_connect_finish (SEAHORSE_LDAP_SOURCE (source),
+	                                                     result, &error);
+	if (error != NULL) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+		g_object_unref (res);
+		return;
+	}
 
-    t = (gchar*)g_object_get_data (G_OBJECT (lop), "details");
-    seahorse_operation_mark_progress (SEAHORSE_OPERATION (lop), t, -1);
-    
-    sinfo = get_ldap_server_info (lop->lsrc, TRUE);
+	sinfo = get_ldap_server_info (self, TRUE);
 
-    seahorse_debug ("Searching Server ... base: %s, filter: %s",
-                    sinfo->base_dn, filter);
-    
-    r = ldap_search_ext (lop->ldap, sinfo->base_dn, LDAP_SCOPE_SUBTREE,
-                         filter, (char**)kPGPAttributes, 0,
-                         NULL, NULL, NULL, 0, &(lop->ldap_op));    
-    if (r != LDAP_SUCCESS) {
-        fail_ldap_operation (lop, r);
-        return FALSE;
-    }                                    
-    
-    lop->ldap_cb = search_entry;
-    return TRUE;                                
-}
+	seahorse_debug ("Searching Server ... base: %s, filter: %s",
+	                sinfo->base_dn, closure->filter);
 
-/* Initiate a serch operation by uid  */
-static SeahorseLDAPOperation*
-start_search_operation (SeahorseLDAPSource *lsrc, const gchar *pattern)
-{
-    SeahorseLDAPOperation *lop;
-    gchar *filter;
-    gchar *t;
-    
-    g_assert (pattern && pattern[0]);
-    
-    t = escape_ldap_value (pattern);
-    filter = g_strdup_printf ("(pgpuserid=*%s*)", t);
-    g_free (t);
-    
-    lop = seahorse_ldap_operation_start (lsrc, start_search, 0);
-    g_return_val_if_fail (lop != NULL, NULL);
-    
-    g_object_set_data_full (G_OBJECT (lop), "filter", filter, g_free);
-    
-    t = g_strdup_printf (_("Searching for keys containing '%s'..."), pattern);
-    g_object_set_data_full (G_OBJECT (lop), "details", t, g_free);
-    
-    return lop;
-}
+	rc = ldap_search_ext (closure->ldap, sinfo->base_dn, LDAP_SCOPE_SUBTREE,
+	                      closure->filter, (char **)PGP_ATTRIBUTES, 0,
+	                      NULL, NULL, NULL, 0, &ldap_op);
 
-#if 0 /* UNUSED */
-/* Initiate a search operation by fingerprint */
-static SeahorseLDAPOperation *
-start_search_operation_fpr (SeahorseLDAPSource *lsrc, const gchar *fpr)
-{
-    SeahorseLDAPOperation *lop;
-    gchar *filter, *t;
-    guint l;
-    
-    g_assert (fpr && fpr[0]);
-    
-    l = strlen (fpr);
-    if (l > 16)
-        fpr += (l - 16);
-    
-    filter = g_strdup_printf ("(pgpcertid=%.16s)", fpr);
-    
-    lop = seahorse_ldap_operation_start (lsrc, start_search, 1);
-    g_return_val_if_fail (lop != NULL, NULL);
-    
-    g_object_set_data_full (G_OBJECT (lop), "filter", filter, g_free);
-    
-    t = g_strdup_printf (_("Searching for key id '%s'..."), fpr);
-    g_object_set_data_full (G_OBJECT (lop), "details", t, g_free);
-    
-    return lop;
+	if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+
+	} else {
+		GSource *gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
+		                                     closure->cancellable);
+		g_source_set_callback (gsource, (GSourceFunc)on_search_search_completed,
+		                       g_object_ref (res), g_object_unref);
+		g_source_attach (gsource, g_main_context_default ());
+		g_source_unref (gsource);
+	}
+
+	g_object_unref (res);
 }
-#endif /* UNUSED */
 
-/* -----------------------------------------------------------------------------
- *  GET OPERATION 
- */
- 
-static gboolean get_key_from_ldap (SeahorseOperation *op, LDAPMessage *result);
 
-/* Called when results come in from a key get */
-static gboolean 
-get_callback (SeahorseOperation *op, LDAPMessage *result)
+static void
+seahorse_ldap_source_search_async (SeahorseSource *source,
+                                   const gchar *match,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
 {
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (op);  
-    LDAPServerInfo *sinfo;
-    GOutputStream *output;
-    char *message;
-    GError *err = NULL;
-    gboolean ret;
-    gchar *key;
-    gsize written;
-    int code;
-    int r;
-  
-    r = ldap_msgtype (result);
-    g_return_val_if_fail (r == LDAP_RES_SEARCH_ENTRY || r == LDAP_RES_SEARCH_RESULT, FALSE);
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
+	source_search_closure *closure;
+	GSimpleAsyncResult *res;
+	gchar *text;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ldap_source_search_async);
+	closure = g_new0 (source_search_closure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	text = escape_ldap_value (match);
+	closure->filter = g_strdup_printf ("(pgpuserid=*%s*)", text);
+	g_free (text);
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_search_free);
+
+	seahorse_progress_prep_and_begin (closure->cancellable, res, NULL);
+
+	seahorse_ldap_source_connect_async (self, cancellable,
+	                                    on_search_connect_completed,
+	                                    g_object_ref (res));
+
+	g_object_unref (res);
+}
 
-    sinfo = get_ldap_server_info (lop->lsrc, TRUE);
-     
-    /* An LDAP Entry */
-    if (r == LDAP_RES_SEARCH_ENTRY) {
+static GList *
+seahorse_ldap_source_search_finish (SeahorseSource *source,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+	source_search_closure *closure;
+	GList *keys;
 
-		seahorse_debug ("Server Info Result:");
-#ifdef WITH_DEBUG
-		if (seahorse_debugging)
-			dump_ldap_entry (lop->ldap, result);
-#endif
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ldap_source_search_async), NULL);
 
-        key = get_string_attribute (lop->ldap, result, sinfo->key_attr);
-        
-        if (key == NULL) {
-            g_warning ("key server missing pgp key data");
-            fail_ldap_operation (lop, LDAP_NO_SUCH_OBJECT); 
-        }
-        
-        	output = seahorse_operation_get_result (SEAHORSE_OPERATION (lop));
-        	g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), FALSE);
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
 
-        	ret = g_output_stream_write_all (output, key, strlen (key), &written, NULL, &err) &&
-        	      g_output_stream_write_all (output, "\n", 1, &written, NULL, &err) && 
-        	      g_output_stream_flush (output, NULL, &err);
-        
-        	g_free (key);
-        
-        if (!ret) {
-            seahorse_operation_mark_done (SEAHORSE_OPERATION (lop), FALSE, err);
-            return FALSE;
-        }
-        
-        return TRUE;
-
-    /* No more entries, result */
-    } else {
-       
-        lop->ldap_op = -1;
-        r = ldap_parse_result (lop->ldap, result, &code, NULL, &message, NULL, NULL, 0);
-        g_return_val_if_fail (r == LDAP_SUCCESS, FALSE);
-        
-        if (code != LDAP_SUCCESS) {
-            seahorse_operation_mark_done (SEAHORSE_OPERATION (lop), FALSE, 
-                            g_error_new_literal (LDAP_ERROR_DOMAIN, code, message));
-        }
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	keys = closure->results;
+	closure->results = NULL;
+	return keys;
+}
 
-        ldap_memfree (message);
+typedef struct {
+	GPtrArray *keydata;
+	gint current_index;
+	GCancellable *cancellable;
+	LDAP *ldap;
+} source_import_closure;
 
-        /* Process more keys if possible */
-        if (code == LDAP_SUCCESS) 
-            return get_key_from_ldap (op, NULL);
-    }       
-    
-    return FALSE;
+static void
+source_import_free (gpointer data)
+{
+	source_import_closure *closure = data;
+	g_ptr_array_free (closure->keydata, TRUE);
+	g_clear_object (&closure->cancellable);
+	if (closure->ldap)
+		ldap_unbind_ext (closure->ldap, NULL, NULL);
+	g_free (closure);
 }
 
-/* Gets a key over an open LDAP connection */
+static void       import_send_key       (SeahorseLDAPSource *self,
+                                         GSimpleAsyncResult *res);
+
+/* Called when results come in for a key send */
 static gboolean
-get_key_from_ldap (SeahorseOperation *op, LDAPMessage *result)
+on_import_add_completed (LDAPMessage *result,
+                         gpointer user_data)
 {
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (op);  
-    LDAPServerInfo *sinfo;
-    GOutputStream *output;
-    gchar **fingerprints;
-    gchar **fprfull;
-    gchar *filter;
-    char *attrs[2];
-    const gchar *fpr;
-    GError *err = NULL;
-    int l, r;
-    
-    g_assert (lop->ldap != NULL);
-    g_assert (lop->ldap_op == -1);
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (user_data));
+	GError *error = NULL;
+	char *message;
+	int code;
+	int rc;
+
+	g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_ADD, FALSE);
+
+	rc = ldap_parse_result (closure->ldap, result, &code, NULL,
+	                        &message, NULL, NULL, 0);
+	g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
+
+	/* TODO: Somehow communicate this to the user */
+	if (code == LDAP_ALREADY_EXISTS)
+		code = LDAP_SUCCESS;
+
+	ldap_memfree (message);
+
+	if (seahorse_ldap_source_propagate_error (self, code, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+		return FALSE; /* don't call for this source again */
+	}
 
-    fingerprints = (gchar **)g_object_get_data (G_OBJECT (lop), "fingerprints");
-    fprfull = (gchar **)g_object_get_data (G_OBJECT (lop), "fingerprints-full");
+	import_send_key (self, res);
+	return FALSE; /* don't call for this source again */
+}
 
-    l = g_strv_length (fprfull);
-    seahorse_operation_mark_progress_full (SEAHORSE_OPERATION (lop), 
-                                           _("Retrieving remote keys..."), 
-                                           l - g_strv_length (fingerprints), l);
+static void
+import_send_key (SeahorseLDAPSource *self,
+                 GSimpleAsyncResult *res)
+{
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	LDAPServerInfo *sinfo;
+	gchar *base;
+	LDAPMod mod;
+	LDAPMod *attrs[2];
+	char *values[2];
+	GSource *gsource;
+	GError *error = NULL;
+	gchar *keydata;
+	int ldap_op;
+	int rc;
+
+	if (closure->current_index >= 0) {
+		keydata = closure->keydata->pdata[closure->current_index];
+		seahorse_progress_end (closure->cancellable, keydata);
+	}
 
-    if (fingerprints[0]) {
+	closure->current_index++;
 
-        fpr = fingerprints[0];
+	/* All done, complete operation */
+	if (closure->current_index == (gint)closure->keydata->len) {
+		g_simple_async_result_complete (res);
+		return;
+	}
 
-        /* Keep track of the ones that have already been done */
-        fingerprints++;
-        g_object_set_data (G_OBJECT (lop), "fingerprints", fingerprints);
+	keydata = closure->keydata->pdata[closure->current_index];
+	seahorse_progress_begin (closure->cancellable, keydata);
+	values[0] = keydata;
+	values[1] = NULL;
 
-        l = strlen (fpr);
-        if (l > 16)
-            fpr += (l - 16);
-    
-        filter = g_strdup_printf ("(pgpcertid=%.16s)", fpr);
-        sinfo = get_ldap_server_info (lop->lsrc, TRUE);
-        
-        attrs[0] = sinfo->key_attr;
-        attrs[1] = NULL;
-        
-        r = ldap_search_ext (lop->ldap, sinfo->base_dn, LDAP_SCOPE_SUBTREE,
-                             filter, attrs, 0,
-                             NULL, NULL, NULL, 0, &(lop->ldap_op));
-        g_free (filter);
-
-        if (r != LDAP_SUCCESS) {
-            fail_ldap_operation (lop, r);
-            return FALSE;
-        }                                    
-                
-        lop->ldap_cb = get_callback;
-        return TRUE;   
-    }
+	sinfo = get_ldap_server_info (self, TRUE);
+	memset (&mod, 0, sizeof (mod));
+	mod.mod_op = LDAP_MOD_ADD;
+	mod.mod_type = sinfo->key_attr;
+	mod.mod_values = values;
 
-	/* At this point we're done */
-	output = seahorse_operation_get_result (op);
-	g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), FALSE);
-	g_output_stream_close (output, NULL, &err);
-	seahorse_operation_mark_done (op, FALSE, err); 
-    
-	return FALSE;
-}
+	attrs[0] = &mod;
+	attrs[1] = NULL;
 
-/* Starts a get operation for multiple keys */
-static SeahorseLDAPOperation *
-start_get_operation_multiple (SeahorseLDAPSource *lsrc, gchar **fingerprints,
-                              GOutputStream *output)
-{
-	SeahorseLDAPOperation *lop;
+	base = g_strdup_printf ("pgpCertid=virtual,%s", sinfo->base_dn);
+	rc = ldap_add_ext (closure->ldap, base, attrs, NULL, NULL, &ldap_op);
 
-	g_assert (fingerprints && fingerprints[0]);
-	g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), NULL);
+	g_free (base);
 
-	lop = seahorse_ldap_operation_start (lsrc, get_key_from_ldap,
-	                                     g_strv_length (fingerprints));
-	g_return_val_if_fail (lop != NULL, NULL);
-
-	g_object_ref (output);
-	seahorse_operation_mark_result (SEAHORSE_OPERATION (lop), output, 
-	                                g_object_unref);
-
-	g_object_set_data (G_OBJECT (lop), "fingerprints", fingerprints);
-	g_object_set_data_full (G_OBJECT (lop), "fingerprints-full", fingerprints, 
-	                        (GDestroyNotify)g_strfreev);
+	if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
+		g_simple_async_result_complete (res);
+		return;
+	}
 
-    	return lop;
+	gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
+	                                     closure->cancellable);
+	g_source_set_callback (gsource, (GSourceFunc)on_import_add_completed,
+	                       g_object_ref (res), g_object_unref);
+	g_source_attach (gsource, g_main_context_default ());
+	g_source_unref (gsource);
 }
 
-/* -----------------------------------------------------------------------------
- *  SEND OPERATION 
- */
+static void
+on_import_connect_completed (GObject *source,
+                             GAsyncResult *result,
+                             gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	closure->ldap = seahorse_ldap_source_connect_finish (SEAHORSE_LDAP_SOURCE (source),
+	                                                     result, &error);
+	if (error != NULL) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+	} else {
+		import_send_key (SEAHORSE_LDAP_SOURCE (source), res);
+	}
 
-static gboolean send_key_to_ldap (SeahorseOperation *op, LDAPMessage *result);
+	g_object_unref (res);
+}
 
-/* Called when results come in for a key send */
-static gboolean 
-send_callback (SeahorseOperation *op, LDAPMessage *result)
+static void
+seahorse_ldap_source_import_async (SeahorseSource *source,
+                                   GInputStream *input,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
 {
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (op);  
-    char *message;
-    int code;
-    int r;
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
+	source_import_closure *closure;
+	GSimpleAsyncResult *res;
+	gchar *keydata;
+	guint len;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ldap_source_import_async);
+	closure = g_new0 (source_import_closure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->current_index = -1;
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_import_free);
+
+	closure->keydata =g_ptr_array_new_with_free_func (g_free);
+	for (;;) {
+		GString *buf = g_string_sized_new (2048);
+		len = seahorse_util_read_data_block (buf, input, "-----BEGIN PGP PUBLIC KEY BLOCK-----",
+		                                     "-----END PGP PUBLIC KEY BLOCK-----");
+		if (len > 0) {
+			keydata = g_string_free (buf, FALSE);
+			g_ptr_array_add (closure->keydata, keydata);
+			seahorse_progress_prep (closure->cancellable, keydata, NULL);
+		} else {
+			g_string_free (buf, TRUE);
+			break;
+		}
+	}
 
-    lop->ldap_op = -1;
+	seahorse_ldap_source_connect_async (self, cancellable,
+	                                    on_import_connect_completed,
+	                                    g_object_ref (res));
 
-    g_return_val_if_fail (ldap_msgtype (result) == LDAP_RES_ADD, FALSE);
+	g_object_unref (res);
+}
 
-    r = ldap_parse_result (lop->ldap, result, &code, NULL, &message, NULL, NULL, 0);
-    g_return_val_if_fail (r == LDAP_SUCCESS, FALSE);
-    
-    /* TODO: Somehow communicate this to the user */
-    if (code == LDAP_ALREADY_EXISTS)
-        code = LDAP_SUCCESS;
-        
-    if (code != LDAP_SUCCESS) 
-        seahorse_operation_mark_done (SEAHORSE_OPERATION (lop), FALSE, 
-                        g_error_new_literal (LDAP_ERROR_DOMAIN, code, message));
+static GList *
+seahorse_ldap_source_import_finish (SeahorseSource *source,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ldap_source_import_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
 
-    ldap_memfree (message);
+	/* We don't know the keys that were imported, since this is a server */
+	return NULL;
+}
 
-    /* Process more keys */
-    if (code == LDAP_SUCCESS)
-        return send_key_to_ldap (op, NULL);
+typedef struct {
+	GPtrArray *fingerprints;
+	gint current_index;
+	GOutputStream *output;
+	GCancellable *cancellable;
+	LDAP *ldap;
+} source_export_closure;
 
-    return FALSE;
+static void
+source_export_free (gpointer data)
+{
+	source_export_closure *closure = data;
+	g_ptr_array_free (closure->fingerprints, TRUE);
+	g_object_unref (closure->output);
+	g_clear_object (&closure->cancellable);
+	if (closure->ldap)
+		ldap_unbind_ext (closure->ldap, NULL, NULL);
+	g_free (closure);
 }
 
-/* Initiate a key send over an open LDAP connection */
+static void     export_retrieve_key     (SeahorseLDAPSource *self,
+                                         GSimpleAsyncResult *res);
+
 static gboolean
-send_key_to_ldap (SeahorseOperation *op, LDAPMessage *result)
+on_export_search_completed (LDAPMessage *result,
+                            gpointer user_data)
 {
-    SeahorseLDAPOperation *lop = SEAHORSE_LDAP_OPERATION (op);  
-    LDAPServerInfo *sinfo;
-    gchar **keys, **keysfull;
-    gchar *key;
-    gchar *base;
-    LDAPMod mod;
-    LDAPMod *attrs[2];
-    char *values[2];
-    guint l;
-    int r;
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_export_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (g_async_result_get_source_object (G_ASYNC_RESULT (res)));
+	LDAPServerInfo *sinfo;
+	char *message;
+	GError *error = NULL;
+	gboolean ret;
+	gchar *key;
+	gsize written;
+	int code;
+	int type;
+	int rc;
+
+	type = ldap_msgtype (result);
+	g_return_val_if_fail (type == LDAP_RES_SEARCH_ENTRY || type == LDAP_RES_SEARCH_RESULT, FALSE);
+	sinfo = get_ldap_server_info (self, TRUE);
+
+	/* An LDAP Entry */
+	if (type == LDAP_RES_SEARCH_ENTRY) {
 
-    g_assert (lop->ldap != NULL);
-    g_assert (lop->ldap_op == -1);
+		seahorse_debug ("Server Info Result:");
+#ifdef WITH_DEBUG
+		if (seahorse_debugging)
+			dump_ldap_entry (closure->ldap, result);
+#endif
 
-    keys = (gchar **)g_object_get_data (G_OBJECT (lop), "key-data");
-    keysfull = (gchar **)g_object_get_data (G_OBJECT (lop), "key-data-full");
+		key = get_string_attribute (closure->ldap, result, sinfo->key_attr);
 
-    l = g_strv_length (keysfull);
-    seahorse_operation_mark_progress_full (SEAHORSE_OPERATION (lop), 
-                                           _("Sending keys to key server..."), 
-                                           l - g_strv_length (keys), l);
-    
-    if (keys[0]) {
-        key = keys[0];
+		if (key == NULL) {
+			g_warning ("key server missing pgp key data");
+			seahorse_ldap_source_propagate_error (self, LDAP_NO_SUCH_OBJECT, &error);
+			g_simple_async_result_take_error (res, error);
+			g_simple_async_result_complete (res);
+			return FALSE;
+		}
 
-        /* Keep track of the ones that have already been done */
-        keys++;
-        g_object_set_data (G_OBJECT (lop), "key-data", keys);
+		ret = g_output_stream_write_all (closure->output, key, strlen (key), &written, NULL, &error) &&
+		      g_output_stream_write_all (closure->output, "\n", 1, &written, NULL, &error) &&
+		      g_output_stream_flush (closure->output, NULL, &error);
 
-        sinfo = get_ldap_server_info (lop->lsrc, TRUE);
-        
-        values[0] = key;
-        values[1] = NULL;
-                
-        memset (&mod, 0, sizeof (mod));
-        mod.mod_op = LDAP_MOD_ADD;
-        mod.mod_type = sinfo->key_attr;
-        mod.mod_values = values;
-        
-        attrs[0] = &mod;
-        attrs[1] = NULL;
-        
-        base = g_strdup_printf ("pgpCertid=virtual,%s", sinfo->base_dn);
-        
-        r = ldap_add_ext (lop->ldap, base, attrs, NULL, NULL, &(lop->ldap_op));
+		g_free (key);
 
-        g_free (base);
-        
-        if (r != LDAP_SUCCESS) {
-            fail_ldap_operation (lop, r);
-            return FALSE;
-        }                                    
-                
-        lop->ldap_cb = send_callback;
-        return TRUE;   
-    }
-    
-    /* At this point we're done */
-    seahorse_operation_mark_done (op, FALSE, NULL);
-    return FALSE;
-}
+		if (!ret) {
+			g_simple_async_result_take_error (res, error);
+			g_simple_async_result_complete (res);
+			return FALSE;
+		}
 
-/* Start a key send operation for multiple keys */
-static SeahorseLDAPOperation *
-start_send_operation_multiple (SeahorseLDAPSource *lsrc, gchar **keys)
-{
-    SeahorseLDAPOperation *lop;
+		return TRUE;
 
-    g_assert (g_strv_length (keys) > 0);
+	/* No more entries, result */
+	} else {
+		rc = ldap_parse_result (closure->ldap, result, &code, NULL,
+		                        &message, NULL, NULL, 0);
+		g_return_val_if_fail (rc == LDAP_SUCCESS, FALSE);
 
-    lop = seahorse_ldap_operation_start (lsrc, send_key_to_ldap, 
-                                         g_strv_length (keys));
-    g_return_val_if_fail (lop != NULL, NULL);
+		if (seahorse_ldap_source_propagate_error (self, code, &error)) {
+			g_simple_async_result_take_error (res, error);
+			g_simple_async_result_complete (res);
+			return FALSE;
+		}
 
-    g_object_set_data (G_OBJECT (lop), "key-data", keys);
-    g_object_set_data_full (G_OBJECT (lop), "key-data-full", keys, 
-                            (GDestroyNotify)g_strfreev);
+		ldap_memfree (message);
 
-    return lop;
+		/* Process more keys if possible */
+		export_retrieve_key (self, res);
+		return FALSE;
+	}
 }
 
-/* -----------------------------------------------------------------------------
- *  SEAHORSE LDAP SOURCE
- */
- 
-enum {
-    PROP_0,
-    PROP_SOURCE_TAG,
-    PROP_SOURCE_LOCATION
-};
+static void
+export_retrieve_key (SeahorseLDAPSource *self,
+                     GSimpleAsyncResult *res)
+{
+	source_export_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	LDAPServerInfo *sinfo;
+	gchar *filter;
+	char *attrs[2];
+	GSource *gsource;
+	const gchar *fingerprint;
+	GError *error = NULL;
+	int length, rc;
+	int ldap_op;
+
+	if (closure->current_index > 0) {
+		fingerprint = closure->fingerprints->pdata[closure->current_index];
+		seahorse_progress_end (closure->cancellable, fingerprint);
+	}
 
-static void seahorse_source_iface (SeahorseSourceIface *iface);
+	closure->current_index++;
 
-G_DEFINE_TYPE_EXTENDED (SeahorseLDAPSource, seahorse_ldap_source, SEAHORSE_TYPE_SERVER_SOURCE, 0,
-                        G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_SOURCE, seahorse_source_iface));
+	/* All done, complete operation */
+	if (closure->current_index == (gint)closure->fingerprints->len) {
+		g_simple_async_result_complete (res);
+		return;
+	}
 
-static void 
-seahorse_ldap_source_init (SeahorseLDAPSource *lsrc)
-{
+	fingerprint = closure->fingerprints->pdata[closure->current_index];
+	seahorse_progress_begin (closure->cancellable, fingerprint);
+	length = strlen (fingerprint);
+	if (length > 16)
+		fingerprint += (length - 16);
 
-}
+	filter = g_strdup_printf ("(pgpcertid=%.16s)", fingerprint);
+	sinfo = get_ldap_server_info (self, TRUE);
 
-static void 
-seahorse_ldap_source_get_property (GObject *object, guint prop_id, GValue *value,
-                                   GParamSpec *pspec)
-{
-    switch (prop_id) {
-    case PROP_SOURCE_TAG:
-        g_value_set_uint (value, SEAHORSE_PGP);
-        break;
-    case PROP_SOURCE_LOCATION:
-        g_value_set_enum (value, SEAHORSE_LOCATION_REMOTE);
-        break;
-    };        
-}
+	attrs[0] = sinfo->key_attr;
+	attrs[1] = NULL;
 
-static void 
-seahorse_ldap_source_set_property (GObject *object, guint prop_id, const GValue *value,
-                                   GParamSpec *pspec)
-{
+	rc = ldap_search_ext (closure->ldap, sinfo->base_dn, LDAP_SCOPE_SUBTREE,
+	                      filter, attrs, 0,
+	                      NULL, NULL, NULL, 0, &ldap_op);
+	g_free (filter);
 
-}
+	if (seahorse_ldap_source_propagate_error (self, rc, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+		return;
+	}
 
-static SeahorseOperation*
-seahorse_ldap_source_search (SeahorseSource *src, const gchar *match)
-{
-    SeahorseLDAPOperation *lop = NULL;
-
-    g_assert (SEAHORSE_IS_SOURCE (src));
-    g_assert (SEAHORSE_IS_LDAP_SOURCE (src));
-
-    /* Search for keys */
-    lop = start_search_operation (SEAHORSE_LDAP_SOURCE (src), match);
-     
-    g_return_val_if_fail (lop != NULL, NULL);
-    seahorse_server_source_take_operation (SEAHORSE_SERVER_SOURCE (src),
-                                           SEAHORSE_OPERATION (lop));
-    g_object_ref (lop);
-    return SEAHORSE_OPERATION (lop);
+	gsource = seahorse_ldap_gsource_new (closure->ldap, ldap_op,
+	                                     closure->cancellable);
+	g_source_set_callback (gsource, (GSourceFunc)on_export_search_completed,
+	                       g_object_ref (res), g_object_unref);
+	g_source_attach (gsource, g_main_context_default ());
+	g_source_unref (gsource);
 }
 
-static SeahorseOperation* 
-seahorse_ldap_source_import (SeahorseSource *sksrc, GInputStream *input)
+static void
+on_export_connect_completed (GObject *source,
+                             GAsyncResult *result,
+                             gpointer user_data)
 {
-    SeahorseLDAPOperation *lop;
-    SeahorseLDAPSource *lsrc;
-    GPtrArray *keydata;
-    GString *buf = NULL;
-    guint len;
-
-    g_return_val_if_fail (SEAHORSE_IS_LDAP_SOURCE (sksrc), NULL);
-    lsrc = SEAHORSE_LDAP_SOURCE (sksrc);
-
-    g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
-    g_object_ref (input);
-
-    keydata = g_ptr_array_new_with_free_func (g_free);
-    for (;;) {
-     
-        buf = g_string_sized_new (2048);
-        len = seahorse_util_read_data_block (buf, input, "-----BEGIN PGP PUBLIC KEY BLOCK-----",
-                                             "-----END PGP PUBLIC KEY BLOCK-----");
-    
-        if (len > 0) {
-            g_ptr_array_add (keydata, g_string_free (buf, FALSE));
-        } else {
-            g_string_free (buf, TRUE);
-            break;
-        }
-    }
-
-    g_ptr_array_add (keydata, NULL);
-    lop = start_send_operation_multiple (lsrc, (gchar **)g_ptr_array_free (keydata, FALSE));
-    g_return_val_if_fail (lop != NULL, NULL);
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_export_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	closure->ldap = seahorse_ldap_source_connect_finish (SEAHORSE_LDAP_SOURCE (source),
+	                                                     result, &error);
+	if (error != NULL) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+	} else {
+		export_retrieve_key (SEAHORSE_LDAP_SOURCE (source), res);
+	}
 
-    g_object_unref (input);
-    return SEAHORSE_OPERATION (lop);
+	g_object_unref (res);
 }
 
-static SeahorseOperation* 
-seahorse_ldap_source_export_raw (SeahorseSource *sksrc, GList *keyids,
-                                 GOutputStream *output)
+static void
+seahorse_ldap_source_export_raw_async (SeahorseSource *source,
+                                       GList *keyids,
+                                       GOutputStream *output,
+                                       GCancellable *cancellable,
+                                       GAsyncReadyCallback callback,
+                                       gpointer user_data)
 {
-    SeahorseLDAPOperation *lop;
-    SeahorseLDAPSource *lsrc;
-    GList *l;
-    GPtrArray *fingerprints;
-    
-    g_return_val_if_fail (SEAHORSE_IS_LDAP_SOURCE (sksrc), NULL);
-    g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), NULL);
-
-    lsrc = SEAHORSE_LDAP_SOURCE (sksrc);
-
-    fingerprints = g_ptr_array_new_with_free_func (g_free);
-    for (l = keyids; l; l = g_list_next (l))
-        g_ptr_array_add (fingerprints,
-            g_strdup (seahorse_pgp_key_calc_rawid (GPOINTER_TO_UINT (l->data))));
-    g_ptr_array_add (fingerprints, NULL);
+	SeahorseLDAPSource *self = SEAHORSE_LDAP_SOURCE (source);
+	source_export_closure *closure;
+	GSimpleAsyncResult *res;
+	gchar *fingerprint;
+	GList *l;
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 seahorse_ldap_source_export_raw_async);
+	closure = g_new0 (source_export_closure, 1);
+	closure->output = g_object_ref (output);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->fingerprints = g_ptr_array_new_with_free_func (g_free);
+	for (l = keyids; l; l = g_list_next (l)) {
+		fingerprint = g_strdup (seahorse_pgp_key_calc_rawid (GPOINTER_TO_UINT (l->data)));
+		g_ptr_array_add (closure->fingerprints, fingerprint);
+		seahorse_progress_prep (closure->cancellable, fingerprint, NULL);
+	}
+	closure->current_index = -1;
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_export_free);
 
-    lop = start_get_operation_multiple (lsrc, (gchar **)g_ptr_array_free (fingerprints, FALSE), output);
-    g_return_val_if_fail (lop != NULL, NULL);
+	seahorse_ldap_source_connect_async (self, cancellable,
+	                                    on_export_connect_completed,
+	                                    g_object_ref (res));
 
-    return SEAHORSE_OPERATION (lop);
+	g_object_unref (res);
 }
 
-/* Initialize the basic class stuff */
-static void
-seahorse_ldap_source_class_init (SeahorseLDAPSourceClass *klass)
+static GOutputStream *
+seahorse_ldap_source_export_raw_finish (SeahorseSource *source,
+                                        GAsyncResult *result,
+                                        GError **error)
 {
-	GObjectClass *gobject_class;
-   
-	gobject_class = G_OBJECT_CLASS (klass);
-	gobject_class->get_property = seahorse_ldap_source_get_property;
-	gobject_class->set_property = seahorse_ldap_source_set_property;
+	source_export_closure *closure;
 
-	seahorse_ldap_source_parent_class = g_type_class_peek_parent (klass);
-    
-	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
-	g_object_class_override_property (gobject_class, PROP_SOURCE_LOCATION, "source-location");
-	    
-	seahorse_registry_register_type (NULL, SEAHORSE_TYPE_LDAP_SOURCE, "source", "remote", SEAHORSE_PGP_STR, NULL);
-	seahorse_servers_register_type ("ldap", _("LDAP Key Server"), seahorse_ldap_is_valid_uri);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ldap_source_export_raw_async), FALSE);
 
-	seahorse_registry_register_function (NULL, seahorse_pgp_key_canonize_id, "canonize", SEAHORSE_PGP_STR, NULL);
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	return closure->output;
 }
 
 static void 
 seahorse_source_iface (SeahorseSourceIface *iface)
 {
-	iface->search = seahorse_ldap_source_search;
-	iface->import = seahorse_ldap_source_import;
-	iface->export_raw = seahorse_ldap_source_export_raw;
+	iface->search_async = seahorse_ldap_source_search_async;
+	iface->search_finish = seahorse_ldap_source_search_finish;
+	iface->import_async = seahorse_ldap_source_import_async;
+	iface->import_finish = seahorse_ldap_source_import_finish;
+	iface->export_raw_async = seahorse_ldap_source_export_raw_async;
+	iface->export_raw_finish = seahorse_ldap_source_export_raw_finish;
 }
 
 /**
diff --git a/pgp/seahorse-pgp-commands.c b/pgp/seahorse-pgp-commands.c
index 132949b..93c7585 100644
--- a/pgp/seahorse-pgp-commands.c
+++ b/pgp/seahorse-pgp-commands.c
@@ -25,6 +25,7 @@
 
 #include "seahorse-gpgme-dialogs.h"
 #include "seahorse-gpgme-key.h"
+#include "seahorse-gpgme-key-op.h"
 #include "seahorse-gpgme-uid.h"
 #include "seahorse-pgp.h"
 #include "seahorse-pgp-commands.h"
@@ -122,7 +123,7 @@ seahorse_pgp_commands_show_properties (SeahorseCommands* base, SeahorseObject* o
 	seahorse_pgp_key_properties_show (SEAHORSE_PGP_KEY (obj), seahorse_commands_get_window (base));
 }
 
-static SeahorseOperation*
+static gboolean
 seahorse_pgp_commands_delete_objects (SeahorseCommands* base, GList* objects) 
 {
 	guint num;
@@ -131,12 +132,14 @@ seahorse_pgp_commands_delete_objects (SeahorseCommands* base, GList* objects)
 	char* message;
 	SeahorseObject *obj;
 	GList* to_delete, *l;
-	SeahorseOperation *op;
+	GtkWidget *parent;
+	gpgme_error_t gerr;
 	guint length;
+	GError *error = NULL;
 
 	num = g_list_length (objects);
 	if (num == 0)
-		return NULL;
+		return TRUE;
 
 	num_keys = 0;
 	num_identities = 0;
@@ -148,7 +151,7 @@ seahorse_pgp_commands_delete_objects (SeahorseCommands* base, GList* objects)
 	 * chopping block.
 	 */
 	to_delete = NULL;
-	
+
 	for (l = objects; l; l = g_list_next (l)) {
 		obj = SEAHORSE_OBJECT (l->data);
 		if (G_OBJECT_TYPE (obj) == SEAHORSE_TYPE_GPGME_UID) {
@@ -166,7 +169,7 @@ seahorse_pgp_commands_delete_objects (SeahorseCommands* base, GList* objects)
 	length = g_list_length (to_delete);
 	switch (length) {
 	case 0:
-		return NULL;
+		return TRUE;
 	case 1:
 		message = g_strdup_printf (_ ("Are you sure you want to permanently delete %s?"), 
 		                           seahorse_object_get_label (to_delete->data));
@@ -183,19 +186,36 @@ seahorse_pgp_commands_delete_objects (SeahorseCommands* base, GList* objects)
 		}
 		break;
 	}
-	
-	if (!seahorse_util_prompt_delete (message, GTK_WIDGET (seahorse_commands_get_window (base)))) {
+
+	parent = GTK_WIDGET (seahorse_commands_get_window (base));
+	if (!seahorse_util_prompt_delete (message, parent)) {
 		g_free (message);
-		return NULL;
+		return FALSE;
+	}
 
+	gerr = 0;
+	for (l = objects; l; l = g_list_next (l)) {
+		obj = SEAHORSE_OBJECT (l->data);
+		if (SEAHORSE_IS_GPGME_UID (obj)) {
+			gerr = seahorse_gpgme_key_op_del_uid (SEAHORSE_GPGME_UID (obj));
+			message = _("Couldn't delete user ID");
+		} else if (SEAHORSE_IS_GPGME_KEY (obj)) {
+			if (seahorse_object_get_usage (obj) == SEAHORSE_USAGE_PRIVATE_KEY) {
+				gerr = seahorse_gpgme_key_op_delete_pair (SEAHORSE_GPGME_KEY (obj));
+				message = _("Couldn't delete private key");
+			} else {
+				gerr = seahorse_gpgme_key_op_delete (SEAHORSE_GPGME_KEY (obj));
+				message = _("Couldn't delete public key");
+			}
+		}
+
+		if (seahorse_gpgme_propagate_error (gerr, &error)) {
+			seahorse_util_handle_error (&error, parent, "%s", message);
+			return FALSE;
+		}
 	}
-	
-	op = seahorse_source_delete_objects (to_delete);
 
-	g_free (message);
-	g_list_free (to_delete);
-	
-	return op;
+	return TRUE;
 }
 
 static GObject* 
diff --git a/pgp/seahorse-pgp-commands.h b/pgp/seahorse-pgp-commands.h
index c1bc1dc..f1df72f 100644
--- a/pgp/seahorse-pgp-commands.h
+++ b/pgp/seahorse-pgp-commands.h
@@ -27,8 +27,6 @@
 
 #include "seahorse-commands.h"
 #include "seahorse-object.h"
-#include <seahorse-operation.h>
-
 
 #define SEAHORSE_TYPE_PGP_COMMANDS                 (seahorse_pgp_commands_get_type ())
 #define SEAHORSE_PGP_COMMANDS(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_PGP_COMMANDS, SeahorsePgpCommands))
diff --git a/pgp/seahorse-pgp-generate.xml b/pgp/seahorse-pgp-generate.xml
index a3bc9ac..a3d9fbe 100644
--- a/pgp/seahorse-pgp-generate.xml
+++ b/pgp/seahorse-pgp-generate.xml
@@ -262,7 +262,7 @@
                                 <property name="yalign">0</property>
                                 <property name="xscale">0</property>
                                 <child>
-                                  <object class="GtkComboBox" id="algorithm-choice">
+                                  <object class="GtkComboBoxText" id="algorithm-choice">
                                     <property name="visible">True</property>
                                     <property name="model">model1</property>
                                     <signal name="changed" handler="on_gpgme_generate_algorithm_changed"/>
diff --git a/pgp/seahorse-pgp-key-properties.c b/pgp/seahorse-pgp-key-properties.c
index bfcd088..82f4778 100644
--- a/pgp/seahorse-pgp-key-properties.c
+++ b/pgp/seahorse-pgp-key-properties.c
@@ -346,6 +346,7 @@ names_populate (SeahorseWidget *swidget, GtkTreeStore *store, SeahorsePgpKey *pk
 	GList *keys, *l;
 	GList *uids, *u;
 	GList *sigs, *s;
+	GCancellable *cancellable;
 
 	/* Insert all the fun-ness */
 	uids = seahorse_pgp_key_get_uids (pkey);
@@ -370,9 +371,15 @@ names_populate (SeahorseWidget *swidget, GtkTreeStore *store, SeahorsePgpKey *pk
 				continue;
 			rawids = g_list_prepend (rawids, (gpointer)seahorse_pgp_signature_get_keyid (s->data));
 		}
-        
-		/* Pass it to 'DiscoverKeys' for resolution/download */
-		keys = seahorse_context_discover_objects (SCTX_APP (), SEAHORSE_PGP, rawids);
+
+		/*
+		 * Pass it to 'DiscoverKeys' for resolution/download, cancellable
+		 * ties search scope together
+		 */
+		cancellable = g_cancellable_new ();
+		keys = seahorse_context_discover_objects (seahorse_context_instance (),
+		                                          SEAHORSE_PGP, rawids, cancellable);
+		g_object_unref (cancellable);
 		g_list_free (rawids);
 		rawids = NULL;
         
@@ -1005,9 +1012,8 @@ export_complete (GFile *file, GAsyncResult *result, gchar *contents)
 	if (!g_file_replace_contents_finish (file, result, NULL, &err)) {
 		uri = g_file_get_uri (file);
 		unesc_uri = g_uri_unescape_string (seahorse_util_uri_get_last (uri), NULL);
-        seahorse_util_handle_error (err, _("Couldn't export key to \"%s\""),
-                                    unesc_uri);
-        g_clear_error (&err);
+		seahorse_util_handle_error (&err, NULL, _("Couldn't export key to \"%s\""),
+		                            unesc_uri);
         g_free (uri);
         g_free (unesc_uri);
 	}
@@ -1058,9 +1064,8 @@ on_pgp_details_export_button (GtkWidget *widget, SeahorseWidget *swidget)
 		                               G_FILE_CREATE_PRIVATE, NULL, 
 		                               (GAsyncReadyCallback)export_complete, results);
 	} else {
-		seahorse_gpgme_to_error (gerr, &err);
-		seahorse_util_handle_error (err, _("Couldn't export key."));
-		g_clear_error (&err);
+		seahorse_gpgme_propagate_error (gerr, &err);
+		seahorse_util_handle_error (&err, NULL, _("Couldn't export key."));
 	}
 	
 	g_free (uri);
@@ -1480,6 +1485,7 @@ signatures_populate_model (SeahorseWidget *swidget, SeahorseObjectModel *skmodel
 	GList *rawids = NULL;
 	GList *keys, *l, *uids;
 	GList *sigs, *s;
+	GCancellable *cancellable;
 
 	pkey = SEAHORSE_PGP_KEY (SEAHORSE_OBJECT_WIDGET (swidget)->object);
 	widget = GTK_WIDGET (seahorse_widget_get_widget (swidget, "signatures-tree"));
@@ -1507,9 +1513,15 @@ signatures_populate_model (SeahorseWidget *swidget, SeahorseObjectModel *skmodel
     
 		/* String out duplicates */
 		rawids = unique_slist_strings (rawids);
-        
-		/* Pass it to 'DiscoverKeys' for resolution/download */
-		keys = seahorse_context_discover_objects (SCTX_APP (), SEAHORSE_PGP, rawids);
+
+		/*
+		 * Pass it to 'DiscoverKeys' for resolution/download. cancellable ties
+		 * search scope together
+		 */
+		cancellable = g_cancellable_new ();
+		keys = seahorse_context_discover_objects (seahorse_context_instance (), SEAHORSE_PGP,
+		                                          rawids, cancellable);
+		g_object_unref (cancellable);
 		g_list_free (rawids);
 		rawids = NULL;
         
diff --git a/pgp/seahorse-server-source.c b/pgp/seahorse-server-source.c
index 0b84bd8..852e67c 100644
--- a/pgp/seahorse-server-source.c
+++ b/pgp/seahorse-server-source.c
@@ -26,7 +26,6 @@
 
 #include <glib/gi18n.h>
 
-#include "seahorse-operation.h"
 #include "seahorse-ldap-source.h"
 #include "seahorse-hkp-source.h"
 #include "seahorse-server-source.h"
@@ -55,7 +54,6 @@ enum {
  */
  
 struct _SeahorseServerSourcePrivate {
-    SeahorseMultiOperation *mop;
     gchar *server;
     gchar *uri;
 };
@@ -66,18 +64,11 @@ G_DEFINE_TYPE_EXTENDED (SeahorseServerSource, seahorse_server_source, G_TYPE_OBJ
                         G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_SOURCE, seahorse_source_iface));
 
 /* GObject handlers */
-static void seahorse_server_source_dispose    (GObject *gobject);
 static void seahorse_server_source_finalize   (GObject *gobject);
 static void seahorse_server_get_property      (GObject *object, guint prop_id,
                                                GValue *value, GParamSpec *pspec);
 static void seahorse_server_set_property      (GObject *object, guint prop_id,
                                                const GValue *value, GParamSpec *pspec);
-                                               
-/* SeahorseSource methods */
-static SeahorseOperation*  seahorse_server_source_load (SeahorseSource *src);
-
-static GObjectClass *parent_class = NULL;
-
 
 /**
 * klass: Class to initialize
@@ -89,11 +80,9 @@ static void
 seahorse_server_source_class_init (SeahorseServerSourceClass *klass)
 {
     GObjectClass *gobject_class;
-   
-    parent_class = g_type_class_peek_parent (klass);
+
     gobject_class = G_OBJECT_CLASS (klass);
     
-    gobject_class->dispose = seahorse_server_source_dispose;
     gobject_class->finalize = seahorse_server_source_finalize;
     gobject_class->set_property = seahorse_server_set_property;
     gobject_class->get_property = seahorse_server_get_property;
@@ -114,6 +103,34 @@ seahorse_server_source_class_init (SeahorseServerSourceClass *klass)
 	seahorse_registry_register_function (NULL, seahorse_pgp_key_canonize_id, "canonize", SEAHORSE_PGP_STR, NULL);
 }
 
+static void
+seahorse_server_source_load_async (SeahorseSource *source,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_server_source_load_async);
+	g_simple_async_result_complete_in_idle (res);
+	g_object_unref (res);
+}
+
+static gboolean
+seahorse_server_source_load_finish (SeahorseSource *source,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_server_source_load_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
+
 /**
 * iface: The #SeahorseSourceIface to init
 *
@@ -125,7 +142,8 @@ seahorse_server_source_class_init (SeahorseServerSourceClass *klass)
 static void 
 seahorse_source_iface (SeahorseSourceIface *iface)
 {
-	iface->load = seahorse_server_source_load;
+	iface->load_async = seahorse_server_source_load_async;
+	iface->load_finish = seahorse_server_source_load_finish;
 }
 
 /**
@@ -140,44 +158,8 @@ seahorse_server_source_init (SeahorseServerSource *ssrc)
 {
     /* init private vars */
     ssrc->priv = g_new0 (SeahorseServerSourcePrivate, 1);
-    ssrc->priv->mop = seahorse_multi_operation_new ();
 }
 
-
-/**
-* gobject: A #SeahorseServerSource object
-*
-* dispose of all our internal references
-*
-**/
-static void
-seahorse_server_source_dispose (GObject *gobject)
-{
-    SeahorseServerSource *ssrc;
-
-    /*
-     * Note that after this executes the rest of the object should
-     * still work without a segfault. This basically nullifies the 
-     * object, but doesn't free it.
-     * 
-     * This function should also be able to run multiple times.
-     */
-  
-    ssrc = SEAHORSE_SERVER_SOURCE (gobject);
-    g_assert (ssrc->priv);
-    
-    /* Clear out all the operations */
-    if (ssrc->priv->mop) {
-        if(seahorse_operation_is_running (SEAHORSE_OPERATION (ssrc->priv->mop)))
-            seahorse_operation_cancel (SEAHORSE_OPERATION (ssrc->priv->mop));
-        g_object_unref (ssrc->priv->mop);
-        ssrc->priv->mop = NULL;
-    }
- 
-    G_OBJECT_CLASS (parent_class)->dispose (gobject);
-}
-
-
 /**
 * gobject: A #SeahorseServerSource object
 *
@@ -194,10 +176,9 @@ seahorse_server_source_finalize (GObject *gobject)
     
     g_free (ssrc->priv->server);
     g_free (ssrc->priv->uri);
-    g_assert (ssrc->priv->mop == NULL);    
     g_free (ssrc->priv);
  
-    G_OBJECT_CLASS (parent_class)->finalize (gobject);
+    G_OBJECT_CLASS (seahorse_server_source_parent_class)->finalize (gobject);
 }
 
 /**
@@ -264,49 +245,11 @@ seahorse_server_get_property (GObject *object, guint prop_id, GValue *value,
     }        
 }
 
-
-/* --------------------------------------------------------------------------
- * HELPERS 
- */
-
-/**
- * seahorse_server_source_take_operation:
- * @ssrc: the #SeahorseServerSource to add the @op to
- * @op: add this to the multioperations stored in @ssrc
- *
- *
- *
- */
-void
-seahorse_server_source_take_operation (SeahorseServerSource *ssrc, SeahorseOperation *op)
-{
-    g_return_if_fail (SEAHORSE_IS_SERVER_SOURCE (ssrc));
-    g_return_if_fail (SEAHORSE_IS_OPERATION (op));
-    
-    seahorse_multi_operation_take (ssrc->priv->mop, op);
-}
-
 /* --------------------------------------------------------------------------
  * METHODS
  */
 
 /**
-* src: #SeahorseSource
-*
-* This function is a stub
-*
-* Returns NULL
-**/
-static SeahorseOperation*
-seahorse_server_source_load (SeahorseSource *src)
-{
-    g_assert (SEAHORSE_IS_SOURCE (src));
-
-    /* We should never be called directly */
-    return NULL;
-}
-
-/**
 * uri: the uri to parse
 * scheme: the scheme ("http") of this uri
 * host: the host part of the uri
diff --git a/pgp/seahorse-server-source.h b/pgp/seahorse-server-source.h
index 2361365..0e429f2 100644
--- a/pgp/seahorse-server-source.h
+++ b/pgp/seahorse-server-source.h
@@ -41,7 +41,6 @@
 #define __SEAHORSE_SERVER_SOURCE_H__
 
 #include "seahorse-source.h"
-#include "seahorse-operation.h"
 
 #define SEAHORSE_TYPE_SERVER_SOURCE            (seahorse_server_source_get_type ())
 #define SEAHORSE_SERVER_SOURCE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_SERVER_SOURCE, SeahorseServerSource))
@@ -63,11 +62,8 @@ struct _SeahorseServerSourceClass {
 	GObjectClass parent_class;
 };
 
-GType        seahorse_server_source_get_type         (void);
+GType                  seahorse_server_source_get_type         (void);
 
-void         seahorse_server_source_take_operation   (SeahorseServerSource *ssrc,
-                                                      SeahorseOperation *operation);
-
-SeahorseServerSource* seahorse_server_source_new     (const gchar *uri);
+SeahorseServerSource*  seahorse_server_source_new              (const gchar *uri);
 
 #endif /* __SEAHORSE_SERVER_SOURCE_H__ */
diff --git a/pgp/seahorse-signer.c b/pgp/seahorse-signer.c
index 8103925..eb7f352 100755
--- a/pgp/seahorse-signer.c
+++ b/pgp/seahorse-signer.c
@@ -25,7 +25,6 @@
 
 #include <glib/gi18n.h>
 
-#include "seahorse-operation.h"
 #include "seahorse-progress.h"
 #include "seahorse-widget.h"
 #include "seahorse-validity.h"
diff --git a/pkcs11/seahorse-pkcs11-certificate.c b/pkcs11/seahorse-pkcs11-certificate.c
index b59d411..3dcd802 100644
--- a/pkcs11/seahorse-pkcs11-certificate.c
+++ b/pkcs11/seahorse-pkcs11-certificate.c
@@ -107,7 +107,7 @@ seahorse_pkcs11_certificate_realize (SeahorseObject *obj)
 	if (!seahorse_object_get_label (obj))
 		g_object_set (self, "label", _("Certificate"), NULL);
 	
-	flags = seahorse_object_get_flags (obj);
+	flags = seahorse_object_get_flags (obj) | SEAHORSE_FLAG_DELETABLE;
 
 	/* TODO: Expiry, revoked, disabled etc... */
 	if (seahorse_pkcs11_certificate_get_trust (self) >= SEAHORSE_VALIDITY_MARGINAL)
diff --git a/pkcs11/seahorse-pkcs11-commands.c b/pkcs11/seahorse-pkcs11-commands.c
index 8c2200a..4d97351 100644
--- a/pkcs11/seahorse-pkcs11-commands.c
+++ b/pkcs11/seahorse-pkcs11-commands.c
@@ -26,7 +26,9 @@
 #include "seahorse-pkcs11.h"
 #include "seahorse-pkcs11-certificate.h"
 #include "seahorse-pkcs11-certificate-props.h"
+#include "seahorse-pkcs11-operations.h"
 
+#include "seahorse-progress.h"
 #include "seahorse-util.h"
 
 #include "common/seahorse-registry.h"
@@ -91,15 +93,32 @@ seahorse_pkcs11_commands_show_properties (SeahorseCommands *cmds, SeahorseObject
 	g_signal_connect (window, "response", G_CALLBACK (properties_response), NULL);
 }
 
-static SeahorseOperation*
+static void
+on_delete_completed (GObject *source,
+                     GAsyncResult *result,
+                     gpointer user_data)
+{
+	SeahorseCommands *self = SEAHORSE_COMMANDS (user_data);
+	GError *error = NULL;
+
+	if (!seahorse_pkcs11_delete_finish (result, &error))
+		seahorse_util_handle_error (&error, seahorse_view_get_window (seahorse_commands_get_view (self)),
+		                            _("Couldn't delete"));
+
+	g_object_unref (self);
+}
+
+static gboolean
 seahorse_pkcs11_commands_delete_objects (SeahorseCommands *cmds, GList *objects)
 {
+	GCancellable *cancellable;
 	gchar *prompt;
 	const gchar *display;
+	GtkWidget *parent;
 	gboolean ret;
 	guint num;
-	
-	g_return_val_if_fail (SEAHORSE_PKCS11_IS_COMMANDS (cmds), NULL);
+
+	g_return_val_if_fail (SEAHORSE_PKCS11_IS_COMMANDS (cmds), FALSE);
 
 	num = g_list_length (objects);
 	
@@ -112,14 +131,20 @@ seahorse_pkcs11_commands_delete_objects (SeahorseCommands *cmds, GList *objects)
 				"Are you sure you want to delete %d certificates?",
 				num), num);
 	}
-	
-	ret = seahorse_util_prompt_delete (prompt, GTK_WIDGET (seahorse_view_get_window (seahorse_commands_get_view (cmds))));
+
+	parent = GTK_WIDGET (seahorse_view_get_window (seahorse_commands_get_view (cmds)));
+	ret = seahorse_util_prompt_delete (prompt, parent);
 	g_free (prompt);
-	
-	if (ret)
-		return seahorse_source_delete_objects (objects);
-	else
-		return NULL;
+
+	if (ret) {
+		cancellable = g_cancellable_new ();
+		seahorse_pkcs11_delete_async (objects, cancellable,
+		                              on_delete_completed, g_object_ref (cmds));
+		seahorse_progress_show (cancellable, _("Deleting"), TRUE);
+		g_object_unref (cancellable);
+	}
+
+	return ret;
 }
 
 static GObject* 
diff --git a/pkcs11/seahorse-pkcs11-object.c b/pkcs11/seahorse-pkcs11-object.c
index 44a3af5..1ec36cb 100644
--- a/pkcs11/seahorse-pkcs11-object.c
+++ b/pkcs11/seahorse-pkcs11-object.c
@@ -153,7 +153,7 @@ seahorse_pkcs11_object_realize (SeahorseObject *obj)
 	
 	g_assert (SEAHORSE_PKCS11_IS_OBJECT (obj));
 
-	flags = 0;
+	flags = SEAHORSE_FLAG_DELETABLE;
 	if (gck_attributes_find_boolean (self->pv->pkcs11_attributes, CKA_EXTRACTABLE, &exportable) && exportable)
 		flags |= SEAHORSE_FLAG_EXPORTABLE;
 
@@ -175,12 +175,6 @@ seahorse_pkcs11_object_refresh (SeahorseObject *obj)
 	SEAHORSE_OBJECT_CLASS (seahorse_pkcs11_object_parent_class)->refresh (obj);
 }
 
-static SeahorseOperation*
-seahorse_pkcs11_object_delete (SeahorseObject *obj)
-{
-	return seahorse_pkcs11_deleter_new (SEAHORSE_PKCS11_OBJECT (obj));
-}
-
 static GObject* 
 seahorse_pkcs11_object_constructor (GType type, guint n_props, GObjectConstructParam *props) 
 {
@@ -288,8 +282,7 @@ seahorse_pkcs11_object_class_init (SeahorsePkcs11ObjectClass *klass)
 
 	seahorse_class->realize = seahorse_pkcs11_object_realize;
 	seahorse_class->refresh = seahorse_pkcs11_object_refresh;
-	seahorse_class->delete = seahorse_pkcs11_object_delete;
-	
+
 	g_object_class_install_property (gobject_class, PROP_PKCS11_OBJECT, 
 	         g_param_spec_object ("pkcs11-object", "pkcs11-object", "pkcs11-object", GCK_TYPE_OBJECT,
 	                              G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
diff --git a/pkcs11/seahorse-pkcs11-operations.c b/pkcs11/seahorse-pkcs11-operations.c
index a1a96ac..d9c8acb 100644
--- a/pkcs11/seahorse-pkcs11-operations.c
+++ b/pkcs11/seahorse-pkcs11-operations.c
@@ -25,6 +25,7 @@
 #include "seahorse-pkcs11-operations.h"
 #include "seahorse-pkcs11-source.h"
 
+#include "seahorse-progress.h"
 #include "common/seahorse-object-list.h"
 
 #include <gck/gck.h>
@@ -32,51 +33,23 @@
 
 #include <glib/gi18n.h>
 
-static void 
-seahorse_pkcs11_mark_complete (SeahorseOperation *self, GError *error) 
-{
-	SeahorseOperation *operation = SEAHORSE_OPERATION (self);
-	if (error == NULL) 
-		seahorse_operation_mark_done (operation, FALSE, NULL);
-	else if (error->code == CKR_FUNCTION_CANCELED)
-		seahorse_operation_mark_done (operation, TRUE, NULL);
-	else 	
-		seahorse_operation_mark_done (operation, FALSE, error);
-	g_clear_error (&error);
-}
-
-/* -----------------------------------------------------------------------------
- * REFRESHER OPERATION
- */
-
-#define SEAHORSE_TYPE_PKCS11_REFRESHER               (seahorse_pkcs11_refresher_get_type ())
-#define SEAHORSE_PKCS11_REFRESHER(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_PKCS11_REFRESHER, SeahorsePkcs11Refresher))
-#define SEAHORSE_PKCS11_REFRESHER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_PKCS11_REFRESHER, SeahorsePkcs11RefresherClass))
-#define SEAHORSE_IS_PKCS11_REFRESHER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_PKCS11_REFRESHER))
-#define SEAHORSE_IS_PKCS11_REFRESHER_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_PKCS11_REFRESHER))
-#define SEAHORSE_PKCS11_REFRESHER_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_PKCS11_REFRESHER, SeahorsePkcs11RefresherClass))
-
-typedef struct _SeahorsePkcs11Refresher SeahorsePkcs11Refresher;
-typedef struct _SeahorsePkcs11RefresherClass SeahorsePkcs11RefresherClass;
-    
-struct _SeahorsePkcs11Refresher {
-	SeahorseOperation parent;
-	GCancellable *cancellable;
+typedef struct {
 	SeahorsePkcs11Source *source;
-	GckSession *session;
+	GCancellable *cancellable;
 	GHashTable *checks;
-};
-
-struct _SeahorsePkcs11RefresherClass {
-	SeahorseOperationClass parent_class;
-};
-
-enum {
-	PROP_0,
-	PROP_SOURCE
-};
+	GckSession *session;
+} pkcs11_refresh_closure;
 
-G_DEFINE_TYPE (SeahorsePkcs11Refresher, seahorse_pkcs11_refresher, SEAHORSE_TYPE_OPERATION);
+static void
+pkcs11_refresh_free (gpointer data)
+{
+	pkcs11_refresh_closure *closure = data;
+	g_object_unref (closure->source);
+	g_clear_object (&closure->cancellable);
+	g_hash_table_destroy (closure->checks);
+	g_clear_object (&closure->session);
+	g_free (closure);
+}
 
 static guint
 ulong_hash (gconstpointer k)
@@ -98,345 +71,226 @@ remove_each_object (gpointer key, gpointer value, gpointer data)
 }
 
 static void 
-on_find_objects(GckSession *session, GAsyncResult *result, SeahorsePkcs11Refresher *self)
+on_refresh_find_objects (GckSession *session,
+                         GAsyncResult *result,
+                         gpointer user_data)
 {
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	pkcs11_refresh_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
 	GList *objects, *l;
-	GError *err = NULL;
+	GError *error = NULL;
 	gulong handle;
-	
-	g_assert (SEAHORSE_IS_PKCS11_REFRESHER (self));
-	
-	objects = gck_session_find_objects_finish (session, result, &err);
-	if (err != NULL) {
-		seahorse_pkcs11_mark_complete (SEAHORSE_OPERATION (self), err);
-		return;
-	}
 
-	/* Remove all objects that were found, from the check table */
-	for (l = objects; l; l = g_list_next (l)) {
-		seahorse_pkcs11_source_receive_object (self->source, l->data);
-		handle = gck_object_get_handle (l->data);
-		g_hash_table_remove (self->checks, &handle);
-	}
+	objects = gck_session_find_objects_finish (session, result, &error);
+	if (error != NULL) {
+		g_simple_async_result_take_error (res, error);
+	} else {
+
+		/* Remove all objects that were found, from the check table */
+		for (l = objects; l; l = g_list_next (l)) {
+			seahorse_pkcs11_source_receive_object (closure->source, l->data);
+			handle = gck_object_get_handle (l->data);
+			g_hash_table_remove (closure->checks, &handle);
+		}
 
-	/* Remove everything not found from the context */
-	g_hash_table_foreach_remove (self->checks, remove_each_object, NULL);
+		/* Remove everything not found from the context */
+		g_hash_table_foreach_remove (closure->checks, remove_each_object, NULL);
+	}
 
-	seahorse_pkcs11_mark_complete (SEAHORSE_OPERATION (self), NULL);
+	g_simple_async_result_complete (res);
+	g_object_unref (res);
 }
 
-static void 
-on_open_session(GckSlot *slot, GAsyncResult *result, SeahorsePkcs11Refresher *self)
+static void
+on_refresh_open_session (GObject *source,
+                         GAsyncResult *result,
+                         gpointer user_data)
 {
-	GError *err = NULL;
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	pkcs11_refresh_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
 	GckAttributes *attrs;
 
-	g_return_if_fail (SEAHORSE_IS_PKCS11_REFRESHER (self));
+	closure->session = gck_slot_open_session_finish (GCK_SLOT (source), result, &error);
+	if (!closure->session) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
 
-	self->session = gck_slot_open_session_finish (slot, result, &err);
-	if (!self->session) {
-		seahorse_pkcs11_mark_complete (SEAHORSE_OPERATION (self), err);
-		return;
-	}
-	
 	/* Step 2. Load all the objects that we want */
-	attrs = gck_attributes_new ();
-	gck_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
-	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE);
-	gck_session_find_objects_async (self->session, attrs, self->cancellable,
-	                                (GAsyncReadyCallback)on_find_objects, self);
-	gck_attributes_unref (attrs);
-}
+	} else {
+		attrs = gck_attributes_new ();
+		gck_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
+		gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE);
+		gck_session_find_objects_async (closure->session, attrs, closure->cancellable,
+		                                (GAsyncReadyCallback)on_refresh_find_objects,
+		                                g_object_ref (res));
+		gck_attributes_unref (attrs);
+	}
 
-static void
-seahorse_pkcs11_refresher_cancel (SeahorseOperation *operation) 
-{
-	SeahorsePkcs11Refresher *self = SEAHORSE_PKCS11_REFRESHER (operation);
-	g_return_if_fail (SEAHORSE_IS_PKCS11_REFRESHER (self));
-	g_cancellable_cancel (self->cancellable);
+	g_object_unref (res);
 }
 
-static GObject* 
-seahorse_pkcs11_refresher_constructor (GType type, guint n_props, GObjectConstructParam *props) 
+void
+seahorse_pkcs11_refresh_async (SeahorsePkcs11Source *source,
+                               GCancellable *cancellable,
+                               GAsyncReadyCallback callback,
+                               gpointer user_data)
 {
-	SeahorsePkcs11Refresher *self = SEAHORSE_PKCS11_REFRESHER (G_OBJECT_CLASS (seahorse_pkcs11_refresher_parent_class)->constructor(type, n_props, props));
+	GSimpleAsyncResult *res;
+	pkcs11_refresh_closure *closure;
 	GckSlot *slot;
 	GList *objects, *l;
 	gulong handle;
 
-	g_return_val_if_fail (self, NULL);	
-	g_return_val_if_fail (self->source, NULL);	
-
-	objects = seahorse_context_get_objects (NULL, SEAHORSE_SOURCE (self->source));
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_pkcs11_refresh_async);
+	closure = g_new0 (pkcs11_refresh_closure, 1);
+	closure->checks = g_hash_table_new_full (ulong_hash, ulong_equal,
+	                                         g_free, g_object_unref);
+	closure->source = g_object_ref (source);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	g_simple_async_result_set_op_res_gpointer (res, closure, pkcs11_refresh_free);
+
+	/* Make note of all the objects that were there */
+	objects = seahorse_context_get_objects (seahorse_context_instance (),
+	                                        SEAHORSE_SOURCE (source));
 	for (l = objects; l; l = g_list_next (l)) {
 		if (g_object_class_find_property (G_OBJECT_GET_CLASS (l->data), "pkcs11-handle")) {
 			g_object_get (l->data, "pkcs11-handle", &handle, NULL);
-			g_hash_table_insert (self->checks, g_memdup (&handle, sizeof (handle)), g_object_ref (l->data));
+			g_hash_table_insert (closure->checks,
+			                     g_memdup (&handle, sizeof (handle)),
+			                     g_object_ref (l->data));
 		}
-		
 	}
-
 	g_list_free (objects);
 
 	/* Step 1. Load the session */
-	slot = seahorse_pkcs11_source_get_slot (self->source);
-	gck_slot_open_session_async (slot, GCK_SESSION_READ_WRITE, self->cancellable,
-	                              (GAsyncReadyCallback)on_open_session, self);
-	seahorse_operation_mark_start (SEAHORSE_OPERATION (self));
-	
-	return G_OBJECT (self);
-}
+	slot = seahorse_pkcs11_source_get_slot (closure->source);
+	gck_slot_open_session_async (slot, GCK_SESSION_READ_WRITE, closure->cancellable,
+	                             on_refresh_open_session, g_object_ref (res));
 
-static void
-seahorse_pkcs11_refresher_init (SeahorsePkcs11Refresher *self)
-{
-	self->cancellable = g_cancellable_new ();
-	self->checks = g_hash_table_new_full (ulong_hash, ulong_equal, g_free, g_object_unref);
+	g_object_unref (res);
 }
 
-static void
-seahorse_pkcs11_refresher_finalize (GObject *obj)
+gboolean
+seahorse_pkcs11_refresh_finish (SeahorsePkcs11Source *source,
+                                GAsyncResult *result,
+                                GError **error)
 {
-	SeahorsePkcs11Refresher *self = SEAHORSE_PKCS11_REFRESHER (obj);
-	
-	if (self->cancellable)
-		g_object_unref (self->cancellable);
-	self->cancellable = NULL;
-	
-	if (self->source)
-		g_object_unref (self->source);
-	self->source = NULL;
-
-	if (self->session)
-		g_object_unref (self->session);
-	self->session = NULL;
-
-	g_hash_table_destroy (self->checks);
-
-	G_OBJECT_CLASS (seahorse_pkcs11_refresher_parent_class)->finalize (obj);
-}
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_pkcs11_refresh_async), FALSE);
 
-static void
-seahorse_pkcs11_refresher_set_property (GObject *obj, guint prop_id, const GValue *value, 
-                                      GParamSpec *pspec)
-{
-	SeahorsePkcs11Refresher *self = SEAHORSE_PKCS11_REFRESHER (obj);
-	
-	switch (prop_id) {
-	case PROP_SOURCE:
-		g_return_if_fail (!self->source);
-		self->source = g_value_get_object (value);
-		g_return_if_fail (self->source);
-		g_object_ref (self->source);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
-		break;
-	}
-}
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
 
-static void
-seahorse_pkcs11_refresher_get_property (GObject *obj, guint prop_id, GValue *value, 
-                                      GParamSpec *pspec)
-{
-	SeahorsePkcs11Refresher *self = SEAHORSE_PKCS11_REFRESHER (obj);
-	
-	switch (prop_id) {
-	case PROP_SOURCE:
-		g_value_set_object (value, self->source);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
-		break;
-	}
-}
+	return TRUE;
 
-static void
-seahorse_pkcs11_refresher_class_init (SeahorsePkcs11RefresherClass *klass)
-{
-	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-	SeahorseOperationClass *operation_class = SEAHORSE_OPERATION_CLASS (klass);
-	
-	seahorse_pkcs11_refresher_parent_class = g_type_class_peek_parent (klass);
-
-	gobject_class->constructor = seahorse_pkcs11_refresher_constructor;
-	gobject_class->finalize = seahorse_pkcs11_refresher_finalize;
-	gobject_class->set_property = seahorse_pkcs11_refresher_set_property;
-	gobject_class->get_property = seahorse_pkcs11_refresher_get_property;
-	
-	operation_class->cancel = seahorse_pkcs11_refresher_cancel;
-	
-	g_object_class_install_property (gobject_class, PROP_SOURCE,
-	           g_param_spec_object ("source", "Source", "Source", 
-	                                SEAHORSE_TYPE_SOURCE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-    
 }
 
-SeahorseOperation*
-seahorse_pkcs11_refresher_new (SeahorsePkcs11Source *source)
+typedef struct {
+	GQueue *objects;
+	GCancellable *cancellable;
+} pkcs11_delete_closure;
+
+static void
+pkcs11_delete_free (gpointer data)
 {
-	return g_object_new (SEAHORSE_TYPE_PKCS11_REFRESHER, "source", source, NULL);
+	pkcs11_delete_closure *closure = data;
+	g_queue_foreach (closure->objects, (GFunc)g_object_unref, NULL);
+	g_queue_free (closure->objects);
+	g_clear_object (&closure->cancellable);
+	g_free (closure);
 }
 
+static void pkcs11_delete_one_object (GSimpleAsyncResult *res);
 
-/* -----------------------------------------------------------------------------
- * DELETER OPERATION
- */
-
-#define SEAHORSE_TYPE_PKCS11_DELETER               (seahorse_pkcs11_deleter_get_type ())
-#define SEAHORSE_PKCS11_DELETER(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_PKCS11_DELETER, SeahorsePkcs11Deleter))
-#define SEAHORSE_PKCS11_DELETER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_PKCS11_DELETER, SeahorsePkcs11DeleterClass))
-#define SEAHORSE_IS_PKCS11_DELETER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_PKCS11_DELETER))
-#define SEAHORSE_IS_PKCS11_DELETER_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_PKCS11_DELETER))
-#define SEAHORSE_PKCS11_DELETER_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_PKCS11_DELETER, SeahorsePkcs11DeleterClass))
-
-typedef struct _SeahorsePkcs11Deleter SeahorsePkcs11Deleter;
-typedef struct _SeahorsePkcs11DeleterClass SeahorsePkcs11DeleterClass;
-    
-struct _SeahorsePkcs11Deleter {
-	SeahorseOperation parent;
-	SeahorsePkcs11Object *object;
-	GCancellable *cancellable;
-};
-
-struct _SeahorsePkcs11DeleterClass {
-	SeahorseOperationClass parent_class;
-};
-
-enum {
-	PROP_D0,
-	PROP_OBJECT
-};
+static void
+on_delete_object_completed (GObject *source,
+                            GAsyncResult *result,
+                            gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	pkcs11_delete_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	SeahorseObject *object;
 
-G_DEFINE_TYPE (SeahorsePkcs11Deleter, seahorse_pkcs11_deleter, SEAHORSE_TYPE_OPERATION);
+	object = g_queue_pop_head (closure->objects);
+	seahorse_progress_end (closure->cancellable, object);
 
-static void 
-on_deleted (GckObject *object, GAsyncResult *result, SeahorsePkcs11Deleter *self)
-{
-	GError *err = NULL;
-	
-	g_return_if_fail (SEAHORSE_IS_PKCS11_DELETER (self));
-	
-	if (!gck_object_destroy_finish (object, result, &err)) {
+	if (!gck_object_destroy_finish (GCK_OBJECT (source), result, &error)) {
 
 		/* Ignore objects that have gone away */
-		if (err->code != CKR_OBJECT_HANDLE_INVALID) { 
-			seahorse_pkcs11_mark_complete (SEAHORSE_OPERATION (self), err);
-			return;
+		if (g_error_matches (error, GCK_ERROR, CKR_OBJECT_HANDLE_INVALID)) {
+			g_clear_error (&error);
+		} else {
+			g_simple_async_result_take_error (res, error);
+			g_simple_async_result_complete (res);
 		}
-		
-		g_error_free (err);
+
 	}
-	
-	seahorse_context_remove_object (NULL, SEAHORSE_OBJECT (self->object));
-	seahorse_pkcs11_mark_complete (SEAHORSE_OPERATION (self), NULL);
-}
-			
-static void
-seahorse_pkcs11_deleter_cancel (SeahorseOperation *operation) 
-{
-	SeahorsePkcs11Deleter *self = SEAHORSE_PKCS11_DELETER (operation);
-	g_return_if_fail (SEAHORSE_IS_PKCS11_DELETER (self));
-	g_cancellable_cancel (self->cancellable);
-}
 
-static GObject* 
-seahorse_pkcs11_deleter_constructor (GType type, guint n_props, GObjectConstructParam *props) 
-{
-	SeahorsePkcs11Deleter *self = SEAHORSE_PKCS11_DELETER (G_OBJECT_CLASS (seahorse_pkcs11_deleter_parent_class)->constructor(type, n_props, props));
-	
-	g_return_val_if_fail (self, NULL);
-	g_return_val_if_fail (self->object, NULL);
-
-	/* Start the delete */
-	gck_object_destroy_async (seahorse_pkcs11_object_get_pkcs11_object (self->object),
-	                          self->cancellable, (GAsyncReadyCallback)on_deleted, self);
-	seahorse_operation_mark_start (SEAHORSE_OPERATION (self));
-	
-	return G_OBJECT (self);
-}
+	if (error == NULL) {
+		seahorse_context_remove_object (seahorse_context_instance (),
+		                                object);
+		pkcs11_delete_one_object (res);
+	}
 
-static void
-seahorse_pkcs11_deleter_init (SeahorsePkcs11Deleter *self)
-{
-	self->cancellable = g_cancellable_new ();
+	g_object_unref (object);
+	g_object_unref (res);
 }
 
 static void
-seahorse_pkcs11_deleter_finalize (GObject *obj)
+pkcs11_delete_one_object (GSimpleAsyncResult *res)
 {
-	SeahorsePkcs11Deleter *self = SEAHORSE_PKCS11_DELETER (obj);
-	
-	if (self->cancellable)
-		g_object_unref (self->cancellable);
-	self->cancellable = NULL;
-	
-	if (self->object)
-		g_object_unref (self->object);
-	self->object = NULL;
-
-	G_OBJECT_CLASS (seahorse_pkcs11_deleter_parent_class)->finalize (obj);
-}
+	pkcs11_delete_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseObject *object;
 
-static void
-seahorse_pkcs11_deleter_set_property (GObject *obj, guint prop_id, const GValue *value, 
-                                      GParamSpec *pspec)
-{
-	SeahorsePkcs11Deleter *self = SEAHORSE_PKCS11_DELETER (obj);
-	
-	switch (prop_id) {
-	case PROP_OBJECT:
-		g_return_if_fail (!self->object);
-		self->object = g_value_get_object (value);
-		g_return_if_fail (self->object);
-		g_object_ref (self->object);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
-		break;
+	if (g_queue_is_empty (closure->objects)) {
+		g_simple_async_result_complete_in_idle (res);
+		return;
 	}
+
+	object = g_queue_peek_head (closure->objects);
+	seahorse_progress_begin (closure->cancellable, object);
+
+	gck_object_destroy_async (seahorse_pkcs11_object_get_pkcs11_object (SEAHORSE_PKCS11_OBJECT (object)),
+	                          closure->cancellable, on_delete_object_completed, g_object_ref (res));
 }
 
-static void
-seahorse_pkcs11_deleter_get_property (GObject *obj, guint prop_id, GValue *value, 
-                                      GParamSpec *pspec)
+void
+seahorse_pkcs11_delete_async (GList *objects,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
 {
-	SeahorsePkcs11Deleter *self = SEAHORSE_PKCS11_DELETER (obj);
-	
-	switch (prop_id) {
-	case PROP_OBJECT:
-		g_value_set_object (value, self->object);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
-		break;
+	GSimpleAsyncResult *res;
+	pkcs11_delete_closure *closure;
+	GList *l;
+
+	res = g_simple_async_result_new (NULL, callback, user_data,
+	                                 seahorse_pkcs11_delete_async);
+	closure = g_new0 (pkcs11_delete_closure, 1);
+	closure->objects = g_queue_new ();
+	for (l = objects; l != NULL; l = g_list_next (l)) {
+		g_queue_push_tail (closure->objects, g_object_ref (l->data));
+		seahorse_progress_prep (cancellable, l->data, NULL);
 	}
-}
+	g_simple_async_result_set_op_res_gpointer (res, closure, pkcs11_delete_free);
 
-static void
-seahorse_pkcs11_deleter_class_init (SeahorsePkcs11DeleterClass *klass)
-{
-	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-	SeahorseOperationClass *operation_class = SEAHORSE_OPERATION_CLASS (klass);
-	
-	seahorse_pkcs11_deleter_parent_class = g_type_class_peek_parent (klass);
-
-	gobject_class->constructor = seahorse_pkcs11_deleter_constructor;
-	gobject_class->finalize = seahorse_pkcs11_deleter_finalize;
-	gobject_class->set_property = seahorse_pkcs11_deleter_set_property;
-	gobject_class->get_property = seahorse_pkcs11_deleter_get_property;
-	
-	operation_class->cancel = seahorse_pkcs11_deleter_cancel;
-	
-	g_object_class_install_property (gobject_class, PROP_OBJECT,
-	           g_param_spec_object ("object", "Object", "Deleting Object", 
-	                                SEAHORSE_PKCS11_TYPE_OBJECT, 
-	                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-    
+	pkcs11_delete_one_object (res);
+
+	g_object_unref (res);
 }
 
-SeahorseOperation*
-seahorse_pkcs11_deleter_new (SeahorsePkcs11Object *object)
+gboolean
+seahorse_pkcs11_delete_finish (GAsyncResult *result,
+                               GError **error)
 {
-	return g_object_new (SEAHORSE_TYPE_PKCS11_DELETER, "object", object, NULL);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+	                      seahorse_pkcs11_delete_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
 }
diff --git a/pkcs11/seahorse-pkcs11-operations.h b/pkcs11/seahorse-pkcs11-operations.h
index 80a0965..d105cd5 100644
--- a/pkcs11/seahorse-pkcs11-operations.h
+++ b/pkcs11/seahorse-pkcs11-operations.h
@@ -24,13 +24,24 @@
 
 #include <glib-object.h>
 
-#include "seahorse-operation.h"
-
 #include "seahorse-pkcs11-object.h"
 #include "seahorse-pkcs11-source.h"
 
-SeahorseOperation*         seahorse_pkcs11_refresher_new   (SeahorsePkcs11Source *source);
+void          seahorse_pkcs11_refresh_async    (SeahorsePkcs11Source *source,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+
+gboolean      seahorse_pkcs11_refresh_finish   (SeahorsePkcs11Source *source,
+                                                GAsyncResult *result,
+                                                GError **error);
+
+void          seahorse_pkcs11_delete_async     (GList *objects,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
 
-SeahorseOperation*         seahorse_pkcs11_deleter_new     (SeahorsePkcs11Object *object);
+gboolean      seahorse_pkcs11_delete_finish    (GAsyncResult *result,
+                                                GError **error);
 
 #endif /* __SEAHORSE_PKCS11_OPERATIONS_H__ */
diff --git a/pkcs11/seahorse-pkcs11-source.c b/pkcs11/seahorse-pkcs11-source.c
index 27e789b..81d55e4 100644
--- a/pkcs11/seahorse-pkcs11-source.c
+++ b/pkcs11/seahorse-pkcs11-source.c
@@ -27,7 +27,6 @@
 
 #include <glib/gi18n.h>
 
-#include "seahorse-operation.h"
 #include "seahorse-util.h"
 #include "seahorse-secure-memory.h"
 #include "seahorse-passphrase.h"
@@ -119,10 +118,23 @@ seahorse_pkcs11_source_set_property (GObject *object, guint prop_id, const GValu
 	};
 }
 
-static SeahorseOperation*
-seahorse_pkcs11_source_load (SeahorseSource *src)
+static void
+seahorse_pkcs11_source_load_async (SeahorseSource *source,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
+{
+	seahorse_pkcs11_refresh_async (SEAHORSE_PKCS11_SOURCE (source),
+	                               cancellable, callback, user_data);
+}
+
+static gboolean
+seahorse_pkcs11_source_load_finish (SeahorseSource *source,
+                                    GAsyncResult *result,
+                                    GError **error)
 {
-	return seahorse_pkcs11_refresher_new (SEAHORSE_PKCS11_SOURCE (src));
+	return seahorse_pkcs11_refresh_finish (SEAHORSE_PKCS11_SOURCE (source),
+	                                       result, error);
 }
 
 static void
@@ -180,7 +192,8 @@ seahorse_pkcs11_source_class_init (SeahorsePkcs11SourceClass *klass)
 static void 
 seahorse_source_iface (SeahorseSourceIface *iface)
 {
-	iface->load = seahorse_pkcs11_source_load;
+	iface->load_async = seahorse_pkcs11_source_load_async;
+	iface->load_finish = seahorse_pkcs11_source_load_finish;
 }
 
 /* -------------------------------------------------------------------------- 
diff --git a/src/seahorse-key-manager-store.c b/src/seahorse-key-manager-store.c
index 8a4d90c..908c5d6 100644
--- a/src/seahorse-key-manager-store.c
+++ b/src/seahorse-key-manager-store.c
@@ -500,78 +500,30 @@ drag_begin (GtkWidget *widget, GdkDragContext *context, SeahorseKeyManagerStore
 	return skstore->priv->drag_objects ? TRUE : FALSE;
 }
 
-static gboolean
-export_keys_to_output (GList *objects, GOutputStream *output, GError **error)
-{
-	SeahorseMultiOperation *mop = NULL;
-	SeahorseOperation *op;
-	SeahorseSource *sksrc;
-	SeahorseObject *sobj;
-	GList *next;
-	gboolean ret;
-	
-	objects = seahorse_util_objects_sort (objects);
-	seahorse_debug ("exporting %d objects", g_list_length (objects));
-	
-	while (objects) {
-		
-		/* Break off one set (same keysource) */
-		next = seahorse_util_objects_splice (objects);
-
-		g_assert (SEAHORSE_IS_OBJECT (objects->data));
-		sobj = SEAHORSE_OBJECT (objects->data);
+typedef struct {
+	SeahorseKeyManagerStore *skstore;
 
-		/* Export from this key source */        
-		sksrc = seahorse_object_get_source (sobj);
-		g_return_val_if_fail (sksrc != NULL, FALSE);
-
-		if (!mop) 
-			mop = seahorse_multi_operation_new ();
-
-		/* We pass our own data object, to which data is appended */
-		op = seahorse_source_export (sksrc, objects, output);
-		g_return_val_if_fail (op != NULL, FALSE);
-
-		seahorse_multi_operation_take (mop, op);
-		
-		g_list_free (objects);
-		objects = next;		
-	}
-	
-	/* Make sure it's complete before we can return data */
-	op = SEAHORSE_OPERATION (mop);
-	seahorse_operation_wait (op);
-
-	ret = TRUE;
-	if (!seahorse_operation_is_successful (op)) { 
-		seahorse_operation_copy_error (op, error);
-		ret = FALSE;
-	}
-	
-	g_object_unref (mop);
-	return ret;
-}
+	gint exports;
+	gboolean failures;
+} export_keys_to_output_closure;
 
 static gboolean
-export_to_text (SeahorseKeyManagerStore *skstore, GtkSelectionData *selection_data)
+export_to_text (SeahorseKeyManagerStore *skstore,
+                GtkSelectionData *selection_data)
 {
 	GOutputStream *output;
-	gboolean ret;
-	GList *keys;
-	
-	ret = FALSE;
-	
-	g_return_val_if_fail (skstore->priv->drag_objects, FALSE);
-	keys = g_list_copy (skstore->priv->drag_objects);
+	gboolean ret = FALSE;
 
+	g_return_val_if_fail (skstore->priv->drag_objects, FALSE);
 	seahorse_debug ("exporting to text");
 
 	output = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
 	g_return_val_if_fail (output, FALSE);
 
-	/* This modifies and frees keys */
-	ret = export_keys_to_output (keys, output, &skstore->priv->drag_error) &&
-	       g_output_stream_close (output, NULL, &skstore->priv->drag_error);
+	ret = seahorse_source_export_auto_wait (skstore->priv->drag_objects, output,
+	                                        &skstore->priv->drag_error) &&
+	      g_output_stream_close (output, NULL, &skstore->priv->drag_error);
+
 	if (ret) {
 		seahorse_debug ("setting selection text");
 		gtk_selection_data_set_text (selection_data, 
@@ -613,9 +565,9 @@ export_to_filename (SeahorseKeyManagerStore *skstore, const gchar *filename)
 	
 	if (output) {
 		/* This modifies and frees keys */
-		ret = export_keys_to_output (keys, output, &skstore->priv->drag_error) &&
+		ret = seahorse_source_export_auto_wait (keys, output, &skstore->priv->drag_error) &&
 		      g_output_stream_close (output, NULL, &skstore->priv->drag_error);
-		
+
 		g_object_unref (output);
 	}
 	
diff --git a/src/seahorse-key-manager.c b/src/seahorse-key-manager.c
index 197f897..ebed10d 100644
--- a/src/seahorse-key-manager.c
+++ b/src/seahorse-key-manager.c
@@ -28,7 +28,6 @@
 #include "seahorse-windows.h"
 #include "seahorse-keyserver-results.h"
 
-#include "seahorse-operation.h"
 #include "seahorse-progress.h"
 #include "seahorse-util.h"
 
@@ -401,35 +400,37 @@ on_filter_changed (GtkEntry* entry, SeahorseKeyManager* self)
 }
 
 static void 
-imported_keys (SeahorseOperation* op, SeahorseKeyManager* self) 
+on_import_complete (GObject *source,
+                    GAsyncResult *result,
+                    gpointer user_data)
 {
-	g_return_if_fail (SEAHORSE_IS_KEY_MANAGER (self));
-	g_return_if_fail (SEAHORSE_IS_OPERATION (op));
-	
-	if (!seahorse_operation_is_successful (op)) {
-		seahorse_operation_display_error (op, _("Couldn't import keys"), 
-		                                  GTK_WIDGET (seahorse_viewer_get_window (SEAHORSE_VIEWER (self))));
-		return;
+	SeahorseKeyManager* self = SEAHORSE_KEY_MANAGER (user_data);
+	GError *error = NULL;
+
+	if (!seahorse_source_import_finish (SEAHORSE_SOURCE (source), result, &error)) {
+		seahorse_util_handle_error (&error, seahorse_viewer_get_window (SEAHORSE_VIEWER (self)),
+		                            "%s", _("Couldn't import keys"));
+	} else {
+		seahorse_viewer_set_status (SEAHORSE_VIEWER (self), _("Imported keys"));
 	}
-	
-	seahorse_viewer_set_status (SEAHORSE_VIEWER (self), _("Imported keys"));
+
+	g_object_unref (self);
 }
 
 static void 
 import_files (SeahorseKeyManager* self, const gchar** uris) 
 {
 	GError *error = NULL;
-	SeahorseMultiOperation* mop;
 	GFileInputStream* input;
-	SeahorseOperation* op;
+	GCancellable *cancellable;
 	const gchar *uri;
 	GString *errmsg;
 	GFile* file;
-	
+
 	g_return_if_fail (SEAHORSE_IS_KEY_MANAGER (self));
-	mop = g_object_new (SEAHORSE_TYPE_MULTI_OPERATION, NULL);
 	errmsg = g_string_new ("");
-	
+	cancellable = g_cancellable_new ();
+
 	for (uri = *uris; uri; uris++, uri = *uris) {
 		GQuark ktype;
 		SeahorseSource* sksrc;
@@ -454,23 +455,20 @@ import_files (SeahorseKeyManager* self, const gchar** uris)
 			g_string_append_printf (errmsg, "%s: %s\n", uri, error->message);
 			g_clear_error (&error);
 			continue;
-		}			
-		
-		op = seahorse_source_import (sksrc, G_INPUT_STREAM (input));
-		seahorse_multi_operation_take (mop, op);
-	}
-	
-	if (seahorse_operation_is_running (SEAHORSE_OPERATION (mop))) {
-		seahorse_progress_show (SEAHORSE_OPERATION (mop), _("Importing keys"), TRUE);
-		seahorse_operation_watch (SEAHORSE_OPERATION (mop), (SeahorseDoneFunc)imported_keys, self, NULL, NULL);
+		}
+
+		seahorse_source_import_async (sksrc, G_INPUT_STREAM (input),
+		                              cancellable, on_import_complete,
+		                              g_object_ref (self));
 	}
-	
+
+	seahorse_progress_show (cancellable, _("Importing keys"), TRUE);
+	g_object_unref (cancellable);
+
 	if (errmsg->len > 0)
 		seahorse_util_show_error (GTK_WIDGET (seahorse_viewer_get_window (SEAHORSE_VIEWER (self))), 
 		                          _("Couldn't import keys"), errmsg->str);
 
-	
-	g_object_unref (mop);
 	g_string_free (errmsg, TRUE);
 }
 
@@ -521,8 +519,8 @@ import_text (SeahorseKeyManager* self, const char* text)
 	GQuark ktype;
 	SeahorseSource* sksrc;
 	GMemoryInputStream* input;
-	SeahorseOperation* op;
-	
+	GCancellable *cancellable;
+
 	g_return_if_fail (SEAHORSE_IS_KEY_MANAGER (self));
 	g_return_if_fail (text != NULL);
 	
@@ -540,13 +538,15 @@ import_text (SeahorseKeyManager* self, const char* text)
 
 	input = G_MEMORY_INPUT_STREAM (g_memory_input_stream_new_from_data (g_strndup (text, len),
 	                                                                    len, g_free));
-	op = seahorse_source_import (sksrc, G_INPUT_STREAM (input));
-	
-	seahorse_progress_show (op, _("Importing Keys"), TRUE);
-	seahorse_operation_watch (op, (SeahorseDoneFunc)imported_keys, self, NULL, NULL);
+
+	cancellable = g_cancellable_new ();
+	seahorse_source_import_async (sksrc, G_INPUT_STREAM (input), cancellable,
+	                              on_import_complete, g_object_ref (self));
+
+	seahorse_progress_show (cancellable, _("Importing Keys"), TRUE);
+	g_object_unref (cancellable);
 
 	g_object_unref (input);
-	g_object_unref (op);
 }
 
 static void 
@@ -714,13 +714,6 @@ on_manager_settings_changed (GSettings *settings, const gchar *key, gpointer use
 	gtk_toggle_action_set_active (action, g_settings_get_boolean (settings, key));
 }
 
-static void
-on_refreshing (SeahorseContext *sctx, SeahorseOperation *operation, SeahorseWidget *swidget)
-{
-	seahorse_progress_status_set_operation (swidget, operation);
-}
-
-
 static const GtkActionEntry GENERAL_ENTRIES[] = {
 	{ "remote-menu", NULL, N_("_Remote") }, 
 	{ "app-quit", GTK_STOCK_QUIT, NULL, "<control>Q", 
@@ -991,8 +984,6 @@ seahorse_key_manager_constructed (GObject *object)
 	
 	/* To show first time dialog */
 	g_timeout_add_seconds (1, (GSourceFunc)on_first_timer, self);
-	
-	g_signal_connect (seahorse_context_instance (), "refreshing", G_CALLBACK (on_refreshing), self);
 }
 
 static void
diff --git a/src/seahorse-keyserver-results.c b/src/seahorse-keyserver-results.c
index cd0b084..328b07f 100644
--- a/src/seahorse-keyserver-results.c
+++ b/src/seahorse-keyserver-results.c
@@ -25,7 +25,6 @@
 #include "seahorse-key-manager-store.h"
 #include "seahorse-windows.h"
 
-#include "seahorse-operation.h"
 #include "seahorse-progress.h"
 
 #include <glib/gi18n.h>
@@ -516,13 +515,25 @@ seahorse_keyserver_results_class_init (SeahorseKeyserverResultsClass *klass)
 	g_object_class_override_property (G_OBJECT_CLASS (klass), PROP_SELECTED, "selected");
 }
 
-/* -----------------------------------------------------------------------------
- * PUBLIC 
- */
+static void
+on_search_completed (GObject *source,
+                     GAsyncResult *result,
+                     gpointer user_data)
+{
+	SeahorseKeyserverResults *self = SEAHORSE_KEYSERVER_RESULTS (user_data);
+	GError *error = NULL;
+
+	seahorse_context_search_remote_finish (seahorse_context_instance (),
+	                                       result, &error);
+	if (error != NULL) {
+		seahorse_viewer_set_status (SEAHORSE_VIEWER (self), error->message);
+		g_error_free (error);
+	}
 
+	g_object_unref (self);
+}
 /**
  * seahorse_keyserver_results_show:
- * @op: The search operation
  * @parent: A GTK window as parent (or NULL)
  * @search_text: The test to search for
  *
@@ -530,26 +541,30 @@ seahorse_keyserver_results_class_init (SeahorseKeyserverResultsClass *klass)
  *
  */
 void 
-seahorse_keyserver_results_show (SeahorseOperation* op, GtkWindow* parent, const char* search_text) 
+seahorse_keyserver_results_show (const char* search_text)
 {
-	SeahorseKeyserverResults* res;
-	GtkWindow *window;
-	
-	g_return_if_fail (SEAHORSE_IS_OPERATION (op));
-	g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
+	SeahorseKeyserverResults* self;
+	GCancellable *cancellable;
+
 	g_return_if_fail (search_text != NULL);
-	
-	res = g_object_new (SEAHORSE_TYPE_KEYSERVER_RESULTS, "name", "keyserver-results", "search", search_text, NULL);
-	
+
+	self = g_object_new (SEAHORSE_TYPE_KEYSERVER_RESULTS,
+	                     "name", "keyserver-results",
+	                     "search", search_text,
+	                     NULL);
+
 	/* Destorys itself with destroy */
-	g_object_ref_sink (res);
-	
-	if (parent != NULL) {
-		window = GTK_WINDOW (seahorse_widget_get_toplevel (SEAHORSE_WIDGET (res)));
-		gtk_window_set_transient_for (window, parent);
-	}
+	g_object_ref_sink (self);
+
+	cancellable = g_cancellable_new ();
+	seahorse_context_search_remote_async (seahorse_context_instance (),
+	                                      search_text, cancellable,
+	                                      on_search_completed,
+	                                      g_object_ref (self));
+
+	seahorse_progress_attach (cancellable, SEAHORSE_WIDGET (self));
 
-	seahorse_progress_status_set_operation (SEAHORSE_WIDGET (res), op);
+	g_object_unref (cancellable);
 }
 
 /**
diff --git a/src/seahorse-keyserver-results.h b/src/seahorse-keyserver-results.h
index 422df66..d4f574d 100644
--- a/src/seahorse-keyserver-results.h
+++ b/src/seahorse-keyserver-results.h
@@ -26,9 +26,8 @@
 #include <glib-object.h>
 #include <gtk/gtk.h>
 
-#include <seahorse-viewer.h>
-#include <seahorse-operation.h>
-#include <seahorse-object.h>
+#include "seahorse-viewer.h"
+#include "seahorse-object.h"
 
 G_BEGIN_DECLS
 
@@ -55,8 +54,7 @@ struct _SeahorseKeyserverResultsClass {
 
 GType            seahorse_keyserver_results_get_type         (void);
 
-void             seahorse_keyserver_results_show             (SeahorseOperation* op, GtkWindow* parent, 
-                                                              const char* search_text);
+void             seahorse_keyserver_results_show             (const gchar *search_text);
 
 const gchar*     seahorse_keyserver_results_get_search       (SeahorseKeyserverResults* self);
 
diff --git a/src/seahorse-keyserver-results.xml b/src/seahorse-keyserver-results.xml
index 73561fa..6e02305 100644
--- a/src/seahorse-keyserver-results.xml
+++ b/src/seahorse-keyserver-results.xml
@@ -62,7 +62,7 @@
               <object class="GtkHBox" id="hbox1">
                 <property name="visible">True</property>
                 <child>
-                  <object class="GtkProgressBar" id="progress">
+                  <object class="GtkProgressBar" id="progress-bar">
                     <property name="visible">True</property>
                     <property name="pulse_step">0.10000000149</property>
                   </object>
diff --git a/src/seahorse-keyserver-search.c b/src/seahorse-keyserver-search.c
index 2d183ea..6fc5d2a 100644
--- a/src/seahorse-keyserver-search.c
+++ b/src/seahorse-keyserver-search.c
@@ -213,7 +213,7 @@ foreach_child_select_checks (GtkWidget *widget, gpointer user_data)
 
 	if (GTK_IS_CHECK_BUTTON (widget)) {
 		name = g_utf8_casefold (gtk_button_get_label (GTK_BUTTON (widget)), -1);
-		checked = names ? FALSE : TRUE;
+		checked = names != NULL && names[0] != NULL ? FALSE : TRUE;
 		for (i = 0; names && names[i] != NULL; i++) {
 			if (g_utf8_collate (names[i], name) == 0) {
 				checked = TRUE;
@@ -244,7 +244,7 @@ select_inital_keyservers (SeahorseWidget *swidget)
 	/* Close the expander if all servers are selected */
 	widget = seahorse_widget_get_widget (swidget, "search-where");
 	g_return_if_fail (widget != NULL);
-	gtk_expander_set_expanded (GTK_EXPANDER (widget), names != NULL);
+	gtk_expander_set_expanded (GTK_EXPANDER (widget), names != NULL && names[0] != NULL);
 
 	/* We do case insensitive matches */
 	for (i = 0; names[i] != NULL; i++) {
@@ -395,7 +395,6 @@ refresh_shared_keys (SeahorseServiceDiscovery *ssd, const gchar *name, SeahorseW
 G_MODULE_EXPORT void
 on_keyserver_search_ok_clicked (GtkButton *button, SeahorseWidget *swidget)
 {
-	SeahorseOperation *op;
 	KeyserverSelection *selection;
 	const gchar *search;
 	GtkWidget *widget;
@@ -412,16 +411,10 @@ on_keyserver_search_ok_clicked (GtkButton *button, SeahorseWidget *swidget)
 	selection = get_keyserver_selection (swidget);
 	g_return_if_fail (selection->uris != NULL);
 	g_settings_set_strv (seahorse_context_settings (NULL), "last-search-servers",
-	                     selection->all ? NULL : (const gchar * const*)selection->names->pdata);
-
-	op = seahorse_context_search_remote (SCTX_APP(), search);
-	if (op == NULL)
-		return;
+	                     selection->all ? NULL : (const gchar * const*)selection->uris->pdata);
 
 	/* Open the new result window */
-	seahorse_keyserver_results_show (op,
-	                                 GTK_WINDOW (seahorse_widget_get_widget (swidget, swidget->name)),
-	                                 search);
+	seahorse_keyserver_results_show (search);
 
 	free_keyserver_selection (selection);
 	seahorse_widget_destroy (swidget);
diff --git a/src/seahorse-keyserver-sync.c b/src/seahorse-keyserver-sync.c
index 8194c32..728da3a 100644
--- a/src/seahorse-keyserver-sync.c
+++ b/src/seahorse-keyserver-sync.c
@@ -29,43 +29,49 @@
 #include "seahorse-progress.h"
 #include "seahorse-preferences.h"
 #include "seahorse-servers.h"
-#include "seahorse-transfer-operation.h"
+#include "seahorse-transfer.h"
 #include "seahorse-util.h"
 #include "seahorse-widget.h"
 #include "seahorse-windows.h"
 
-static void 
-sync_import_complete (SeahorseOperation *op, SeahorseSource *sksrc)
+static void
+on_transfer_upload_complete (GObject *object,
+                             GAsyncResult *result,
+                             gpointer user_data)
 {
+	SeahorseSource *source = SEAHORSE_SOURCE (user_data);
 	GError *error = NULL;
 	gchar *publish_to;
 
-	if (!seahorse_operation_is_successful (op)) {
-		seahorse_operation_copy_error (op, &error);
+	if (!seahorse_context_transfer_objects_finish (SEAHORSE_CONTEXT (object),
+	                                               result, &error)) {
 		publish_to = g_settings_get_string (seahorse_context_settings (NULL),
 		                                    "server-publish-to");
-		seahorse_util_handle_error (error, _("Couldn't publish keys to server"),
-		                            publish_to);
+		seahorse_util_handle_error (&error, NULL,
+		                            _("Couldn't publish keys to server"), publish_to);
 		g_free (publish_to);
-		g_clear_error (&error);
 	}
+
+	g_object_unref (source);
 }
 
 static void
-sync_export_complete (SeahorseOperation *op, SeahorseSource *sksrc)
+on_transfer_download_complete (GObject *object,
+                               GAsyncResult *result,
+                               gpointer user_data)
 {
-    GError *err = NULL;
-    gchar *keyserver;
-
-    if (!seahorse_operation_is_successful (op)) {
-        g_object_get (sksrc, "key-server", &keyserver, NULL);
-
-        seahorse_operation_copy_error (op, &err);
-        seahorse_util_handle_error (err, _("Couldn't retrieve keys from server: %s"), 
-                                    keyserver);
-        g_clear_error (&err);
-        g_free (keyserver);
-    }    
+	SeahorseSource *source = SEAHORSE_SOURCE (user_data);
+	GError *error = NULL;
+	gchar *keyserver;
+
+	if (!seahorse_transfer_finish (result, &error)) {
+		g_object_get (source, "key-server", &keyserver, NULL);
+		seahorse_util_handle_error (&error, NULL,
+		                            _("Couldn't retrieve keys from server: %s"), keyserver);
+		g_free (keyserver);
+	}
+
+	g_object_unref (source);
 }
 
 G_MODULE_EXPORT void
@@ -169,73 +175,68 @@ seahorse_keyserver_sync_show (GList *keys, GtkWindow *parent)
 void
 seahorse_keyserver_sync (GList *keys)
 {
-    SeahorseSource *sksrc;
-    SeahorseSource *lsksrc;
-    SeahorseMultiOperation *mop;
-    SeahorseOperation *op;
-    gchar *keyserver;
-    gchar **keyservers;
-    GList *k;
-    GList *keyids = NULL;
-    guint i;
-
-    if (!keys)
-        return;
-    
-    g_assert (SEAHORSE_IS_OBJECT (keys->data));
-    
-    /* Build a keyid list */
-    for (k = keys; k; k = g_list_next (k)) 
-        keyids = g_list_prepend (keyids,
-                    GUINT_TO_POINTER (seahorse_object_get_id (SEAHORSE_OBJECT (k->data))));
-
-    mop = seahorse_multi_operation_new ();
-
-    /* And now synchronizing keys from the servers */
-    keyservers = seahorse_servers_get_uris ();
-    for (i = 0; keyservers[i] != NULL; i++) {
-        sksrc = seahorse_context_remote_source (SCTX_APP (), keyservers[i]);
-
-        /* This can happen if the URI scheme is not supported */
-        if (sksrc == NULL)
-            continue;
-        
-        lsksrc = seahorse_context_find_source (SCTX_APP (), 
-                        seahorse_source_get_tag (sksrc), SEAHORSE_LOCATION_LOCAL);
-        
-        if (lsksrc) {
-            op = seahorse_transfer_operation_new (_("Synchronizing keys"), sksrc, lsksrc, keyids);
-            g_return_if_fail (op != NULL);
-
-            seahorse_multi_operation_take (mop, op);
-            seahorse_operation_watch (op, (SeahorseDoneFunc) sync_export_complete, sksrc, NULL, NULL);
-        }
-    }
-
-    g_strfreev (keyservers);
-
-    /* Publishing keys online */
-    keyserver = g_settings_get_string (seahorse_context_settings (NULL),
-                                       "server-publish-to");
-    if (keyserver && keyserver[0]) {
-        sksrc = seahorse_context_remote_source (SCTX_APP (), keyserver);
-
-        /* This can happen if the URI scheme is not supported */
-        if (sksrc != NULL) {
-
-            op = seahorse_context_transfer_objects (SCTX_APP (), keys, sksrc);
-            g_return_if_fail (sksrc != NULL);
-
-            seahorse_multi_operation_take (mop, op);
-            seahorse_operation_watch (op, (SeahorseDoneFunc) sync_import_complete, sksrc, NULL, NULL);
-
-        }
-    }
-
-    g_list_free (keyids);
-    g_free (keyserver);
-    
-    /* Show the progress window if necessary */
-    seahorse_progress_show (SEAHORSE_OPERATION (mop), _("Synchronizing keys..."), FALSE);
-    g_object_unref (mop);
+	SeahorseSource *source;
+	SeahorseSource *local_source;
+	gchar *keyserver;
+	GList *k, *keyids = NULL;
+	GCancellable *cancellable;
+	gchar **keyservers;
+	guint i;
+
+	if (!keys)
+		return;
+
+	/* Build a keyid list */
+	for (k = keys; k != NULL; k = g_list_next (k))
+		keyids = g_list_prepend (keyids,
+		                         GUINT_TO_POINTER (seahorse_object_get_id (k->data)));
+
+	cancellable = g_cancellable_new ();
+
+	/* And now synchronizing keys from the servers */
+	keyservers = seahorse_servers_get_uris ();
+	for (i = 0; keyservers[i] != NULL; i++) {
+		source = seahorse_context_remote_source (seahorse_context_instance (),
+		                                         keyservers[i]);
+
+		/* This can happen if the URI scheme is not supported */
+		if (source == NULL)
+			continue;
+
+		local_source = seahorse_context_find_source (seahorse_context_instance (),
+		                                             seahorse_source_get_tag (source),
+		                                             SEAHORSE_LOCATION_LOCAL);
+
+		if (local_source) {
+			seahorse_transfer_async (source, local_source, keyids,
+			                         cancellable, on_transfer_download_complete,
+			                         g_object_ref (source));
+		}
+	}
+
+	g_strfreev (keyservers);
+
+	/* Publishing keys online */
+	keyserver = g_settings_get_string (seahorse_context_settings (NULL),
+	                                   "server-publish-to");
+	if (keyserver && keyserver[0]) {
+		source = seahorse_context_remote_source (seahorse_context_instance (),
+		                                         keyserver);
+
+		/* This can happen if the URI scheme is not supported */
+		if (source != NULL) {
+
+			seahorse_context_transfer_objects_async (seahorse_context_instance (),
+			                                         keys, source, cancellable,
+			                                         on_transfer_upload_complete,
+			                                         g_object_ref (source));
+		}
+	}
+
+	g_free (keyserver);
+
+	g_list_free (keyids);
+
+	seahorse_progress_show (cancellable, _("Synchronizing keys..."), FALSE);
+	g_object_unref (cancellable);
 }
diff --git a/src/seahorse-viewer.c b/src/seahorse-viewer.c
index 9f4a35d..1379835 100644
--- a/src/seahorse-viewer.c
+++ b/src/seahorse-viewer.c
@@ -248,14 +248,18 @@ has_matching_objects (SeahorseObjectPredicate *pred, GList *objects)
 }
 
 static void 
-on_export_done (SeahorseOperation* op, SeahorseViewer* self) 
+on_file_export_completed (GObject *source,
+                          GAsyncResult *result,
+                          gpointer user_data)
 {
-	g_return_if_fail (SEAHORSE_IS_VIEWER (self));
-	g_return_if_fail (SEAHORSE_IS_OPERATION (op));
-	
-	if (!seahorse_operation_is_successful (op))
-		seahorse_operation_display_error (op, _ ("Couldn't export keys"), 
-		                                  GTK_WIDGET (seahorse_view_get_window (SEAHORSE_VIEW (self))));
+	SeahorseViewer* self = SEAHORSE_VIEWER (user_data);
+	GError *error = NULL;
+
+	if (!seahorse_source_export_auto_finish (result, &error))
+		seahorse_util_handle_error (&error, seahorse_view_get_window (SEAHORSE_VIEW (self)),
+		                            _("Couldn't export keys"));
+
+	g_object_unref (self);
 }
 
 static void 
@@ -282,21 +286,21 @@ on_key_export_file (GtkAction* action, SeahorseViewer* self)
 	if (uri != NULL) {
 		GFile* file;
 		GOutputStream* output;
-		SeahorseOperation* op;
-		
+		GCancellable *cancellable;
+
 		file = g_file_new_for_uri (uri);
 		output = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, 0, NULL, &error));
 		if (output == NULL) {
 		    unesc_uri = g_uri_unescape_string (seahorse_util_uri_get_last (uri), NULL);
-			seahorse_util_handle_error (error, _ ("Couldn't export key to \"%s\""), 
+			seahorse_util_handle_error (&error, NULL, _ ("Couldn't export key to \"%s\""),
 			                            unesc_uri, NULL);
-			g_clear_error (&error);
 			g_free (unesc_uri);
 		} else {
-			op = seahorse_source_export_objects (objects, output);
-			seahorse_progress_show (op, _("Exporting keys"), TRUE);
-			seahorse_operation_watch (op, (SeahorseDoneFunc)on_export_done, self, NULL, NULL);
-			g_object_unref (op);
+			cancellable = g_cancellable_new ();
+			seahorse_source_export_auto_async (objects, output, cancellable,
+			                                   on_file_export_completed, g_object_ref (self));
+			seahorse_progress_show (cancellable, _("Exporting keys"), TRUE);
+			g_object_unref (cancellable);
 		}
 		
 
@@ -304,41 +308,41 @@ on_key_export_file (GtkAction* action, SeahorseViewer* self)
 		g_object_unref (output);
 		g_free (uri);
 	}
+
+	g_list_free (objects);
 }
 
 static void 
-on_copy_complete (SeahorseOperation* op, SeahorseViewer* self) 
+on_copy_export_complete (GObject *source,
+                         GAsyncResult *result,
+                         gpointer user_data)
 {
-	GMemoryOutputStream* output;
+	SeahorseViewer *self = SEAHORSE_VIEWER (user_data);
+	GOutputStream* output;
+	GError *error = NULL;
 	const gchar* text;
 	guint size;
 	GdkAtom atom;
 	GtkClipboard* board;
-	
-	g_return_if_fail (SEAHORSE_IS_VIEWER (self));
-	g_return_if_fail (SEAHORSE_IS_OPERATION (op));
-	
-	if (!seahorse_operation_is_successful (op)) {
-		seahorse_operation_display_error (op, _ ("Couldn't retrieve data from key server"), 
-		                                  GTK_WIDGET (seahorse_view_get_window (SEAHORSE_VIEW (self))));
+
+	output = seahorse_source_export_auto_finish (result, &error);
+	if (error != NULL) {
+		seahorse_util_handle_error (&error, seahorse_view_get_window (SEAHORSE_VIEW (self)),
+		                            _("Couldn't retrieve data from key server"));
 		return;
 	}
-	
-	output = G_MEMORY_OUTPUT_STREAM (seahorse_operation_get_result (op));
-	g_return_if_fail (G_IS_MEMORY_OUTPUT_STREAM (output));
-	
-	text = g_memory_output_stream_get_data (output);
-	g_return_if_fail (text != NULL);
 
-	size = g_memory_output_stream_get_data_size (output);
-	g_return_if_fail (size >= 0);
-	
-	atom = gdk_atom_intern ("CLIPBOARD", FALSE);
+	text = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (output));
+	size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (output));
 
+	atom = gdk_atom_intern ("CLIPBOARD", FALSE);
 	board = gtk_clipboard_get (atom);
 	gtk_clipboard_set_text (board, text, (gint)size);
+
 	/* Translators: "Copied" is a verb (used as a status indicator), not an adjective for the word "keys" */
 	seahorse_viewer_set_status (self, _ ("Copied keys"));
+
+	g_object_unref (self);
 }
 
 static void 
@@ -346,45 +350,36 @@ on_key_export_clipboard (GtkAction* action, SeahorseViewer* self)
 {
 	GList* objects;
 	GOutputStream* output;
-	SeahorseOperation* op;
-	
+	GCancellable *cancellable;
+
 	g_return_if_fail (SEAHORSE_IS_VIEWER (self));
 	g_return_if_fail (GTK_IS_ACTION (action));
-	
+
 	objects = seahorse_viewer_get_selected_objects (self);
 	objects = objects_prune_non_exportable (objects);
 	if (objects == NULL)
 		return;
 
 	output = G_OUTPUT_STREAM (g_memory_output_stream_new (NULL, 0, g_realloc, g_free));
-	op = seahorse_source_export_objects (objects, output);
-	seahorse_progress_show (op, _ ("Retrieving keys"), TRUE);
-	seahorse_operation_watch (op, (SeahorseDoneFunc)on_copy_complete, self, NULL, NULL);
-	
+
+	cancellable = g_cancellable_new ();
+	seahorse_source_export_auto_async (objects, output, cancellable,
+	                                   on_copy_export_complete, g_object_ref (self));
+	seahorse_progress_show (cancellable, _ ("Retrieving keys"), TRUE);
+	g_object_unref (cancellable);
+
 	g_list_free (objects);
 	g_object_unref (output);
-	g_object_unref (op);
-}
-
-static void 
-on_delete_complete (SeahorseOperation* op, SeahorseViewer* self) 
-{
-	g_return_if_fail (SEAHORSE_IS_VIEWER (self));
-	g_return_if_fail (SEAHORSE_IS_OPERATION (op));
-	
-	if (!seahorse_operation_is_successful (op))
-		seahorse_operation_display_error (op, _ ("Couldn't delete."), 
-		                                  GTK_WIDGET (seahorse_view_get_window (SEAHORSE_VIEW (self))));
 }
 
 static gboolean
 delete_objects_for_selected (SeahorseViewer *self, SeahorseCommands *commands, 
                              SeahorseObjectPredicate *pred, gpointer user_data)
 {
-	SeahorseOperation* op;
 	GList **all_objects;
 	GList *objects;
-	
+	gboolean ret;
+
 	all_objects = (GList**)user_data;
 	
 	/* Stop the enumeration if nothing still selected */
@@ -399,19 +394,11 @@ delete_objects_for_selected (SeahorseViewer *self, SeahorseCommands *commands,
 	
 	/* Indicate to our users what is being operated on */
 	seahorse_viewer_set_selected_objects (self, objects);
-	
-	op = seahorse_commands_delete_objects (commands, objects);
+
+	ret = seahorse_commands_delete_objects (commands, objects);
 	g_list_free (objects);
-	
-	/* Did the user cancel? */
-	if (op == NULL)
-		return FALSE;
 
-	seahorse_progress_show (op, _ ("Deleting..."), TRUE);
-	seahorse_operation_watch (op, (SeahorseDoneFunc)on_delete_complete, self, NULL, NULL);
-	g_object_unref (op);
-	
-	return TRUE;
+	return ret;
 }
 
 static void
@@ -450,25 +437,28 @@ on_key_delete (GtkAction* action, SeahorseViewer* self)
 }
 
 static void 
-imported_keys (SeahorseOperation* op, SeahorseViewer* self) 
+on_import_complete (GObject *source,
+                    GAsyncResult *result,
+                    gpointer user_data)
 {
-	g_return_if_fail (SEAHORSE_IS_VIEWER (self));
-	g_return_if_fail (SEAHORSE_IS_OPERATION (op));
-	
-	if (!seahorse_operation_is_successful (op)) {
-		seahorse_operation_display_error (op, _ ("Couldn't import keys"), 
-		                                  GTK_WIDGET (seahorse_viewer_get_window (self)));
-		return;
-	}
-	
-	seahorse_viewer_set_status (self, _ ("Imported keys"));
+	SeahorseViewer *self = SEAHORSE_VIEWER (user_data);
+	GError *error = NULL;
+
+	if (!seahorse_context_transfer_objects_finish (SEAHORSE_CONTEXT (source),
+	                                               result, &error))
+		seahorse_util_handle_error (&error, seahorse_viewer_get_window (self),
+		                            _("Couldn't import keys"));
+	else
+		seahorse_viewer_set_status (self, _ ("Imported keys"));
+
+	g_object_unref (self);
 }
 
 static void 
 on_key_import_keyring (GtkAction* action, SeahorseViewer* self) 
 {
+	GCancellable *cancellable;
 	GList* objects;
-	SeahorseOperation* op;
 
 	g_return_if_fail (SEAHORSE_IS_VIEWER (self));
 	g_return_if_fail (GTK_IS_ACTION (action));
@@ -480,11 +470,13 @@ on_key_import_keyring (GtkAction* action, SeahorseViewer* self)
 	if (objects == NULL) 
 		return;
 
-	op = seahorse_context_transfer_objects (seahorse_context_instance (), objects, NULL);
-	seahorse_progress_show (op, _ ("Importing keys from key servers"), TRUE);
-	seahorse_operation_watch (op, (SeahorseDoneFunc)imported_keys, self, NULL, NULL);
-	
-	g_object_unref (op);
+	cancellable = g_cancellable_new ();
+	seahorse_context_transfer_objects_async (seahorse_context_instance (),
+	                                         objects, NULL, cancellable,
+	                                         on_import_complete, g_object_ref (self));
+	seahorse_progress_show (cancellable, _ ("Importing keys from key servers"), TRUE);
+	g_object_unref (cancellable);
+
 	g_list_free (objects);
 }
 
diff --git a/ssh/seahorse-ssh-commands.c b/ssh/seahorse-ssh-commands.c
index f0beed1..ade7439 100644
--- a/ssh/seahorse-ssh-commands.c
+++ b/ssh/seahorse-ssh-commands.c
@@ -26,6 +26,7 @@
 #include "seahorse-ssh.h"
 #include "seahorse-ssh-commands.h"
 #include "seahorse-ssh-dialogs.h"
+#include "seahorse-ssh-operation.h"
 
 #include "common/seahorse-registry.h"
 
@@ -101,28 +102,40 @@ seahorse_ssh_commands_show_properties (SeahorseCommands* base, SeahorseObject* o
 	seahorse_ssh_key_properties_show (SEAHORSE_SSH_KEY (obj), seahorse_commands_get_window (base));
 }
 
-static SeahorseOperation*
+static gboolean
 seahorse_ssh_commands_delete_objects (SeahorseCommands* base, GList* objects) 
 {
-	SeahorseOperation* op = NULL;
 	guint num;
 	gchar* prompt;
+	GList *l;
+	GtkWidget *parent;
+	GError *error = NULL;
 
 	num = g_list_length (objects);
 	if (num == 0) {
-		return NULL;
+		return TRUE;
 	} else if (num == 1) {
 		prompt = g_strdup_printf (_("Are you sure you want to delete the secure shell key '%s'?"), 
 		                          seahorse_object_get_label (objects->data));
 	} else {
 		prompt = g_strdup_printf (_("Are you sure you want to delete %d secure shell keys?"), num);
 	}
-	
-	if (seahorse_util_prompt_delete (prompt, NULL))
-		op = seahorse_source_delete_objects (objects);
-	
+
+	parent = GTK_WIDGET (seahorse_view_get_window (seahorse_commands_get_view (base)));
+	if (!seahorse_util_prompt_delete (prompt, NULL)) {
+		g_free (prompt);
+		return FALSE;
+	}
+
 	g_free (prompt);
-	return op;
+	for (l = objects; l != NULL; l = g_list_next (l)) {
+		if (!seahorse_ssh_op_delete_sync (l->data, &error)) {
+			seahorse_util_handle_error (&error, parent, _("Couldn't delete key"));
+			return FALSE;
+		}
+	}
+
+	return TRUE;
 }
 
 static GObject* 
diff --git a/ssh/seahorse-ssh-commands.h b/ssh/seahorse-ssh-commands.h
index a95d532..0689355 100644
--- a/ssh/seahorse-ssh-commands.h
+++ b/ssh/seahorse-ssh-commands.h
@@ -27,8 +27,6 @@
 
 #include "seahorse-commands.h"
 #include "seahorse-object.h"
-#include <seahorse-operation.h>
-
 
 #define SEAHORSE_TYPE_SSH_COMMANDS                 (seahorse_ssh_commands_get_type ())
 #define SEAHORSE_SSH_COMMANDS(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_SSH_COMMANDS, SeahorseSshCommands))
diff --git a/ssh/seahorse-ssh-generate.c b/ssh/seahorse-ssh-generate.c
index a8478bd..3f93c9b 100644
--- a/ssh/seahorse-ssh-generate.c
+++ b/ssh/seahorse-ssh-generate.c
@@ -82,41 +82,6 @@ seahorse_ssh_generate_register (void)
 #define DEFAULT_RSA_SIZE 2048
 
 static void
-completion_handler (SeahorseOperation *op, gpointer data)
-{
-    GError *error = NULL;
-    if (!seahorse_operation_is_successful (op)) {
-        seahorse_operation_copy_error (op, &error);
-        seahorse_util_handle_error (error, _("Couldn't generate Secure Shell key"));
-        g_clear_error (&error);
-    }
-}
-
-static void
-upload_handler (SeahorseOperation *op, SeahorseWidget *swidget)
-{
-    SeahorseSSHKey *skey;
-    GList *keys;
-    
-    if (!seahorse_operation_is_successful (op) ||
-        seahorse_operation_is_cancelled (op)) {
-		seahorse_widget_destroy (swidget);
-        return;
-	}
-    
-    skey = SEAHORSE_SSH_KEY (seahorse_operation_get_result (op));
-	if (!SEAHORSE_IS_SSH_KEY (skey)) {
-		seahorse_widget_destroy (swidget);
-		return;
-	}
-	
-    keys = g_list_append (NULL, skey);
-    seahorse_ssh_upload_prompt (keys, GTK_WINDOW (seahorse_widget_get_widget (swidget, swidget->name)));
-    g_list_free (keys);
-	seahorse_widget_destroy (swidget);
-}
-
-static void
 on_change (GtkComboBox *combo, SeahorseWidget *swidget)
 {
     const gchar *t;    
@@ -136,10 +101,52 @@ on_change (GtkComboBox *combo, SeahorseWidget *swidget)
 }
 
 static void
+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);
+}
+
+static void
+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;
+
+	object = 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"));
+
+	} else {
+		keys = g_list_append (NULL, object);
+		seahorse_ssh_upload_prompt (keys, GTK_WINDOW (seahorse_widget_get_widget (swidget, swidget->name)));
+		g_list_free (keys);
+	}
+
+	g_object_unref (swidget);
+}
+
+static void
 on_response (GtkDialog *dialog, guint response, SeahorseWidget *swidget)
 {
     SeahorseSSHSource *src;
-    SeahorseOperation *op;
+    GCancellable *cancellable;
     GtkWidget *widget;
     const gchar *email;
     const gchar *t;
@@ -186,24 +193,14 @@ on_response (GtkDialog *dialog, guint response, SeahorseWidget *swidget)
     
     src = SEAHORSE_SSH_SOURCE (g_object_get_data (G_OBJECT (swidget), "source"));
     g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (src));
-    
+
     /* We start creation */
-    op = seahorse_ssh_operation_generate (src, email, type, bits);
-    g_return_if_fail (op != NULL);
-    
-    /* Watch for errors so we can display */
-    seahorse_operation_watch (op, (SeahorseDoneFunc)completion_handler, NULL, NULL, NULL);
-    
-    /* When completed upload */
-    if (upload) {
-        seahorse_operation_watch (op, (SeahorseDoneFunc)upload_handler, swidget, NULL, NULL);
-		seahorse_widget_set_visible (swidget, swidget->name, FALSE);
-	}
-	else
-		seahorse_widget_destroy (swidget);
-    
-    seahorse_progress_show (op, _("Creating Secure Shell Key"), TRUE);
-    g_object_unref (op);
+    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));
+    seahorse_progress_show (cancellable, _("Creating Secure Shell Key"), FALSE);
+    g_object_unref (cancellable);
 }
 
 void
@@ -234,5 +231,5 @@ seahorse_ssh_generate_show (SeahorseSSHSource *src, GtkWindow *parent)
     /* on_change() gets called, bits entry is setup */
     widget = seahorse_widget_get_widget (swidget, "algorithm-choice");
     g_return_if_fail (widget != NULL);
-    gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+    /* gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); */
 }
diff --git a/ssh/seahorse-ssh-generate.xml b/ssh/seahorse-ssh-generate.xml
index 5022e1e..1f90b28 100644
--- a/ssh/seahorse-ssh-generate.xml
+++ b/ssh/seahorse-ssh-generate.xml
@@ -252,7 +252,7 @@
                                 <property name="yalign">0</property>
                                 <property name="xscale">0</property>
                                 <child>
-                                  <object class="GtkComboBox" id="algorithm-choice">
+                                  <object class="GtkComboBoxText" id="algorithm-choice">
                                     <property name="visible">True</property>
                                     <property name="model">model1</property>
                                     <child>
diff --git a/ssh/seahorse-ssh-key-properties.c b/ssh/seahorse-ssh-key-properties.c
index 52a8b4f..62cb02a 100644
--- a/ssh/seahorse-ssh-key-properties.c
+++ b/ssh/seahorse-ssh-key-properties.c
@@ -35,45 +35,64 @@
 
 #define NOTEBOOK "notebook"
 
+typedef struct {
+	SeahorseWidget *swidget;
+	GtkEntry *entry;
+	gchar *original;
+} ssh_rename_closure;
+
+static void
+ssh_rename_free (gpointer data)
+{
+	ssh_rename_closure *closure = data;
+	g_object_unref (closure->swidget);
+	g_free (closure->original);
+	g_free (closure);
+}
+
+static void
+on_rename_complete (GObject *source,
+                    GAsyncResult *result,
+                    gpointer user_data)
+{
+	ssh_rename_closure *closure = user_data;
+	GError *error = NULL;
+
+	if (!seahorse_ssh_op_rename_finish (SEAHORSE_SSH_SOURCE (source), result, &error)) {
+		seahorse_util_handle_error (&error, closure->swidget, _("Couldn't rename key."));
+		gtk_entry_set_text (closure->entry, closure->original);
+	}
+
+	gtk_widget_set_sensitive (GTK_WIDGET (closure->entry), TRUE);
+	ssh_rename_free (closure);
+}
+
 G_MODULE_EXPORT void
-on_ssh_comment_activate (GtkWidget *entry, SeahorseWidget *swidget)
+on_ssh_comment_activate (GtkWidget *entry,
+                         SeahorseWidget *swidget)
 {
-    SeahorseObject *object;
-    SeahorseSSHKey *skey;
-    SeahorseSource *sksrc;
-    SeahorseOperation *op;
-    const gchar *text;
-    gchar *comment;
-    GError *err = NULL;
-    
-    object = SEAHORSE_OBJECT_WIDGET (swidget)->object;
-    skey = SEAHORSE_SSH_KEY (object);
-    sksrc = seahorse_object_get_source (object);
-    g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (sksrc));
-    
-    text = gtk_entry_get_text (GTK_ENTRY (entry));
-    
-    /* Make sure not the same */
-    if (skey->keydata->comment && g_utf8_collate (text, skey->keydata->comment) == 0)
-        return;
+	SeahorseSSHKey *skey;
+	SeahorseSSHSource *source;
+	const gchar *text;
+	ssh_rename_closure *closure;
 
-    gtk_widget_set_sensitive (entry, FALSE);
-    
-    comment = g_strdup (text);
-    op = seahorse_ssh_operation_rename (SEAHORSE_SSH_SOURCE (sksrc), skey, comment);
-    g_free (comment);
-    
-    /* This is usually a quick operation */
-    seahorse_operation_wait (op);
-    
-    if (!seahorse_operation_is_successful (op)) {
-        seahorse_operation_copy_error (op, &err);
-        seahorse_util_handle_error (err, _("Couldn't rename key."));
-        g_clear_error (&err);
-        gtk_entry_set_text (GTK_ENTRY (entry), skey->keydata->comment ? skey->keydata->comment : "");
-    }
-    
-    gtk_widget_set_sensitive (entry, TRUE);
+	skey = SEAHORSE_SSH_KEY (SEAHORSE_OBJECT_WIDGET (swidget)->object);
+	source = SEAHORSE_SSH_SOURCE (seahorse_object_get_source (SEAHORSE_OBJECT (skey)));
+
+	text = gtk_entry_get_text (GTK_ENTRY (entry));
+
+	/* Make sure not the same */
+	if (skey->keydata->comment && g_utf8_collate (text, skey->keydata->comment) == 0)
+		return;
+
+	gtk_widget_set_sensitive (entry, FALSE);
+
+	closure = g_new0 (ssh_rename_closure, 1);
+	closure->swidget = g_object_ref (swidget);
+	closure->entry = GTK_ENTRY (entry);
+	closure->original = g_strdup (skey->keydata->comment ? skey->keydata->comment : "");
+	seahorse_ssh_op_rename_async (source, skey, text,
+	                              NULL, on_rename_complete, closure);
 }
 
 G_MODULE_EXPORT gboolean
@@ -83,75 +102,72 @@ on_ssh_comment_focus_out (GtkWidget* widget, GdkEventFocus *event, SeahorseWidge
     return FALSE;
 }
 
+static void
+on_authorize_complete (GObject *source,
+                       GAsyncResult *result,
+                       gpointer user_data)
+{
+	GtkToggleButton *button = GTK_TOGGLE_BUTTON (user_data);
+	GError *error = NULL;
+
+	if (!seahorse_ssh_op_authorize_finish (SEAHORSE_SSH_SOURCE (source), result, &error)) {
+		seahorse_util_handle_error (&error, GTK_WIDGET (button),
+		                            _("Couldn't change authorization for key."));
+	}
+
+	gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
+	g_object_unref (button);
+}
+
 G_MODULE_EXPORT void
-on_ssh_trust_toggled (GtkToggleButton *button, SeahorseWidget *swidget)
+on_ssh_trust_toggled (GtkToggleButton *button,
+                      SeahorseWidget *swidget)
 {
-    SeahorseSource *sksrc;
-    SeahorseOperation *op;
-    SeahorseObject *object;
-    SeahorseSSHKey *skey;
-    gboolean authorize;
-    GError *err = NULL;
+	SeahorseSSHSource *source;
+	SeahorseSSHKey *skey;
+	gboolean authorize;
 
-    object = SEAHORSE_OBJECT_WIDGET (swidget)->object;
-    skey = SEAHORSE_SSH_KEY (object);
-    sksrc = seahorse_object_get_source (object);
-    g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (sksrc));
-    
-    authorize = gtk_toggle_button_get_active (button);
-    gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
-    
-    op = seahorse_ssh_operation_authorize (SEAHORSE_SSH_SOURCE (sksrc), skey, authorize);
-    g_return_if_fail (op);
-    
-    /* A very fast op, so just wait */
-    seahorse_operation_wait (op);
-    
-    if (!seahorse_operation_is_successful (op)) {
-        seahorse_operation_copy_error (op, &err);
-        seahorse_util_handle_error (err, _("Couldn't change authorization for key."));
-        g_clear_error (&err);
-    }
-    
-    gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
+	skey = SEAHORSE_SSH_KEY (SEAHORSE_OBJECT_WIDGET (swidget)->object);
+	source = SEAHORSE_SSH_SOURCE (seahorse_object_get_source (SEAHORSE_OBJECT (skey)));
+
+	authorize = gtk_toggle_button_get_active (button);
+	gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
+
+	seahorse_ssh_op_authorize_async (source, skey, authorize,
+	                                 NULL, on_authorize_complete, g_object_ref (button));
 }
 
 static void
-passphrase_done (SeahorseOperation *op, SeahorseWidget *swidget)
+on_passphrase_complete (GObject *source,
+                        GAsyncResult *result,
+                        gpointer user_data)
 {
-    GError *err = NULL;
-    GtkWidget *w;
+	GtkWidget *button = GTK_WIDGET (user_data);
+	GError *error = NULL;
 
-    if (!seahorse_operation_is_successful (op)) {
-        seahorse_operation_copy_error (op, &err);
-        seahorse_util_handle_error (err, _("Couldn't change passphrase for key."));
-        g_clear_error (&err);
-    }
-    
-    w = GTK_WIDGET (seahorse_widget_get_widget (swidget, "passphrase-button"));
-    g_return_if_fail (w != NULL);
-    gtk_widget_set_sensitive (w, TRUE);
+	if (!seahorse_ssh_op_change_passphrase_finish (SEAHORSE_SSH_KEY (source),
+	                                               result, &error)) {
+		seahorse_util_handle_error (&error, button, _("Couldn't change passphrase for key."));
+	}
+
+	gtk_widget_set_sensitive (button, TRUE);
+	g_object_unref (button);
 }
 
 G_MODULE_EXPORT void
-on_ssh_passphrase_button_clicked (GtkWidget *widget, SeahorseWidget *swidget)
+on_ssh_passphrase_button_clicked (GtkWidget *widget,
+                                  SeahorseWidget *swidget)
 {
-    SeahorseOperation *op;
-    SeahorseObject *object;
-    GtkWidget *w;
-    
-    object = SEAHORSE_OBJECT_WIDGET (swidget)->object;
-    g_assert (SEAHORSE_IS_SSH_KEY (object));
+	SeahorseObject *object;
+	GtkWidget *button;
 
-    w = GTK_WIDGET (seahorse_widget_get_widget (swidget, "passphrase-button"));
-    g_return_if_fail (w != NULL);
-    gtk_widget_set_sensitive (w, FALSE);
-    
-    op = seahorse_ssh_operation_change_passphrase (SEAHORSE_SSH_KEY (object));
-    seahorse_operation_watch (op, (SeahorseDoneFunc)passphrase_done, swidget, NULL, NULL);
+	object = SEAHORSE_OBJECT_WIDGET (swidget)->object;
+
+	button = seahorse_widget_get_widget (swidget, "passphrase-button");
+	gtk_widget_set_sensitive (button, FALSE);
 
-    /* Running operations ref themselves */
-    g_object_unref (op);
+	seahorse_ssh_op_change_passphrase_async (SEAHORSE_SSH_KEY (object), NULL,
+	                                         on_passphrase_complete, g_object_ref (button));
 }
 
 static void
@@ -165,9 +181,8 @@ export_complete (GFile *file, GAsyncResult *result, guchar *contents)
 	if (!g_file_replace_contents_finish (file, result, NULL, &err)) {
 		uri = g_file_get_uri (file);
 		unesc_uri = g_uri_unescape_string (seahorse_util_uri_get_last (uri), NULL);
-        seahorse_util_handle_error (err, _("Couldn't export key to \"%s\""),
-                                    unesc_uri);
-        g_clear_error (&err);
+		seahorse_util_handle_error (&err, NULL, _("Couldn't export key to \"%s\""),
+		                            unesc_uri);
         g_free (uri);
         g_free (unesc_uri);
 	}
@@ -211,11 +226,9 @@ on_ssh_export_button_clicked (GtkWidget *widget, SeahorseWidget *swidget)
 		                               (GAsyncReadyCallback)export_complete, results);
 	}
 	
-	if (err) {
-	        seahorse_util_handle_error (err, _("Couldn't export key."));
-	        g_clear_error (&err);
-	}
-	
+	if (err)
+		seahorse_util_handle_error (&err, swidget, _("Couldn't export key."));
+
 	g_free (uri);
 }
 
diff --git a/ssh/seahorse-ssh-key.c b/ssh/seahorse-ssh-key.c
index 7a52e84..d1b8e5c 100644
--- a/ssh/seahorse-ssh-key.c
+++ b/ssh/seahorse-ssh-key.c
@@ -130,7 +130,7 @@ changed_key (SeahorseSSHKey *self)
 	              "description", description,
 	              "location", SEAHORSE_LOCATION_LOCAL,
 	              "identifier", identifier,
-	              "flags", (self->keydata->authorized ? SEAHORSE_FLAG_TRUSTED : 0) | SEAHORSE_FLAG_EXPORTABLE,
+	              "flags", (self->keydata->authorized ? SEAHORSE_FLAG_TRUSTED : 0) | SEAHORSE_FLAG_EXPORTABLE | SEAHORSE_FLAG_DELETABLE,
 	              NULL);
 	
 	g_free (identifier);
@@ -163,49 +163,6 @@ seahorse_ssh_key_refresh (SeahorseObject *sobj)
 	SEAHORSE_OBJECT_CLASS (seahorse_ssh_key_parent_class)->refresh (sobj);
 }
 
-static SeahorseOperation*
-seahorse_ssh_key_delete (SeahorseObject *sobj)
-{
-	SeahorseSSHKeyData *keydata = NULL;
-	gboolean ret = TRUE;
-	GError *err = NULL;
-    
-	g_return_val_if_fail (SEAHORSE_IS_SSH_KEY (sobj), NULL);
-
-	g_object_get (sobj, "key-data", &keydata, NULL);
-	g_return_val_if_fail (keydata, FALSE);
-    
-	/* Just part of a file for this key */
-	if (keydata->partial) {
-	
-		/* Take just that line out of the file */
-		if (keydata->pubfile)
-			seahorse_ssh_key_data_filter_file (keydata->pubfile, NULL, keydata, &err);
-	
-	/* A full file for this key */
-	} else {
-	
-		if (keydata->pubfile) {
-			if (g_unlink (keydata->pubfile) == -1) {
-				g_set_error (&err, G_FILE_ERROR, g_file_error_from_errno (errno), 
-				             "%s", g_strerror (errno));
-			}
-		}
-
-		if (ret && keydata->privfile) {
-			if (g_unlink (keydata->privfile) == -1) {
-				g_set_error (&err, G_FILE_ERROR, g_file_error_from_errno (errno), 
-				             "%s", g_strerror (errno));
-			}
-		}
-	}
-
-	if (err == NULL)
-		seahorse_context_remove_object (SCTX_APP (), sobj);
-
-	return seahorse_operation_new_complete (err);
-}
-
 static void
 seahorse_ssh_key_get_property (GObject *object, guint prop_id,
                                GValue *value, GParamSpec *pspec)
@@ -281,8 +238,7 @@ seahorse_ssh_key_class_init (SeahorseSSHKeyClass *klass)
     gobject_class->finalize = seahorse_ssh_key_finalize;
     gobject_class->set_property = seahorse_ssh_key_set_property;
     gobject_class->get_property = seahorse_ssh_key_get_property;
-    
-    seahorse_class->delete = seahorse_ssh_key_delete;
+
     seahorse_class->refresh = seahorse_ssh_key_refresh;
     
     g_object_class_install_property (gobject_class, PROP_KEY_DATA,
diff --git a/ssh/seahorse-ssh-key.h b/ssh/seahorse-ssh-key.h
index 741858a..24580c8 100644
--- a/ssh/seahorse-ssh-key.h
+++ b/ssh/seahorse-ssh-key.h
@@ -25,7 +25,6 @@
 #include <gtk/gtk.h>
 
 #include "seahorse-object.h"
-#include "seahorse-operation.h"
 #include "seahorse-source.h"
 #include "seahorse-validity.h"
 
@@ -73,8 +72,15 @@ const gchar*            seahorse_ssh_key_get_algo_str         (SeahorseSSHKey *s
 guint                   seahorse_ssh_key_get_strength         (SeahorseSSHKey *skey);
 
 const gchar*            seahorse_ssh_key_get_location         (SeahorseSSHKey *skey);
-                                                                   
-SeahorseOperation*      seahorse_ssh_key_op_change_passphrase (SeahorseSSHKey *skey);
+
+void             seahorse_ssh_key_op_change_passphrase_async  (SeahorseSSHKey *self,
+                                                               GCancellable *cancellable,
+                                                               GAsyncReadyCallback callback,
+                                                               gpointer user_data);
+
+gboolean         seahorse_ssh_key_op_change_passphrase_finish (SeahorseSSHKey *self,
+                                                               GAsyncResult *result,
+                                                               GError **error);
 
 SeahorseValidity        seahorse_ssh_key_get_trust            (SeahorseSSHKey *self);
 
diff --git a/ssh/seahorse-ssh-operation.c b/ssh/seahorse-ssh-operation.c
index 2b3fbb9..0a48a4c 100644
--- a/ssh/seahorse-ssh-operation.c
+++ b/ssh/seahorse-ssh-operation.c
@@ -30,6 +30,7 @@
 #include <unistd.h>
 
 #include <glib/gi18n.h>
+#include <glib/gstdio.h>
 
 #include "seahorse-ssh-operation.h"
 #include "seahorse-util.h"
@@ -38,337 +39,103 @@
 #define DEBUG_FLAG SEAHORSE_DEBUG_OPERATION
 #include "seahorse-debug.h"
 
-#include <gnome-keyring.h>
-
-/* -----------------------------------------------------------------------------
- * DEFINITIONS
- */
- 
-typedef void (*ResultCallback) (SeahorseSSHOperation *sop);
-typedef const gchar* (*PasswordCallback) (SeahorseSSHOperation *sop, const gchar* msg);
-
-typedef struct _SeahorseSSHOperationPrivate {
-    
-    /* Data written to SSH */
-    GString *sin;
-    guint win;
-    GIOChannel *iin;
-    
-    /* Data being read from SSH */
-    GString *sout;
-    guint wout;
-    GIOChannel *iout;
-    
-    /* Data from SSH error */
-    GString *serr;
-    guint werr;
-    GIOChannel *ierr;
-    
-    /* Process Information */
-    GPid pid;
-    guint wpid;
-    
-    /* Callback when ready to parse result */
-    ResultCallback result_cb;
-    
-    /* Callback for password prompting */
-    PasswordCallback password_cb;
-    
-    /* Prompt information */
-    SeahorseObject *prompt_skey;
-    GtkDialog *prompt_dialog;
-    guint prompt_requests;
-    
-    /* seahorse-ssh-askpass communication */
-    GIOChannel *io_askpass;
-    guint stag_askpass;
-    int fds_askpass[2];
-
-} SeahorseSSHOperationPrivate;
-
 #define COMMAND_PASSWORD "PASSWORD "
 #define COMMAND_PASSWORD_LEN   9
 
-enum {
-    PROP_0,
-    PROP_KEY_SOURCE
-};
-
-#define SEAHORSE_SSH_OPERATION_GET_PRIVATE(obj)  \
-    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SEAHORSE_TYPE_SSH_OPERATION, SeahorseSSHOperationPrivate))
-
-/* TODO: This is just nasty. Gotta get rid of these weird macros */
-IMPLEMENT_OPERATION_PROPS(SSH, ssh)
-
-    g_object_class_install_property (gobject_class, PROP_KEY_SOURCE,
-        g_param_spec_object ("source", "SSH Key Source", "Key source this operation works on.", 
-                             SEAHORSE_TYPE_SSH_SOURCE, G_PARAM_READABLE));
-
-    g_type_class_add_private (gobject_class, sizeof (SeahorseSSHOperationPrivate));
-
-END_IMPLEMENT_OPERATION_PROPS
-
-/* -----------------------------------------------------------------------------
- * HELPERS
- */
-
-static void 
-watch_ssh_process (GPid pid, gint status, SeahorseSSHOperation *sop)
-{
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-
-    seahorse_debug ("SSHOP: SSH process done");
-
-    /* Close off the askpass io channel etc... */
-    if(pv->stag_askpass)
-        g_source_remove (pv->stag_askpass);
-    pv->stag_askpass = 0;
-    
-    if (seahorse_operation_is_running (SEAHORSE_OPERATION (sop))) {
-
-        /* Was killed */
-        if (!WIFEXITED (status)) {
-            seahorse_operation_mark_done (SEAHORSE_OPERATION (sop), FALSE, 
-                g_error_new (SEAHORSE_ERROR, 0, _("The SSH command was terminated unexpectedly.")));
-            
-        /* Command failed */
-        } else if (WEXITSTATUS (status) != 0) {
-            g_warning ("SSH command failed: (%d)", WEXITSTATUS (status));
-            if (pv->serr->len)
-                g_warning ("SSH error output: %s", pv->serr->str);
-            seahorse_operation_mark_done (SEAHORSE_OPERATION (sop), FALSE, 
-                g_error_new_literal (SEAHORSE_ERROR, 0, pv->serr->len ? pv->serr->str : _("The SSH command failed.")));
-
-        /* Successful completion */
-        } else {
-            
-            /*
-             * If a result callback is set (by one of our specific operations below)
-             * then we let it setup the result. Otherwise use the output string.
-             */
-            if (pv->result_cb)
-                (pv->result_cb) (sop);
-            else
-                seahorse_operation_mark_result (SEAHORSE_OPERATION (sop), pv->sout->str, NULL);
-    
-            /* The result callback may have completed operation */
-            if (seahorse_operation_is_running (SEAHORSE_OPERATION (sop)))
-                seahorse_operation_mark_done (SEAHORSE_OPERATION (sop), FALSE, NULL);
-        }
-    }
+typedef struct {
+	SeahorseObject *key;
+	GtkDialog *dialog;
+	guint requests;
+} SeahorseSshSourcePrompt;
 
-    g_spawn_close_pid (pid);
-    pv->pid = 0;
-    pv->wpid = 0;
-    
-    
-    if(pv->io_askpass)
-        g_io_channel_unref (pv->io_askpass);
-    pv->io_askpass = NULL;
-    
-    /* This watch holds a ref on the operation, release */
-    g_object_unref (sop);
-}
+typedef const gchar * (*SeahorseSshSourcePasswordCallback) (SeahorseSshSourcePrompt *prompt,
+                                                            const gchar* message,
+                                                            gpointer user_data);
 
-static gboolean    
-io_ssh_write (GIOChannel *source, GIOCondition condition, SeahorseSSHOperation *sop)
-{
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    GError *error = NULL;
-    GIOStatus status;
-    gsize written = 0;
-
-    if (seahorse_operation_is_running (SEAHORSE_OPERATION (sop)) && pv->sin) {
-        seahorse_debug ("SSHOP: SSH ready for input");
-
-        status = g_io_channel_write_chars (pv->iin, pv->sin->str, pv->sin->len,
-                                           &written, &error);
-        switch (status) {
-        case G_IO_STATUS_ERROR:
-            seahorse_operation_mark_done (SEAHORSE_OPERATION (sop), FALSE, error);
-            break;
-        case G_IO_STATUS_AGAIN:
-            break;
-        default:
-            seahorse_debug ("SSHOP: Wrote %d bytes to SSH", (gint)written);
-            g_string_erase (pv->sin, 0, written);
-            break;
-        }
-    }
-    
-    if (pv->sin && !pv->sin->len) {
-        seahorse_debug ("SSHOP: Finished writing SSH input");
-        g_string_free (pv->sin, TRUE);
-        pv->sin = NULL;
-    }
-    
-    if (!seahorse_operation_is_running (SEAHORSE_OPERATION (sop)) || !pv->sin) {
-        seahorse_debug ("SSHOP: Closing SSH input channel");
-        g_io_channel_unref (pv->iin);
-        pv->iin = NULL;
-        g_source_remove (pv->win);
-        pv->win = 0;
-        return FALSE;
-    }
-    
-    return TRUE;
-}
+typedef struct {
+	GError *previous_error;
 
-static gboolean    
-io_ssh_read (GIOChannel *source, GIOCondition condition, SeahorseSSHOperation *sop)
-{
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    GError *error = NULL;
-    gchar buf[128];
-    GIOStatus status;
-    gsize read = 0;
-    GString *str;
-    
-    if (!seahorse_operation_is_running (SEAHORSE_OPERATION (sop)))
-        return TRUE;
-    
-    /* Figure out which buffer we're writing into */
-    if (source == pv->iout) {
-        str = pv->sout;
-        seahorse_debug ("SSHOP: SSH output: ");
-    } else if(source == pv->ierr) {
-        str = pv->serr;
-        seahorse_debug ("SSHOP: SSH errout: ");
-    } else
-        g_assert_not_reached ();
-
-    do {
-        status = g_io_channel_read_chars (source, buf, sizeof (buf), &read, &error);
-        switch (status) {
-        case G_IO_STATUS_ERROR:
-            seahorse_operation_mark_done (SEAHORSE_OPERATION (sop), FALSE, error);
-            break;
-        case G_IO_STATUS_AGAIN:
-            continue;
-        case G_IO_STATUS_EOF:
-            break;
-        default:
-            g_string_append_len (str, buf, read);
-            seahorse_debug ("%s", str->str + (str->len - read));
-            break;
-        }
-    } while (read == sizeof (buf));
-    
-    return TRUE;
-}
+	/* Data written to SSH */
+	GString *sin;
+	guint win;
+	GIOChannel *iin;
 
-/* Communication with seahorse-ssh-askpass */
-static gboolean
-askpass_handler (GIOChannel *source, GIOCondition condition, SeahorseSSHOperation *sop)
-{
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    gchar *string = NULL;
-    gsize length;
-    GError *err = 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, &err);
-
-        if (err != NULL) {
-            g_critical ("couldn't read from seahorse-ssh-askpass: %s", err->message);
-            g_clear_error (&err);
-            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 (pv->password_cb) {
-                    result = (pv->password_cb) (sop, line);
-                    
-                    /* Cancelled prompt, cancel operation */
-                    if (!result) {
-                        if (seahorse_operation_is_running (SEAHORSE_OPERATION (sop)))
-                            seahorse_operation_cancel (SEAHORSE_OPERATION (sop));
-                        seahorse_debug ("SSHOP: password prompt cancelled");
-                        ret = FALSE;
-                    }
-                }
-                
-                pv->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 (pv->io_askpass, result, strlen (result), &length, &err);
-                if (err == NULL)
-                    g_io_channel_write_chars (pv->io_askpass, "", 1, &length, &err);
-                if (err == NULL)
-                    g_io_channel_flush (pv->io_askpass, &err);
-                if (err != NULL) {
-                    g_critical ("couldn't read from seahorse-ssh-askpass: %s", err->message);
-                    g_clear_error (&err);
-                    ret = FALSE;
-                }
-            }
-        }
-    }
+	/* Data being read from SSH */
+	GString *sout;
+	guint wout;
+	GIOChannel *iout;
 
-    if (condition & G_IO_HUP)
-        ret = FALSE;
-        
-    if (!ret) {
-        if (pv->io_askpass)
-            g_io_channel_unref (pv->io_askpass);
-        pv->io_askpass = NULL;
-        pv->stag_askpass = 0;
-    }
+	/* Data from SSH error */
+	GString *serr;
+	guint werr;
+	GIOChannel *ierr;
 
-    g_free (string);
-    return ret;
-}
+	/* Process Information */
+	GPid pid;
+	guint wpid;
 
-static void
-ssh_child_setup (gpointer user_data)
-{
-    SeahorseSSHOperationPrivate *pv = (SeahorseSSHOperationPrivate*)user_data;
-    gchar buf[15];
+	/* Callback for password prompting */
+	SeahorseSshSourcePasswordCallback password_cb;
+	SeahorseSshSourcePrompt *prompt;
 
-    /* No terminal for this process */
-    setsid ();
-    
-    g_setenv ("SSH_ASKPASS", EXECDIR "seahorse-ssh-askpass", FALSE);
+	/* seahorse-ssh-askpass communication */
+	GIOChannel *io_askpass;
+	guint stag_askpass;
+	int fds_askpass[2];
 
-    /* We do screen scraping so we need locale C */
-    if (g_getenv ("LC_ALL"))
-        g_setenv ("LC_ALL", "C", TRUE);
-    g_setenv ("LANG", "C", TRUE);
-    
-    /* Let child know which fd it is */
-    if (pv->fds_askpass[1] != -1) {
-        snprintf (buf, sizeof (buf), "%d", pv->fds_askpass[1]);
-        g_setenv ("SEAHORSE_SSH_ASKPASS_FD", buf, TRUE);
-    }
-    
-    /* Child doesn't need this stuff */
-    if (pv->fds_askpass[0] != -1)
-        close(pv->fds_askpass[0]);
-}
+	GCancellable *cancellable;
+	gulong cancelled_sig;
+} ssh_operation_closure;
 
 static void
-ssh_sync_child_setup (gpointer user_data)
+ssh_operation_free (gpointer data)
 {
-    /* No terminal for this process */
-    setsid ();
+	ssh_operation_closure *closure = data;
+
+	/* Should have been used */
+	g_assert (closure->previous_error == NULL);
+
+	/* Disconnected when process exits */
+	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)
+		g_source_remove (closure->wout);
+	if (closure->werr)
+		g_source_remove (closure->werr);
+
+	if (closure->iin)
+		g_io_channel_unref (closure->iin);
+	if (closure->iout)
+		g_io_channel_unref (closure->iout);
+	if (closure->ierr)
+		g_io_channel_unref (closure->ierr);
+
+	if (closure->sin)
+		g_string_free (closure->sin, TRUE);
+	if (closure->sout)
+		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);
 }
 
 static const gchar*
@@ -417,720 +184,1094 @@ escape_shell_arg (const gchar *arg)
     return escaped;
 }
 
-static const gchar* 
-prompt_passphrase (SeahorseSSHOperation *sop, const gchar* title, const gchar* message,
-                   const gchar* check, gboolean confirm)
+static const gchar*
+seahorse_ssh_source_prompt_passphrase (SeahorseSshSourcePrompt *prompt,
+                                       const gchar* title,
+                                       const gchar* message,
+                                       const gchar* check,
+                                       gboolean confirm)
 {
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    const gchar *display;
-    gchar *msg;
-    
-    if (pv->prompt_dialog)
-        gtk_widget_destroy (GTK_WIDGET (pv->prompt_dialog));
-    
-    if (pv->prompt_skey)
-        display = seahorse_object_get_label (pv->prompt_skey);
-    else 
-        display = _("Secure Shell key");
-    msg = g_strdup_printf (message, display);
-
-    pv->prompt_dialog = seahorse_passphrase_prompt_show (title, msg, _("Passphrase:"), 
-                                                         check, confirm);
-    g_free (msg);
-    
-    /* Run and check if cancelled? */
-    if (gtk_dialog_run (pv->prompt_dialog) != GTK_RESPONSE_ACCEPT) {
-        gtk_widget_destroy (GTK_WIDGET (pv->prompt_dialog));
-        pv->prompt_dialog = NULL;
-        return NULL;
-    }
-    
-    gtk_widget_hide (GTK_WIDGET (pv->prompt_dialog));
-    return seahorse_passphrase_prompt_get (pv->prompt_dialog);
+	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 const gchar* 
-prompt_password (SeahorseSSHOperation *sop, const gchar* title, const gchar* message,
-                 const gchar* check, gboolean confirm)
+static void
+on_ssh_operation_cancelled (GCancellable *cancellable,
+                            gpointer user_data)
 {
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    const gchar *display;
-    gchar *msg;
-    
-    if (pv->prompt_dialog)
-        gtk_widget_destroy (GTK_WIDGET (pv->prompt_dialog));
-    
-    if (pv->prompt_skey)
-        display = seahorse_object_get_label (pv->prompt_skey);
-    else 
-        display = g_strdup (_("Secure Shell key"));
-    msg = g_strdup_printf (message, display);
-
-    pv->prompt_dialog = seahorse_passphrase_prompt_show (title, msg, _("Password:"), 
-                                                         check, confirm);
-    g_free (msg);
-    
-    /* Run and check if cancelled? */
-    if (gtk_dialog_run (pv->prompt_dialog) != GTK_RESPONSE_ACCEPT) {
-        gtk_widget_destroy (GTK_WIDGET (pv->prompt_dialog));
-        pv->prompt_dialog = NULL;
-        return NULL;
-    }
-    
-    gtk_widget_hide (GTK_WIDGET (pv->prompt_dialog));
-    return seahorse_passphrase_prompt_get (pv->prompt_dialog);
+	GPid *pid = user_data;
+	kill (*pid, SIGTERM);
 }
 
 /* -----------------------------------------------------------------------------
- * OBJECT 
+ * PUBLIC 
  */
 
-static void 
-seahorse_ssh_operation_init (SeahorseSSHOperation *sop)
+static void
+on_watch_ssh_process (GPid pid,
+                      gint status,
+                      gpointer user_data)
 {
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    
-    pv->sout = g_string_new (NULL);
-    pv->serr = g_string_new (NULL);
-
-    /* The seahorse-ssh-askpass pipes */
-    if (socketpair (AF_UNIX, SOCK_STREAM, 0, pv->fds_askpass) == -1) {
-        g_warning ("couldn't create pipes to communicate with seahorse-ssh-askpass: %s",
-                   strerror(errno));
-        pv->fds_askpass[0] = -1;
-        pv->fds_askpass[1] = -1;
-    }
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	ssh_operation_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+
+	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);
+		closure->previous_error = NULL;
+
+	/* Was cancelled */
+	} else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGTERM) {
+		g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+		                                 _("The operation was cancelled"));
+
+	/* Failed abnormally */
+	} else if (!WIFEXITED (status)) {
+		g_simple_async_result_set_error (res, SEAHORSE_ERROR, 0, "%s",
+		                                 _("The SSH command was terminated unexpectedly."));
+
+	/* Command failed */
+	} else if (WEXITSTATUS (status) != 0) {
+		g_warning ("SSH command failed: (%d)", WEXITSTATUS (status));
+		if (closure->serr->len)
+			g_warning ("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."));
+
+	}
+
+	g_cancellable_disconnect (closure->cancellable,
+	                          closure->cancelled_sig);
+	closure->cancelled_sig = 0;
+
+	g_spawn_close_pid (pid);
+	closure->pid = 0;
+	closure->wpid = 0;
+
+	if (closure->io_askpass)
+		g_io_channel_unref (closure->io_askpass);
+	closure->io_askpass = NULL;
+
+	g_simple_async_result_complete (res);
 }
 
-static void 
-seahorse_ssh_operation_set_property (GObject *gobject, guint prop_id, 
-                                     const GValue *value, GParamSpec *pspec)
+static gboolean
+on_io_ssh_read (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);
+	GError **error = NULL;
+	gchar buf[128];
+	GIOStatus status;
+	gsize read = 0;
+	GString *str;
+	gboolean ret = TRUE;
+
+	/* Figure out which buffer we're writing into */
+	if (source == closure->iout) {
+		str = closure->sout;
+		seahorse_debug ("SSHOP: SSH output: ");
+	} else if(source == closure->ierr) {
+		str = closure->serr;
+		seahorse_debug ("SSHOP: SSH errout: ");
+	} else
+		g_assert_not_reached ();
+
+	if (!closure->previous_error)
+		error = &closure->previous_error;
+
+	do {
+		status = g_io_channel_read_chars (source, buf, sizeof (buf),
+		                                  &read, error);
+		switch (status) {
+		case G_IO_STATUS_ERROR:
+			ret = FALSE;
+			kill (closure->pid, SIGTERM);
+			break;
+		case G_IO_STATUS_AGAIN:
+			continue;
+		case G_IO_STATUS_EOF:
+			break;
+		default:
+			g_string_append_len (str, buf, read);
+			seahorse_debug ("%s", str->str + (str->len - read));
+			break;
+		}
+	} while (read == sizeof (buf));
+
+	return ret;
 }
 
-static void 
-seahorse_ssh_operation_get_property (GObject *gobject, guint prop_id, 
-                                     GValue *value, GParamSpec *pspec)
+static gboolean
+on_io_ssh_write (GIOChannel *source,
+                 GIOCondition condition,
+                 gpointer user_data)
 {
-    SeahorseSSHOperation *sop = SEAHORSE_SSH_OPERATION (gobject);
-    
-    switch (prop_id) {
-    case PROP_KEY_SOURCE:
-        g_value_set_object (value, sop->sksrc);
-        break;
-    }
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	ssh_operation_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError **error = NULL;
+	GIOStatus status;
+	gsize written = 0;
+	gboolean ret = TRUE;
+
+	if (closure->sin) {
+		seahorse_debug ("SSHOP: SSH ready for input");
+
+		if (!closure->previous_error)
+			error = &closure->previous_error;
+
+		status = g_io_channel_write_chars (closure->iin, closure->sin->str,
+		                                   closure->sin->len, &written, error);
+		switch (status) {
+		case G_IO_STATUS_ERROR:
+			ret = FALSE;
+			kill (closure->pid, SIGTERM);
+			break;
+		case G_IO_STATUS_AGAIN:
+			break;
+		default:
+			seahorse_debug ("SSHOP: Wrote %d bytes to SSH", (gint)written);
+			g_string_erase (closure->sin, 0, written);
+			break;
+		}
+	}
+
+	if (closure->sin && !closure->sin->len) {
+		seahorse_debug ("SSHOP: Finished writing SSH input");
+		g_string_free (closure->sin, TRUE);
+		closure->sin = NULL;
+	}
+
+	if (!closure->sin) {
+		seahorse_debug ("SSHOP: Closing SSH input channel");
+		g_io_channel_unref (closure->iin);
+		closure->iin = NULL;
+		g_source_remove (closure->win);
+		closure->win = 0;
+		return FALSE;
+	}
+
+	return ret;
 }
 
-static void 
-seahorse_ssh_operation_dispose (GObject *gobject)
+/* Communication with seahorse-ssh-askpass */
+static gboolean
+on_io_askpass_handler (GIOChannel *source,
+                       GIOCondition condition,
+                       gpointer user_data)
 {
-    SeahorseOperation *op = SEAHORSE_OPERATION (gobject);
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (op);
-
-    if (seahorse_operation_is_running (op))
-        seahorse_ssh_operation_cancel (op);
-    
-    if (pv->prompt_dialog)
-        gtk_widget_destroy (GTK_WIDGET (pv->prompt_dialog));
-    pv->prompt_dialog = NULL;
-    
-    G_OBJECT_CLASS (ssh_operation_parent_class)->dispose (gobject);  
+	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 
-seahorse_ssh_operation_finalize (GObject *gobject)
-{
-    SeahorseSSHOperation *sop = SEAHORSE_SSH_OPERATION (gobject);
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    
-    if (pv->win)
-        g_source_remove (pv->win);
-    if (pv->wout)
-        g_source_remove (pv->wout);
-    if (pv->werr)
-        g_source_remove (pv->werr);
-
-    if (pv->iin)
-        g_io_channel_unref (pv->iin);
-    if (pv->iout)
-        g_io_channel_unref (pv->iout);
-    if (pv->ierr)
-        g_io_channel_unref (pv->ierr);
-        
-    if (pv->sin)
-        g_string_free (pv->sin, TRUE);
-    g_string_free (pv->sout, TRUE);
-    g_string_free (pv->serr, TRUE);
-    
-    /* Close the sockets */
-    if (pv->fds_askpass[0] != -1) 
-        close (pv->fds_askpass[0]);
-    pv->fds_askpass[0] = -1;
-
-    if (pv->fds_askpass[1] != -1) 
-        close (pv->fds_askpass[1]);
-    pv->fds_askpass[1] = -1;
-    
-    g_assert (pv->prompt_dialog == NULL);
-
-    /* watch_ssh_process always needs to have been called */
-    g_assert (pv->pid == 0 && pv->wpid == 0);
-    g_assert (pv->io_askpass == NULL && pv->stag_askpass == 0);
-    
-    G_OBJECT_CLASS (ssh_operation_parent_class)->finalize (gobject);  
-}
 
-static void 
-seahorse_ssh_operation_cancel (SeahorseOperation *operation)
+static void
+on_spawn_setup_child (gpointer user_data)
 {
-    SeahorseSSHOperation *sop = SEAHORSE_SSH_OPERATION (operation);    
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
+	ssh_operation_closure *closure = user_data;
+	gchar buf[15];
 
-    seahorse_operation_mark_done (operation, TRUE, NULL);
-
-    if (pv->pid != 0)
-        kill (pv->pid, SIGTERM);
-}
+	/* No terminal for this process */
+	setsid ();
 
-/* -----------------------------------------------------------------------------
- * PUBLIC 
- */
+	g_setenv ("SSH_ASKPASS", EXECDIR "seahorse-ssh-askpass", FALSE);
 
-SeahorseOperation*
-seahorse_ssh_operation_new (SeahorseSSHSource *ssrc, const gchar *command, 
-                            const gchar *input, gint length, SeahorseSSHKey *skey)
-{
-    SeahorseSSHOperationPrivate *pv;
-    SeahorseSSHOperation *sop;
-    GError *error = NULL;
-    int argc, r;
-    int fin, fout, ferr;
-    char **argv;
-    
-    g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (ssrc), NULL);
-    g_return_val_if_fail (command && command[0], NULL);
-    
-    if (!g_shell_parse_argv (command, &argc, &argv, NULL)) {
-        g_critical ("couldn't parse ssh command line: %s", command);
-        g_return_val_if_reached (NULL);
-    }
-    
-    sop = g_object_new (SEAHORSE_TYPE_SSH_OPERATION, NULL);
-    pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
+	/* We do screen scraping so we need locale C */
+	if (g_getenv ("LC_ALL"))
+		g_setenv ("LC_ALL", "C", TRUE);
+	g_setenv ("LANG", "C", TRUE);
 
-    sop->sksrc = ssrc;
-    pv->prompt_skey = SEAHORSE_OBJECT (skey);
+	/* 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);
+	}
 
-    seahorse_debug ("SSHOP: Executing SSH command: %s", command);
+	/* Child doesn't need this stuff */
+	if (closure->fds_askpass[0] != -1)
+		close (closure->fds_askpass[0]);
+}
 
-    /* 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 	, 
-                                  ssh_child_setup, pv, &pv->pid, 
-                                  input ? &fin : NULL, &fout, &ferr, &error);
-    g_strfreev (argv);  
-    
-    if (!r)
-        return seahorse_operation_new_complete (error);
-    
-    /* Copy the input for later writing */
-    if (input) {
-        pv->sin = g_string_new_len (input, length == -1 ? strlen (input) : length);
-        seahorse_debug ("SSHOP: Will send SSH input: %s", pv->sin->str);
-
-        fcntl (fin, F_SETFL, O_NONBLOCK | fcntl (fin, F_GETFL));
-        pv->iin = g_io_channel_unix_new (fin);
-        g_io_channel_set_encoding (pv->iin, NULL, NULL);
-        g_io_channel_set_close_on_unref (pv->iin, TRUE);
-        pv->win = g_io_add_watch (pv->iin, G_IO_OUT, (GIOFunc)io_ssh_write, sop);
-    }
-    
-    /* Make all the proper IO Channels for the output/error */
-    fcntl (fout, F_SETFL, O_NONBLOCK | fcntl (fout, F_GETFL));
-    pv->iout = g_io_channel_unix_new (fout);
-    g_io_channel_set_encoding (pv->iout, NULL, NULL);
-    g_io_channel_set_close_on_unref (pv->iout, TRUE);
-    pv->wout = g_io_add_watch (pv->iout, G_IO_IN, (GIOFunc)io_ssh_read, sop);
-    
-    fcntl (ferr, F_SETFL, O_NONBLOCK | fcntl (ferr, F_GETFL));
-    pv->ierr = g_io_channel_unix_new (ferr);
-    g_io_channel_set_encoding (pv->ierr, NULL, NULL);
-    g_io_channel_set_close_on_unref (pv->ierr, TRUE);
-    pv->werr = g_io_add_watch (pv->ierr, G_IO_IN, (GIOFunc)io_ssh_read, sop);
-    
-    /* Process watch */
-    g_object_ref (sop); /* When the process ends, reference is released */
-    pv->wpid = g_child_watch_add (pv->pid, (GChildWatchFunc)watch_ssh_process, sop);
-    
-    /* Setup askpass communication */
-    if (pv->fds_askpass[0] != -1) {
-        pv->io_askpass = g_io_channel_unix_new (pv->fds_askpass[0]);
-        g_io_channel_set_close_on_unref (pv->io_askpass, TRUE);
-        g_io_channel_set_encoding (pv->io_askpass, NULL, NULL);
-        pv->stag_askpass = g_io_add_watch (pv->io_askpass, G_IO_IN | G_IO_HUP, 
-                                           (GIOFunc)askpass_handler, sop);
-        pv->fds_askpass[0] = -1; /* closed by io channel */
-    }
-    
-    /* The other end of the pipe, close it */
-    if (pv->fds_askpass[1] != -1) 
-        close (pv->fds_askpass[1]);
-    pv->fds_askpass[1] = -1;
-    
-    seahorse_operation_mark_start (SEAHORSE_OPERATION (sop));
-    
-    return SEAHORSE_OPERATION (sop);
+static void
+seahorse_ssh_operation_async (SeahorseSSHSource *source,
+                              const gchar *command,
+                              const gchar *input,
+                              gssize length,
+                              SeahorseSSHKey *key,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              SeahorseSshSourcePasswordCallback password,
+                              gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+	ssh_operation_closure *closure;
+	GError *error = NULL;
+	int argc, r;
+	int fin, fout, ferr;
+	char **argv;
+
+	g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (source));
+	g_return_if_fail (command && command[0]);
+
+	if (!g_shell_parse_argv (command, &argc, &argv, NULL)) {
+		g_critical ("couldn't parse ssh command line: %s", command);
+		g_return_if_reached ();
+	}
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ssh_operation_async);
+	closure = g_new0 (ssh_operation_closure, 1);
+	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);
+
+	seahorse_debug ("SSHOP: Executing SSH command: %s", command);
+
+	/* 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,
+	                              input ? &fin : NULL, &fout, &ferr, &error);
+	g_strfreev (argv);
+
+	if (!r) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		g_object_unref (res);
+		return;
+	}
+
+	/* Copy the input for later writing */
+	if (input) {
+		closure->sin = g_string_new_len (input, length == -1 ? strlen (input) : length);
+		seahorse_debug ("SSHOP: Will send SSH input: %s", closure->sin->str);
+
+		fcntl (fin, F_SETFL, O_NONBLOCK | fcntl (fin, F_GETFL));
+		closure->iin = g_io_channel_unix_new (fin);
+		g_io_channel_set_encoding (closure->iin, NULL, NULL);
+		g_io_channel_set_close_on_unref (closure->iin, TRUE);
+		closure->win = g_io_add_watch_full (closure->iin, G_PRIORITY_DEFAULT,
+		                                    G_IO_OUT, on_io_ssh_write,
+		                                    g_object_ref (res), g_object_unref);
+	}
+
+	/* Make all the proper IO Channels for the output/error */
+	fcntl (fout, F_SETFL, O_NONBLOCK | fcntl (fout, F_GETFL));
+	closure->iout = g_io_channel_unix_new (fout);
+	g_io_channel_set_encoding (closure->iout, NULL, NULL);
+	g_io_channel_set_close_on_unref (closure->iout, TRUE);
+	closure->wout = g_io_add_watch_full (closure->iout, G_PRIORITY_DEFAULT,
+	                                     G_IO_IN, on_io_ssh_read,
+	                                     g_object_ref (res), g_object_unref);
+
+	fcntl (ferr, F_SETFL, O_NONBLOCK | fcntl (ferr, F_GETFL));
+	closure->ierr = g_io_channel_unix_new (ferr);
+	g_io_channel_set_encoding (closure->ierr, NULL, NULL);
+	g_io_channel_set_close_on_unref (closure->ierr, TRUE);
+	closure->werr = g_io_add_watch_full (closure->ierr, G_PRIORITY_DEFAULT,
+	                                     G_IO_IN, on_io_ssh_read,
+	                                     g_object_ref (res), g_object_unref);
+
+	/* Process watch */
+	closure->wpid = g_child_watch_add_full (G_PRIORITY_DEFAULT, closure->pid,
+	                                        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),
+		                                                &closure->pid, NULL);
+
+	g_object_unref (res);
 }
 
-gchar*
-seahorse_ssh_operation_sync (SeahorseSSHSource *ssrc, const gchar *command, 
-                             GError **error)
+static GString *
+seahorse_ssh_operation_finish (SeahorseSSHSource *source,
+                               GAsyncResult *result,
+                               GError **error)
 {
-    GError *err = NULL;
-    gchar *sout, *serr;
-    gint status;
-    gint argc;
-    gchar **argv;
-    gboolean r;
-    
-    g_assert (!error || !*error);
-    
-    /* We use this internally, so guarantee it exists */
-    if (!error)
-        error = &err;
-    
-    if (!g_shell_parse_argv (command, &argc, &argv, NULL)) {
-        g_critical ("couldn't parse ssh command line: %s", command);
-        return NULL;
-    }
+	GString *output;
+	ssh_operation_closure *closure;
 
-    seahorse_debug ("SSHOP: executing SSH command: %s", command);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_operation_async), NULL);
 
-    r = g_spawn_sync (NULL, argv, NULL, 0, ssh_sync_child_setup, NULL, 
-                      &sout, &serr, &status, error);
-    g_strfreev (argv);
-    
-    if (!r) {
-        g_critical ("couldn't execute SSH command: %s (%s)", command, *error ? (*error)->message : "");
-        return NULL;
-    }
-    
-    if (!WIFEXITED (status)) {
-        g_critical ("SSH command didn't exit properly: %s", command);
-        g_set_error (error, SEAHORSE_ERROR, 0, "%s", _("The SSH command was terminated unexpectedly."));
-        g_free (sout);
-        g_free (serr);
-        return NULL;
-    }
-    
-    if (WEXITSTATUS (status) != 0) {
-        g_set_error (error, SEAHORSE_ERROR, 0, "%s", _("The SSH command failed."));
-        g_warning ("SSH command failed: %s (%d)", command, WEXITSTATUS (status));
-        if (serr && serr[0])
-            g_warning ("SSH error output: %s", serr);
-        g_free (serr);
-        g_free (sout);
-        return NULL;
-    }
-    
-    g_free (serr);
-    return sout;
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	output = closure->sout;
+	closure->sout = NULL;
+	return output;
 }
 
 /* -----------------------------------------------------------------------------
  * UPLOAD KEY 
  */
 
+typedef struct {
+	GMemoryOutputStream *output;
+	GCancellable *cancellable;
+	gchar *username;
+	gchar *hostname;
+	gchar *port;
+} ssh_upload_closure;
+
+static void
+ssh_upload_free (gpointer data)
+{
+	ssh_upload_closure *closure = data;
+	g_object_unref (closure->output);
+	g_clear_object (&closure->cancellable);
+	g_free (closure->username);
+	g_free (closure->hostname);
+	g_free (closure->port);
+	g_free (closure);
+}
+
 static const gchar*
-upload_password_cb (SeahorseSSHOperation *sop, const gchar* msg)
+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 prompt_password (sop, _("Remote Host Password"), msg, NULL, FALSE);
+    return seahorse_ssh_source_prompt_passphrase (prompt, _("Remote Host Password"),
+                                                  message, NULL, FALSE);
 }
 
-SeahorseOperation*  
-seahorse_ssh_operation_upload (SeahorseSSHSource *ssrc, GList *keys, 
-                               const gchar *username, const gchar *hostname, const gchar *port)
+static void
+on_upload_send_complete (GObject *source,
+                         GAsyncResult *result,
+                         gpointer user_data)
 {
-    SeahorseSSHOperationPrivate *pv;
-    SeahorseOperation *op;
-    GMemoryOutputStream *output;
-    gchar *data;
-    size_t length;
-    gchar *cmd;
-    
-    g_return_val_if_fail (keys != NULL, NULL);
-    g_return_val_if_fail (username && username[0], NULL);
-    g_return_val_if_fail (hostname && hostname[0], NULL);
-    
-    if (port && !port[0])
-        port = NULL;
-    
-    	output = G_MEMORY_OUTPUT_STREAM (g_memory_output_stream_new (NULL, 0, g_realloc, NULL));
-    	g_return_val_if_fail (output, NULL);
-    	
-    	/* Buffer for what we send to the server */
-    	op = seahorse_source_export (SEAHORSE_SOURCE (ssrc), keys, G_OUTPUT_STREAM (output));
-    	g_return_val_if_fail (op != NULL, NULL);
-    
-    /* 
-     * We happen to know that seahorse_ssh_source_export always returns
-     * completed operations, so we don't need to factor that in. If this
-     * ever changes, then we need to recode this bit 
-     */
-    g_return_val_if_fail (!seahorse_operation_is_running (op), NULL);
-    
-    /* Return any errors */
-    if (!seahorse_operation_is_successful (op)) {
-        g_object_unref (output);
-        return op;
-    }
-    
-    /* Free the export operation */
-    g_object_unref (op);
-
-    /* 
-     * This command creates the .ssh directory if necessary (with appropriate permissions) 
-     * and then appends all input data onto the end of .ssh/authorized_keys
-     */
-    /* TODO: Important, we should handle the host checking properly */
-    cmd = g_strdup_printf (SSH_PATH " '%s %s' %s %s -o StrictHostKeyChecking=no "
-                                    "\"umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys\"", 
-                           username, hostname, 
-                           port ? "-p" : "", 
-                           port ? port : "");
-    
-	data = g_memory_output_stream_get_data (output);
-	length = strlen (data);
-	g_object_unref (output);
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	GError *error = NULL;
+
+	if (!seahorse_ssh_operation_finish (SEAHORSE_SSH_SOURCE (source), result, &error))
+		g_simple_async_result_take_error (res, error);
+
+	g_simple_async_result_complete (res);
+	g_object_unref (res);
+}
+
+static void
+on_upload_export_complete (GObject *source,
+                           GAsyncResult *result,
+                           gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	ssh_upload_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	gchar *data;
+	size_t length;
+	gchar *cmd;
+
+	if (!seahorse_source_export_finish (SEAHORSE_SOURCE (source), result, &error)) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
+		g_object_unref (res);
+		return;
+	}
+
+	/*
+	 * This command creates the .ssh directory if necessary (with appropriate permissions)
+	 * and then appends all input data onto the end of .ssh/authorized_keys
+	 */
+	/* TODO: Important, we should handle the host checking properly */
+	cmd = g_strdup_printf (SSH_PATH " '%s %s' %s %s -o StrictHostKeyChecking=no "
+	                       "\"umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys\"",
+	                       closure->username, closure->hostname,
+	                       closure->port ? "-p" : "", closure->port ? closure->port : "");
+
+	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,
+	                              closure->cancellable, on_upload_send_complete,
+	                              on_upload_send_password, g_object_ref (res));
 
-	op = seahorse_ssh_operation_new (ssrc, cmd, data, length, NULL);
-    
 	g_free (cmd);
-	g_free (data);
+	g_object_unref (res);
+}
+
+void
+seahorse_ssh_op_upload_async (SeahorseSSHSource *source,
+                              GList *keys,
+                              const gchar *username,
+                              const gchar *hostname,
+                              const gchar *port,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+	ssh_upload_closure *closure;
+
+	g_return_if_fail (keys != NULL);
+	g_return_if_fail (username && username[0]);
+	g_return_if_fail (hostname && hostname[0]);
+
+	if (port && !port[0])
+		port = NULL;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ssh_op_upload_async);
+	closure = g_new0 (ssh_upload_closure, 1);
+	closure->output = G_MEMORY_OUTPUT_STREAM (g_memory_output_stream_new (NULL, 0, g_realloc, NULL));
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->username = g_strdup (username);
+	closure->hostname = g_strdup (hostname);
+	closure->port = g_strdup (port);
+	g_simple_async_result_set_op_res_gpointer (res, closure, ssh_upload_free);
+
+	/* Buffer for what we send to the server */
+	seahorse_source_export_async (SEAHORSE_SOURCE (source), keys, G_OUTPUT_STREAM (closure->output),
+	                              cancellable, on_upload_export_complete, g_object_ref (res));
 
-    pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (op);
-    pv->password_cb = upload_password_cb;
+	g_object_unref (res);
 
-    return op;
+}
+
+gboolean
+seahorse_ssh_op_upload_finish (SeahorseSSHSource *source,
+                               GAsyncResult *result,
+                               GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_op_change_passphrase_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
 }
 
 /* -----------------------------------------------------------------------------
  * CHANGE PASSPHRASE 
  */
 
-static const gchar*
-change_password_cb (SeahorseSSHOperation *sop, const gchar* msg)
+static const gchar *
+on_change_passphrase_password (SeahorseSshSourcePrompt *prompt,
+                               const gchar* message,
+                               gpointer user_data)
 {
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    const gchar *ret = NULL;
-    gchar *lcase;
-
-    lcase = g_strdup (msg ? msg : "");
-    seahorse_util_string_lower (lcase);
-
-    seahorse_debug ("in change_password_cb");
-
-    /* Need the old passphrase */
-    if (strstr (lcase, "old pass"))
-        ret = prompt_passphrase (sop, _("Old Key Passphrase"), 
-                _("Enter the old passphrase for: %s"), NULL, FALSE);
-        
-    /* Look for the new passphrase thingy */
-    else if (strstr (lcase, "new pass"))
-        ret = prompt_passphrase (sop, _("New Key Passphrase"), 
-                _("Enter the new passphrase for: %s"), NULL, TRUE);
-        
-    /* Confirm the new passphrase, just send it again */
-    else if (strstr (lcase, "again") && pv->prompt_dialog)
-        ret = seahorse_passphrase_prompt_get (pv->prompt_dialog);
-        
-    /* Something we don't understand */
-    else
-        ret = prompt_passphrase (sop, _("Enter Key Passphrase"), msg, NULL, FALSE);
-    
-    g_free (lcase);
-    return ret;
+	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
-change_result_cb (SeahorseSSHOperation *sop)
+on_change_passphrase_complete (GObject *source,
+                               GAsyncResult *result,
+                               gpointer user_data)
 {
-	SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-	if (pv->prompt_skey)
-		seahorse_object_refresh (SEAHORSE_OBJECT (pv->prompt_skey));
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	SeahorseSSHKey *key = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	if (seahorse_ssh_operation_finish (SEAHORSE_SSH_SOURCE (source), result, &error))
+		seahorse_object_refresh (SEAHORSE_OBJECT (key));
+	else
+		g_simple_async_result_take_error (res, error);
+
+	g_simple_async_result_complete (res);
+	g_object_unref (res);
 }
 
-SeahorseOperation*
-seahorse_ssh_operation_change_passphrase (SeahorseSSHKey *skey)
+void
+seahorse_ssh_op_change_passphrase_async  (SeahorseSSHKey *key,
+                                          GCancellable *cancellable,
+                                          GAsyncReadyCallback callback,
+                                          gpointer user_data)
 {
-    SeahorseSSHOperationPrivate *pv;
-    SeahorseSource *ssrc;
-    SeahorseOperation *op;
-    gchar *cmd;
-    
-    g_return_val_if_fail (SEAHORSE_IS_SSH_KEY (skey), NULL);
-    g_return_val_if_fail (skey->keydata && skey->keydata->privfile, NULL);
-    
-    ssrc = seahorse_object_get_source (SEAHORSE_OBJECT (skey));
-    g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (ssrc), NULL);
-    
-    cmd = g_strdup_printf (SSH_KEYGEN_PATH " -p -f '%s'", skey->keydata->privfile);
-    op = seahorse_ssh_operation_new (SEAHORSE_SSH_SOURCE (ssrc), cmd, NULL, -1, skey);
-    g_free (cmd);
-    
-    pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (op);
-    pv->password_cb = change_password_cb;
-    pv->result_cb = change_result_cb;
-    
-    return op;
+	GSimpleAsyncResult *res;
+	SeahorseSource *source;
+	gchar *cmd;
+
+	g_return_if_fail (SEAHORSE_IS_SSH_KEY (key));
+	g_return_if_fail (key->keydata && key->keydata->privfile);
+
+	source = seahorse_object_get_source (SEAHORSE_OBJECT (key));
+	g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (source));
+
+	res = g_simple_async_result_new (G_OBJECT (source), 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));
+
+	g_free (cmd);
+	g_object_unref (res);
+}
+
+gboolean
+seahorse_ssh_op_change_passphrase_finish (SeahorseSSHKey *key,
+                                          GAsyncResult *result,
+                                          GError **error)
+{
+	SeahorseSource *source;
+
+	source = seahorse_object_get_source (SEAHORSE_OBJECT (key));
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_op_change_passphrase_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
 }
 
 /* -----------------------------------------------------------------------------
  * KEY GENERATE OPERATION
- */ 
+ */
+
+typedef struct {
+	gchar *filename;
+	SeahorseSSHKey *key;
+} ssh_generate_closure;
 
 static void
-generate_result_cb (SeahorseSSHOperation *sop)
+ssh_generate_free (gpointer data)
 {
-    SeahorseSSHKey *skey;
-    const char *filename;
-    
-    filename = g_object_get_data (G_OBJECT (sop), "filename");
-    g_return_if_fail (filename != NULL);
-    
-    /* The result of the operation is the key we generated */
-    skey = seahorse_ssh_source_key_for_filename (sop->sksrc, filename);
-    g_return_if_fail (SEAHORSE_IS_SSH_KEY (skey));
-    
-    seahorse_operation_mark_result (SEAHORSE_OPERATION (sop), skey, NULL);
+	ssh_generate_closure *closure = data;
+	g_free (closure->filename);
+	g_clear_object (&closure->key);
+	g_free (closure);
 }
 
-static const gchar*
-generate_password_cb (SeahorseSSHOperation *sop, const gchar* msg)
+static void
+on_generate_complete (GObject *source,
+                      GAsyncResult *result,
+                      gpointer user_data)
 {
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    seahorse_debug ("in generate_password_cb");
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	ssh_generate_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	if (!seahorse_ssh_operation_finish (SEAHORSE_SSH_SOURCE (source), result, &error)) {
+		g_simple_async_result_take_error (res, error);
+
+	} else {
+		/* The result of the operation is the key we generated */
+		closure->key = seahorse_ssh_source_key_for_filename (SEAHORSE_SSH_SOURCE (source),
+		                                                     closure->filename);
+		g_return_if_fail (SEAHORSE_IS_SSH_KEY (closure->key));
+		g_object_ref (closure->key);
+	}
+
+	g_simple_async_result_complete (res);
+	g_object_unref (res);
+}
 
-    /* If the first time then prompt */
-    if (!pv->prompt_dialog) {
-        return prompt_passphrase (sop, _("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 (pv->prompt_dialog);
+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);
 }
 
-SeahorseOperation*
-seahorse_ssh_operation_generate (SeahorseSSHSource *src, const gchar *email, 
-                                 guint type, guint bits)
+void
+seahorse_ssh_op_generate_async (SeahorseSSHSource *source,
+                                const gchar *email,
+                                guint type,
+                                guint bits,
+                                GCancellable *cancellable,
+                                GAsyncReadyCallback callback,
+                                gpointer user_data)
 {
-    SeahorseSSHOperationPrivate *pv;
-    SeahorseOperation *op;
-    gchar *filename, *comment;
-    const gchar *algo;
-    gchar *cmd;
-    
-    filename = seahorse_ssh_source_file_for_algorithm (src, type);
-    g_return_val_if_fail (filename, NULL);
-    
-    comment = escape_shell_arg (email);
-    
-    algo = get_algorithm_text (type);
-    g_return_val_if_fail (algo != NULL, NULL);
-    
-    /* Default number of bits */
-    if (bits == 0)
-        bits = 2048;
-    
-    cmd = g_strdup_printf (SSH_KEYGEN_PATH " -b '%d' -t '%s' -C %s -f '%s'",
-                           bits, algo, comment, filename);
-    g_free (comment);
-    
-    op = seahorse_ssh_operation_new (SEAHORSE_SSH_SOURCE (src), cmd, NULL, -1, NULL);
-    g_free (cmd);
-    
-    pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (op);
-    pv->result_cb = generate_result_cb;
-    pv->password_cb = generate_password_cb;
-    g_object_set_data_full (G_OBJECT (op), "filename", filename, g_free);
-    
-    return op;
+	ssh_generate_closure *closure;
+	GSimpleAsyncResult *res;
+	const gchar *algo;
+	gchar *comment;
+	gchar *cmd;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ssh_op_generate_async);
+	closure = g_new0 (ssh_generate_closure, 1);
+	closure->filename = seahorse_ssh_source_file_for_algorithm (source, type);
+	g_simple_async_result_set_op_res_gpointer (res, closure, ssh_generate_free);
+
+	comment = escape_shell_arg (email);
+	algo = get_algorithm_text (type);
+	g_return_if_fail (algo != NULL);
+
+	/* Default number of bits */
+	if (bits == 0)
+		bits = 2048;
+
+	cmd = g_strdup_printf (SSH_KEYGEN_PATH " -b '%d' -t '%s' -C %s -f '%s'",
+	                       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));
+
+	g_free (cmd);
+	g_object_unref (res);
+}
+
+SeahorseObject *
+seahorse_ssh_op_generate_finish (SeahorseSSHSource *source,
+                                 GAsyncResult *result,
+                                 GError **error)
+{
+	ssh_generate_closure *closure;
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_op_generate_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	return SEAHORSE_OBJECT (closure->key);
 }
 
 /* -----------------------------------------------------------------------------
  * IMPORT A PUBLIC KEY 
  */
 
-SeahorseOperation*
-seahorse_ssh_operation_import_public (SeahorseSSHSource *ssrc, SeahorseSSHKeyData *data,
-                                      const gchar* filename)
+void
+seahorse_ssh_op_import_public_async (SeahorseSSHSource *source,
+                                     SeahorseSSHKeyData *data,
+                                     const gchar* filename,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
 {
-    SeahorseOperation *op;
-    GError *err = NULL;
-    
-    g_return_val_if_fail (seahorse_ssh_key_data_is_valid (data), NULL);
-    g_return_val_if_fail (data->rawdata, NULL);
-    g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (ssrc), NULL);
+	GError *error = NULL;
+	GSimpleAsyncResult *res;
 
-    seahorse_ssh_key_data_filter_file (filename, data, NULL, &err);
-    
-    op = seahorse_operation_new_complete (err);
-    seahorse_operation_mark_result (op, g_strdup (data->fingerprint), g_free);
-    return op;
+	g_return_if_fail (seahorse_ssh_key_data_is_valid (data));
+	g_return_if_fail (data->rawdata);
+	g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (source));
+
+	seahorse_ssh_key_data_filter_file (filename, data, NULL, &error);
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ssh_op_import_public_async);
+	g_simple_async_result_set_op_res_gpointer (res, g_strdup (data->fingerprint), g_free);
+	g_simple_async_result_complete_in_idle (res);
+	g_object_unref (res);
 }
 
+gchar *
+seahorse_ssh_op_import_public_finish (SeahorseSSHSource *source,
+                                      GAsyncResult *result,
+                                      GError **error)
+{
+	const gchar *fingerprint;
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_op_authorize_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	fingerprint = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	return g_strdup (fingerprint);
+}
 
 /* -----------------------------------------------------------------------------
  * IMPORT A PRIVATE KEY 
- */ 
+ */
 
-static const gchar*
-import_password_cb (SeahorseSSHOperation *sop, const gchar* msg)
+typedef struct {
+	gchar *pubfile;
+	gchar *comment;
+	gchar *fingerprint;
+} ssh_import_closure;
+
+static void
+ssh_import_free (gpointer data)
 {
-    const gchar *comment;
-    const gchar *ret;
-    gchar* message;
-    
-    /* Add the comment to the output */
-    comment = (const gchar*)g_object_get_data (G_OBJECT (sop), "import-comment");
-    if (comment)
-        message = g_strdup_printf (_("Importing key: %s"), comment);
-    else
-        message = g_strdup (_("Importing key. Enter passphrase"));
-    
-    ret = prompt_passphrase (sop, _("Import Key"), message, NULL, FALSE);
-    g_free (message);
-    
-    return ret;
+	ssh_import_closure *closure = data;
+	g_free (closure->pubfile);
+	g_free (closure->comment);
+	g_free (closure->fingerprint);
+	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
-import_result_cb (SeahorseSSHOperation *sop)
+on_import_private_complete (GObject *source,
+                            GAsyncResult *result,
+                            gpointer user_data)
 {
-    SeahorseSSHOperationPrivate *pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (sop);
-    SeahorseSSHKeyData *keydata;
-    const gchar *pubfile;
-    const gchar *comment;
-    GError *err = NULL;
-    gsize pos;
-    
-    g_assert (seahorse_operation_is_running (SEAHORSE_OPERATION (sop)));
-    
-    /* Only use the first line of the output */
-    pos = strcspn (pv->sout->str, "\n\r");
-    if (pos < pv->sout->len)
-        g_string_erase (pv->sout, pos, -1);
-    
-    /* Parse the data so we can get the fingerprint */
-    keydata = seahorse_ssh_key_data_parse_line (pv->sout->str, -1);
-    if (seahorse_ssh_key_data_is_valid (keydata))
-        seahorse_operation_mark_result (SEAHORSE_OPERATION (sop),
-                                        g_strdup (keydata->fingerprint), g_free);
-    else
-        g_warning ("couldn't parse imported private key fingerprint");
-    seahorse_ssh_key_data_free (keydata);
-    
-    /* Add the comment to the output */
-    comment = (const gchar*)g_object_get_data (G_OBJECT (sop), "import-comment");
-    if (comment) {
-        g_string_append_c (pv->sout, ' ');
-        g_string_append (pv->sout, comment);
-    }
-    
-    /* The file to write to */
-    pubfile = (const gchar*)g_object_get_data (G_OBJECT (sop), "import-file");
-    g_assert (pubfile);
-    
-    if (!seahorse_util_write_file_private (pubfile, pv->sout->str, &err))
-        seahorse_operation_mark_done (SEAHORSE_OPERATION (sop), FALSE, err);
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	ssh_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	SeahorseSSHKeyData *keydata;
+	GError *error = NULL;
+	GString *output;
+	gsize pos;
+
+	output = seahorse_ssh_operation_finish (SEAHORSE_SSH_SOURCE (source), result, &error);
+	if (error == NULL) {
+		/* Only use the first line of the output */
+		pos = strcspn (output->str, "\n\r");
+		if (pos < output->len)
+			g_string_erase (output, pos, -1);
+
+		/* Parse the data so we can get the fingerprint */
+		keydata = seahorse_ssh_key_data_parse_line (output->str, -1);
+		if (seahorse_ssh_key_data_is_valid (keydata))
+			closure->fingerprint = g_strdup (keydata->fingerprint);
+		else
+			g_warning ("couldn't parse imported private key fingerprint");
+		seahorse_ssh_key_data_free (keydata);
+
+		/* Add the comment to the output */
+		if (closure->comment) {
+			g_string_append_c (output, ' ');
+			g_string_append (output, closure->comment);
+		}
+
+		/* The file to write to */
+		seahorse_util_write_file_private (closure->pubfile, output->str, &error);
+	}
+
+	if (error != NULL)
+		g_simple_async_result_take_error (res, error);
+	g_simple_async_result_complete (res);
+	g_object_unref (res);
 }
 
-SeahorseOperation*
-seahorse_ssh_operation_import_private (SeahorseSSHSource *ssrc, SeahorseSSHSecData *data,
-                                       const gchar *filename)
+void
+seahorse_ssh_op_import_private_async (SeahorseSSHSource *source,
+                                      SeahorseSSHSecData *data,
+                                      const gchar *filename,
+                                      GCancellable *cancellable,
+                                      GAsyncReadyCallback callback,
+                                      gpointer user_data)
 {
-    SeahorseSSHOperationPrivate *pv;
-    SeahorseOperation *op;
-    gchar *cmd, *privfile = NULL;
-    GError *err = NULL;
-    
-    g_return_val_if_fail (data && data->rawdata, NULL);
-    g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (ssrc), NULL);
-    
-    /* No filename specified, make one up */
-    if (!filename) {
-        filename = privfile = seahorse_ssh_source_file_for_algorithm (ssrc, data->algo);
-        g_return_val_if_fail (privfile, NULL);
-    }
-    
-    /* Write the private key into the file */
-    if (!seahorse_util_write_file_private (filename, data->rawdata, &err)) {
-        g_free (privfile);
-        return seahorse_operation_new_complete (err);
-    }
-    
-    /* Start command to generate public key */
-    cmd = g_strdup_printf (SSH_KEYGEN_PATH " -y -f '%s'", privfile);
-    op = seahorse_ssh_operation_new (ssrc, cmd, NULL, 0, NULL);
-    g_free (cmd);
-    
-    g_object_set_data_full (G_OBJECT (op), "import-file", 
-                g_strdup_printf ("%s.pub", filename), g_free);
-    g_object_set_data_full (G_OBJECT (op), "import-comment",
-                g_strdup (data->comment), g_free);
-    
-    g_free (privfile);
-    
-    pv = SEAHORSE_SSH_OPERATION_GET_PRIVATE (op);
-    pv->result_cb = import_result_cb;
-    pv->password_cb = import_password_cb;
-    
-    return op;
+	GSimpleAsyncResult *res;
+	gchar *cmd, *privfile = NULL;
+	GError *error = NULL;
+	ssh_import_closure *closure;
+
+	g_return_if_fail (data && data->rawdata);
+	g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (source));
+
+	/* No filename specified, make one up */
+	if (!filename) {
+		filename = privfile = seahorse_ssh_source_file_for_algorithm (source, data->algo);
+		g_return_if_fail (privfile);
+	}
+
+	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);
+	closure->pubfile = g_strdup_printf ("%s.pub", filename);
+	closure->comment = g_strdup (data->comment);
+	g_simple_async_result_set_op_res_gpointer (res, closure, ssh_import_free);
+
+	/* Write the private key into the file */
+	if (!seahorse_util_write_file_private (filename, data->rawdata, &error)) {
+		g_free (privfile);
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		g_object_unref (res);
+		return;
+	}
+
+	/* 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,
+	                              g_object_ref (res));
+	g_free (cmd);
+
+	g_object_unref (res);
+	g_free (privfile);
+
+}
+
+gchar *
+seahorse_ssh_op_import_private_finish (SeahorseSSHSource *source,
+                                       GAsyncResult *result,
+                                       GError **error)
+{
+	ssh_import_closure *closure;
+	gchar *fingerprint;
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_op_import_private_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	fingerprint = closure->fingerprint;
+	closure->fingerprint = NULL;
+	return fingerprint;
+
 }
 
 /* -----------------------------------------------------------------------------
  * AUTHORIZE A PUBLIC KEY 
  */ 
 
-SeahorseOperation*
-seahorse_ssh_operation_authorize (SeahorseSSHSource *ssrc, SeahorseSSHKey *skey,
-                                  gboolean authorize)
+void
+seahorse_ssh_op_authorize_async (SeahorseSSHSource *source,
+                                 SeahorseSSHKey *key,
+                                 gboolean authorize,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
 {
-    SeahorseSSHKeyData *keydata = NULL;
-    GError *err = NULL;
-    gchar* from = NULL;
-    gchar* to = NULL;
-    
-    g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (ssrc), NULL);
-    g_return_val_if_fail (SEAHORSE_IS_SSH_KEY (skey), NULL);
-    
-    g_object_get (skey, "key-data", &keydata, NULL);
-    g_return_val_if_fail (keydata, NULL);
-    
-    if (authorize) {
-        to = seahorse_ssh_source_file_for_public (ssrc, TRUE);
-    } else {
-        from = seahorse_ssh_source_file_for_public (ssrc, TRUE);
-        to = seahorse_ssh_source_file_for_public (ssrc, FALSE);
-    }
-    
-    /* Take it out of the from file, and put into the to file */
-    if (!from || seahorse_ssh_key_data_filter_file (from, NULL, keydata, &err))
-        seahorse_ssh_key_data_filter_file (to, keydata, NULL, &err);
-    
-    g_free (from);
-    g_free (to);
-    
-    /* Just reload that one key */
-    if (!err)
-        seahorse_object_refresh (SEAHORSE_OBJECT (skey));
-    
-    return seahorse_operation_new_complete (err);
+	SeahorseSSHKeyData *keydata = NULL;
+	GError *error = NULL;
+	gchar* from = NULL;
+	gchar* to = NULL;
+	GSimpleAsyncResult *res;
+
+	g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (source));
+	g_return_if_fail (SEAHORSE_IS_SSH_KEY (key));
+
+	g_object_get (key, "key-data", &keydata, NULL);
+	g_return_if_fail (keydata);
+
+	if (authorize) {
+		to = seahorse_ssh_source_file_for_public (source, TRUE);
+	} else {
+		from = seahorse_ssh_source_file_for_public (source, TRUE);
+		to = seahorse_ssh_source_file_for_public (source, FALSE);
+	}
+
+	/* Take it out of the from file, and put into the to file */
+	if (!from || seahorse_ssh_key_data_filter_file (from, NULL, keydata, &error))
+		seahorse_ssh_key_data_filter_file (to, keydata, NULL, &error);
+
+	g_free (from);
+	g_free (to);
+
+	/* Just reload that one key */
+	if (!error)
+		seahorse_object_refresh (SEAHORSE_OBJECT (key));
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ssh_op_authorize_async);
+	if (error != NULL)
+		g_simple_async_result_take_error (res, error);
+	g_simple_async_result_complete_in_idle (res);
+	g_object_unref (res);
+}
+
+gboolean
+seahorse_ssh_op_authorize_finish (SeahorseSSHSource *source,
+                                  GAsyncResult *result,
+                                  GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_op_authorize_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
 }
 
 /* -----------------------------------------------------------------------------
@@ -1160,39 +1301,107 @@ change_raw_comment (SeahorseSSHKeyData *keydata, const gchar *newcomment)
     return TRUE;
 }
 
-SeahorseOperation*
-seahorse_ssh_operation_rename (SeahorseSSHSource *ssrc, SeahorseSSHKey *skey,
-                               const gchar *newcomment)
+void
+seahorse_ssh_op_rename_async (SeahorseSSHSource *source,
+                              SeahorseSSHKey *key,
+                              const gchar *newcomment,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
 {
-    SeahorseSSHKeyData *keydata;
-    GError *err = NULL;
-    
-    g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (ssrc), NULL);
-    g_return_val_if_fail (SEAHORSE_IS_SSH_KEY (skey), NULL);
-    g_assert (seahorse_ssh_key_data_is_valid (skey->keydata));
-    g_assert (skey->keydata->rawdata);
-    
-    keydata = seahorse_ssh_key_data_dup (skey->keydata);
-    
-    if (!newcomment)
-        newcomment = "";
-    
-    if (!change_raw_comment (keydata, newcomment ? newcomment : ""))
-        g_return_val_if_reached (NULL);
+	SeahorseSSHKeyData *keydata;
+	GSimpleAsyncResult *res;
+	GError *error = NULL;
 
-    seahorse_debug ("renaming key to: %s", newcomment);
-
-    /* Just part of a file for this key */
-    if (keydata->partial) {
-        g_assert (keydata->pubfile);
-        seahorse_ssh_key_data_filter_file (keydata->pubfile, keydata, keydata, &err);
-        
-    /* A full file for this key */
-    } else {
-        g_assert (keydata->pubfile);
-        seahorse_util_write_file_private (keydata->pubfile, keydata->rawdata, &err);
-    }
-    
-    seahorse_ssh_key_data_free (keydata);
-    return seahorse_operation_new_complete (err);
+	g_return_if_fail (SEAHORSE_IS_SSH_SOURCE (source));
+	g_return_if_fail (SEAHORSE_IS_SSH_KEY (key));
+
+	keydata = seahorse_ssh_key_data_dup (key->keydata);
+
+	if (!newcomment)
+		newcomment = "";
+
+	if (!change_raw_comment (keydata, newcomment ? newcomment : ""))
+		g_return_if_reached ();
+
+	seahorse_debug ("renaming key to: %s", newcomment);
+
+	/* Just part of a file for this key */
+	if (keydata->partial) {
+		g_assert (keydata->pubfile);
+		seahorse_ssh_key_data_filter_file (keydata->pubfile, keydata, keydata, &error);
+
+		/* A full file for this key */
+	} else {
+		g_assert (keydata->pubfile);
+		seahorse_util_write_file_private (keydata->pubfile, keydata->rawdata, &error);
+	}
+
+	seahorse_ssh_key_data_free (keydata);
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ssh_op_rename_async);
+	if (error != NULL)
+		g_simple_async_result_take_error (res, error);
+	g_simple_async_result_complete_in_idle (res);
+	g_object_unref (res);
 }
+
+gboolean
+seahorse_ssh_op_rename_finish (SeahorseSSHSource *source,
+                               GAsyncResult *result,
+                               GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_op_rename_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
+
+gboolean
+seahorse_ssh_op_delete_sync (SeahorseSSHKey *key,
+                             GError **error)
+{
+	SeahorseSSHKeyData *keydata = NULL;
+	gboolean ret = TRUE;
+
+	g_return_val_if_fail (SEAHORSE_IS_SSH_KEY (key), FALSE);
+
+	g_object_get (key, "key-data", &keydata, NULL);
+	g_return_val_if_fail (keydata, FALSE);
+
+	/* Just part of a file for this key */
+	if (keydata->partial) {
+		/* Take just that line out of the file */
+		if (keydata->pubfile)
+			ret = seahorse_ssh_key_data_filter_file (keydata->pubfile, NULL, keydata, error);
+
+	/* A full file for this key */
+	} else {
+		if (keydata->pubfile) {
+			if (g_unlink (keydata->pubfile) == -1) {
+				g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+				             "%s", g_strerror (errno));
+				ret = FALSE;
+			}
+		}
+
+		if (ret && keydata->privfile) {
+			if (g_unlink (keydata->privfile) == -1) {
+				g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+				             "%s", g_strerror (errno));
+				ret = FALSE;
+			}
+		}
+	}
+
+	if (ret)
+		seahorse_context_remove_object (seahorse_context_instance (),
+		                                SEAHORSE_OBJECT (key));
+
+	return ret;
+}
+
diff --git a/ssh/seahorse-ssh-operation.h b/ssh/seahorse-ssh-operation.h
index f8f59c9..2723eba 100644
--- a/ssh/seahorse-ssh-operation.h
+++ b/ssh/seahorse-ssh-operation.h
@@ -18,81 +18,93 @@
  * 59 Temple Place, Suite 330,
  * Boston, MA 02111-1307, USA.
  */
-
-/** 
- * SeahorsePGPOperation: Operations to be done on SSH keys
- * 
- * - Derived from SeahorseOperation
- *
- * Properties:
- *  TODO: 
- */
  
 #ifndef __SEAHORSE_SSH_OPERATION_H__
 #define __SEAHORSE_SSH_OPERATION_H__
 
-#include "seahorse-operation.h"
 #include "seahorse-ssh-source.h"
 #include "seahorse-ssh-key.h"
 
-#define SEAHORSE_TYPE_SSH_OPERATION            (seahorse_ssh_operation_get_type ())
-#define SEAHORSE_SSH_OPERATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEAHORSE_TYPE_SSH_OPERATION, SeahorseSSHOperation))
-#define SEAHORSE_SSH_OPERATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SEAHORSE_TYPE_SSH_OPERATION, SeahorseSSHOperationClass))
-#define SEAHORSE_IS_SSH_OPERATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAHORSE_TYPE_SSH_OPERATION))
-#define SEAHORSE_IS_SSH_OPERATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SEAHORSE_TYPE_SSH_OPERATION))
-#define SEAHORSE_SSH_OPERATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SEAHORSE_TYPE_SSH_OPERATION, SeahorseSSHOperationClass))
-
-DECLARE_OPERATION (SSH, ssh)
+/* result: nothing */
+void              seahorse_ssh_op_upload_async             (SeahorseSSHSource *source,
+                                                            GList *keys,
+                                                            const gchar *username,
+                                                            const gchar *hostname,
+                                                            const gchar *port,
+                                                            GCancellable *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer user_data);
 
-    /*< public >*/
-    SeahorseSSHSource *sksrc;
-    
-END_DECLARE_OPERATION
+gboolean          seahorse_ssh_op_upload_finish            (SeahorseSSHSource *source,
+                                                            GAsyncResult *result,
+                                                            GError **error);
 
-SeahorseOperation*   seahorse_ssh_operation_new          (SeahorseSSHSource *ssrc,
-                                                          const gchar *command, 
-                                                          const gchar *input, 
-                                                          gint length,
-                                                          SeahorseSSHKey *key);
+void              seahorse_ssh_op_generate_async           (SeahorseSSHSource *source,
+                                                            const gchar *email,
+                                                            guint type,
+                                                            guint bits,
+                                                            GCancellable *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer user_data);
 
-gchar*               seahorse_ssh_operation_sync         (SeahorseSSHSource *ssrc,
-                                                          const gchar *command, 
-                                                          GError **error);
+SeahorseObject *  seahorse_ssh_op_generate_finish          (SeahorseSSHSource *source,
+                                                            GAsyncResult *result,
+                                                            GError **error);
 
-/* result: nothing */
-SeahorseOperation*   seahorse_ssh_operation_upload       (SeahorseSSHSource *ssrc,
-                                                          GList *keys,
-                                                          const gchar *username,
-                                                          const gchar *hostname, 
-                                                          const gchar *port);
-
-/* result: the generated SeahorseKey */
-SeahorseOperation*   seahorse_ssh_operation_generate     (SeahorseSSHSource *src, 
-                                                          const gchar *email, 
-                                                          guint type, 
-                                                          guint bits);
+void              seahorse_ssh_op_change_passphrase_async  (SeahorseSSHKey *key,
+                                                            GCancellable *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer user_data);
 
-/* result: nothing */
-SeahorseOperation*   seahorse_ssh_operation_change_passphrase (SeahorseSSHKey *skey);
+gboolean          seahorse_ssh_op_change_passphrase_finish (SeahorseSSHKey *key,
+                                                            GAsyncResult *result,
+                                                            GError **error);
 
-/* result: fingerprint of imported key */
-SeahorseOperation*   seahorse_ssh_operation_import_public  (SeahorseSSHSource *ssrc,
+void              seahorse_ssh_op_import_public_async      (SeahorseSSHSource *source,
                                                             SeahorseSSHKeyData *data,
-                                                            const gchar* filename);
+                                                            const gchar* filename,
+                                                            GCancellable *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer user_data);
+
+gchar *           seahorse_ssh_op_import_public_finish     (SeahorseSSHSource *source,
+                                                            GAsyncResult *result,
+                                                            GError **error);
 
-/* result: fingerprint of imported key */
-SeahorseOperation*   seahorse_ssh_operation_import_private (SeahorseSSHSource *ssrc, 
+void              seahorse_ssh_op_import_private_async     (SeahorseSSHSource *source,
                                                             SeahorseSSHSecData *data,
-                                                            const gchar* filename);
+                                                            const gchar* filename,
+                                                            GCancellable *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer user_data);
 
-/* result: nothing */
-SeahorseOperation*  seahorse_ssh_operation_authorize       (SeahorseSSHSource *ssrc,
-                                                            SeahorseSSHKey *skey,
-                                                            gboolean authorize);
+gchar *           seahorse_ssh_op_import_private_finish    (SeahorseSSHSource *source,
+                                                            GAsyncResult *result,
+                                                            GError **error);
 
-/* result: nothing */
-SeahorseOperation*  seahorse_ssh_operation_rename          (SeahorseSSHSource *ssrc,
+void              seahorse_ssh_op_authorize_async          (SeahorseSSHSource *source,
                                                             SeahorseSSHKey *skey,
-                                                            const gchar *newcomment);
+                                                            gboolean authorize,
+                                                            GCancellable *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer user_data);
+
+gboolean          seahorse_ssh_op_authorize_finish         (SeahorseSSHSource *source,
+                                                            GAsyncResult *result,
+                                                            GError **error);
+
+void              seahorse_ssh_op_rename_async             (SeahorseSSHSource *source,
+                                                            SeahorseSSHKey *key,
+                                                            const gchar *newcomment,
+                                                            GCancellable *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer user_data);
+
+gboolean          seahorse_ssh_op_rename_finish            (SeahorseSSHSource *source,
+                                                            GAsyncResult *result,
+                                                            GError **error);
+
+gboolean          seahorse_ssh_op_delete_sync              (SeahorseSSHKey *key,
+                                                            GError **error);
 
 #endif /* __SEAHORSE_SSH_OPERATION_H__ */
diff --git a/ssh/seahorse-ssh-source.c b/ssh/seahorse-ssh-source.c
index 8551361..b927d34 100644
--- a/ssh/seahorse-ssh-source.c
+++ b/ssh/seahorse-ssh-source.c
@@ -27,7 +27,6 @@
 #include "seahorse-ssh-key.h"
 #include "seahorse-ssh-operation.h"
 
-#include "seahorse-operation.h"
 #include "seahorse-util.h"
 
 #include "common/seahorse-registry.h"
@@ -57,19 +56,6 @@ struct _SeahorseSSHSourcePrivate {
     GFileMonitor *monitor_handle;           /* For monitoring the .ssh directory */
 };
 
-typedef struct _LoadContext {
-    SeahorseSSHSource *ssrc;
-    GHashTable *loaded;
-    GHashTable *checks;
-    gchar *pubfile;
-    gchar *privfile;
-} LoadContext;
-
-typedef struct _ImportContext {
-    SeahorseSSHSource *ssrc;
-    SeahorseMultiOperation *mop;
-} ImportContext;
-
 static void seahorse_source_iface (SeahorseSourceIface *iface);
 
 G_DEFINE_TYPE_EXTENDED (SeahorseSSHSource, seahorse_ssh_source, G_TYPE_OBJECT, 0,
@@ -153,7 +139,7 @@ scheduled_refresh (SeahorseSSHSource *ssrc)
 {
     seahorse_debug ("scheduled refresh event ocurring now");
     cancel_scheduled_refresh (ssrc);
-    seahorse_source_load_async (SEAHORSE_SOURCE (ssrc));
+    seahorse_source_load_async (SEAHORSE_SOURCE (ssrc), NULL, NULL, NULL);
     return FALSE; /* don't run again */    
 }
 
@@ -222,370 +208,6 @@ merge_keydata (SeahorseSSHKey *prev, SeahorseSSHKeyData *keydata)
         
 }
 
-static SeahorseSSHKey*
-ssh_key_from_data (SeahorseSSHSource *ssrc, LoadContext *ctx, 
-                   SeahorseSSHKeyData *keydata)
-{   
-    SeahorseSource *sksrc = SEAHORSE_SOURCE (ssrc);
-    SeahorseSSHKey *skey;
-    SeahorseObject *prev;
-    GQuark keyid;
-
-    g_assert (ctx);
-
-    if (!seahorse_ssh_key_data_is_valid (keydata)) {
-        seahorse_ssh_key_data_free (keydata);
-        return NULL;
-    }
-
-    /* Make sure it's valid */
-    keyid = seahorse_ssh_key_calc_cannonical_id (keydata->fingerprint);
-    g_return_val_if_fail (keyid, NULL);
-
-    /* Does this key exist in the context? */
-    prev = seahorse_context_get_object (SCTX_APP (), sksrc, keyid);
-    
-    /* Mark this key as seen */
-    if (ctx->checks)
-        g_hash_table_remove (ctx->checks, GUINT_TO_POINTER (keyid));
-
-    if (ctx->loaded) {
-
-        /* See if we've already gotten a key like this in this load batch */
-        if (g_hash_table_lookup (ctx->loaded, GUINT_TO_POINTER (keyid))) {
-            
-            /* 
-             * Sometimes later keys loaded have more information (for 
-             * example keys loaded from authorized_keys), so propogate 
-             * that up to the previously loaded key 
-             */
-            merge_keydata (SEAHORSE_SSH_KEY (prev), keydata);
-            
-            seahorse_ssh_key_data_free (keydata);
-            return NULL;
-        }
-        
-        /* Mark this key as loaded */
-        g_hash_table_insert (ctx->loaded, GUINT_TO_POINTER (keyid), 
-                                          GUINT_TO_POINTER (TRUE));
-    }
-     
-    /* If we already have this key then just transfer ownership of keydata */
-    if (prev) {
-        g_object_set (prev, "key-data", keydata, NULL);
-        return SEAHORSE_SSH_KEY (prev);
-    }
-
-    /* Create a new key */        
-    g_assert (keydata);
-    skey = seahorse_ssh_key_new (sksrc, keydata);
-
-    seahorse_context_take_object (SCTX_APP (), SEAHORSE_OBJECT (skey));
-    return skey;
-}
-
-static gboolean
-parsed_authorized_key (SeahorseSSHKeyData *data, gpointer arg)
-{
-    LoadContext *ctx = (LoadContext*)arg;
-    
-    g_assert (ctx);
-    g_assert (SEAHORSE_IS_SSH_SOURCE (ctx->ssrc));
-
-    data->pubfile = g_strdup (ctx->pubfile);
-    data->partial = TRUE;
-    data->authorized = TRUE;
-    
-    /* Check and register thet key with the context, frees keydata */
-    ssh_key_from_data (ctx->ssrc, ctx, data);
-    
-    return TRUE;
-}
-
-static gboolean
-parsed_other_key (SeahorseSSHKeyData *data, gpointer arg)
-{
-    LoadContext *ctx = (LoadContext*)arg;
-    
-    g_assert (ctx);
-    g_assert (SEAHORSE_IS_SSH_SOURCE (ctx->ssrc));
-
-    data->pubfile = g_strdup (ctx->pubfile);
-    data->partial = TRUE;
-    data->authorized = FALSE;
-    
-    /* Check and register thet key with the context, frees keydata */
-    ssh_key_from_data (ctx->ssrc, ctx, data);
-    
-    return TRUE;
-}
-
-static gboolean
-parsed_public_key (SeahorseSSHKeyData *data, gpointer arg)
-{
-    LoadContext *ctx = (LoadContext*)arg;
-    
-    g_assert (ctx);
-    g_assert (SEAHORSE_IS_SSH_SOURCE (ctx->ssrc));
-
-    data->pubfile = g_strdup (ctx->pubfile);
-    data->privfile = g_strdup (ctx->privfile);
-    data->partial = FALSE;
-    
-    /* Check and register thet key with the context, frees keydata */
-    ssh_key_from_data (ctx->ssrc, ctx, data);
-    
-    return TRUE;
-}
-
-static GHashTable*
-load_present_keys (SeahorseSource *sksrc)
-{
-    GList *keys, *l;
-    GHashTable *checks;
-
-    checks = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
-    keys = seahorse_context_get_objects (SCTX_APP (), sksrc);
-    for (l = keys; l; l = g_list_next (l))
-        g_hash_table_insert (checks, GUINT_TO_POINTER (seahorse_object_get_id (l->data)), 
-                                     GUINT_TO_POINTER (TRUE));
-    g_list_free (keys);
-    return checks;
-}
-
-static gboolean
-import_public_key (SeahorseSSHKeyData *data, gpointer arg)
-{
-    ImportContext *ctx = (ImportContext*)arg;
-    gchar *fullpath;
-    
-    g_assert (data->rawdata);
-    g_assert (SEAHORSE_IS_MULTI_OPERATION (ctx->mop));
-    g_assert (SEAHORSE_IS_SSH_SOURCE (ctx->ssrc));
-
-    fullpath = seahorse_ssh_source_file_for_public (ctx->ssrc, FALSE);
-    seahorse_multi_operation_take (ctx->mop, 
-                seahorse_ssh_operation_import_public (ctx->ssrc, data, fullpath));
-    g_free (fullpath);
-    seahorse_ssh_key_data_free (data);
-    return TRUE;
-}
-
-static gboolean
-import_private_key (SeahorseSSHSecData *data, gpointer arg)
-{
-    ImportContext *ctx = (ImportContext*)arg;
-    
-    g_assert (SEAHORSE_IS_MULTI_OPERATION (ctx->mop));
-    g_assert (SEAHORSE_IS_SSH_SOURCE (ctx->ssrc));
-    
-    seahorse_multi_operation_take (ctx->mop, 
-                seahorse_ssh_operation_import_private (ctx->ssrc, data, NULL));
-    
-    seahorse_ssh_sec_data_free (data);
-    return TRUE;
-}
-
-/* -----------------------------------------------------------------------------
- * OBJECT
- */
-
-static SeahorseOperation*
-seahorse_ssh_source_load (SeahorseSource *sksrc)
-{
-    SeahorseSSHSource *ssrc;
-    GError *err = NULL;
-    LoadContext ctx;
-    const gchar *filename;
-    GDir *dir;
-    
-    g_assert (SEAHORSE_IS_SSH_SOURCE (sksrc));
-    ssrc = SEAHORSE_SSH_SOURCE (sksrc);
- 
-    /* Schedule a dummy refresh. This blocks all monitoring for a while */
-    cancel_scheduled_refresh (ssrc);
-    ssrc->priv->scheduled_refresh = g_timeout_add (500, (GSourceFunc)scheduled_dummy, ssrc);
-    seahorse_debug ("scheduled a dummy refresh");
-
-    /* List the .ssh directory for private keys */
-    dir = g_dir_open (ssrc->priv->ssh_homedir, 0, &err);
-    if (!dir)
-        return seahorse_operation_new_complete (err);
-
-    memset (&ctx, 0, sizeof (ctx));
-    ctx.ssrc = ssrc;
-    
-    /* Since we can find duplicate keys, limit them with this hash */
-    ctx.loaded = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
-    
-    /* Keys that currently exist, so we can remove any that disappeared */
-    ctx.checks = load_present_keys (sksrc);
-
-    /* For each private key file */
-    for(;;) {
-        filename = g_dir_read_name (dir);
-        if (filename == NULL)
-            break;
-
-        ctx.privfile = g_build_filename (ssrc->priv->ssh_homedir, filename, NULL);
-        ctx.pubfile = g_strconcat (ctx.privfile, ".pub", NULL);
-        
-        /* possibly an SSH key? */
-        if (g_file_test (ctx.privfile, G_FILE_TEST_EXISTS) && 
-            g_file_test (ctx.pubfile, G_FILE_TEST_EXISTS) &&
-            check_file_for_ssh_private (ssrc, ctx.privfile)) {
-                
-            seahorse_ssh_key_data_parse_file (ctx.pubfile, parsed_public_key, NULL, &ctx, &err);
-            if (err != NULL) {
-                g_warning ("couldn't read SSH file: %s (%s)", ctx.pubfile, err->message);
-                g_clear_error (&err);
-            }
-        }
-        
-        g_free (ctx.privfile);
-        g_free (ctx.pubfile);
-        ctx.privfile = ctx.pubfile = NULL;
-    }
-
-    g_dir_close (dir);
-    
-    /* Now load the authorized file */
-    ctx.privfile = NULL;
-    ctx.pubfile = seahorse_ssh_source_file_for_public (ssrc, TRUE);
-        
-    if (g_file_test (ctx.pubfile, G_FILE_TEST_EXISTS)) {
-        seahorse_ssh_key_data_parse_file (ctx.pubfile, parsed_authorized_key, NULL, &ctx, &err);
-        if (err != NULL) {
-            g_warning ("couldn't read SSH file: %s (%s)", ctx.pubfile, err->message);
-            g_clear_error (&err);
-        }
-    }
-        
-    g_free (ctx.pubfile);
-    ctx.pubfile = NULL;
-    
-    /* Load the other keys file */
-    ctx.privfile = NULL;
-    ctx.pubfile = seahorse_ssh_source_file_for_public (ssrc, FALSE);
-    if (g_file_test (ctx.pubfile, G_FILE_TEST_EXISTS)) {
-        seahorse_ssh_key_data_parse_file (ctx.pubfile, parsed_other_key, NULL, &ctx, &err);
-        if (err != NULL) {
-            g_warning ("couldn't read SSH file: %s (%s)", ctx.pubfile, err->message);
-            g_clear_error (&err);
-        }
-    }
-        
-    g_free (ctx.pubfile);
-    ctx.pubfile = NULL;
-
-    /* Clean up and done */
-    if (ctx.checks) {
-        g_hash_table_foreach (ctx.checks, (GHFunc)remove_key_from_context, ssrc);
-        g_hash_table_destroy (ctx.checks);
-    }
-    
-    g_hash_table_destroy (ctx.loaded);
-
-    return seahorse_operation_new_complete (NULL);
-}
-
-static SeahorseOperation* 
-seahorse_ssh_source_import (SeahorseSource *sksrc, GInputStream *input)
-{
-    SeahorseSSHSource *ssrc = SEAHORSE_SSH_SOURCE (sksrc);
-    ImportContext ctx;
-    gchar *contents;
-    
-    	g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (ssrc), NULL);
-    	g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
-
-    	contents = (gchar*)seahorse_util_read_to_memory (input, NULL);
-    
-    memset (&ctx, 0, sizeof (ctx));
-    ctx.ssrc = ssrc;
-    ctx.mop = seahorse_multi_operation_new ();
-    
-    seahorse_ssh_key_data_parse (contents, import_public_key, import_private_key, &ctx);
-    g_free (contents);
-    
-    /* TODO: The list of keys imported? */
-    
-    return SEAHORSE_OPERATION (ctx.mop);
-}
-
-static SeahorseOperation* 
-seahorse_ssh_source_export (SeahorseSource *sksrc, GList *keys, 
-                            GOutputStream *output)
-{
-    SeahorseSSHKeyData *keydata;
-    SeahorseOperation *op;
-    gchar *results = NULL;
-    gchar *raw = NULL;
-    GError *error = NULL;
-    SeahorseObject *object;
-    GList *l;
-    gsize written;
-    
-    g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (sksrc), NULL);
-    g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), NULL);
-    
-    for (l = keys; l; l = g_list_next (l)) {
-        object = SEAHORSE_OBJECT (l->data);
-        
-        g_assert (SEAHORSE_IS_SSH_KEY (object));
-        
-        results = NULL;
-        raw = NULL;
-        
-        keydata = NULL;
-        g_object_get (object, "key-data", &keydata, NULL);
-        g_return_val_if_fail (keydata, NULL);
-        
-        /* We should already have the data loaded */
-        if (keydata->pubfile) { 
-            g_assert (keydata->rawdata);
-            results = g_strdup_printf ("%s", keydata->rawdata);
-            
-        /* Public key without identity.pub. Export it. */
-        } else if (!keydata->pubfile) {
-            
-            /* 
-             * TODO: We should be able to get at this data by using ssh-keygen 
-             * to make a public key from the private 
-             */
-            g_warning ("private key without public, not exporting: %s", keydata->privfile);
-        }
-        
-        	/* Write the data out */
-        	if (results) {
-        		if (g_output_stream_write_all (output, results, strlen (results), 
-        		                               &written, NULL, &error))
-        			g_output_stream_flush (output, NULL, &error);
-        		g_free (results);
-        	}
-
-        	g_free (raw);
-        
-        	if (error != NULL)
-        		break;
-    	}
-    
-    	if (error == NULL)
-    		g_output_stream_close (output, NULL, &error);
-    
-    	op = seahorse_operation_new_complete (error);
-    	g_object_ref (output);
-    	seahorse_operation_mark_result (op, output, g_object_unref);
-    	return op;
-}
-
-static void 
-seahorse_ssh_source_set_property (GObject *object, guint prop_id, const GValue *value, 
-                                  GParamSpec *pspec)
-{
-    
-}
-
 static void 
 seahorse_ssh_source_get_property (GObject *object, guint prop_id, GValue *value, 
                                   GParamSpec *pspec)
@@ -676,12 +298,9 @@ static void
 seahorse_ssh_source_class_init (SeahorseSSHSourceClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-   
-    seahorse_ssh_source_parent_class = g_type_class_peek_parent (klass);
-    
+
     gobject_class->dispose = seahorse_ssh_source_dispose;
     gobject_class->finalize = seahorse_ssh_source_finalize;
-    gobject_class->set_property = seahorse_ssh_source_set_property;
     gobject_class->get_property = seahorse_ssh_source_get_property;
     
 	g_object_class_override_property (gobject_class, PROP_SOURCE_TAG, "source-tag");
@@ -696,12 +315,506 @@ seahorse_ssh_source_class_init (SeahorseSSHSourceClass *klass)
 	seahorse_registry_register_function (NULL, seahorse_ssh_key_calc_cannonical_id, "canonize", SEAHORSE_SSH_STR, NULL);
 }
 
+
+typedef struct {
+	SeahorseSSHSource *source;
+	GHashTable *loaded;
+	GHashTable *checks;
+	gchar *pubfile;
+	gchar *privfile;
+} source_load_closure;
+
+static void
+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);
+	g_free (closure->pubfile);
+	g_free (closure->privfile);
+	g_free (closure);
+}
+
+static SeahorseSSHKey *
+ssh_key_from_data (SeahorseSSHSource *self,
+                   source_load_closure *closure,
+                   SeahorseSSHKeyData *keydata)
+{
+	SeahorseSource *source = SEAHORSE_SOURCE (self);
+	SeahorseSSHKey *skey;
+	SeahorseObject *prev;
+	GQuark keyid;
+
+	if (!seahorse_ssh_key_data_is_valid (keydata)) {
+		seahorse_ssh_key_data_free (keydata);
+		return NULL;
+	}
+
+	/* Make sure it's valid */
+	keyid = seahorse_ssh_key_calc_cannonical_id (keydata->fingerprint);
+	g_return_val_if_fail (keyid, NULL);
+
+	/* Does this key exist in the context? */
+	prev = seahorse_context_get_object (SCTX_APP (), source, keyid);
+
+	/* Mark this key as seen */
+	if (closure->checks)
+		g_hash_table_remove (closure->checks, GUINT_TO_POINTER (keyid));
+
+	if (closure->loaded) {
+
+		/* See if we've already gotten a key like this in this load batch */
+		if (g_hash_table_lookup (closure->loaded, GUINT_TO_POINTER (keyid))) {
+
+			/*
+			 * Sometimes later keys loaded have more information (for
+			 * example keys loaded from authorized_keys), so propogate
+			 * that up to the previously loaded key
+			 */
+			merge_keydata (SEAHORSE_SSH_KEY (prev), keydata);
+			seahorse_ssh_key_data_free (keydata);
+			return NULL;
+		}
+
+		/* Mark this key as loaded */
+		g_hash_table_insert (closure->loaded, GUINT_TO_POINTER (keyid),
+		                     GUINT_TO_POINTER (TRUE));
+	}
+
+	/* If we already have this key then just transfer ownership of keydata */
+	if (prev) {
+		g_object_set (prev, "key-data", keydata, NULL);
+		return SEAHORSE_SSH_KEY (prev);
+	}
+
+	/* Create a new key */
+	g_assert (keydata);
+	skey = seahorse_ssh_key_new (source, keydata);
+
+	seahorse_context_take_object (seahorse_context_instance (),
+	                              SEAHORSE_OBJECT (skey));
+	return skey;
+}
+
+static GHashTable*
+load_present_keys (SeahorseSSHSource *self)
+{
+	GList *keys, *l;
+	GHashTable *checks;
+
+	checks = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+	keys = seahorse_context_get_objects (seahorse_context_instance (),
+	                                     SEAHORSE_SOURCE (self));
+	for (l = keys; l != NULL; l = g_list_next (l))
+		g_hash_table_insert (checks,
+		                     GUINT_TO_POINTER (seahorse_object_get_id (l->data)),
+		                     GUINT_TO_POINTER (TRUE));
+	g_list_free (keys);
+	return checks;
+}
+
+static gboolean
+on_load_found_authorized_key (SeahorseSSHKeyData *data,
+                              gpointer user_data)
+{
+	source_load_closure *closure = user_data;
+
+	data->pubfile = g_strdup (closure->pubfile);
+	data->partial = TRUE;
+	data->authorized = TRUE;
+
+	/* Check and register thet key with the context, frees keydata */
+	ssh_key_from_data (closure->source, closure, data);
+	return TRUE;
+}
+
+static gboolean
+on_load_found_other_key (SeahorseSSHKeyData *data,
+                         gpointer user_data)
+{
+	source_load_closure *closure = user_data;
+
+	data->pubfile = g_strdup (closure->pubfile);
+	data->partial = TRUE;
+	data->authorized = FALSE;
+
+	/* Check and register thet key with the context, frees keydata */
+	ssh_key_from_data (closure->source, closure, data);
+	return TRUE;
+}
+
+static gboolean
+on_load_found_public_key (SeahorseSSHKeyData *data,
+                          gpointer user_data)
+{
+	source_load_closure *closure = user_data;
+
+	data->pubfile = g_strdup (closure->pubfile);
+	data->privfile = g_strdup (closure->privfile);
+	data->partial = FALSE;
+
+	/* Check and register thet key with the context, frees keydata */
+	ssh_key_from_data (closure->source, closure, data);
+	return TRUE;
+}
+
+static void
+seahorse_ssh_source_load_async (SeahorseSource *source,
+                                GCancellable *cancellable,
+                                GAsyncReadyCallback callback,
+                                gpointer user_data)
+{
+	SeahorseSSHSource *self = SEAHORSE_SSH_SOURCE (source);
+	GSimpleAsyncResult *res;
+	source_load_closure *closure;
+	GError *error = NULL;
+	const gchar *filename;
+	GDir *dir;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ssh_source_load_async);
+	closure = g_new0 (source_load_closure, 1);
+	closure->source = g_object_ref (self);
+
+	/* Since we can find duplicate keys, limit them with this hash */
+	closure->loaded = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
+	/* Keys that currently exist, so we can remove any that disappeared */
+	closure->checks = load_present_keys (self);
+
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_load_free);
+
+	/* Schedule a dummy refresh. This blocks all monitoring for a while */
+	cancel_scheduled_refresh (self);
+	self->priv->scheduled_refresh = g_timeout_add (500, (GSourceFunc)scheduled_dummy, self);
+	seahorse_debug ("scheduled a dummy refresh");
+
+	/* List the .ssh directory for private keys */
+	dir = g_dir_open (self->priv->ssh_homedir, 0, &error);
+	if (dir == NULL) {
+		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete_in_idle (res);
+		g_object_unref (res);
+		return;
+	}
+
+	/* For each private key file */
+	for(;;) {
+		filename = g_dir_read_name (dir);
+		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;
+	}
+
+	g_dir_close (dir);
+
+	/* Now load the authorized file */
+	closure->privfile = NULL;
+	closure->pubfile = seahorse_ssh_source_file_for_public (self, TRUE);
+
+	if (g_file_test (closure->pubfile, G_FILE_TEST_EXISTS)) {
+		seahorse_ssh_key_data_parse_file (closure->pubfile, on_load_found_authorized_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->pubfile);
+	closure->pubfile = NULL;
+
+	/* Load the other keys file */
+	closure->privfile = NULL;
+	closure->pubfile = seahorse_ssh_source_file_for_public (self, FALSE);
+	if (g_file_test (closure->pubfile, G_FILE_TEST_EXISTS)) {
+		seahorse_ssh_key_data_parse_file (closure->pubfile, on_load_found_other_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->pubfile);
+	closure->pubfile = NULL;
+
+	/* Clean up and done */
+	g_hash_table_foreach (closure->checks, (GHFunc)remove_key_from_context, self);
+
+	g_simple_async_result_complete_in_idle (res);
+	g_object_unref (res);
+}
+
+static gboolean
+seahorse_ssh_source_load_finish (SeahorseSource *source,
+                                 GAsyncResult *result,
+                                 GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_source_load_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
+
+typedef struct {
+	SeahorseSSHSource *source;
+	GCancellable *cancellable;
+	gint imports;
+} source_import_closure;
+
+static void
+source_import_free (gpointer data)
+{
+	source_import_closure *closure = data;
+	g_object_unref (closure->source);
+	g_clear_object (&closure->cancellable);
+	g_free (closure);
+}
+
+static void
+on_import_public_complete (GObject *source,
+                           GAsyncResult *result,
+                           gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	gchar *path;
+
+	g_assert (closure->imports > 0);
+	closure->imports--;
+
+	path = seahorse_ssh_op_import_public_finish (closure->source, result, &error);
+	if (error != NULL)
+		g_simple_async_result_take_error (res, error);
+	g_free (path);
+
+	if (closure->imports == 0)
+		g_simple_async_result_complete (res);
+
+	g_object_unref (res);
+}
+
+static gboolean
+on_import_found_public_key (SeahorseSSHKeyData *data,
+                      gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	gchar *fullpath;
+
+	fullpath = seahorse_ssh_source_file_for_public (closure->source, FALSE);
+	seahorse_ssh_op_import_public_async (closure->source, data, fullpath,
+	                                     closure->cancellable, on_import_public_complete,
+	                                     g_object_ref (res));
+	closure->imports++;
+	g_free (fullpath);
+	seahorse_ssh_key_data_free (data);
+
+	return TRUE;
+}
+
+static void
+on_import_private_complete (GObject *source,
+                            GAsyncResult *result,
+                            gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+	gchar *path;
+
+	g_assert (closure->imports > 0);
+	closure->imports--;
+
+	path = seahorse_ssh_op_import_private_finish (closure->source, result, &error);
+	if (error != NULL)
+		g_simple_async_result_take_error (res, error);
+	g_free (path);
+
+	if (closure->imports == 0)
+		g_simple_async_result_complete (res);
+
+	g_object_unref (res);
+}
+
+static gboolean
+on_import_found_private_key (SeahorseSSHSecData *data,
+                             gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	source_import_closure *closure = g_simple_async_result_get_op_res_gpointer (res);
+
+	seahorse_ssh_op_import_private_async (closure->source, data, NULL,
+	                                      closure->cancellable, on_import_private_complete,
+	                                      g_object_ref (res));
+
+	seahorse_ssh_sec_data_free (data);
+	return TRUE;
+}
+
+static void
+seahorse_ssh_source_import_async (SeahorseSource *source,
+                                  GInputStream *input,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
+{
+	SeahorseSSHSource *self = SEAHORSE_SSH_SOURCE (source);
+	source_import_closure *closure;
+	gchar *contents;
+	GSimpleAsyncResult *res;
+	guint count;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ssh_source_import_async);
+	closure = g_new0 (source_import_closure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->source = g_object_ref (self);
+	g_simple_async_result_set_op_res_gpointer (res, closure, source_import_free);
+
+	contents = (gchar*)seahorse_util_read_to_memory (input, NULL);
+	count = seahorse_ssh_key_data_parse (contents, on_import_found_public_key,
+	                                     on_import_found_private_key, res);
+	g_assert (count == closure->imports);
+	g_free (contents);
+
+	if (count == 0)
+		g_simple_async_result_complete_in_idle (res);
+	g_object_unref (res);
+}
+
+static GList *
+seahorse_ssh_source_import_finish (SeahorseSource *source,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_source_import_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	/* TODO: The list of keys imported? */
+	return NULL;
+}
+
+static void
+seahorse_ssh_source_export_async (SeahorseSource *source,
+                                  GList *keys,
+                                  GOutputStream *output,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+	SeahorseSSHKeyData *keydata;
+	gchar *results = NULL;
+	gchar *raw = NULL;
+	GError *error = NULL;
+	SeahorseObject *object;
+	GList *l;
+	gsize written;
+
+	res = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+	                                 seahorse_ssh_source_export_async);
+
+	for (l = keys; l; l = g_list_next (l)) {
+		object = SEAHORSE_OBJECT (l->data);
+		g_assert (SEAHORSE_IS_SSH_KEY (object));
+
+		results = NULL;
+		raw = NULL;
+
+		keydata = NULL;
+		g_object_get (object, "key-data", &keydata, NULL);
+		g_assert (keydata);
+
+		/* We should already have the data loaded */
+		if (keydata->pubfile) {
+			g_assert (keydata->rawdata);
+			results = g_strdup_printf ("%s", keydata->rawdata);
+
+		} else if (!keydata->pubfile) {
+
+			/*
+			 * TODO: We should be able to get at this data by using ssh-keygen
+			 * to make a public key from the private
+			 */
+			g_warning ("private key without public, not exporting: %s", keydata->privfile);
+		}
+
+		/* Write the data out */
+		if (results) {
+			if (g_output_stream_write_all (output, results, strlen (results),
+			                               &written, NULL, &error))
+				g_output_stream_flush (output, NULL, &error);
+			g_free (results);
+		}
+
+		g_free (raw);
+
+		if (error != NULL) {
+			g_simple_async_result_take_error (res, error);
+			break;
+		}
+	}
+
+	g_simple_async_result_set_op_res_gpointer (res, g_object_ref (output), g_object_unref);
+	g_simple_async_result_complete_in_idle (res);
+	g_object_unref (res);
+}
+
+static GOutputStream *
+seahorse_ssh_source_export_finish (SeahorseSource *source,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source),
+	                      seahorse_ssh_source_export_async), NULL);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return NULL;
+
+	return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+}
+
 static void 
 seahorse_source_iface (SeahorseSourceIface *iface)
 {
-	iface->load = seahorse_ssh_source_load;
-	iface->import = seahorse_ssh_source_import;
-	iface->export = seahorse_ssh_source_export;
+	iface->load_async = seahorse_ssh_source_load_async;
+	iface->load_finish = seahorse_ssh_source_load_finish;
+	iface->import_async = seahorse_ssh_source_import_async;
+	iface->import_finish = seahorse_ssh_source_import_finish;
+	iface->export_async = seahorse_ssh_source_export_async;
+	iface->export_finish = seahorse_ssh_source_export_finish;
 }
 
 /* -----------------------------------------------------------------------------
@@ -715,36 +828,28 @@ seahorse_ssh_source_new (void)
 }
 
 SeahorseSSHKey*
-seahorse_ssh_source_key_for_filename (SeahorseSSHSource *ssrc, const gchar *privfile)
+seahorse_ssh_source_key_for_filename (SeahorseSSHSource *ssrc,
+                                      const gchar *privfile)
 {
-    SeahorseSSHKeyData *data;
-    GList *keys, *l;
-    int i;
-    
-    g_assert (privfile);
-    g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (ssrc), NULL);
-    
-    for (i = 0; i < 2; i++) {
-    
-        /* Try to find it first */
-        keys = seahorse_context_get_objects (SCTX_APP (), SEAHORSE_SOURCE (ssrc));
-        for (l = keys; l; l = g_list_next (l)) {
-            
-            g_object_get (l->data, "key-data", &data, NULL);
-            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)
-                return SEAHORSE_SSH_KEY (l->data);
-        }
-        
-        /* Force loading of all new keys */
-        if (!i) {
-            seahorse_source_load_sync (SEAHORSE_SOURCE (ssrc));
-        }
-    }
-    
-    return NULL;
+	SeahorseSSHKeyData *data;
+	GList *keys, *l;
+
+	g_return_val_if_fail (privfile, NULL);
+	g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (ssrc), NULL);
+
+	/* Try to find it first */
+	keys = seahorse_context_get_objects (SCTX_APP (), SEAHORSE_SOURCE (ssrc));
+	for (l = keys; l; l = g_list_next (l)) {
+
+		g_object_get (l->data, "key-data", &data, NULL);
+		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)
+			return SEAHORSE_SSH_KEY (l->data);
+	}
+
+	return NULL;
 }
 
 gchar*
diff --git a/ssh/seahorse-ssh-source.h b/ssh/seahorse-ssh-source.h
index 4769f5b..7c84ba3 100644
--- a/ssh/seahorse-ssh-source.h
+++ b/ssh/seahorse-ssh-source.h
@@ -66,8 +66,8 @@ GType                seahorse_ssh_source_get_type           (void);
 
 SeahorseSSHSource*   seahorse_ssh_source_new                (void);
 
-struct _SeahorseSSHKey*      
-                     seahorse_ssh_source_key_for_filename   (SeahorseSSHSource *ssrc, 
+struct _SeahorseSSHKey*
+                     seahorse_ssh_source_key_for_filename   (SeahorseSSHSource *ssrc,
                                                              const gchar *privfile);
 
 gchar*               seahorse_ssh_source_file_for_public    (SeahorseSSHSource *ssrc,
diff --git a/ssh/seahorse-ssh-upload.c b/ssh/seahorse-ssh-upload.c
index 62c27dc..0f4a3e2 100644
--- a/ssh/seahorse-ssh-upload.c
+++ b/ssh/seahorse-ssh-upload.c
@@ -27,7 +27,6 @@
 
 #include "seahorse-widget.h"
 #include "seahorse-util.h"
-#include "seahorse-operation.h"
 #include "seahorse-progress.h"
 #include "seahorse-gtkstock.h"
 
@@ -36,15 +35,17 @@
 #include "ssh/seahorse-ssh-operation.h"
 
 static void 
-upload_complete (SeahorseOperation *op, gpointer dummy)
+on_upload_complete (GObject *source,
+                    GAsyncResult *result,
+                    gpointer user_data)
 {
-    GError *err = NULL;
-    
-    if (!seahorse_operation_is_successful (op)) {
-        seahorse_operation_copy_error (op, &err);
-        seahorse_util_handle_error (err, _("Couldn't configure Secure Shell keys on remote computer."));
-        g_clear_error (&err);
-    }    
+	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);
 }
 
 G_MODULE_EXPORT void
@@ -79,68 +80,18 @@ on_upload_input_changed (GtkWidget *dummy, SeahorseWidget *swidget)
     g_free (t);
 }
 
-
-static SeahorseOperation*
-upload_via_source (const gchar *user, const gchar *host, const gchar *port, GList *keys)
-{
-    SeahorseMultiOperation *mop = NULL;
-    SeahorseOperation *op = NULL;
-    SeahorseSource *sksrc;
-    SeahorseObject *object;
-    GList *next;
-    
-    seahorse_util_objects_sort (keys);
-    g_assert (keys);
-    
-    while (keys) {
-     
-        /* Break off one set (same keysource) */
-        next = seahorse_util_objects_splice (keys);
-        
-        g_assert (SEAHORSE_IS_OBJECT (keys->data));
-        object = SEAHORSE_OBJECT (keys->data);
-
-        /* Upload via this key source */        
-        sksrc = seahorse_object_get_source (object);
-        g_return_val_if_fail (sksrc != NULL, NULL);
-        
-        g_return_val_if_fail (SEAHORSE_IS_SSH_SOURCE (sksrc), NULL);
-
-        /* If more than one operation start combining */
-        if (op != NULL) {
-            g_assert (mop == NULL);
-            mop = seahorse_multi_operation_new ();
-            seahorse_multi_operation_take (mop, op);
-        }
-
-        /* Start an upload process */
-        op = seahorse_ssh_operation_upload (SEAHORSE_SSH_SOURCE (sksrc), keys, user, host, port);
-        g_return_val_if_fail (op != NULL, NULL);
-
-        /* And combine if necessary */
-        if (mop != NULL) {
-            seahorse_multi_operation_take (mop, op);
-            op = NULL;
-        }
-        
-        g_list_free (keys);
-        keys = next;
-    }
-    
-    return mop ? SEAHORSE_OPERATION (mop) : op;
-}
-
 static void
 upload_keys (SeahorseWidget *swidget)
 {
-    SeahorseOperation *op;
     GtkWidget *widget;
     const gchar *cuser, *chost;
     gchar *user, *host, *port;
     GList *keys;
+    GCancellable *cancellable;
 
     keys = (GList*)g_object_steal_data (G_OBJECT (swidget), "upload-keys");
-    g_return_if_fail (keys != NULL);
+    if (keys == NULL)
+        return;
 
     widget = GTK_WIDGET (seahorse_widget_get_widget (swidget, "user-label"));
     cuser = gtk_entry_get_text (GTK_ENTRY (widget));
@@ -167,19 +118,18 @@ upload_keys (SeahorseWidget *swidget)
 
     seahorse_util_string_trim_whitespace (host);
     seahorse_util_string_trim_whitespace (user);
-    
-    /* This frees |keys| */
-    op = upload_via_source (user, host, port, keys);
+
+    cancellable = g_cancellable_new ();
+
+    /* Start an upload process */
+    seahorse_ssh_op_upload_async (SEAHORSE_SSH_SOURCE (seahorse_object_get_source (keys->data)),
+                                  keys, user, host, port, cancellable, on_upload_complete, NULL);
 
     g_free (host);
     g_free (user);
 
-    g_return_if_fail (op != NULL);
-    seahorse_operation_watch (op, (SeahorseDoneFunc)upload_complete, NULL, NULL, NULL);
-    
-    /* Show the progress window if necessary */
-    seahorse_progress_show (op, _("Configuring Secure Shell Keys..."), FALSE);
-    g_object_unref (op);
+    seahorse_progress_show (cancellable, _("Configuring Secure Shell Keys..."), FALSE);
+    g_object_unref (cancellable);
 }
 
 /**



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