diff --git a/docs/reference/libsecret/libsecret-docs.sgml b/docs/reference/libsecret/libsecret-docs.sgml index 3ec04c1..c7b168a 100644 --- a/docs/reference/libsecret/libsecret-docs.sgml +++ b/docs/reference/libsecret/libsecret-docs.sgml @@ -30,6 +30,7 @@ + diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt index 1168fea..1a53da5 100644 --- a/docs/reference/libsecret/libsecret-sections.txt +++ b/docs/reference/libsecret/libsecret-sections.txt @@ -186,30 +186,15 @@ secret_service_ensure_collections_sync secret_service_search secret_service_search_finish secret_service_search_sync -secret_service_search_for_paths -secret_service_search_for_paths_finish -secret_service_search_for_paths_sync secret_service_get_secrets secret_service_get_secrets_finish secret_service_get_secrets_sync -secret_service_get_secrets_for_paths -secret_service_get_secrets_for_paths_finish -secret_service_get_secrets_for_paths_sync -secret_service_get_secret_for_path -secret_service_get_secret_for_path_finish -secret_service_get_secret_for_path_sync secret_service_lock secret_service_lock_finish secret_service_lock_sync -secret_service_lock_paths -secret_service_lock_paths_finish -secret_service_lock_paths_sync secret_service_unlock secret_service_unlock_finish secret_service_unlock_sync -secret_service_unlock_paths -secret_service_unlock_paths_finish -secret_service_unlock_paths_sync secret_service_store secret_service_store_finish secret_service_store_sync @@ -222,6 +207,43 @@ secret_service_remove_sync secret_service_prompt secret_service_prompt_finish secret_service_prompt_sync +secret_service_read_alias +secret_service_read_alias_finish +secret_service_read_alias_sync +secret_service_set_alias +secret_service_set_alias_finish +secret_service_set_alias_sync + +SECRET_IS_SERVICE +SECRET_IS_SERVICE_CLASS +SECRET_SERVICE +SECRET_SERVICE_CLASS +SECRET_SERVICE_GET_CLASS +SECRET_TYPE_SERVICE +SECRET_TYPE_SERVICE_FLAGS +SecretServicePrivate +secret_service_flags_get_type +secret_service_get_type + + +
+secret-paths +secret/secret-unstable.h +secret_service_search_for_paths +secret_service_search_for_paths_finish +secret_service_search_for_paths_sync +secret_service_get_secrets_for_paths +secret_service_get_secrets_for_paths_finish +secret_service_get_secrets_for_paths_sync +secret_service_get_secret_for_path +secret_service_get_secret_for_path_finish +secret_service_get_secret_for_path_sync +secret_service_lock_paths +secret_service_lock_paths_finish +secret_service_lock_paths_sync +secret_service_unlock_paths +secret_service_unlock_paths_finish +secret_service_unlock_paths_sync secret_service_prompt_path secret_service_prompt_path_finish secret_service_prompt_path_sync @@ -234,29 +256,12 @@ secret_service_create_item_path_sync secret_service_delete_path secret_service_delete_path_finish secret_service_delete_path_sync -secret_service_read_alias -secret_service_read_alias_finish -secret_service_read_alias_sync secret_service_read_alias_path secret_service_read_alias_path_finish secret_service_read_alias_path_sync -secret_service_set_alias -secret_service_set_alias_finish -secret_service_set_alias_sync secret_service_set_alias_path secret_service_set_alias_path_finish secret_service_set_alias_path_sync - -SECRET_IS_SERVICE -SECRET_IS_SERVICE_CLASS -SECRET_SERVICE -SECRET_SERVICE_CLASS -SECRET_SERVICE_GET_CLASS -SECRET_TYPE_SERVICE -SECRET_TYPE_SERVICE_FLAGS -SecretServicePrivate -secret_service_flags_get_type -secret_service_get_type
diff --git a/library/Makefile.am b/library/Makefile.am index 752dd01..c45c10f 100644 --- a/library/Makefile.am +++ b/library/Makefile.am @@ -26,6 +26,7 @@ HEADER_FILES = \ secret-collection.h \ secret-item.h \ secret-password.h \ + secret-paths.h \ secret-prompt.h \ secret-schema.h \ secret-schemas.h \ @@ -51,6 +52,7 @@ PUBLIC_FILES = \ secret-item.h secret-item.c \ secret-methods.c \ secret-password.h secret-password.c \ + secret-paths.h secret-paths.c \ secret-prompt.h secret-prompt.c \ secret-schema.h secret-schema.c \ secret-schemas.h secret-schemas.c \ diff --git a/library/secret-collection.c b/library/secret-collection.c index 56992b5..95e8b22 100644 --- a/library/secret-collection.c +++ b/library/secret-collection.c @@ -17,6 +17,7 @@ #include "secret-collection.h" #include "secret-dbus-generated.h" #include "secret-item.h" +#include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "secret-types.h" diff --git a/library/secret-item.c b/library/secret-item.c index ce53955..81f5a2e 100644 --- a/library/secret-item.c +++ b/library/secret-item.c @@ -18,6 +18,7 @@ #include "secret-dbus-generated.h" #include "secret-enum-types.h" #include "secret-item.h" +#include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "secret-types.h" diff --git a/library/secret-methods.c b/library/secret-methods.c index 6842384..91405c4 100644 --- a/library/secret-methods.c +++ b/library/secret-methods.c @@ -18,213 +18,12 @@ #include "secret-collection.h" #include "secret-dbus-generated.h" #include "secret-item.h" +#include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "secret-types.h" #include "secret-value.h" -static void -on_search_items_complete (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GError *error = NULL; - GVariant *response; - - response = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); - if (error != NULL) - g_simple_async_result_take_error (res, error); - else - g_simple_async_result_set_op_res_gpointer (res, response, - (GDestroyNotify)g_variant_unref); - - g_simple_async_result_complete (res); - g_object_unref (res); -} - -/** - * secret_service_search_for_paths: - * @self: the secret service - * @attributes: (element-type utf8 utf8): search for items matching these attributes - * @cancellable: optional cancellation object - * @callback: called when the operation completes - * @user_data: data to pass to the callback - * - * Search for items matching the @attributes, and return their D-Bus object paths. - * All collections are searched. The @attributes should be a table of string keys - * and string values. - * - * This function returns immediately and completes asynchronously. - * - * When your callback is called use secret_service_search_for_paths_finish() - * to get the results of this function. Only the D-Bus object paths of the - * items will be returned. If you would like #SecretItem objects to be returned - * instead, then use the secret_service_search() function. - */ -void -secret_service_search_for_paths (SecretService *self, - GHashTable *attributes, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (attributes != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - _secret_service_search_for_paths_variant (self, _secret_attributes_to_variant (attributes, NULL), - cancellable, callback, user_data); -} - -void -_secret_service_search_for_paths_variant (SecretService *self, - GVariant *attributes, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (attributes != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, - secret_service_search_for_paths); - - g_dbus_proxy_call (G_DBUS_PROXY (self), "SearchItems", - g_variant_new ("(@a{ss})", attributes), - G_DBUS_CALL_FLAGS_NONE, -1, cancellable, - on_search_items_complete, g_object_ref (res)); - - g_object_unref (res); -} - -/** - * secret_service_search_for_paths_finish: - * @self: the secret service - * @result: asynchronous result passed to callback - * @unlocked: (out) (transfer full) (array zero-terminated=1) (allow-none): - * location to place an array of D-Bus object paths for matching - * items which were locked. - * @locked: (out) (transfer full) (array zero-terminated=1) (allow-none): - * location to place an array of D-Bus object paths for matching - * items which were locked. - * @error: location to place error on failure - * - * Complete asynchronous operation to search for items, and return their - * D-Bus object paths. - * - * Matching items that are locked or unlocked, have their D-Bus paths placed - * in the @locked or @unlocked arrays respectively. - * - * D-Bus object paths of the items will be returned in the @unlocked or - * @locked arrays. If you would to have #SecretItem objects to be returned - * instead, then us the secret_service_search() and - * secret_service_search_finish() functions. - * - * Returns: whether the search was successful or not - */ -gboolean -secret_service_search_for_paths_finish (SecretService *self, - GAsyncResult *result, - gchar ***unlocked, - gchar ***locked, - GError **error) -{ - GVariant *response; - GSimpleAsyncResult *res; - gchar **dummy = NULL; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), - secret_service_search_for_paths), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - res = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (res, error)) - return FALSE; - - if (unlocked || locked) { - if (!unlocked) - unlocked = &dummy; - else if (!locked) - locked = &dummy; - response = g_simple_async_result_get_op_res_gpointer (res); - g_variant_get (response, "(^ao^ao)", unlocked, locked); - } - - g_strfreev (dummy); - return TRUE; -} - -/** - * secret_service_search_for_paths_sync: - * @self: the secret service - * @attributes: (element-type utf8 utf8): search for items matching these attributes - * @cancellable: optional cancellation object - * @unlocked: (out) (transfer full) (array zero-terminated=1) (allow-none): - * location to place an array of D-Bus object paths for matching - * items which were locked. - * @locked: (out) (transfer full) (array zero-terminated=1) (allow-none): - * location to place an array of D-Bus object paths for matching - * items which were locked. - * @error: location to place error on failure - * - * Search for items matching the @attributes, and return their D-Bus object - * paths. 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. - * - * Matching items that are locked or unlocked, have their D-Bus paths placed - * in the @locked or @unlocked arrays respectively. - * - * D-Bus object paths of the items will be returned in the @unlocked or - * @locked arrays. If you would to have #SecretItem objects to be returned - * instead, then use the secret_service_search_sync() function. - * - * Returns: whether the search was successful or not - */ -gboolean -secret_service_search_for_paths_sync (SecretService *self, - GHashTable *attributes, - GCancellable *cancellable, - gchar ***unlocked, - gchar ***locked, - GError **error) -{ - gchar **dummy = NULL; - GVariant *response; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); - g_return_val_if_fail (attributes != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - response = g_dbus_proxy_call_sync (G_DBUS_PROXY (self), "SearchItems", - g_variant_new ("(@a{ss})", - _secret_attributes_to_variant (attributes, NULL)), - G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error); - - if (response != NULL) { - if (unlocked || locked) { - if (!unlocked) - unlocked = &dummy; - else if (!locked) - locked = &dummy; - g_variant_get (response, "(^ao^ao)", unlocked, locked); - } - - g_variant_unref (response); - } - - g_strfreev (dummy); - - return response != NULL; -} - typedef struct { GCancellable *cancellable; GHashTable *items; @@ -584,54 +383,10 @@ on_get_secrets_session (GObject *source, g_object_unref (res); } -/** - * secret_service_get_secret_for_path: - * @self: the secret service - * @item_path: the D-Bus path to item to retrieve secret for - * @cancellable: optional cancellation object - * @callback: called when the operation completes - * @user_data: data to pass to the callback - * - * Get the secret value for an secret item stored in the service. - * - * The item is represented by its D-Bus object path. If you already have a - * #SecretItem proxy object, use use secret_item_get_secret() to more simply - * get its secret value. - * - * This function returns immediately and completes asynchronously. - */ -void -secret_service_get_secret_for_path (SecretService *self, - const gchar *item_path, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - GetClosure *closure; - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (item_path != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, - secret_service_get_secret_for_path); - - closure = g_slice_new0 (GetClosure); - closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - closure->in = g_variant_ref_sink (g_variant_new_objv (&item_path, 1)); - g_simple_async_result_set_op_res_gpointer (res, closure, get_closure_free); - - secret_service_ensure_session (self, cancellable, - on_get_secrets_session, - g_object_ref (res)); - - g_object_unref (res); -} - -static SecretValue * -service_decode_get_secrets_first (SecretService *self, - GVariant *out) +SecretValue * +_secret_service_decode_get_secrets_first (SecretService *self, + GVariant *out) { SecretSession *session; SecretValue *value = NULL; @@ -650,9 +405,9 @@ service_decode_get_secrets_first (SecretService *self, return value; } -static GHashTable * -service_decode_get_secrets_all (SecretService *self, - GVariant *out) +GHashTable * +_secret_service_decode_get_secrets_all (SecretService *self, + GVariant *out) { SecretSession *session; GVariantIter *iter; @@ -674,223 +429,6 @@ service_decode_get_secrets_all (SecretService *self, return values; } -/** - * secret_service_get_secret_for_path_finish: - * @self: the secret service - * @result: asynchronous result passed to callback - * @error: location to place an error on failure - * - * Complete asynchronous operation to get the secret value for an - * secret item stored in the service. - * - * Will return %NULL if the item is locked. - * - * Returns: (transfer full) (allow-none): the newly allocated secret value - * for the item, which should be released with secret_value_unref() - */ -SecretValue * -secret_service_get_secret_for_path_finish (SecretService *self, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *res; - GetClosure *closure; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), - secret_service_get_secret_for_path), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - res = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (res, error)) - return NULL; - - closure = g_simple_async_result_get_op_res_gpointer (res); - return service_decode_get_secrets_first (self, closure->out); -} - -/** - * secret_service_get_secret_for_path_sync: - * @self: the secret service - * @item_path: the D-Bus path to item to retrieve secret for - * @cancellable: optional cancellation object - * @error: location to place an error on failure - * - * Get the secret value for an secret item stored in the service. - * - * The item is represented by its D-Bus object path. If you already have a - * #SecretItem proxy object, use use secret_item_get_secret_sync() to more simply - * get its secret value. - * - * This method may block indefinitely and should not be used in user interface - * threads. - * - * Will return %NULL if the item is locked. - * - * Returns: (transfer full) (allow-none): the newly allocated secret value - * for the item, which should be released with secret_value_unref() - */ -SecretValue * -secret_service_get_secret_for_path_sync (SecretService *self, - const gchar *item_path, - GCancellable *cancellable, - GError **error) -{ - SecretSync *sync; - SecretValue *value; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); - g_return_val_if_fail (item_path != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - sync = _secret_sync_new (); - g_main_context_push_thread_default (sync->context); - - secret_service_get_secret_for_path (self, item_path, cancellable, - _secret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - value = secret_service_get_secret_for_path_finish (self, sync->result, error); - - g_main_context_pop_thread_default (sync->context); - _secret_sync_free (sync); - - return value; -} - -/** - * secret_service_get_secrets_for_paths: - * @self: the secret service - * @item_paths: the D-Bus paths to items to retrieve secrets for - * @cancellable: optional cancellation object - * @callback: called when the operation completes - * @user_data: data to pass to the callback - * - * Get the secret values for an secret items stored in the service. - * - * The items are represented by their D-Bus object paths. If you already have - * #SecretItem proxy objects, use use secret_service_get_secrets() to more simply - * get their secret values. - * - * This function returns immediately and completes asynchronously. - */ -void -secret_service_get_secrets_for_paths (SecretService *self, - const gchar **item_paths, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - GetClosure *closure; - - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (item_paths != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, - secret_service_get_secret_for_path); - - closure = g_slice_new0 (GetClosure); - closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - closure->in = g_variant_ref_sink (g_variant_new_objv (item_paths, -1)); - g_simple_async_result_set_op_res_gpointer (res, closure, get_closure_free); - - secret_service_ensure_session (self, cancellable, - on_get_secrets_session, - g_object_ref (res)); - - g_object_unref (res); -} - -/** - * secret_service_get_secrets_for_paths_finish: - * @self: the secret service - * @result: asynchronous result passed to callback - * @error: location to place an error on failure - * - * Complete asynchronous operation to get the secret values for an - * secret items stored in the service. - * - * Items that are locked will not be included the results. - * - * Returns: (transfer full): a newly allocated hash table of item_path keys to - * #SecretValue values. - */ -GHashTable * -secret_service_get_secrets_for_paths_finish (SecretService *self, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *res; - GetClosure *closure; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), - secret_service_get_secret_for_path), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - res = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (res, error)) - return NULL; - - closure = g_simple_async_result_get_op_res_gpointer (res); - return service_decode_get_secrets_all (self, closure->out); -} - -/** - * secret_service_get_secrets_for_paths_sync: - * @self: the secret service - * @item_paths: the D-Bus paths to items to retrieve secrets for - * @cancellable: optional cancellation object - * @error: location to place an error on failure - * - * Get the secret values for an secret items stored in the service. - * - * The items are represented by their D-Bus object paths. If you already have - * #SecretItem proxy objects, use use secret_service_get_secrets_sync() to more - * simply get their secret values. - * - * This method may block indefinitely and should not be used in user interface - * threads. - * - * Items that are locked will not be included the results. - * - * Returns: (transfer full): a newly allocated hash table of item_path keys to - * #SecretValue values. - */ -GHashTable * -secret_service_get_secrets_for_paths_sync (SecretService *self, - const gchar **item_paths, - GCancellable *cancellable, - GError **error) -{ - SecretSync *sync; - GHashTable *secrets; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); - g_return_val_if_fail (item_paths != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - sync = _secret_sync_new (); - g_main_context_push_thread_default (sync->context); - - secret_service_get_secrets_for_paths (self, item_paths, cancellable, - _secret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - secrets = secret_service_get_secrets_for_paths_finish (self, sync->result, error); - - g_main_context_pop_thread_default (sync->context); - _secret_sync_free (sync); - - return secrets; -} - /** * secret_service_get_secrets: * @self: the secret service @@ -988,7 +526,7 @@ secret_service_get_secrets_finish (SecretService *self, return NULL; closure = g_simple_async_result_get_op_res_gpointer (res); - with_paths = service_decode_get_secrets_all (self, closure->out); + with_paths = _secret_service_decode_get_secrets_all (self, closure->out); g_return_val_if_fail (with_paths != NULL, NULL); with_items = g_hash_table_new_full (g_direct_hash, g_direct_equal, @@ -1381,262 +919,6 @@ secret_service_lock_sync (SecretService *self, return count; } -/** - * secret_service_lock_paths_sync: - * @self: the secret service - * @paths: the D-Bus object paths of the items or collections to lock - * @cancellable: optional cancellation object - * @locked: (out) (array zero-terminated=1) (transfer full) (allow-none): - * location to place array of D-Bus paths of items or collections - * that were locked - * @error: location to place an error on failure - * - * Lock items or collections in the secret service. - * - * The items or collections are represented by their D-Bus object paths. If you - * already have #SecretItem and #SecretCollection proxy objects, use use - * secret_service_lock_sync() instead. - * - * The secret service may not be able to lock items individually, and may - * lock an entire collection instead. - * - * This method may block indefinitely and should not be used in user - * interface threads. The secret service may prompt the user. - * secret_service_prompt() will be used to handle any prompts that show up. - * - * Returns: the number of items or collections that were locked - */ -gint -secret_service_lock_paths_sync (SecretService *self, - const gchar **paths, - GCancellable *cancellable, - gchar ***locked, - GError **error) -{ - SecretSync *sync; - gint count; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); - g_return_val_if_fail (paths != NULL, -1); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); - - sync = _secret_sync_new (); - g_main_context_push_thread_default (sync->context); - - secret_service_lock_paths (self, paths, cancellable, - _secret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - count = secret_service_lock_paths_finish (self, sync->result, - locked, error); - - g_main_context_pop_thread_default (sync->context); - _secret_sync_free (sync); - - return count; -} - -/** - * secret_service_lock_paths: - * @self: the secret service - * @paths: the D-Bus paths for items or collections to lock - * @cancellable: optional cancellation object - * @callback: called when the operation completes - * @user_data: data to pass to the callback - * - * Lock items or collections in the secret service. - * - * The items or collections are represented by their D-Bus object paths. If you - * already have #SecretItem and #SecretCollection proxy objects, use use - * secret_service_lock() instead. - * - * The secret service may not be able to lock items individually, and may - * lock an entire collection instead. - * - * This method returns immediately and completes asynchronously. The secret - * service may prompt the user. secret_service_prompt() will be used to handle - * any prompts that show up. - */ -void -secret_service_lock_paths (SecretService *self, - const gchar **paths, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (paths != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - res = service_xlock_paths_async (self, "Lock", paths, cancellable, - callback, user_data); - - g_object_unref (res); -} - -/** - * secret_service_lock_paths_finish: - * @self: the secret service - * @result: asynchronous result passed to the callback - * @locked: (out) (array zero-terminated=1) (transfer full) (allow-none): - * location to place array of D-Bus paths of items or collections - * that were locked - * @error: location to place an error on failure - * - * Complete asynchronous operation to lock items or collections in the secret - * service. - * - * The secret service may not be able to lock items individually, and may - * lock an entire collection instead. - * - * Returns: the number of items or collections that were locked - */ -gint -secret_service_lock_paths_finish (SecretService *self, - GAsyncResult *result, - gchar ***locked, - GError **error) -{ - g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); - g_return_val_if_fail (locked != NULL, -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); - - return service_xlock_paths_finish (self, result, locked, error); -} - -/** - * secret_service_unlock_paths_sync: - * @self: the secret service - * @paths: the D-Bus object paths of the items or collections to unlock - * @cancellable: optional cancellation object - * @unlocked: (out) (array zero-terminated=1) (transfer full) (allow-none): - * location to place array of D-Bus paths of items or collections - * that were unlocked - * @error: location to place an error on failure - * - * Unlock items or collections in the secret service. - * - * The items or collections are represented by their D-Bus object paths. If you - * already have #SecretItem and #SecretCollection proxy objects, use use - * secret_service_unlock_sync() instead. - * - * The secret service may not be able to unlock items individually, and may - * unlock an entire collection instead. - * - * This method may block indefinitely and should not be used in user - * interface threads. The secret service may prompt the user. - * secret_service_prompt() will be used to handle any prompts that show up. - * - * Returns: the number of items or collections that were unlocked - */ -gint -secret_service_unlock_paths_sync (SecretService *self, - const gchar **paths, - GCancellable *cancellable, - gchar ***unlocked, - GError **error) -{ - SecretSync *sync; - gint count; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); - g_return_val_if_fail (paths != NULL, -1); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); - g_return_val_if_fail (unlocked != NULL, -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); - - sync = _secret_sync_new (); - g_main_context_push_thread_default (sync->context); - - secret_service_unlock_paths (self, paths, cancellable, - _secret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - count = secret_service_unlock_paths_finish (self, sync->result, - unlocked, error); - - g_main_context_pop_thread_default (sync->context); - _secret_sync_free (sync); - - return count; -} - -/** - * secret_service_unlock_paths: - * @self: the secret service - * @paths: the D-Bus paths for items or collections to unlock - * @cancellable: optional cancellation object - * @callback: called when the operation completes - * @user_data: data to pass to the callback - * - * Unlock items or collections in the secret service. - * - * The items or collections are represented by their D-Bus object paths. If you - * already have #SecretItem and #SecretCollection proxy objects, use use - * secret_service_unlock() instead. - * - * The secret service may not be able to unlock items individually, and may - * unlock an entire collection instead. - * - * This method returns immediately and completes asynchronously. The secret - * service may prompt the user. secret_service_prompt() will be used to handle - * any prompts that show up. - */ -void -secret_service_unlock_paths (SecretService *self, - const gchar **paths, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (paths != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - res = service_xlock_paths_async (self, "Unlock", - paths, cancellable, - callback, user_data); - - g_object_unref (res); -} - -/** - * secret_service_unlock_paths_finish: - * @self: the secret service - * @result: asynchronous result passed to the callback - * @unlocked: (out) (array zero-terminated=1) (transfer full) (allow-none): - * location to place array of D-Bus paths of items or collections - * that were unlocked - * @error: location to place an error on failure - * - * Complete asynchronous operation to unlock items or collections in the secret - * service. - * - * The secret service may not be able to unlock items individually, and may - * unlock an entire collection instead. - * - * Returns: the number of items or collections that were unlocked - */ -gint -secret_service_unlock_paths_finish (SecretService *self, - GAsyncResult *result, - gchar ***unlocked, - GError **error) -{ - g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); - - return service_xlock_paths_finish (self, result, - unlocked, error); -} - /** * secret_service_unlock: * @self: the secret service @@ -2179,208 +1461,6 @@ delete_closure_free (gpointer data) g_slice_free (DeleteClosure, closure); } -static void -on_delete_prompted (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - GError *error = NULL; - GVariant *retval; - - retval = secret_service_prompt_finish (SECRET_SERVICE (source), result, - NULL, &error); - - if (error == NULL) - closure->deleted = TRUE; - else - g_simple_async_result_take_error (res, error); - if (retval != NULL) - g_variant_unref (retval); - g_simple_async_result_complete (res); - g_object_unref (res); -} - -static void -on_delete_complete (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data)); - const gchar *prompt_path; - GError *error = NULL; - GVariant *retval; - - retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); - if (error == NULL) { - g_variant_get (retval, "(&o)", &prompt_path); - - if (_secret_util_empty_path (prompt_path)) { - closure->deleted = TRUE; - g_simple_async_result_complete (res); - - } else { - closure->prompt = _secret_prompt_instance (self, prompt_path); - - secret_service_prompt (self, closure->prompt, - closure->cancellable, - on_delete_prompted, - g_object_ref (res)); - } - - g_variant_unref (retval); - - } else { - g_simple_async_result_take_error (res, error); - g_simple_async_result_complete (res); - } - - g_object_unref (self); - g_object_unref (res); -} - -void -_secret_service_delete_path (SecretService *self, - const gchar *object_path, - gboolean is_an_item, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - DeleteClosure *closure; - - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (object_path != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, - _secret_service_delete_path); - closure = g_slice_new0 (DeleteClosure); - closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free); - - g_dbus_connection_call (g_dbus_proxy_get_connection (G_DBUS_PROXY (self)), - g_dbus_proxy_get_name (G_DBUS_PROXY (self)), object_path, - is_an_item ? SECRET_ITEM_INTERFACE : SECRET_COLLECTION_INTERFACE, - "Delete", g_variant_new ("()"), G_VARIANT_TYPE ("(o)"), - G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, - cancellable, on_delete_complete, g_object_ref (res)); - - g_object_unref (res); -} - -/** - * secret_service_delete_path: - * @self: the secret service - * @item_path: the D-Bus path of item to delete - * @cancellable: optional cancellation object - * @callback: called when the operation completes - * @user_data: data to be passed to the callback - * - * Delete a secret item from the secret service. - * - * The item is represented by its D-Bus object path. If you already have a - * #SecretItem proxy objects, use use secret_item_delete() instead. - * - * This method will return immediately and complete asynchronously. - */ -void -secret_service_delete_path (SecretService *self, - const gchar *item_path, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (item_path != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - _secret_service_delete_path (self, item_path, TRUE, cancellable, callback, user_data); -} - -/** - * secret_service_delete_path_finish: - * @self: the secret service - * @result: the asynchronous result passed to the callback - * @error: location to place an error on failure - * - * Complete an asynchronous operation to delete a secret item from the secret - * service. - * - * Returns: whether the deletion was successful or not - */ -gboolean -secret_service_delete_path_finish (SecretService *self, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *res; - DeleteClosure *closure; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), - _secret_service_delete_path), FALSE); - - res = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (res, error)) - return FALSE; - - closure = g_simple_async_result_get_op_res_gpointer (res); - return closure->deleted; -} - -/** - * secret_service_delete_path_sync: - * @self: the secret service - * @item_path: the D-Bus path of item to delete - * @cancellable: optional cancellation object - * @error: location to place an error on failure - * - * Delete a secret item from the secret service. - * - * The item is represented by its D-Bus object path. If you already have a - * #SecretItem proxy objects, use use secret_item_delete_sync() instead. - * - * This method may block indefinitely and should not be used in user interface - * threads. - * - * Returns: whether the deletion was successful or not - */ -gboolean -secret_service_delete_path_sync (SecretService *self, - const gchar *item_path, - GCancellable *cancellable, - GError **error) -{ - SecretSync *sync; - gboolean result; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); - g_return_val_if_fail (item_path != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - sync = _secret_sync_new (); - g_main_context_push_thread_default (sync->context); - - secret_service_delete_path (self, item_path, cancellable, - _secret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - result = secret_service_delete_path_finish (self, sync->result, error); - - g_main_context_pop_thread_default (sync->context); - _secret_sync_free (sync); - - return result; -} - static void on_delete_password_complete (GObject *source, GAsyncResult *result, @@ -2586,564 +1666,6 @@ secret_service_remove_sync (SecretService *self, return result; } -typedef struct { - GCancellable *cancellable; - SecretPrompt *prompt; - gchar *collection_path; -} CollectionClosure; - -static void -collection_closure_free (gpointer data) -{ - CollectionClosure *closure = data; - g_clear_object (&closure->cancellable); - g_clear_object (&closure->prompt); - g_slice_free (CollectionClosure, closure); -} - -static void -on_create_collection_prompt (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - CollectionClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - GError *error = NULL; - GVariant *value; - - value = secret_service_prompt_finish (SECRET_SERVICE (source), result, - G_VARIANT_TYPE ("o"), &error); - if (error != NULL) - g_simple_async_result_take_error (res, error); - if (value != NULL) { - closure->collection_path = g_variant_dup_string (value, NULL); - g_variant_unref (value); - } - - g_simple_async_result_complete (res); - g_object_unref (res); -} - -static void -on_create_collection_called (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - CollectionClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data)); - const gchar *prompt_path = NULL; - const gchar *collection_path = NULL; - GError *error = NULL; - GVariant *retval; - - retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); - if (error == NULL) { - g_variant_get (retval, "(&o&o)", &collection_path, &prompt_path); - if (!_secret_util_empty_path (prompt_path)) { - closure->prompt = _secret_prompt_instance (self, prompt_path); - secret_service_prompt (self, closure->prompt, - closure->cancellable, on_create_collection_prompt, - g_object_ref (res)); - - } else { - closure->collection_path = g_strdup (collection_path); - g_simple_async_result_complete (res); - } - - g_variant_unref (retval); - - } else { - g_simple_async_result_take_error (res, error); - g_simple_async_result_complete (res); - } - - g_object_unref (self); - g_object_unref (res); -} - -/** - * secret_service_create_collection_path: - * @self: a secret service object - * @properties: (element-type utf8 GLib.Variant): hash table of properties for - * the new collection - * @alias: (allow-none): an alias to check for before creating the new - * collection, or to assign to the new collection - * @cancellable: optional cancellation object - * @callback: called when the operation completes - * @user_data: data to be passed to the callback - * - * Create a new collection in the secret service, and return its path. - * - * Using this method requires that you setup a correct hash table of D-Bus - * properties for the new collection. You may prefer to use - * secret_collection_create() which does handles this for you. - * - * An @alias is a well-known tag for a collection, such as 'default' (ie: the - * default collection to store items in). This allows other applications to - * easily identify and share a collection. If a collection with the @alias - * already exists, then instead of creating a new collection, the existing - * collection will be returned. If no collection with this alias exists, then a - * new collection will be created and this alias will be assigned to it. - * - * @properties is a set of properties for the new collection. The keys in the - * hash table should be interface.property strings like - * org.freedesktop.Secret.Collection.Label. The values - * in the hash table should be #GVariant values of the properties. - * - * If you wish to have a - * - * This method will return immediately and complete asynchronously. The secret - * service may prompt the user. secret_service_prompt() will be used to handle - * any prompts that are required. - */ -void -secret_service_create_collection_path (SecretService *self, - GHashTable *properties, - const gchar *alias, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - CollectionClosure *closure; - GVariant *params; - GVariant *props; - GDBusProxy *proxy; - - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (properties != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - if (alias == NULL) - alias = ""; - - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, - secret_service_create_collection_path); - closure = g_slice_new0 (CollectionClosure); - closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - g_simple_async_result_set_op_res_gpointer (res, closure, collection_closure_free); - - props = _secret_util_variant_for_properties (properties); - params = g_variant_new ("(@a{sv}s)", props, alias); - proxy = G_DBUS_PROXY (self); - - g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), - g_dbus_proxy_get_name (proxy), - g_dbus_proxy_get_object_path (proxy), - SECRET_SERVICE_INTERFACE, - "CreateCollection", params, G_VARIANT_TYPE ("(oo)"), - G_DBUS_CALL_FLAGS_NONE, -1, - closure->cancellable, - on_create_collection_called, - g_object_ref (res)); - - g_object_unref (res); - -} - -/** - * secret_service_create_collection_path_finish: - * @self: a secret service object - * @result: the asynchronous result passed to the callback - * @error: location to place an error on failure - * - * Finish asynchronous operation to create a new collection in the secret - * service. - * - * Returns: (transfer full): a new string containing the D-Bus object path - * of the collection - */ -gchar * -secret_service_create_collection_path_finish (SecretService *self, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *res; - CollectionClosure *closure; - gchar *path; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), - secret_service_create_collection_path), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - res = G_SIMPLE_ASYNC_RESULT (result); - - if (g_simple_async_result_propagate_error (res, error)) - return NULL; - - closure = g_simple_async_result_get_op_res_gpointer (res); - path = closure->collection_path; - closure->collection_path = NULL; - return path; -} - -/** - * secret_service_create_collection_path_sync: - * @self: a secret service object - * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties - * for the new collection - * @alias: (allow-none): an alias to check for before creating the new - * collection, or to assign to the new collection - * @cancellable: optional cancellation object - * @error: location to place an error on failure - * - * Create a new collection in the secret service and return its path. - * - * Using this method requires that you setup a correct hash table of D-Bus - * properties for the new collection. You may prefer to use - * secret_collection_create() which does handles this for you. - * - * An @alias is a well-known tag for a collection, such as 'default' (ie: the - * default collection to store items in). This allows other applications to - * easily identify and share a collection. If a collection with the @alias - * already exists, then instead of creating a new collection, the existing - * collection will be returned. If no collection with this alias exists, then - * a new collection will be created and this alias will be assigned to it. - * - * @properties is a set of properties for the new collection. The keys in the - * hash table should be interface.property strings like - * org.freedesktop.Secret.Collection.Label. The values - * in the hash table should be #GVariant values of the properties. - * - * This method may block indefinitely and should not be used in user interface - * threads. The secret service may prompt the user. secret_service_prompt() - * will be used to handle any prompts that are required. - * - * Returns: (transfer full): a new string containing the D-Bus object path - * of the collection - */ -gchar * -secret_service_create_collection_path_sync (SecretService *self, - GHashTable *properties, - const gchar *alias, - GCancellable *cancellable, - GError **error) -{ - SecretSync *sync; - gchar *path; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); - g_return_val_if_fail (properties != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - sync = _secret_sync_new (); - g_main_context_push_thread_default (sync->context); - - secret_service_create_collection_path (self, properties, alias, cancellable, - _secret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - path = secret_service_create_collection_path_finish (self, sync->result, error); - - g_main_context_pop_thread_default (sync->context); - _secret_sync_free (sync); - - return path; -} - -typedef struct { - GCancellable *cancellable; - GVariant *properties; - SecretValue *value; - gboolean replace; - gchar *collection_path; - SecretPrompt *prompt; - gchar *item_path; -} ItemClosure; - -static void -item_closure_free (gpointer data) -{ - ItemClosure *closure = data; - g_variant_unref (closure->properties); - secret_value_unref (closure->value); - g_clear_object (&closure->cancellable); - g_free (closure->collection_path); - g_clear_object (&closure->prompt); - g_slice_free (ItemClosure, closure); -} - -static void -on_create_item_prompt (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - ItemClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - GError *error = NULL; - GVariant *value; - - value = secret_service_prompt_finish (SECRET_SERVICE (source), result, - G_VARIANT_TYPE ("o"), &error); - if (error != NULL) - g_simple_async_result_take_error (res, error); - if (value != NULL) { - closure->item_path = g_variant_dup_string (value, NULL); - g_variant_unref (value); - } - - g_simple_async_result_complete (res); - g_object_unref (res); -} - -static void -on_create_item_called (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - ItemClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data)); - const gchar *prompt_path = NULL; - const gchar *item_path = NULL; - GError *error = NULL; - GVariant *retval; - - retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); - if (error == NULL) { - g_variant_get (retval, "(&o&o)", &item_path, &prompt_path); - if (!_secret_util_empty_path (prompt_path)) { - closure->prompt = _secret_prompt_instance (self, prompt_path); - secret_service_prompt (self, closure->prompt, - closure->cancellable, on_create_item_prompt, - g_object_ref (res)); - - } else { - closure->item_path = g_strdup (item_path); - g_simple_async_result_complete (res); - } - - g_variant_unref (retval); - - } else { - g_simple_async_result_take_error (res, error); - g_simple_async_result_complete (res); - } - - g_object_unref (self); - g_object_unref (res); -} - -static void -on_create_item_session (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - ItemClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - SecretService *self = SECRET_SERVICE (source); - SecretSession *session; - GVariant *params; - GError *error = NULL; - GDBusProxy *proxy; - - secret_service_ensure_session_finish (self, result, &error); - if (error == NULL) { - session = _secret_service_get_session (self); - params = g_variant_new ("(@a{sv}@(oayays)b)", - closure->properties, - _secret_session_encode_secret (session, closure->value), - closure->replace); - - proxy = G_DBUS_PROXY (self); - g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), - g_dbus_proxy_get_name (proxy), - closure->collection_path, - SECRET_COLLECTION_INTERFACE, - "CreateItem", params, G_VARIANT_TYPE ("(oo)"), - G_DBUS_CALL_FLAGS_NONE, -1, - closure->cancellable, - on_create_item_called, - g_object_ref (res)); - } else { - g_simple_async_result_take_error (res, error); - g_simple_async_result_complete (res); - } - - g_object_unref (res); -} - -/** - * secret_service_create_item_path: - * @self: a secret service object - * @collection_path: (allow-none): the D-Bus object path of the collection in which to create item - * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties - * for the new collection - * @value: the secret value to store in the item - * @replace: whether to replace an item with the matching attributes - * @cancellable: optional cancellation object - * @callback: called when the operation completes - * @user_data: data to be passed to the callback - * - * Create a new item in a secret service collection and return its D-Bus - * object path. - * - * It is often easier to use secret_password_store() or secret_item_create() - * rather than using this function. Using this method requires that you setup - * a correct hash table of D-Bus @properties for the new collection. - * - * If @replace is set to %TRUE, and an item already in the collection matches - * the attributes (specified in @properties) then the item will be updated - * instead of creating a new item. - * - * @properties is a set of properties for the new collection. The keys in the - * hash table should be interface.property strings like - * org.freedesktop.Secret.Item.Label. The values - * in the hash table should be #GVariant values of the properties. - * - * If @collection_path is %NULL, then the default collection will be - * used. Use #SECRET_COLLECTION_SESSION to store the password in the session - * collection, which doesn't get stored across login sessions. - * - * This method will return immediately and complete asynchronously. The secret - * service may prompt the user. secret_service_prompt() will be used to handle - * any prompts that are required. - */ -void -secret_service_create_item_path (SecretService *self, - const gchar *collection_path, - GHashTable *properties, - SecretValue *value, - gboolean replace, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - ItemClosure *closure; - - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (properties != NULL); - g_return_if_fail (value != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - if (collection_path == NULL) - collection_path = SECRET_COLLECTION_DEFAULT; - - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, - secret_service_create_item_path); - closure = g_slice_new0 (ItemClosure); - closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - closure->properties = _secret_util_variant_for_properties (properties); - g_variant_ref_sink (closure->properties); - closure->replace = replace; - closure->value = secret_value_ref (value); - closure->collection_path = g_strdup (collection_path); - g_simple_async_result_set_op_res_gpointer (res, closure, item_closure_free); - - secret_service_ensure_session (self, cancellable, - on_create_item_session, - g_object_ref (res)); - - g_object_unref (res); -} - -/** - * secret_service_create_item_path_finish: - * @self: a secret service object - * @result: the asynchronous result passed to the callback - * @error: location to place an error on failure - * - * Finish asynchronous operation to create a new item in the secret - * service. - * - * Returns: (transfer full): a new string containing the D-Bus object path - * of the item - */ -gchar * -secret_service_create_item_path_finish (SecretService *self, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *res; - ItemClosure *closure; - gchar *path; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), - secret_service_create_item_path), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - res = G_SIMPLE_ASYNC_RESULT (result); - - if (g_simple_async_result_propagate_error (res, error)) - return NULL; - - closure = g_simple_async_result_get_op_res_gpointer (res); - path = closure->item_path; - closure->item_path = NULL; - return path; -} - -/** - * secret_service_create_item_path_sync: - * @self: a secret service object - * @collection_path: (allow-none): the D-Bus path of the collection in which to create item - * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties - * for the new collection - * @value: the secret value to store in the item - * @replace: whether to replace an item with the matching attributes - * @cancellable: optional cancellation object - * @error: location to place an error on failure - * - * Create a new item in a secret service collection and return its D-Bus - * object path. - * - * It is often easier to use secret_password_store_sync() or secret_item_create_sync() - * rather than using this function. Using this method requires that you setup - * a correct hash table of D-Bus @properties for the new collection. - * - * If @replace is set to %TRUE, and an item already in the collection matches - * the attributes (specified in @properties) then the item will be updated - * instead of creating a new item. - * - * @properties is a set of properties for the new collection. The keys in the - * hash table should be interface.property strings like - * org.freedesktop.Secret.Item.Label. The values - * in the hash table should be #GVariant values of the properties. - * - * This method may block indefinitely and should not be used in user interface - * threads. The secret service may prompt the user. secret_service_prompt() - * will be used to handle any prompts that are required. - * - * Returns: (transfer full): a new string containing the D-Bus object path - * of the item - */ -gchar * -secret_service_create_item_path_sync (SecretService *self, - const gchar *collection_path, - GHashTable *properties, - SecretValue *value, - gboolean replace, - GCancellable *cancellable, - GError **error) -{ - SecretSync *sync; - gchar *path; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); - g_return_val_if_fail (properties != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - sync = _secret_sync_new (); - g_main_context_push_thread_default (sync->context); - - secret_service_create_item_path (self, collection_path, properties, value, replace, - cancellable, _secret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - path = secret_service_create_item_path_finish (self, sync->result, error); - - g_main_context_pop_thread_default (sync->context); - _secret_sync_free (sync); - - return path; -} - typedef struct { GCancellable *cancellable; SecretCollection *collection; @@ -3341,117 +1863,6 @@ secret_service_read_alias_sync (SecretService *self, return collection; } -/** - * secret_service_read_alias_path: - * @self: a secret service object - * @alias: the alias to lookup - * @cancellable: (allow-none): optional cancellation object - * @callback: called when the operation completes - * @user_data: data to pass to the callback - * - * Lookup which collection is assigned to this alias. Aliases help determine - * well known collections, such as 'default'. This method looks up the - * dbus object path of the well known collection. - * - * This method will return immediately and complete asynchronously. - */ -void -secret_service_read_alias_path (SecretService *self, - const gchar *alias, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (alias != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - g_dbus_proxy_call (G_DBUS_PROXY (self), "ReadAlias", - g_variant_new ("(s)", alias), - G_DBUS_CALL_FLAGS_NONE, -1, - cancellable, callback, user_data); -} - -/** - * secret_service_read_alias_path_finish: - * @self: a secret service object - * @result: asynchronous result passed to callback - * @error: location to place error on failure - * - * Finish an asynchronous operation to lookup which collection is assigned - * to an alias. This method returns the DBus object path of the collection - * - * Returns: (transfer full): the collection dbus object path, or %NULL if - * none assigned to the alias - */ -gchar * -secret_service_read_alias_path_finish (SecretService *self, - GAsyncResult *result, - GError **error) -{ - gchar *collection_path; - GVariant *retval; - - retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, error); - if (retval == NULL) - return NULL; - - g_variant_get (retval, "(o)", &collection_path); - g_variant_unref (retval); - - if (g_str_equal (collection_path, "/")) { - g_free (collection_path); - collection_path = NULL; - } - - return collection_path; -} - -/** - * secret_service_read_alias_path_sync: - * @self: a secret service object - * @alias: the alias to lookup - * @cancellable: (allow-none): optional cancellation object - * @error: location to place error on failure - * - * Lookup which collection is assigned to this alias. Aliases help determine - * well known collections, such as 'default'. This method returns the dbus - * object path of the collection. - * - * This method may block and should not be used in user interface threads. - * - * Returns: (transfer full): the collection dbus object path, or %NULL if - * none assigned to the alias - */ -gchar * -secret_service_read_alias_path_sync (SecretService *self, - const gchar *alias, - GCancellable *cancellable, - GError **error) -{ - SecretSync *sync; - gchar *collection_path; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); - g_return_val_if_fail (alias != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - sync = _secret_sync_new (); - g_main_context_push_thread_default (sync->context); - - secret_service_read_alias_path (self, alias, cancellable, _secret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - collection_path = secret_service_read_alias_path_finish (self, sync->result, error); - - g_main_context_pop_thread_default (sync->context); - _secret_sync_free (sync); - - return collection_path; -} - /** * secret_service_set_alias: * @self: a secret service object @@ -3558,121 +1969,3 @@ secret_service_set_alias_sync (SecretService *self, return ret; } - -/** - * secret_service_set_alias_path: - * @self: a secret service object - * @alias: the alias to assign the collection to - * @collection_path: (allow-none): the dbus object path of the collection to assign to the alias - * @cancellable: (allow-none): optional cancellation object - * @callback: called when the operation completes - * @user_data: data to pass to the callback - * - * Assign a collection to this alias. Aliases help determine - * well known collections, such as 'default'. This method takes the dbus object - * path of the collection to assign to the alias. - * - * This method will return immediately and complete asynchronously. - */ -void -secret_service_set_alias_path (SecretService *self, - const gchar *alias, - const gchar *collection_path, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (alias != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - if (collection_path == NULL) - collection_path = "/"; - else - g_return_if_fail (g_variant_is_object_path (collection_path)); - - g_dbus_proxy_call (G_DBUS_PROXY (self), "SetAlias", - g_variant_new ("(so)", alias, collection_path), - G_DBUS_CALL_FLAGS_NONE, -1, cancellable, - callback, user_data); -} - -/** - * secret_service_set_alias_path_finish: - * @self: a secret service object - * @result: asynchronous result passed to callback - * @error: location to place error on failure - * - * Finish an asynchronous operation to assign a collection to an alias. - * - * Returns: %TRUE if successful - */ -gboolean -secret_service_set_alias_path_finish (SecretService *self, - GAsyncResult *result, - GError **error) -{ - GVariant *retval; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, error); - if (retval == NULL) - return FALSE; - - g_variant_unref (retval); - return TRUE; -} - -/** - * secret_service_set_alias_path_sync: - * @self: a secret service object - * @alias: the alias to assign the collection to - * @collection_path: (allow-none): the dbus object path of the collection to assign to the alias - * @cancellable: (allow-none): optional cancellation object - * @error: location to place error on failure - * - * Assign a collection to this alias. Aliases help determine - * well known collections, such as 'default'. This method takes the dbus object - * path of the collection to assign to the alias. - * - * This method may block and should not be used in user interface threads. - * - * Returns: %TRUE if successful - */ -gboolean -secret_service_set_alias_path_sync (SecretService *self, - const gchar *alias, - const gchar *collection_path, - GCancellable *cancellable, - GError **error) -{ - SecretSync *sync; - gboolean ret; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); - g_return_val_if_fail (alias != NULL, FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - if (collection_path == NULL) - collection_path = "/"; - else - g_return_val_if_fail (g_variant_is_object_path (collection_path), FALSE); - - sync = _secret_sync_new (); - g_main_context_push_thread_default (sync->context); - - secret_service_set_alias_path (self, alias, collection_path, - cancellable, _secret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - ret = secret_service_set_alias_path_finish (self, sync->result, error); - - g_main_context_pop_thread_default (sync->context); - _secret_sync_free (sync); - - return ret; -} diff --git a/library/secret-paths.c b/library/secret-paths.c new file mode 100644 index 0000000..6919d87 --- /dev/null +++ b/library/secret-paths.c @@ -0,0 +1,2054 @@ +/* libsecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * Copyright 2012 Red Hat Inc. + * + * 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 licence or (at + * your option) any later version. + * + * See the included COPYING file for more information. + * + * Author: Stef Walter + */ + +#include "config.h" + +#include "secret-dbus-generated.h" +#include "secret-paths.h" +#include "secret-private.h" +#include "secret-service.h" +#include "secret-types.h" +#include "secret-value.h" + + +/** + * SECTION:secret-paths + * @title: DBus Path Related Functions + * @short_description: Secret Service functions which operate on DBus object paths + * + * These are low level functions which operate on DBus object paths of + * collections or items, instead of the #SecretCollection or #SecretItem + * objects themselves. + * + * You can use these functions if you wish to manage access to the secret + * service using the DBus API directly, and only wish to use a few calls + * in libsecret. + * + * Stability: Unstable + */ + +static void +on_search_items_complete (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + GError *error = NULL; + GVariant *response; + + response = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + else + g_simple_async_result_set_op_res_gpointer (res, response, + (GDestroyNotify)g_variant_unref); + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +/** + * secret_service_search_for_paths: + * @self: the secret service + * @attributes: (element-type utf8 utf8): search for items matching these attributes + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to pass to the callback + * + * Search for items matching the @attributes, and return their D-Bus object paths. + * All collections are searched. The @attributes should be a table of string keys + * and string values. + * + * This function returns immediately and completes asynchronously. + * + * When your callback is called use secret_service_search_for_paths_finish() + * to get the results of this function. Only the D-Bus object paths of the + * items will be returned. If you would like #SecretItem objects to be returned + * instead, then use the secret_service_search() function. + */ +void +secret_service_search_for_paths (SecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (attributes != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + _secret_service_search_for_paths_variant (self, _secret_attributes_to_variant (attributes, NULL), + cancellable, callback, user_data); +} + +void +_secret_service_search_for_paths_variant (SecretService *self, + GVariant *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (attributes != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + secret_service_search_for_paths); + + g_dbus_proxy_call (G_DBUS_PROXY (self), "SearchItems", + g_variant_new ("(@a{ss})", attributes), + G_DBUS_CALL_FLAGS_NONE, -1, cancellable, + on_search_items_complete, g_object_ref (res)); + + g_object_unref (res); +} + +/** + * secret_service_search_for_paths_finish: + * @self: the secret service + * @result: asynchronous result passed to callback + * @unlocked: (out) (transfer full) (array zero-terminated=1) (allow-none): + * location to place an array of D-Bus object paths for matching + * items which were locked. + * @locked: (out) (transfer full) (array zero-terminated=1) (allow-none): + * location to place an array of D-Bus object paths for matching + * items which were locked. + * @error: location to place error on failure + * + * Complete asynchronous operation to search for items, and return their + * D-Bus object paths. + * + * Matching items that are locked or unlocked, have their D-Bus paths placed + * in the @locked or @unlocked arrays respectively. + * + * D-Bus object paths of the items will be returned in the @unlocked or + * @locked arrays. If you would to have #SecretItem objects to be returned + * instead, then us the secret_service_search() and + * secret_service_search_finish() functions. + * + * Returns: whether the search was successful or not + */ +gboolean +secret_service_search_for_paths_finish (SecretService *self, + GAsyncResult *result, + gchar ***unlocked, + gchar ***locked, + GError **error) +{ + GVariant *response; + GSimpleAsyncResult *res; + gchar **dummy = NULL; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + secret_service_search_for_paths), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return FALSE; + + if (unlocked || locked) { + if (!unlocked) + unlocked = &dummy; + else if (!locked) + locked = &dummy; + response = g_simple_async_result_get_op_res_gpointer (res); + g_variant_get (response, "(^ao^ao)", unlocked, locked); + } + + g_strfreev (dummy); + return TRUE; +} + +/** + * secret_service_search_for_paths_sync: + * @self: the secret service + * @attributes: (element-type utf8 utf8): search for items matching these attributes + * @cancellable: optional cancellation object + * @unlocked: (out) (transfer full) (array zero-terminated=1) (allow-none): + * location to place an array of D-Bus object paths for matching + * items which were locked. + * @locked: (out) (transfer full) (array zero-terminated=1) (allow-none): + * location to place an array of D-Bus object paths for matching + * items which were locked. + * @error: location to place error on failure + * + * Search for items matching the @attributes, and return their D-Bus object + * paths. 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. + * + * Matching items that are locked or unlocked, have their D-Bus paths placed + * in the @locked or @unlocked arrays respectively. + * + * D-Bus object paths of the items will be returned in the @unlocked or + * @locked arrays. If you would to have #SecretItem objects to be returned + * instead, then use the secret_service_search_sync() function. + * + * Returns: whether the search was successful or not + */ +gboolean +secret_service_search_for_paths_sync (SecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + gchar ***unlocked, + gchar ***locked, + GError **error) +{ + gchar **dummy = NULL; + GVariant *response; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (attributes != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + response = g_dbus_proxy_call_sync (G_DBUS_PROXY (self), "SearchItems", + g_variant_new ("(@a{ss})", + _secret_attributes_to_variant (attributes, NULL)), + G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error); + + if (response != NULL) { + if (unlocked || locked) { + if (!unlocked) + unlocked = &dummy; + else if (!locked) + locked = &dummy; + g_variant_get (response, "(^ao^ao)", unlocked, locked); + } + + g_variant_unref (response); + } + + g_strfreev (dummy); + + return response != NULL; +} + +typedef struct { + GCancellable *cancellable; + GVariant *in; + GVariant *out; + GHashTable *items; +} GetClosure; + +static void +get_closure_free (gpointer data) +{ + GetClosure *closure = data; + if (closure->in) + g_variant_unref (closure->in); + if (closure->out) + g_variant_unref (closure->out); + g_clear_object (&closure->cancellable); + g_slice_free (GetClosure, closure); +} + +static void +on_get_secrets_complete (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + GetClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GError *error = NULL; + + closure->out = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + + g_object_unref (res); +} + +static void +on_get_secrets_session (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + GetClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GError *error = NULL; + const gchar *session; + + session = secret_service_ensure_session_finish (SECRET_SERVICE (source), + result, &error); + if (error != NULL) { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + } else { + g_dbus_proxy_call (G_DBUS_PROXY (source), "GetSecrets", + g_variant_new ("(@aoo)", closure->in, session), + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, + closure->cancellable, on_get_secrets_complete, + g_object_ref (res)); + } + + g_object_unref (res); +} + +/** + * secret_service_get_secret_for_path: + * @self: the secret service + * @item_path: the D-Bus path to item to retrieve secret for + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to pass to the callback + * + * Get the secret value for an secret item stored in the service. + * + * The item is represented by its D-Bus object path. If you already have a + * #SecretItem proxy object, use use secret_item_get_secret() to more simply + * get its secret value. + * + * This function returns immediately and completes asynchronously. + */ +void +secret_service_get_secret_for_path (SecretService *self, + const gchar *item_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + GetClosure *closure; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (item_path != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + secret_service_get_secret_for_path); + + closure = g_slice_new0 (GetClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + closure->in = g_variant_ref_sink (g_variant_new_objv (&item_path, 1)); + g_simple_async_result_set_op_res_gpointer (res, closure, get_closure_free); + + secret_service_ensure_session (self, cancellable, + on_get_secrets_session, + g_object_ref (res)); + + g_object_unref (res); +} + +/** + * secret_service_get_secret_for_path_finish: + * @self: the secret service + * @result: asynchronous result passed to callback + * @error: location to place an error on failure + * + * Complete asynchronous operation to get the secret value for an + * secret item stored in the service. + * + * Will return %NULL if the item is locked. + * + * Returns: (transfer full) (allow-none): the newly allocated secret value + * for the item, which should be released with secret_value_unref() + */ +SecretValue * +secret_service_get_secret_for_path_finish (SecretService *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res; + GetClosure *closure; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + secret_service_get_secret_for_path), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return NULL; + + closure = g_simple_async_result_get_op_res_gpointer (res); + return _secret_service_decode_get_secrets_first (self, closure->out); +} + +/** + * secret_service_get_secret_for_path_sync: + * @self: the secret service + * @item_path: the D-Bus path to item to retrieve secret for + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * + * Get the secret value for an secret item stored in the service. + * + * The item is represented by its D-Bus object path. If you already have a + * #SecretItem proxy object, use use secret_item_get_secret_sync() to more simply + * get its secret value. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Will return %NULL if the item is locked. + * + * Returns: (transfer full) (allow-none): the newly allocated secret value + * for the item, which should be released with secret_value_unref() + */ +SecretValue * +secret_service_get_secret_for_path_sync (SecretService *self, + const gchar *item_path, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + SecretValue *value; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (item_path != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_service_get_secret_for_path (self, item_path, cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + value = secret_service_get_secret_for_path_finish (self, sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return value; +} + +/** + * secret_service_get_secrets_for_paths: + * @self: the secret service + * @item_paths: the D-Bus paths to items to retrieve secrets for + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to pass to the callback + * + * Get the secret values for an secret items stored in the service. + * + * The items are represented by their D-Bus object paths. If you already have + * #SecretItem proxy objects, use use secret_service_get_secrets() to more simply + * get their secret values. + * + * This function returns immediately and completes asynchronously. + */ +void +secret_service_get_secrets_for_paths (SecretService *self, + const gchar **item_paths, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + GetClosure *closure; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (item_paths != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + secret_service_get_secret_for_path); + + closure = g_slice_new0 (GetClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + closure->in = g_variant_ref_sink (g_variant_new_objv (item_paths, -1)); + g_simple_async_result_set_op_res_gpointer (res, closure, get_closure_free); + + secret_service_ensure_session (self, cancellable, + on_get_secrets_session, + g_object_ref (res)); + + g_object_unref (res); +} + +/** + * secret_service_get_secrets_for_paths_finish: + * @self: the secret service + * @result: asynchronous result passed to callback + * @error: location to place an error on failure + * + * Complete asynchronous operation to get the secret values for an + * secret items stored in the service. + * + * Items that are locked will not be included the results. + * + * Returns: (transfer full): a newly allocated hash table of item_path keys to + * #SecretValue values. + */ +GHashTable * +secret_service_get_secrets_for_paths_finish (SecretService *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res; + GetClosure *closure; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + secret_service_get_secret_for_path), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return NULL; + + closure = g_simple_async_result_get_op_res_gpointer (res); + return _secret_service_decode_get_secrets_all (self, closure->out); +} + +/** + * secret_service_get_secrets_for_paths_sync: + * @self: the secret service + * @item_paths: the D-Bus paths to items to retrieve secrets for + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * + * Get the secret values for an secret items stored in the service. + * + * The items are represented by their D-Bus object paths. If you already have + * #SecretItem proxy objects, use use secret_service_get_secrets_sync() to more + * simply get their secret values. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Items that are locked will not be included the results. + * + * Returns: (transfer full): a newly allocated hash table of item_path keys to + * #SecretValue values. + */ +GHashTable * +secret_service_get_secrets_for_paths_sync (SecretService *self, + const gchar **item_paths, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + GHashTable *secrets; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (item_paths != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_service_get_secrets_for_paths (self, item_paths, cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + secrets = secret_service_get_secrets_for_paths_finish (self, sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return secrets; +} + + +typedef struct { + GCancellable *cancellable; + SecretPrompt *prompt; + GHashTable *objects; + GPtrArray *xlocked; +} XlockClosure; + +static void +xlock_closure_free (gpointer data) +{ + XlockClosure *closure = data; + g_clear_object (&closure->cancellable); + g_clear_object (&closure->prompt); + if (closure->xlocked) + g_ptr_array_unref (closure->xlocked); + if (closure->objects) + g_hash_table_unref (closure->objects); + g_slice_free (XlockClosure, closure); +} + +static void +on_xlock_prompted (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + XlockClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + SecretService *self = SECRET_SERVICE (source); + GError *error = NULL; + GVariantIter iter; + GVariant *retval; + gchar *path; + + retval = secret_service_prompt_finish (self, result, G_VARIANT_TYPE ("ao"), &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + + if (retval != NULL) { + g_variant_iter_init (&iter, retval); + while (g_variant_iter_loop (&iter, "o", &path)) + g_ptr_array_add (closure->xlocked, g_strdup (path)); + g_variant_unref (retval); + } + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_xlock_called (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + XlockClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data)); + const gchar *prompt = NULL; + gchar **xlocked = NULL; + GError *error = NULL; + GVariant *retval; + guint i; + + retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); + if (error != NULL) { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + + } else { + g_variant_get (retval, "(^ao&o)", &xlocked, &prompt); + + if (_secret_util_empty_path (prompt)) { + for (i = 0; xlocked[i]; i++) + g_ptr_array_add (closure->xlocked, g_strdup (xlocked[i])); + g_simple_async_result_complete (res); + + } else { + closure->prompt = _secret_prompt_instance (self, prompt); + secret_service_prompt (self, closure->prompt, closure->cancellable, + on_xlock_prompted, g_object_ref (res)); + } + + g_strfreev (xlocked); + g_variant_unref (retval); + } + + g_object_unref (self); + g_object_unref (res); +} + +static GSimpleAsyncResult * +service_xlock_paths_async (SecretService *self, + const gchar *method, + const gchar **paths, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + XlockClosure *closure; + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + service_xlock_paths_async); + closure = g_slice_new0 (XlockClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable; + closure->xlocked = g_ptr_array_new_with_free_func (g_free); + g_simple_async_result_set_op_res_gpointer (res, closure, xlock_closure_free); + + g_dbus_proxy_call (G_DBUS_PROXY (self), method, + g_variant_new ("(@ao)", g_variant_new_objv (paths, -1)), + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, + cancellable, on_xlock_called, g_object_ref (res)); + + return res; +} + +static gint +service_xlock_paths_finish (SecretService *self, + GAsyncResult *result, + gchar ***xlocked, + GError **error) +{ + GSimpleAsyncResult *res; + XlockClosure *closure; + gint count; + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return -1; + + closure = g_simple_async_result_get_op_res_gpointer (res); + count = closure->xlocked->len; + + if (xlocked != NULL) { + g_ptr_array_add (closure->xlocked, NULL); + *xlocked = (gchar **)g_ptr_array_free (closure->xlocked, FALSE); + closure->xlocked = NULL; + } + + return count; +} + +/** + * secret_service_lock_paths_sync: + * @self: the secret service + * @paths: the D-Bus object paths of the items or collections to lock + * @cancellable: optional cancellation object + * @locked: (out) (array zero-terminated=1) (transfer full) (allow-none): + * location to place array of D-Bus paths of items or collections + * that were locked + * @error: location to place an error on failure + * + * Lock items or collections in the secret service. + * + * The items or collections are represented by their D-Bus object paths. If you + * already have #SecretItem and #SecretCollection proxy objects, use use + * secret_service_lock_sync() instead. + * + * The secret service may not be able to lock items individually, and may + * lock an entire collection instead. + * + * This method may block indefinitely and should not be used in user + * interface threads. The secret service may prompt the user. + * secret_service_prompt() will be used to handle any prompts that show up. + * + * Returns: the number of items or collections that were locked + */ +gint +secret_service_lock_paths_sync (SecretService *self, + const gchar **paths, + GCancellable *cancellable, + gchar ***locked, + GError **error) +{ + SecretSync *sync; + gint count; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (paths != NULL, -1); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); + g_return_val_if_fail (error == NULL || *error == NULL, -1); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_service_lock_paths (self, paths, cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + count = secret_service_lock_paths_finish (self, sync->result, + locked, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return count; +} + +/** + * secret_service_lock_paths: + * @self: the secret service + * @paths: the D-Bus paths for items or collections to lock + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to pass to the callback + * + * Lock items or collections in the secret service. + * + * The items or collections are represented by their D-Bus object paths. If you + * already have #SecretItem and #SecretCollection proxy objects, use use + * secret_service_lock() instead. + * + * The secret service may not be able to lock items individually, and may + * lock an entire collection instead. + * + * This method returns immediately and completes asynchronously. The secret + * service may prompt the user. secret_service_prompt() will be used to handle + * any prompts that show up. + */ +void +secret_service_lock_paths (SecretService *self, + const gchar **paths, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (paths != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = service_xlock_paths_async (self, "Lock", paths, cancellable, + callback, user_data); + + g_object_unref (res); +} + +/** + * secret_service_lock_paths_finish: + * @self: the secret service + * @result: asynchronous result passed to the callback + * @locked: (out) (array zero-terminated=1) (transfer full) (allow-none): + * location to place array of D-Bus paths of items or collections + * that were locked + * @error: location to place an error on failure + * + * Complete asynchronous operation to lock items or collections in the secret + * service. + * + * The secret service may not be able to lock items individually, and may + * lock an entire collection instead. + * + * Returns: the number of items or collections that were locked + */ +gint +secret_service_lock_paths_finish (SecretService *self, + GAsyncResult *result, + gchar ***locked, + GError **error) +{ + g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (locked != NULL, -1); + g_return_val_if_fail (error == NULL || *error == NULL, -1); + + return service_xlock_paths_finish (self, result, locked, error); +} + +/** + * secret_service_unlock_paths_sync: + * @self: the secret service + * @paths: the D-Bus object paths of the items or collections to unlock + * @cancellable: optional cancellation object + * @unlocked: (out) (array zero-terminated=1) (transfer full) (allow-none): + * location to place array of D-Bus paths of items or collections + * that were unlocked + * @error: location to place an error on failure + * + * Unlock items or collections in the secret service. + * + * The items or collections are represented by their D-Bus object paths. If you + * already have #SecretItem and #SecretCollection proxy objects, use use + * secret_service_unlock_sync() instead. + * + * The secret service may not be able to unlock items individually, and may + * unlock an entire collection instead. + * + * This method may block indefinitely and should not be used in user + * interface threads. The secret service may prompt the user. + * secret_service_prompt() will be used to handle any prompts that show up. + * + * Returns: the number of items or collections that were unlocked + */ +gint +secret_service_unlock_paths_sync (SecretService *self, + const gchar **paths, + GCancellable *cancellable, + gchar ***unlocked, + GError **error) +{ + SecretSync *sync; + gint count; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (paths != NULL, -1); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); + g_return_val_if_fail (unlocked != NULL, -1); + g_return_val_if_fail (error == NULL || *error == NULL, -1); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_service_unlock_paths (self, paths, cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + count = secret_service_unlock_paths_finish (self, sync->result, + unlocked, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return count; +} + +/** + * secret_service_unlock_paths: + * @self: the secret service + * @paths: the D-Bus paths for items or collections to unlock + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to pass to the callback + * + * Unlock items or collections in the secret service. + * + * The items or collections are represented by their D-Bus object paths. If you + * already have #SecretItem and #SecretCollection proxy objects, use use + * secret_service_unlock() instead. + * + * The secret service may not be able to unlock items individually, and may + * unlock an entire collection instead. + * + * This method returns immediately and completes asynchronously. The secret + * service may prompt the user. secret_service_prompt() will be used to handle + * any prompts that show up. + */ +void +secret_service_unlock_paths (SecretService *self, + const gchar **paths, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (paths != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = service_xlock_paths_async (self, "Unlock", + paths, cancellable, + callback, user_data); + + g_object_unref (res); +} + +/** + * secret_service_unlock_paths_finish: + * @self: the secret service + * @result: asynchronous result passed to the callback + * @unlocked: (out) (array zero-terminated=1) (transfer full) (allow-none): + * location to place array of D-Bus paths of items or collections + * that were unlocked + * @error: location to place an error on failure + * + * Complete asynchronous operation to unlock items or collections in the secret + * service. + * + * The secret service may not be able to unlock items individually, and may + * unlock an entire collection instead. + * + * Returns: the number of items or collections that were unlocked + */ +gint +secret_service_unlock_paths_finish (SecretService *self, + GAsyncResult *result, + gchar ***unlocked, + GError **error) +{ + g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (error == NULL || *error == NULL, -1); + + return service_xlock_paths_finish (self, result, + unlocked, error); +} + +typedef struct { + GCancellable *cancellable; + SecretPrompt *prompt; + gboolean deleted; +} DeleteClosure; + +static void +delete_closure_free (gpointer data) +{ + DeleteClosure *closure = data; + g_clear_object (&closure->prompt); + g_clear_object (&closure->cancellable); + g_slice_free (DeleteClosure, closure); +} + +static void +on_delete_prompted (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GError *error = NULL; + GVariant *retval; + + retval = secret_service_prompt_finish (SECRET_SERVICE (source), result, + NULL, &error); + + if (error == NULL) + closure->deleted = TRUE; + else + g_simple_async_result_take_error (res, error); + if (retval != NULL) + g_variant_unref (retval); + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_delete_complete (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data)); + const gchar *prompt_path; + GError *error = NULL; + GVariant *retval; + + retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (error == NULL) { + g_variant_get (retval, "(&o)", &prompt_path); + + if (_secret_util_empty_path (prompt_path)) { + closure->deleted = TRUE; + g_simple_async_result_complete (res); + + } else { + closure->prompt = _secret_prompt_instance (self, prompt_path); + + secret_service_prompt (self, closure->prompt, + closure->cancellable, + on_delete_prompted, + g_object_ref (res)); + } + + g_variant_unref (retval); + + } else { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + } + + g_object_unref (self); + g_object_unref (res); +} + +void +_secret_service_delete_path (SecretService *self, + const gchar *object_path, + gboolean is_an_item, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + DeleteClosure *closure; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (object_path != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + _secret_service_delete_path); + closure = g_slice_new0 (DeleteClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free); + + g_dbus_connection_call (g_dbus_proxy_get_connection (G_DBUS_PROXY (self)), + g_dbus_proxy_get_name (G_DBUS_PROXY (self)), object_path, + is_an_item ? SECRET_ITEM_INTERFACE : SECRET_COLLECTION_INTERFACE, + "Delete", g_variant_new ("()"), G_VARIANT_TYPE ("(o)"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, + cancellable, on_delete_complete, g_object_ref (res)); + + g_object_unref (res); +} + +/** + * secret_service_delete_path: + * @self: the secret service + * @item_path: the D-Bus path of item to delete + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to be passed to the callback + * + * Delete a secret item from the secret service. + * + * The item is represented by its D-Bus object path. If you already have a + * #SecretItem proxy objects, use use secret_item_delete() instead. + * + * This method will return immediately and complete asynchronously. + */ +void +secret_service_delete_path (SecretService *self, + const gchar *item_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (item_path != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + _secret_service_delete_path (self, item_path, TRUE, cancellable, callback, user_data); +} + +/** + * secret_service_delete_path_finish: + * @self: the secret service + * @result: the asynchronous result passed to the callback + * @error: location to place an error on failure + * + * Complete an asynchronous operation to delete a secret item from the secret + * service. + * + * Returns: whether the deletion was successful or not + */ +gboolean +secret_service_delete_path_finish (SecretService *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res; + DeleteClosure *closure; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + _secret_service_delete_path), FALSE); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return FALSE; + + closure = g_simple_async_result_get_op_res_gpointer (res); + return closure->deleted; +} + +/** + * secret_service_delete_path_sync: + * @self: the secret service + * @item_path: the D-Bus path of item to delete + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * + * Delete a secret item from the secret service. + * + * The item is represented by its D-Bus object path. If you already have a + * #SecretItem proxy objects, use use secret_item_delete_sync() instead. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: whether the deletion was successful or not + */ +gboolean +secret_service_delete_path_sync (SecretService *self, + const gchar *item_path, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + gboolean result; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (item_path != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_service_delete_path (self, item_path, cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + result = secret_service_delete_path_finish (self, sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return result; +} + +typedef struct { + GCancellable *cancellable; + SecretPrompt *prompt; + gchar *collection_path; +} CollectionClosure; + +static void +collection_closure_free (gpointer data) +{ + CollectionClosure *closure = data; + g_clear_object (&closure->cancellable); + g_clear_object (&closure->prompt); + g_slice_free (CollectionClosure, closure); +} + +static void +on_create_collection_prompt (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + CollectionClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GError *error = NULL; + GVariant *value; + + value = secret_service_prompt_finish (SECRET_SERVICE (source), result, + G_VARIANT_TYPE ("o"), &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + if (value != NULL) { + closure->collection_path = g_variant_dup_string (value, NULL); + g_variant_unref (value); + } + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_create_collection_called (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + CollectionClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data)); + const gchar *prompt_path = NULL; + const gchar *collection_path = NULL; + GError *error = NULL; + GVariant *retval; + + retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (error == NULL) { + g_variant_get (retval, "(&o&o)", &collection_path, &prompt_path); + if (!_secret_util_empty_path (prompt_path)) { + closure->prompt = _secret_prompt_instance (self, prompt_path); + secret_service_prompt (self, closure->prompt, + closure->cancellable, on_create_collection_prompt, + g_object_ref (res)); + + } else { + closure->collection_path = g_strdup (collection_path); + g_simple_async_result_complete (res); + } + + g_variant_unref (retval); + + } else { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + } + + g_object_unref (self); + g_object_unref (res); +} + +/** + * secret_service_create_collection_path: + * @self: a secret service object + * @properties: (element-type utf8 GLib.Variant): hash table of properties for + * the new collection + * @alias: (allow-none): an alias to check for before creating the new + * collection, or to assign to the new collection + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to be passed to the callback + * + * Create a new collection in the secret service, and return its path. + * + * Using this method requires that you setup a correct hash table of D-Bus + * properties for the new collection. You may prefer to use + * secret_collection_create() which does handles this for you. + * + * An @alias is a well-known tag for a collection, such as 'default' (ie: the + * default collection to store items in). This allows other applications to + * easily identify and share a collection. If a collection with the @alias + * already exists, then instead of creating a new collection, the existing + * collection will be returned. If no collection with this alias exists, then a + * new collection will be created and this alias will be assigned to it. + * + * @properties is a set of properties for the new collection. The keys in the + * hash table should be interface.property strings like + * org.freedesktop.Secret.Collection.Label. The values + * in the hash table should be #GVariant values of the properties. + * + * If you wish to have a + * + * This method will return immediately and complete asynchronously. The secret + * service may prompt the user. secret_service_prompt() will be used to handle + * any prompts that are required. + */ +void +secret_service_create_collection_path (SecretService *self, + GHashTable *properties, + const gchar *alias, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + CollectionClosure *closure; + GVariant *params; + GVariant *props; + GDBusProxy *proxy; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (properties != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + if (alias == NULL) + alias = ""; + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + secret_service_create_collection_path); + closure = g_slice_new0 (CollectionClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + g_simple_async_result_set_op_res_gpointer (res, closure, collection_closure_free); + + props = _secret_util_variant_for_properties (properties); + params = g_variant_new ("(@a{sv}s)", props, alias); + proxy = G_DBUS_PROXY (self); + + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + SECRET_SERVICE_INTERFACE, + "CreateCollection", params, G_VARIANT_TYPE ("(oo)"), + G_DBUS_CALL_FLAGS_NONE, -1, + closure->cancellable, + on_create_collection_called, + g_object_ref (res)); + + g_object_unref (res); + +} + +/** + * secret_service_create_collection_path_finish: + * @self: a secret service object + * @result: the asynchronous result passed to the callback + * @error: location to place an error on failure + * + * Finish asynchronous operation to create a new collection in the secret + * service. + * + * Returns: (transfer full): a new string containing the D-Bus object path + * of the collection + */ +gchar * +secret_service_create_collection_path_finish (SecretService *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res; + CollectionClosure *closure; + gchar *path; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + secret_service_create_collection_path), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + res = G_SIMPLE_ASYNC_RESULT (result); + + if (g_simple_async_result_propagate_error (res, error)) + return NULL; + + closure = g_simple_async_result_get_op_res_gpointer (res); + path = closure->collection_path; + closure->collection_path = NULL; + return path; +} + +/** + * secret_service_create_collection_path_sync: + * @self: a secret service object + * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties + * for the new collection + * @alias: (allow-none): an alias to check for before creating the new + * collection, or to assign to the new collection + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * + * Create a new collection in the secret service and return its path. + * + * Using this method requires that you setup a correct hash table of D-Bus + * properties for the new collection. You may prefer to use + * secret_collection_create() which does handles this for you. + * + * An @alias is a well-known tag for a collection, such as 'default' (ie: the + * default collection to store items in). This allows other applications to + * easily identify and share a collection. If a collection with the @alias + * already exists, then instead of creating a new collection, the existing + * collection will be returned. If no collection with this alias exists, then + * a new collection will be created and this alias will be assigned to it. + * + * @properties is a set of properties for the new collection. The keys in the + * hash table should be interface.property strings like + * org.freedesktop.Secret.Collection.Label. The values + * in the hash table should be #GVariant values of the properties. + * + * This method may block indefinitely and should not be used in user interface + * threads. The secret service may prompt the user. secret_service_prompt() + * will be used to handle any prompts that are required. + * + * Returns: (transfer full): a new string containing the D-Bus object path + * of the collection + */ +gchar * +secret_service_create_collection_path_sync (SecretService *self, + GHashTable *properties, + const gchar *alias, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + gchar *path; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (properties != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_service_create_collection_path (self, properties, alias, cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + path = secret_service_create_collection_path_finish (self, sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return path; +} + +typedef struct { + GCancellable *cancellable; + GVariant *properties; + SecretValue *value; + gboolean replace; + gchar *collection_path; + SecretPrompt *prompt; + gchar *item_path; +} ItemClosure; + +static void +item_closure_free (gpointer data) +{ + ItemClosure *closure = data; + g_variant_unref (closure->properties); + secret_value_unref (closure->value); + g_clear_object (&closure->cancellable); + g_free (closure->collection_path); + g_clear_object (&closure->prompt); + g_slice_free (ItemClosure, closure); +} + +static void +on_create_item_prompt (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + ItemClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GError *error = NULL; + GVariant *value; + + value = secret_service_prompt_finish (SECRET_SERVICE (source), result, + G_VARIANT_TYPE ("o"), &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + if (value != NULL) { + closure->item_path = g_variant_dup_string (value, NULL); + g_variant_unref (value); + } + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_create_item_called (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + ItemClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data)); + const gchar *prompt_path = NULL; + const gchar *item_path = NULL; + GError *error = NULL; + GVariant *retval; + + retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (error == NULL) { + g_variant_get (retval, "(&o&o)", &item_path, &prompt_path); + if (!_secret_util_empty_path (prompt_path)) { + closure->prompt = _secret_prompt_instance (self, prompt_path); + secret_service_prompt (self, closure->prompt, + closure->cancellable, on_create_item_prompt, + g_object_ref (res)); + + } else { + closure->item_path = g_strdup (item_path); + g_simple_async_result_complete (res); + } + + g_variant_unref (retval); + + } else { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + } + + g_object_unref (self); + g_object_unref (res); +} + +static void +on_create_item_session (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + ItemClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + SecretService *self = SECRET_SERVICE (source); + SecretSession *session; + GVariant *params; + GError *error = NULL; + GDBusProxy *proxy; + + secret_service_ensure_session_finish (self, result, &error); + if (error == NULL) { + session = _secret_service_get_session (self); + params = g_variant_new ("(@a{sv}@(oayays)b)", + closure->properties, + _secret_session_encode_secret (session, closure->value), + closure->replace); + + proxy = G_DBUS_PROXY (self); + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + closure->collection_path, + SECRET_COLLECTION_INTERFACE, + "CreateItem", params, G_VARIANT_TYPE ("(oo)"), + G_DBUS_CALL_FLAGS_NONE, -1, + closure->cancellable, + on_create_item_called, + g_object_ref (res)); + } else { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + } + + g_object_unref (res); +} + +/** + * secret_service_create_item_path: + * @self: a secret service object + * @collection_path: (allow-none): the D-Bus object path of the collection in which to create item + * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties + * for the new collection + * @value: the secret value to store in the item + * @replace: whether to replace an item with the matching attributes + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to be passed to the callback + * + * Create a new item in a secret service collection and return its D-Bus + * object path. + * + * It is often easier to use secret_password_store() or secret_item_create() + * rather than using this function. Using this method requires that you setup + * a correct hash table of D-Bus @properties for the new collection. + * + * If @replace is set to %TRUE, and an item already in the collection matches + * the attributes (specified in @properties) then the item will be updated + * instead of creating a new item. + * + * @properties is a set of properties for the new collection. The keys in the + * hash table should be interface.property strings like + * org.freedesktop.Secret.Item.Label. The values + * in the hash table should be #GVariant values of the properties. + * + * If @collection_path is %NULL, then the default collection will be + * used. Use #SECRET_COLLECTION_SESSION to store the password in the session + * collection, which doesn't get stored across login sessions. + * + * This method will return immediately and complete asynchronously. The secret + * service may prompt the user. secret_service_prompt() will be used to handle + * any prompts that are required. + */ +void +secret_service_create_item_path (SecretService *self, + const gchar *collection_path, + GHashTable *properties, + SecretValue *value, + gboolean replace, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + ItemClosure *closure; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (properties != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + if (collection_path == NULL) + collection_path = SECRET_COLLECTION_DEFAULT; + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + secret_service_create_item_path); + closure = g_slice_new0 (ItemClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + closure->properties = _secret_util_variant_for_properties (properties); + g_variant_ref_sink (closure->properties); + closure->replace = replace; + closure->value = secret_value_ref (value); + closure->collection_path = g_strdup (collection_path); + g_simple_async_result_set_op_res_gpointer (res, closure, item_closure_free); + + secret_service_ensure_session (self, cancellable, + on_create_item_session, + g_object_ref (res)); + + g_object_unref (res); +} + +/** + * secret_service_create_item_path_finish: + * @self: a secret service object + * @result: the asynchronous result passed to the callback + * @error: location to place an error on failure + * + * Finish asynchronous operation to create a new item in the secret + * service. + * + * Returns: (transfer full): a new string containing the D-Bus object path + * of the item + */ +gchar * +secret_service_create_item_path_finish (SecretService *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res; + ItemClosure *closure; + gchar *path; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + secret_service_create_item_path), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + res = G_SIMPLE_ASYNC_RESULT (result); + + if (g_simple_async_result_propagate_error (res, error)) + return NULL; + + closure = g_simple_async_result_get_op_res_gpointer (res); + path = closure->item_path; + closure->item_path = NULL; + return path; +} + +/** + * secret_service_create_item_path_sync: + * @self: a secret service object + * @collection_path: (allow-none): the D-Bus path of the collection in which to create item + * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties + * for the new collection + * @value: the secret value to store in the item + * @replace: whether to replace an item with the matching attributes + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * + * Create a new item in a secret service collection and return its D-Bus + * object path. + * + * It is often easier to use secret_password_store_sync() or secret_item_create_sync() + * rather than using this function. Using this method requires that you setup + * a correct hash table of D-Bus @properties for the new collection. + * + * If @replace is set to %TRUE, and an item already in the collection matches + * the attributes (specified in @properties) then the item will be updated + * instead of creating a new item. + * + * @properties is a set of properties for the new collection. The keys in the + * hash table should be interface.property strings like + * org.freedesktop.Secret.Item.Label. The values + * in the hash table should be #GVariant values of the properties. + * + * This method may block indefinitely and should not be used in user interface + * threads. The secret service may prompt the user. secret_service_prompt() + * will be used to handle any prompts that are required. + * + * Returns: (transfer full): a new string containing the D-Bus object path + * of the item + */ +gchar * +secret_service_create_item_path_sync (SecretService *self, + const gchar *collection_path, + GHashTable *properties, + SecretValue *value, + gboolean replace, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + gchar *path; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (properties != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_service_create_item_path (self, collection_path, properties, value, replace, + cancellable, _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + path = secret_service_create_item_path_finish (self, sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return path; +} + +/** + * secret_service_read_alias_path: + * @self: a secret service object + * @alias: the alias to lookup + * @cancellable: (allow-none): optional cancellation object + * @callback: called when the operation completes + * @user_data: data to pass to the callback + * + * Lookup which collection is assigned to this alias. Aliases help determine + * well known collections, such as 'default'. This method looks up the + * dbus object path of the well known collection. + * + * This method will return immediately and complete asynchronously. + */ +void +secret_service_read_alias_path (SecretService *self, + const gchar *alias, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (alias != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + g_dbus_proxy_call (G_DBUS_PROXY (self), "ReadAlias", + g_variant_new ("(s)", alias), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, callback, user_data); +} + +/** + * secret_service_read_alias_path_finish: + * @self: a secret service object + * @result: asynchronous result passed to callback + * @error: location to place error on failure + * + * Finish an asynchronous operation to lookup which collection is assigned + * to an alias. This method returns the DBus object path of the collection + * + * Returns: (transfer full): the collection dbus object path, or %NULL if + * none assigned to the alias + */ +gchar * +secret_service_read_alias_path_finish (SecretService *self, + GAsyncResult *result, + GError **error) +{ + gchar *collection_path; + GVariant *retval; + + retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, error); + if (retval == NULL) + return NULL; + + g_variant_get (retval, "(o)", &collection_path); + g_variant_unref (retval); + + if (g_str_equal (collection_path, "/")) { + g_free (collection_path); + collection_path = NULL; + } + + return collection_path; +} + +/** + * secret_service_read_alias_path_sync: + * @self: a secret service object + * @alias: the alias to lookup + * @cancellable: (allow-none): optional cancellation object + * @error: location to place error on failure + * + * Lookup which collection is assigned to this alias. Aliases help determine + * well known collections, such as 'default'. This method returns the dbus + * object path of the collection. + * + * This method may block and should not be used in user interface threads. + * + * Returns: (transfer full): the collection dbus object path, or %NULL if + * none assigned to the alias + */ +gchar * +secret_service_read_alias_path_sync (SecretService *self, + const gchar *alias, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + gchar *collection_path; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (alias != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_service_read_alias_path (self, alias, cancellable, _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + collection_path = secret_service_read_alias_path_finish (self, sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return collection_path; +} + +/** + * secret_service_set_alias_path: + * @self: a secret service object + * @alias: the alias to assign the collection to + * @collection_path: (allow-none): the dbus object path of the collection to assign to the alias + * @cancellable: (allow-none): optional cancellation object + * @callback: called when the operation completes + * @user_data: data to pass to the callback + * + * Assign a collection to this alias. Aliases help determine + * well known collections, such as 'default'. This method takes the dbus object + * path of the collection to assign to the alias. + * + * This method will return immediately and complete asynchronously. + */ +void +secret_service_set_alias_path (SecretService *self, + const gchar *alias, + const gchar *collection_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (alias != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + if (collection_path == NULL) + collection_path = "/"; + else + g_return_if_fail (g_variant_is_object_path (collection_path)); + + g_dbus_proxy_call (G_DBUS_PROXY (self), "SetAlias", + g_variant_new ("(so)", alias, collection_path), + G_DBUS_CALL_FLAGS_NONE, -1, cancellable, + callback, user_data); +} + +/** + * secret_service_set_alias_path_finish: + * @self: a secret service object + * @result: asynchronous result passed to callback + * @error: location to place error on failure + * + * Finish an asynchronous operation to assign a collection to an alias. + * + * Returns: %TRUE if successful + */ +gboolean +secret_service_set_alias_path_finish (SecretService *self, + GAsyncResult *result, + GError **error) +{ + GVariant *retval; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, error); + if (retval == NULL) + return FALSE; + + g_variant_unref (retval); + return TRUE; +} + +/** + * secret_service_set_alias_path_sync: + * @self: a secret service object + * @alias: the alias to assign the collection to + * @collection_path: (allow-none): the dbus object path of the collection to assign to the alias + * @cancellable: (allow-none): optional cancellation object + * @error: location to place error on failure + * + * Assign a collection to this alias. Aliases help determine + * well known collections, such as 'default'. This method takes the dbus object + * path of the collection to assign to the alias. + * + * This method may block and should not be used in user interface threads. + * + * Returns: %TRUE if successful + */ +gboolean +secret_service_set_alias_path_sync (SecretService *self, + const gchar *alias, + const gchar *collection_path, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + gboolean ret; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (alias != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (collection_path == NULL) + collection_path = "/"; + else + g_return_val_if_fail (g_variant_is_object_path (collection_path), FALSE); + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_service_set_alias_path (self, alias, collection_path, + cancellable, _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + ret = secret_service_set_alias_path_finish (self, sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return ret; +} + +GVariant * +secret_service_prompt_path_sync (SecretService *self, + const gchar *prompt_path, + GCancellable *cancellable, + const GVariantType *return_type, + GError **error) +{ + SecretPrompt *prompt; + GVariant *retval; + + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (prompt_path != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + prompt = _secret_prompt_instance (self, prompt_path); + retval = secret_service_prompt_sync (self, prompt, cancellable, return_type, error); + g_object_unref (prompt); + + return retval; +} + +/** + * secret_service_prompt_path: + * @self: the secret service + * @prompt_path: the D-Bus object path of the prompt + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to be passed to the callback + * + * Perform prompting for a #SecretPrompt. + * + * This function is called by other parts of this library to handle prompts + * for the various actions that can require prompting. + * + * Override the #SecretServiceClass prompt_async virtual method + * to change the behavior of the propmting. The default behavior is to simply + * run secret_prompt_perform() on the prompt. + */ +void +secret_service_prompt_path (SecretService *self, + const gchar *prompt_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + SecretPrompt *prompt; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (prompt_path != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + prompt = _secret_prompt_instance (self, prompt_path); + secret_service_prompt (self, prompt, cancellable, callback, user_data); + g_object_unref (prompt); +} + +/** + * secret_service_prompt_path_finish: + * @self: the secret service + * @result: the asynchronous result passed to the callback + * @return_type: the variant type of the prompt result + * @error: location to place an error on failure + * + * Complete asynchronous operation to perform prompting for a #SecretPrompt. + * + * Returns a variant result if the prompt was completed and not dismissed. The + * type of result depends on the action the prompt is completing, and is defined + * in the Secret Service DBus API specification. + * + * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred, + * a variant result if the prompt was successful + */ +GVariant * +secret_service_prompt_path_finish (SecretService *self, + GAsyncResult *result, + const GVariantType *return_type, + GError **error) +{ + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + return secret_service_prompt_finish (self, result, return_type, error); +} diff --git a/library/secret-paths.h b/library/secret-paths.h new file mode 100644 index 0000000..a26a5e7 --- /dev/null +++ b/library/secret-paths.h @@ -0,0 +1,219 @@ +/* libsecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * Copyright 2012 Red Hat Inc. + * + * 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 licence or (at + * your option) any later version. + * + * See the included COPYING file for more information. + * + * Author: Stef Walter + */ + +#if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION) +#error "Only or can be included directly." +#endif + +#ifndef __SECRET_PATHS_H__ +#define __SECRET_PATHS_H__ + +#include + +#include "secret-prompt.h" +#include "secret-schema.h" +#include "secret-types.h" +#include "secret-value.h" + +G_BEGIN_DECLS + +void secret_service_search_for_paths (SecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean secret_service_search_for_paths_finish (SecretService *self, + GAsyncResult *result, + gchar ***unlocked, + gchar ***locked, + GError **error); + +gboolean secret_service_search_for_paths_sync (SecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + gchar ***unlocked, + gchar ***locked, + GError **error); + +void secret_service_get_secret_for_path (SecretService *self, + const gchar *item_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +SecretValue * secret_service_get_secret_for_path_finish (SecretService *self, + GAsyncResult *result, + GError **error); + +SecretValue * secret_service_get_secret_for_path_sync (SecretService *self, + const gchar *item_path, + GCancellable *cancellable, + GError **error); + +void secret_service_get_secrets_for_paths (SecretService *self, + const gchar **item_paths, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GHashTable * secret_service_get_secrets_for_paths_finish (SecretService *self, + GAsyncResult *result, + GError **error); + +GHashTable * secret_service_get_secrets_for_paths_sync (SecretService *self, + const gchar **item_paths, + GCancellable *cancellable, + GError **error); + +gint secret_service_lock_paths_sync (SecretService *self, + const gchar **paths, + GCancellable *cancellable, + gchar ***locked, + GError **error); + +void secret_service_lock_paths (SecretService *self, + const gchar **paths, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gint secret_service_lock_paths_finish (SecretService *self, + GAsyncResult *result, + gchar ***locked, + GError **error); + +gint secret_service_unlock_paths_sync (SecretService *self, + const gchar **paths, + GCancellable *cancellable, + gchar ***unlocked, + GError **error); + +void secret_service_unlock_paths (SecretService *self, + const gchar **paths, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gint secret_service_unlock_paths_finish (SecretService *self, + GAsyncResult *result, + gchar ***unlocked, + GError **error); + +GVariant * secret_service_prompt_path_sync (SecretService *self, + const gchar *prompt_path, + GCancellable *cancellable, + const GVariantType *return_type, + GError **error); + +void secret_service_prompt_path (SecretService *self, + const gchar *prompt_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GVariant * secret_service_prompt_path_finish (SecretService *self, + GAsyncResult *result, + const GVariantType *return_type, + GError **error); + +void secret_service_delete_path (SecretService *self, + const gchar *item_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean secret_service_delete_path_finish (SecretService *self, + GAsyncResult *result, + GError **error); + +gboolean secret_service_delete_path_sync (SecretService *self, + const gchar *item_path, + GCancellable *cancellable, + GError **error); + +void secret_service_create_collection_path (SecretService *self, + GHashTable *properties, + const gchar *alias, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gchar * secret_service_create_collection_path_finish (SecretService *self, + GAsyncResult *result, + GError **error); + +gchar * secret_service_create_collection_path_sync (SecretService *self, + GHashTable *properties, + const gchar *alias, + GCancellable *cancellable, + GError **error); + +void secret_service_create_item_path (SecretService *self, + const gchar *collection_path, + GHashTable *properties, + SecretValue *value, + gboolean replace, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gchar * secret_service_create_item_path_finish (SecretService *self, + GAsyncResult *result, + GError **error); + +gchar * secret_service_create_item_path_sync (SecretService *self, + const gchar *collection_path, + GHashTable *properties, + SecretValue *value, + gboolean replace, + GCancellable *cancellable, + GError **error); + +void secret_service_read_alias_path (SecretService *self, + const gchar *alias, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gchar * secret_service_read_alias_path_finish (SecretService *self, + GAsyncResult *result, + GError **error); + +gchar * secret_service_read_alias_path_sync (SecretService *self, + const gchar *alias, + GCancellable *cancellable, + GError **error); + +void secret_service_set_alias_path (SecretService *self, + const gchar *alias, + const gchar *collection_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean secret_service_set_alias_path_finish (SecretService *self, + GAsyncResult *result, + GError **error); + +gboolean secret_service_set_alias_path_sync (SecretService *self, + const gchar *alias, + const gchar *collection_path, + GCancellable *cancellable, + GError **error); + +G_END_DECLS + +#endif /* __SECRET_SERVICE_H___ */ diff --git a/library/secret-private.h b/library/secret-private.h index e6a86d7..b4ecebd 100644 --- a/library/secret-private.h +++ b/library/secret-private.h @@ -139,6 +139,12 @@ SecretItem * _secret_service_find_item_instance (SecretService *se SecretCollection * _secret_service_find_collection_instance (SecretService *self, const gchar *collection_path); +SecretValue * _secret_service_decode_get_secrets_first (SecretService *self, + GVariant *out); + +GHashTable * _secret_service_decode_get_secrets_all (SecretService *self, + GVariant *out); + SecretItem * _secret_collection_find_item_instance (SecretCollection *self, const gchar *item_path); diff --git a/library/secret-service.c b/library/secret-service.c index 0b9e923..9a6eb16 100644 --- a/library/secret-service.c +++ b/library/secret-service.c @@ -19,6 +19,7 @@ #include "secret-dbus-generated.h" #include "secret-enum-types.h" #include "secret-item.h" +#include "secret-paths.h" #include "secret-private.h" #include "secret-service.h" #include "secret-types.h" @@ -1648,89 +1649,3 @@ secret_service_prompt_finish (SecretService *self, return (klass->prompt_finish) (self, result, return_type, error); } - -GVariant * -secret_service_prompt_path_sync (SecretService *self, - const gchar *prompt_path, - GCancellable *cancellable, - const GVariantType *return_type, - GError **error) -{ - SecretPrompt *prompt; - GVariant *retval; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); - g_return_val_if_fail (prompt_path != NULL, NULL); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - prompt = _secret_prompt_instance (self, prompt_path); - retval = secret_service_prompt_sync (self, prompt, cancellable, return_type, error); - g_object_unref (prompt); - - return retval; -} - -/** - * secret_service_prompt_path: - * @self: the secret service - * @prompt_path: the D-Bus object path of the prompt - * @cancellable: optional cancellation object - * @callback: called when the operation completes - * @user_data: data to be passed to the callback - * - * Perform prompting for a #SecretPrompt. - * - * This function is called by other parts of this library to handle prompts - * for the various actions that can require prompting. - * - * Override the #SecretServiceClass prompt_async virtual method - * to change the behavior of the propmting. The default behavior is to simply - * run secret_prompt_perform() on the prompt. - */ -void -secret_service_prompt_path (SecretService *self, - const gchar *prompt_path, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - SecretPrompt *prompt; - - g_return_if_fail (SECRET_IS_SERVICE (self)); - g_return_if_fail (prompt_path != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - prompt = _secret_prompt_instance (self, prompt_path); - secret_service_prompt (self, prompt, cancellable, callback, user_data); - g_object_unref (prompt); -} - -/** - * secret_service_prompt_path_finish: - * @self: the secret service - * @result: the asynchronous result passed to the callback - * @return_type: the variant type of the prompt result - * @error: location to place an error on failure - * - * Complete asynchronous operation to perform prompting for a #SecretPrompt. - * - * Returns a variant result if the prompt was completed and not dismissed. The - * type of result depends on the action the prompt is completing, and is defined - * in the Secret Service DBus API specification. - * - * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred, - * a variant result if the prompt was successful - */ -GVariant * -secret_service_prompt_path_finish (SecretService *self, - GAsyncResult *result, - const GVariantType *return_type, - GError **error) -{ - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); - g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - return secret_service_prompt_finish (self, result, return_type, error); -} diff --git a/library/secret-service.h b/library/secret-service.h index 8bb4e7a..a29bd47 100644 --- a/library/secret-service.h +++ b/library/secret-service.h @@ -162,55 +162,6 @@ gboolean secret_service_search_sync (SecretService GList **locked, GError **error); -void secret_service_search_for_paths (SecretService *self, - GHashTable *attributes, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean secret_service_search_for_paths_finish (SecretService *self, - GAsyncResult *result, - gchar ***unlocked, - gchar ***locked, - GError **error); - -gboolean secret_service_search_for_paths_sync (SecretService *self, - GHashTable *attributes, - GCancellable *cancellable, - gchar ***unlocked, - gchar ***locked, - GError **error); - -void secret_service_get_secret_for_path (SecretService *self, - const gchar *item_path, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -SecretValue * secret_service_get_secret_for_path_finish (SecretService *self, - GAsyncResult *result, - GError **error); - -SecretValue * secret_service_get_secret_for_path_sync (SecretService *self, - const gchar *item_path, - GCancellable *cancellable, - GError **error); - -void secret_service_get_secrets_for_paths (SecretService *self, - const gchar **item_paths, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -GHashTable * secret_service_get_secrets_for_paths_finish (SecretService *self, - GAsyncResult *result, - GError **error); - -GHashTable * secret_service_get_secrets_for_paths_sync (SecretService *self, - const gchar **item_paths, - GCancellable *cancellable, - GError **error); - void secret_service_get_secrets (SecretService *self, GList *items, GCancellable *cancellable, @@ -243,23 +194,6 @@ gint secret_service_lock_sync (SecretService GList **locked, GError **error); -gint secret_service_lock_paths_sync (SecretService *self, - const gchar **paths, - GCancellable *cancellable, - gchar ***locked, - GError **error); - -void secret_service_lock_paths (SecretService *self, - const gchar **paths, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gint secret_service_lock_paths_finish (SecretService *self, - GAsyncResult *result, - gchar ***locked, - GError **error); - void secret_service_unlock (SecretService *self, GList *objects, GCancellable *cancellable, @@ -277,23 +211,6 @@ gint secret_service_unlock_sync (SecretService GList **unlocked, GError **error); -gint secret_service_unlock_paths_sync (SecretService *self, - const gchar **paths, - GCancellable *cancellable, - gchar ***unlocked, - GError **error); - -void secret_service_unlock_paths (SecretService *self, - const gchar **paths, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gint secret_service_unlock_paths_finish (SecretService *self, - GAsyncResult *result, - gchar ***unlocked, - GError **error); - GVariant * secret_service_prompt_sync (SecretService *self, SecretPrompt *prompt, GCancellable *cancellable, @@ -311,23 +228,6 @@ GVariant * secret_service_prompt_finish (SecretService const GVariantType *return_type, GError **error); -GVariant * secret_service_prompt_path_sync (SecretService *self, - const gchar *prompt_path, - GCancellable *cancellable, - const GVariantType *return_type, - GError **error); - -void secret_service_prompt_path (SecretService *self, - const gchar *prompt_path, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -GVariant * secret_service_prompt_path_finish (SecretService *self, - GAsyncResult *result, - const GVariantType *return_type, - GError **error); - void secret_service_store (SecretService *self, const SecretSchema *schema, GHashTable *attributes, @@ -368,21 +268,6 @@ SecretValue * secret_service_lookup_sync (SecretService GCancellable *cancellable, GError **error); -void secret_service_delete_path (SecretService *self, - const gchar *item_path, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean secret_service_delete_path_finish (SecretService *self, - GAsyncResult *result, - GError **error); - -gboolean secret_service_delete_path_sync (SecretService *self, - const gchar *item_path, - GCancellable *cancellable, - GError **error); - void secret_service_remove (SecretService *self, const SecretSchema *schema, GHashTable *attributes, @@ -400,44 +285,6 @@ gboolean secret_service_remove_sync (SecretService GCancellable *cancellable, GError **error); -void secret_service_create_collection_path (SecretService *self, - GHashTable *properties, - const gchar *alias, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gchar * secret_service_create_collection_path_finish (SecretService *self, - GAsyncResult *result, - GError **error); - -gchar * secret_service_create_collection_path_sync (SecretService *self, - GHashTable *properties, - const gchar *alias, - GCancellable *cancellable, - GError **error); - -void secret_service_create_item_path (SecretService *self, - const gchar *collection_path, - GHashTable *properties, - SecretValue *value, - gboolean replace, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gchar * secret_service_create_item_path_finish (SecretService *self, - GAsyncResult *result, - GError **error); - -gchar * secret_service_create_item_path_sync (SecretService *self, - const gchar *collection_path, - GHashTable *properties, - SecretValue *value, - gboolean replace, - GCancellable *cancellable, - GError **error); - void secret_service_read_alias (SecretService *self, const gchar *alias, GCancellable *cancellable, @@ -453,21 +300,6 @@ SecretCollection * secret_service_read_alias_sync (SecretService GCancellable *cancellable, GError **error); -void secret_service_read_alias_path (SecretService *self, - const gchar *alias, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gchar * secret_service_read_alias_path_finish (SecretService *self, - GAsyncResult *result, - GError **error); - -gchar * secret_service_read_alias_path_sync (SecretService *self, - const gchar *alias, - GCancellable *cancellable, - GError **error); - void secret_service_set_alias (SecretService *self, const gchar *alias, SecretCollection *collection, @@ -485,23 +317,6 @@ gboolean secret_service_set_alias_sync (SecretService GCancellable *cancellable, GError **error); -void secret_service_set_alias_path (SecretService *self, - const gchar *alias, - const gchar *collection_path, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean secret_service_set_alias_path_finish (SecretService *self, - GAsyncResult *result, - GError **error); - -gboolean secret_service_set_alias_path_sync (SecretService *self, - const gchar *alias, - const gchar *collection_path, - GCancellable *cancellable, - GError **error); - G_END_DECLS #endif /* __SECRET_SERVICE_H___ */ diff --git a/library/secret-unstable.h b/library/secret-unstable.h index 2d1a629..0a781bd 100644 --- a/library/secret-unstable.h +++ b/library/secret-unstable.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/library/tests/Makefile.am b/library/tests/Makefile.am index 77c0d28..fe0e86e 100644 --- a/library/tests/Makefile.am +++ b/library/tests/Makefile.am @@ -36,6 +36,7 @@ C_TESTS = \ test-prompt \ test-service \ test-session \ + test-paths \ test-methods \ test-password \ test-item \ diff --git a/library/tests/test-methods.c b/library/tests/test-methods.c index f0f6665..09de317 100644 --- a/library/tests/test-methods.c +++ b/library/tests/test-methods.c @@ -16,8 +16,9 @@ #include "secret-attributes.h" #include "secret-collection.h" #include "secret-item.h" -#include "secret-service.h" +#include "secret-paths.h" #include "secret-private.h" +#include "secret-service.h" #include "mock-service.h" @@ -115,147 +116,6 @@ on_complete_get_result (GObject *source, egg_test_wait_stop (); } -static void -test_search_paths_sync (Test *test, - gconstpointer used) -{ - GHashTable *attributes; - gboolean ret; - gchar **locked; - gchar **unlocked; - GError *error = NULL; - - attributes = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (attributes, "number", "1"); - - ret = secret_service_search_for_paths_sync (test->service, attributes, NULL, - &unlocked, &locked, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (locked); - g_assert_cmpstr (locked[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); - - g_assert (unlocked); - g_assert_cmpstr (unlocked[0], ==, "/org/freedesktop/secrets/collection/english/1"); - - g_strfreev (unlocked); - g_strfreev (locked); - - g_hash_table_unref (attributes); -} - -static void -test_search_paths_async (Test *test, - gconstpointer used) -{ - GAsyncResult *result = NULL; - GHashTable *attributes; - gboolean ret; - gchar **locked; - gchar **unlocked; - GError *error = NULL; - - attributes = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (attributes, "number", "1"); - - secret_service_search_for_paths (test->service, attributes, NULL, - on_complete_get_result, &result); - egg_test_wait (); - - g_assert (G_IS_ASYNC_RESULT (result)); - ret = secret_service_search_for_paths_finish (test->service, result, - &unlocked, &locked, - &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (locked); - g_assert_cmpstr (locked[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); - - g_assert (unlocked); - g_assert_cmpstr (unlocked[0], ==, "/org/freedesktop/secrets/collection/english/1"); - - g_strfreev (unlocked); - g_strfreev (locked); - g_object_unref (result); - - g_hash_table_unref (attributes); -} - -static void -test_search_paths_nulls (Test *test, - gconstpointer used) -{ - GAsyncResult *result = NULL; - GHashTable *attributes; - gboolean ret; - gchar **paths; - GError *error = NULL; - - attributes = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (attributes, "number", "1"); - - ret = secret_service_search_for_paths_sync (test->service, attributes, NULL, - &paths, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_assert (paths != NULL); - g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/english/1"); - g_strfreev (paths); - - ret = secret_service_search_for_paths_sync (test->service, attributes, NULL, - NULL, &paths, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_assert (paths != NULL); - g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); - g_strfreev (paths); - - ret = secret_service_search_for_paths_sync (test->service, attributes, NULL, - NULL, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - secret_service_search_for_paths (test->service, attributes, NULL, - on_complete_get_result, &result); - egg_test_wait (); - g_assert (G_IS_ASYNC_RESULT (result)); - ret = secret_service_search_for_paths_finish (test->service, result, - &paths, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_assert (paths != NULL); - g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/english/1"); - g_strfreev (paths); - g_clear_object (&result); - - secret_service_search_for_paths (test->service, attributes, NULL, - on_complete_get_result, &result); - egg_test_wait (); - g_assert (G_IS_ASYNC_RESULT (result)); - ret = secret_service_search_for_paths_finish (test->service, result, - NULL, &paths, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_assert (paths != NULL); - g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); - g_strfreev (paths); - g_clear_object (&result); - - secret_service_search_for_paths (test->service, attributes, NULL, - on_complete_get_result, &result); - egg_test_wait (); - g_assert (G_IS_ASYNC_RESULT (result)); - ret = secret_service_search_for_paths_finish (test->service, result, - NULL, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_clear_object (&result); - - g_hash_table_unref (attributes); -} - static void test_search_sync (Test *test, gconstpointer used) @@ -397,154 +257,6 @@ test_search_nulls (Test *test, g_hash_table_unref (attributes); } -static void -test_secret_for_path_sync (Test *test, - gconstpointer used) -{ - SecretValue *value; - GError *error = NULL; - const gchar *path; - const gchar *password; - gsize length; - - path = "/org/freedesktop/secrets/collection/english/1"; - value = secret_service_get_secret_for_path_sync (test->service, path, NULL, &error); - g_assert_no_error (error); - g_assert (value != NULL); - - password = secret_value_get (value, &length); - g_assert_cmpuint (length, ==, 3); - g_assert_cmpstr (password, ==, "111"); - - password = secret_value_get (value, NULL); - g_assert_cmpstr (password, ==, "111"); - - secret_value_unref (value); -} - -static void -test_secret_for_path_async (Test *test, - gconstpointer used) -{ - SecretValue *value; - GError *error = NULL; - const gchar *path; - const gchar *password; - GAsyncResult *result = NULL; - gsize length; - - path = "/org/freedesktop/secrets/collection/english/1"; - secret_service_get_secret_for_path (test->service, path, NULL, - on_complete_get_result, &result); - g_assert (result == NULL); - egg_test_wait (); - - value = secret_service_get_secret_for_path_finish (test->service, result, &error); - g_assert_no_error (error); - g_assert (value != NULL); - g_object_unref (result); - - password = secret_value_get (value, &length); - g_assert_cmpuint (length, ==, 3); - g_assert_cmpstr (password, ==, "111"); - - password = secret_value_get (value, NULL); - g_assert_cmpstr (password, ==, "111"); - - secret_value_unref (value); -} - -static void -test_secrets_for_paths_sync (Test *test, - gconstpointer used) -{ - const gchar *path_item_one = "/org/freedesktop/secrets/collection/english/1"; - const gchar *path_item_two = "/org/freedesktop/secrets/collection/english/2"; - const gchar *paths[] = { - path_item_one, - path_item_two, - - /* This one is locked, and not returned */ - "/org/freedesktop/secrets/collection/spanish/10", - NULL - }; - - SecretValue *value; - GHashTable *values; - GError *error = NULL; - const gchar *password; - gsize length; - - values = secret_service_get_secrets_for_paths_sync (test->service, paths, NULL, &error); - g_assert_no_error (error); - - g_assert (values != NULL); - g_assert_cmpuint (g_hash_table_size (values), ==, 2); - - value = g_hash_table_lookup (values, path_item_one); - g_assert (value != NULL); - password = secret_value_get (value, &length); - g_assert_cmpuint (length, ==, 3); - g_assert_cmpstr (password, ==, "111"); - - value = g_hash_table_lookup (values, path_item_two); - g_assert (value != NULL); - password = secret_value_get (value, &length); - g_assert_cmpuint (length, ==, 3); - g_assert_cmpstr (password, ==, "222"); - - g_hash_table_unref (values); -} - -static void -test_secrets_for_paths_async (Test *test, - gconstpointer used) -{ - const gchar *path_item_one = "/org/freedesktop/secrets/collection/english/1"; - const gchar *path_item_two = "/org/freedesktop/secrets/collection/english/2"; - const gchar *paths[] = { - path_item_one, - path_item_two, - - /* This one is locked, and not returned */ - "/org/freedesktop/secrets/collection/spanish/10", - NULL - }; - - SecretValue *value; - GHashTable *values; - GError *error = NULL; - const gchar *password; - GAsyncResult *result = NULL; - gsize length; - - secret_service_get_secrets_for_paths (test->service, paths, NULL, - on_complete_get_result, &result); - g_assert (result == NULL); - egg_test_wait (); - - values = secret_service_get_secrets_for_paths_finish (test->service, result, &error); - g_assert_no_error (error); - g_object_unref (result); - - g_assert (values != NULL); - g_assert_cmpuint (g_hash_table_size (values), ==, 2); - - value = g_hash_table_lookup (values, path_item_one); - g_assert (value != NULL); - password = secret_value_get (value, &length); - g_assert_cmpuint (length, ==, 3); - g_assert_cmpstr (password, ==, "111"); - - value = g_hash_table_lookup (values, path_item_two); - g_assert (value != NULL); - password = secret_value_get (value, &length); - g_assert_cmpuint (length, ==, 3); - g_assert_cmpstr (password, ==, "222"); - - g_hash_table_unref (values); -} - static void test_secrets_sync (Test *test, gconstpointer used) @@ -655,82 +367,6 @@ test_secrets_async (Test *test, g_object_unref (item_three); } -static void -test_delete_for_path_sync (Test *test, - gconstpointer used) - -{ - const gchar *path_item_one = "/org/freedesktop/secrets/collection/todelete/item"; - GError *error = NULL; - gboolean ret; - - ret = secret_service_delete_path_sync (test->service, path_item_one, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); -} - -static void -test_delete_for_path_sync_prompt (Test *test, - gconstpointer used) - -{ - const gchar *path_item_one = "/org/freedesktop/secrets/collection/todelete/confirm"; - GError *error = NULL; - gboolean ret; - - ret = secret_service_delete_path_sync (test->service, path_item_one, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); -} - -static void -test_lock_paths_sync (Test *test, - gconstpointer used) -{ - const gchar *collection_path = "/org/freedesktop/secrets/collection/lockone"; - const gchar *paths[] = { - collection_path, - NULL, - }; - - GError *error = NULL; - gchar **locked = NULL; - gboolean ret; - - ret = secret_service_lock_paths_sync (test->service, paths, NULL, &locked, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (locked != NULL); - g_assert_cmpstr (locked[0], ==, collection_path); - g_assert (locked[1] == NULL); - g_strfreev (locked); -} - -static void -test_lock_prompt_sync (Test *test, - gconstpointer used) -{ - const gchar *collection_path = "/org/freedesktop/secrets/collection/lockprompt"; - const gchar *paths[] = { - collection_path, - NULL, - }; - - GError *error = NULL; - gchar **locked = NULL; - gboolean ret; - - ret = secret_service_lock_paths_sync (test->service, paths, NULL, &locked, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (locked != NULL); - g_assert_cmpstr (locked[0], ==, collection_path); - g_assert (locked[1] == NULL); - g_strfreev (locked); -} - static void test_lock_sync (Test *test, gconstpointer used) @@ -760,54 +396,6 @@ test_lock_sync (Test *test, g_object_unref (collection); } -static void -test_unlock_paths_sync (Test *test, - gconstpointer used) -{ - const gchar *collection_path = "/org/freedesktop/secrets/collection/lockone"; - const gchar *paths[] = { - collection_path, - NULL, - }; - - GError *error = NULL; - gchar **unlocked = NULL; - gboolean ret; - - ret = secret_service_unlock_paths_sync (test->service, paths, NULL, &unlocked, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (unlocked != NULL); - g_assert_cmpstr (unlocked[0], ==, collection_path); - g_assert (unlocked[1] == NULL); - g_strfreev (unlocked); -} - -static void -test_unlock_prompt_sync (Test *test, - gconstpointer used) -{ - const gchar *collection_path = "/org/freedesktop/secrets/collection/lockprompt"; - const gchar *paths[] = { - collection_path, - NULL, - }; - - GError *error = NULL; - gchar **unlocked = NULL; - gboolean ret; - - ret = secret_service_unlock_paths_sync (test->service, paths, NULL, &unlocked, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (unlocked != NULL); - g_assert_cmpstr (unlocked[0], ==, collection_path); - g_assert (unlocked[1] == NULL); - g_strfreev (unlocked); -} - static void test_unlock_sync (Test *test, gconstpointer used) @@ -837,152 +425,6 @@ test_unlock_sync (Test *test, g_object_unref (collection); } -static void -test_collection_sync (Test *test, - gconstpointer used) -{ - GHashTable *properties; - GError *error = NULL; - gchar *path; - - properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify)g_variant_unref); - g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", - g_variant_ref_sink (g_variant_new_string ("Wheeee"))); - - path = secret_service_create_collection_path_sync (test->service, properties, - NULL, NULL, &error); - - g_hash_table_unref (properties); - - g_assert_no_error (error); - g_assert (path != NULL); - g_assert (g_str_has_prefix (path, "/org/freedesktop/secrets/collection/")); - - g_free (path); -} - -static void -test_collection_async (Test *test, - gconstpointer used) -{ - GAsyncResult *result = NULL; - GHashTable *properties; - GError *error = NULL; - gchar *path; - - properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify)g_variant_unref); - g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", - g_variant_ref_sink (g_variant_new_string ("Wheeee"))); - - secret_service_create_collection_path (test->service, properties, - NULL, NULL, on_complete_get_result, &result); - - g_hash_table_unref (properties); - g_assert (result == NULL); - - egg_test_wait (); - - path = secret_service_create_collection_path_finish (test->service, result, &error); - g_object_unref (result); - - g_assert_no_error (error); - g_assert (path != NULL); - g_assert (g_str_has_prefix (path, "/org/freedesktop/secrets/collection/")); - - g_free (path); -} - -static void -test_item_sync (Test *test, - gconstpointer used) -{ - const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; - GHashTable *properties; - GHashTable *attributes; - SecretValue *value; - GError *error = NULL; - gchar *path; - - attributes = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (attributes, "even", "true"); - g_hash_table_insert (attributes, "string", "ten"); - g_hash_table_insert (attributes, "number", "10"); - - properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify)g_variant_unref); - g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", - g_variant_ref_sink (g_variant_new_string ("Wheeee"))); - g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Attributes", - g_variant_ref_sink (_secret_attributes_to_variant (attributes, "org.gnome.Test"))); - - g_hash_table_unref (attributes); - - value = secret_value_new ("andmoreandmore", -1, "text/plain"); - - path = secret_service_create_item_path_sync (test->service, collection_path, - properties, value, FALSE, - NULL, &error); - - secret_value_unref (value); - g_hash_table_unref (properties); - - g_assert_no_error (error); - g_assert (path != NULL); - g_assert (g_str_has_prefix (path, collection_path)); - - g_free (path); -} - -static void -test_item_async (Test *test, - gconstpointer used) -{ - const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; - GHashTable *properties; - GHashTable *attributes; - SecretValue *value; - GError *error = NULL; - GAsyncResult *result = NULL; - gchar *path; - - attributes = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (attributes, "even", "true"); - g_hash_table_insert (attributes, "string", "ten"); - g_hash_table_insert (attributes, "number", "10"); - - properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify)g_variant_unref); - g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", - g_variant_ref_sink (g_variant_new_string ("Wheeee"))); - g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Attributes", - g_variant_ref_sink (_secret_attributes_to_variant (attributes, NULL))); - - g_hash_table_unref (attributes); - - value = secret_value_new ("andmoreandmore", -1, "text/plain"); - - secret_service_create_item_path (test->service, collection_path, - properties, value, FALSE, - NULL, on_complete_get_result, &result); - - g_assert (result == NULL); - secret_value_unref (value); - g_hash_table_unref (properties); - - egg_test_wait (); - - path = secret_service_create_item_path_finish (test->service, result, &error); - g_object_unref (result); - - g_assert_no_error (error); - g_assert (path != NULL); - g_assert (g_str_has_prefix (path, collection_path)); - - g_free (path); -} - static void test_remove_sync (Test *test, gconstpointer used) @@ -1485,36 +927,6 @@ test_set_alias_sync (Test *test, g_object_unref (collection); } -static void -test_set_alias_path (Test *test, - gconstpointer used) -{ - gchar *path; - GError *error = NULL; - gboolean ret; - - path = secret_service_read_alias_path_sync (test->service, "blah", NULL, &error); - g_assert_no_error (error); - g_assert (path == NULL); - - ret = secret_service_set_alias_path_sync (test->service, "blah", "/org/freedesktop/secrets/collection/english", NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - path = secret_service_read_alias_path_sync (test->service, "blah", NULL, &error); - g_assert_no_error (error); - g_assert_cmpstr (path, ==, "/org/freedesktop/secrets/collection/english"); - g_free (path); - - ret = secret_service_set_alias_path_sync (test->service, "blah", NULL, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - path = secret_service_read_alias_path_sync (test->service, "blah", NULL, &error); - g_assert_no_error (error); - g_assert (path == NULL); -} - int main (int argc, char **argv) { @@ -1522,38 +934,17 @@ main (int argc, char **argv) g_set_prgname ("test-service"); g_type_init (); - g_test_add ("/service/search-for-paths", Test, "mock-service-normal.py", setup, test_search_paths_sync, teardown); - g_test_add ("/service/search-for-paths-async", Test, "mock-service-normal.py", setup, test_search_paths_async, teardown); - g_test_add ("/service/search-for-paths-nulls", Test, "mock-service-normal.py", setup, test_search_paths_nulls, teardown); 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/secret-for-path-sync", Test, "mock-service-normal.py", setup, test_secret_for_path_sync, teardown); - g_test_add ("/service/secret-for-path-plain", Test, "mock-service-only-plain.py", setup, test_secret_for_path_sync, teardown); - g_test_add ("/service/secret-for-path-async", Test, "mock-service-normal.py", setup, test_secret_for_path_async, teardown); - g_test_add ("/service/secrets-for-paths-sync", Test, "mock-service-normal.py", setup, test_secrets_for_paths_sync, teardown); - g_test_add ("/service/secrets-for-paths-async", Test, "mock-service-normal.py", setup, test_secrets_for_paths_async, teardown); g_test_add ("/service/secrets-sync", Test, "mock-service-normal.py", setup, test_secrets_sync, teardown); g_test_add ("/service/secrets-async", Test, "mock-service-normal.py", setup, test_secrets_async, teardown); - g_test_add ("/service/delete-for-path", Test, "mock-service-delete.py", setup, test_delete_for_path_sync, teardown); - g_test_add ("/service/delete-for-path-with-prompt", Test, "mock-service-delete.py", setup, test_delete_for_path_sync_prompt, teardown); - - g_test_add ("/service/lock-paths-sync", Test, "mock-service-lock.py", setup, test_lock_paths_sync, teardown); - g_test_add ("/service/lock-prompt-sync", Test, "mock-service-lock.py", setup, test_lock_prompt_sync, teardown); g_test_add ("/service/lock-sync", Test, "mock-service-lock.py", setup, test_lock_sync, teardown); - g_test_add ("/service/unlock-paths-sync", Test, "mock-service-lock.py", setup, test_unlock_paths_sync, teardown); - g_test_add ("/service/unlock-prompt-sync", Test, "mock-service-lock.py", setup, test_unlock_prompt_sync, teardown); g_test_add ("/service/unlock-sync", Test, "mock-service-lock.py", setup, test_unlock_sync, teardown); - g_test_add ("/service/create-collection-sync", Test, "mock-service-normal.py", setup, test_collection_sync, teardown); - g_test_add ("/service/create-collection-async", Test, "mock-service-normal.py", setup, test_collection_async, teardown); - - g_test_add ("/service/create-item-sync", Test, "mock-service-normal.py", setup, test_item_sync, teardown); - g_test_add ("/service/create-item-async", Test, "mock-service-normal.py", setup, test_item_async, teardown); - g_test_add ("/service/lookup-sync", Test, "mock-service-normal.py", setup, test_lookup_sync, teardown); g_test_add ("/service/lookup-async", Test, "mock-service-normal.py", setup, test_lookup_async, teardown); g_test_add ("/service/lookup-locked", Test, "mock-service-normal.py", setup, test_lookup_locked, teardown); @@ -1574,7 +965,6 @@ main (int argc, char **argv) g_test_add ("/service/read-alias-async", Test, "mock-service-normal.py", setup, test_read_alias_async, teardown); g_test_add ("/service/set-alias-sync", Test, "mock-service-normal.py", setup, test_set_alias_sync, teardown); - g_test_add ("/service/set-alias-path", Test, "mock-service-normal.py", setup, test_set_alias_path, teardown); return egg_tests_run_with_loop (); } diff --git a/library/tests/test-paths.c b/library/tests/test-paths.c new file mode 100644 index 0000000..ba349eb --- /dev/null +++ b/library/tests/test-paths.c @@ -0,0 +1,743 @@ +/* libsecret - GLib wrapper for Secret Service + * + * Copyright 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 of the licence or (at + * your option) any later version. + * + * See the included COPYING file for more information. + */ + + +#include "config.h" + +#include "secret-attributes.h" +#include "secret-collection.h" +#include "secret-item.h" +#include "secret-paths.h" +#include "secret-private.h" +#include "secret-service.h" + +#include "mock-service.h" + +#include "egg/egg-testing.h" + +#include + +#include +#include + +static const SecretSchema MOCK_SCHEMA = { + "org.mock.Schema", + SECRET_SCHEMA_NONE, + { + { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, + { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, + } +}; + +static const SecretSchema PRIME_SCHEMA = { + "org.mock.Prime", + SECRET_SCHEMA_NONE, + { + { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, + { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "prime", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN }, + } +}; + +static const SecretSchema NO_NAME_SCHEMA = { + "unused.Schema.Name", + SECRET_SCHEMA_DONT_MATCH_NAME, + { + { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, + { "string", SECRET_SCHEMA_ATTRIBUTE_STRING }, + } +}; + +typedef struct { + SecretService *service; +} Test; + +static void +setup_mock (Test *test, + gconstpointer data) +{ + GError *error = NULL; + const gchar *mock_script = data; + + mock_service_start (mock_script, &error); + g_assert_no_error (error); +} + +static void +setup (Test *test, + gconstpointer data) +{ + GError *error = NULL; + + setup_mock (test, data); + + test->service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); + g_assert_no_error (error); +} + +static void +teardown_mock (Test *test, + gconstpointer unused) +{ + mock_service_stop (); +} + +static void +teardown (Test *test, + gconstpointer unused) +{ + egg_test_wait_idle (); + + g_object_unref (test->service); + egg_assert_not_object (test->service); + + teardown_mock (test, unused); +} + +static void +on_complete_get_result (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GAsyncResult **ret = user_data; + g_assert (ret != NULL); + g_assert (*ret == NULL); + *ret = g_object_ref (result); + egg_test_wait_stop (); +} + +static void +test_search_paths_sync (Test *test, + gconstpointer used) +{ + GHashTable *attributes; + gboolean ret; + gchar **locked; + gchar **unlocked; + GError *error = NULL; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "number", "1"); + + ret = secret_service_search_for_paths_sync (test->service, attributes, NULL, + &unlocked, &locked, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + g_assert (locked); + g_assert_cmpstr (locked[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); + + g_assert (unlocked); + g_assert_cmpstr (unlocked[0], ==, "/org/freedesktop/secrets/collection/english/1"); + + g_strfreev (unlocked); + g_strfreev (locked); + + g_hash_table_unref (attributes); +} + +static void +test_search_paths_async (Test *test, + gconstpointer used) +{ + GAsyncResult *result = NULL; + GHashTable *attributes; + gboolean ret; + gchar **locked; + gchar **unlocked; + GError *error = NULL; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "number", "1"); + + secret_service_search_for_paths (test->service, attributes, NULL, + on_complete_get_result, &result); + egg_test_wait (); + + g_assert (G_IS_ASYNC_RESULT (result)); + ret = secret_service_search_for_paths_finish (test->service, result, + &unlocked, &locked, + &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + g_assert (locked); + g_assert_cmpstr (locked[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); + + g_assert (unlocked); + g_assert_cmpstr (unlocked[0], ==, "/org/freedesktop/secrets/collection/english/1"); + + g_strfreev (unlocked); + g_strfreev (locked); + g_object_unref (result); + + g_hash_table_unref (attributes); +} + +static void +test_search_paths_nulls (Test *test, + gconstpointer used) +{ + GAsyncResult *result = NULL; + GHashTable *attributes; + gboolean ret; + gchar **paths; + GError *error = NULL; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "number", "1"); + + ret = secret_service_search_for_paths_sync (test->service, attributes, NULL, + &paths, NULL, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + g_assert (paths != NULL); + g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/english/1"); + g_strfreev (paths); + + ret = secret_service_search_for_paths_sync (test->service, attributes, NULL, + NULL, &paths, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + g_assert (paths != NULL); + g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); + g_strfreev (paths); + + ret = secret_service_search_for_paths_sync (test->service, attributes, NULL, + NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + secret_service_search_for_paths (test->service, attributes, NULL, + on_complete_get_result, &result); + egg_test_wait (); + g_assert (G_IS_ASYNC_RESULT (result)); + ret = secret_service_search_for_paths_finish (test->service, result, + &paths, NULL, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + g_assert (paths != NULL); + g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/english/1"); + g_strfreev (paths); + g_clear_object (&result); + + secret_service_search_for_paths (test->service, attributes, NULL, + on_complete_get_result, &result); + egg_test_wait (); + g_assert (G_IS_ASYNC_RESULT (result)); + ret = secret_service_search_for_paths_finish (test->service, result, + NULL, &paths, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + g_assert (paths != NULL); + g_assert_cmpstr (paths[0], ==, "/org/freedesktop/secrets/collection/spanish/10"); + g_strfreev (paths); + g_clear_object (&result); + + secret_service_search_for_paths (test->service, attributes, NULL, + on_complete_get_result, &result); + egg_test_wait (); + g_assert (G_IS_ASYNC_RESULT (result)); + ret = secret_service_search_for_paths_finish (test->service, result, + NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + g_clear_object (&result); + + g_hash_table_unref (attributes); +} + +static void +test_secret_for_path_sync (Test *test, + gconstpointer used) +{ + SecretValue *value; + GError *error = NULL; + const gchar *path; + const gchar *password; + gsize length; + + path = "/org/freedesktop/secrets/collection/english/1"; + value = secret_service_get_secret_for_path_sync (test->service, path, NULL, &error); + g_assert_no_error (error); + g_assert (value != NULL); + + password = secret_value_get (value, &length); + g_assert_cmpuint (length, ==, 3); + g_assert_cmpstr (password, ==, "111"); + + password = secret_value_get (value, NULL); + g_assert_cmpstr (password, ==, "111"); + + secret_value_unref (value); +} + +static void +test_secret_for_path_async (Test *test, + gconstpointer used) +{ + SecretValue *value; + GError *error = NULL; + const gchar *path; + const gchar *password; + GAsyncResult *result = NULL; + gsize length; + + path = "/org/freedesktop/secrets/collection/english/1"; + secret_service_get_secret_for_path (test->service, path, NULL, + on_complete_get_result, &result); + g_assert (result == NULL); + egg_test_wait (); + + value = secret_service_get_secret_for_path_finish (test->service, result, &error); + g_assert_no_error (error); + g_assert (value != NULL); + g_object_unref (result); + + password = secret_value_get (value, &length); + g_assert_cmpuint (length, ==, 3); + g_assert_cmpstr (password, ==, "111"); + + password = secret_value_get (value, NULL); + g_assert_cmpstr (password, ==, "111"); + + secret_value_unref (value); +} + +static void +test_secrets_for_paths_sync (Test *test, + gconstpointer used) +{ + const gchar *path_item_one = "/org/freedesktop/secrets/collection/english/1"; + const gchar *path_item_two = "/org/freedesktop/secrets/collection/english/2"; + const gchar *paths[] = { + path_item_one, + path_item_two, + + /* This one is locked, and not returned */ + "/org/freedesktop/secrets/collection/spanish/10", + NULL + }; + + SecretValue *value; + GHashTable *values; + GError *error = NULL; + const gchar *password; + gsize length; + + values = secret_service_get_secrets_for_paths_sync (test->service, paths, NULL, &error); + g_assert_no_error (error); + + g_assert (values != NULL); + g_assert_cmpuint (g_hash_table_size (values), ==, 2); + + value = g_hash_table_lookup (values, path_item_one); + g_assert (value != NULL); + password = secret_value_get (value, &length); + g_assert_cmpuint (length, ==, 3); + g_assert_cmpstr (password, ==, "111"); + + value = g_hash_table_lookup (values, path_item_two); + g_assert (value != NULL); + password = secret_value_get (value, &length); + g_assert_cmpuint (length, ==, 3); + g_assert_cmpstr (password, ==, "222"); + + g_hash_table_unref (values); +} + +static void +test_secrets_for_paths_async (Test *test, + gconstpointer used) +{ + const gchar *path_item_one = "/org/freedesktop/secrets/collection/english/1"; + const gchar *path_item_two = "/org/freedesktop/secrets/collection/english/2"; + const gchar *paths[] = { + path_item_one, + path_item_two, + + /* This one is locked, and not returned */ + "/org/freedesktop/secrets/collection/spanish/10", + NULL + }; + + SecretValue *value; + GHashTable *values; + GError *error = NULL; + const gchar *password; + GAsyncResult *result = NULL; + gsize length; + + secret_service_get_secrets_for_paths (test->service, paths, NULL, + on_complete_get_result, &result); + g_assert (result == NULL); + egg_test_wait (); + + values = secret_service_get_secrets_for_paths_finish (test->service, result, &error); + g_assert_no_error (error); + g_object_unref (result); + + g_assert (values != NULL); + g_assert_cmpuint (g_hash_table_size (values), ==, 2); + + value = g_hash_table_lookup (values, path_item_one); + g_assert (value != NULL); + password = secret_value_get (value, &length); + g_assert_cmpuint (length, ==, 3); + g_assert_cmpstr (password, ==, "111"); + + value = g_hash_table_lookup (values, path_item_two); + g_assert (value != NULL); + password = secret_value_get (value, &length); + g_assert_cmpuint (length, ==, 3); + g_assert_cmpstr (password, ==, "222"); + + g_hash_table_unref (values); +} + +static void +test_delete_for_path_sync (Test *test, + gconstpointer used) + +{ + const gchar *path_item_one = "/org/freedesktop/secrets/collection/todelete/item"; + GError *error = NULL; + gboolean ret; + + ret = secret_service_delete_path_sync (test->service, path_item_one, NULL, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); +} + +static void +test_delete_for_path_sync_prompt (Test *test, + gconstpointer used) + +{ + const gchar *path_item_one = "/org/freedesktop/secrets/collection/todelete/confirm"; + GError *error = NULL; + gboolean ret; + + ret = secret_service_delete_path_sync (test->service, path_item_one, NULL, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); +} + +static void +test_lock_paths_sync (Test *test, + gconstpointer used) +{ + const gchar *collection_path = "/org/freedesktop/secrets/collection/lockone"; + const gchar *paths[] = { + collection_path, + NULL, + }; + + GError *error = NULL; + gchar **locked = NULL; + gboolean ret; + + ret = secret_service_lock_paths_sync (test->service, paths, NULL, &locked, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + g_assert (locked != NULL); + g_assert_cmpstr (locked[0], ==, collection_path); + g_assert (locked[1] == NULL); + g_strfreev (locked); +} + +static void +test_lock_prompt_sync (Test *test, + gconstpointer used) +{ + const gchar *collection_path = "/org/freedesktop/secrets/collection/lockprompt"; + const gchar *paths[] = { + collection_path, + NULL, + }; + + GError *error = NULL; + gchar **locked = NULL; + gboolean ret; + + ret = secret_service_lock_paths_sync (test->service, paths, NULL, &locked, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + g_assert (locked != NULL); + g_assert_cmpstr (locked[0], ==, collection_path); + g_assert (locked[1] == NULL); + g_strfreev (locked); +} + +static void +test_unlock_paths_sync (Test *test, + gconstpointer used) +{ + const gchar *collection_path = "/org/freedesktop/secrets/collection/lockone"; + const gchar *paths[] = { + collection_path, + NULL, + }; + + GError *error = NULL; + gchar **unlocked = NULL; + gboolean ret; + + ret = secret_service_unlock_paths_sync (test->service, paths, NULL, &unlocked, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + g_assert (unlocked != NULL); + g_assert_cmpstr (unlocked[0], ==, collection_path); + g_assert (unlocked[1] == NULL); + g_strfreev (unlocked); +} + +static void +test_unlock_prompt_sync (Test *test, + gconstpointer used) +{ + const gchar *collection_path = "/org/freedesktop/secrets/collection/lockprompt"; + const gchar *paths[] = { + collection_path, + NULL, + }; + + GError *error = NULL; + gchar **unlocked = NULL; + gboolean ret; + + ret = secret_service_unlock_paths_sync (test->service, paths, NULL, &unlocked, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + g_assert (unlocked != NULL); + g_assert_cmpstr (unlocked[0], ==, collection_path); + g_assert (unlocked[1] == NULL); + g_strfreev (unlocked); +} + +static void +test_collection_sync (Test *test, + gconstpointer used) +{ + GHashTable *properties; + GError *error = NULL; + gchar *path; + + properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify)g_variant_unref); + g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", + g_variant_ref_sink (g_variant_new_string ("Wheeee"))); + + path = secret_service_create_collection_path_sync (test->service, properties, + NULL, NULL, &error); + + g_hash_table_unref (properties); + + g_assert_no_error (error); + g_assert (path != NULL); + g_assert (g_str_has_prefix (path, "/org/freedesktop/secrets/collection/")); + + g_free (path); +} + +static void +test_collection_async (Test *test, + gconstpointer used) +{ + GAsyncResult *result = NULL; + GHashTable *properties; + GError *error = NULL; + gchar *path; + + properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify)g_variant_unref); + g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", + g_variant_ref_sink (g_variant_new_string ("Wheeee"))); + + secret_service_create_collection_path (test->service, properties, + NULL, NULL, on_complete_get_result, &result); + + g_hash_table_unref (properties); + g_assert (result == NULL); + + egg_test_wait (); + + path = secret_service_create_collection_path_finish (test->service, result, &error); + g_object_unref (result); + + g_assert_no_error (error); + g_assert (path != NULL); + g_assert (g_str_has_prefix (path, "/org/freedesktop/secrets/collection/")); + + g_free (path); +} + +static void +test_item_sync (Test *test, + gconstpointer used) +{ + const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; + GHashTable *properties; + GHashTable *attributes; + SecretValue *value; + GError *error = NULL; + gchar *path; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "even", "true"); + g_hash_table_insert (attributes, "string", "ten"); + g_hash_table_insert (attributes, "number", "10"); + + properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify)g_variant_unref); + g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", + g_variant_ref_sink (g_variant_new_string ("Wheeee"))); + g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Attributes", + g_variant_ref_sink (_secret_attributes_to_variant (attributes, "org.gnome.Test"))); + + g_hash_table_unref (attributes); + + value = secret_value_new ("andmoreandmore", -1, "text/plain"); + + path = secret_service_create_item_path_sync (test->service, collection_path, + properties, value, FALSE, + NULL, &error); + + secret_value_unref (value); + g_hash_table_unref (properties); + + g_assert_no_error (error); + g_assert (path != NULL); + g_assert (g_str_has_prefix (path, collection_path)); + + g_free (path); +} + +static void +test_item_async (Test *test, + gconstpointer used) +{ + const gchar *collection_path = "/org/freedesktop/secrets/collection/english"; + GHashTable *properties; + GHashTable *attributes; + SecretValue *value; + GError *error = NULL; + GAsyncResult *result = NULL; + gchar *path; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "even", "true"); + g_hash_table_insert (attributes, "string", "ten"); + g_hash_table_insert (attributes, "number", "10"); + + properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify)g_variant_unref); + g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Label", + g_variant_ref_sink (g_variant_new_string ("Wheeee"))); + g_hash_table_insert (properties, SECRET_COLLECTION_INTERFACE ".Attributes", + g_variant_ref_sink (_secret_attributes_to_variant (attributes, NULL))); + + g_hash_table_unref (attributes); + + value = secret_value_new ("andmoreandmore", -1, "text/plain"); + + secret_service_create_item_path (test->service, collection_path, + properties, value, FALSE, + NULL, on_complete_get_result, &result); + + g_assert (result == NULL); + secret_value_unref (value); + g_hash_table_unref (properties); + + egg_test_wait (); + + path = secret_service_create_item_path_finish (test->service, result, &error); + g_object_unref (result); + + g_assert_no_error (error); + g_assert (path != NULL); + g_assert (g_str_has_prefix (path, collection_path)); + + g_free (path); +} + +static void +test_set_alias_path (Test *test, + gconstpointer used) +{ + gchar *path; + GError *error = NULL; + gboolean ret; + + path = secret_service_read_alias_path_sync (test->service, "blah", NULL, &error); + g_assert_no_error (error); + g_assert (path == NULL); + + ret = secret_service_set_alias_path_sync (test->service, "blah", "/org/freedesktop/secrets/collection/english", NULL, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + path = secret_service_read_alias_path_sync (test->service, "blah", NULL, &error); + g_assert_no_error (error); + g_assert_cmpstr (path, ==, "/org/freedesktop/secrets/collection/english"); + g_free (path); + + ret = secret_service_set_alias_path_sync (test->service, "blah", NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + path = secret_service_read_alias_path_sync (test->service, "blah", NULL, &error); + g_assert_no_error (error); + g_assert (path == NULL); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_set_prgname ("test-service"); + g_type_init (); + + g_test_add ("/service/search-for-paths", Test, "mock-service-normal.py", setup, test_search_paths_sync, teardown); + g_test_add ("/service/search-for-paths-async", Test, "mock-service-normal.py", setup, test_search_paths_async, teardown); + g_test_add ("/service/search-for-paths-nulls", Test, "mock-service-normal.py", setup, test_search_paths_nulls, teardown); + + g_test_add ("/service/secret-for-path-sync", Test, "mock-service-normal.py", setup, test_secret_for_path_sync, teardown); + g_test_add ("/service/secret-for-path-plain", Test, "mock-service-only-plain.py", setup, test_secret_for_path_sync, teardown); + g_test_add ("/service/secret-for-path-async", Test, "mock-service-normal.py", setup, test_secret_for_path_async, teardown); + g_test_add ("/service/secrets-for-paths-sync", Test, "mock-service-normal.py", setup, test_secrets_for_paths_sync, teardown); + g_test_add ("/service/secrets-for-paths-async", Test, "mock-service-normal.py", setup, test_secrets_for_paths_async, teardown); + + g_test_add ("/service/delete-for-path", Test, "mock-service-delete.py", setup, test_delete_for_path_sync, teardown); + g_test_add ("/service/delete-for-path-with-prompt", Test, "mock-service-delete.py", setup, test_delete_for_path_sync_prompt, teardown); + + g_test_add ("/service/lock-paths-sync", Test, "mock-service-lock.py", setup, test_lock_paths_sync, teardown); + g_test_add ("/service/lock-prompt-sync", Test, "mock-service-lock.py", setup, test_lock_prompt_sync, teardown); + + g_test_add ("/service/unlock-paths-sync", Test, "mock-service-lock.py", setup, test_unlock_paths_sync, teardown); + g_test_add ("/service/unlock-prompt-sync", Test, "mock-service-lock.py", setup, test_unlock_prompt_sync, teardown); + + g_test_add ("/service/create-collection-sync", Test, "mock-service-normal.py", setup, test_collection_sync, teardown); + g_test_add ("/service/create-collection-async", Test, "mock-service-normal.py", setup, test_collection_async, teardown); + + g_test_add ("/service/create-item-sync", Test, "mock-service-normal.py", setup, test_item_sync, teardown); + g_test_add ("/service/create-item-async", Test, "mock-service-normal.py", setup, test_item_async, teardown); + + g_test_add ("/service/set-alias-path", Test, "mock-service-normal.py", setup, test_set_alias_path, teardown); + + return egg_tests_run_with_loop (); +}