[libsecret] Make secret_service_search() able to unlock, load secrets



commit 889f6d66b72904df779ff52054ee86abc03bcd7e
Author: Stef Walter <stefw gnome org>
Date:   Thu Jul 5 19:08:09 2012 +0200

    Make secret_service_search() able to unlock, load secrets
    
     * Turn secret_service_search() and friends into a more convenient
       API, so that callers can get attributes, unlocking, and secrets
       if so desired.
     * Also support retrieving either one secret, or all of them.

 docs/reference/libsecret/libsecret-sections.txt |    3 +
 library/secret-methods.c                        |  285 ++++++++++++++++-------
 library/secret-service.h                        |   19 +-
 library/tests/test-methods.c                    |  268 ++++++++++++++++------
 4 files changed, 413 insertions(+), 162 deletions(-)
---
diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt
index cd014ef..805ee22 100644
--- a/docs/reference/libsecret/libsecret-sections.txt
+++ b/docs/reference/libsecret/libsecret-sections.txt
@@ -186,6 +186,7 @@ secret_service_ensure_session_sync
 secret_service_ensure_collections
 secret_service_ensure_collections_finish
 secret_service_ensure_collections_sync
+SecretSearchFlags
 secret_service_search
 secret_service_search_finish
 secret_service_search_sync
@@ -219,9 +220,11 @@ SECRET_IS_SERVICE_CLASS
 SECRET_SERVICE
 SECRET_SERVICE_CLASS
 SECRET_SERVICE_GET_CLASS
+SECRET_TYPE_SEARCH_FLAGS
 SECRET_TYPE_SERVICE
 SECRET_TYPE_SERVICE_FLAGS
 SecretServicePrivate
+secret_search_flags_get_type
 secret_service_flags_get_type
 secret_service_get_type
 </SECTION>
diff --git a/library/secret-methods.c b/library/secret-methods.c
index 151e5f7..df43525 100644
--- a/library/secret-methods.c
+++ b/library/secret-methods.c
@@ -25,17 +25,20 @@
 #include "secret-value.h"
 
 typedef struct {
+	SecretService *service;
 	GCancellable *cancellable;
 	GHashTable *items;
 	gchar **unlocked;
 	gchar **locked;
 	guint loading;
+	SecretSearchFlags flags;
 } SearchClosure;
 
 static void
 search_closure_free (gpointer data)
 {
 	SearchClosure *closure = data;
+	g_object_unref (closure->service);
 	g_clear_object (&closure->cancellable);
 	g_hash_table_unref (closure->items);
 	g_strfreev (closure->unlocked);
@@ -51,6 +54,64 @@ search_closure_take_item (SearchClosure *closure,
 	g_hash_table_insert (closure->items, (gpointer)path, item);
 }
 
+static GList *
+search_closure_build_items (SearchClosure *closure,
+                            gchar **paths)
+{
+	GList *results = NULL;
+	SecretItem *item;
+	guint i;
+
+	for (i = 0; paths[i]; i++) {
+		item = g_hash_table_lookup (closure->items, paths[i]);
+		if (item != NULL)
+			results = g_list_prepend (results, g_object_ref (item));
+	}
+
+	return g_list_reverse (results);
+}
+
+static void
+on_search_secrets (GObject *source,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+
+	/* Note that we ignore any unlock failure */
+	secret_item_load_secrets_finish (result, NULL);
+
+	g_simple_async_result_complete (async);
+	g_object_unref (async);
+}
+
+static void
+on_search_unlocked (GObject *source,
+                    GAsyncResult *result,
+                    gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	SearchClosure *search = g_simple_async_result_get_op_res_gpointer (async);
+	GList *items;
+
+	/* Note that we ignore any unlock failure */
+	secret_service_unlock_finish (search->service, result, NULL, NULL);
+
+	/* If loading secrets ... locked items automatically ignored */
+	if (search->flags & SECRET_SEARCH_LOAD_SECRETS) {
+		items = g_hash_table_get_values (search->items);
+		secret_item_load_secrets (items, search->cancellable,
+		                          on_search_secrets, g_object_ref (async));
+		g_list_free (items);
+
+	/* No additional options, just complete */
+	} else {
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (async);
+}
+
 static void
 on_search_loaded (GObject *source,
                   GAsyncResult *result,
@@ -60,6 +121,7 @@ on_search_loaded (GObject *source,
 	SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
 	GError *error = NULL;
 	SecretItem *item;
+	GList *items;
 
 	closure->loading--;
 
@@ -69,8 +131,29 @@ on_search_loaded (GObject *source,
 
 	if (item != NULL)
 		search_closure_take_item (closure, item);
-	if (closure->loading == 0)
-		g_simple_async_result_complete (res);
+
+	/* We're done loading, lets go to the next step */
+	if (closure->loading == 0) {
+
+		/* If unlocking then unlock all the locked items */
+		if (closure->flags & SECRET_SEARCH_UNLOCK) {
+			items = search_closure_build_items (closure, closure->locked);
+			secret_service_unlock (closure->service, items, closure->cancellable,
+			                       on_search_unlocked, g_object_ref (res));
+			g_list_free_full (items, g_object_unref);
+
+		/* If loading secrets ... locked items automatically ignored */
+		} else if (closure->flags & SECRET_SEARCH_LOAD_SECRETS) {
+			items = g_hash_table_get_values (closure->items);
+			secret_item_load_secrets (items, closure->cancellable,
+			                          on_search_secrets, g_object_ref (res));
+			g_list_free (items);
+
+		/* No additional options, just complete */
+		} else {
+			g_simple_async_result_complete (res);
+		}
+	}
 
 	g_object_unref (res);
 }
@@ -100,23 +183,31 @@ on_search_paths (GObject *source,
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
 	SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	SecretService *self = SECRET_SERVICE (source);
+	SecretService *self = closure->service;
 	GError *error = NULL;
+	gint want = 1;
 	guint i;
 
-	if (!secret_service_search_for_paths_finish (self, result, &closure->unlocked,
-	                                              &closure->locked, &error)) {
-		g_simple_async_result_take_error (res, error);
-		g_simple_async_result_complete (res);
-	}
+	secret_service_search_for_paths_finish (self, result, &closure->unlocked,
+	                                        &closure->locked, &error);
+	if (error == NULL) {
+		want = 1;
+		if (closure->flags & SECRET_SEARCH_ALL)
+			want = G_MAXINT;
 
-	for (i = 0; closure->unlocked[i] != NULL; i++)
-		search_load_item_async (self, res, closure, closure->unlocked[i]);
-	for (i = 0; closure->locked[i] != NULL; i++)
-		search_load_item_async (self, res, closure, closure->locked[i]);
+		for (i = 0; closure->loading < want && closure->unlocked[i] != NULL; i++)
+			search_load_item_async (self, res, closure, closure->unlocked[i]);
+		for (i = 0; closure->loading < want && closure->locked[i] != NULL; i++)
+			search_load_item_async (self, res, closure, closure->locked[i]);
 
-	if (closure->loading == 0)
+		/* No items loading, complete operation now */
+		if (closure->loading == 0)
+			g_simple_async_result_complete (res);
+
+	} else {
+		g_simple_async_result_take_error (res, error);
 		g_simple_async_result_complete (res);
+	}
 
 	g_object_unref (res);
 }
@@ -125,6 +216,7 @@ on_search_paths (GObject *source,
  * secret_service_search:
  * @self: the secret service
  * @attributes: (element-type utf8 utf8): search for items matching these attributes
+ * @flags: search option flags
  * @cancellable: optional cancellation object
  * @callback: called when the operation completes
  * @user_data: data to pass to the callback
@@ -132,16 +224,23 @@ on_search_paths (GObject *source,
  * Search for items matching the @attributes. All collections are searched.
  * The @attributes should be a table of string keys and string values.
  *
- * This function returns immediately and completes asynchronously.
+ * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the
+ * search will be returned. Otherwise only the first item will be returned.
+ * This is almost always the unlocked item that was most recently stored.
+ *
+ * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked
+ * if necessary. In either case, locked and unlocked items will match the
+ * search and be returned. If the unlock fails, the search does not fail.
  *
- * When your callback is called use secret_service_search_finish()
- * to get the results of this function. #SecretItem proxy objects will be
- * returned. If you prefer to only have the items D-Bus object paths returned,
- * then then use the secret_service_search_for_paths() function.
+ * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items will have
+ * their secret values loaded and available via secret_item_get_secret().
+ *
+ * This function returns immediately and completes asynchronously.
  */
 void
 secret_service_search (SecretService *self,
                        GHashTable *attributes,
+                       SecretSearchFlags flags,
                        GCancellable *cancellable,
                        GAsyncReadyCallback callback,
                        gpointer user_data)
@@ -156,8 +255,10 @@ secret_service_search (SecretService *self,
 	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
 	                                 secret_service_search);
 	closure = g_slice_new0 (SearchClosure);
+	closure->service = g_object_ref (self);
 	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
 	closure->items = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+	closure->flags = flags;
 	g_simple_async_result_set_op_res_gpointer (res, closure, search_closure_free);
 
 	secret_service_search_for_paths (self, attributes, cancellable,
@@ -166,53 +267,25 @@ secret_service_search (SecretService *self,
 	g_object_unref (res);
 }
 
-static GList *
-search_finish_build (gchar **paths,
-                     SearchClosure *closure)
-{
-	GList *results = NULL;
-	SecretItem *item;
-	guint i;
-
-	for (i = 0; paths[i]; i++) {
-		item = g_hash_table_lookup (closure->items, paths[i]);
-		if (item != NULL)
-			results = g_list_prepend (results, g_object_ref (item));
-	}
-
-	return g_list_reverse (results);
-}
-
 /**
  * secret_service_search_finish:
  * @self: the secret service
  * @result: asynchronous result passed to callback
- * @unlocked: (out) (transfer full) (element-type Secret.Item) (allow-none):
- *            location to place a list of matching items which were not locked.
- * @locked: (out) (transfer full) (element-type Secret.Item) (allow-none):
- *          location to place a list of matching items which were locked.
  * @error: location to place error on failure
  *
  * Complete asynchronous operation to search for items.
  *
- * Matching items that are locked or unlocked are placed in the @locked or
- * @unlocked lists respectively.
- *
- * #SecretItem proxy objects will be returned. If you prefer to only have
- * the items' D-Bus object paths returned, then then use the
- * secret_service_search_for_paths() function.
- *
- * Returns: whether the search was successful or not
+ * Returns: (transfer full) (element-type Secret.Item):
+ *          a list of items that matched the search
  */
-gboolean
+GList *
 secret_service_search_finish (SecretService *self,
                               GAsyncResult *result,
-                              GList **unlocked,
-                              GList **locked,
                               GError **error)
 {
 	GSimpleAsyncResult *res;
 	SearchClosure *closure;
+	GList *items;
 
 	g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -225,12 +298,11 @@ secret_service_search_finish (SecretService *self,
 		return FALSE;
 
 	closure = g_simple_async_result_get_op_res_gpointer (res);
-	if (unlocked)
-		*unlocked = search_finish_build (closure->unlocked, closure);
-	if (locked)
-		*locked = search_finish_build (closure->locked, closure);
-
-	return TRUE;
+	if (closure->unlocked)
+		items = search_closure_build_items (closure, closure->unlocked);
+	if (closure->locked)
+		items = g_list_concat (items, search_closure_build_items (closure, closure->locked));
+	return items;
 }
 
 static gboolean
@@ -238,26 +310,27 @@ service_load_items_sync (SecretService *self,
                          GCancellable *cancellable,
                          gchar **paths,
                          GList **items,
+                         gint want,
+                         gint *have,
                          GError **error)
 {
 	SecretItem *item;
-	GList *result = NULL;
 	guint i;
 
-	for (i = 0; paths[i] != NULL; i++) {
+	for (i = 0; *have < want && paths[i] != NULL; i++) {
 		item = _secret_service_find_item_instance (self, paths[i]);
 		if (item == NULL)
 			item = secret_item_new_sync (self, paths[i], SECRET_ITEM_NONE,
 			                             cancellable, error);
 		if (item == NULL) {
-			g_list_free_full (result, g_object_unref);
 			return FALSE;
+
 		} else {
-			result = g_list_prepend (result, item);
+			*items = g_list_prepend (*items, item);
+			(*have)++;
 		}
 	}
 
-	*items = g_list_reverse (result);
 	return TRUE;
 }
 
@@ -265,60 +338,98 @@ service_load_items_sync (SecretService *self,
  * secret_service_search_sync:
  * @self: the secret service
  * @attributes: (element-type utf8 utf8): search for items matching these attributes
+ * @flags: search option flags
  * @cancellable: optional cancellation object
- * @unlocked: (out) (transfer full) (element-type Secret.Item) (allow-none):
- *            location to place a list of matching items which were not locked.
- * @locked: (out) (transfer full) (element-type Secret.Item) (allow-none):
- *          location to place a list of matching items which were locked.
  * @error: location to place error on failure
  *
  * Search for items matching the @attributes. All collections are searched.
  * The @attributes should be a table of string keys and string values.
  *
- * This function may block indefinetely. Use the asynchronous version
- * in user interface threads.
+ * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the
+ * search will be returned. Otherwise only the first item will be returned.
+ * This is almost always the unlocked item that was most recently stored.
  *
- * Matching items that are locked or unlocked are placed
- * in the @locked or @unlocked lists respectively.
+ * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked
+ * if necessary. In either case, locked and unlocked items will match the
+ * search and be returned. If the unlock fails, the search does not fail.
  *
- * #SecretItem proxy objects will be returned. If you prefer to only have
- * the items' D-Bus object paths returned, then then use the
- * secret_service_search_sync() function.
+ * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items' secret
+ * values will be loaded for any unlocked items. Loaded item secret values
+ * are available via secret_item_get_secret(). If the load of a secret values
+ * fail, then the
  *
- * Returns: whether the search was successful or not
+ * This function may block indefinetely. Use the asynchronous version
+ * in user interface threads.
+ *
+ * Returns: (transfer full) (element-type Secret.Item):
+ *          a list of items that matched the search
  */
-gboolean
+GList *
 secret_service_search_sync (SecretService *self,
                             GHashTable *attributes,
+                            SecretSearchFlags flags,
                             GCancellable *cancellable,
-                            GList **unlocked,
-                            GList **locked,
                             GError **error)
 {
 	gchar **unlocked_paths = NULL;
 	gchar **locked_paths = NULL;
+	GList *items = NULL;
+	GList *locked = NULL;
+	GList *unlocked = NULL;
 	gboolean ret;
+	gint want;
+	gint have;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
-	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
 	if (!secret_service_search_for_paths_sync (self, attributes, cancellable,
-	                                           unlocked ? &unlocked_paths : NULL,
-	                                           locked ? &locked_paths : NULL, error))
-		return FALSE;
+	                                           &unlocked_paths, &locked_paths, error))
+		return NULL;
 
 	ret = TRUE;
 
-	if (unlocked)
-		ret = service_load_items_sync (self, cancellable, unlocked_paths, unlocked, error);
-	if (ret && locked)
-		ret = service_load_items_sync (self, cancellable, locked_paths, locked, error);
+	want = 1;
+	if (flags & SECRET_SEARCH_ALL)
+		want = G_MAXINT;
+	have = 0;
+
+	/* Remember, we're adding to the list backwards */
+
+	if (unlocked_paths) {
+		ret = service_load_items_sync (self, cancellable, unlocked_paths,
+		                               &unlocked, want, &have, error);
+	}
+
+	if (ret && locked_paths) {
+		ret = service_load_items_sync (self, cancellable, locked_paths,
+		                               &locked, want, &have, error);
+	}
 
 	g_strfreev (unlocked_paths);
 	g_strfreev (locked_paths);
 
-	return ret;
+	if (!ret) {
+		g_list_free_full (unlocked, g_object_unref);
+		g_list_free_full (locked, g_object_unref);
+		return NULL;
+	}
+
+	/* The lists are backwards at this point ... */
+	items = g_list_concat (items, g_list_copy (locked));
+	items = g_list_concat (items, g_list_copy (unlocked));
+	items = g_list_reverse (items);
+
+	if (flags & SECRET_SEARCH_UNLOCK)
+		secret_service_unlock_sync (self, locked, cancellable, NULL, NULL);
+
+	if (flags & SECRET_SEARCH_LOAD_SECRETS)
+		secret_item_load_secrets_sync (items, NULL, NULL);
+
+	g_list_free (locked);
+	g_list_free (unlocked);
+	return items;
 }
 
 SecretValue *
diff --git a/library/secret-service.h b/library/secret-service.h
index b3afcae..cb221e4 100644
--- a/library/secret-service.h
+++ b/library/secret-service.h
@@ -30,11 +30,18 @@
 G_BEGIN_DECLS
 
 typedef enum {
-	SECRET_SERVICE_NONE,
+	SECRET_SERVICE_NONE = 0,
 	SECRET_SERVICE_OPEN_SESSION = 1 << 1,
 	SECRET_SERVICE_LOAD_COLLECTIONS = 1 << 2,
 } SecretServiceFlags;
 
+typedef enum {
+	SECRET_SEARCH_NONE = 0,
+	SECRET_SEARCH_ALL = 1 << 1,
+	SECRET_SEARCH_UNLOCK = 1 << 2,
+	SECRET_SEARCH_LOAD_SECRETS = 1 << 3,
+} SecretSearchFlags;
+
 #define SECRET_TYPE_SERVICE            (secret_service_get_type ())
 #define SECRET_SERVICE(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), SECRET_TYPE_SERVICE, SecretService))
 #define SECRET_SERVICE_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), SECRET_TYPE_SERVICE, SecretServiceClass))
@@ -145,21 +152,19 @@ gboolean             secret_service_ensure_collections_sync       (SecretService
 
 void                 secret_service_search                        (SecretService *self,
                                                                    GHashTable *attributes,
+                                                                   SecretSearchFlags flags,
                                                                    GCancellable *cancellable,
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 
-gboolean             secret_service_search_finish                 (SecretService *self,
+GList *              secret_service_search_finish                 (SecretService *self,
                                                                    GAsyncResult *result,
-                                                                   GList **unlocked,
-                                                                   GList **locked,
                                                                    GError **error);
 
-gboolean             secret_service_search_sync                   (SecretService *self,
+GList *              secret_service_search_sync                   (SecretService *self,
                                                                    GHashTable *attributes,
+                                                                   SecretSearchFlags flags,
                                                                    GCancellable *cancellable,
-                                                                   GList **unlocked,
-                                                                   GList **locked,
                                                                    GError **error);
 
 void                 secret_service_lock                          (SecretService *self,
diff --git a/library/tests/test-methods.c b/library/tests/test-methods.c
index b52ab58..f725b5a 100644
--- a/library/tests/test-methods.c
+++ b/library/tests/test-methods.c
@@ -121,29 +121,22 @@ test_search_sync (Test *test,
                   gconstpointer used)
 {
 	GHashTable *attributes;
-	gboolean ret;
-	GList *locked;
-	GList *unlocked;
 	GError *error = NULL;
+	GList *items;
 
 	attributes = g_hash_table_new (g_str_hash, g_str_equal);
 	g_hash_table_insert (attributes, "number", "1");
 
-	ret = secret_service_search_sync (test->service, attributes, NULL,
-	                                   &unlocked, &locked, &error);
+	items = secret_service_search_sync (test->service, attributes, SECRET_SEARCH_NONE,
+	                                    NULL, &error);
 	g_assert_no_error (error);
-	g_assert (ret == TRUE);
-
-	g_assert (locked != NULL);
-	g_assert_cmpstr (g_dbus_proxy_get_object_path (locked->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
-
-	g_assert (unlocked != NULL);
-	g_assert_cmpstr (g_dbus_proxy_get_object_path (unlocked->data), ==, "/org/freedesktop/secrets/collection/english/1");
+	g_hash_table_unref (attributes);
 
-	g_list_free_full (unlocked, g_object_unref);
-	g_list_free_full (locked, g_object_unref);
+	g_assert (items != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1");
 
-	g_hash_table_unref (attributes);
+	g_assert (items->next == NULL);
+	g_list_free_full (items, g_object_unref);
 }
 
 static void
@@ -152,109 +145,243 @@ test_search_async (Test *test,
 {
 	GAsyncResult *result = NULL;
 	GHashTable *attributes;
-	gboolean ret;
-	GList *locked;
-	GList *unlocked;
 	GError *error = NULL;
+	GList *items;
 
 	attributes = g_hash_table_new (g_str_hash, g_str_equal);
 	g_hash_table_insert (attributes, "number", "1");
 
-	secret_service_search (test->service, attributes, NULL,
-	                        on_complete_get_result, &result);
+	secret_service_search (test->service, attributes, SECRET_SEARCH_NONE, NULL,
+	                       on_complete_get_result, &result);
+	g_hash_table_unref (attributes);
+	g_assert (result == NULL);
+
 	egg_test_wait ();
 
 	g_assert (G_IS_ASYNC_RESULT (result));
-	ret = secret_service_search_finish (test->service, result,
-	                                     &unlocked, &locked,
-	                                     &error);
+	items = secret_service_search_finish (test->service, result, &error);
 	g_assert_no_error (error);
-	g_assert (ret == TRUE);
+	g_object_unref (result);
 
-	g_assert (locked != NULL);
-	g_assert_cmpstr (g_dbus_proxy_get_object_path (locked->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
+	g_assert (items != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1");
 
-	g_assert (unlocked != NULL);
-	g_assert_cmpstr (g_dbus_proxy_get_object_path (unlocked->data), ==, "/org/freedesktop/secrets/collection/english/1");
+	g_assert (items->next == NULL);
+	g_list_free_full (items, g_object_unref);
+}
 
-	g_list_free_full (unlocked, g_object_unref);
-	g_list_free_full (locked, g_object_unref);
-	g_object_unref (result);
+static void
+test_search_all_sync (Test *test,
+                  gconstpointer used)
+{
+	GHashTable *attributes;
+	GError *error = NULL;
+	GList *items;
+
+	attributes = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (attributes, "number", "1");
 
+	items = secret_service_search_sync (test->service, attributes, SECRET_SEARCH_ALL,
+	                                    NULL, &error);
+	g_assert_no_error (error);
 	g_hash_table_unref (attributes);
+
+	g_assert (items != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1");
+	g_assert (secret_item_get_locked (items->data) == FALSE);
+	g_assert (secret_item_get_secret (items->data) == NULL);
+
+	g_assert (items->next != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
+	g_assert (secret_item_get_locked (items->next->data) == TRUE);
+	g_assert (secret_item_get_secret (items->next->data) == NULL);
+
+	g_assert (items->next->next == NULL);
+	g_list_free_full (items, g_object_unref);
 }
 
 static void
-test_search_nulls (Test *test,
+test_search_all_async (Test *test,
                    gconstpointer used)
 {
 	GAsyncResult *result = NULL;
 	GHashTable *attributes;
-	gboolean ret;
-	GList *items;
 	GError *error = NULL;
+	GList *items;
 
 	attributes = g_hash_table_new (g_str_hash, g_str_equal);
 	g_hash_table_insert (attributes, "number", "1");
 
-	ret = secret_service_search_sync (test->service, attributes, NULL,
-	                                   &items, NULL, &error);
+	secret_service_search (test->service, attributes, SECRET_SEARCH_ALL, NULL,
+	                       on_complete_get_result, &result);
+	g_hash_table_unref (attributes);
+	g_assert (result == NULL);
+
+	egg_test_wait ();
+
+	g_assert (G_IS_ASYNC_RESULT (result));
+	items = secret_service_search_finish (test->service, result, &error);
 	g_assert_no_error (error);
-	g_assert (ret == TRUE);
+	g_object_unref (result);
+
 	g_assert (items != NULL);
 	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1");
+	g_assert (secret_item_get_locked (items->data) == FALSE);
+	g_assert (secret_item_get_secret (items->data) == NULL);
+
+	g_assert (items->next != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
+	g_assert (secret_item_get_locked (items->next->data) == TRUE);
+	g_assert (secret_item_get_secret (items->next->data) == NULL);
+
+	g_assert (items->next->next == NULL);
 	g_list_free_full (items, g_object_unref);
+}
 
-	ret = secret_service_search_sync (test->service, attributes, NULL,
-	                                   NULL, &items, &error);
+static void
+test_search_unlock_sync (Test *test,
+                         gconstpointer used)
+{
+	GHashTable *attributes;
+	GError *error = NULL;
+	GList *items;
+
+	attributes = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (attributes, "number", "1");
+
+	items = secret_service_search_sync (test->service, attributes,
+	                                    SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK,
+	                                    NULL, &error);
 	g_assert_no_error (error);
-	g_assert (ret == TRUE);
+	g_hash_table_unref (attributes);
+
 	g_assert (items != NULL);
-	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1");
+	g_assert (secret_item_get_locked (items->data) == FALSE);
+	g_assert (secret_item_get_secret (items->data) == NULL);
+
+	g_assert (items->next != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
+	g_assert (secret_item_get_locked (items->next->data) == FALSE);
+	g_assert (secret_item_get_secret (items->next->data) == NULL);
+
+	g_assert (items->next->next == NULL);
 	g_list_free_full (items, g_object_unref);
+}
 
-	ret = secret_service_search_sync (test->service, attributes, NULL,
-	                                   NULL, NULL, &error);
-	g_assert_no_error (error);
-	g_assert (ret == TRUE);
+static void
+test_search_unlock_async (Test *test,
+                          gconstpointer used)
+{
+	GAsyncResult *result = NULL;
+	GHashTable *attributes;
+	GError *error = NULL;
+	GList *items;
+
+	attributes = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (attributes, "number", "1");
+
+	secret_service_search (test->service, attributes,
+	                       SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK, NULL,
+	                       on_complete_get_result, &result);
+	g_hash_table_unref (attributes);
+	g_assert (result == NULL);
 
-	secret_service_search (test->service, attributes, NULL,
-	                        on_complete_get_result, &result);
 	egg_test_wait ();
+
 	g_assert (G_IS_ASYNC_RESULT (result));
-	ret = secret_service_search_finish (test->service, result,
-	                                     &items, NULL, &error);
+	items = secret_service_search_finish (test->service, result, &error);
 	g_assert_no_error (error);
-	g_assert (ret == TRUE);
+	g_object_unref (result);
+
 	g_assert (items != NULL);
 	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1");
+	g_assert (secret_item_get_locked (items->data) == FALSE);
+	g_assert (secret_item_get_secret (items->data) == NULL);
+
+	g_assert (items->next != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
+	g_assert (secret_item_get_locked (items->next->data) == FALSE);
+	g_assert (secret_item_get_secret (items->next->data) == NULL);
+
+	g_assert (items->next->next == NULL);
 	g_list_free_full (items, g_object_unref);
-	g_clear_object (&result);
+}
 
-	secret_service_search (test->service, attributes, NULL,
-	                        on_complete_get_result, &result);
-	egg_test_wait ();
-	g_assert (G_IS_ASYNC_RESULT (result));
-	ret = secret_service_search_finish (test->service, result,
-	                                     NULL, &items, &error);
+static void
+test_search_secrets_sync (Test *test,
+                          gconstpointer used)
+{
+	GHashTable *attributes;
+	GError *error = NULL;
+	SecretValue *value;
+	GList *items;
+
+	attributes = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (attributes, "number", "1");
+
+	items = secret_service_search_sync (test->service, attributes,
+	                                    SECRET_SEARCH_ALL | SECRET_SEARCH_LOAD_SECRETS,
+	                                    NULL, &error);
 	g_assert_no_error (error);
-	g_assert (ret == TRUE);
+	g_hash_table_unref (attributes);
+
 	g_assert (items != NULL);
-	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1");
+	g_assert (secret_item_get_locked (items->data) == FALSE);
+	value = secret_item_get_secret (items->data);
+	g_assert (value != NULL);
+	secret_value_unref (value);
+
+	g_assert (items->next != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
+	g_assert (secret_item_get_locked (items->next->data) == TRUE);
+	g_assert (secret_item_get_secret (items->next->data) == NULL);
+
+	g_assert (items->next->next == NULL);
 	g_list_free_full (items, g_object_unref);
-	g_clear_object (&result);
+}
+
+static void
+test_search_secrets_async (Test *test,
+                           gconstpointer used)
+{
+	GAsyncResult *result = NULL;
+	GHashTable *attributes;
+	GError *error = NULL;
+	SecretValue *value;
+	GList *items;
+
+	attributes = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (attributes, "number", "1");
+
+	secret_service_search (test->service, attributes,
+	                       SECRET_SEARCH_ALL | SECRET_SEARCH_LOAD_SECRETS, NULL,
+	                       on_complete_get_result, &result);
+	g_hash_table_unref (attributes);
+	g_assert (result == NULL);
 
-	secret_service_search (test->service, attributes, NULL,
-	                        on_complete_get_result, &result);
 	egg_test_wait ();
+
 	g_assert (G_IS_ASYNC_RESULT (result));
-	ret = secret_service_search_finish (test->service, result,
-	                                     NULL, NULL, &error);
+	items = secret_service_search_finish (test->service, result, &error);
 	g_assert_no_error (error);
-	g_assert (ret == TRUE);
-	g_clear_object (&result);
+	g_object_unref (result);
 
-	g_hash_table_unref (attributes);
+	g_assert (items != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1");
+	g_assert (secret_item_get_locked (items->data) == FALSE);
+	value = secret_item_get_secret (items->data);
+	g_assert (value != NULL);
+	secret_value_unref (value);
+
+	g_assert (items->next != NULL);
+	g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10");
+	g_assert (secret_item_get_locked (items->next->data) == TRUE);
+	g_assert (secret_item_get_secret (items->next->data) == NULL);
+
+	g_assert (items->next->next == NULL);
+	g_list_free_full (items, g_object_unref);
 }
 
 static void
@@ -826,7 +953,12 @@ main (int argc, char **argv)
 
 	g_test_add ("/service/search-sync", Test, "mock-service-normal.py", setup, test_search_sync, teardown);
 	g_test_add ("/service/search-async", Test, "mock-service-normal.py", setup, test_search_async, teardown);
-	g_test_add ("/service/search-nulls", Test, "mock-service-normal.py", setup, test_search_nulls, teardown);
+	g_test_add ("/service/search-all-sync", Test, "mock-service-normal.py", setup, test_search_all_sync, teardown);
+	g_test_add ("/service/search-all-async", Test, "mock-service-normal.py", setup, test_search_all_async, teardown);
+	g_test_add ("/service/search-unlock-sync", Test, "mock-service-normal.py", setup, test_search_unlock_sync, teardown);
+	g_test_add ("/service/search-unlock-async", Test, "mock-service-normal.py", setup, test_search_unlock_async, teardown);
+	g_test_add ("/service/search-secrets-sync", Test, "mock-service-normal.py", setup, test_search_secrets_sync, teardown);
+	g_test_add ("/service/search-secrets-async", Test, "mock-service-normal.py", setup, test_search_secrets_async, teardown);
 
 	g_test_add ("/service/lock-sync", Test, "mock-service-lock.py", setup, test_lock_sync, teardown);
 



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