diff --git a/library/secret-collection.c b/library/secret-collection.c index cdf87b2..94d606f 100644 --- a/library/secret-collection.c +++ b/library/secret-collection.c @@ -138,6 +138,23 @@ on_set_label (GObject *source, g_object_unref (self); } +static void +collection_take_service (SecretCollection *self, + SecretService *service) +{ + if (service == NULL) + return; + + g_return_if_fail (self->pv->service == NULL); + + self->pv->service = service; + g_object_add_weak_pointer (G_OBJECT (self->pv->service), + (gpointer *)&self->pv->service); + + /* Yes, we expect that the service will stay around */ + g_object_unref (service); +} + static void secret_collection_set_property (GObject *obj, guint prop_id, @@ -148,11 +165,7 @@ secret_collection_set_property (GObject *obj, switch (prop_id) { case PROP_SERVICE: - g_return_if_fail (self->pv->service == NULL); - self->pv->service = g_value_get_object (value); - if (self->pv->service) - g_object_add_weak_pointer (G_OBJECT (self->pv->service), - (gpointer *)&self->pv->service); + collection_take_service (self, g_value_dup_object (value)); break; case PROP_FLAGS: self->pv->init_flags = g_value_get_flags (value); @@ -494,6 +507,7 @@ secret_collection_initable_init (GInitable *initable, GError **error) { SecretCollection *self; + SecretService *service; GDBusProxy *proxy; if (!secret_collection_initable_parent_iface->init (initable, cancellable, error)) @@ -510,6 +524,14 @@ secret_collection_initable_init (GInitable *initable, self = SECRET_COLLECTION (initable); + if (self->pv->service == NULL) { + service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error); + if (service == NULL) + return FALSE; + else + collection_take_service (self, service); + } + if (self->pv->init_flags & SECRET_COLLECTION_LOAD_ITEMS) { if (!secret_collection_load_items_sync (self, cancellable, error)) return FALSE; @@ -555,6 +577,45 @@ on_init_items (GObject *source, g_object_unref (res); } +static void +collection_ensure_for_flags_async (SecretCollection *self, + SecretCollectionFlags flags, + GSimpleAsyncResult *async) +{ + InitClosure *init = g_simple_async_result_get_op_res_gpointer (async); + + if (flags & SECRET_COLLECTION_LOAD_ITEMS) + secret_collection_load_items (self, init->cancellable, + on_init_items, g_object_ref (async)); + + else + g_simple_async_result_complete (async); +} + +static void +on_init_service (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + SecretCollection *self = SECRET_COLLECTION (g_async_result_get_source_object (user_data)); + SecretService *service; + GError *error = NULL; + + service = secret_service_get_finish (result, &error); + if (error == NULL) { + collection_take_service (self, service); + collection_ensure_for_flags_async (self, self->pv->init_flags, async); + + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (self); + g_object_unref (async); +} + static void on_init_base (GObject *source, GAsyncResult *result, @@ -562,7 +623,7 @@ on_init_base (GObject *source, { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); SecretCollection *self = SECRET_COLLECTION (source); - InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + InitClosure *init = g_simple_async_result_get_op_res_gpointer (res); GDBusProxy *proxy = G_DBUS_PROXY (self); GError *error = NULL; @@ -577,12 +638,12 @@ on_init_base (GObject *source, g_dbus_proxy_get_object_path (proxy)); g_simple_async_result_complete (res); - } else if (self->pv->init_flags & SECRET_COLLECTION_LOAD_ITEMS) { - secret_collection_load_items (self, closure->cancellable, - on_init_items, g_object_ref (res)); + } else if (self->pv->service == NULL) { + secret_service_get (SECRET_SERVICE_NONE, init->cancellable, + on_init_service, g_object_ref (res)); } else { - g_simple_async_result_complete (res); + collection_ensure_for_flags_async (self, self->pv->init_flags, res); } g_object_unref (res); @@ -640,7 +701,7 @@ secret_collection_async_initable_iface (GAsyncInitableIface *iface) /** * secret_collection_new: - * @service: a secret service object + * @service: (allow-none): a secret service object * @collection_path: the D-Bus path of the collection * @flags: options for the collection initialization * @cancellable: optional cancellation object @@ -649,6 +710,9 @@ secret_collection_async_initable_iface (GAsyncInitableIface *iface) * * Get a new collection proxy for a collection in the secret service. * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * * This method will return immediately and complete asynchronously. */ void @@ -661,7 +725,7 @@ secret_collection_new (SecretService *service, { GDBusProxy *proxy; - g_return_if_fail (SECRET_IS_SERVICE (service)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (collection_path != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -714,7 +778,7 @@ secret_collection_new_finish (GAsyncResult *result, /** * secret_collection_new_sync: - * @service: a secret service object + * @service: (allow-none): a secret service object * @collection_path: the D-Bus path of the collection * @flags: options for the collection initialization * @cancellable: optional cancellation object @@ -722,6 +786,9 @@ secret_collection_new_finish (GAsyncResult *result, * * Get a new collection proxy for a collection in the secret service. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * This method may block indefinitely and should not be used in user interface * threads. * @@ -737,7 +804,7 @@ secret_collection_new_sync (SecretService *service, { GDBusProxy *proxy; - g_return_val_if_fail (SECRET_IS_SERVICE (service), NULL); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (collection_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); @@ -988,6 +1055,8 @@ secret_collection_refresh (SecretCollection *self) typedef struct { GCancellable *cancellable; SecretCollection *collection; + GHashTable *properties; + gchar *alias; } CreateClosure; static void @@ -996,6 +1065,8 @@ create_closure_free (gpointer data) CreateClosure *closure = data; g_clear_object (&closure->cancellable); g_clear_object (&closure->collection); + g_hash_table_unref (closure->properties); + g_free (closure->alias); g_slice_free (CreateClosure, closure); } @@ -1040,6 +1111,31 @@ on_create_path (GObject *source, g_object_unref (res); } +static void +on_create_service (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + CreateClosure *create = g_simple_async_result_get_op_res_gpointer (async); + GError *error = NULL; + SecretService *service; + + service = secret_service_get_finish (result, &error); + if (error == NULL) { + secret_service_create_collection_path (service, create->properties, + create->alias, create->cancellable, + on_create_path, g_object_ref (async)); + g_object_unref (service); + + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (async); +} + static GHashTable * collection_properties_new (const gchar *label) { @@ -1058,7 +1154,7 @@ collection_properties_new (const gchar *label) /** * secret_collection_create: - * @service: a secret service object + * @service: (allow-none): a secret service object * @label: label for the new collection * @alias: (allow-none): alias to assign to the collection * @cancellable: optional cancellation object @@ -1076,6 +1172,10 @@ collection_properties_new (const gchar *label) * easily identify and share a collection. If you specify an @alias, and a * collection with that alias already exists, then a new collection will not * be created. The previous one will be returned instead. + * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * */ void secret_collection_create (SecretService *service, @@ -1087,9 +1187,8 @@ secret_collection_create (SecretService *service, { GSimpleAsyncResult *res; CreateClosure *closure; - GHashTable *properties; - g_return_if_fail (SECRET_IS_SERVICE (service)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (label != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -1097,14 +1196,20 @@ secret_collection_create (SecretService *service, secret_collection_create); closure = g_slice_new0 (CreateClosure); closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + closure->properties = collection_properties_new (label); + closure->alias = g_strdup (alias); g_simple_async_result_set_op_res_gpointer (res, closure, create_closure_free); - properties = collection_properties_new (label); + if (service == NULL) { + secret_service_get (SECRET_SERVICE_NONE, cancellable, + on_create_service, g_object_ref (res)); - secret_service_create_collection_path (service, properties, alias, cancellable, - on_create_path, g_object_ref (res)); + } else { + secret_service_create_collection_path (service, closure->properties, + closure->alias, closure->cancellable, + on_create_path, g_object_ref (res)); + } - g_hash_table_unref (properties); g_object_unref (res); } @@ -1143,7 +1248,7 @@ secret_collection_create_finish (GAsyncResult *result, /** * secret_collection_create_sync: - * @service: a secret service object + * @service: (allow-none): a secret service object * @label: label for the new collection * @alias: (allow-none): alias to assign to the collection * @cancellable: optional cancellation object @@ -1161,6 +1266,9 @@ secret_collection_create_finish (GAsyncResult *result, * collection with that alias already exists, then a new collection will not * be created. The previous one will be returned instead. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * Returns: (transfer full): the new collection, which should be unreferenced * with g_object_unref() */ @@ -1175,11 +1283,19 @@ secret_collection_create_sync (SecretService *service, GHashTable *properties; gchar *path; - g_return_val_if_fail (SECRET_IS_SERVICE (service), NULL); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (label != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + if (service == NULL) { + service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error); + if (service == NULL) + return NULL; + } else { + g_object_ref (service); + } + properties = collection_properties_new (label); path = secret_service_create_collection_path_sync (service, properties, alias, @@ -1187,12 +1303,16 @@ secret_collection_create_sync (SecretService *service, g_hash_table_unref (properties); - if (path == NULL) + if (path == NULL) { + g_object_unref (service); return NULL; + } collection = secret_collection_new_sync (service, path, SECRET_COLLECTION_LOAD_ITEMS, cancellable, error); + + g_object_unref (service); g_free (path); return collection; diff --git a/library/secret-item.c b/library/secret-item.c index 3c5d876..5219092 100644 --- a/library/secret-item.c +++ b/library/secret-item.c @@ -152,6 +152,24 @@ on_set_label (GObject *source, g_object_unref (self); } + +static void +item_take_service (SecretItem *self, + SecretService *service) +{ + if (service == NULL) + return; + + g_return_if_fail (self->pv->service == NULL); + + self->pv->service = service; + g_object_add_weak_pointer (G_OBJECT (self->pv->service), + (gpointer *)&self->pv->service); + + /* Yes, we expect that the service will stay around */ + g_object_unref (service); +} + static void secret_item_set_property (GObject *obj, guint prop_id, @@ -162,11 +180,7 @@ secret_item_set_property (GObject *obj, switch (prop_id) { case PROP_SERVICE: - g_return_if_fail (self->pv->service == NULL); - self->pv->service = g_value_get_object (value); - if (self->pv->service) - g_object_add_weak_pointer (G_OBJECT (self->pv->service), - (gpointer *)&self->pv->service); + item_take_service (self, g_value_dup_object (value)); break; case PROP_FLAGS: self->pv->init_flags = g_value_get_flags (value); @@ -444,6 +458,7 @@ secret_item_initable_init (GInitable *initable, GError **error) { SecretItem *self; + SecretService *service; GDBusProxy *proxy; if (!secret_item_initable_parent_iface->init (initable, cancellable, error)) @@ -459,6 +474,14 @@ secret_item_initable_init (GInitable *initable, } self = SECRET_ITEM (initable); + if (!self->pv->service) { + service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error); + if (service == NULL) + return FALSE; + else + item_take_service (self, service); + } + return item_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error); } @@ -470,12 +493,37 @@ secret_item_initable_iface (GInitableIface *iface) iface->init = secret_item_initable_init; } +static void +on_init_service (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data)); + SecretService *service; + GError *error = NULL; + + service = secret_service_get_finish (result, &error); + if (error == NULL) { + item_take_service (self, service); + item_ensure_for_flags_async (self, self->pv->init_flags, async); + + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (self); + g_object_unref (async); +} + static void on_init_base (GObject *source, GAsyncResult *result, gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + InitClosure *init = g_simple_async_result_get_op_res_gpointer (res); SecretItem *self = SECRET_ITEM (source); GDBusProxy *proxy = G_DBUS_PROXY (self); GError *error = NULL; @@ -491,6 +539,10 @@ on_init_base (GObject *source, g_dbus_proxy_get_object_path (proxy)); g_simple_async_result_complete (res); + } else if (self->pv->service == NULL) { + secret_service_get (SECRET_SERVICE_NONE, init->cancellable, + on_init_service, g_object_ref (res)); + } else { item_ensure_for_flags_async (self, self->pv->init_flags, res); } @@ -547,7 +599,7 @@ secret_item_async_initable_iface (GAsyncInitableIface *iface) /** * secret_item_new: - * @service: a secret service object + * @service: (allow-none): a secret service object * @item_path: the D-Bus path of the collection * @flags: initialization flags for the new item * @cancellable: optional cancellation object @@ -556,6 +608,9 @@ secret_item_async_initable_iface (GAsyncInitableIface *iface) * * Get a new item proxy for a secret item in the secret service. * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * * This method will return immediately and complete asynchronously. */ void @@ -568,7 +623,7 @@ secret_item_new (SecretService *service, { GDBusProxy *proxy; - g_return_if_fail (SECRET_IS_SERVICE (service)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (item_path != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -618,7 +673,7 @@ secret_item_new_finish (GAsyncResult *result, /** * secret_item_new_sync: - * @service: a secret service object + * @service: (allow-none): a secret service object * @item_path: the D-Bus path of the item * @flags: initialization flags for the new item * @cancellable: optional cancellation object @@ -626,6 +681,9 @@ secret_item_new_finish (GAsyncResult *result, * * Get a new item proxy for a secret item in the secret service. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * This method may block indefinitely and should not be used in user interface * threads. * @@ -641,7 +699,7 @@ secret_item_new_sync (SecretService *service, { GDBusProxy *proxy; - g_return_val_if_fail (SECRET_IS_SERVICE (service), NULL); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), 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); diff --git a/library/secret-methods.c b/library/secret-methods.c index d0e2558..2a5b467 100644 --- a/library/secret-methods.c +++ b/library/secret-methods.c @@ -32,6 +32,7 @@ typedef struct { gchar **locked; guint loading; SecretSearchFlags flags; + GVariant *attributes; } SearchClosure; static void @@ -41,6 +42,7 @@ search_closure_free (gpointer data) g_object_unref (closure->service); g_clear_object (&closure->cancellable); g_hash_table_unref (closure->items); + g_variant_unref (closure->attributes); g_strfreev (closure->unlocked); g_strfreev (closure->locked); g_slice_free (SearchClosure, closure); @@ -212,9 +214,32 @@ on_search_paths (GObject *source, g_object_unref (res); } +static void +on_search_service (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + SearchClosure *search = g_simple_async_result_get_op_res_gpointer (async); + GError *error = NULL; + + search->service = secret_service_get_finish (result, &error); + if (error == NULL) { + _secret_service_search_for_paths_variant (search->service, search->attributes, + search->cancellable, on_search_paths, + g_object_ref (async)); + + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (async); +} + /** * secret_service_search: - * @self: the secret service + * @service: (allow-none): the secret service * @schema: (allow-none): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @flags: search option flags @@ -225,6 +250,9 @@ on_search_paths (GObject *source, * Search for items matching the @attributes. All collections are searched. * The @attributes should be a table of string keys and string values. * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the * search will be returned. Otherwise only the first item will be returned. * This is almost always the unlocked item that was most recently stored. @@ -239,7 +267,7 @@ on_search_paths (GObject *source, * This function returns immediately and completes asynchronously. */ void -secret_service_search (SecretService *self, +secret_service_search (SecretService *service, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, @@ -249,8 +277,9 @@ secret_service_search (SecretService *self, { GSimpleAsyncResult *res; SearchClosure *closure; + const gchar *schema_name = NULL; - g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -258,24 +287,36 @@ secret_service_search (SecretService *self, if (schema != NULL && !_secret_attributes_validate (schema, attributes)) return; - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) + schema_name = schema->name; + + res = g_simple_async_result_new (G_OBJECT (service), callback, user_data, secret_service_search); closure = g_slice_new0 (SearchClosure); - closure->service = g_object_ref (self); closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; closure->items = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); closure->flags = flags; + closure->attributes = _secret_attributes_to_variant (attributes, schema_name); + g_variant_ref_sink (closure->attributes); g_simple_async_result_set_op_res_gpointer (res, closure, search_closure_free); - secret_service_search_for_paths (self, schema, attributes, cancellable, - on_search_paths, g_object_ref (res)); + if (service) { + closure->service = g_object_ref (service); + _secret_service_search_for_paths_variant (closure->service, closure->attributes, + closure->cancellable, on_search_paths, + g_object_ref (res)); + + } else { + secret_service_get (SECRET_SERVICE_NONE, cancellable, + on_search_service, g_object_ref (res)); + } g_object_unref (res); } /** * secret_service_search_finish: - * @self: the secret service + * @service: (allow-none): the secret service * @result: asynchronous result passed to callback * @error: location to place error on failure * @@ -285,7 +326,7 @@ secret_service_search (SecretService *self, * a list of items that matched the search */ GList * -secret_service_search_finish (SecretService *self, +secret_service_search_finish (SecretService *service, GAsyncResult *result, GError **error) { @@ -293,9 +334,9 @@ secret_service_search_finish (SecretService *self, SearchClosure *closure; GList *items; - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), 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), + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service), secret_service_search), FALSE); res = G_SIMPLE_ASYNC_RESULT (result); @@ -312,7 +353,7 @@ secret_service_search_finish (SecretService *self, } static gboolean -service_load_items_sync (SecretService *self, +service_load_items_sync (SecretService *service, GCancellable *cancellable, gchar **paths, GList **items, @@ -324,9 +365,9 @@ service_load_items_sync (SecretService *self, guint i; for (i = 0; *have < want && paths[i] != NULL; i++) { - item = _secret_service_find_item_instance (self, paths[i]); + item = _secret_service_find_item_instance (service, paths[i]); if (item == NULL) - item = secret_item_new_sync (self, paths[i], SECRET_ITEM_NONE, + item = secret_item_new_sync (service, paths[i], SECRET_ITEM_NONE, cancellable, error); if (item == NULL) { return FALSE; @@ -342,7 +383,7 @@ service_load_items_sync (SecretService *self, /** * secret_service_search_sync: - * @self: the secret service + * @service: (allow-none): the secret service * @schema: (allow-none): the schema for the attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes * @flags: search option flags @@ -352,6 +393,9 @@ service_load_items_sync (SecretService *self, * Search for items matching the @attributes. All collections are searched. * The @attributes should be a table of string keys and string values. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the * search will be returned. Otherwise only the first item will be returned. * This is almost always the unlocked item that was most recently stored. @@ -372,7 +416,7 @@ service_load_items_sync (SecretService *self, * a list of items that matched the search */ GList * -secret_service_search_sync (SecretService *self, +secret_service_search_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, SecretSearchFlags flags, @@ -388,7 +432,7 @@ secret_service_search_sync (SecretService *self, gint want; gint have; - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); @@ -396,9 +440,19 @@ secret_service_search_sync (SecretService *self, if (schema != NULL && !_secret_attributes_validate (schema, attributes)) return NULL; - if (!secret_service_search_for_paths_sync (self, schema, attributes, cancellable, - &unlocked_paths, &locked_paths, error)) + if (service == NULL) { + service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error); + if (service == NULL) + return NULL; + } else { + g_object_ref (service); + } + + if (!secret_service_search_for_paths_sync (service, schema, attributes, cancellable, + &unlocked_paths, &locked_paths, error)) { + g_object_unref (service); return NULL; + } ret = TRUE; @@ -410,12 +464,12 @@ secret_service_search_sync (SecretService *self, /* Remember, we're adding to the list backwards */ if (unlocked_paths) { - ret = service_load_items_sync (self, cancellable, unlocked_paths, + ret = service_load_items_sync (service, cancellable, unlocked_paths, &unlocked, want, &have, error); } if (ret && locked_paths) { - ret = service_load_items_sync (self, cancellable, locked_paths, + ret = service_load_items_sync (service, cancellable, locked_paths, &locked, want, &have, error); } @@ -425,6 +479,7 @@ secret_service_search_sync (SecretService *self, if (!ret) { g_list_free_full (unlocked, g_object_unref); g_list_free_full (locked, g_object_unref); + g_object_unref (service); return NULL; } @@ -434,13 +489,14 @@ secret_service_search_sync (SecretService *self, items = g_list_reverse (items); if (flags & SECRET_SEARCH_UNLOCK) - secret_service_unlock_sync (self, locked, cancellable, NULL, NULL); + secret_service_unlock_sync (service, locked, cancellable, NULL, NULL); if (flags & SECRET_SEARCH_LOAD_SECRETS) secret_item_load_secrets_sync (items, NULL, NULL); g_list_free (locked); g_list_free (unlocked); + g_object_unref (service); return items; } @@ -490,6 +546,8 @@ _secret_service_decode_get_secrets_all (SecretService *self, } typedef struct { + GCancellable *cancellable; + GPtrArray *paths; GHashTable *objects; gchar **xlocked; guint count; @@ -500,6 +558,9 @@ static void xlock_closure_free (gpointer data) { XlockClosure *closure = data; + if (closure->cancellable) + g_object_unref (closure->cancellable); + g_ptr_array_free (closure->paths, TRUE); g_strfreev (closure->xlocked); g_hash_table_unref (closure->objects); g_slice_free (XlockClosure, closure); @@ -544,7 +605,33 @@ on_xlock_paths (GObject *source, } static void -service_xlock_async (SecretService *self, +on_xlock_service (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + XlockClosure *xlock = g_simple_async_result_get_op_res_gpointer (async); + GError *error = NULL; + SecretService *service; + + service = secret_service_get_finish (result, &error); + if (error == NULL) { + _secret_service_xlock_paths_async (service, xlock->locking ? "Lock" : "Unlock", + (const gchar **)xlock->paths->pdata, + xlock->cancellable, on_xlock_paths, + g_object_ref (async)); + g_object_unref (service); + + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (async); +} + +static void +service_xlock_async (SecretService *service, gboolean locking, GList *objects, GCancellable *cancellable, @@ -553,37 +640,41 @@ service_xlock_async (SecretService *self, { GSimpleAsyncResult *async; XlockClosure *xlock; - GPtrArray *paths; const gchar *path; GList *l; - async = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + async = g_simple_async_result_new (G_OBJECT (service), callback, user_data, service_xlock_async); xlock = g_slice_new0 (XlockClosure); xlock->objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); xlock->locking = locking; + xlock->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + xlock->paths = g_ptr_array_new (); - paths = g_ptr_array_new (); for (l = objects; l != NULL; l = g_list_next (l)) { path = g_dbus_proxy_get_object_path (l->data); - g_ptr_array_add (paths, (gpointer)path); + g_ptr_array_add (xlock->paths, (gpointer)path); g_hash_table_insert (xlock->objects, g_strdup (path), g_object_ref (l->data)); } - g_ptr_array_add (paths, NULL); + g_ptr_array_add (xlock->paths, NULL); g_simple_async_result_set_op_res_gpointer (async, xlock, xlock_closure_free); - _secret_service_xlock_paths_async (self, locking ? "Lock" : "Unlock", - (const gchar **)paths->pdata, - cancellable, on_xlock_paths, - g_object_ref (async)); + if (service == NULL) { + secret_service_get (SECRET_SERVICE_NONE, cancellable, + on_xlock_service, g_object_ref (async)); + } else { + _secret_service_xlock_paths_async (service, xlock->locking ? "Lock" : "Unlock", + (const gchar **)xlock->paths->pdata, + xlock->cancellable, on_xlock_paths, + g_object_ref (async)); + } - g_ptr_array_free (paths, TRUE); g_object_unref (async); } static gint -service_xlock_finish (SecretService *self, +service_xlock_finish (SecretService *service, GAsyncResult *result, GList **xlocked, GError **error) @@ -593,7 +684,8 @@ service_xlock_finish (SecretService *self, GDBusProxy *object; gint i; - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), service_xlock_async), -1); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service), + service_xlock_async), -1); async = G_SIMPLE_ASYNC_RESULT (result); if (g_simple_async_result_propagate_error (async, error)) @@ -614,7 +706,7 @@ service_xlock_finish (SecretService *self, /** * secret_service_lock: - * @self: the secret service + * @service: (allow-none): the secret service * @objects: (element-type GLib.DBusProxy): the items or collections to lock * @cancellable: optional cancellation object * @callback: called when the operation completes @@ -629,26 +721,29 @@ service_xlock_finish (SecretService *self, * The secret service may not be able to lock items individually, and may * lock an entire collection instead. * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * * 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 (SecretService *self, +secret_service_lock (SecretService *service, GList *objects, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { - g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - service_xlock_async (self, TRUE, objects, cancellable, callback, user_data); + service_xlock_async (service, TRUE, objects, cancellable, callback, user_data); } /** * secret_service_lock_finish: - * @self: the secret service + * @service: (allow-none): the secret service * @result: asynchronous result passed to the callback * @locked: (out) (element-type GLib.DBusProxy) (transfer full) (allow-none): * location to place list of items or collections that were locked @@ -663,20 +758,20 @@ secret_service_lock (SecretService *self, * Returns: the number of items or collections that were locked */ gint -secret_service_lock_finish (SecretService *self, +secret_service_lock_finish (SecretService *service, GAsyncResult *result, GList **locked, GError **error) { - g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); - return service_xlock_finish (self, result, locked, error); + return service_xlock_finish (service, result, locked, error); } /** * secret_service_lock_sync: - * @self: the secret service + * @service: (allow-none): the secret service * @objects: (element-type GLib.DBusProxy): the items or collections to lock * @cancellable: optional cancellation object * @locked: (out) (element-type GLib.DBusProxy) (transfer full) (allow-none): @@ -692,6 +787,9 @@ secret_service_lock_finish (SecretService *self, * The secret service may not be able to lock items individually, and may * lock an entire collection instead. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * 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. @@ -699,7 +797,7 @@ secret_service_lock_finish (SecretService *self, * Returns: the number of items or collections that were locked */ gint -secret_service_lock_sync (SecretService *self, +secret_service_lock_sync (SecretService *service, GList *objects, GCancellable *cancellable, GList **locked, @@ -708,19 +806,19 @@ secret_service_lock_sync (SecretService *self, SecretSync *sync; gint count; - g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -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 (self, objects, cancellable, - _secret_sync_on_result, sync); + secret_service_lock (service, objects, cancellable, + _secret_sync_on_result, sync); g_main_loop_run (sync->loop); - count = secret_service_lock_finish (self, sync->result, locked, error); + count = secret_service_lock_finish (service, sync->result, locked, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); @@ -730,7 +828,7 @@ secret_service_lock_sync (SecretService *self, /** * secret_service_unlock: - * @self: the secret service + * @service: (allow-none): the secret service * @objects: (element-type GLib.DBusProxy): the items or collections to unlock * @cancellable: optional cancellation object * @callback: called when the operation completes @@ -745,26 +843,29 @@ secret_service_lock_sync (SecretService *self, * The secret service may not be able to unlock items individually, and may * unlock an entire collection instead. * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * * 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. */ void -secret_service_unlock (SecretService *self, +secret_service_unlock (SecretService *service, GList *objects, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { - g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - service_xlock_async (self, FALSE, objects, cancellable, callback, user_data); + service_xlock_async (service, FALSE, objects, cancellable, callback, user_data); } /** * secret_service_unlock_finish: - * @self: the secret service + * @service: (allow-none): the secret service * @result: asynchronous result passed to the callback * @unlocked: (out) (element-type GLib.DBusProxy) (transfer full) (allow-none): * location to place list of items or collections that were unlocked @@ -779,20 +880,20 @@ secret_service_unlock (SecretService *self, * Returns: the number of items or collections that were unlocked */ gint -secret_service_unlock_finish (SecretService *self, +secret_service_unlock_finish (SecretService *service, GAsyncResult *result, GList **unlocked, GError **error) { - g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1); g_return_val_if_fail (error == NULL || *error == NULL, -1); - return service_xlock_finish (self, result, unlocked, error); + return service_xlock_finish (service, result, unlocked, error); } /** * secret_service_unlock_sync: - * @self: the secret service + * @service: (allow-none): the secret service * @objects: (element-type GLib.DBusProxy): the items or collections to unlock * @cancellable: optional cancellation object * @unlocked: (out) (element-type GLib.DBusProxy) (transfer full) (allow-none): @@ -808,6 +909,9 @@ secret_service_unlock_finish (SecretService *self, * The secret service may not be able to unlock items individually, and may * unlock an entire collection instead. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * 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. @@ -815,7 +919,7 @@ secret_service_unlock_finish (SecretService *self, * Returns: the number of items or collections that were unlocked */ gint -secret_service_unlock_sync (SecretService *self, +secret_service_unlock_sync (SecretService *service, GList *objects, GCancellable *cancellable, GList **unlocked, @@ -824,20 +928,19 @@ secret_service_unlock_sync (SecretService *self, SecretSync *sync; gint count; - g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -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_unlock (self, objects, cancellable, - _secret_sync_on_result, sync); + secret_service_unlock (service, objects, cancellable, + _secret_sync_on_result, sync); g_main_loop_run (sync->loop); - count = secret_service_unlock_finish (self, sync->result, - unlocked, error); + count = secret_service_unlock_finish (service, sync->result, unlocked, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); @@ -845,9 +948,72 @@ secret_service_unlock_sync (SecretService *self, return count; } +typedef struct { + GCancellable *cancellable; + gchar *collection_path; + SecretValue *value; + GHashTable *properties; +} StoreClosure; + +static void +store_closure_free (gpointer data) +{ + StoreClosure *store = data; + if (store->cancellable) + g_object_unref (store->cancellable); + g_free (store->collection_path); + secret_value_unref (store->value); + g_hash_table_unref (store->properties); + g_slice_free (StoreClosure, store); +} + +static void +on_store_create (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + GError *error = NULL; + gchar *path; + + path = secret_service_create_item_path_finish (SECRET_SERVICE (source), result, &error); + if (error != NULL) + g_simple_async_result_take_error (async, error); + g_free (path); + + g_simple_async_result_complete (async); + g_object_unref (async); +} + +static void +on_store_service (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + StoreClosure *store = g_simple_async_result_get_op_res_gpointer (async); + SecretService *service; + GError *error = NULL; + + service = secret_service_get_finish (result, &error); + if (error == NULL) { + secret_service_create_item_path (service, store->collection_path, + store->properties, store->value, + TRUE, store->cancellable, + on_store_create, g_object_ref (async)); + g_object_unref (service); + + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (async); +} + /** * secret_service_store: - * @self: the secret service + * @service: (allow-none): the secret service * @schema: (allow-none): the schema to use to check attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @collection_path: (allow-none): the D-Bus path to the collection where to store the secret @@ -864,6 +1030,9 @@ secret_service_unlock_sync (SecretService *self, * If the attributes match a secret item already stored in the collection, then * the item will be updated with these new values. * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * * If @collection_path is not specified, 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. @@ -871,7 +1040,7 @@ secret_service_unlock_sync (SecretService *self, * This method will return immediately and complete asynchronously. */ void -secret_service_store (SecretService *self, +secret_service_store (SecretService *service, const SecretSchema *schema, GHashTable *attributes, const gchar *collection_path, @@ -881,11 +1050,12 @@ secret_service_store (SecretService *self, GAsyncReadyCallback callback, gpointer user_data) { + GSimpleAsyncResult *async; + StoreClosure *store; const gchar *schema_name; - GHashTable *properties; GVariant *propval; - g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (attributes != NULL); g_return_if_fail (label != NULL); g_return_if_fail (value != NULL); @@ -895,30 +1065,46 @@ secret_service_store (SecretService *self, if (schema != NULL && !_secret_attributes_validate (schema, attributes)) return; - properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify)g_variant_unref); + async = g_simple_async_result_new (G_OBJECT (service), callback, user_data, + secret_service_store); + store = g_slice_new0 (StoreClosure); + store->collection_path = g_strdup (collection_path); + store->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + store->value = secret_value_ref (value); + store->properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify)g_variant_unref); propval = g_variant_new_string (label); - g_hash_table_insert (properties, + g_hash_table_insert (store->properties, SECRET_ITEM_INTERFACE ".Label", g_variant_ref_sink (propval)); /* Always store the schema name in the attributes */ schema_name = (schema == NULL) ? NULL : schema->name; propval = _secret_attributes_to_variant (attributes, schema_name); - g_hash_table_insert (properties, + g_hash_table_insert (store->properties, SECRET_ITEM_INTERFACE ".Attributes", g_variant_ref_sink (propval)); - secret_service_create_item_path (self, collection_path, properties, value, - TRUE, cancellable, callback, user_data); + g_simple_async_result_set_op_res_gpointer (async, store, store_closure_free); - g_hash_table_unref (properties); + if (service == NULL) { + secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable, + on_store_service, g_object_ref (async)); + + } else { + secret_service_create_item_path (service, store->collection_path, + store->properties, store->value, + TRUE, store->cancellable, + on_store_create, g_object_ref (async)); + } + + g_object_unref (async); } /** * secret_service_store_finish: - * @self: the secret service + * @service: (allow-none): the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * @@ -927,24 +1113,24 @@ secret_service_store (SecretService *self, * Returns: whether the storage was successful or not */ gboolean -secret_service_store_finish (SecretService *self, +secret_service_store_finish (SecretService *service, GAsyncResult *result, GError **error) { - gchar *path; - - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service), + secret_service_store), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - path = secret_service_create_item_path_finish (self, result, error); + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return FALSE; - g_free (path); - return path != NULL; + return TRUE; } /** * secret_service_store_sync: - * @self: the secret service + * @service: (allow-none): the secret service * @schema: (allow-none): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @collection_path: (allow-none): the D-Bus path to the collection where to store the secret @@ -964,13 +1150,16 @@ secret_service_store_finish (SecretService *self, * used. Use #SECRET_COLLECTION_SESSION to store the password in the session * collection, which doesn't get stored across login sessions. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the storage was successful or not */ gboolean -secret_service_store_sync (SecretService *self, +secret_service_store_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, const gchar *collection_path, @@ -982,7 +1171,7 @@ secret_service_store_sync (SecretService *self, SecretSync *sync; gboolean ret; - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); g_return_val_if_fail (attributes != NULL, FALSE); g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); @@ -996,12 +1185,12 @@ secret_service_store_sync (SecretService *self, sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); - secret_service_store (self, schema, attributes, collection_path, - label, value, cancellable, _secret_sync_on_result, sync); + secret_service_store (service, schema, attributes, collection_path, + label, value, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); - ret = secret_service_store_finish (self, sync->result, error); + ret = secret_service_store_finish (service, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); @@ -1010,6 +1199,7 @@ secret_service_store_sync (SecretService *self, } typedef struct { + GVariant *attributes; SecretValue *value; GCancellable *cancellable; } LookupClosure; @@ -1018,6 +1208,7 @@ static void lookup_closure_free (gpointer data) { LookupClosure *closure = data; + g_variant_unref (closure->attributes); if (closure->value) secret_value_unref (closure->value); g_clear_object (&closure->cancellable); @@ -1112,9 +1303,34 @@ on_lookup_searched (GObject *source, g_object_unref (res); } +static void +on_lookup_service (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + LookupClosure *lookup = g_simple_async_result_get_op_res_gpointer (async); + SecretService *service; + GError *error = NULL; + + service = secret_service_get_finish (result, &error); + if (error == NULL) { + _secret_service_search_for_paths_variant (service, lookup->attributes, + lookup->cancellable, + on_lookup_searched, g_object_ref (async)); + g_object_unref (service); + + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (async); +} + /** * secret_service_lookup: - * @self: the secret service + * @service: (allow-none): the secret service * @schema: (allow-none): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object @@ -1125,10 +1341,13 @@ on_lookup_searched (GObject *source, * * The @attributes should be a set of key and value string pairs. * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * * This method will return immediately and complete asynchronously. */ void -secret_service_lookup (SecretService *self, +secret_service_lookup (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, @@ -1138,9 +1357,8 @@ secret_service_lookup (SecretService *self, const gchar *schema_name = NULL; GSimpleAsyncResult *res; LookupClosure *closure; - GVariant *variant; - g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -1148,25 +1366,32 @@ secret_service_lookup (SecretService *self, if (schema != NULL && !_secret_attributes_validate (schema, attributes)) return; - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) + schema_name = schema->name; + + res = g_simple_async_result_new (G_OBJECT (service), callback, user_data, secret_service_lookup); closure = g_slice_new0 (LookupClosure); closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + closure->attributes = _secret_attributes_to_variant (attributes, schema_name); + g_variant_ref_sink (closure->attributes); g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free); - if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) - schema_name = schema->name; - variant = _secret_attributes_to_variant (attributes, schema_name); - - _secret_service_search_for_paths_variant (self, variant, cancellable, - on_lookup_searched, g_object_ref (res)); + if (service == NULL) { + secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable, + on_lookup_service, g_object_ref (res)); + } else { + _secret_service_search_for_paths_variant (service, closure->attributes, + closure->cancellable, + on_lookup_searched, g_object_ref (res)); + } g_object_unref (res); } /** * secret_service_lookup_finish: - * @self: the secret service + * @service: (allow-none): the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * @@ -1178,7 +1403,7 @@ secret_service_lookup (SecretService *self, * released with secret_value_unref(), or %NULL if no secret found */ SecretValue * -secret_service_lookup_finish (SecretService *self, +secret_service_lookup_finish (SecretService *service, GAsyncResult *result, GError **error) { @@ -1186,9 +1411,9 @@ secret_service_lookup_finish (SecretService *self, LookupClosure *closure; SecretValue *value; - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service), secret_service_lookup), NULL); res = G_SIMPLE_ASYNC_RESULT (result); @@ -1203,7 +1428,7 @@ secret_service_lookup_finish (SecretService *self, /** * secret_service_lookup_sync: - * @self: the secret service + * @service: (allow-none): the secret service * @schema: (allow-none): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object @@ -1213,6 +1438,9 @@ secret_service_lookup_finish (SecretService *self, * * The @attributes should be a set of key and value string pairs. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * This method may block indefinitely and should not be used in user interface * threads. * @@ -1220,7 +1448,7 @@ secret_service_lookup_finish (SecretService *self, * released with secret_value_unref(), or %NULL if no secret found */ SecretValue * -secret_service_lookup_sync (SecretService *self, +secret_service_lookup_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, @@ -1229,7 +1457,7 @@ secret_service_lookup_sync (SecretService *self, SecretSync *sync; SecretValue *value; - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); @@ -1240,12 +1468,12 @@ secret_service_lookup_sync (SecretService *self, sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); - secret_service_lookup (self, schema, attributes, cancellable, + secret_service_lookup (service, schema, attributes, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); - value = secret_service_lookup_finish (self, sync->result, error); + value = secret_service_lookup_finish (service, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); @@ -1255,6 +1483,8 @@ secret_service_lookup_sync (SecretService *self, typedef struct { GCancellable *cancellable; + SecretService *service; + GVariant *attributes; SecretPrompt *prompt; gboolean deleted; } DeleteClosure; @@ -1263,6 +1493,9 @@ static void delete_closure_free (gpointer data) { DeleteClosure *closure = data; + if (closure->service) + g_object_unref (closure->service); + g_variant_unref (closure->attributes); g_clear_object (&closure->prompt); g_clear_object (&closure->cancellable); g_slice_free (DeleteClosure, closure); @@ -1274,34 +1507,31 @@ on_delete_password_complete (GObject *source, gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data)); DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GError *error = NULL; - closure->deleted = secret_service_delete_path_finish (self, result, &error); + closure->deleted = secret_service_delete_path_finish (SECRET_SERVICE (source), result, &error); if (error != NULL) 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_search_delete_password (GObject *source, - GAsyncResult *result, - gpointer user_data) +on_delete_searched (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 *path = NULL; GError *error = NULL; gchar **locked; gchar **unlocked; - secret_service_search_for_paths_finish (self, result, &unlocked, &locked, &error); + secret_service_search_for_paths_finish (SECRET_SERVICE (source), result, &unlocked, &locked, &error); if (error != NULL) { g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); @@ -1321,7 +1551,7 @@ on_search_delete_password (GObject *source, /* Delete the first path */ } else { closure->deleted = TRUE; - _secret_service_delete_path (self, path, TRUE, + _secret_service_delete_path (closure->service, path, TRUE, closure->cancellable, on_delete_password_complete, g_object_ref (res)); @@ -1330,13 +1560,35 @@ on_search_delete_password (GObject *source, g_strfreev (locked); g_strfreev (unlocked); - g_object_unref (self); g_object_unref (res); } +static void +on_delete_service (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (async); + GError *error = NULL; + + closure->service = secret_service_get_finish (result, &error); + if (error == NULL) { + _secret_service_search_for_paths_variant (closure->service, closure->attributes, + closure->cancellable, + on_delete_searched, g_object_ref (async)); + + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (async); +} + /** * secret_service_remove: - * @self: the secret service + * @service: (allow-none): the secret service * @schema: (allow-none): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object @@ -1349,10 +1601,13 @@ on_search_delete_password (GObject *source, * * If multiple items match the attributes, then only one will be deleted. * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * * This method will return immediately and complete asynchronously. */ void -secret_service_remove (SecretService *self, +secret_service_remove (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, @@ -1362,9 +1617,8 @@ secret_service_remove (SecretService *self, const gchar *schema_name = NULL; GSimpleAsyncResult *res; DeleteClosure *closure; - GVariant *variant; - g_return_if_fail (SECRET_SERVICE (self)); + g_return_if_fail (service == NULL || SECRET_SERVICE (service)); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -1372,25 +1626,33 @@ secret_service_remove (SecretService *self, if (schema != NULL && !_secret_attributes_validate (schema, attributes)) return; - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) + schema_name = schema->name; + + res = g_simple_async_result_new (G_OBJECT (service), callback, user_data, secret_service_remove); closure = g_slice_new0 (DeleteClosure); closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + closure->attributes = _secret_attributes_to_variant (attributes, schema_name); + g_variant_ref_sink (closure->attributes); g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free); - if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME)) - schema_name = schema->name; - variant = _secret_attributes_to_variant (attributes, schema_name); - - _secret_service_search_for_paths_variant (self, variant, cancellable, - on_search_delete_password, g_object_ref (res)); + if (service == NULL) { + secret_service_get (SECRET_SERVICE_NONE, cancellable, + on_delete_service, g_object_ref (res)); + } else { + closure->service = g_object_ref (service); + _secret_service_search_for_paths_variant (closure->service, closure->attributes, + closure->cancellable, + on_delete_searched, g_object_ref (res)); + } g_object_unref (res); } /** * secret_service_remove_finish: - * @self: the secret service + * @service: (allow-none): the secret service * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * @@ -1400,16 +1662,16 @@ secret_service_remove (SecretService *self, * Returns: whether the removal was successful or not */ gboolean -secret_service_remove_finish (SecretService *self, +secret_service_remove_finish (SecretService *service, GAsyncResult *result, GError **error) { GSimpleAsyncResult *res; DeleteClosure *closure; - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), 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), + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service), secret_service_remove), FALSE); res = G_SIMPLE_ASYNC_RESULT (result); @@ -1422,7 +1684,7 @@ secret_service_remove_finish (SecretService *self, /** * secret_service_remove_sync: - * @self: the secret service + * @service: (allow-none): the secret service * @schema: (allow-none): the schema for the attributes * @attributes: (element-type utf8 utf8): the attribute keys and values * @cancellable: optional cancellation object @@ -1434,13 +1696,16 @@ secret_service_remove_finish (SecretService *self, * * If multiple items match the attributes, then only one will be deleted. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * This method may block indefinitely and should not be used in user interface * threads. * * Returns: whether the removal was successful or not */ gboolean -secret_service_remove_sync (SecretService *self, +secret_service_remove_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, @@ -1449,7 +1714,7 @@ secret_service_remove_sync (SecretService *self, SecretSync *sync; gboolean result; - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -1460,12 +1725,12 @@ secret_service_remove_sync (SecretService *self, sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); - secret_service_remove (self, schema, attributes, cancellable, + secret_service_remove (service, schema, attributes, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); - result = secret_service_remove_finish (self, sync->result, error); + result = secret_service_remove_finish (service, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); @@ -1475,6 +1740,7 @@ secret_service_remove_sync (SecretService *self, typedef struct { GCancellable *cancellable; + gchar *alias; SecretCollection *collection; } ReadClosure; @@ -1482,6 +1748,7 @@ static void read_closure_free (gpointer data) { ReadClosure *read = data; + g_free (read->alias); if (read->collection) g_object_unref (read->collection); if (read->cancellable) @@ -1547,9 +1814,33 @@ on_read_alias_path (GObject *source, g_object_unref (async); } +static void +on_read_alias_service (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + ReadClosure *read = g_simple_async_result_get_op_res_gpointer (async); + SecretService *service; + GError *error = NULL; + + service = secret_service_get_finish (result, &error); + if (error == NULL) { + secret_service_read_alias_path (service, read->alias, read->cancellable, + on_read_alias_path, g_object_ref (async)); + g_object_unref (service); + + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (async); +} + /** * secret_service_read_alias: - * @self: a secret service object + * @service: (allow-none): a secret service object * @alias: the alias to lookup * @cancellable: (allow-none): optional cancellation object * @callback: called when the operation completes @@ -1558,10 +1849,13 @@ on_read_alias_path (GObject *source, * Lookup which collection is assigned to this alias. Aliases help determine * well known collections, such as 'default'. * + * If @service is NULL, then secret_service_get() will be called to get + * the default #SecretService proxy. + * * This method will return immediately and complete asynchronously. */ void -secret_service_read_alias (SecretService *self, +secret_service_read_alias (SecretService *service, const gchar *alias, GCancellable *cancellable, GAsyncReadyCallback callback, @@ -1570,25 +1864,31 @@ secret_service_read_alias (SecretService *self, GSimpleAsyncResult *async; ReadClosure *read; - g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (alias != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - async = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + async = g_simple_async_result_new (G_OBJECT (service), callback, user_data, secret_service_read_alias); read = g_slice_new0 (ReadClosure); read->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + read->alias = g_strdup (alias); g_simple_async_result_set_op_res_gpointer (async, read, read_closure_free); - secret_service_read_alias_path (self, alias, cancellable, - on_read_alias_path, g_object_ref (async)); + if (service == NULL) { + secret_service_get (SECRET_SERVICE_NONE, cancellable, + on_read_alias_service, g_object_ref (async)); + } else { + secret_service_read_alias_path (service, read->alias, read->cancellable, + on_read_alias_path, g_object_ref (async)); + } g_object_unref (async); } /** * secret_service_read_alias_finish: - * @self: a secret service object + * @service: (allow-none): a secret service object * @result: asynchronous result passed to callback * @error: location to place error on failure * @@ -1598,15 +1898,15 @@ secret_service_read_alias (SecretService *self, * Returns: (transfer full): the collection, or %NULL if none assigned to the alias */ SecretCollection * -secret_service_read_alias_finish (SecretService *self, +secret_service_read_alias_finish (SecretService *service, GAsyncResult *result, GError **error) { GSimpleAsyncResult *async; ReadClosure *read; - 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), + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service), secret_service_read_alias), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); @@ -1621,7 +1921,7 @@ secret_service_read_alias_finish (SecretService *self, /** * secret_service_read_alias_sync: - * @self: a secret service object + * @service: (allow-none): a secret service object * @alias: the alias to lookup * @cancellable: (allow-none): optional cancellation object * @error: location to place error on failure @@ -1629,12 +1929,15 @@ secret_service_read_alias_finish (SecretService *self, * Lookup which collection is assigned to this alias. Aliases help determine * well known collections, such as 'default'. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * This method may block and should not be used in user interface threads. * * Returns: (transfer full): the collection, or %NULL if none assigned to the alias */ SecretCollection * -secret_service_read_alias_sync (SecretService *self, +secret_service_read_alias_sync (SecretService *service, const gchar *alias, GCancellable *cancellable, GError **error) @@ -1642,12 +1945,12 @@ secret_service_read_alias_sync (SecretService *self, SecretCollection *collection; gchar *collection_path; - g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), 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); - collection_path = secret_service_read_alias_path_sync (self, alias, + collection_path = secret_service_read_alias_path_sync (service, alias, cancellable, error); if (collection_path == NULL) return NULL; @@ -1657,12 +1960,12 @@ secret_service_read_alias_sync (SecretService *self, collection = NULL; } else { - collection = _secret_service_find_collection_instance (self, + collection = _secret_service_find_collection_instance (service, collection_path); /* No collection loaded, but valid path, load */ if (collection == NULL) { - collection = secret_collection_new_sync (self, collection_path, + collection = secret_collection_new_sync (service, collection_path, SECRET_COLLECTION_LOAD_ITEMS, cancellable, error); } @@ -1674,7 +1977,7 @@ secret_service_read_alias_sync (SecretService *self, /** * secret_service_set_alias: - * @self: a secret service object + * @service: (allow-none): a secret service object * @alias: the alias to assign the collection to * @collection: (allow-none): the collection to assign to the alias * @cancellable: (allow-none): optional cancellation object @@ -1684,10 +1987,13 @@ secret_service_read_alias_sync (SecretService *self, * Assign a collection to this alias. Aliases help determine * well known collections, such as 'default'. * + * If @service is NULL, then secret_collection_get_service() will be called to get + * a #SecretService proxy. + * * This method will return immediately and complete asynchronously. */ void -secret_service_set_alias (SecretService *self, +secret_service_set_alias (SecretService *service, const gchar *alias, SecretCollection *collection, GCancellable *cancellable, @@ -1696,7 +2002,7 @@ secret_service_set_alias (SecretService *self, { const gchar *collection_path; - g_return_if_fail (SECRET_IS_SERVICE (self)); + g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service)); g_return_if_fail (alias != NULL); g_return_if_fail (collection == NULL || SECRET_IS_COLLECTION (collection)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -1708,13 +2014,22 @@ secret_service_set_alias (SecretService *self, collection_path = NULL; } - secret_service_set_alias_path (self, alias, collection_path, cancellable, + if (service == NULL) { + service = secret_collection_get_service (collection); + g_return_if_fail (service != NULL); + } else { + g_object_ref (service); + } + + secret_service_set_alias_path (service, alias, collection_path, cancellable, callback, user_data); + + g_object_unref (service); } /** * secret_service_set_alias_finish: - * @self: a secret service object + * @service: (allow-none): a secret service object * @result: asynchronous result passed to callback * @error: location to place error on failure * @@ -1723,19 +2038,30 @@ secret_service_set_alias (SecretService *self, * Returns: %TRUE if successful */ gboolean -secret_service_set_alias_finish (SecretService *self, +secret_service_set_alias_finish (SecretService *service, GAsyncResult *result, GError **error) { - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + gboolean ret; + + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - return secret_service_set_alias_path_finish (self, result, error); + if (service == NULL) + service = SECRET_SERVICE (g_async_result_get_source_object (result)); + else + g_object_ref (service); + + ret = secret_service_set_alias_path_finish (service, result, error); + + g_object_unref (service); + + return ret; } /** * secret_service_set_alias_sync: - * @self: a secret service object + * @service: (allow-none): a secret service object * @alias: the alias to assign the collection to * @collection: (allow-none): the collection to assign to the alias * @cancellable: (allow-none): optional cancellation object @@ -1744,12 +2070,15 @@ secret_service_set_alias_finish (SecretService *self, * Assign a collection to this alias. Aliases help determine * well known collections, such as 'default'. * + * If @service is NULL, then secret_service_get_sync() will be called to get + * the default #SecretService proxy. + * * This method may block and should not be used in user interface threads. * * Returns: %TRUE if successful */ gboolean -secret_service_set_alias_sync (SecretService *self, +secret_service_set_alias_sync (SecretService *service, const gchar *alias, SecretCollection *collection, GCancellable *cancellable, @@ -1758,7 +2087,7 @@ secret_service_set_alias_sync (SecretService *self, SecretSync *sync; gboolean ret; - g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), 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); @@ -1766,12 +2095,12 @@ secret_service_set_alias_sync (SecretService *self, sync = _secret_sync_new (); g_main_context_push_thread_default (sync->context); - secret_service_set_alias (self, alias, collection, cancellable, + secret_service_set_alias (service, alias, collection, cancellable, _secret_sync_on_result, sync); g_main_loop_run (sync->loop); - ret = secret_service_set_alias_finish (self, sync->result, error); + ret = secret_service_set_alias_finish (service, sync->result, error); g_main_context_pop_thread_default (sync->context); _secret_sync_free (sync); diff --git a/library/secret-password.c b/library/secret-password.c index 0f34010..b27c44e 100644 --- a/library/secret-password.c +++ b/library/secret-password.c @@ -42,76 +42,6 @@ * Stability: Stable */ -typedef struct { - const SecretSchema *schema; - GHashTable *attributes; - gchar *collection_path; - gchar *label; - SecretValue *value; - GCancellable *cancellable; - gboolean created; -} StoreClosure; - -static void -store_closure_free (gpointer data) -{ - StoreClosure *closure = data; - _secret_schema_unref_if_nonstatic (closure->schema); - g_hash_table_unref (closure->attributes); - g_free (closure->collection_path); - g_free (closure->label); - secret_value_unref (closure->value); - g_clear_object (&closure->cancellable); - g_slice_free (StoreClosure, closure); -} - -static void -on_store_complete (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - GError *error = NULL; - - closure->created = secret_service_store_finish (SECRET_SERVICE (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_store_connected (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - SecretService *service; - GError *error = NULL; - - service = secret_service_get_finish (result, &error); - if (error == NULL) { - secret_service_store (service, closure->schema, - closure->attributes, - closure->collection_path, - closure->label, closure->value, - closure->cancellable, - on_store_complete, - g_object_ref (res)); - g_object_unref (service); - - } else { - g_simple_async_result_take_error (res, error); - g_simple_async_result_complete (res); - } - - g_object_unref (res); -} - /** * secret_password_store: (skip) * @schema: the schema for attributes @@ -203,8 +133,7 @@ secret_password_storev (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; - StoreClosure *closure; + SecretValue *value; g_return_if_fail (schema != NULL); g_return_if_fail (label != NULL); @@ -216,21 +145,12 @@ secret_password_storev (const SecretSchema *schema, if (!_secret_attributes_validate (schema, attributes)) return; - res = g_simple_async_result_new (NULL, callback, user_data, - secret_password_storev); - closure = g_slice_new0 (StoreClosure); - closure->schema = _secret_schema_ref_if_nonstatic (schema); - closure->collection_path = g_strdup (collection_path); - closure->label = g_strdup (label); - closure->value = secret_value_new (password, -1, "text/plain"); - closure->attributes = _secret_attributes_copy (attributes); - closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - g_simple_async_result_set_op_res_gpointer (res, closure, store_closure_free); + value = secret_value_new (password, -1, "text/plain"); - secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable, - on_store_connected, g_object_ref (res)); + secret_service_store (NULL, schema, attributes, collection_path, + label, value, cancellable, callback, user_data); - g_object_unref (res); + secret_value_unref (value); } /** @@ -246,19 +166,8 @@ gboolean secret_password_store_finish (GAsyncResult *result, GError **error) { - GSimpleAsyncResult *res; - StoreClosure *closure; - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, - secret_password_storev), 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->created; + return secret_service_store_finish (NULL, result, error); } /** @@ -387,25 +296,6 @@ secret_password_storev_sync (const SecretSchema *schema, return ret; } -typedef struct { - GCancellable *cancellable; - GHashTable *attributes; - SecretValue *value; - const SecretSchema *schema; -} LookupClosure; - -static void -lookup_closure_free (gpointer data) -{ - LookupClosure *closure = data; - _secret_schema_unref_if_nonstatic (closure->schema); - g_clear_object (&closure->cancellable); - g_hash_table_unref (closure->attributes); - if (closure->value) - secret_value_unref (closure->value); - g_slice_free (LookupClosure, closure); -} - /** * secret_password_lookup: (skip) * @schema: the schema for the attributes @@ -448,50 +338,6 @@ secret_password_lookup (const SecretSchema *schema, g_hash_table_unref (attributes); } -static void -on_lookup_complete (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - GError *error = NULL; - - closure->value = secret_service_lookup_finish (SECRET_SERVICE (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_lookup_connected (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - SecretService *service; - GError *error = NULL; - - service = secret_service_get_finish (result, &error); - if (error != NULL) { - g_simple_async_result_take_error (res, error); - g_simple_async_result_complete (res); - - } else { - secret_service_lookup (service, closure->schema, closure->attributes, - closure->cancellable, on_lookup_complete, - g_object_ref (res)); - g_object_unref (service); - } - - g_object_unref (res); -} - /** * secret_password_lookupv: * @schema: the schema for attributes @@ -517,9 +363,6 @@ secret_password_lookupv (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; - LookupClosure *closure; - g_return_if_fail (schema != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -528,18 +371,8 @@ secret_password_lookupv (const SecretSchema *schema, if (!_secret_attributes_validate (schema, attributes)) return; - res = g_simple_async_result_new (NULL, callback, user_data, - secret_password_lookupv); - closure = g_slice_new0 (LookupClosure); - closure->schema = _secret_schema_ref_if_nonstatic (schema); - closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - closure->attributes = _secret_attributes_copy (attributes); - g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free); - - secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable, - on_lookup_connected, g_object_ref (res)); - - g_object_unref (res); + secret_service_lookup (NULL, schema, attributes, + cancellable, callback, user_data); } /** @@ -556,25 +389,15 @@ gchar * secret_password_lookup_nonpageable_finish (GAsyncResult *result, GError **error) { - GSimpleAsyncResult *res; - LookupClosure *closure; - gchar *password = NULL; + SecretValue *value; g_return_val_if_fail (error == NULL || *error == NULL, NULL); - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, - secret_password_lookupv), NULL); - res = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (res, error)) + value = secret_service_lookup_finish (NULL, result, error); + if (value == NULL) return NULL; - closure = g_simple_async_result_get_op_res_gpointer (res); - if (closure->value == NULL) - return NULL; - - password = _secret_value_unref_to_password (closure->value); - closure->value = NULL; - return password; + return _secret_value_unref_to_password (value); } /** @@ -591,25 +414,15 @@ gchar * secret_password_lookup_finish (GAsyncResult *result, GError **error) { - GSimpleAsyncResult *res; - LookupClosure *closure; - gchar *string = NULL; + SecretValue *value; g_return_val_if_fail (error == NULL || *error == NULL, NULL); - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, - secret_password_lookupv), NULL); - res = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (res, error)) + value = secret_service_lookup_finish (NULL, result, error); + if (value == NULL) return NULL; - closure = g_simple_async_result_get_op_res_gpointer (res); - if (closure->value == NULL) - return NULL; - - string = _secret_value_unref_to_string (closure->value); - closure->value = NULL; - return string; + return _secret_value_unref_to_string (value); } /** @@ -816,23 +629,6 @@ secret_password_lookupv_sync (const SecretSchema *schema, return string; } -typedef struct { - GCancellable *cancellable; - GHashTable *attributes; - gboolean deleted; - const SecretSchema *schema; -} DeleteClosure; - -static void -delete_closure_free (gpointer data) -{ - DeleteClosure *closure = data; - g_clear_object (&closure->cancellable); - g_hash_table_unref (closure->attributes); - _secret_schema_unref_if_nonstatic (closure->schema); - g_slice_free (DeleteClosure, closure); -} - /** * secret_password_remove: * @schema: the schema for the attributes @@ -875,48 +671,6 @@ secret_password_remove (const SecretSchema *schema, g_hash_table_unref (attributes); } -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); - GError *error = NULL; - - closure->deleted = secret_service_remove_finish (SECRET_SERVICE (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_delete_connect (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 *service; - GError *error = NULL; - - service = secret_service_get_finish (result, &error); - if (error == NULL) { - secret_service_remove (service, closure->schema, closure->attributes, - closure->cancellable, on_delete_complete, - g_object_ref (res)); - g_object_unref (service); - - } else { - g_simple_async_result_take_error (res, error); - g_simple_async_result_complete (res); - } - - g_object_unref (res); -} /** * secret_password_removev: @@ -943,9 +697,6 @@ secret_password_removev (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; - DeleteClosure *closure; - g_return_if_fail (schema != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -954,18 +705,8 @@ secret_password_removev (const SecretSchema *schema, if (!_secret_attributes_validate (schema, attributes)) return; - res = g_simple_async_result_new (NULL, callback, user_data, - secret_password_removev); - closure = g_slice_new0 (DeleteClosure); - closure->schema = _secret_schema_ref_if_nonstatic (schema); - closure->attributes = _secret_attributes_copy (attributes); - closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free); - - secret_service_get (SECRET_SERVICE_NONE, cancellable, - on_delete_connect, g_object_ref (res)); - - g_object_unref (res); + secret_service_remove (NULL, schema, attributes, + cancellable, callback, user_data); } /** @@ -982,19 +723,8 @@ gboolean secret_password_remove_finish (GAsyncResult *result, GError **error) { - DeleteClosure *closure; - GSimpleAsyncResult *res; - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, - secret_password_removev), 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; + return secret_service_remove_finish (NULL, result, error); } /** diff --git a/library/secret-service.c b/library/secret-service.c index 4a2a273..c073f6b 100644 --- a/library/secret-service.c +++ b/library/secret-service.c @@ -653,18 +653,6 @@ _secret_service_set_default_bus_name (const gchar *bus_name) default_bus_name = bus_name; } -static void -on_service_instance_gone (gpointer user_data, - GObject *where_the_object_was) -{ - G_LOCK (service_instance); - - g_assert (service_instance == where_the_object_was); - service_instance = NULL; - - G_UNLOCK (service_instance); -} - /** * secret_service_get: * @flags: flags for which service functionality to ensure is initialized @@ -758,10 +746,8 @@ secret_service_get_finish (GAsyncResult *result, if (service) { G_LOCK (service_instance); - if (service_instance == NULL) { - service_instance = service; - g_object_weak_ref (G_OBJECT (service), on_service_instance_gone, NULL); - } + if (service_instance == NULL) + service_instance = g_object_ref (service); G_UNLOCK (service_instance); } } @@ -818,10 +804,8 @@ secret_service_get_sync (SecretServiceFlags flags, if (service != NULL) { G_LOCK (service_instance); - if (service_instance == NULL) { - service_instance = service; - g_object_weak_ref (G_OBJECT (service), on_service_instance_gone, NULL); - } + if (service_instance == NULL) + service_instance = g_object_ref (service); G_UNLOCK (service_instance); } @@ -835,6 +819,33 @@ secret_service_get_sync (SecretServiceFlags flags, return service; } +/** + * secret_service_disconnect: + * + * Disconnect the default #SecretService proxy returned by secret_service_get() + * and secret_service_get_sync(). + * + * It is not necessary to call this function, but you may choose to do so at + * program exit. It is useful for testing that memory is not leaked. + * + * This function is safe to call at any time. But if other objects in this + * library are still referenced, then this will not result in all memory + * being freed. + */ +void +secret_service_disconnect (void) +{ + SecretService *instance; + + G_LOCK (service_instance); + instance = service_instance; + service_instance = NULL; + G_UNLOCK (service_instance); + + if (instance != NULL) + g_object_unref (instance); +} + /** * secret_service_new: * @service_gtype: the GType of the new secret service diff --git a/library/secret-service.h b/library/secret-service.h index 6fae768..b4626be 100644 --- a/library/secret-service.h +++ b/library/secret-service.h @@ -100,6 +100,8 @@ SecretService * secret_service_get_sync (SecretService GCancellable *cancellable, GError **error); +void secret_service_disconnect (void); + void secret_service_new (GType service_gtype, const gchar *service_bus_name, SecretServiceFlags flags, @@ -150,59 +152,6 @@ gboolean secret_service_load_collections_sync (SecretService GCancellable *cancellable, GError **error); -void secret_service_search (SecretService *self, - const SecretSchema *schema, - GHashTable *attributes, - SecretSearchFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -GList * secret_service_search_finish (SecretService *self, - GAsyncResult *result, - GError **error); - -GList * secret_service_search_sync (SecretService *self, - const SecretSchema *schema, - GHashTable *attributes, - SecretSearchFlags flags, - GCancellable *cancellable, - GError **error); - -void secret_service_lock (SecretService *self, - GList *objects, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gint secret_service_lock_finish (SecretService *self, - GAsyncResult *result, - GList **locked, - GError **error); - -gint secret_service_lock_sync (SecretService *self, - GList *objects, - GCancellable *cancellable, - GList **locked, - GError **error); - -void secret_service_unlock (SecretService *self, - GList *objects, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gint secret_service_unlock_finish (SecretService *self, - GAsyncResult *result, - GList **unlocked, - GError **error); - -gint secret_service_unlock_sync (SecretService *self, - GList *objects, - GCancellable *cancellable, - GList **unlocked, - GError **error); - GVariant * secret_service_prompt_sync (SecretService *self, SecretPrompt *prompt, GCancellable *cancellable, @@ -220,7 +169,60 @@ GVariant * secret_service_prompt_finish (SecretService const GVariantType *return_type, GError **error); -void secret_service_store (SecretService *self, +void secret_service_search (SecretService *service, + const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GList * secret_service_search_finish (SecretService *service, + GAsyncResult *result, + GError **error); + +GList * secret_service_search_sync (SecretService *service, + const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GError **error); + +void secret_service_lock (SecretService *service, + GList *objects, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gint secret_service_lock_finish (SecretService *service, + GAsyncResult *result, + GList **locked, + GError **error); + +gint secret_service_lock_sync (SecretService *service, + GList *objects, + GCancellable *cancellable, + GList **locked, + GError **error); + +void secret_service_unlock (SecretService *service, + GList *objects, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gint secret_service_unlock_finish (SecretService *service, + GAsyncResult *result, + GList **unlocked, + GError **error); + +gint secret_service_unlock_sync (SecretService *service, + GList *objects, + GCancellable *cancellable, + GList **unlocked, + GError **error); + +void secret_service_store (SecretService *service, const SecretSchema *schema, GHashTable *attributes, const gchar *collection_path, @@ -230,11 +232,11 @@ void secret_service_store (SecretService GAsyncReadyCallback callback, gpointer user_data); -gboolean secret_service_store_finish (SecretService *self, +gboolean secret_service_store_finish (SecretService *service, GAsyncResult *result, GError **error); -gboolean secret_service_store_sync (SecretService *self, +gboolean secret_service_store_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, const gchar *collection_path, @@ -243,67 +245,67 @@ gboolean secret_service_store_sync (SecretService GCancellable *cancellable, GError **error); -void secret_service_lookup (SecretService *self, +void secret_service_lookup (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); -SecretValue * secret_service_lookup_finish (SecretService *self, +SecretValue * secret_service_lookup_finish (SecretService *service, GAsyncResult *result, GError **error); -SecretValue * secret_service_lookup_sync (SecretService *self, +SecretValue * secret_service_lookup_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); -void secret_service_remove (SecretService *self, +void secret_service_remove (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); -gboolean secret_service_remove_finish (SecretService *self, +gboolean secret_service_remove_finish (SecretService *service, GAsyncResult *result, GError **error); -gboolean secret_service_remove_sync (SecretService *self, +gboolean secret_service_remove_sync (SecretService *service, const SecretSchema *schema, GHashTable *attributes, GCancellable *cancellable, GError **error); -void secret_service_read_alias (SecretService *self, +void secret_service_read_alias (SecretService *service, const gchar *alias, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); -SecretCollection * secret_service_read_alias_finish (SecretService *self, +SecretCollection * secret_service_read_alias_finish (SecretService *service, GAsyncResult *result, GError **error); -SecretCollection * secret_service_read_alias_sync (SecretService *self, +SecretCollection * secret_service_read_alias_sync (SecretService *service, const gchar *alias, GCancellable *cancellable, GError **error); -void secret_service_set_alias (SecretService *self, +void secret_service_set_alias (SecretService *service, const gchar *alias, SecretCollection *collection, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); -gboolean secret_service_set_alias_finish (SecretService *self, +gboolean secret_service_set_alias_finish (SecretService *service, GAsyncResult *result, GError **error); -gboolean secret_service_set_alias_sync (SecretService *self, +gboolean secret_service_set_alias_sync (SecretService *service, const gchar *alias, SecretCollection *collection, GCancellable *cancellable, diff --git a/library/tests/test-collection.c b/library/tests/test-collection.c index 85acf8c..70e3998 100644 --- a/library/tests/test-collection.c +++ b/library/tests/test-collection.c @@ -51,6 +51,7 @@ teardown (Test *test, gconstpointer unused) { g_object_unref (test->service); + secret_service_disconnect (); egg_assert_not_object (test->service); mock_service_stop (); diff --git a/library/tests/test-item.c b/library/tests/test-item.c index d0c55c0..1a58907 100644 --- a/library/tests/test-item.c +++ b/library/tests/test-item.c @@ -52,6 +52,7 @@ teardown (Test *test, gconstpointer unused) { g_object_unref (test->service); + secret_service_disconnect (); egg_assert_not_object (test->service); mock_service_stop (); diff --git a/library/tests/test-methods.c b/library/tests/test-methods.c index 0cefcd4..b000b56 100644 --- a/library/tests/test-methods.c +++ b/library/tests/test-methods.c @@ -99,6 +99,7 @@ teardown (Test *test, egg_test_wait_idle (); g_object_unref (test->service); + secret_service_disconnect (); egg_assert_not_object (test->service); teardown_mock (test, unused); diff --git a/library/tests/test-password.c b/library/tests/test-password.c index d5829df..d541daf 100644 --- a/library/tests/test-password.c +++ b/library/tests/test-password.c @@ -74,6 +74,7 @@ static void teardown (Test *test, gconstpointer unused) { + secret_service_disconnect (); mock_service_stop (); } diff --git a/library/tests/test-paths.c b/library/tests/test-paths.c index b29ab3e..2a6f04d 100644 --- a/library/tests/test-paths.c +++ b/library/tests/test-paths.c @@ -99,6 +99,7 @@ teardown (Test *test, egg_test_wait_idle (); g_object_unref (test->service); + secret_service_disconnect (); egg_assert_not_object (test->service); teardown_mock (test, unused); diff --git a/library/tests/test-prompt.c b/library/tests/test-prompt.c index 9a7fd29..0bc03dd 100644 --- a/library/tests/test-prompt.c +++ b/library/tests/test-prompt.c @@ -52,6 +52,7 @@ teardown (Test *test, gconstpointer unused) { g_object_unref (test->service); + secret_service_disconnect (); egg_assert_not_object (test->service); mock_service_stop (); diff --git a/library/tests/test-service.c b/library/tests/test-service.c index e78fbe6..85820e4 100644 --- a/library/tests/test-service.c +++ b/library/tests/test-service.c @@ -84,14 +84,16 @@ test_get_sync (void) g_assert (G_IS_OBJECT (service1)); g_object_unref (service2); + secret_service_disconnect (); egg_assert_not_object (service2); - /* Services were unreffed, so this should create a new one */ + /* Services were disconnected, so this should create a new one */ service3 = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); g_assert (SECRET_IS_SERVICE (service3)); g_assert_no_error (error); g_object_unref (service3); + secret_service_disconnect (); egg_assert_not_object (service3); } @@ -127,6 +129,7 @@ test_get_async (void) g_assert (G_IS_OBJECT (service1)); g_object_unref (service2); + secret_service_disconnect (); egg_assert_not_object (service2); /* Services were unreffed, so this should create a new one */ @@ -138,6 +141,7 @@ test_get_async (void) g_clear_object (&result); g_object_unref (service3); + secret_service_disconnect (); egg_assert_not_object (service3); } @@ -179,6 +183,7 @@ test_get_more_sync (Test *test, g_object_unref (service2); g_object_unref (service); + secret_service_disconnect (); egg_assert_not_object (service); } @@ -211,6 +216,7 @@ test_get_more_async (Test *test, g_list_free_full (collections, g_object_unref); g_object_unref (service); + secret_service_disconnect (); egg_assert_not_object (service); /* Now get a session with just collections */ @@ -233,6 +239,7 @@ test_get_more_async (Test *test, g_list_free_full (collections, g_object_unref); g_object_unref (service); + secret_service_disconnect (); egg_assert_not_object (service); } @@ -430,6 +437,7 @@ test_connect_async (Test *test, g_assert (path == NULL); g_object_unref (service); + secret_service_disconnect (); egg_assert_not_object (service); } @@ -457,6 +465,7 @@ test_connect_ensure_async (Test *test, g_assert (path != NULL); g_object_unref (service); + secret_service_disconnect (); egg_assert_not_object (service); } diff --git a/library/tests/test-session.c b/library/tests/test-session.c index 6599ae4..0439e1b 100644 --- a/library/tests/test-session.c +++ b/library/tests/test-session.c @@ -49,6 +49,7 @@ teardown (Test *test, gconstpointer unused) { g_object_unref (test->service); + secret_service_disconnect (); egg_assert_not_object (test->service); mock_service_stop ();