[seahorse] Refactor asynchronous operation code in seahorse.
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [seahorse] Refactor asynchronous operation code in seahorse.
- Date: Sat, 20 Aug 2011 13:26:34 +0000 (UTC)
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"><b>Path:</b></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"><b>Permissions:</b></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"><b>Progress Message</b></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]