[gnome-keyring/ui-widgets: 1/7] Rework how the importer and parser work together.



commit dd767066b8db5d0b601001ad24c1bd0a34182947
Author: Stef Walter <stef memberwebs com>
Date:   Sun Jun 20 01:11:48 2010 +0000

    Rework how the importer and parser work together.
    
     * Parser becomes a general source for objects.

 gcr/gcr-importer.c     |  424 ++++++++++++++++--------------------------------
 gcr/gcr-importer.h     |   18 +-
 gcr/gcr-marshal.list   |    1 +
 gcr/gcr-parser.c       |  302 ++++++++++++++++++++++++++++++++++
 gcr/gcr-parser.h       |   16 ++
 tool/gkr-tool-import.c |   10 +-
 6 files changed, 481 insertions(+), 290 deletions(-)
---
diff --git a/gcr/gcr-importer.c b/gcr/gcr-importer.c
index 8fcc3f6..68c94b8 100644
--- a/gcr/gcr-importer.c
+++ b/gcr/gcr-importer.c
@@ -24,6 +24,7 @@
 #include "gcr-import-dialog.h"
 #include "gcr-importer.h"
 #include "gcr-internal.h"
+#include "gcr-marshal.h"
 #include "gcr-parser.h"
 
 #include <glib/gi18n-lib.h>
@@ -31,11 +32,11 @@
 enum {
 	PROP_0,
 	PROP_SLOT,
-	PROP_PARSER,
 	PROP_PROMPT_BEHAVIOR
 };
 
 enum {
+	QUEUED,
 	IMPORTED,
 	LAST_SIGNAL
 };
@@ -54,10 +55,8 @@ struct _GcrImporterPrivate {
 	/* State data during import */
 	gboolean processing;
 	GCancellable *cancel;
-	GInputStream *input;
 	gboolean prompted;
 	gboolean async;
-	GByteArray *buffer;
 	GP11Session *session;
 	GQueue queue;
 	
@@ -72,8 +71,6 @@ 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 state_parse_buffer (GcrImporter *self, gboolean async);
-static void state_read_buffer (GcrImporter *self, gboolean async);
 
 static void gcr_importer_async_result (GAsyncResultIface *iface);
 G_DEFINE_TYPE_WITH_CODE (GcrImporter, gcr_importer, G_TYPE_OBJECT,
@@ -89,11 +86,7 @@ static void
 cleanup_state_data (GcrImporter *self)
 {
 	GP11Attributes *attrs;
-	
-	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;
@@ -101,11 +94,7 @@ cleanup_state_data (GcrImporter *self)
 	while ((attrs = g_queue_pop_head (&self->pv->queue)) != NULL)
 		gp11_attributes_unref (attrs);
 	g_assert (g_queue_is_empty (&self->pv->queue));
-	
-	if (self->pv->input)
-		g_object_unref (self->pv->input);
-	self->pv->input = NULL;
-	
+
 	if (self->pv->cancel)
 		g_object_unref (self->pv->cancel);
 	self->pv->cancel = NULL;
@@ -132,6 +121,103 @@ next_state (GcrImporter *self, void (*state) (GcrImporter*, gboolean))
 	(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);
+		}
+	}
+}
+
+static void
+on_parser_parsed (GcrParser *parser, GcrImporter *self)
+{
+	GP11Attributes *attrs;
+
+	g_return_if_fail (GCR_IS_PARSER (parser));
+	g_return_if_fail (GCR_IS_IMPORTER (self));
+
+	attrs = gcr_parser_get_parsed_attributes (parser);
+	g_return_if_fail (attrs);
+
+	gcr_importer_queue (self, gcr_parser_get_parsed_label (parser), attrs);
+}
+
+static gboolean
+on_parser_authenticate (GcrParser *parser, gint count, GcrImporter *self)
+{
+	GcrImportDialog *dialog;
+	GP11Attributes *attrs;
+	const gchar *password;
+	gchar *text, *label;
+	GP11Slot *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 (!gp11_attributes_find_ulong (attrs, CKA_CLASS, &klass))
+		klass = (gulong)-1;
+	if (!gp11_attributes_find_string (attrs, CKA_LABEL, &label))
+		label = NULL;
+
+	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);
+
+	if (!_gcr_import_dialog_run (dialog, NULL))
+		return FALSE;
+
+	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;
+}
+
 /* ---------------------------------------------------------------------------------
  * COMPLETE
  */
@@ -425,216 +511,6 @@ state_import_prompt (GcrImporter *self, gboolean async)
 	}
 }
 
-/* ---------------------------------------------------------------------------------
- * PARSING
- */
-
-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);
-		}
-	}
-}
-
-static void
-on_parser_parsed (GcrParser *parser, GcrImporter *self)
-{
-	GP11Attributes *attrs;
-	
-	g_return_if_fail (GCR_IS_PARSER (parser));
-	g_return_if_fail (GCR_IS_IMPORTER (self));
-	
-	attrs = gcr_parser_get_parsed_attributes (parser);
-	g_return_if_fail (attrs);
-	g_queue_push_tail (&self->pv->queue, gp11_attributes_ref (attrs));
-}
-
-static gboolean
-on_parser_authenticate (GcrParser *parser, gint count, GcrImporter *self)
-{
-	GcrImportDialog *dialog;
-	GP11Attributes *attrs;
-	const gchar *password;
-	gchar *text, *label;
-	GP11Slot *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 (!gp11_attributes_find_ulong (attrs, CKA_CLASS, &klass))
-		klass = (gulong)-1;
-	if (!gp11_attributes_find_string (attrs, CKA_LABEL, &label))
-		label = NULL;
-	
-	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);
-	
-	if (!_gcr_import_dialog_run (dialog, NULL))
-		return FALSE;
-
-	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;
-}
-
-static void 
-state_parse_buffer (GcrImporter *self, gboolean async)
-{
-	GError *error = NULL;
-	GcrParser *parser;
-	gulong parsed_conn;
-	gulong auth_conn;
-	gboolean ret;
-	
-	g_assert (GCR_IS_IMPORTER (self));
-	g_assert (self->pv->buffer);
-	
-	parser = gcr_importer_get_parser (self);
-	g_object_ref (parser);
-
-	/* Listen in to the parser */
-	parsed_conn = g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), self);
-	auth_conn = g_signal_connect (parser, "authenticate", G_CALLBACK (on_parser_authenticate), self);
-
-	ret = gcr_parser_parse_data (parser, self->pv->buffer->data, self->pv->buffer->len, &error);
-	
-	/* An optimization to free data early as possible */
-	g_byte_array_free (self->pv->buffer, TRUE);
-	self->pv->buffer = NULL;
-	
-	g_signal_handler_disconnect (parser, parsed_conn);
-	g_signal_handler_disconnect (parser, auth_conn);
-	g_object_unref (parser);
-	
-	if (ret == TRUE) {
-		next_state (self, state_import_prompt);
-	} else {
-		g_propagate_error (&self->pv->error, error);
-		next_state (self, state_failure);
-	}
-}
-
-/* ---------------------------------------------------------------------------------
- * BUFFER READING
- */
-
-static void
-complete_read_buffer (GcrImporter *self, gssize count, GError *error)
-{
-	g_assert (GCR_IS_IMPORTER (self));
-	g_assert (self->pv->buffer);
-	
-	/* A failure */
-	if (count == -1) {
-		g_propagate_error (&self->pv->error, error);
-		next_state (self, state_failure);
-	} else {
-	
-		g_return_if_fail (count >= 0 && count <= BLOCK);
-		g_byte_array_set_size (self->pv->buffer, self->pv->buffer->len - (BLOCK - count));
-		
-		/* Finished reading */
-		if (count == 0) {
-			
-			/* Optimization, unref input early */
-			g_object_unref (self->pv->input);
-			self->pv->input = NULL;
-			
-			next_state (self, state_parse_buffer);
-			
-		/* Read the next block */
-		} else {
-			next_state (self, state_read_buffer);
-		}
-	}
-	
-}
-
-static void
-on_read_buffer (GObject *obj, GAsyncResult *res, gpointer user_data)
-{
-	GError *error = NULL;
-	gssize count;
-	
-	count = g_input_stream_read_finish (G_INPUT_STREAM (obj), res, &error);
-	complete_read_buffer (user_data, count, error);
-}
-
-static void 
-state_read_buffer (GcrImporter *self, gboolean async)
-{
-	GError *error = NULL;
-	gssize count;
-	gsize at;
-	
-	g_assert (GCR_IS_IMPORTER (self));
-	g_assert (G_IS_INPUT_STREAM (self->pv->input));
-	
-	if (!self->pv->buffer)
-		self->pv->buffer = g_byte_array_sized_new (BLOCK);
-
-	at = self->pv->buffer->len;
-	g_byte_array_set_size (self->pv->buffer, at + BLOCK);
-	
-	if (async) {
-		g_input_stream_read_async (self->pv->input, self->pv->buffer->data + at, 
-		                           BLOCK, G_PRIORITY_DEFAULT, self->pv->cancel,
-		                           on_read_buffer, self);
-	} else {
-		count = g_input_stream_read (self->pv->input, self->pv->buffer->data + at, 
-		                             BLOCK, self->pv->cancel, &error);
-		complete_read_buffer (self, count, error);
-	}
-}
-
 /* -----------------------------------------------------------------------------
  * OBJECT 
  */
@@ -693,9 +569,6 @@ gcr_importer_set_property (GObject *obj, guint prop_id, const GValue *value,
 	GcrImporter *self = GCR_IMPORTER (obj);
 	
 	switch (prop_id) {
-	case PROP_PARSER:
-		gcr_importer_set_parser (self, g_value_get_object (value));
-		break;
 	case PROP_SLOT:
 		gcr_importer_set_slot (self, g_value_get_object (value));
 		break;
@@ -715,9 +588,6 @@ gcr_importer_get_property (GObject *obj, guint prop_id, GValue *value,
 	GcrImporter *self = GCR_IMPORTER (obj);
 	
 	switch (prop_id) {
-	case PROP_PARSER:
-		g_value_set_object (value, gcr_importer_get_parser (self));
-		break;
 	case PROP_SLOT:
 		g_value_set_object (value, gcr_importer_get_slot (self));
 		break;
@@ -742,19 +612,20 @@ gcr_importer_class_init (GcrImporterClass *klass)
 	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_PARSER,
-	           g_param_spec_object ("parser", "Parser", "Parser used to parse imported data",
-	                                GCR_TYPE_PARSER, G_PARAM_READWRITE));
-	
-	g_object_class_install_property (gobject_class, PROP_PARSER,
+
+	g_object_class_install_property (gobject_class, PROP_SLOT,
 	           g_param_spec_object ("slot", "Slot", "PKCS#11 slot to import data into",
 	                                GP11_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));
-	
+
+	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, GP11_TYPE_ATTRIBUTES);
+
 	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, 
@@ -794,28 +665,6 @@ gcr_importer_new (void)
 	return g_object_new (GCR_TYPE_IMPORTER, NULL);
 }
 
-GcrParser*
-gcr_importer_get_parser (GcrImporter *self)
-{
-	g_return_val_if_fail (GCR_IS_IMPORTER (self), NULL);
-	if (!self->pv->parser) 
-		self->pv->parser = gcr_parser_new ();
-	return self->pv->parser;
-}
-
-void
-gcr_importer_set_parser (GcrImporter *self, GcrParser *parser)
-{
-	g_return_if_fail (GCR_IS_IMPORTER (self));
-	
-	if (parser)
-		g_object_ref (parser);
-	if (self->pv->parser)
-		g_object_unref (self->pv->parser);
-	self->pv->parser = parser;
-	g_object_notify (G_OBJECT (self), "parser");
-}
-
 GP11Slot*
 gcr_importer_get_slot (GcrImporter *self)
 {
@@ -852,26 +701,22 @@ gcr_importer_set_prompt_behavior (GcrImporter *self, GcrImporterPromptBehavior b
 }
 
 gboolean
-gcr_importer_import (GcrImporter *self, GInputStream *input,
-                     GCancellable *cancel, GError **error)
+gcr_importer_import (GcrImporter *self, GCancellable *cancel, GError **error)
 {
 	g_return_val_if_fail (GCR_IS_IMPORTER (self), FALSE);
-	g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE);
 	g_return_val_if_fail (!error || !*error, FALSE);
 	g_return_val_if_fail (!self->pv->processing, FALSE);
-	
+
 	cleanup_import_data (self);
-	
-	self->pv->input = g_object_ref (input);
+
 	if (cancel)
 		self->pv->cancel = g_object_ref (cancel);
 	self->pv->processing = TRUE;
 	self->pv->async = FALSE;
-	
-	next_state (self, state_read_buffer);
-	
+
+	next_state (self, state_import_prompt);
+
 	g_assert (!self->pv->processing);
-	g_assert (!self->pv->input);
 	g_assert (!self->pv->cancel);
 	
 	if (!self->pv->succeeded) {
@@ -884,24 +729,22 @@ gcr_importer_import (GcrImporter *self, GInputStream *input,
 }
 
 void
-gcr_importer_import_async (GcrImporter *self, GInputStream *input, GCancellable *cancel,
+gcr_importer_import_async (GcrImporter *self, GCancellable *cancel,
                            GAsyncReadyCallback callback, gpointer user_data)
 {
 	g_return_if_fail (GCR_IS_IMPORTER (self));
-	g_return_if_fail (G_IS_INPUT_STREAM (input));
 	g_return_if_fail (!self->pv->processing);
-	
+
 	cleanup_import_data (self);
-	
-	self->pv->input = g_object_ref (input);
+
 	if (cancel)
 		self->pv->cancel = g_object_ref (cancel);
 	self->pv->processing = TRUE;
 	self->pv->async = TRUE;
 	self->pv->callback = callback;
 	self->pv->user_data = user_data;
-	
-	next_state (self, state_read_buffer);
+
+	next_state (self, state_import_prompt);
 	g_assert (self->pv->processing);
 }
 
@@ -913,9 +756,8 @@ gcr_importer_import_finish (GcrImporter *self, GAsyncResult *res, GError **error
 	g_return_val_if_fail (!error || !*error, FALSE);
 	g_return_val_if_fail (!self->pv->processing, FALSE);
 
-	g_assert (!self->pv->input);
 	g_assert (!self->pv->cancel);
-	
+
 	if (!self->pv->succeeded) {
 		g_propagate_error (error, self->pv->error);
 		self->pv->error = NULL;
@@ -924,3 +766,25 @@ gcr_importer_import_finish (GcrImporter *self, GAsyncResult *res, GError **error
 	
 	return TRUE;
 }
+
+
+void
+gcr_importer_listen (GcrImporter *self, GcrParser *parser)
+{
+	g_return_if_fail (GCR_IS_IMPORTER (self));
+	g_return_if_fail (GCR_IS_PARSER (self));
+
+	/* 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);
+}
+
+void
+gcr_importer_queue (GcrImporter *self, const gchar *label, GP11Attributes *attrs)
+{
+	g_return_if_fail (GCR_IS_IMPORTER (self));
+	g_return_if_fail (attrs);
+
+	g_queue_push_tail (&self->pv->queue, gp11_attributes_ref (attrs));
+	g_signal_emit (self, signals[QUEUED], 0, label, attrs);
+}
diff --git a/gcr/gcr-importer.h b/gcr/gcr-importer.h
index 358b302..2d9f794 100644
--- a/gcr/gcr-importer.h
+++ b/gcr/gcr-importer.h
@@ -53,9 +53,9 @@ struct _GcrImporter {
 
 struct _GcrImporterClass {
 	GObjectClass parent_class;
-	
+
 	/* signals */
-	
+	void (*queued) (GcrImporter *self, const gchar *label, struct _GP11Attributes *attrs);
 	void (*imported) (GcrImporter *self, struct _GP11Object *object);
 };
 
@@ -63,11 +63,6 @@ GType                     gcr_importer_get_type               (void);
 
 GcrImporter*              gcr_importer_new                    (void);
 
-GcrParser*                gcr_importer_get_parser             (GcrImporter *self);
-
-void                      gcr_importer_set_parser             (GcrImporter *self,
-                                                               GcrParser *parser);
-
 struct _GP11Slot*         gcr_importer_get_slot               (GcrImporter *self);
 
 void                      gcr_importer_set_slot               (GcrImporter *self,
@@ -78,13 +73,18 @@ GcrImporterPromptBehavior gcr_importer_get_prompt_behavior    (GcrImporter *self
 void                      gcr_importer_set_prompt_behavior    (GcrImporter *self,
                                                                GcrImporterPromptBehavior behavior);
 
+void                      gcr_importer_queue                  (GcrImporter *self,
+                                                               const gchar *label,
+                                                               struct _GP11Attributes *attrs);
+
+void                      gcr_importer_listen                 (GcrImporter *self,
+                                                               GcrParser *parser);
+
 gboolean                  gcr_importer_import                 (GcrImporter *self,
-                                                               GInputStream *input,
                                                                GCancellable *cancel,
                                                                GError **error);
 
 void                      gcr_importer_import_async           (GcrImporter *self,
-                                                               GInputStream *input,
                                                                GCancellable *cancel,
                                                                GAsyncReadyCallback callback,
                                                                gpointer user_data);
diff --git a/gcr/gcr-marshal.list b/gcr/gcr-marshal.list
index 8ff8506..a448d71 100644
--- a/gcr/gcr-marshal.list
+++ b/gcr/gcr-marshal.list
@@ -1 +1,2 @@
 BOOLEAN:INT
+VOID:STRING,BOXED
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index 3d7febe..86ffe11 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -1665,3 +1665,305 @@ gcr_parser_get_parsed_label (GcrParser *self)
 	g_return_val_if_fail (GCR_IS_PARSER (self), NULL);
 	return self->pv->parsed_label;		
 }
+
+/* ---------------------------------------------------------------------------------
+ * STREAM PARSING
+ */
+
+#define GCR_TYPE_PARSING        (gcr_parsing_get_type ())
+#define GCR_PARSING(obj)        (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PARSING, GcrParsing))
+#define GCR_IS_PARSING(obj)     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PARSING))
+
+typedef struct _GcrParsing {
+	GObjectClass parent;
+
+	GcrParser *parser;
+	gboolean async;
+	GCancellable *cancel;
+
+	/* Failure information */
+	GError *error;
+	gboolean complete;
+
+	/* Operation state */
+	GInputStream *input;
+	GByteArray *buffer;
+
+	/* Async callback stuff */
+	GAsyncReadyCallback callback;
+	gpointer user_data;
+
+} GcrParsing;
+
+typedef struct _GcrParsingClass {
+	GObjectClass parent_class;
+} GcrParsingClass;
+
+/* State forward declarations */
+static void state_cancelled (GcrParsing *self, gboolean async);
+static void state_failure (GcrParsing *self, gboolean async);
+static void state_complete (GcrParsing *self, gboolean async);
+static void state_parse_buffer (GcrParsing *self, gboolean async);
+static void state_read_buffer (GcrParsing *self, gboolean async);
+
+/* Other forward declarations */
+static GType gcr_parsing_get_type (void) G_GNUC_CONST;
+static void gcr_parsing_async_result_init (GAsyncResultIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrParsing, gcr_parsing, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, gcr_parsing_async_result_init));
+
+#define BLOCK 4096
+
+static void
+next_state (GcrParsing *self, void (*state) (GcrParsing*, gboolean))
+{
+	g_assert (GCR_IS_PARSING (self));
+	g_assert (state);
+
+	if (self->cancel && g_cancellable_is_cancelled (self->cancel))
+		state = state_cancelled;
+
+	(state) (self, self->async);
+}
+
+static void
+state_complete (GcrParsing *self, gboolean async)
+{
+	g_assert (GCR_IS_PARSING (self));
+	g_assert (!self->complete);
+	self->complete = TRUE;
+	if (async && self->callback != NULL)
+		(self->callback) (G_OBJECT (self->parser), G_ASYNC_RESULT (self), self->user_data);
+}
+
+static void
+state_failure (GcrParsing *self, gboolean async)
+{
+	g_assert (GCR_IS_PARSING (self));
+	g_assert (self->error);
+	next_state (self, state_complete);
+}
+
+static void
+state_cancelled (GcrParsing *self, gboolean async)
+{
+	g_assert (GCR_IS_PARSING (self));
+	if (self->cancel && g_cancellable_is_cancelled (self->cancel))
+		g_cancellable_cancel (self->cancel);
+	if (self->error)
+		g_error_free (self->error);
+	self->error = g_error_new_literal (GCR_DATA_ERROR, GCR_ERROR_CANCELLED, _("The operation was cancelled"));
+	next_state (self, state_failure);
+}
+
+static void
+state_parse_buffer (GcrParsing *self, gboolean async)
+{
+	GError *error = NULL;
+	gboolean ret;
+
+	g_assert (GCR_IS_PARSING (self));
+	g_assert (self->buffer);
+
+	ret = gcr_parser_parse_data (self->parser, self->buffer->data, self->buffer->len, &error);
+
+	if (ret == TRUE) {
+		next_state (self, state_complete);
+	} else {
+		g_propagate_error (&self->error, error);
+		next_state (self, state_failure);
+	}
+}
+
+static void
+complete_read_buffer (GcrParsing *self, gssize count, GError *error)
+{
+	g_assert (GCR_IS_IMPORTER (self));
+	g_assert (self->buffer);
+
+	/* A failure */
+	if (count == -1) {
+		g_propagate_error (&self->error, error);
+		next_state (self, state_failure);
+	} else {
+
+		g_return_if_fail (count >= 0 && count <= BLOCK);
+		g_byte_array_set_size (self->buffer, self->buffer->len - (BLOCK - count));
+
+		/* Finished reading */
+		if (count == 0)
+			next_state (self, state_parse_buffer);
+
+		/* Read the next block */
+		else
+			next_state (self, state_read_buffer);
+	}
+
+}
+
+static void
+on_read_buffer (GObject *obj, GAsyncResult *res, gpointer user_data)
+{
+	GError *error = NULL;
+	gssize count;
+
+	count = g_input_stream_read_finish (G_INPUT_STREAM (obj), res, &error);
+	complete_read_buffer (user_data, count, error);
+}
+
+static void
+state_read_buffer (GcrParsing *self, gboolean async)
+{
+	GError *error = NULL;
+	gssize count;
+	gsize at;
+
+	g_assert (GCR_IS_IMPORTER (self));
+	g_assert (G_IS_INPUT_STREAM (self->input));
+
+	if (!self->buffer)
+		self->buffer = g_byte_array_sized_new (BLOCK);
+
+	at = self->buffer->len;
+	g_byte_array_set_size (self->buffer, at + BLOCK);
+
+	if (async) {
+		g_input_stream_read_async (self->input, self->buffer->data + at,
+		                           BLOCK, G_PRIORITY_DEFAULT, self->cancel,
+		                           on_read_buffer, self);
+	} else {
+		count = g_input_stream_read (self->input, self->buffer->data + at,
+		                             BLOCK, self->cancel, &error);
+		complete_read_buffer (self, count, error);
+	}
+}
+
+static void
+gcr_parsing_init (GcrParsing *self)
+{
+
+}
+
+static void
+gcr_parsing_finalize (GObject *obj)
+{
+	GcrParsing *self = GCR_PARSING (obj);
+
+	g_object_unref (self->parser);
+	self->parser = NULL;
+
+	g_object_unref (self->input);
+	self->input = NULL;
+
+	if (self->cancel)
+		g_object_unref (self->cancel);
+	self->cancel = NULL;
+
+	g_clear_error (&self->error);
+
+	if (self->buffer)
+		g_byte_array_free (self->buffer, TRUE);
+	self->buffer = NULL;
+
+	G_OBJECT_CLASS (gcr_parsing_parent_class)->finalize (obj);
+}
+
+static void
+gcr_parsing_class_init (GcrParsingClass *klass)
+{
+	G_OBJECT_CLASS (klass)->finalize = gcr_parsing_finalize;
+}
+
+static gpointer
+gcr_parsing_real_get_user_data (GAsyncResult *base)
+{
+	g_return_val_if_fail (GCR_IS_PARSING (base), NULL);
+	return GCR_PARSING (base)->user_data;
+}
+
+static GObject*
+gcr_parsing_real_get_source_object (GAsyncResult *base)
+{
+	g_return_val_if_fail (GCR_IS_PARSING (base), NULL);
+	return G_OBJECT (GCR_PARSING (base)->parser);
+}
+
+static void
+gcr_parsing_async_result_init (GAsyncResultIface *iface)
+{
+	iface->get_source_object = gcr_parsing_real_get_source_object;
+	iface->get_user_data = gcr_parsing_real_get_user_data;
+}
+
+static GcrParsing*
+gcr_parsing_new (GcrParser *parser, GInputStream *input, GCancellable *cancel)
+{
+	GcrParsing *self;
+
+	g_assert (GCR_IS_PARSER (parser));
+	g_assert (G_IS_INPUT_STREAM (input));
+
+	self = g_object_new (GCR_TYPE_PARSING, NULL);
+	self->parser = g_object_ref (parser);
+	self->input = g_object_ref (input);
+	if (cancel)
+		self->cancel = g_object_ref (cancel);
+
+	return self;
+}
+
+gboolean
+gcr_parser_parse_stream (GcrParser *self, GInputStream *input, GCancellable *cancel,
+                         GError **error)
+{
+	GcrParsing *parsing;
+
+	g_return_val_if_fail (GCR_IS_PARSER (self), FALSE);
+	g_return_val_if_fail (G_IS_INPUT_STREAM (self), FALSE);
+	g_return_val_if_fail (!error || !*error, FALSE);
+
+	parsing = gcr_parsing_new (self, input, cancel);
+	parsing->async = FALSE;
+
+	next_state (parsing, state_read_buffer);
+	g_assert (parsing->complete);
+
+	return gcr_parser_parse_stream_finish (self, G_ASYNC_RESULT (parsing), error);
+}
+
+void
+gcr_parser_parse_stream_async (GcrParser *self, GInputStream *input, GCancellable *cancel,
+                               GAsyncReadyCallback callback, gpointer user_data)
+{
+	GcrParsing *parsing;
+
+	g_return_if_fail (GCR_IS_PARSER (self));
+	g_return_if_fail (G_IS_INPUT_STREAM (self));
+
+	parsing = gcr_parsing_new (self, input, cancel);
+	parsing->async = TRUE;
+	parsing->callback = callback;
+	parsing->user_data = user_data;
+
+	next_state (parsing, state_read_buffer);
+}
+
+gboolean
+gcr_parser_parse_stream_finish (GcrParser *self, GAsyncResult *res, GError **error)
+{
+	GcrParsing *parsing;
+
+	g_return_val_if_fail (GCR_IS_PARSING (res), FALSE);
+	g_return_val_if_fail (!error || !*error, FALSE);
+
+	parsing = GCR_PARSING (res);
+	g_return_val_if_fail (parsing->complete, FALSE);
+
+	if (parsing->error) {
+		g_propagate_error (error, parsing->error);
+		return FALSE;
+	}
+
+	return TRUE;
+}
diff --git a/gcr/gcr-parser.h b/gcr/gcr-parser.h
index 55c7671..c890eff 100644
--- a/gcr/gcr-parser.h
+++ b/gcr/gcr-parser.h
@@ -23,6 +23,7 @@
 #define __GCR_PARSER_H__
 
 #include <glib-object.h>
+#include <gio/gio.h>
 
 #include "gcr-types.h"
 
@@ -74,6 +75,21 @@ gboolean                 gcr_parser_parse_data             (GcrParser *self,
                                                             gsize n_data, 
                                                             GError **err);
 
+gboolean                 gcr_parser_parse_stream           (GcrParser *self,
+                                                            GInputStream *input,
+                                                            GCancellable *cancel,
+                                                            GError **error);
+
+void                     gcr_parser_parse_stream_async     (GcrParser *self,
+                                                            GInputStream *input,
+                                                            GCancellable *cancel,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer user_data);
+
+gboolean                 gcr_parser_parse_stream_finish    (GcrParser *self,
+                                                            GAsyncResult *res,
+                                                            GError **error);
+
 void                     gcr_parser_add_password           (GcrParser *self,
                                                             const gchar *password);
 
diff --git a/tool/gkr-tool-import.c b/tool/gkr-tool-import.c
index 74bbfab..99c3890 100644
--- a/tool/gkr-tool-import.c
+++ b/tool/gkr-tool-import.c
@@ -98,6 +98,7 @@ int
 gkr_tool_import (int argc, char *argv[])
 {
 	GcrImporter *importer;
+	GcrParser *parser;
 	GError *error = NULL;
 	GInputStream *input;
 	gboolean res;
@@ -129,8 +130,15 @@ gkr_tool_import (int argc, char *argv[])
 			gkr_tool_handle_error (&error, "couldn't read file: %s", *imp);
 			ret = 1;
 		} else {
-			res = gcr_importer_import (importer, input, NULL, &error);
+			parser = gcr_parser_new ();
+			gcr_importer_listen (importer, parser);
+			res = gcr_parser_parse_stream (parser, input, NULL, &error);
 			g_object_unref (input);
+			g_object_unref (parser);
+
+			if (res == TRUE)
+				res = gcr_importer_import (importer, NULL, &error);
+
 			if (res == FALSE) {
 				if (!error || error->code != GCR_ERROR_CANCELLED)
 					gkr_tool_handle_error (&error, "couldn't import file: %s", *imp);



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