summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/reference/gck/gck-sections.txt2
-rw-r--r--docs/reference/gcr/Makefile.am4
-rw-r--r--docs/reference/gcr/gcr-sections.txt79
-rw-r--r--gck/gck-misc.c12
-rw-r--r--gck/gck.h4
-rw-r--r--gck/gck.symbols1
-rw-r--r--gcr/Makefile.am4
-rw-r--r--gcr/gcr-base.symbols12
-rw-r--r--gcr/gcr-certificate-widget.c7
-rw-r--r--gcr/gcr-deprecated-base.h6
-rw-r--r--gcr/gcr-deprecated.h5
-rw-r--r--gcr/gcr-gnupg-importer.c315
-rw-r--r--gcr/gcr-gnupg-importer.h67
-rw-r--r--gcr/gcr-gnupg-process.c7
-rw-r--r--gcr/gcr-gnupg-process.h2
-rw-r--r--gcr/gcr-import-dialog.c15
-rw-r--r--gcr/gcr-import-dialog.h17
-rw-r--r--gcr/gcr-importer.c1144
-rw-r--r--gcr/gcr-importer.h109
-rw-r--r--gcr/gcr-internal.h1
-rw-r--r--gcr/gcr-key-widget.c7
-rw-r--r--gcr/gcr-pkcs11-importer.c582
-rw-r--r--gcr/gcr-pkcs11-importer.h68
-rw-r--r--gcr/gcr-record.h11
-rw-r--r--gcr/gcr.symbols14
-rw-r--r--po/POTFILES.in1
-rw-r--r--tool/gkr-tool-import.c138
27 files changed, 1602 insertions, 1032 deletions
diff --git a/docs/reference/gck/gck-sections.txt b/docs/reference/gck/gck-sections.txt
index 21069a8d..e200c28c 100644
--- a/docs/reference/gck/gck-sections.txt
+++ b/docs/reference/gck/gck-sections.txt
@@ -315,4 +315,6 @@ gck_value_to_ulong
GCK_INVALID
<SUBSECTION Private>
gck_get_error_quark
+GCK_TYPE_LIST
+gck_list_get_boxed_type
</SECTION>
diff --git a/docs/reference/gcr/Makefile.am b/docs/reference/gcr/Makefile.am
index 47499c97..d13563fd 100644
--- a/docs/reference/gcr/Makefile.am
+++ b/docs/reference/gcr/Makefile.am
@@ -64,11 +64,15 @@ IGNORE_HFILES= \
gcr-display-scrolled.h \
gcr-display-view.h \
gcr-failure-renderer.h \
+ gcr-gnupg-renderer.h \
gcr-icons.h \
gcr-import-dialog.h \
gcr-internal.h \
gcr-live-search.h \
gcr-marshal.h \
+ gcr-openpgp.h \
+ gcr-pkcs11-renderer.h \
+ gcr-record.h \
gcr-unlock-renderer.h \
gcr-xxx.h \
gcr-zzz.h
diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt
index 08e7dd0a..22e19b05 100644
--- a/docs/reference/gcr/gcr-sections.txt
+++ b/docs/reference/gcr/gcr-sections.txt
@@ -80,31 +80,40 @@ GcrGeneralNameType
<SECTION>
<FILE>gcr-importer</FILE>
GcrImporter
-GcrImporterClass
-GcrImporterPromptBehavior
-gcr_importer_new
-gcr_importer_listen
-gcr_importer_queue
+GcrImporterIface
gcr_importer_import
gcr_importer_import_async
gcr_importer_import_finish
-gcr_importer_get_slot
-gcr_importer_set_slot
-gcr_importer_get_prompt_behavior
-gcr_importer_set_prompt_behavior
-gcr_importer_get_parser
-gcr_importer_set_parser
+gcr_importer_register
+gcr_importer_register_well_known
+gcr_importer_create_for_parsed
+gcr_importer_queue_for_parsed
+gcr_importer_queue_and_filter_for_parsed
<SUBSECTION Standard>
-GcrImporterPrivate
GCR_IMPORTER
GCR_IS_IMPORTER
GCR_TYPE_IMPORTER
gcr_importer_get_type
-GCR_IMPORTER_CLASS
-GCR_IS_IMPORTER_CLASS
-GCR_IMPORTER_GET_CLASS
-GCR_TYPE_IMPORTER_PROMPT_BEHAVIOR
-gcr_importer_prompt_behavior_get_type
+GCR_IMPORTER_GET_INTERFACE
+<SUBSECTION Private>
+GCR_GNUPG_IMPORTER
+GCR_GNUPG_IMPORTER_CLASS
+GCR_GNUPG_IMPORTER_GET_CLASS
+GCR_IS_GNUPG_IMPORTER
+GCR_IS_GNUPG_IMPORTER_CLASS
+GCR_IS_PKCS11_IMPORTER
+GCR_IS_PKCS11_IMPORTER_CLASS
+GCR_PKCS11_IMPORTER
+GCR_PKCS11_IMPORTER_CLASS
+GCR_PKCS11_IMPORTER_GET_CLASS
+GCR_TYPE_GNUPG_IMPORTER
+GCR_TYPE_PKCS11_IMPORTER
+GcrGnupgImporter
+GcrGnupgImporterClass
+GcrGnupgImporterPrivate
+GcrPkcs11Importer
+GcrPkcs11ImporterClass
+GcrPkcs11ImporterPrivate
</SECTION>
<SECTION>
@@ -533,17 +542,6 @@ GCR_VIEWER_WINDOW_GET_CLASS
<SECTION>
<FILE>gcr-private</FILE>
<SUBSECTION Private>
-GCR_RECORD_SCHEMA_PUB
-GCR_RECORD_SCHEMA_UID
-GCR_RECORD_SCHEMA_SEC
-GCR_RECORD_SCHEMA_ATTRIBUTE
-GCR_RECORD_SCHEMA_FPR
-GCR_RECORD_SCHEMA_XA1
-GCR_RECORD_SCHEMA_RVK
-GCR_RECORD_SCHEMA_SIG
-GCR_RECORD_SCHEMA_SSB
-GCR_RECORD_SCHEMA_SUB
-GCR_RECORD_SCHEMA_UAT
GCR_GNUPG_COLLECTION
GCR_GNUPG_COLLECTION_CLASS
GCR_GNUPG_COLLECTION_GET_CLASS
@@ -557,19 +555,6 @@ GCR_IS_GNUPG_KEY
GCR_IS_GNUPG_KEY_CLASS
GCR_TYPE_GNUPG_COLLECTION
GCR_TYPE_GNUPG_KEY
-GCR_TYPE_RECORD
-GcrRecordColumns
-GcrRecordPubColumns
-GcrRecordUidColumns
-GcrRecordSecColumns
-GcrRecordAttributeColumns
-GcrRecordFprColumns
-GcrRecordXa1Columns
-GcrRecordKeyColumns
-GcrRecordRvkColumns
-GcrRecordSigColumns
-GcrRecordUatColumns
-GcrRecord
GCR_GNUPG_PROCESS
GCR_GNUPG_PROCESS_CLASS
GCR_GNUPG_PROCESS_GET_CLASS
@@ -600,7 +585,6 @@ GcrMemoryIconPrivate
GCR_ERROR
gcr_error_get_domain
GcrOpensshPubCallback
-GcrOpenpgpCallback
GCR_CALLBACK_OUTPUT_STREAM
GCR_CALLBACK_OUTPUT_STREAM_CLASS
GCR_CALLBACK_OUTPUT_STREAM_GET_CLASS
@@ -610,15 +594,4 @@ GCR_TYPE_CALLBACK_OUTPUT_STREAM
GcrCallbackOutputFunc
GcrCallbackOutputStream
GcrCallbackOutputStreamClass
-GcrOpenpgpParseFlags
-GCR_GNUPG_RENDERER
-GCR_GNUPG_RENDERER_CLASS
-GCR_GNUPG_RENDERER_GET_CLASS
-GCR_IS_GNUPG_RENDERER
-GCR_IS_GNUPG_RENDERER_CLASS
-GCR_TYPE_GNUPG_RENDERER
-GcrGnupgRenderer
-GcrGnupgRendererClass
-GcrGnupgRendererPrivate
-GcrOpenpgpAlgo
</SECTION>
diff --git a/gck/gck-misc.c b/gck/gck-misc.c
index 4004954d..563f40dc 100644
--- a/gck/gck-misc.c
+++ b/gck/gck-misc.c
@@ -212,6 +212,18 @@ _gck_stringize_rv (CK_RV rv)
* library or PKCS11 in general.
*/
+GType
+gck_list_get_boxed_type (void)
+{
+ static GType type = 0;
+ if (!type)
+ type = g_boxed_type_register_static ("GckList",
+ (GBoxedCopyFunc)gck_list_ref_copy,
+ (GBoxedFreeFunc)gck_list_unref_free);
+ return type;
+
+}
+
/**
* gck_list_unref_free:
* @reflist: List of Gobject reference counted pointers.
diff --git a/gck/gck.h b/gck/gck.h
index 1d8ff3d1..42064e38 100644
--- a/gck/gck.h
+++ b/gck/gck.h
@@ -50,6 +50,10 @@ G_BEGIN_DECLS
GQuark gck_get_error_quark (void);
+#define GCK_TYPE_LIST (gck_list_get_boxed_type ())
+
+GType gck_list_get_boxed_type (void) G_GNUC_CONST;
+
GList* gck_list_ref_copy (GList *reflist);
void gck_list_unref_free (GList *reflist);
diff --git a/gck/gck.symbols b/gck/gck.symbols
index c6cfb1e2..18df7b65 100644
--- a/gck/gck.symbols
+++ b/gck/gck.symbols
@@ -59,6 +59,7 @@ gck_enumerator_next_n
gck_get_error_quark
gck_list_ref_copy
gck_list_unref_free
+gck_list_get_boxed_type
gck_mechanism_info_free
gck_mechanisms_check
gck_message_from_rv
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index f4f86e06..4d31f9a4 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -97,11 +97,13 @@ libgcr_base_@GCR_MAJOR@_la_SOURCES = \
gcr-comparable.c gcr-comparable.h \
gcr-debug.c gcr-debug.h \
gcr-gnupg-collection.c gcr-gnupg-collection.h \
+ gcr-gnupg-importer.c gcr-gnupg-importer.h \
gcr-gnupg-key.c gcr-gnupg-key.h \
gcr-gnupg-process.c gcr-gnupg-process.h \
gcr-gnupg-records.c gcr-gnupg-records.h \
gcr-gnupg-util.c gcr-gnupg-util.h \
gcr-library.c gcr-library.h \
+ gcr-importer.c gcr-importer.h \
gcr-internal.h \
gcr-memory.c \
gcr-memory-icon.c gcr-memory-icon.h \
@@ -109,6 +111,7 @@ libgcr_base_@GCR_MAJOR@_la_SOURCES = \
gcr-openssh.c gcr-openssh.h \
gcr-parser.c gcr-parser.h \
gcr-pkcs11-certificate.c gcr-pkcs11-certificate.h \
+ gcr-pkcs11-importer.c gcr-pkcs11-importer.h \
gcr-record.c gcr-record.h \
gcr-simple-certificate.c gcr-simple-certificate.h \
gcr-simple-collection.c gcr-simple-collection.h \
@@ -136,7 +139,6 @@ libgcr_@GCR_MAJOR@_la_SOURCES = \
gcr-gnupg-records.c gcr-gnupg-records.h \
gcr-icons.c gcr-icons.h \
gcr-import-dialog.c gcr-import-dialog.h \
- gcr-importer.c gcr-importer.h \
gcr-key-renderer.c gcr-key-renderer.h \
gcr-key-widget.c gcr-key-widget.h \
gcr-list-selector.c gcr-list-selector.h gcr-list-selector-private.h \
diff --git a/gcr/gcr-base.symbols b/gcr/gcr-base.symbols
index 49b54e85..015543c6 100644
--- a/gcr/gcr-base.symbols
+++ b/gcr/gcr-base.symbols
@@ -52,6 +52,18 @@ gcr_data_error_get_domain
gcr_data_error_get_type
gcr_data_format_get_type
gcr_error_get_domain
+gcr_importer_get_parser
+gcr_importer_get_prompt_behavior
+gcr_importer_get_slot
+gcr_importer_create_for_parsed
+gcr_importer_get_type
+gcr_importer_import
+gcr_importer_import_async
+gcr_importer_import_finish
+gcr_importer_queue_and_filter_for_parsed
+gcr_importer_queue_for_parsed
+gcr_importer_register
+gcr_importer_register_well_known
gcr_parser_add_password
gcr_parser_format_disable
gcr_parser_format_enable
diff --git a/gcr/gcr-certificate-widget.c b/gcr/gcr-certificate-widget.c
index 82a8d91f..272354bd 100644
--- a/gcr/gcr-certificate-widget.c
+++ b/gcr/gcr-certificate-widget.c
@@ -169,7 +169,6 @@ static void
gcr_certificate_widget_class_init (GcrCertificateWidgetClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GckAttributes *registered;
gcr_certificate_widget_parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (klass, sizeof (GcrCertificateWidgetPrivate));
@@ -186,12 +185,6 @@ gcr_certificate_widget_class_init (GcrCertificateWidgetClass *klass)
g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
g_param_spec_boxed ("attributes", "Attributes", "Attributes which contain the certificate",
GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
-
- /* Register this as a renderer which can be loaded */
- registered = gck_attributes_new ();
- gck_attributes_add_ulong (registered, CKA_CLASS, CKO_CERTIFICATE);
- gcr_renderer_register (GCR_TYPE_CERTIFICATE_WIDGET, registered);
- gck_attributes_unref (registered);
}
/* -----------------------------------------------------------------------------
diff --git a/gcr/gcr-deprecated-base.h b/gcr/gcr-deprecated-base.h
index 9f812817..b8536709 100644
--- a/gcr/gcr-deprecated-base.h
+++ b/gcr/gcr-deprecated-base.h
@@ -31,6 +31,7 @@
#include <glib.h>
+#include "gcr-importer.h"
#include "gcr-parser.h"
#include "gcr-simple-collection.h"
@@ -43,6 +44,11 @@ GQuark gcr_error_get_domain (void) G_GNUC_CONS
gboolean gcr_simple_collection_contains (GcrSimpleCollection *self,
GObject *object);
+GcrParser * gcr_importer_get_parser (GcrImporter *self);
+
+void gcr_importer_set_parser (GcrImporter *self,
+ GcrParser *parser);
+
G_END_DECLS
#endif /* GCR_DISABLE_DEPRECATED */
diff --git a/gcr/gcr-deprecated.h b/gcr/gcr-deprecated.h
index b3bfad74..25cbc1d9 100644
--- a/gcr/gcr-deprecated.h
+++ b/gcr/gcr-deprecated.h
@@ -41,11 +41,6 @@ G_BEGIN_DECLS
void gcr_renderer_render (GcrRenderer *self,
GcrViewer *viewer);
-GcrParser* gcr_importer_get_parser (GcrImporter *self);
-
-void gcr_importer_set_parser (GcrImporter *self,
- GcrParser *parser);
-
G_END_DECLS
#endif /* GCR_DISABLE_DEPRECATED */
diff --git a/gcr/gcr-gnupg-importer.c b/gcr/gcr-gnupg-importer.c
new file mode 100644
index 00000000..f527938c
--- /dev/null
+++ b/gcr/gcr-gnupg-importer.c
@@ -0,0 +1,315 @@
+/*
+ * gnome-keyring
+ *
+ * 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.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "gcr-gnupg-importer.h"
+#include "gcr-gnupg-process.h"
+#include "gcr-internal.h"
+
+#include <glib/gi18n-lib.h>
+
+enum {
+ PROP_0,
+ PROP_LABEL,
+ PROP_ICON,
+ PROP_IMPORTED,
+ PROP_DIRECTORY
+};
+
+struct _GcrGnupgImporterPrivate {
+ GcrGnupgProcess *process;
+ GMemoryInputStream *packets;
+ GArray *imported;
+};
+
+static void gcr_gnupg_importer_iface (GcrImporterIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrGnupgImporter, _gcr_gnupg_importer, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GCR_TYPE_IMPORTER, gcr_gnupg_importer_iface);
+);
+
+static void
+_gcr_gnupg_importer_init (GcrGnupgImporter *self)
+{
+ self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_IMPORTER, GcrGnupgImporterPrivate);
+ self->pv->packets = G_MEMORY_INPUT_STREAM (g_memory_input_stream_new ());
+ self->pv->imported = g_array_new (TRUE, TRUE, sizeof (gchar *));
+}
+
+static void
+_gcr_gnupg_importer_dispose (GObject *obj)
+{
+ GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj);
+
+ if (self->pv->process)
+ g_object_run_dispose (G_OBJECT (self->pv->process));
+ g_clear_object (&self->pv->process);
+ g_clear_object (&self->pv->packets);
+
+ G_OBJECT_CLASS (_gcr_gnupg_importer_parent_class)->dispose (obj);
+}
+
+static void
+_gcr_gnupg_importer_finalize (GObject *obj)
+{
+ GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj);
+
+ g_array_free (self->pv->imported, TRUE);
+
+ G_OBJECT_CLASS (_gcr_gnupg_importer_parent_class)->finalize (obj);
+}
+
+static gchar *
+calculate_label (GcrGnupgImporter *self)
+{
+ const gchar *directory;
+
+ directory = _gcr_gnupg_process_get_directory (self->pv->process);
+ if (directory == NULL)
+ return g_strdup (_("GnuPG Keyring"));
+ else
+ return g_strdup_printf (_("GnuPG Keyring: %s"), directory);
+}
+
+static GIcon *
+calculate_icon (GcrGnupgImporter *self)
+{
+ const gchar *directory;
+
+ directory = _gcr_gnupg_process_get_directory (self->pv->process);
+ if (directory == NULL)
+ return g_themed_icon_new ("user-home");
+ else
+ return g_themed_icon_new ("folder");
+}
+
+static gboolean
+on_process_status_record (GcrGnupgProcess *process,
+ GcrRecord *record,
+ gpointer user_data)
+{
+ GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (user_data);
+ const gchar *value;
+ gchar *fingerprint;
+
+ if (_gcr_record_get_schema (record) != GCR_RECORD_SCHEMA_IMPORT_OK)
+ return TRUE;
+
+ value = _gcr_record_get_raw (record, GCR_RECORD_IMPORT_FINGERPRINT);
+ if (value != NULL && value[0] != 0) {
+ fingerprint = g_strdup (value);
+ g_array_append_val (self->pv->imported, fingerprint);
+ }
+
+ return TRUE;
+}
+
+static void
+_gcr_gnupg_importer_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj);
+
+ switch (prop_id) {
+ case PROP_DIRECTORY:
+ self->pv->process = _gcr_gnupg_process_new (g_value_get_string (value),
+ NULL);
+ _gcr_gnupg_process_set_input_stream (self->pv->process, G_INPUT_STREAM (self->pv->packets));
+ g_signal_connect (self->pv->process, "status-record", G_CALLBACK (on_process_status_record), self);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gcr_gnupg_importer_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj);
+
+ switch (prop_id) {
+ case PROP_LABEL:
+ g_value_take_string (value, calculate_label (self));
+ break;
+ case PROP_ICON:
+ g_value_take_object (value, calculate_icon (self));
+ break;
+ case PROP_IMPORTED:
+ g_value_set_boxed (value, _gcr_gnupg_importer_get_imported (self));
+ break;
+ case PROP_DIRECTORY:
+ g_value_set_string (value, _gcr_gnupg_process_get_directory (self->pv->process));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gcr_gnupg_importer_class_init (GcrGnupgImporterClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GckAttributes *registered;
+
+ gobject_class->dispose = _gcr_gnupg_importer_dispose;
+ gobject_class->finalize = _gcr_gnupg_importer_finalize;
+ gobject_class->set_property = _gcr_gnupg_importer_set_property;
+ gobject_class->get_property = _gcr_gnupg_importer_get_property;
+
+ g_type_class_add_private (gobject_class, sizeof (GcrGnupgImporterPrivate));
+
+ g_object_class_override_property (gobject_class, PROP_LABEL, "label");
+
+ g_object_class_override_property (gobject_class, PROP_ICON, "icon");
+
+ g_object_class_install_property (gobject_class, PROP_IMPORTED,
+ g_param_spec_boxed ("imported", "Imported", "Fingerprints of imported keys",
+ G_TYPE_STRV, G_PARAM_READABLE));
+
+ g_object_class_install_property (gobject_class, PROP_DIRECTORY,
+ g_param_spec_string ("directory", "Directory", "Directory to import keys to",
+ NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ registered = gck_attributes_new ();
+ gck_attributes_add_ulong (registered, CKA_CLASS, CKO_GCR_GNUPG_RECORDS);
+ gcr_importer_register (GCR_TYPE_GNUPG_IMPORTER, registered);
+ gck_attributes_unref (registered);
+
+ _gcr_initialize_library ();
+}
+
+static GList *
+_gcr_gnupg_importer_create_for_parsed (GcrParser *parser)
+{
+ GcrImporter *self;
+
+ if (gcr_parser_get_parsed_format (parser) != GCR_FORMAT_OPENPGP_PACKET)
+ return FALSE;
+
+ self = _gcr_gnupg_importer_new (NULL);
+ if (!gcr_importer_queue_for_parsed (self, parser))
+ g_assert_not_reached ();
+
+ return g_list_append (NULL, self);
+}
+
+static gboolean
+_gcr_gnupg_importer_queue_for_parsed (GcrImporter *importer,
+ GcrParser *parser)
+{
+ GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (importer);
+ gconstpointer block;
+ gsize n_block;
+
+ if (gcr_parser_get_parsed_format (parser) != GCR_FORMAT_OPENPGP_PACKET)
+ return FALSE;
+
+ block = gcr_parser_get_parsed_block (parser, &n_block);
+ g_return_val_if_fail (block, FALSE);
+
+ g_memory_input_stream_add_data (self->pv->packets, g_memdup (block, n_block),
+ n_block, g_free);
+ return TRUE;
+}
+
+static void
+on_process_run_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ GError *error = NULL;
+
+ if (!_gcr_gnupg_process_run_finish (GCR_GNUPG_PROCESS (source), result, &error))
+ g_simple_async_result_take_error (res, error);
+
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
+}
+
+static void
+_gcr_gnupg_importer_import_async (GcrImporter *importer,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (importer);
+ GSimpleAsyncResult *res;
+ const gchar *argv[] = { "--import", NULL };
+
+ res = g_simple_async_result_new (G_OBJECT (importer), callback, user_data,
+ _gcr_gnupg_importer_import_async);
+
+ _gcr_gnupg_process_run_async (self->pv->process, argv, NULL,
+ GCR_GNUPG_PROCESS_WITH_STATUS,
+ cancellable, on_process_run_complete,
+ g_object_ref (res));
+
+ g_object_unref (res);
+}
+
+static gboolean
+_gcr_gnupg_importer_import_finish (GcrImporter *importer,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (importer),
+ _gcr_gnupg_importer_import_async), FALSE);
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+gcr_gnupg_importer_iface (GcrImporterIface *iface)
+{
+ iface->create_for_parsed = _gcr_gnupg_importer_create_for_parsed;
+ iface->queue_for_parsed = _gcr_gnupg_importer_queue_for_parsed;
+ iface->import_async = _gcr_gnupg_importer_import_async;
+ iface->import_finish = _gcr_gnupg_importer_import_finish;
+}
+
+GcrImporter *
+_gcr_gnupg_importer_new (const gchar *directory)
+{
+ return g_object_new (GCR_TYPE_GNUPG_IMPORTER,
+ "directory", directory,
+ NULL);
+}
+
+const gchar **
+_gcr_gnupg_importer_get_imported (GcrGnupgImporter *self)
+{
+ g_return_val_if_fail (GCR_IS_GNUPG_IMPORTER (self), NULL);
+ return (const gchar **)self->pv->imported->data;
+}
diff --git a/gcr/gcr-gnupg-importer.h b/gcr/gcr-gnupg-importer.h
new file mode 100644
index 00000000..8511af84
--- /dev/null
+++ b/gcr/gcr-gnupg-importer.h
@@ -0,0 +1,67 @@
+/*
+ * gnome-keyring
+ *
+ * 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.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> can be included directly."
+#endif
+
+#ifndef __GCR_GNUPG_IMPORTER_H__
+#define __GCR_GNUPG_IMPORTER_H__
+
+#include "gcr-importer.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_GNUPG_IMPORTER (_gcr_gnupg_importer_get_type ())
+#define GCR_GNUPG_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_GNUPG_IMPORTER, GcrGnupgImporter))
+#define GCR_GNUPG_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_GNUPG_IMPORTER, GcrGnupgImporterClass))
+#define GCR_IS_GNUPG_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_GNUPG_IMPORTER))
+#define GCR_IS_GNUPG_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_GNUPG_IMPORTER))
+#define GCR_GNUPG_IMPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_GNUPG_IMPORTER, GcrGnupgImporterClass))
+
+typedef struct _GcrGnupgImporter GcrGnupgImporter;
+typedef struct _GcrGnupgImporterClass GcrGnupgImporterClass;
+typedef struct _GcrGnupgImporterPrivate GcrGnupgImporterPrivate;
+
+struct _GcrGnupgImporter {
+ GObject parent;
+
+ /*< private >*/
+ GcrGnupgImporterPrivate *pv;
+};
+
+struct _GcrGnupgImporterClass {
+ GObjectClass parent_class;
+};
+
+GType _gcr_gnupg_importer_get_type (void) G_GNUC_CONST;
+
+GcrImporter * _gcr_gnupg_importer_new (const gchar *directory);
+
+const gchar ** _gcr_gnupg_importer_get_imported (GcrGnupgImporter *self);
+
+G_END_DECLS
+
+#endif /* __GCR_IMPORTER_H__ */
diff --git a/gcr/gcr-gnupg-process.c b/gcr/gcr-gnupg-process.c
index ed4592aa..0e87ea9a 100644
--- a/gcr/gcr-gnupg-process.c
+++ b/gcr/gcr-gnupg-process.c
@@ -343,6 +343,13 @@ _gcr_gnupg_process_new (const gchar *directory, const gchar *executable)
NULL);
}
+const gchar *
+_gcr_gnupg_process_get_directory (GcrGnupgProcess *self)
+{
+ g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL);
+ return self->pv->directory;
+}
+
GInputStream *
_gcr_gnupg_process_get_input_stream (GcrGnupgProcess *self)
{
diff --git a/gcr/gcr-gnupg-process.h b/gcr/gcr-gnupg-process.h
index 8eabfeba..820f371c 100644
--- a/gcr/gcr-gnupg-process.h
+++ b/gcr/gcr-gnupg-process.h
@@ -68,6 +68,8 @@ GType _gcr_gnupg_process_get_type (void) G_GNUC_CON
GcrGnupgProcess* _gcr_gnupg_process_new (const gchar *directory,
const gchar *executable);
+const gchar * _gcr_gnupg_process_get_directory (GcrGnupgProcess *self);
+
GInputStream * _gcr_gnupg_process_get_input_stream (GcrGnupgProcess *self);
void _gcr_gnupg_process_set_input_stream (GcrGnupgProcess *self,
diff --git a/gcr/gcr-import-dialog.c b/gcr/gcr-import-dialog.c
index 11960350..2c73924c 100644
--- a/gcr/gcr-import-dialog.c
+++ b/gcr/gcr-import-dialog.c
@@ -27,21 +27,16 @@
#include "egg/egg-entry-buffer.h"
+#if TODO
+
enum {
PROP_0,
- PROP_SELECTED_SLOT,
- PROP_PASSWORD,
+ PROP_IMPORTER,
+ PROP_IMPORTERS,
PROP_PRIMARY_TEXT,
PROP_SECONDARY_TEXT
};
-enum {
- COLUMN_SLOT,
- COLUMN_ICON,
- COLUMN_LABEL,
- N_COLUMNS
-};
-
struct _GcrImportDialogPrivate {
GtkBuilder *builder;
GtkEntry *entry;
@@ -460,3 +455,5 @@ _gcr_import_dialog_set_secondary_text (GcrImportDialog *self, const gchar *text)
gtk_label_set_markup (GTK_LABEL (gtk_builder_get_object (self->pv->builder, "secondary-text")), text);
g_object_notify (G_OBJECT (self), "primary-text");
}
+
+#endif /* TODO */
diff --git a/gcr/gcr-import-dialog.h b/gcr/gcr-import-dialog.h
index 00e147e4..692e71ab 100644
--- a/gcr/gcr-import-dialog.h
+++ b/gcr/gcr-import-dialog.h
@@ -52,24 +52,15 @@ struct _GcrImportDialogClass {
GType _gcr_import_dialog_get_type (void);
-GcrImportDialog* _gcr_import_dialog_new (void);
+GcrImportDialog * _gcr_import_dialog_new (GList *importers);
gboolean _gcr_import_dialog_run (GcrImportDialog *self,
GtkWindow *parent);
-GckSlot* _gcr_import_dialog_get_selected_slot (GcrImportDialog *self);
+GcrImporter * _gcr_import_dialog_get_importer (GcrImportDialog *self);
-void _gcr_import_dialog_set_selected_slot (GcrImportDialog *self,
- GckSlot *slot);
-
-void _gcr_import_dialog_show_selected_slot (GcrImportDialog *self);
-
-void _gcr_import_dialog_hide_selected_slot (GcrImportDialog *self);
-
-const gchar* _gcr_import_dialog_get_password (GcrImportDialog *self);
-
-void _gcr_import_dialog_set_password (GcrImportDialog *self,
- const gchar *password);
+void _gcr_import_dialog_set_importer (GcrImportDialog *self,
+ GcrImporter *importer);
void _gcr_import_dialog_show_password (GcrImportDialog *self);
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 */
diff --git a/gcr/gcr-importer.h b/gcr/gcr-importer.h
index 892b5d48..1441e327 100644
--- a/gcr/gcr-importer.h
+++ b/gcr/gcr-importer.h
@@ -1,22 +1,24 @@
-/*
+/*
* 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>
*/
#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
@@ -27,77 +29,70 @@
#define __GCR_IMPORTER_H__
#include "gcr-parser.h"
-#include "gcr-types.h"
#include <glib-object.h>
G_BEGIN_DECLS
-typedef enum {
- GCR_IMPORTER_PROMPT_NEEDED,
- GCR_IMPORTER_PROMPT_ALWAYS,
- GCR_IMPORTER_PROMPT_NEVER
-} GcrImporterPromptBehavior;
-
-#define GCR_TYPE_IMPORTER (gcr_importer_get_type ())
-#define GCR_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_IMPORTER, GcrImporter))
-#define GCR_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_IMPORTER, GcrImporterClass))
-#define GCR_IS_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_IMPORTER))
-#define GCR_IS_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_IMPORTER))
-#define GCR_IMPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_IMPORTER, GcrImporterClass))
+#define GCR_TYPE_IMPORTER (gcr_importer_get_type ())
+#define GCR_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_IMPORTER, GcrImporter))
+#define GCR_IS_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_IMPORTER))
+#define GCR_IMPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_IMPORTER, GcrImporterIface))
typedef struct _GcrImporter GcrImporter;
-typedef struct _GcrImporterClass GcrImporterClass;
-typedef struct _GcrImporterPrivate GcrImporterPrivate;
+typedef struct _GcrImporterIface GcrImporterIface;
-struct _GcrImporter {
- GObject parent;
+struct _GcrImporterIface {
+ GTypeInterface parent;
- /*< private >*/
- GcrImporterPrivate *pv;
-};
+ GList * (*create_for_parsed) (GcrParser *parser);
-struct _GcrImporterClass {
- GObjectClass parent_class;
+ gboolean (*queue_for_parsed) (GcrImporter *importer,
+ GcrParser *parser);
- /* signals */
- void (*queued) (GcrImporter *self, const gchar *label, GckAttributes *attrs);
- void (*imported) (GcrImporter *self, GckObject *object);
-};
+ gboolean (*import_sync) (GcrImporter *importer,
+ GCancellable *cancellable,
+ GError **error);
-GType gcr_importer_get_type (void);
+ void (*import_async) (GcrImporter *importer,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
-GcrImporter* gcr_importer_new (void);
+ gboolean (*import_finish) (GcrImporter *importer,
+ GAsyncResult *result,
+ GError **error);
+
+ gpointer reserved[14];
+};
-GckSlot* gcr_importer_get_slot (GcrImporter *self);
+GType gcr_importer_get_type (void);
-void gcr_importer_set_slot (GcrImporter *self,
- GckSlot *slot);
+GList * gcr_importer_create_for_parsed (GcrParser *parser);
-GcrImporterPromptBehavior gcr_importer_get_prompt_behavior (GcrImporter *self);
+gboolean gcr_importer_queue_for_parsed (GcrImporter *importer,
+ GcrParser *parser);
-void gcr_importer_set_prompt_behavior (GcrImporter *self,
- GcrImporterPromptBehavior behavior);
+GList * gcr_importer_queue_and_filter_for_parsed (GList *importers,
+ GcrParser *parser);
-void gcr_importer_queue (GcrImporter *self,
- const gchar *label,
- GckAttributes *attrs);
+gboolean gcr_importer_import (GcrImporter *importer,
+ GCancellable *cancellable,
+ GError **error);
-void gcr_importer_listen (GcrImporter *self,
- GcrParser *parser);
+void gcr_importer_import_async (GcrImporter *importer,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
-gboolean gcr_importer_import (GcrImporter *self,
- GCancellable *cancellable,
- GError **error);
+gboolean gcr_importer_import_finish (GcrImporter *importer,
+ GAsyncResult *result,
+ GError **error);
-void gcr_importer_import_async (GcrImporter *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+void gcr_importer_register (GType importer_type,
+ GckAttributes *attrs);
-gboolean gcr_importer_import_finish (GcrImporter *self,
- GAsyncResult *result,
- GError **error);
+void gcr_importer_register_well_known (void);
G_END_DECLS
diff --git a/gcr/gcr-internal.h b/gcr/gcr-internal.h
index 9ae38315..fdf37488 100644
--- a/gcr/gcr-internal.h
+++ b/gcr/gcr-internal.h
@@ -25,6 +25,7 @@
#define GCR_INTERNAL_H_
#include <glib.h>
+#include <gio/gio.h>
/* Should only be used internally */
#define GCR_SUCCESS 0
diff --git a/gcr/gcr-key-widget.c b/gcr/gcr-key-widget.c
index 59eb04ff..be9139ef 100644
--- a/gcr/gcr-key-widget.c
+++ b/gcr/gcr-key-widget.c
@@ -160,7 +160,6 @@ static void
gcr_key_widget_class_init (GcrKeyWidgetClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GckAttributes *registered;
gcr_key_widget_parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (klass, sizeof (GcrKeyWidgetPrivate));
@@ -173,12 +172,6 @@ gcr_key_widget_class_init (GcrKeyWidgetClass *klass)
g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the widget",
GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
-
- /* Register this as a view which can be loaded */
- registered = gck_attributes_new ();
- gck_attributes_add_ulong (registered, CKA_CLASS, CKO_PRIVATE_KEY);
- gcr_renderer_register (GCR_TYPE_KEY_WIDGET, registered);
- gck_attributes_unref (registered);
}
/* -----------------------------------------------------------------------------
diff --git a/gcr/gcr-pkcs11-importer.c b/gcr/gcr-pkcs11-importer.c
new file mode 100644
index 00000000..714e13a2
--- /dev/null
+++ b/gcr/gcr-pkcs11-importer.c
@@ -0,0 +1,582 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 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 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.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "gcr-internal.h"
+#include "gcr-library.h"
+#include "gcr-parser.h"
+#include "gcr-pkcs11-importer.h"
+
+#include <gck/gck.h>
+
+#include <glib/gi18n-lib.h>
+
+enum {
+ PROP_0,
+ PROP_LABEL,
+ PROP_ICON,
+ PROP_SLOT,
+ PROP_IMPORTED
+};
+
+struct _GcrPkcs11ImporterPrivate {
+ GckSlot *slot;
+ GList *objects;
+ GckSession *session;
+ GQueue queue;
+ gboolean any_private;
+};
+
+typedef struct {
+ GcrPkcs11Importer *importer;
+ GCancellable *cancellable;
+ gboolean prompted;
+ gboolean async;
+} GcrImporterData;
+
+/* State forward declarations */
+static void state_cancelled (GSimpleAsyncResult *res,
+ gboolean async);
+
+static void state_complete (GSimpleAsyncResult *res,
+ gboolean async);
+
+static void state_create_object (GSimpleAsyncResult *res,
+ gboolean async);
+
+static void state_open_session (GSimpleAsyncResult *res,
+ gboolean async);
+
+static void _gcr_pkcs11_importer_init_iface (GcrImporterIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrPkcs11Importer, _gcr_pkcs11_importer, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GCR_TYPE_IMPORTER, _gcr_pkcs11_importer_init_iface);
+);
+
+#define BLOCK 4096
+
+static void
+gcr_importer_data_free (gpointer data)
+{
+ GcrImporterData *state = data;
+
+ g_clear_object (&state->cancellable);
+ g_clear_object (&state->importer);
+ g_free (state);
+}
+
+static void
+next_state (GSimpleAsyncResult *res,
+ void (*state) (GSimpleAsyncResult *, gboolean))
+{
+ GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
+
+ g_assert (state);
+
+ if (g_cancellable_is_cancelled (data->cancellable))
+ state = state_cancelled;
+
+ (state) (res, data->async);
+}
+
+/* ---------------------------------------------------------------------------------
+ * COMPLETE
+ */
+
+static void
+state_complete (GSimpleAsyncResult *res,
+ gboolean async)
+{
+ g_simple_async_result_complete (res);
+}
+
+static void
+state_cancelled (GSimpleAsyncResult *res,
+ gboolean async)
+{
+ GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
+ GError *error = NULL;
+
+ if (data->cancellable && !g_cancellable_is_cancelled (data->cancellable))
+ g_cancellable_cancel (data->cancellable);
+
+ g_cancellable_set_error_if_cancelled (data->cancellable, &error);
+ g_simple_async_result_take_error (res, error);
+ next_state (res, state_complete);
+}
+
+/* ---------------------------------------------------------------------------------
+ * CREATE OBJECTS
+ */
+
+static void
+complete_create_object (GSimpleAsyncResult *res,
+ GckObject *object,
+ GError *error)
+{
+ GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
+ GcrPkcs11Importer *self = data->importer;
+
+ if (object == NULL) {
+ g_simple_async_result_take_error (res, error);
+ next_state (res, state_complete);
+
+ } else {
+ self->pv->objects = g_list_append (self->pv->objects, object);
+ next_state (res, state_create_object);
+ }
+}
+
+static void
+on_create_object (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ GError *error = NULL;
+ GckObject *object;
+
+ object = gck_session_create_object_finish (GCK_SESSION (source), result, &error);
+ complete_create_object (res, object, error);
+ g_object_unref (res);
+}
+
+static void
+state_create_object (GSimpleAsyncResult *res,
+ gboolean async)
+{
+ GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
+ GcrPkcs11Importer *self = data->importer;
+ GckAttributes *attrs;
+ GckObject *object;
+ GError *error = NULL;
+
+ /* No more objects */
+ if (g_queue_is_empty (&self->pv->queue)) {
+ next_state (res, state_complete);
+
+ } else {
+
+ /* Pop first one off the list */
+ attrs = g_queue_pop_head (&self->pv->queue);
+ g_assert (attrs != NULL);
+
+ gck_attributes_add_boolean (attrs, CKA_TOKEN, CK_TRUE);
+
+ if (async) {
+ gck_session_create_object_async (self->pv->session, attrs,
+ data->cancellable, on_create_object,
+ g_object_ref (res));
+ } else {
+ object = gck_session_create_object (self->pv->session, attrs,
+ data->cancellable, &error);
+ complete_create_object (res, object, error);
+ }
+
+ gck_attributes_unref (attrs);
+ }
+}
+
+/* ---------------------------------------------------------------------------------
+ * OPEN SESSION
+ */
+
+static void
+complete_open_session (GSimpleAsyncResult *res,
+ GckSession *session,
+ GError *error)
+{
+ GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
+ GcrPkcs11Importer *self = data->importer;
+
+ if (!session) {
+ g_simple_async_result_take_error (res, error);
+ next_state (res, state_complete);
+
+ } else {
+ g_clear_object (&self->pv->session);
+ self->pv->session = session;
+ next_state (res, state_create_object);
+ }
+}
+
+static void
+on_open_session (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ GError *error = NULL;
+ GckSession *session;
+
+ session = gck_slot_open_session_finish (GCK_SLOT (source), result, &error);
+ complete_open_session (res, session, error);
+ g_object_unref (res);
+}
+
+static void
+state_open_session (GSimpleAsyncResult *res,
+ gboolean async)
+{
+ GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res);
+ GcrPkcs11Importer *self = data->importer;
+ guint options = GCK_SESSION_READ_WRITE;
+ GckSession *session;
+ GError *error = NULL;
+
+ if (self->pv->any_private)
+ options |= GCK_SESSION_LOGIN_USER;
+
+ if (async) {
+ gck_slot_open_session_async (self->pv->slot, options,
+ data->cancellable, on_open_session,
+ g_object_ref (res));
+ } else {
+ session = gck_slot_open_session_full (self->pv->slot, options, 0,
+ NULL, NULL, data->cancellable, &error);
+ complete_open_session (res, session, error);
+ }
+}
+
+static void
+_gcr_pkcs11_importer_init (GcrPkcs11Importer *self)
+{
+ self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_PKCS11_IMPORTER, GcrPkcs11ImporterPrivate);
+ g_queue_init (&self->pv->queue);
+}
+
+static void
+_gcr_pkcs11_importer_dispose (GObject *obj)
+{
+ GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
+
+ gck_list_unref_free (self->pv->objects);
+ self->pv->objects = NULL;
+ g_clear_object (&self->pv->session);
+
+ while (!g_queue_is_empty (&self->pv->queue))
+ gck_attributes_unref (g_queue_pop_head (&self->pv->queue));
+
+ G_OBJECT_CLASS (_gcr_pkcs11_importer_parent_class)->dispose (obj);
+}
+
+static void
+_gcr_pkcs11_importer_finalize (GObject *obj)
+{
+ GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
+
+ g_clear_object (&self->pv->slot);
+
+ G_OBJECT_CLASS (_gcr_pkcs11_importer_parent_class)->finalize (obj);
+}
+
+static void
+_gcr_pkcs11_importer_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
+
+ switch (prop_id) {
+ case PROP_SLOT:
+ self->pv->slot = g_value_dup_object (value);
+ g_return_if_fail (self->pv->slot);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static gchar *
+calculate_label (GcrPkcs11Importer *self)
+{
+ GckTokenInfo *info;
+ gchar *result;
+
+ info = gck_slot_get_token_info (self->pv->slot);
+ result = g_strdup (info->label);
+ gck_token_info_free (info);
+
+ return result;
+}
+
+static GIcon *
+calculate_icon (GcrPkcs11Importer *self)
+{
+ GckTokenInfo *info;
+ GIcon *result;
+
+ info = gck_slot_get_token_info (self->pv->slot);
+ if (g_strcmp0 (info->manufacturer_id, "Gnome Keyring") == 0)
+ result = g_themed_icon_new ("home-folder");
+ else
+ result = g_themed_icon_new ("media-flash");
+ gck_token_info_free (info);
+
+ return result;
+}
+
+static void
+_gcr_pkcs11_importer_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj);
+
+ switch (prop_id) {
+ case PROP_LABEL:
+ g_value_take_string (value, calculate_label (self));
+ break;
+ case PROP_ICON:
+ g_value_take_object (value, calculate_icon (self));
+ break;
+ case PROP_SLOT:
+ g_value_set_object (value, _gcr_pkcs11_importer_get_slot (self));
+ break;
+ case PROP_IMPORTED:
+ g_value_set_boxed (value, _gcr_pkcs11_importer_get_imported (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gcr_pkcs11_importer_class_init (GcrPkcs11ImporterClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GckAttributes *registered;
+
+ gobject_class->dispose = _gcr_pkcs11_importer_dispose;
+ gobject_class->finalize = _gcr_pkcs11_importer_finalize;
+ gobject_class->set_property = _gcr_pkcs11_importer_set_property;
+ gobject_class->get_property = _gcr_pkcs11_importer_get_property;
+
+ g_type_class_add_private (gobject_class, sizeof (GcrPkcs11ImporterPrivate));
+
+ g_object_class_override_property (gobject_class, PROP_LABEL, "label");
+
+ g_object_class_override_property (gobject_class, PROP_ICON, "icon");
+
+ 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_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (gobject_class, PROP_IMPORTED,
+ g_param_spec_boxed ("imported", "Imported", "Imported objects",
+ GCK_TYPE_LIST, G_PARAM_READABLE));
+
+ registered = gck_attributes_new ();
+ gck_attributes_add_ulong (registered, CKA_CLASS, CKO_CERTIFICATE);
+ gck_attributes_add_ulong (registered, CKA_CERTIFICATE_TYPE, CKC_X_509);
+ gcr_importer_register (GCR_TYPE_PKCS11_IMPORTER, registered);
+ gck_attributes_unref (registered);
+
+ registered = gck_attributes_new ();
+ gck_attributes_add_ulong (registered, CKA_CLASS, CKO_PRIVATE_KEY);
+ gcr_importer_register (GCR_TYPE_PKCS11_IMPORTER, registered);
+ gck_attributes_unref (registered);
+
+ _gcr_initialize_library ();
+}
+
+static GList *
+list_all_slots (void)
+{
+ GError *error = NULL;
+ GList *modules, *l;
+ GList *results = NULL;
+
+ if (!_gcr_initialize_pkcs11 (NULL, &error)) {
+ g_warning ("couldn't initialize PKCS#11 modules: %s", error->message);
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ modules = gcr_pkcs11_get_modules ();
+ for (l = modules; l != NULL; l = g_list_next (l))
+ results = g_list_concat (results, gck_modules_get_slots (modules, TRUE));
+ gck_list_unref_free (modules);
+
+ return results;
+}
+
+static const char *token_blacklist[] = {
+ "pkcs11:manufacturer=Gnome%20Keyring;serial=1:SECRET:MAIN",
+ NULL
+};
+
+static gboolean
+is_slot_importable (GckSlot *slot,
+ GckTokenInfo *token)
+{
+ GError *error = NULL;
+ GckUriData *uri;
+ gboolean match;
+ guint i;
+
+ if (token->flags & CKF_WRITE_PROTECTED)
+ return FALSE;
+ if (!(token->flags & CKF_TOKEN_INITIALIZED))
+ return FALSE;
+ if ((token->flags & CKF_LOGIN_REQUIRED) &&
+ !(token->flags & CKF_USER_PIN_INITIALIZED))
+ return FALSE;
+
+ for (i = 0; token_blacklist[i] != NULL; i++) {
+ uri = gck_uri_parse (token_blacklist[i], GCK_URI_FOR_TOKEN | GCK_URI_FOR_MODULE, &error);
+ if (uri == NULL) {
+ g_warning ("couldn't parse pkcs11 blacklist uri: %s", error->message);
+ g_clear_error (&error);
+ continue;
+ }
+
+ match = gck_slot_match (slot, uri);
+ gck_uri_data_free (uri);
+
+ if (match)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GList *
+_gcr_pkcs11_importer_create_for_parsed (GcrParser *parser)
+{
+ GcrImporter *self;
+ GList *slots, *l;
+ GList *results = NULL;
+ GckTokenInfo *token_info;
+ gboolean importable;
+
+ slots = list_all_slots ();
+ for (l = slots; l != NULL; l = g_list_next (l)) {
+ token_info = gck_slot_get_token_info (l->data);
+ importable = is_slot_importable (l->data, token_info);
+ gck_token_info_free (token_info);
+
+ if (importable) {
+ self = _gcr_pkcs11_importer_new (l->data);
+ if (!gcr_importer_queue_for_parsed (self, parser))
+ g_assert_not_reached ();
+ results = g_list_prepend (results, self);
+ }
+ }
+ gck_list_unref_free (slots);
+
+ return g_list_reverse (results);
+}
+
+static gboolean
+_gcr_pkcs11_importer_queue_for_parsed (GcrImporter *importer,
+ GcrParser *parser)
+{
+ GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (importer);
+ GckAttributes *attrs;
+ gboolean is_private;
+
+ attrs = gcr_parser_get_parsed_attributes (parser);
+
+ if (!gck_attributes_find_boolean (attrs, CKA_PRIVATE, &is_private))
+ is_private = FALSE;
+ if (is_private)
+ self->pv->any_private = TRUE;
+
+ g_queue_push_tail (&self->pv->queue, gck_attributes_ref (attrs));
+ return TRUE;
+}
+
+static void
+_gcr_pkcs11_importer_import_async (GcrImporter *importer,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ GcrImporterData *data;
+
+ res = g_simple_async_result_new (G_OBJECT (importer), callback, user_data,
+ _gcr_pkcs11_importer_import_async);
+ data = g_new0 (GcrImporterData, 1);
+ data->async = TRUE;
+ data->importer = g_object_ref (importer);
+ data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ g_simple_async_result_set_op_res_gpointer (res, data, gcr_importer_data_free);
+
+ next_state (res, state_open_session);
+ g_object_unref (res);
+}
+
+static gboolean
+_gcr_pkcs11_importer_import_finish (GcrImporter *importer,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (importer),
+ _gcr_pkcs11_importer_import_async), FALSE);
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+_gcr_pkcs11_importer_init_iface (GcrImporterIface *iface)
+{
+ iface->create_for_parsed = _gcr_pkcs11_importer_create_for_parsed;
+ iface->queue_for_parsed = _gcr_pkcs11_importer_queue_for_parsed;
+ iface->import_async = _gcr_pkcs11_importer_import_async;
+ iface->import_finish = _gcr_pkcs11_importer_import_finish;
+}
+
+GcrImporter *
+_gcr_pkcs11_importer_new (GckSlot *slot)
+{
+ g_return_val_if_fail (GCK_IS_SLOT (slot), NULL);
+
+ return g_object_new (GCR_TYPE_PKCS11_IMPORTER,
+ "slot", slot,
+ NULL);
+}
+
+GckSlot *
+_gcr_pkcs11_importer_get_slot (GcrPkcs11Importer *self)
+{
+ g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL);
+ return self->pv->slot;
+}
+
+GList *
+_gcr_pkcs11_importer_get_imported (GcrPkcs11Importer *self)
+{
+ g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL);
+ return self->pv->objects;
+}
diff --git a/gcr/gcr-pkcs11-importer.h b/gcr/gcr-pkcs11-importer.h
new file mode 100644
index 00000000..bbf752ca
--- /dev/null
+++ b/gcr/gcr-pkcs11-importer.h
@@ -0,0 +1,68 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 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 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.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> can be included directly."
+#endif
+
+#ifndef __GCR_PKCS11_IMPORTER_H__
+#define __GCR_PKCS11_IMPORTER_H__
+
+#include "gcr-importer.h"
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_PKCS11_IMPORTER (_gcr_pkcs11_importer_get_type ())
+#define GCR_PKCS11_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PKCS11_IMPORTER, GcrPkcs11Importer))
+#define GCR_PKCS11_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_PKCS11_IMPORTER, GcrPkcs11ImporterClass))
+#define GCR_IS_PKCS11_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PKCS11_IMPORTER))
+#define GCR_IS_PKCS11_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_PKCS11_IMPORTER))
+#define GCR_PKCS11_IMPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_PKCS11_IMPORTER, GcrPkcs11ImporterClass))
+
+typedef struct _GcrPkcs11Importer GcrPkcs11Importer;
+typedef struct _GcrPkcs11ImporterClass GcrPkcs11ImporterClass;
+typedef struct _GcrPkcs11ImporterPrivate GcrPkcs11ImporterPrivate;
+
+struct _GcrPkcs11Importer {
+ GObject parent;
+
+ /*< private >*/
+ GcrPkcs11ImporterPrivate *pv;
+};
+
+struct _GcrPkcs11ImporterClass {
+ GObjectClass parent_class;
+};
+
+GType _gcr_pkcs11_importer_get_type (void);
+
+GcrImporter * _gcr_pkcs11_importer_new (GckSlot *slot);
+
+GckSlot * _gcr_pkcs11_importer_get_slot (GcrPkcs11Importer *self);
+
+GList * _gcr_pkcs11_importer_get_imported (GcrPkcs11Importer *self);
+
+G_END_DECLS
+
+#endif /* __GCR_PKCS11_IMPORTER_H__ */
diff --git a/gcr/gcr-record.h b/gcr/gcr-record.h
index 39153751..37201cef 100644
--- a/gcr/gcr-record.h
+++ b/gcr/gcr-record.h
@@ -52,6 +52,7 @@
G_BEGIN_DECLS
#define GCR_RECORD_SCHEMA_ATTRIBUTE (g_quark_from_static_string ("ATTRIBUTE"))
+#define GCR_RECORD_SCHEMA_IMPORT_OK (g_quark_from_static_string ("IMPORT_OK"))
#define GCR_RECORD_SCHEMA_FPR (g_quark_from_static_string ("fpr"))
#define GCR_RECORD_SCHEMA_PUB (g_quark_from_static_string ("pub"))
#define GCR_RECORD_SCHEMA_SUB (g_quark_from_static_string ("sub"))
@@ -83,6 +84,16 @@ typedef enum {
} GcrRecordAttributeColumns;
/*
+ * Columns for IMPORT_OK and IMPORT_PROBLEM status message. eg:
+ * [GNUPG:] IMPORT_OK 1 6BD9050FD8FC941B43412DCC68B7AB8957548DCD
+ * [GNUPG:] IMPORT_PROBLEM 1
+ */
+typedef enum {
+ GCR_RECORD_IMPORT_REASON = 1,
+ GCR_RECORD_IMPORT_FINGERPRINT
+} GcrRecordImportColumns;
+
+/*
* Columns for fpr schema, add them as they're used. eg:
* fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013:
*/
diff --git a/gcr/gcr.symbols b/gcr/gcr.symbols
index 5781424b..d7703def 100644
--- a/gcr/gcr.symbols
+++ b/gcr/gcr.symbols
@@ -42,20 +42,6 @@ gcr_combo_selector_get_selected
gcr_combo_selector_get_type
gcr_combo_selector_new
gcr_combo_selector_set_selected
-gcr_importer_get_parser
-gcr_importer_get_prompt_behavior
-gcr_importer_get_slot
-gcr_importer_get_type
-gcr_importer_import
-gcr_importer_import_async
-gcr_importer_import_finish
-gcr_importer_listen
-gcr_importer_new
-gcr_importer_prompt_behavior_get_type
-gcr_importer_queue
-gcr_importer_set_parser
-gcr_importer_set_prompt_behavior
-gcr_importer_set_slot
gcr_key_renderer_get_attributes
gcr_key_renderer_get_type
gcr_key_renderer_new
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d10485d6..6579f434 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -23,6 +23,7 @@ gcr/gcr-certificate-widget.c
gcr/gcr-display-view.c
gcr/gcr-failure-renderer.c
[type: gettext/glade]gcr/gcr-import-dialog.ui
+gcr/gcr-gnupg-importer.c
gcr/gcr-gnupg-key.c
gcr/gcr-gnupg-process.c
gcr/gcr-gnupg-renderer.c
diff --git a/tool/gkr-tool-import.c b/tool/gkr-tool-import.c
index fdb8e018..05f26ddc 100644
--- a/tool/gkr-tool-import.c
+++ b/tool/gkr-tool-import.c
@@ -39,7 +39,16 @@ static GOptionEntry import_entries[] = {
};
static void
-on_imported (GcrImporter *importer, GckObject *object)
+imported_fingerprint (const gchar *fingerprint,
+ const gchar *destination)
+{
+ g_print ("%s: imported openpgp\n", destination);
+ g_print ("\tfingerprint: %s\n", fingerprint);
+}
+
+static void
+imported_object (GckObject *object,
+ const gchar *destination)
{
gulong attr_types[3];
GckAttributes *attrs;
@@ -67,30 +76,30 @@ on_imported (GcrImporter *importer, GckObject *object)
switch (klass) {
case CKO_CERTIFICATE:
- message = "Imported certificate: %s\n";
+ message = "%s: imported certificate: %s\n";
break;
case CKO_DATA:
- message = "Imported data: %s\n";
+ message = "%s: imported data: %s\n";
break;
case CKO_PRIVATE_KEY:
- message = "Imported private key: %s\n";
+ message = "%s: imported private key: %s\n";
break;
case CKO_PUBLIC_KEY:
- message = "Imported public key: %s\n";
+ message = "%s: imported public key: %s\n";
break;
case CKO_SECRET_KEY:
- message = "Imported secret key: %s\n";
+ message = "%s: imported secret key: %s\n";
break;
default:
- message = "Imported object: %s\n";
+ message = "%s: imported object: %s\n";
break;
};
- g_print (message, label);
+ g_print (message, destination, label);
if (id) {
hex = egg_hex_encode (id->value, id->length);
- g_print ("\tID: %s\n", hex);
+ g_print ("\tidentifier: %s\n", hex);
g_free (hex);
}
@@ -98,18 +107,70 @@ on_imported (GcrImporter *importer, GckObject *object)
g_free (label);
}
+static void
+imported_display (GcrImporter *importer)
+{
+ GParamSpec *spec;
+ gchar *label = NULL;
+
+ spec = g_object_class_find_property (G_OBJECT_GET_CLASS (importer), "imported");
+ if (spec == NULL)
+ return;
+
+ g_object_get (importer, "label", &label, NULL);
+
+ if (spec->value_type == GCK_TYPE_LIST) {
+ GList *list, *l;
+ g_object_get (importer, "imported", &list, NULL);
+ for (l = list; l != NULL; l = g_list_next (l))
+ imported_object (l->data, label);
+ gck_list_unref_free (list);
+
+ } else if (spec->value_type == G_TYPE_STRV) {
+ gchar **fingerprints;
+ guint i;
+ g_object_get (importer, "imported", &fingerprints, NULL);
+ for (i = 0; fingerprints && fingerprints[i] != NULL; i++)
+ imported_fingerprint (fingerprints[i], label);
+ g_strfreev (fingerprints);
+ }
+}
+
+typedef struct {
+ GList *importers;
+ gboolean num_parsed;
+} ImportClosure;
+
+static void
+on_parser_parsed (GcrParser *parser,
+ gpointer user_data)
+{
+ ImportClosure *closure = user_data;
+ GList *filtered;
+
+ if (closure->num_parsed == 0) {
+ closure->importers = gcr_importer_create_for_parsed (parser);
+ } else {
+ filtered = gcr_importer_queue_and_filter_for_parsed (closure->importers, parser);
+ gck_list_unref_free (closure->importers);
+ closure->importers = filtered;
+ }
+
+ closure->num_parsed++;
+}
+
int
gkr_tool_import (int argc, char *argv[])
{
- GcrImporter *importer;
GcrParser *parser;
GError *error = NULL;
GInputStream *input;
- gboolean res;
+ ImportClosure *closure;
GFile *file;
gchar **imp;
int ret = 0;
-
+ GList *l;
+
ret = gkr_tool_parse_options (&argc, &argv, import_entries);
if (ret != 0)
return ret;
@@ -118,39 +179,50 @@ gkr_tool_import (int argc, char *argv[])
gkr_tool_handle_error (NULL, "specify files to import");
return 2;
}
-
- importer = gcr_importer_new ();
- gcr_importer_set_prompt_behavior (importer, GCR_IMPORTER_PROMPT_NEEDED);
-
- if (!gkr_tool_mode_quiet)
- g_signal_connect (importer, "imported", G_CALLBACK (on_imported), NULL);
-
+
+ parser = gcr_parser_new ();
+ closure = g_new0 (ImportClosure, 1);
+ g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), closure);
+
for (imp = import_files; *imp; ++imp) {
file = g_file_new_for_commandline_arg (*imp);
input = G_INPUT_STREAM (g_file_read (file, NULL, &error));
g_object_unref (file);
- if (!input) {
+ if (input == NULL) {
gkr_tool_handle_error (&error, "couldn't read file: %s", *imp);
ret = 1;
+
} else {
- parser = gcr_parser_new ();
- gcr_importer_listen (importer, parser);
- res = gcr_parser_parse_stream (parser, input, NULL, &error);
+ if (!gcr_parser_parse_stream (parser, input, NULL, &error)) {
+ if (error->code != GCR_ERROR_CANCELLED)
+ gkr_tool_handle_error (&error, "couldn't parse: %s", *imp);
+ ret = 1;
+ }
+
g_object_unref (input);
- g_object_unref (parser);
+ }
+ }
- if (res == TRUE)
- res = gcr_importer_import (importer, NULL, &error);
+ if (closure->importers == NULL) {
+ gkr_tool_handle_error (NULL, "couldn't find any place to import files");
+ ret = 1;
+ }
- if (res == FALSE) {
- if (!error || error->code != GCR_ERROR_CANCELLED)
- gkr_tool_handle_error (&error, "couldn't import file: %s", *imp);
- ret = 1;
- }
+ for (l = closure->importers; l != NULL; l = g_list_next (l)) {
+ if (gcr_importer_import (l->data, NULL, &error)) {
+ if (!gkr_tool_mode_quiet)
+ imported_display (l->data);
+ } else {
+ if (error->code != GCR_ERROR_CANCELLED)
+ gkr_tool_handle_error (&error, "couldn't import");
+ ret = 1;
}
}
-
- g_object_unref (importer);
+
+ gck_list_unref_free (closure->importers);
+ g_free (closure);
+
+ g_object_unref (parser);
return ret;
}