summaryrefslogtreecommitdiff
path: root/gcr/gcr-importer.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcr/gcr-importer.c')
-rw-r--r--gcr/gcr-importer.c1144
1 files changed, 311 insertions, 833 deletions
diff --git a/gcr/gcr-importer.c b/gcr/gcr-importer.c
index 1f0f6dcd..49d8cd66 100644
--- a/gcr/gcr-importer.c
+++ b/gcr/gcr-importer.c
@@ -1,976 +1,454 @@
-/*
+/*
* gnome-keyring
- *
- * Copyright (C) 2008 Stefan Walter
- *
- * This program is free software; you can redistribute it and/or modify
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 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
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser 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.
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
*/
#include "config.h"
-#include "gcr-import-dialog.h"
+#include "gcr-base.h"
#include "gcr-importer.h"
#include "gcr-internal.h"
#include "gcr-marshal.h"
+#include "gcr-gnupg-importer.h"
#include "gcr-parser.h"
+#include "gcr-pkcs11-importer.h"
#include <glib/gi18n-lib.h>
/**
* SECTION:gcr-importer
* @title: GcrImporter
- * @short_description: Import objects into PKCS\#11 slots.
+ * @short_description: Import certificates and keys
+ *
+ * An interface which allows importing of certificates and keys. Each
+ * #GcrImporter is registered with a set of PKCS#11 attributes to match
+ * stuff that it can import.
*
- * A #GcrImporter can be used to import items into PKCS\#11 slots. It's most
- * often used to parse the objects parsed with a #GcrParser. Use
- * gcr_importer_listen() to hook up the importer to the parser.
+ * An importer gets passed a #GcrParser and accesses the currently parsed
+ * item. To create a set of importers that can import the currently parsed
+ * item in a #GcrParser, use gcr_importer_create_for_parsed(). The list of
+ * importers returned has the parsed item queued for import.
*
- * Items are queued, and then imported with gcr_importer_import() or
- * gcr_importer_import_async().
+ * To queue additional items with a importer use gcr_importer_queue_for_parsed().
+ * In addition you can try and queue an additional item with a set of importers
+ * using the gcr_importer_queue_and_filter_for_parsed().
+ *
+ * To start the import use gcr_importer_import() or the async variants.
*/
/**
* GcrImporter:
*
- * Imports items into PKCS\#11
+ * Imports certificates and keys
*/
/**
- * GcrImporterClass:
- * @parent_class: The parent class
- * @queued: Signal which is fired when an item is queued
- * @imported: Signal which is fired when an item is imported
+ * GcrImporterIface:
*
- * The class for #GcrImporter.
+ * Interface implemented for a #GcrImporter.
*/
-/**
- * GcrImporterPromptBehavior:
- * @GCR_IMPORTER_PROMPT_NEEDED: Prompt when needed.
- * @GCR_IMPORTER_PROMPT_ALWAYS: Always prompt.
- * @GCR_IMPORTER_PROMPT_NEVER: Never prompt.
- *
- * Flags for the prompting behavior of #GcrImporter.
- */
+typedef GcrImporterIface GcrImporterInterface;
-enum {
- PROP_0,
- PROP_SLOT,
- PROP_PROMPT_BEHAVIOR
-};
-
-enum {
- QUEUED,
- IMPORTED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-struct _GcrImporterPrivate {
- GckSlot *slot;
- GcrParser *parser;
- GcrImporterPromptBehavior behavior;
-
- /* Information about last import */
- GError *error;
- gboolean succeeded;
-
- /* State data during import */
- gboolean processing;
- GCancellable *cancel;
- gboolean prompted;
- gboolean async;
- GByteArray *buffer;
- GckSession *session;
- GQueue queue;
- gboolean any_private;
-
- /* Extra async stuff */
- GAsyncReadyCallback callback;
- gpointer user_data;
-};
-
-/* State forward declarations */
-static void state_cancelled (GcrImporter *self, gboolean async);
-static void state_complete (GcrImporter *self, gboolean async);
-static void state_create_object (GcrImporter *self, gboolean async);
-static void state_open_session (GcrImporter *self, gboolean async);
-static void state_initialize_pin (GcrImporter *self, gboolean async);
-
-static void gcr_importer_async_result (GAsyncResultIface *iface);
-G_DEFINE_TYPE_WITH_CODE (GcrImporter, gcr_importer, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, gcr_importer_async_result));
-
-#define BLOCK 4096
-
-/* -----------------------------------------------------------------------------
- * INTERNAL
- */
+G_DEFINE_INTERFACE (GcrImporter, gcr_importer, 0);
-static void
-cleanup_state_data (GcrImporter *self)
-{
+typedef struct _GcrRegistered {
GckAttributes *attrs;
+ GType importer_type;
+} GcrRegistered;
- if (self->pv->buffer)
- g_byte_array_free (self->pv->buffer, TRUE);
- self->pv->buffer = NULL;
-
- if (self->pv->session)
- g_object_unref (self->pv->session);
- self->pv->session = NULL;
-
- while ((attrs = g_queue_pop_head (&self->pv->queue)) != NULL)
- gck_attributes_unref (attrs);
- g_assert (g_queue_is_empty (&self->pv->queue));
- self->pv->any_private = FALSE;
-
- if (self->pv->cancel)
- g_object_unref (self->pv->cancel);
- self->pv->cancel = NULL;
-}
+static GArray *registered_importers = NULL;
+static gboolean registered_sorted = FALSE;
static void
-cleanup_import_data (GcrImporter *self)
-{
- if (self->pv->error)
- g_clear_error (&self->pv->error);
- self->pv->succeeded = TRUE;
-}
-
-static void
-next_state (GcrImporter *self, void (*state) (GcrImporter*, gboolean))
-{
- g_assert (GCR_IS_IMPORTER (self));
- g_assert (self->pv->processing);
- g_assert (state);
-
- if (self->pv->cancel && g_cancellable_is_cancelled (self->pv->cancel))
- state = state_cancelled;
-
- (state) (self, self->pv->async);
-}
-
-static const gchar*
-prepare_auth_primary (CK_OBJECT_CLASS klass)
-{
- if (klass == CKO_PRIVATE_KEY)
- return _("Enter password to unlock the private key");
- else if (klass == CKO_CERTIFICATE)
- return _("Enter password to unlock the certificate");
- else
- return _("Enter password to unlock");
-}
-
-static gchar*
-prepare_auth_secondary (CK_OBJECT_CLASS klass, const gchar *label)
-{
- if (label == NULL) {
- if (klass == CKO_PRIVATE_KEY) {
- /* TRANSLATORS: The key is locked. */
- return g_strdup (_("In order to import the private key, it must be unlocked"));
- } else if (klass == CKO_CERTIFICATE) {
- /* TRANSLATORS: The certificate is locked. */
- return g_strdup (_("In order to import the certificate, it must be unlocked"));
- } else {
- /* TRANSLATORS: The data is locked. */
- return g_strdup (_("In order to import the data, it must be unlocked"));
- }
- } else {
- if (klass == CKO_PRIVATE_KEY) {
- /* TRANSLATORS: The key is locked. */
- return g_strdup_printf (_("In order to import the private key '%s', it must be unlocked"), label);
- } else if (klass == CKO_CERTIFICATE) {
- /* TRANSLATORS: The certificate is locked. */
- return g_strdup_printf (_("In order to import the certificate '%s', it must be unlocked"), label);
- } else {
- /* TRANSLATORS: The object '%s' is locked. */
- return g_strdup_printf (_("In order to import '%s', it must be unlocked"), label);
- }
+gcr_importer_default_init (GcrImporterIface *iface)
+{
+ static volatile gsize initialized = 0;
+
+ if (g_once_init_enter (&initialized)) {
+
+ /**
+ * GcrImporter:label:
+ *
+ * The label for the importer.
+ */
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("label", "Label", "The label for the importer",
+ "", G_PARAM_READABLE));
+
+ /**
+ * GcrImporter:icon:
+ *
+ * The icon for the importer.
+ */
+ g_object_interface_install_property (iface,
+ g_param_spec_object ("icon", "Icon", "The icon for the importer",
+ G_TYPE_ICON, G_PARAM_READABLE));
+
+ g_once_init_leave (&initialized, 1);
}
}
-static void
-on_parser_parsed (GcrParser *parser, GcrImporter *self)
+/**
+ * gcr_importer_register:
+ * @importer_type: the GType of the importer being registered
+ * @attrs: the attributes that this importer is compatible with
+ *
+ * Register an importer to handle parsed items that match the given attributes.
+ */
+void
+gcr_importer_register (GType importer_type,
+ GckAttributes *attrs)
{
- GckAttributes *attrs;
+ GcrRegistered registered;
- g_return_if_fail (GCR_IS_PARSER (parser));
- g_return_if_fail (GCR_IS_IMPORTER (self));
+ if (!registered_importers)
+ registered_importers = g_array_new (FALSE, FALSE, sizeof (GcrRegistered));
- attrs = gcr_parser_get_parsed_attributes (parser);
- g_return_if_fail (attrs);
-
- gcr_importer_queue (self, gcr_parser_get_parsed_label (parser), attrs);
+ registered.importer_type = importer_type;
+ registered.attrs = gck_attributes_ref (attrs);
+ g_array_append_val (registered_importers, registered);
+ registered_sorted = FALSE;
}
-static gboolean
-on_parser_authenticate (GcrParser *parser, gint count, GcrImporter *self)
+static gint
+sort_registered_by_n_attrs (gconstpointer a, gconstpointer b)
{
- GcrImportDialog *dialog;
- GckAttributes *attrs;
- const gchar *password;
- gchar *text, *label;
- GckSlot *slot;
- gulong klass;
-
- dialog = _gcr_import_dialog_new ();
-
- if (self->pv->slot)
- _gcr_import_dialog_set_selected_slot (dialog, self->pv->slot);
-
- /* Figure out the text for the dialog */
- attrs = gcr_parser_get_parsed_attributes (parser);
- g_return_val_if_fail (attrs, FALSE);
-
- if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass))
- klass = (gulong)-1;
- if (!gck_attributes_find_string (attrs, CKA_LABEL, &label))
- label = NULL;
+ const GcrRegistered *ra = a;
+ const GcrRegistered *rb = b;
+ gulong na, nb;
- text = prepare_auth_secondary (klass, label);
- _gcr_import_dialog_set_primary_text (dialog, prepare_auth_primary (klass));
- _gcr_import_dialog_set_secondary_text (dialog, text);
- g_free (label);
- g_free (text);
+ g_assert (a);
+ g_assert (b);
- if (!_gcr_import_dialog_run (dialog, NULL))
- return FALSE;
+ na = gck_attributes_count (ra->attrs);
+ nb = gck_attributes_count (rb->attrs);
- slot = _gcr_import_dialog_get_selected_slot (dialog);
- gcr_importer_set_slot (self, slot);
-
- password = _gcr_import_dialog_get_password (dialog);
- gcr_parser_add_password (parser, password);
-
- g_object_unref (dialog);
- self->pv->prompted = TRUE;
- return TRUE;
+ /* Note we're sorting in reverse order */
+ if (na < nb)
+ return 1;
+ return (na == nb) ? 0 : -1;
}
-/* ---------------------------------------------------------------------------------
- * COMPLETE
+/**
+ * gcr_importer_create_for_parsed:
+ * @parsed: a parser with a parsed item to import
+ *
+ * Create a set of importers which can import this parsed item.
+ * The parsed item is represented by the state of the GcrParser at the
+ * time of calling this method.
+ *
+ * Returns: a list of importers which can import the parsed item, which
+ * should be freed with gck_list_unref_free().
*/
-
-static void
-state_complete (GcrImporter *self, gboolean async)
-{
- if (async && self->pv->callback != NULL)
- (self->pv->callback) (G_OBJECT (self), G_ASYNC_RESULT (self), self->pv->user_data);
-
- cleanup_state_data (self);
- self->pv->processing = FALSE;
-}
-
-static void
-state_failure (GcrImporter *self, gboolean async)
-{
- self->pv->succeeded = FALSE;
- next_state (self, state_complete);
-}
-
-static void
-state_cancelled (GcrImporter *self, gboolean async)
+GList *
+gcr_importer_create_for_parsed (GcrParser *parser)
{
- if (self->pv->cancel && g_cancellable_is_cancelled (self->pv->cancel))
- g_cancellable_cancel (self->pv->cancel);
- if (self->pv->error)
- g_error_free (self->pv->error);
- self->pv->error = g_error_new_literal (GCR_DATA_ERROR, GCR_ERROR_CANCELLED, _("The operation was cancelled"));
- next_state (self, state_failure);
-}
+ GcrRegistered *registered;
+ GcrImporterIface *iface;
+ gpointer instance_class;
+ GckAttributes *attrs;
+ gboolean matched;
+ gulong n_attrs;
+ GList *results = NULL;
+ gulong j;
+ gsize i;
-/* ---------------------------------------------------------------------------------
- * CREATE OBJECTS
- */
+ g_return_val_if_fail (GCR_IS_PARSER (parser), NULL);
-static void
-complete_create_object (GcrImporter *self, GckObject *object, GError *error)
-{
- if (object == NULL) {
- g_propagate_error (&self->pv->error, error);
- next_state (self, state_failure);
-
- } else {
- g_signal_emit (self, signals[IMPORTED], 0, object);
- g_object_unref (object);
- next_state (self, state_create_object);
- }
-}
+ gcr_importer_register_well_known ();
-static void
-on_create_object (GObject *obj, GAsyncResult *res, gpointer user_data)
-{
- GError *error = NULL;
- GckObject *object = gck_session_create_object_finish (GCK_SESSION (obj), res, &error);
- complete_create_object (GCR_IMPORTER (user_data), object, error);
-}
+ if (!registered_importers)
+ return NULL;
-static void
-state_create_object (GcrImporter *self, gboolean async)
-{
- GckAttributes *attrs;
- GckObject *object;
- GError *error = NULL;
-
- /* No more objects */
- if (g_queue_is_empty (&self->pv->queue)) {
- next_state (self, state_complete);
-
- } else {
-
- /* Pop first one off the list */
- attrs = g_queue_pop_head (&self->pv->queue);
- g_assert (attrs);
-
- gck_attributes_add_boolean (attrs, CKA_TOKEN, CK_TRUE);
-
- if (async) {
- gck_session_create_object_async (self->pv->session, attrs, self->pv->cancel,
- on_create_object, self);
- } else {
- object = gck_session_create_object (self->pv->session, attrs, self->pv->cancel, &error);
- complete_create_object (self, object, error);
- }
-
- gck_attributes_unref (attrs);
+ if (!registered_sorted) {
+ g_array_sort (registered_importers, sort_registered_by_n_attrs);
+ registered_sorted = TRUE;
}
-}
-/* ---------------------------------------------------------------------------------
- * OPEN SESSION
- */
+ attrs = gcr_parser_get_parsed_attributes (parser);
+ if (attrs != NULL)
+ gck_attributes_ref (attrs);
+ else
+ attrs = gck_attributes_new ();
-static void
-complete_open_session (GcrImporter *self, GckSession *session, GError *error)
-{
- if (!session) {
- g_propagate_error (&self->pv->error, error);
- next_state (self, state_failure);
- } else {
- self->pv->session = session;
- next_state (self, state_create_object);
- }
-}
+ for (i = 0; i < registered_importers->len; ++i) {
+ registered = &(g_array_index (registered_importers, GcrRegistered, i));
+ n_attrs = gck_attributes_count (registered->attrs);
-static void
-on_open_session (GObject *obj, GAsyncResult *res, gpointer user_data)
-{
- GError *error = NULL;
- GckSession *session = gck_slot_open_session_finish (GCK_SLOT (obj), res, &error);
- complete_open_session (GCR_IMPORTER (user_data), session, error);
-}
+ matched = TRUE;
-static void
-state_open_session (GcrImporter *self, gboolean async)
-{
- guint options = GCK_SESSION_READ_WRITE;
- GckSession *session;
- GError *error = NULL;
-
- if (!self->pv->slot) {
- g_set_error (&self->pv->error, GCR_DATA_ERROR, GCR_ERROR_FAILURE, _("No location available to import to"));
- next_state (self, state_failure);
-
- } else {
- if (self->pv->any_private)
- options |= GCK_SESSION_LOGIN_USER;
-
- if (async) {
- gck_slot_open_session_async (self->pv->slot, options, self->pv->cancel,
- on_open_session, self);
- } else {
- session = gck_slot_open_session_full (self->pv->slot, options, 0, NULL, NULL,
- self->pv->cancel, &error);
- complete_open_session (self, session, error);
+ for (j = 0; j < n_attrs; ++j) {
+ if (!gck_attributes_contains (attrs, gck_attributes_at (registered->attrs, j))) {
+ matched = FALSE;
+ break;
+ }
}
- }
-}
-/* ---------------------------------------------------------------------------------
- * INITIALIZE TOKEN
- *
- * HACK: This is a big temporary hack to get, until the next version
- * when we can fix this correctly.
- */
+ if (matched) {
+ instance_class = g_type_class_ref (registered->importer_type);
-static CK_RV
-hacky_perform_initialize_pin (GckSlot *slot)
-{
- CK_FUNCTION_LIST_PTR funcs;
- CK_SESSION_HANDLE session;
- CK_SLOT_ID slot_id;
- CK_RV rv;
-
- /*
- * This hack only works when:
- *
- * - Module is protected authentication path
- * - No other sessions are open.
- *
- * Thankfully this is the case with gnome-keyring-daemon and
- * the gnome-keyring tool.
- */
-
- funcs = gck_module_get_functions (gck_slot_get_module (slot));
- g_return_val_if_fail (funcs, CKR_GENERAL_ERROR);
- slot_id = gck_slot_get_handle (slot);
-
- rv = funcs->C_OpenSession (slot_id, CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL, NULL, &session);
- if (rv != CKR_OK)
- return rv;
-
- rv = funcs->C_Login (session, CKU_SO, NULL, 0);
- if (rv == CKR_OK) {
- rv = funcs->C_InitPIN (session, NULL, 0);
- funcs->C_Logout (session);
- }
-
- funcs->C_CloseSession (session);
-
- return rv;
-}
+ iface = g_type_interface_peek (instance_class, GCR_TYPE_IMPORTER);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->create_for_parsed, NULL);
+ results = g_list_concat (results, (iface->create_for_parsed) (parser));
-static void
-state_initialize_pin (GcrImporter *self, gboolean async)
-{
- GckTokenInfo *info;
- gboolean initialize;
- CK_RV rv;
-
- g_assert (GCR_IS_IMPORTER (self));
-
- /* HACK: Doesn't function when async */
- if (!async) {
- g_return_if_fail (self->pv->slot);
- info = gck_slot_get_token_info (self->pv->slot);
- g_return_if_fail (info);
-
- initialize = !(info->flags & CKF_USER_PIN_INITIALIZED);
- gck_token_info_free (info);
-
- if (initialize) {
- rv = hacky_perform_initialize_pin (self->pv->slot);
- if (rv != CKR_OK) {
- g_propagate_error (&self->pv->error, g_error_new (GCK_ERROR, rv, "%s", gck_message_from_rv (rv)));
- next_state (self, state_failure);
- return;
- }
+ g_type_class_unref (instance_class);
}
}
- next_state (self, state_open_session);
+ gck_attributes_unref (attrs);
+ return results;
}
-/* ---------------------------------------------------------------------------------
- * IMPORT PROMPT
+/**
+ * gcr_importer_queue_for_parsed:
+ * @importer: an importer to add additional items to
+ * @parser: a parser with a parsed item to import
+ *
+ * Queues an additional item to be imported. The parsed item is represented
+ * by the state of the #GcrParser at the time of calling this method.
+ *
+ * If the parsed item is incompatible with the importer, then this will
+ * fail and the item will not be queued.
+ *
+ * Returns: whether the item was queued or not
*/
-
-static void
-complete_import_prompt (GcrImporter *self, GcrImportDialog *dialog, gint response)
+gboolean
+gcr_importer_queue_for_parsed (GcrImporter *importer,
+ GcrParser *parser)
{
- GckSlot *slot;
+ GcrImporterIface *iface;
- gtk_widget_hide (GTK_WIDGET (dialog));
- self->pv->prompted = TRUE;
+ g_return_val_if_fail (GCR_IS_IMPORTER (importer), FALSE);
+ g_return_val_if_fail (GCR_IS_PARSER (parser), FALSE);
- /* No dialog or dialog completed */
- if (response == GTK_RESPONSE_OK) {
+ iface = GCR_IMPORTER_GET_INTERFACE (importer);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->queue_for_parsed != NULL, FALSE);
- slot = _gcr_import_dialog_get_selected_slot (dialog);
- gcr_importer_set_slot (self, slot);
- next_state (self, state_initialize_pin);
-
- /* The dialog was cancelled or closed */
- } else {
- next_state (self, state_cancelled);
- }
-}
-
-static void
-on_prompt_response (GtkDialog *dialog, gint response, gpointer user_data)
-{
- complete_import_prompt (GCR_IMPORTER (user_data), GCR_IMPORT_DIALOG (dialog), response);
- g_object_unref (dialog);
+ return (iface->queue_for_parsed) (importer, parser);
}
-static void
-state_import_prompt (GcrImporter *self, gboolean async)
-{
- GcrImportDialog *dialog;
- gboolean prompt;
- gint response;
-
- g_assert (GCR_IS_IMPORTER (self));
-
- /* No need to prompt */
- if (self->pv->prompted == TRUE)
- prompt = FALSE;
- else if (self->pv->behavior == GCR_IMPORTER_PROMPT_ALWAYS)
- prompt = TRUE;
- else if (self->pv->behavior == GCR_IMPORTER_PROMPT_NEVER)
- prompt = FALSE;
- else
- prompt = self->pv->slot ? FALSE : TRUE;
-
- if (prompt == FALSE) {
- next_state (self, state_initialize_pin);
-
- } else {
-
- dialog = _gcr_import_dialog_new ();
-
- _gcr_import_dialog_set_primary_text (dialog, _("Import Certificates/Keys"));
- _gcr_import_dialog_hide_password (dialog);
-
- if (self->pv->slot) {
- _gcr_import_dialog_set_selected_slot (dialog, self->pv->slot);
- _gcr_import_dialog_hide_selected_slot (dialog);
- } else {
- _gcr_import_dialog_set_secondary_text (dialog, _("Choose a location to store the imported certificates/keys."));
- }
-
- /* Prompt without blocking main loop */
- if (async) {
- g_signal_connect (dialog, "response", G_CALLBACK (on_prompt_response), self);
- gtk_widget_show (GTK_WIDGET (dialog));
-
- /* Block mainloop */
- } else {
- response = gtk_dialog_run (GTK_DIALOG (dialog));
- complete_import_prompt (self, dialog, response);
- g_object_unref (dialog);
- }
- }
-}
-
-/* -----------------------------------------------------------------------------
- * OBJECT
+/**
+ * gcr_importer_queue_and_filter_for_parsed:
+ * @importer: a set of importers
+ * @parser: a parser with a parsed item to import
+ *
+ * Queues an additional item to be imported in all compattible importers
+ * in the set. The parsed item is represented by the state of the #GcrParser
+ * at the time of calling this method.
+ *
+ * If the parsed item is incompatible with an importer, then that the item
+ * will not be queued on that importer.
+ *
+ * Returns: a new set of importers that queued the item, which should be freed
+ * with gck_list_unref_free().
*/
-
-static GObject*
-gcr_importer_constructor (GType type, guint n_props, GObjectConstructParam *props)
+GList *
+gcr_importer_queue_and_filter_for_parsed (GList *importers,
+ GcrParser *parser)
{
- GcrImporter *self = GCR_IMPORTER (G_OBJECT_CLASS (gcr_importer_parent_class)->constructor(type, n_props, props));
- g_return_val_if_fail (self, NULL);
-
- return G_OBJECT (self);
-}
+ GList *results = NULL;
+ GList *l;
-static void
-gcr_importer_init (GcrImporter *self)
-{
- self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_IMPORTER, GcrImporterPrivate);
- self->pv->behavior = GCR_IMPORTER_PROMPT_NEEDED;
- g_queue_init (&self->pv->queue);
-}
+ for (l = importers; l != NULL; l = g_list_next (l)) {
+ if (gcr_importer_queue_for_parsed (l->data, parser))
+ results = g_list_prepend (results, g_object_ref (l->data));
+ }
-static void
-gcr_importer_dispose (GObject *obj)
-{
- GcrImporter *self = GCR_IMPORTER (obj);
-
- cleanup_state_data (self);
- cleanup_import_data (self);
-
- if (self->pv->parser)
- g_object_unref (self->pv->parser);
- self->pv->parser = NULL;
-
- if (self->pv->slot)
- g_object_unref (self->pv->slot);
- self->pv->slot = NULL;
-
- G_OBJECT_CLASS (gcr_importer_parent_class)->dispose (obj);
+ return g_list_reverse (results);
}
-static void
-gcr_importer_finalize (GObject *obj)
-{
- GcrImporter *self = GCR_IMPORTER (obj);
-
- g_assert (!self->pv->parser);
- g_assert (!self->pv->slot);
-
- G_OBJECT_CLASS (gcr_importer_parent_class)->finalize (obj);
-}
+typedef struct {
+ gboolean complete;
+ GCond *cond;
+ GMutex *mutex;
+ GError *error;
+ GMainContext *context;
+} ImportClosure;
static void
-gcr_importer_set_property (GObject *obj, guint prop_id, const GValue *value,
- GParamSpec *pspec)
+on_import_async_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GcrImporter *self = GCR_IMPORTER (obj);
-
- switch (prop_id) {
- case PROP_SLOT:
- gcr_importer_set_slot (self, g_value_get_object (value));
- break;
- case PROP_PROMPT_BEHAVIOR:
- gcr_importer_set_prompt_behavior (self, (GcrImporterPromptBehavior)g_value_get_int (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
- break;
- }
-}
+ ImportClosure *closure = user_data;
+ GError *error = NULL;
-static void
-gcr_importer_get_property (GObject *obj, guint prop_id, GValue *value,
- GParamSpec *pspec)
-{
- GcrImporter *self = GCR_IMPORTER (obj);
-
- switch (prop_id) {
- case PROP_SLOT:
- g_value_set_object (value, gcr_importer_get_slot (self));
- break;
- case PROP_PROMPT_BEHAVIOR:
- g_value_set_int (value, gcr_importer_get_prompt_behavior (self));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
- break;
+ if (!gcr_importer_import_finish (GCR_IMPORTER (source), result, &error)) {
+ if (error == NULL) {
+ g_warning ("%s::import_finished returned false, but did not set error",
+ G_OBJECT_TYPE_NAME (source));
+ }
}
-}
-static void
-gcr_importer_class_init (GcrImporterClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gobject_class->constructor = gcr_importer_constructor;
- gobject_class->dispose = gcr_importer_dispose;
- gobject_class->finalize = gcr_importer_finalize;
- gobject_class->set_property = gcr_importer_set_property;
- gobject_class->get_property = gcr_importer_get_property;
-
- g_type_class_add_private (gobject_class, sizeof (GcrImporterPrivate));
-
- g_object_class_install_property (gobject_class, PROP_SLOT,
- g_param_spec_object ("slot", "Slot", "PKCS#11 slot to import data into",
- GCK_TYPE_SLOT, G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class, PROP_PROMPT_BEHAVIOR,
- g_param_spec_int ("prompt-behavior", "Prompt Behavior", "Import Prompt Behavior",
- 0, G_MAXINT, GCR_IMPORTER_PROMPT_NEEDED, G_PARAM_READWRITE));
-
- /**
- * GcrImporter::queued:
- * @label: The label of the queued item.
- * @attrs: The attributes of the queued item.
- *
- * This signal is emitted when an item is queued for import.
- */
- signals[QUEUED] = g_signal_new ("queued", GCR_TYPE_IMPORTER,
- G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcrImporterClass, queued),
- NULL, NULL, _gcr_marshal_VOID__STRING_BOXED,
- G_TYPE_NONE, 1, G_TYPE_STRING, GCK_TYPE_ATTRIBUTES);
-
- /**
- * GcrImporter::imported:
- * @object: The object which was imported.
- *
- * This signal is emitted when an item has been imported.
- */
- signals[IMPORTED] = g_signal_new ("imported", GCR_TYPE_IMPORTER,
- G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcrImporterClass, imported),
- NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, GCK_TYPE_OBJECT);
-}
+ g_mutex_lock (closure->mutex);
-static gpointer
-gcr_importer_real_get_user_data (GAsyncResult *base)
-{
- g_return_val_if_fail (GCR_IS_IMPORTER (base), NULL);
- return GCR_IMPORTER (base)->pv->user_data;
-}
+ closure->complete = TRUE;
+ closure->error = error;
+ g_cond_signal (closure->cond);
-static GObject*
-gcr_importer_real_get_source_object (GAsyncResult *base)
-{
- g_return_val_if_fail (GCR_IS_IMPORTER (base), NULL);
- return G_OBJECT (base);
-}
-
-static void
-gcr_importer_async_result (GAsyncResultIface *iface)
-{
- iface->get_source_object = gcr_importer_real_get_source_object;
- iface->get_user_data = gcr_importer_real_get_user_data;
-}
-
-/* -----------------------------------------------------------------------------
- * PUBLIC
- */
-
-/**
- * gcr_importer_new:
- *
- * Create a new #GcrImporter.
- *
- * Returns: A newly allocated importer, which should be released with
- * g_object_unref().
- */
-GcrImporter*
-gcr_importer_new (void)
-{
- return g_object_new (GCR_TYPE_IMPORTER, NULL);
-}
-
-/**
- * gcr_importer_get_slot:
- * @self: The importer
- *
- * Get the PKCS\#11 slot the items will be imported to, or after
- * an import operation, which slot they have been imported to.
- *
- * Returns: The slot.
- */
-GckSlot*
-gcr_importer_get_slot (GcrImporter *self)
-{
- g_return_val_if_fail (GCR_IS_IMPORTER (self), NULL);
- return self->pv->slot;
-}
-
-/**
- * gcr_importer_set_slot:
- * @self: The importer
- * @slot: The slot to import to
- *
- * Set the PKCS\#11 slot to import the items to.
- */
-void
-gcr_importer_set_slot (GcrImporter *self, GckSlot *slot)
-{
- g_return_if_fail (GCR_IS_IMPORTER (self));
-
- if (slot)
- g_object_ref (slot);
- if (self->pv->slot)
- g_object_unref (self->pv->slot);
- self->pv->slot = slot;
- g_object_notify (G_OBJECT (self), "slot");
-}
-
-/**
- * gcr_importer_get_prompt_behavior:
- * @self: The importer
- *
- * Get the type of prompting configured for this importer.
- *
- * Returns: The prompting flags.
- */
-GcrImporterPromptBehavior
-gcr_importer_get_prompt_behavior (GcrImporter *self)
-{
- g_return_val_if_fail (GCR_IS_IMPORTER (self), GCR_IMPORTER_PROMPT_NEEDED);
- return self->pv->behavior;
-}
-
-/**
- * gcr_importer_set_prompt_behavior:
- * @self: The importer
- * @behavior: The prompt behavior flag
- *
- * Set the type of prompting desired during import.
- */
-void
-gcr_importer_set_prompt_behavior (GcrImporter *self, GcrImporterPromptBehavior behavior)
-{
- g_return_if_fail (GCR_IMPORTER (self));
- self->pv->behavior = behavior;
- g_object_notify (G_OBJECT (self), "prompt-behavior");
+ g_mutex_unlock (closure->mutex);
}
/**
* gcr_importer_import:
- * @self: The importer
- * @cancellable: An optional cancellation object
- * @error: A location to raise an error on failure
+ * @importer: the importer
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: the location to place an error on failure, or %NULL
*
- * Start an synchronous import operation of the items that have been queued.
+ * Import the queued items in the importer. This call will block
+ * until the operation completes.
*
- * Returns: Whether the import was successful or not.
+ * Returns: whether the items were imported successfully or not
*/
gboolean
-gcr_importer_import (GcrImporter *self, GCancellable *cancellable, GError **error)
+gcr_importer_import (GcrImporter *importer,
+ GCancellable *cancellable,
+ GError **error)
{
- g_return_val_if_fail (GCR_IS_IMPORTER (self), FALSE);
- g_return_val_if_fail (!error || !*error, FALSE);
- g_return_val_if_fail (!self->pv->processing, FALSE);
-
- cleanup_import_data (self);
-
- if (cancellable)
- self->pv->cancel = g_object_ref (cancellable);
- self->pv->processing = TRUE;
- self->pv->async = FALSE;
-
- next_state (self, state_import_prompt);
-
- g_assert (!self->pv->processing);
- g_assert (!self->pv->cancel);
-
- if (!self->pv->succeeded) {
- g_propagate_error (error, self->pv->error);
- self->pv->error = NULL;
- return FALSE;
- }
-
- return TRUE;
-}
+ gboolean result;
+ ImportClosure *closure;
+ GcrImporterIface *iface;
-/**
- * gcr_importer_import_async:
- * @self: The importer
- * @cancellable: An optional cancellation object
- * @callback: Call when the operation result is ready
- * @user_data: Data to pass to the callback
- *
- * Start an asynchronous import operation of the items that have been queued.
- */
-void
-gcr_importer_import_async (GcrImporter *self, GCancellable *cancellable,
- GAsyncReadyCallback callback, gpointer user_data)
-{
- g_return_if_fail (GCR_IS_IMPORTER (self));
- g_return_if_fail (!self->pv->processing);
+ g_return_val_if_fail (GCR_IS_IMPORTER (importer), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- cleanup_import_data (self);
+ iface = GCR_IMPORTER_GET_INTERFACE (importer);
+ if (iface->import_sync)
+ return (iface->import_sync) (importer, cancellable, error);
- if (cancellable)
- self->pv->cancel = g_object_ref (cancellable);
- self->pv->processing = TRUE;
- self->pv->async = TRUE;
- self->pv->callback = callback;
- self->pv->user_data = user_data;
+ g_return_val_if_fail (iface->import_async != NULL, FALSE);
+ g_return_val_if_fail (iface->import_finish != NULL, FALSE);
- next_state (self, state_import_prompt);
- g_assert (self->pv->processing);
-}
+ closure = g_new0 (ImportClosure, 1);
+ closure->cond = g_cond_new ();
+ closure->mutex = g_mutex_new ();
+ closure->context = g_main_context_get_thread_default ();
+ g_mutex_lock (closure->mutex);
-/**
- * gcr_importer_import_finish:
- * @self: The importer
- * @result: The operation result
- * @error: A location to raise an error on failure.
- *
- * Complete an asynchronous import operation.
- *
- * Returns: Whether the operation was successful or not.
- */
-gboolean
-gcr_importer_import_finish (GcrImporter *self, GAsyncResult *result, GError **error)
-{
- g_return_val_if_fail (GCR_IS_IMPORTER (self), FALSE);
- g_return_val_if_fail (GCR_IMPORTER (result) == self, FALSE);
- g_return_val_if_fail (!error || !*error, FALSE);
- g_return_val_if_fail (!self->pv->processing, FALSE);
+ (iface->import_async) (importer, cancellable, on_import_async_complete, closure);
+
+ /*
+ * Handle the case where we've been called from within the main context
+ * or in the case where the main context is not running. This approximates
+ * the behavior of a modal dialog.
+ */
+ if (g_main_context_acquire (closure->context)) {
+ while (!closure->complete) {
+ g_mutex_unlock (closure->mutex);
+ g_main_context_iteration (closure->context, TRUE);
+ g_mutex_lock (closure->mutex);
+ }
- g_assert (!self->pv->cancel);
+ g_main_context_release (closure->context);
- if (!self->pv->succeeded) {
- g_propagate_error (error, self->pv->error);
- self->pv->error = NULL;
- return FALSE;
+ /*
+ * Handle the case where we're in a different thread than the main
+ * context and a main loop is running.
+ */
+ } else {
+ while (!closure->complete)
+ g_cond_wait (closure->cond, closure->mutex);
}
-
- return TRUE;
-}
-/**
- * gcr_importer_listen:
- * @self: The importer
- * @parser: The parser to listen to
- *
- * Listen for parse events from the #GcrParser, and queue parsed items for
- * importing.
- */
-void
-gcr_importer_listen (GcrImporter *self, GcrParser *parser)
-{
- g_return_if_fail (GCR_IS_IMPORTER (self));
- g_return_if_fail (GCR_IS_PARSER (parser));
+ g_mutex_unlock (closure->mutex);
+
+ result = (closure->error == NULL);
+ if (closure->error)
+ g_propagate_error (error, closure->error);
- /* Listen in to the parser */
- g_signal_connect_object (parser, "parsed", G_CALLBACK (on_parser_parsed), self, 0);
- g_signal_connect_object (parser, "authenticate", G_CALLBACK (on_parser_authenticate), self, 0);
+ g_cond_free (closure->cond);
+ g_mutex_free (closure->mutex);
+ g_free (closure);
+
+ return result;
}
/**
- * gcr_importer_queue:
- * @self: The importer
- * @label: Label of item to import
- * @attrs: Attributes of item to import
+ * gcr_importer_import_async:
+ * @importer: the importer
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: called when the operation completes
+ * @user_data: data to be passed to the callback
*
- * Queue the importing of an item. Use gcr_importer_listen() to automatically
- * queue items parsed by a #GcrParser.
+ * Import the queued items in the importer. This function returns immediately
+ * and completes asynchronously.
*/
void
-gcr_importer_queue (GcrImporter *self, const gchar *label, GckAttributes *attrs)
+gcr_importer_import_async (GcrImporter *importer,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- gboolean is_private;
+ GcrImporterIface *iface;
- g_return_if_fail (GCR_IS_IMPORTER (self));
- g_return_if_fail (attrs);
+ g_return_if_fail (GCR_IS_IMPORTER (importer));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- if (!gck_attributes_find_boolean (attrs, CKA_PRIVATE, &is_private))
- is_private = FALSE;
- if (is_private)
- self->pv->any_private = TRUE;
+ iface = GCR_IMPORTER_GET_INTERFACE (importer);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->import_async != NULL);
- g_queue_push_tail (&self->pv->queue, gck_attributes_ref (attrs));
- g_signal_emit (self, signals[QUEUED], 0, label, attrs);
+ return (iface->import_async) (importer, cancellable, callback, user_data);
}
-#ifndef GCR_DISABLE_DEPRECATED
-
/**
- * gcr_importer_get_parser:
- * @self: An importer
+ * gcr_importer_import_finish:
+ * @importer: the importer
+ * @result: an asynchronous result
+ * @error: the location to place an error on failure, or %NULL
*
- * Has no effect. Use gcr_importer_listen() instead.
+ * Complete an asynchronous operation to import queued items.
*
- * Returns: %NULL is always returned.
- * Deprecated: Since 3.0.0
+ * Returns: whether the import succeeded or failed
*/
-GcrParser*
-gcr_importer_get_parser (GcrImporter *self)
+gboolean
+gcr_importer_import_finish (GcrImporter *importer,
+ GAsyncResult *result,
+ GError **error)
{
- g_warning ("gcr_importer_get_parser() is no longer supported "
- "Use gcr_importer_listen() instead.");
- return NULL;
+ GcrImporterIface *iface;
+
+ g_return_val_if_fail (GCR_IS_IMPORTER (importer), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ iface = GCR_IMPORTER_GET_INTERFACE (importer);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->import_finish != NULL, FALSE);
+
+ return (iface->import_finish) (importer, result, error);
}
/**
- * gcr_importer_set_parser:
- * @self: An importer
- * @parser: A parser
- *
- * Has no effect. Use gcr_importer_listen() instead.
+ * gcr_importer_register_well_known:
*
- * Deprecated: Since 3.0.0
+ * Register built-in PKCS#11 and GnuPG importers.
*/
void
-gcr_importer_set_parser (GcrImporter *self, GcrParser *parser)
+gcr_importer_register_well_known (void)
{
- g_warning ("gcr_importer_set_parser() is no longer supported "
- "Use gcr_importer_listen() instead.");
+ g_type_class_unref (g_type_class_ref (GCR_TYPE_PKCS11_IMPORTER));
+ g_type_class_unref (g_type_class_ref (GCR_TYPE_GNUPG_IMPORTER));
}
-
-#endif /* GCR_DISABLE_DEPRECATED */