[gnome-keyring] gcr: Implement loading of attributes in GcrGnupgCollection



commit dac5daa5fbe0013a712ecfd241800f1242920e27
Author: Stef Walter <stefw collabora co uk>
Date:   Thu May 12 19:18:41 2011 +0200

    gcr: Implement loading of attributes in GcrGnupgCollection
    
     * These attributes can contain photo ids.
     * Add various definitions for dealing with attributes.
     * Since we like everything in the --with-colons gnupg format,
       we implement our own record type 'xa1' and cram the attribute
       (photo id) into there, along with all data.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=650433

 docs/reference/gcr/gcr-sections.txt |    6 ++
 gcr/Makefile.am                     |    1 +
 gcr/gcr-gnupg-collection.c          |  161 ++++++++++++++++++++++++++++++++---
 gcr/gcr-gnupg-key.c                 |   11 +++
 gcr/gcr-gnupg-key.h                 |    2 +
 gcr/gcr-gnupg-util.c                |  102 ++++++++++++++++++++++
 gcr/gcr-gnupg-util.h                |   41 +++++++++
 gcr/gcr-record.h                    |   43 +++++++++-
 gcr/tests/test-gnupg-collection.c   |   45 +++++++++--
 9 files changed, 393 insertions(+), 19 deletions(-)
---
diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt
index e8df765..8d8b22b 100644
--- a/docs/reference/gcr/gcr-sections.txt
+++ b/docs/reference/gcr/gcr-sections.txt
@@ -456,6 +456,9 @@ GcrUnlockOptionsWidgetPrivate
 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_GNUPG_COLLECTION
 GCR_GNUPG_COLLECTION_CLASS
 GCR_GNUPG_COLLECTION_GET_CLASS
@@ -474,6 +477,9 @@ GcrRecordColumns
 GcrRecordPubColumns
 GcrRecordUidColumns
 GcrRecordSecColumns
+GcrRecordAttributeColumns
+GcrRecordFprColumns
+GcrRecordXa1Columns
 GcrRecord
 GCR_GNUPG_PROCESS
 GCR_GNUPG_PROCESS_CLASS
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index 5a5270c..496f9d3 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -91,6 +91,7 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
 	gcr-gnupg-key.c gcr-gnupg-key.h \
 	gcr-fingerprint.c gcr-fingerprint.h \
 	gcr-gnupg-process.c gcr-gnupg-process.h \
+	gcr-gnupg-util.c gcr-gnupg-util.h \
 	gcr-icons.c gcr-icons.h \
 	gcr-import-dialog.c gcr-import-dialog.h \
 	gcr-importer.c gcr-importer.h  \
diff --git a/gcr/gcr-gnupg-collection.c b/gcr/gcr-gnupg-collection.c
index 1fc2e21..82991e5 100644
--- a/gcr/gcr-gnupg-collection.c
+++ b/gcr/gcr-gnupg-collection.c
@@ -30,6 +30,7 @@
 #include "gcr-gnupg-collection.h"
 #include "gcr-gnupg-key.h"
 #include "gcr-gnupg-process.h"
+#include "gcr-gnupg-util.h"
 #include "gcr-internal.h"
 #include "gcr-util.h"
 
@@ -165,7 +166,7 @@ static GList*
 gcr_gnupg_collection_real_get_objects (GcrCollection *coll)
 {
 	GcrGnupgCollection *self = GCR_GNUPG_COLLECTION (coll);
-	return g_hash_table_get_keys (self->pv->items);
+	return g_hash_table_get_values (self->pv->items);
 }
 
 static void
@@ -229,6 +230,10 @@ typedef struct {
 	guint error_sig;
 	guint status_sig;
 	guint attribute_sig;
+
+	GQueue *attribute_queue;              /* Queue of unprocessed GcrRecord* status records */
+	GByteArray *attribute_buf;            /* Buffer of unprocessed attribute data received */
+	GHashTable *attributes;               /* Processed attributes waiting for a matching key */
 } GcrGnupgCollectionLoad;
 
 /* Forward declarations */
@@ -259,6 +264,17 @@ _gcr_gnupg_collection_load_free (gpointer data)
 
 	if (load->cancel)
 		g_object_unref (load->cancel);
+
+	if (load->attribute_queue) {
+		while (!g_queue_is_empty (load->attribute_queue))
+			_gcr_record_free (g_queue_pop_head (load->attribute_queue));
+		g_queue_free (load->attribute_queue);
+	}
+	if (load->attribute_buf)
+		g_byte_array_unref (load->attribute_buf);
+	if (load->attributes)
+		g_hash_table_destroy (load->attributes);
+
 	g_slice_free (GcrGnupgCollectionLoad, load);
 }
 
@@ -266,7 +282,29 @@ static void
 process_records_as_public_key (GcrGnupgCollectionLoad *load, GPtrArray *records,
                                const gchar *keyid)
 {
+	GPtrArray *attr_records = NULL;
+	const gchar *fingerprint;
 	GcrGnupgKey *key;
+	guint i;
+
+	/* Add in any attributes we have loaded */
+	fingerprint = _gcr_gnupg_key_get_fingerprint_for_records (records);
+	if (fingerprint && load->attributes)
+		attr_records = g_hash_table_lookup (load->attributes, fingerprint);
+	if (attr_records) {
+		_gcr_debug ("adding %d user id attribute(s) to key/fingerprint: %s/%s",
+		            (gint)attr_records->len, keyid, fingerprint);
+
+		if (!g_hash_table_steal (load->attributes, fingerprint))
+			g_assert_not_reached ();
+
+		/* Move all the attribute records over to main records set */
+		for (i = 0; i < attr_records->len; i++)
+			g_ptr_array_add (records, attr_records->pdata[i]);
+
+		/* Shallow free of attr_records array */
+		g_free (g_ptr_array_free (attr_records, FALSE));
+	}
 
 	/* Note that we've seen this keyid */
 	g_hash_table_remove (load->difference, keyid);
@@ -340,6 +378,76 @@ process_records_as_key (GcrGnupgCollectionLoad *load)
 	g_ptr_array_unref (records);
 }
 
+static gboolean
+process_outstanding_attribute (GcrGnupgCollectionLoad *load, GcrRecord *record)
+{
+	const gchar *fingerprint;
+	GPtrArray *records;
+	GcrRecord *xa1;
+	guint length;
+
+	if (!_gcr_record_get_uint (record, GCR_RECORD_ATTRIBUTE_LENGTH, &length))
+		g_return_val_if_reached (FALSE);
+	fingerprint = _gcr_record_get_raw (record, GCR_RECORD_ATTRIBUTE_FINGERPRINT);
+	g_return_val_if_fail (fingerprint != NULL, FALSE);
+
+	/* Do we have enough data for this attribute? */
+	if (!load->attribute_buf || load->attribute_buf->len < length) {
+		_gcr_debug ("not enough attribute data in buffer: %u", length);
+		return FALSE;
+	}
+
+	if (!load->attributes)
+		load->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
+							  g_free, (GDestroyNotify)g_ptr_array_unref);
+
+	records = g_hash_table_lookup (load->attributes, fingerprint);
+	if (!records) {
+		records = g_ptr_array_new_with_free_func (_gcr_record_free);
+		g_hash_table_insert (load->attributes, g_strdup (fingerprint), records);
+	}
+
+	_gcr_debug ("new attribute of length %d for key with fingerprint %s",
+		    length, fingerprint);
+
+	xa1 = _gcr_gnupg_build_xa1_record (record, load->attribute_buf->data, length);
+	g_ptr_array_add (records, xa1);
+
+	/* Did we use up all the attribute data? Get rid of the buffer */
+	if (length == load->attribute_buf->len) {
+		g_byte_array_unref (load->attribute_buf);
+		load->attribute_buf = NULL;
+
+	/* Otherwise clear out the used data from buffer */
+	} else {
+		g_byte_array_remove_range (load->attribute_buf, 0, length);
+	}
+
+	return TRUE;
+}
+
+static void
+process_outstanding_attributes (GcrGnupgCollectionLoad *load)
+{
+	GcrRecord *record;
+
+	if (load->attribute_queue == NULL)
+		return;
+
+	_gcr_debug ("%d outstanding attribute records",
+	            (gint)g_queue_get_length (load->attribute_queue));
+
+	for (;;) {
+		record = g_queue_peek_head (load->attribute_queue);
+		if (record == NULL)
+			break;
+		if (!process_outstanding_attribute (load, record))
+			break;
+		g_queue_pop_head (load->attribute_queue);
+		_gcr_record_free (record);
+	}
+}
+
 static void
 on_line_parse_output (const gchar *line, gpointer user_data)
 {
@@ -370,9 +478,10 @@ on_line_parse_output (const gchar *line, gpointer user_data)
 		record = NULL;
 
 	/*
-	 * 'uid' schema lines get added to the key that came before.
+	 * 'uid' and 'fpr' schema lines get added to the key that came before.
 	 */
-	} else if (schema == GCR_RECORD_SCHEMA_UID) {
+	} else if (schema == GCR_RECORD_SCHEMA_UID ||
+	           schema == GCR_RECORD_SCHEMA_FPR) {
 		if (load->records->len) {
 			g_ptr_array_add (load->records, record);
 			record = NULL;
@@ -403,6 +512,41 @@ on_gnupg_process_error_line (GcrGnupgProcess *process, const gchar *line,
 }
 
 static void
+on_gnupg_process_status_record (GcrGnupgProcess *process, GcrRecord *record,
+                                gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	GcrGnupgCollectionLoad *load = g_simple_async_result_get_op_res_gpointer (res);
+
+	if (GCR_RECORD_SCHEMA_ATTRIBUTE != _gcr_record_get_schema (record))
+		return;
+
+	if (!load->attribute_queue)
+		load->attribute_queue = g_queue_new ();
+
+	g_queue_push_tail (load->attribute_queue, _gcr_record_copy (record));
+	process_outstanding_attributes (load);
+}
+
+static void
+on_gnupg_process_attribute_data (GcrGnupgProcess *process, GByteArray *buffer,
+                                 gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	GcrGnupgCollectionLoad *load = g_simple_async_result_get_op_res_gpointer (res);
+
+	/* If we don't have a buffer, just claim this one */
+	if (!load->attribute_buf)
+		load->attribute_buf = g_byte_array_ref (buffer);
+
+	/* If we have data remaining over, add it to our buffer */
+	else
+		g_byte_array_append (load->attribute_buf, buffer->data, buffer->len);
+
+	process_outstanding_attributes (load);
+}
+
+static void
 on_gnupg_process_completed (GObject *source, GAsyncResult *result, gpointer user_data)
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
@@ -486,14 +630,9 @@ spawn_gnupg_list_process (GcrGnupgCollectionLoad *load, GSimpleAsyncResult *res)
 
 	g_ptr_array_add (argv, (gpointer)"--fixed-list-mode");
 	g_ptr_array_add (argv, (gpointer)"--with-colons");
+	g_ptr_array_add (argv, (gpointer)"--with-fingerprint");
 	g_ptr_array_add (argv, NULL);
 
-	if (_gcr_debugging) {
-		gchar *command = g_strjoinv (" ", (gchar**)argv->pdata);
-		_gcr_debug ("spawning gnupg process: %s", command);
-		g_free (command);
-	}
-
 	/* res is unreffed in on_gnupg_process_completed */
 	_gcr_gnupg_process_run_async (load->process, (const gchar**)argv->pdata, NULL, flags,
 	                              load->cancel, on_gnupg_process_completed,
@@ -537,10 +676,8 @@ _gcr_gnupg_collection_load_async (GcrGnupgCollection *self, GCancellable *cancel
 	load->process = _gcr_gnupg_process_new (self->pv->directory, NULL);
 	load->output_sig = g_signal_connect (load->process, "output-data", G_CALLBACK (on_gnupg_process_output_data), res);
 	load->error_sig = g_signal_connect (load->process, "error-line", G_CALLBACK (on_gnupg_process_error_line), res);
-#if 0
-	load->status_sig = g_signal_connect (load->process, "status-message", G_CALLBACK (on_gnupg_process_status_message), res);
+	load->status_sig = g_signal_connect (load->process, "status-record", G_CALLBACK (on_gnupg_process_status_record), res);
 	load->attribute_sig = g_signal_connect (load->process, "attribute-data", G_CALLBACK (on_gnupg_process_attribute_data), res);
-#endif
 
 	/*
 	 * Track all the keys we currently have, at end remove those that
diff --git a/gcr/gcr-gnupg-key.c b/gcr/gcr-gnupg-key.c
index 31ab77b..3bf768f 100644
--- a/gcr/gcr-gnupg-key.c
+++ b/gcr/gcr-gnupg-key.c
@@ -410,6 +410,17 @@ _gcr_gnupg_key_get_keyid_for_records (GPtrArray *records)
 	return NULL;
 }
 
+const gchar*
+_gcr_gnupg_key_get_fingerprint_for_records (GPtrArray *records)
+{
+	GcrRecord *record;
+
+	record = _gcr_record_find (records, GCR_RECORD_SCHEMA_FPR);
+	if (record != NULL)
+		return _gcr_record_get_raw (record, GCR_RECORD_FPR_FINGERPRINT);
+	return NULL;
+}
+
 /**
  * _gcr_gnupg_key_get_columns:
  *
diff --git a/gcr/gcr-gnupg-key.h b/gcr/gcr-gnupg-key.h
index dcef960..271bb90 100644
--- a/gcr/gcr-gnupg-key.h
+++ b/gcr/gcr-gnupg-key.h
@@ -78,6 +78,8 @@ void                _gcr_gnupg_key_set_secret_records            (GcrGnupgKey *s
 
 const gchar*        _gcr_gnupg_key_get_keyid_for_records         (GPtrArray *records);
 
+const gchar*        _gcr_gnupg_key_get_fingerprint_for_records   (GPtrArray *records);
+
 G_END_DECLS
 
 #endif /* __GCR_GNUPG_KEY_H__ */
diff --git a/gcr/gcr-gnupg-util.c b/gcr/gcr-gnupg-util.c
new file mode 100644
index 0000000..5e0025f
--- /dev/null
+++ b/gcr/gcr-gnupg-util.c
@@ -0,0 +1,102 @@
+/*
+ * 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 "egg/egg-hex.h"
+
+#include "gcr-gnupg-util.h"
+
+#include <gcrypt.h>
+
+GcrRecord*
+_gcr_gnupg_build_xa1_record (GcrRecord *meta, gpointer attribute,
+                             gsize n_attribute)
+{
+	gchar hash[20];
+	gchar *hex;
+	gchar *status = "";
+	gint state, save;
+	gsize length;
+	gsize n_prefix, estimate;
+	GString *output;
+	GcrRecord *record;
+	guint flags, type;
+	const gchar *fingerprint, *created, *expiry;
+
+	g_return_val_if_fail (meta, NULL);
+
+	gcry_md_hash_buffer (GCRY_MD_RMD160, hash, attribute, n_attribute);
+	hex = egg_hex_encode_full (hash, sizeof (hash), TRUE, 0, 1);
+
+	if (!_gcr_record_get_uint (meta, GCR_RECORD_ATTRIBUTE_FLAGS, &flags))
+		flags = 0;
+
+	if (!_gcr_record_get_uint (meta, GCR_RECORD_ATTRIBUTE_TYPE, &type))
+		type = 0;
+
+	fingerprint = _gcr_record_get_raw (meta, GCR_RECORD_ATTRIBUTE_FINGERPRINT);
+	if (fingerprint == NULL)
+		fingerprint = "";
+
+	created = _gcr_record_get_raw (meta, GCR_RECORD_ATTRIBUTE_TIMESTAMP);
+	if (created == NULL)
+		created = "0";
+
+	expiry = _gcr_record_get_raw (meta, GCR_RECORD_ATTRIBUTE_EXPIRY);
+	if (expiry == NULL)
+		expiry = "";
+
+	if (flags & 0x02)
+		status = "r";
+	else if (flags & 0x04)
+		status = "e";
+	else if (flags & 0x01)
+		status = "P";
+
+	/* Algorithm from Glib reference */
+	estimate = n_attribute * 4 / 3 + n_attribute * 4 / (3 * 65) + 7;
+
+	output = g_string_sized_new (64 + estimate);
+	g_string_append_printf (output, "xa1::%u:%u:%s:%s:%s:%s:%s:",
+	                        (guint)n_attribute, type, fingerprint,
+	                        created, expiry, hex, status);
+
+	g_free (hex);
+
+	/* Resize string to fit the base64 data. */
+	n_prefix = output->len;
+	g_string_set_size (output, n_prefix + estimate);
+
+	/* The actual base64 data, without line breaks */
+	state = save = 0;
+	length = g_base64_encode_step ((guchar*)attribute, n_attribute, FALSE,
+	                               output->str + n_prefix, &state, &save);
+	length += g_base64_encode_close (TRUE, output->str + n_prefix + length,
+	                                 &state, &save);
+
+	g_assert (length <= estimate);
+	g_string_set_size (output, n_prefix + length);
+	record = _gcr_record_take_colons (g_string_free (output, FALSE));
+	g_assert (record);
+
+	return record;
+}
diff --git a/gcr/gcr-gnupg-util.h b/gcr/gcr-gnupg-util.h
new file mode 100644
index 0000000..49b0e4f
--- /dev/null
+++ b/gcr/gcr-gnupg-util.h
@@ -0,0 +1,41 @@
+/*
+ * 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_UTIL_H
+#define GCR_GNUPG_UTIL_H
+
+#include <glib.h>
+
+#include "gcr-record.h"
+
+G_BEGIN_DECLS
+
+GcrRecord*          _gcr_gnupg_build_xa1_record              (GcrRecord *meta,
+                                                              gpointer attribute,
+                                                              gsize n_attribute);
+
+G_END_DECLS
+
+#endif /* __GCR_GNUPG_KEY_H__ */
diff --git a/gcr/gcr-record.h b/gcr/gcr-record.h
index 3cc6d8d..5b1b69a 100644
--- a/gcr/gcr-record.h
+++ b/gcr/gcr-record.h
@@ -51,9 +51,12 @@
 
 G_BEGIN_DECLS
 
-#define GCR_RECORD_SCHEMA_UID  (g_quark_from_static_string ("uid"))
+#define GCR_RECORD_SCHEMA_ATTRIBUTE  (g_quark_from_static_string ("ATTRIBUTE"))
+#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_SEC  (g_quark_from_static_string ("sec"))
+#define GCR_RECORD_SCHEMA_UID  (g_quark_from_static_string ("uid"))
+#define GCR_RECORD_SCHEMA_XA1  (g_quark_from_static_string ("xa1"))
 
 /* Common columns for all schemas */
 typedef enum {
@@ -61,6 +64,28 @@ typedef enum {
 } GcrRecordColumns;
 
 /*
+ * Columns for ATTRIBUTE status message. eg:
+ * [GNUPG:] ATTRIBUTE FBAFC70D60AE13D560764062B547B5580EEB5A80 10604 1 1 1 1227936754 0 1
+ */
+typedef enum {
+	GCR_RECORD_ATTRIBUTE_FINGERPRINT = 1,
+	GCR_RECORD_ATTRIBUTE_LENGTH = 2,
+	GCR_RECORD_ATTRIBUTE_TYPE = 3,
+	GCR_RECORD_ATTRIBUTE_TIMESTAMP = 6,
+	GCR_RECORD_ATTRIBUTE_EXPIRY = 7,
+	GCR_RECORD_ATTRIBUTE_FLAGS = 8
+} GcrRecordAttributeColumns;
+
+/*
+ * Columns for fpr schema, add them as they're used. eg:
+ * fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013:
+ */
+typedef enum {
+	GCR_RECORD_FPR_FINGERPRINT = 9
+} GcrRecordFprColumns;
+
+
+/*
  * Columns for pub schema, add them as they're used. eg:
  * pub:f:1024:17:6C7EE1B8621CC013:899817715:1055898235::m:::scESC:
  */
@@ -84,6 +109,22 @@ typedef enum {
 	GCR_RECORD_UID_NAME = 9
 } GcrRecordUidColumns;
 
+/*
+ * Columns for xa1 schema. This is a schema that we've invented ourselves
+ * for representing the actual data of openpgp attribute packets. eg:
+ * xa1::10838:1:ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013:1998-02-02:0:ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013:P:...
+ */
+typedef enum {
+	GCR_RECORD_XA1_LENGTH = 2,
+	GCR_RECORD_XA1_TYPE = 3,
+	GCR_RECORD_XA1_FINGERPRINT = 4,
+	GCR_RECORD_XA1_TIMESTAMP = 5,
+	GCR_RECORD_XA1_EXPIRY = 6,
+	GCR_RECORD_XA1_HASH = 7,
+	GCR_RECORD_XA1_STATUS = 8,
+	GCR_RECORD_XA1_DATA = 9,
+} GcrRecordXa1Columns;
+
 typedef struct _GcrRecord GcrRecord;
 
 #define        GCR_TYPE_RECORD                  (_gcr_record_get_type ())
diff --git a/gcr/tests/test-gnupg-collection.c b/gcr/tests/test-gnupg-collection.c
index c164ea6..3808596 100644
--- a/gcr/tests/test-gnupg-collection.c
+++ b/gcr/tests/test-gnupg-collection.c
@@ -25,6 +25,7 @@
 #include "gcr/gcr.h"
 #include "gcr/gcr-gnupg-collection.h"
 #include "gcr/gcr-gnupg-key.h"
+#include "gcr/gcr-record.h"
 
 #include "egg/egg-testing.h"
 
@@ -35,6 +36,7 @@
 
 typedef struct {
 	GcrGnupgCollection *collection;
+	gchar *directory;
 	GHashTable *keys;
 	GAsyncResult *result;
 } Test;
@@ -81,19 +83,17 @@ setup (Test *test, gconstpointer unused)
 {
 	GcrCollection *collection;
 	gchar *directory;
-	gchar *path;
 
 	directory = g_get_current_dir ();
-	path = g_build_filename (directory, "files", "gnupg-homedir", NULL);
+	test->directory = g_build_filename (directory, "files", "gnupg-homedir", NULL);
 
-	collection = _gcr_gnupg_collection_new (path);
+	collection = _gcr_gnupg_collection_new (test->directory);
 	test->collection = GCR_GNUPG_COLLECTION (collection);
 
 	test->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 	g_signal_connect (collection, "added", G_CALLBACK (on_collection_added), test);
 	g_signal_connect (collection, "removed", G_CALLBACK (on_collection_removed), test);
 
-	g_free (path);
 	g_free (directory);
 }
 
@@ -106,6 +106,7 @@ teardown (Test *test, gconstpointer unused)
 		g_object_unref (test->result);
 
 	g_object_unref (test->collection);
+	g_free (test->directory);
 }
 
 static void
@@ -119,13 +120,24 @@ on_async_ready (GObject *source, GAsyncResult *res, gpointer user_data)
 }
 
 static void
+test_properties (Test *test, gconstpointer unused)
+{
+	gchar *directory;
+	g_object_get (test->collection, "directory", &directory, NULL);
+	g_assert_cmpstr (directory, ==, test->directory);
+	g_free (directory);
+}
+
+static void
 test_load (Test *test, gconstpointer unused)
 {
 	GError *error = NULL;
 	GcrGnupgKey *key;
+	GList *l, *objects;
+	GcrRecord *record;
 
 	_gcr_gnupg_collection_load_async (test->collection, NULL, on_async_ready, test);
-	egg_test_wait_until (500);
+	egg_test_wait_until (500000);
 
 	g_assert (test->result);
 	_gcr_gnupg_collection_load_finish (test->collection, test->result, &error);
@@ -140,6 +152,26 @@ test_load (Test *test, gconstpointer unused)
 	key = g_hash_table_lookup (test->keys, "268FEE686262C395");
 	g_assert (GCR_IS_GNUPG_KEY (key));
 	g_assert (_gcr_gnupg_key_get_secret_records (key));
+
+	/* The length of collection should be correct */
+	g_assert_cmpuint (g_hash_table_size (test->keys), ==,
+	                  gcr_collection_get_length (GCR_COLLECTION (test->collection)));
+
+	/* The list of objects should be correct */
+	objects = gcr_collection_get_objects (GCR_COLLECTION (test->collection));
+	g_assert_cmpuint (g_hash_table_size (test->keys), ==, g_list_length (objects));
+	for (l = objects; l != NULL; l = g_list_next (l)) {
+		g_assert (GCR_IS_GNUPG_KEY (l->data));
+		key = g_hash_table_lookup (test->keys, _gcr_gnupg_key_get_keyid (l->data));
+		g_assert (key == l->data);
+	}
+	g_list_free (objects);
+
+	/* Phillip R. Zimmerman's key should have a photo */
+	key = g_hash_table_lookup (test->keys, "C7463639B2D7795E");
+	g_assert (GCR_IS_GNUPG_KEY (key));
+	record = _gcr_record_find (_gcr_gnupg_key_get_public_records (key), GCR_RECORD_SCHEMA_XA1);
+	g_assert (record);
 }
 
 static void
@@ -158,7 +190,7 @@ test_reload (Test *test, gconstpointer unused)
 	test->result = NULL;
 
 	_gcr_gnupg_collection_load_async (test->collection, NULL, on_async_ready, test);
-	egg_test_wait_until (500);
+	egg_test_wait_until (500000);
 	g_assert (test->result);
 	_gcr_gnupg_collection_load_finish (test->collection, test->result, &error);
 	g_assert_no_error (error);
@@ -187,6 +219,7 @@ main (int argc, char **argv)
 	if (srcdir && chdir (srcdir) < 0)
 		g_error ("couldn't change directory to: %s: %s", srcdir, g_strerror (errno));
 
+	g_test_add ("/gcr/gnupg-collection/properties", Test, NULL, setup, test_properties, teardown);
 	g_test_add ("/gcr/gnupg-collection/load", Test, NULL, setup, test_load, teardown);
 	g_test_add ("/gcr/gnupg-collection/reload", Test, NULL, setup, test_reload, teardown);
 



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