Properly refer to the fact that multiple passwords may be removed.
[platform/upstream/libsecret.git] / libsecret / secret-paths.c
1 /* libsecret - GLib wrapper for Secret Service
2  *
3  * Copyright 2011 Collabora Ltd.
4  * Copyright 2012 Red Hat Inc.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published
8  * by the Free Software Foundation; either version 2.1 of the licence or (at
9  * your option) any later version.
10  *
11  * See the included COPYING file for more information.
12  *
13  * Author: Stef Walter <stefw@gnome.org>
14  */
15
16 #include "config.h"
17
18 #include "secret-dbus-generated.h"
19 #include "secret-paths.h"
20 #include "secret-private.h"
21 #include "secret-service.h"
22 #include "secret-types.h"
23 #include "secret-value.h"
24
25
26 /**
27  * SECTION:secret-paths
28  * @title: DBus Path Related Functions
29  * @short_description: Secret Service functions which operate on DBus object paths
30  *
31  * These are low level functions which operate on DBus object paths of
32  * collections or items, instead of the #SecretCollection or #SecretItem
33  * objects themselves.
34  *
35  * You can use these functions if you wish to manage access to the secret
36  * service using the DBus API directly, and only wish to use a few calls
37  * in libsecret.
38  *
39  * These functions have an unstable API and may change across versions. Use
40  * <literal>libsecret-unstable</literal> package to access them.
41  *
42  * Stability: Unstable
43  */
44
45 /**
46  * secret_collection_new_for_dbus_path:
47  * @service: (allow-none): a secret service object
48  * @collection_path: the D-Bus path of the collection
49  * @flags: options for the collection initialization
50  * @cancellable: optional cancellation object
51  * @callback: called when the operation completes
52  * @user_data: data to be passed to the callback
53  *
54  * Get a new collection proxy for a collection in the secret service.
55  *
56  * If @service is NULL, then secret_service_get() will be called to get
57  * the default #SecretService proxy.
58  *
59  * This method will return immediately and complete asynchronously.
60  */
61 void
62 secret_collection_new_for_dbus_path (SecretService *service,
63                                      const gchar *collection_path,
64                                      SecretCollectionFlags flags,
65                                      GCancellable *cancellable,
66                                      GAsyncReadyCallback callback,
67                                      gpointer user_data)
68 {
69         GDBusProxy *proxy;
70
71         g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
72         g_return_if_fail (collection_path != NULL);
73         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
74
75         proxy = G_DBUS_PROXY (service);
76
77         g_async_initable_new_async (SECRET_SERVICE_GET_CLASS (service)->collection_gtype,
78                                     G_PRIORITY_DEFAULT, cancellable, callback, user_data,
79                                     "g-flags", G_DBUS_CALL_FLAGS_NONE,
80                                     "g-interface-info", _secret_gen_collection_interface_info (),
81                                     "g-name", g_dbus_proxy_get_name (proxy),
82                                     "g-connection", g_dbus_proxy_get_connection (proxy),
83                                     "g-object-path", collection_path,
84                                     "g-interface-name", SECRET_COLLECTION_INTERFACE,
85                                     "service", service,
86                                     "flags", flags,
87                                     NULL);
88 }
89
90 /**
91  * secret_collection_new_for_dbus_path_finish:
92  * @result: the asynchronous result passed to the callback
93  * @error: location to place an error on failure
94  *
95  * Finish asynchronous operation to get a new collection proxy for a
96  * collection in the secret service.
97  *
98  * Returns: (transfer full): the new collection, which should be unreferenced
99  *          with g_object_unref()
100  */
101 SecretCollection *
102 secret_collection_new_for_dbus_path_finish (GAsyncResult *result,
103                                             GError **error)
104 {
105         GObject *source_object;
106         GObject *object;
107
108         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
109         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
110
111         source_object = g_async_result_get_source_object (result);
112         object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
113                                               result, error);
114         g_object_unref (source_object);
115
116         if (object == NULL)
117                 return NULL;
118
119         return SECRET_COLLECTION (object);
120 }
121
122 /**
123  * secret_collection_new_for_dbus_path_sync:
124  * @service: (allow-none): a secret service object
125  * @collection_path: the D-Bus path of the collection
126  * @flags: options for the collection initialization
127  * @cancellable: optional cancellation object
128  * @error: location to place an error on failure
129  *
130  * Get a new collection proxy for a collection in the secret service.
131  *
132  * If @service is NULL, then secret_service_get_sync() will be called to get
133  * the default #SecretService proxy.
134  *
135  * This method may block indefinitely and should not be used in user interface
136  * threads.
137  *
138  * Returns: (transfer full): the new collection, which should be unreferenced
139  *          with g_object_unref()
140  */
141 SecretCollection *
142 secret_collection_new_for_dbus_path_sync (SecretService *service,
143                                           const gchar *collection_path,
144                                           SecretCollectionFlags flags,
145                                           GCancellable *cancellable,
146                                           GError **error)
147 {
148         GDBusProxy *proxy;
149
150         g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
151         g_return_val_if_fail (collection_path != NULL, NULL);
152         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
153         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
154
155         proxy = G_DBUS_PROXY (service);
156
157         return g_initable_new (SECRET_SERVICE_GET_CLASS (service)->collection_gtype,
158                                cancellable, error,
159                                "g-flags", G_DBUS_CALL_FLAGS_NONE,
160                                "g-interface-info", _secret_gen_collection_interface_info (),
161                                "g-name", g_dbus_proxy_get_name (proxy),
162                                "g-connection", g_dbus_proxy_get_connection (proxy),
163                                "g-object-path", collection_path,
164                                "g-interface-name", SECRET_COLLECTION_INTERFACE,
165                                "service", service,
166                                "flags", flags,
167                                NULL);
168 }
169
170 /**
171  * secret_item_new_for_dbus_path:
172  * @service: (allow-none): a secret service object
173  * @item_path: the D-Bus path of the collection
174  * @flags: initialization flags for the new item
175  * @cancellable: optional cancellation object
176  * @callback: called when the operation completes
177  * @user_data: data to be passed to the callback
178  *
179  * Get a new item proxy for a secret item in the secret service.
180  *
181  * If @service is NULL, then secret_service_get() will be called to get
182  * the default #SecretService proxy.
183  *
184  * This method will return immediately and complete asynchronously.
185  */
186 void
187 secret_item_new_for_dbus_path (SecretService *service,
188                                const gchar *item_path,
189                                SecretItemFlags flags,
190                                GCancellable *cancellable,
191                                GAsyncReadyCallback callback,
192                                gpointer user_data)
193 {
194         GDBusProxy *proxy;
195
196         g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
197         g_return_if_fail (item_path != NULL);
198         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
199
200         proxy = G_DBUS_PROXY (service);
201
202         g_async_initable_new_async (SECRET_SERVICE_GET_CLASS (service)->item_gtype,
203                                     G_PRIORITY_DEFAULT, cancellable, callback, user_data,
204                                     "g-flags", G_DBUS_CALL_FLAGS_NONE,
205                                     "g-interface-info", _secret_gen_item_interface_info (),
206                                     "g-name", g_dbus_proxy_get_name (proxy),
207                                     "g-connection", g_dbus_proxy_get_connection (proxy),
208                                     "g-object-path", item_path,
209                                     "g-interface-name", SECRET_ITEM_INTERFACE,
210                                     "service", service,
211                                     "flags", flags,
212                                     NULL);
213 }
214
215 /**
216  * secret_item_new_for_dbus_path_finish:
217  * @result: the asynchronous result passed to the callback
218  * @error: location to place an error on failure
219  *
220  * Finish asynchronous operation to get a new item proxy for an secret
221  * item in the secret service.
222  *
223  * Returns: (transfer full): the new item, which should be unreferenced
224  *          with g_object_unref()
225  */
226 SecretItem *
227 secret_item_new_for_dbus_path_finish (GAsyncResult *result,
228                                       GError **error)
229 {
230         GObject *object;
231         GObject *source_object;
232
233         source_object = g_async_result_get_source_object (result);
234         object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
235                                               result, error);
236         g_object_unref (source_object);
237
238         if (object == NULL)
239                 return NULL;
240
241         return SECRET_ITEM (object);
242 }
243
244 /**
245  * secret_item_new_dbus_path_sync:
246  * @service: (allow-none): a secret service object
247  * @item_path: the D-Bus path of the item
248  * @flags: initialization flags for the new item
249  * @cancellable: optional cancellation object
250  * @error: location to place an error on failure
251  *
252  * Get a new item proxy for a secret item in the secret service.
253  *
254  * If @service is NULL, then secret_service_get_sync() will be called to get
255  * the default #SecretService proxy.
256  *
257  * This method may block indefinitely and should not be used in user interface
258  * threads.
259  *
260  * Returns: (transfer full): the new item, which should be unreferenced
261  *          with g_object_unref()
262  */
263 SecretItem *
264 secret_item_new_for_dbus_path_sync (SecretService *service,
265                                     const gchar *item_path,
266                                     SecretItemFlags flags,
267                                     GCancellable *cancellable,
268                                     GError **error)
269 {
270         GDBusProxy *proxy;
271
272         g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
273         g_return_val_if_fail (item_path != NULL, NULL);
274         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
275         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
276
277         proxy = G_DBUS_PROXY (service);
278
279         return g_initable_new (SECRET_SERVICE_GET_CLASS (service)->item_gtype,
280                                cancellable, error,
281                                "g-flags", G_DBUS_CALL_FLAGS_NONE,
282                                "g-interface-info", _secret_gen_item_interface_info (),
283                                "g-name", g_dbus_proxy_get_name (proxy),
284                                "g-connection", g_dbus_proxy_get_connection (proxy),
285                                "g-object-path", item_path,
286                                "g-interface-name", SECRET_ITEM_INTERFACE,
287                                "service", service,
288                                "flags", flags,
289                                NULL);
290 }
291
292 static void
293 on_search_items_complete (GObject *source,
294                           GAsyncResult *result,
295                           gpointer user_data)
296 {
297         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
298         GError *error = NULL;
299         GVariant *response;
300
301         response = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
302         if (error != NULL) {
303                 _secret_util_strip_remote_error (&error);
304                 g_simple_async_result_take_error (res, error);
305         } else {
306                 g_simple_async_result_set_op_res_gpointer (res, response,
307                                                            (GDestroyNotify)g_variant_unref);
308         }
309
310         g_simple_async_result_complete (res);
311         g_object_unref (res);
312 }
313
314 /**
315  * secret_collection_search_for_dbus_paths:
316  * @collection: the secret collection
317  * @schema: (allow-none): the schema for the attributes
318  * @attributes: (element-type utf8 utf8): search for items matching these attributes
319  * @cancellable: optional cancellation object
320  * @callback: called when the operation completes
321  * @user_data: data to pass to the callback
322  *
323  * Search for items in @collection matching the @attributes, and return their
324  * DBus object paths. Only the specified collection is searched. The @attributes
325  * should be a table of string keys and string values.
326  *
327  * This function returns immediately and completes asynchronously.
328  *
329  * When your callback is called use secret_collection_search_for_dbus_paths_finish()
330  * to get the results of this function. Only the DBus object paths of the
331  * items will be returned. If you would like #SecretItem objects to be returned
332  * instead, then use the secret_collection_search() function.
333  */
334 void
335 secret_collection_search_for_dbus_paths (SecretCollection *collection,
336                                          const SecretSchema *schema,
337                                          GHashTable *attributes,
338                                          GCancellable *cancellable,
339                                          GAsyncReadyCallback callback,
340                                          gpointer user_data)
341 {
342         GSimpleAsyncResult *async;
343         const gchar *schema_name = NULL;
344
345         g_return_if_fail (SECRET_IS_COLLECTION (collection));
346         g_return_if_fail (attributes != NULL);
347         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
348
349         /* Warnings raised already */
350         if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
351                 return;
352
353         if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
354                 schema_name = schema->name;
355
356         async = g_simple_async_result_new (G_OBJECT (collection), callback, user_data,
357                                            secret_collection_search_for_dbus_paths);
358
359         g_dbus_proxy_call (G_DBUS_PROXY (collection), "SearchItems",
360                            g_variant_new ("(@a{ss})", _secret_attributes_to_variant (attributes, schema_name)),
361                            G_DBUS_CALL_FLAGS_NONE, -1, cancellable,
362                            on_search_items_complete, g_object_ref (async));
363
364         g_object_unref (async);
365 }
366
367 /**
368  * secret_collection_search_for_dbus_paths_finish:
369  * @collection: the secret collection
370  * @result: asynchronous result passed to callback
371  * @error: location to place error on failure
372  *
373  * Complete asynchronous operation to search for items in a collection.
374  *
375  * DBus object paths of the items will be returned. If you would to have
376  * #SecretItem objects to be returned instead, then use the
377  * secret_collection_search() and secret_collection_search_finish() functions.
378  *
379  * Returns: (transfer full) (array zero-terminated=1): an array of DBus object
380  *          paths for matching items.
381  */
382 gchar **
383 secret_collection_search_for_dbus_paths_finish (SecretCollection *collection,
384                                                 GAsyncResult *result,
385                                                 GError **error)
386 {
387         GVariant *retval;
388         GSimpleAsyncResult *async;
389         gchar **paths = NULL;
390
391         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (collection),
392                               secret_collection_search_for_dbus_paths), FALSE);
393         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
394
395         async = G_SIMPLE_ASYNC_RESULT (result);
396         if (g_simple_async_result_propagate_error (async, error))
397                 return FALSE;
398
399         retval= g_simple_async_result_get_op_res_gpointer (async);
400         g_variant_get (retval, "(^ao)", &paths);
401         return paths;
402 }
403
404 /**
405  * secret_collection_search_for_dbus_paths_sync:
406  * @collection: the secret collection
407  * @schema: (allow-none): the schema for the attributes
408  * @attributes: (element-type utf8 utf8): search for items matching these attributes
409  * @cancellable: optional cancellation object
410  * @error: location to place error on failure
411  *
412  * Search for items matching the @attributes in @collection, and return their
413  * DBus object paths. The @attributes should be a table of string keys and
414  * string values.
415  *
416  * This function may block indefinetely. Use the asynchronous version
417  * in user interface threads.
418  *
419  * DBus object paths of the items will be returned. If you would to have
420  * #SecretItem objects to be returned instead, then use the
421  * secret_collection_search_sync() function.
422  *
423  * Returns: (transfer full) (array zero-terminated=1): an array of DBus object
424  *          paths for matching items.
425  */
426 gchar **
427 secret_collection_search_for_dbus_paths_sync (SecretCollection *collection,
428                                               const SecretSchema *schema,
429                                               GHashTable *attributes,
430                                               GCancellable *cancellable,
431                                               GError **error)
432 {
433         SecretSync *sync;
434         gchar **paths;
435
436         g_return_val_if_fail (SECRET_IS_COLLECTION (collection), NULL);
437         g_return_val_if_fail (attributes != NULL, NULL);
438         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
439         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
440
441         sync = _secret_sync_new ();
442         g_main_context_push_thread_default (sync->context);
443
444         secret_collection_search_for_dbus_paths (collection, schema, attributes, cancellable,
445                                                  _secret_sync_on_result, sync);
446
447         g_main_loop_run (sync->loop);
448
449         paths = secret_collection_search_for_dbus_paths_finish (collection, sync->result, error);
450
451         g_main_context_pop_thread_default (sync->context);
452         _secret_sync_free (sync);
453
454         return paths;
455 }
456
457 /**
458  * secret_service_search_for_dbus_paths:
459  * @self: the secret service
460  * @schema: (allow-none): the schema for the attributes
461  * @attributes: (element-type utf8 utf8): search for items matching these attributes
462  * @cancellable: optional cancellation object
463  * @callback: called when the operation completes
464  * @user_data: data to pass to the callback
465  *
466  * Search for items matching the @attributes, and return their D-Bus object paths.
467  * All collections are searched. The @attributes should be a table of string keys
468  * and string values.
469  *
470  * This function returns immediately and completes asynchronously.
471  *
472  * When your callback is called use secret_service_search_for_dbus_paths_finish()
473  * to get the results of this function. Only the D-Bus object paths of the
474  * items will be returned. If you would like #SecretItem objects to be returned
475  * instead, then use the secret_service_search() function.
476  */
477 void
478 secret_service_search_for_dbus_paths (SecretService *self,
479                                       const SecretSchema *schema,
480                                       GHashTable *attributes,
481                                       GCancellable *cancellable,
482                                       GAsyncReadyCallback callback,
483                                       gpointer user_data)
484 {
485         const gchar *schema_name = NULL;
486
487         g_return_if_fail (SECRET_IS_SERVICE (self));
488         g_return_if_fail (attributes != NULL);
489         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
490
491         /* Warnings raised already */
492         if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
493                 return;
494
495         if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
496                 schema_name = schema->name;
497
498         _secret_service_search_for_paths_variant (self, _secret_attributes_to_variant (attributes, schema_name),
499                                                   cancellable, callback, user_data);
500 }
501
502 void
503 _secret_service_search_for_paths_variant (SecretService *self,
504                                           GVariant *attributes,
505                                           GCancellable *cancellable,
506                                           GAsyncReadyCallback callback,
507                                           gpointer user_data)
508 {
509         GSimpleAsyncResult *res;
510
511         g_return_if_fail (SECRET_IS_SERVICE (self));
512         g_return_if_fail (attributes != NULL);
513         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
514
515         res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
516                                          secret_service_search_for_dbus_paths);
517
518         g_dbus_proxy_call (G_DBUS_PROXY (self), "SearchItems",
519                            g_variant_new ("(@a{ss})", attributes),
520                            G_DBUS_CALL_FLAGS_NONE, -1, cancellable,
521                            on_search_items_complete, g_object_ref (res));
522
523         g_object_unref (res);
524 }
525
526 /**
527  * secret_service_search_for_dbus_paths_finish:
528  * @self: the secret service
529  * @result: asynchronous result passed to callback
530  * @unlocked: (out) (transfer full) (array zero-terminated=1) (allow-none):
531  *            location to place an array of D-Bus object paths for matching
532  *            items which were locked.
533  * @locked: (out) (transfer full) (array zero-terminated=1) (allow-none):
534  *          location to place an array of D-Bus object paths for matching
535  *          items which were locked.
536  * @error: location to place error on failure
537  *
538  * Complete asynchronous operation to search for items, and return their
539  * D-Bus object paths.
540  *
541  * Matching items that are locked or unlocked, have their D-Bus paths placed
542  * in the @locked or @unlocked arrays respectively.
543  *
544  * D-Bus object paths of the items will be returned in the @unlocked or
545  * @locked arrays. If you would to have #SecretItem objects to be returned
546  * instead, then us the secret_service_search() and
547  * secret_service_search_finish() functions.
548  *
549  * Returns: whether the search was successful or not
550  */
551 gboolean
552 secret_service_search_for_dbus_paths_finish (SecretService *self,
553                                              GAsyncResult *result,
554                                              gchar ***unlocked,
555                                              gchar ***locked,
556                                              GError **error)
557 {
558         GVariant *response;
559         GSimpleAsyncResult *res;
560         gchar **dummy = NULL;
561
562         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
563                               secret_service_search_for_dbus_paths), FALSE);
564         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
565
566         res = G_SIMPLE_ASYNC_RESULT (result);
567         if (g_simple_async_result_propagate_error (res, error))
568                 return FALSE;
569
570         if (unlocked || locked) {
571                 if (!unlocked)
572                         unlocked = &dummy;
573                 else if (!locked)
574                         locked = &dummy;
575                 response = g_simple_async_result_get_op_res_gpointer (res);
576                 g_variant_get (response, "(^ao^ao)", unlocked, locked);
577         }
578
579         g_strfreev (dummy);
580         return TRUE;
581 }
582
583 /**
584  * secret_service_search_for_dbus_paths_sync:
585  * @self: the secret service
586  * @schema: (allow-none): the schema for the attributes
587  * @attributes: (element-type utf8 utf8): search for items matching these attributes
588  * @cancellable: optional cancellation object
589  * @unlocked: (out) (transfer full) (array zero-terminated=1) (allow-none):
590  *            location to place an array of D-Bus object paths for matching
591  *            items which were locked.
592  * @locked: (out) (transfer full) (array zero-terminated=1) (allow-none):
593  *          location to place an array of D-Bus object paths for matching
594  *          items which were locked.
595  * @error: location to place error on failure
596  *
597  * Search for items matching the @attributes, and return their D-Bus object
598  * paths. All collections are searched. The @attributes should be a table of
599  * string keys and string values.
600  *
601  * This function may block indefinetely. Use the asynchronous version
602  * in user interface threads.
603  *
604  * Matching items that are locked or unlocked, have their D-Bus paths placed
605  * in the @locked or @unlocked arrays respectively.
606  *
607  * D-Bus object paths of the items will be returned in the @unlocked or
608  * @locked arrays. If you would to have #SecretItem objects to be returned
609  * instead, then use the secret_service_search_sync() function.
610  *
611  * Returns: whether the search was successful or not
612  */
613 gboolean
614 secret_service_search_for_dbus_paths_sync (SecretService *self,
615                                            const SecretSchema *schema,
616                                            GHashTable *attributes,
617                                            GCancellable *cancellable,
618                                            gchar ***unlocked,
619                                            gchar ***locked,
620                                            GError **error)
621 {
622         const gchar *schema_name = NULL;
623         gchar **dummy = NULL;
624         GVariant *response;
625
626         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
627         g_return_val_if_fail (attributes != NULL, FALSE);
628         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
629         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
630
631         /* Warnings raised already */
632         if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
633                 return FALSE;
634
635         if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
636                 schema_name = schema->name;
637
638         response = g_dbus_proxy_call_sync (G_DBUS_PROXY (self), "SearchItems",
639                                            g_variant_new ("(@a{ss})",
640                                                           _secret_attributes_to_variant (attributes, schema_name)),
641                                            G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error);
642
643         if (response != NULL) {
644                 if (unlocked || locked) {
645                         if (!unlocked)
646                                 unlocked = &dummy;
647                         else if (!locked)
648                                 locked = &dummy;
649                         g_variant_get (response, "(^ao^ao)", unlocked, locked);
650                 }
651
652                 g_variant_unref (response);
653         }
654
655         g_strfreev (dummy);
656
657         return response != NULL;
658 }
659
660 typedef struct {
661         GCancellable *cancellable;
662         GVariant *in;
663         GVariant *out;
664         GHashTable *items;
665 } GetClosure;
666
667 static void
668 get_closure_free (gpointer data)
669 {
670         GetClosure *closure = data;
671         if (closure->in)
672                 g_variant_unref (closure->in);
673         if (closure->out)
674                 g_variant_unref (closure->out);
675         g_clear_object (&closure->cancellable);
676         g_slice_free (GetClosure, closure);
677 }
678
679 static void
680 on_get_secrets_complete (GObject *source,
681                          GAsyncResult *result,
682                          gpointer user_data)
683 {
684         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
685         GetClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
686         GError *error = NULL;
687
688         closure->out = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
689         if (error != NULL) {
690                 _secret_util_strip_remote_error (&error);
691                 g_simple_async_result_take_error (res, error);
692         }
693         g_simple_async_result_complete (res);
694
695         g_object_unref (res);
696 }
697
698 static void
699 on_get_secrets_session (GObject *source,
700                         GAsyncResult *result,
701                         gpointer user_data)
702 {
703         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
704         GetClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
705         GError *error = NULL;
706         const gchar *session;
707
708         secret_service_ensure_session_finish (SECRET_SERVICE (source), result, &error);
709         if (error != NULL) {
710                 g_simple_async_result_take_error (res, error);
711                 g_simple_async_result_complete (res);
712         } else {
713                 session = secret_service_get_session_dbus_path (SECRET_SERVICE (source));
714                 g_dbus_proxy_call (G_DBUS_PROXY (source), "GetSecrets",
715                                    g_variant_new ("(@aoo)", closure->in, session),
716                                    G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
717                                    closure->cancellable, on_get_secrets_complete,
718                                    g_object_ref (res));
719         }
720
721         g_object_unref (res);
722 }
723
724 /**
725  * secret_service_get_secret_for_dbus_path:
726  * @self: the secret service
727  * @item_path: the D-Bus path to item to retrieve secret for
728  * @cancellable: optional cancellation object
729  * @callback: called when the operation completes
730  * @user_data: data to pass to the callback
731  *
732  * Get the secret value for an secret item stored in the service.
733  *
734  * The item is represented by its D-Bus object path. If you already have a
735  * #SecretItem proxy object, use use secret_item_get_secret() to more simply
736  * get its secret value.
737  *
738  * This function returns immediately and completes asynchronously.
739  */
740 void
741 secret_service_get_secret_for_dbus_path (SecretService *self,
742                                          const gchar *item_path,
743                                          GCancellable *cancellable,
744                                          GAsyncReadyCallback callback,
745                                          gpointer user_data)
746 {
747         GSimpleAsyncResult *res;
748         GetClosure *closure;
749
750         g_return_if_fail (SECRET_IS_SERVICE (self));
751         g_return_if_fail (item_path != NULL);
752         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
753
754         res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
755                                          secret_service_get_secret_for_dbus_path);
756
757         closure = g_slice_new0 (GetClosure);
758         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
759         closure->in = g_variant_ref_sink (g_variant_new_objv (&item_path, 1));
760         g_simple_async_result_set_op_res_gpointer (res, closure, get_closure_free);
761
762         secret_service_ensure_session (self, cancellable,
763                                        on_get_secrets_session,
764                                        g_object_ref (res));
765
766         g_object_unref (res);
767 }
768
769 /**
770  * secret_service_get_secret_for_dbus_path_finish:
771  * @self: the secret service
772  * @result: asynchronous result passed to callback
773  * @error: location to place an error on failure
774  *
775  * Complete asynchronous operation to get the secret value for an
776  * secret item stored in the service.
777  *
778  * Will return %NULL if the item is locked.
779  *
780  * Returns: (transfer full) (allow-none): the newly allocated secret value
781  *          for the item, which should be released with secret_value_unref()
782  */
783 SecretValue *
784 secret_service_get_secret_for_dbus_path_finish (SecretService *self,
785                                                 GAsyncResult *result,
786                                                 GError **error)
787 {
788         GSimpleAsyncResult *res;
789         GetClosure *closure;
790
791         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
792         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
793                               secret_service_get_secret_for_dbus_path), NULL);
794         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
795
796         res = G_SIMPLE_ASYNC_RESULT (result);
797         if (g_simple_async_result_propagate_error (res, error))
798                 return NULL;
799
800         closure = g_simple_async_result_get_op_res_gpointer (res);
801         return _secret_service_decode_get_secrets_first (self, closure->out);
802 }
803
804 /**
805  * secret_service_get_secret_for_dbus_path_sync:
806  * @self: the secret service
807  * @item_path: the D-Bus path to item to retrieve secret for
808  * @cancellable: optional cancellation object
809  * @error: location to place an error on failure
810  *
811  * Get the secret value for an secret item stored in the service.
812  *
813  * The item is represented by its D-Bus object path. If you already have a
814  * #SecretItem proxy object, use use secret_item_load_secret_sync() to more simply
815  * get its secret value.
816  *
817  * This method may block indefinitely and should not be used in user interface
818  * threads.
819  *
820  * Will return %NULL if the item is locked.
821  *
822  * Returns: (transfer full) (allow-none): the newly allocated secret value
823  *          for the item, which should be released with secret_value_unref()
824  */
825 SecretValue *
826 secret_service_get_secret_for_dbus_path_sync (SecretService *self,
827                                               const gchar *item_path,
828                                               GCancellable *cancellable,
829                                               GError **error)
830 {
831         SecretSync *sync;
832         SecretValue *value;
833
834         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
835         g_return_val_if_fail (item_path != NULL, NULL);
836         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
837         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
838
839         sync = _secret_sync_new ();
840         g_main_context_push_thread_default (sync->context);
841
842         secret_service_get_secret_for_dbus_path (self, item_path, cancellable,
843                                                  _secret_sync_on_result, sync);
844
845         g_main_loop_run (sync->loop);
846
847         value = secret_service_get_secret_for_dbus_path_finish (self, sync->result, error);
848
849         g_main_context_pop_thread_default (sync->context);
850         _secret_sync_free (sync);
851
852         return value;
853 }
854
855 /**
856  * secret_service_get_secrets_for_dbus_paths:
857  * @self: the secret service
858  * @item_paths: the D-Bus paths to items to retrieve secrets for
859  * @cancellable: optional cancellation object
860  * @callback: called when the operation completes
861  * @user_data: data to pass to the callback
862  *
863  * Get the secret values for an secret items stored in the service.
864  *
865  * The items are represented by their D-Bus object paths. If you already have
866  * #SecretItem proxy objects, use use secret_item_load_secrets() to more simply
867  * get their secret values.
868  *
869  * This function returns immediately and completes asynchronously.
870  */
871 void
872 secret_service_get_secrets_for_dbus_paths (SecretService *self,
873                                            const gchar **item_paths,
874                                            GCancellable *cancellable,
875                                            GAsyncReadyCallback callback,
876                                            gpointer user_data)
877 {
878         GSimpleAsyncResult *res;
879         GetClosure *closure;
880
881         g_return_if_fail (SECRET_IS_SERVICE (self));
882         g_return_if_fail (item_paths != NULL);
883         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
884
885         res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
886                                          secret_service_get_secret_for_dbus_path);
887
888         closure = g_slice_new0 (GetClosure);
889         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
890         closure->in = g_variant_ref_sink (g_variant_new_objv (item_paths, -1));
891         g_simple_async_result_set_op_res_gpointer (res, closure, get_closure_free);
892
893         secret_service_ensure_session (self, cancellable,
894                                        on_get_secrets_session,
895                                        g_object_ref (res));
896
897         g_object_unref (res);
898 }
899
900 /**
901  * secret_service_get_secrets_for_dbus_paths_finish:
902  * @self: the secret service
903  * @result: asynchronous result passed to callback
904  * @error: location to place an error on failure
905  *
906  * Complete asynchronous operation to get the secret values for an
907  * secret items stored in the service.
908  *
909  * Items that are locked will not be included the results.
910  *
911  * Returns: (transfer full) (element-type utf8 SecretUnstable.Value): a newly
912  *          allocated hash table of item_path keys to #SecretValue
913  *          values.
914  */
915 GHashTable *
916 secret_service_get_secrets_for_dbus_paths_finish (SecretService *self,
917                                                   GAsyncResult *result,
918                                                   GError **error)
919 {
920         GSimpleAsyncResult *res;
921         GetClosure *closure;
922
923         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
924         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
925                               secret_service_get_secret_for_dbus_path), NULL);
926         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
927
928         res = G_SIMPLE_ASYNC_RESULT (result);
929         if (g_simple_async_result_propagate_error (res, error))
930                 return NULL;
931
932         closure = g_simple_async_result_get_op_res_gpointer (res);
933         return _secret_service_decode_get_secrets_all (self, closure->out);
934 }
935
936 /**
937  * secret_service_get_secrets_for_dbus_paths_sync:
938  * @self: the secret service
939  * @item_paths: the D-Bus paths to items to retrieve secrets for
940  * @cancellable: optional cancellation object
941  * @error: location to place an error on failure
942  *
943  * Get the secret values for an secret items stored in the service.
944  *
945  * The items are represented by their D-Bus object paths. If you already have
946  * #SecretItem proxy objects, use use secret_item_load_secrets_sync() to more
947  * simply get their secret values.
948  *
949  * This method may block indefinitely and should not be used in user interface
950  * threads.
951  *
952  * Items that are locked will not be included the results.
953  *
954  * Returns: (transfer full) (element-type utf8 SecretUnstable.Value): a newly
955  *          allocated hash table of item_path keys to #SecretValue
956  *          values.
957  */
958 GHashTable *
959 secret_service_get_secrets_for_dbus_paths_sync (SecretService *self,
960                                                 const gchar **item_paths,
961                                                 GCancellable *cancellable,
962                                                 GError **error)
963 {
964         SecretSync *sync;
965         GHashTable *secrets;
966
967         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
968         g_return_val_if_fail (item_paths != NULL, NULL);
969         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
970         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
971
972         sync = _secret_sync_new ();
973         g_main_context_push_thread_default (sync->context);
974
975         secret_service_get_secrets_for_dbus_paths (self, item_paths, cancellable,
976                                                    _secret_sync_on_result, sync);
977
978         g_main_loop_run (sync->loop);
979
980         secrets = secret_service_get_secrets_for_dbus_paths_finish (self, sync->result, error);
981
982         g_main_context_pop_thread_default (sync->context);
983         _secret_sync_free (sync);
984
985         return secrets;
986 }
987
988
989 typedef struct {
990         GCancellable *cancellable;
991         SecretPrompt *prompt;
992         GPtrArray *xlocked;
993 } XlockClosure;
994
995 static void
996 xlock_closure_free (gpointer data)
997 {
998         XlockClosure *closure = data;
999         g_clear_object (&closure->cancellable);
1000         g_clear_object (&closure->prompt);
1001         if (closure->xlocked)
1002                 g_ptr_array_unref (closure->xlocked);
1003         g_slice_free (XlockClosure, closure);
1004 }
1005
1006 static void
1007 on_xlock_prompted (GObject *source,
1008                    GAsyncResult *result,
1009                    gpointer user_data)
1010 {
1011         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1012         XlockClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1013         SecretService *self = SECRET_SERVICE (source);
1014         GError *error = NULL;
1015         GVariantIter iter;
1016         GVariant *retval;
1017         gchar *path;
1018
1019         retval = secret_service_prompt_finish (self, result, G_VARIANT_TYPE ("ao"), &error);
1020         if (error != NULL)
1021                 g_simple_async_result_take_error (res, error);
1022
1023         if (retval != NULL) {
1024                 g_variant_iter_init (&iter, retval);
1025                 while (g_variant_iter_loop (&iter, "o", &path))
1026                         g_ptr_array_add (closure->xlocked, g_strdup (path));
1027                 g_variant_unref (retval);
1028         }
1029
1030         g_simple_async_result_complete (res);
1031         g_object_unref (res);
1032 }
1033
1034 static void
1035 on_xlock_called (GObject *source,
1036                  GAsyncResult *result,
1037                  gpointer user_data)
1038 {
1039         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1040         XlockClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1041         SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
1042         const gchar *prompt = NULL;
1043         gchar **xlocked = NULL;
1044         GError *error = NULL;
1045         GVariant *retval;
1046         guint i;
1047
1048         retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
1049         if (error != NULL) {
1050                 _secret_util_strip_remote_error (&error);
1051                 g_simple_async_result_take_error (res, error);
1052                 g_simple_async_result_complete (res);
1053
1054         } else {
1055                 g_variant_get (retval, "(^ao&o)", &xlocked, &prompt);
1056
1057                 if (_secret_util_empty_path (prompt)) {
1058                         for (i = 0; xlocked[i]; i++)
1059                                 g_ptr_array_add (closure->xlocked, g_strdup (xlocked[i]));
1060                         g_simple_async_result_complete (res);
1061
1062                 } else {
1063                         closure->prompt = _secret_prompt_instance (self, prompt);
1064                         secret_service_prompt (self, closure->prompt, closure->cancellable,
1065                                                 on_xlock_prompted, g_object_ref (res));
1066                 }
1067
1068                 g_strfreev (xlocked);
1069                 g_variant_unref (retval);
1070         }
1071
1072         g_object_unref (self);
1073         g_object_unref (res);
1074 }
1075
1076 void
1077 _secret_service_xlock_paths_async (SecretService *self,
1078                                    const gchar *method,
1079                                    const gchar **paths,
1080                                    GCancellable *cancellable,
1081                                    GAsyncReadyCallback callback,
1082                                    gpointer user_data)
1083 {
1084         GSimpleAsyncResult *res;
1085         XlockClosure *closure;
1086
1087         res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1088                                          _secret_service_xlock_paths_async);
1089         closure = g_slice_new0 (XlockClosure);
1090         closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable;
1091         closure->xlocked = g_ptr_array_new_with_free_func (g_free);
1092         g_simple_async_result_set_op_res_gpointer (res, closure, xlock_closure_free);
1093
1094         g_dbus_proxy_call (G_DBUS_PROXY (self), method,
1095                            g_variant_new ("(@ao)", g_variant_new_objv (paths, -1)),
1096                            G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
1097                            cancellable, on_xlock_called, g_object_ref (res));
1098
1099         g_object_unref (res);
1100 }
1101
1102 gint
1103 _secret_service_xlock_paths_finish (SecretService *self,
1104                                     GAsyncResult *result,
1105                                     gchar ***xlocked,
1106                                     GError **error)
1107 {
1108         GSimpleAsyncResult *res;
1109         XlockClosure *closure;
1110         gint count;
1111
1112         res = G_SIMPLE_ASYNC_RESULT (result);
1113         if (g_simple_async_result_propagate_error (res, error))
1114                 return -1;
1115
1116         closure = g_simple_async_result_get_op_res_gpointer (res);
1117         count = closure->xlocked->len;
1118
1119         if (xlocked != NULL) {
1120                 g_ptr_array_add (closure->xlocked, NULL);
1121                 *xlocked = (gchar **)g_ptr_array_free (closure->xlocked, FALSE);
1122                 closure->xlocked = NULL;
1123         }
1124
1125         return count;
1126 }
1127
1128 /**
1129  * secret_service_lock_dbus_paths_sync:
1130  * @self: the secret service
1131  * @paths: the D-Bus object paths of the items or collections to lock
1132  * @cancellable: optional cancellation object
1133  * @locked: (out) (array zero-terminated=1) (transfer full) (allow-none):
1134  *          location to place array of D-Bus paths of items or collections
1135  *          that were locked
1136  * @error: location to place an error on failure
1137  *
1138  * Lock items or collections in the secret service.
1139  *
1140  * The items or collections are represented by their D-Bus object paths. If you
1141  * already have #SecretItem and #SecretCollection proxy objects, use use
1142  * secret_service_lock_sync() instead.
1143  *
1144  * The secret service may not be able to lock items individually, and may
1145  * lock an entire collection instead.
1146  *
1147  * This method may block indefinitely and should not be used in user
1148  * interface threads. The secret service may prompt the user.
1149  * secret_service_prompt() will be used to handle any prompts that show up.
1150  *
1151  * Returns: the number of items or collections that were locked
1152  */
1153 gint
1154 secret_service_lock_dbus_paths_sync (SecretService *self,
1155                                      const gchar **paths,
1156                                      GCancellable *cancellable,
1157                                      gchar ***locked,
1158                                      GError **error)
1159 {
1160         SecretSync *sync;
1161         gint count;
1162
1163         g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
1164         g_return_val_if_fail (paths != NULL, -1);
1165         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
1166         g_return_val_if_fail (error == NULL || *error == NULL, -1);
1167
1168         sync = _secret_sync_new ();
1169         g_main_context_push_thread_default (sync->context);
1170
1171         secret_service_lock_dbus_paths (self, paths, cancellable,
1172                                         _secret_sync_on_result, sync);
1173
1174         g_main_loop_run (sync->loop);
1175
1176         count = secret_service_lock_dbus_paths_finish (self, sync->result,
1177                                                        locked, error);
1178
1179         g_main_context_pop_thread_default (sync->context);
1180         _secret_sync_free (sync);
1181
1182         return count;
1183 }
1184
1185 /**
1186  * secret_service_lock_dbus_paths:
1187  * @self: the secret service
1188  * @paths: the D-Bus paths for items or collections to lock
1189  * @cancellable: optional cancellation object
1190  * @callback: called when the operation completes
1191  * @user_data: data to pass to the callback
1192  *
1193  * Lock items or collections in the secret service.
1194  *
1195  * The items or collections are represented by their D-Bus object paths. If you
1196  * already have #SecretItem and #SecretCollection proxy objects, use use
1197  * secret_service_lock() instead.
1198  *
1199  * The secret service may not be able to lock items individually, and may
1200  * lock an entire collection instead.
1201  *
1202  * This method returns immediately and completes asynchronously. The secret
1203  * service may prompt the user. secret_service_prompt() will be used to handle
1204  * any prompts that show up.
1205  */
1206 void
1207 secret_service_lock_dbus_paths (SecretService *self,
1208                                 const gchar **paths,
1209                                 GCancellable *cancellable,
1210                                 GAsyncReadyCallback callback,
1211                                 gpointer user_data)
1212 {
1213         g_return_if_fail (SECRET_IS_SERVICE (self));
1214         g_return_if_fail (paths != NULL);
1215         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1216
1217         _secret_service_xlock_paths_async (self, "Lock", paths, cancellable,
1218                                            callback, user_data);
1219 }
1220
1221 /**
1222  * secret_service_lock_dbus_paths_finish:
1223  * @self: the secret service
1224  * @result: asynchronous result passed to the callback
1225  * @locked: (out) (array zero-terminated=1) (transfer full) (allow-none):
1226  *          location to place array of D-Bus paths of items or collections
1227  *          that were locked
1228  * @error: location to place an error on failure
1229  *
1230  * Complete asynchronous operation to lock items or collections in the secret
1231  * service.
1232  *
1233  * The secret service may not be able to lock items individually, and may
1234  * lock an entire collection instead.
1235  *
1236  * Returns: the number of items or collections that were locked
1237  */
1238 gint
1239 secret_service_lock_dbus_paths_finish (SecretService *self,
1240                                        GAsyncResult *result,
1241                                        gchar ***locked,
1242                                        GError **error)
1243 {
1244         g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
1245         g_return_val_if_fail (locked != NULL, -1);
1246         g_return_val_if_fail (error == NULL || *error == NULL, -1);
1247
1248         return _secret_service_xlock_paths_finish (self, result, locked, error);
1249 }
1250
1251 /**
1252  * secret_service_unlock_dbus_paths_sync:
1253  * @self: the secret service
1254  * @paths: the D-Bus object paths of the items or collections to unlock
1255  * @cancellable: optional cancellation object
1256  * @unlocked: (out) (array zero-terminated=1) (transfer full) (allow-none):
1257  *            location to place array of D-Bus paths of items or collections
1258  *            that were unlocked
1259  * @error: location to place an error on failure
1260  *
1261  * Unlock items or collections in the secret service.
1262  *
1263  * The items or collections are represented by their D-Bus object paths. If you
1264  * already have #SecretItem and #SecretCollection proxy objects, use use
1265  * secret_service_unlock_sync() instead.
1266  *
1267  * The secret service may not be able to unlock items individually, and may
1268  * unlock an entire collection instead.
1269  *
1270  * This method may block indefinitely and should not be used in user
1271  * interface threads. The secret service may prompt the user.
1272  * secret_service_prompt() will be used to handle any prompts that show up.
1273  *
1274  * Returns: the number of items or collections that were unlocked
1275  */
1276 gint
1277 secret_service_unlock_dbus_paths_sync (SecretService *self,
1278                                        const gchar **paths,
1279                                        GCancellable *cancellable,
1280                                        gchar ***unlocked,
1281                                        GError **error)
1282 {
1283         SecretSync *sync;
1284         gint count;
1285
1286         g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
1287         g_return_val_if_fail (paths != NULL, -1);
1288         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
1289         g_return_val_if_fail (error == NULL || *error == NULL, -1);
1290
1291         sync = _secret_sync_new ();
1292         g_main_context_push_thread_default (sync->context);
1293
1294         secret_service_unlock_dbus_paths (self, paths, cancellable,
1295                                           _secret_sync_on_result, sync);
1296
1297         g_main_loop_run (sync->loop);
1298
1299         count = secret_service_unlock_dbus_paths_finish (self, sync->result,
1300                                                          unlocked, error);
1301
1302         g_main_context_pop_thread_default (sync->context);
1303         _secret_sync_free (sync);
1304
1305         return count;
1306 }
1307
1308 /**
1309  * secret_service_unlock_dbus_paths:
1310  * @self: the secret service
1311  * @paths: the D-Bus paths for items or collections to unlock
1312  * @cancellable: optional cancellation object
1313  * @callback: called when the operation completes
1314  * @user_data: data to pass to the callback
1315  *
1316  * Unlock items or collections in the secret service.
1317  *
1318  * The items or collections are represented by their D-Bus object paths. If you
1319  * already have #SecretItem and #SecretCollection proxy objects, use use
1320  * secret_service_unlock() instead.
1321  *
1322  * The secret service may not be able to unlock items individually, and may
1323  * unlock an entire collection instead.
1324  *
1325  * This method returns immediately and completes asynchronously. The secret
1326  * service may prompt the user. secret_service_prompt() will be used to handle
1327  * any prompts that show up.
1328  */
1329 void
1330 secret_service_unlock_dbus_paths (SecretService *self,
1331                                   const gchar **paths,
1332                                   GCancellable *cancellable,
1333                                   GAsyncReadyCallback callback,
1334                                   gpointer user_data)
1335 {
1336         g_return_if_fail (SECRET_IS_SERVICE (self));
1337         g_return_if_fail (paths != NULL);
1338         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1339
1340         _secret_service_xlock_paths_async (self, "Unlock",
1341                                            paths, cancellable,
1342                                            callback, user_data);
1343 }
1344
1345 /**
1346  * secret_service_unlock_dbus_paths_finish:
1347  * @self: the secret service
1348  * @result: asynchronous result passed to the callback
1349  * @unlocked: (out) (array zero-terminated=1) (transfer full) (allow-none):
1350  *            location to place array of D-Bus paths of items or collections
1351  *            that were unlocked
1352  * @error: location to place an error on failure
1353  *
1354  * Complete asynchronous operation to unlock items or collections in the secret
1355  * service.
1356  *
1357  * The secret service may not be able to unlock items individually, and may
1358  * unlock an entire collection instead.
1359  *
1360  * Returns: the number of items or collections that were unlocked
1361  */
1362 gint
1363 secret_service_unlock_dbus_paths_finish (SecretService *self,
1364                                          GAsyncResult *result,
1365                                          gchar ***unlocked,
1366                                          GError **error)
1367 {
1368         g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
1369         g_return_val_if_fail (error == NULL || *error == NULL, -1);
1370
1371         return _secret_service_xlock_paths_finish (self, result,
1372                                                    unlocked, error);
1373 }
1374
1375 typedef struct {
1376         GCancellable *cancellable;
1377         SecretPrompt *prompt;
1378         gboolean deleted;
1379 } DeleteClosure;
1380
1381 static void
1382 delete_closure_free (gpointer data)
1383 {
1384         DeleteClosure *closure = data;
1385         g_clear_object (&closure->prompt);
1386         g_clear_object (&closure->cancellable);
1387         g_slice_free (DeleteClosure, closure);
1388 }
1389
1390 static void
1391 on_delete_prompted (GObject *source,
1392                     GAsyncResult *result,
1393                     gpointer user_data)
1394 {
1395         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1396         DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1397         GError *error = NULL;
1398         GVariant *retval;
1399
1400         retval = secret_service_prompt_finish (SECRET_SERVICE (source), result,
1401                                                NULL, &error);
1402
1403         if (error == NULL)
1404                 closure->deleted = TRUE;
1405         else
1406                 g_simple_async_result_take_error (res, error);
1407         if (retval != NULL)
1408                 g_variant_unref (retval);
1409         g_simple_async_result_complete (res);
1410         g_object_unref (res);
1411 }
1412
1413 static void
1414 on_delete_complete (GObject *source,
1415                     GAsyncResult *result,
1416                     gpointer user_data)
1417 {
1418         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1419         DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1420         SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
1421         const gchar *prompt_path;
1422         GError *error = NULL;
1423         GVariant *retval;
1424
1425         retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
1426         if (error == NULL) {
1427                 g_variant_get (retval, "(&o)", &prompt_path);
1428
1429                 if (_secret_util_empty_path (prompt_path)) {
1430                         closure->deleted = TRUE;
1431                         g_simple_async_result_complete (res);
1432
1433                 } else {
1434                         closure->prompt = _secret_prompt_instance (self, prompt_path);
1435
1436                         secret_service_prompt (self, closure->prompt,
1437                                                closure->cancellable,
1438                                                on_delete_prompted,
1439                                                g_object_ref (res));
1440                 }
1441
1442                 g_variant_unref (retval);
1443
1444         } else {
1445                 _secret_util_strip_remote_error (&error);
1446                 g_simple_async_result_take_error (res, error);
1447                 g_simple_async_result_complete (res);
1448         }
1449
1450         g_object_unref (self);
1451         g_object_unref (res);
1452 }
1453
1454 void
1455 _secret_service_delete_path (SecretService *self,
1456                              const gchar *object_path,
1457                              gboolean is_an_item,
1458                              GCancellable *cancellable,
1459                              GAsyncReadyCallback callback,
1460                              gpointer user_data)
1461 {
1462         GSimpleAsyncResult *res;
1463         DeleteClosure *closure;
1464
1465         g_return_if_fail (SECRET_IS_SERVICE (self));
1466         g_return_if_fail (object_path != NULL);
1467         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1468
1469         res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1470                                          _secret_service_delete_path);
1471         closure = g_slice_new0 (DeleteClosure);
1472         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1473         g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free);
1474
1475         g_dbus_connection_call (g_dbus_proxy_get_connection (G_DBUS_PROXY (self)),
1476                                 g_dbus_proxy_get_name (G_DBUS_PROXY (self)), object_path,
1477                                 is_an_item ? SECRET_ITEM_INTERFACE : SECRET_COLLECTION_INTERFACE,
1478                                 "Delete", g_variant_new ("()"), G_VARIANT_TYPE ("(o)"),
1479                                 G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
1480                                 cancellable, on_delete_complete, g_object_ref (res));
1481
1482         g_object_unref (res);
1483 }
1484
1485 gboolean
1486 _secret_service_delete_path_finish (SecretService *self,
1487                                     GAsyncResult *result,
1488                                     GError **error)
1489 {
1490         GSimpleAsyncResult *res;
1491         DeleteClosure *closure;
1492
1493         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1494         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1495         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1496                               _secret_service_delete_path), FALSE);
1497
1498         res = G_SIMPLE_ASYNC_RESULT (result);
1499         if (g_simple_async_result_propagate_error (res, error))
1500                 return FALSE;
1501
1502         closure = g_simple_async_result_get_op_res_gpointer (res);
1503         return closure->deleted;
1504 }
1505
1506 /**
1507  * secret_service_delete_item_dbus_path:
1508  * @self: the secret service
1509  * @item_path: the D-Bus path of item to delete
1510  * @cancellable: optional cancellation object
1511  * @callback: called when the operation completes
1512  * @user_data: data to be passed to the callback
1513  *
1514  * Delete a secret item from the secret service.
1515  *
1516  * The item is represented by its D-Bus object path. If you already have a
1517  * #SecretItem proxy objects, use use secret_item_delete() instead.
1518  *
1519  * This method will return immediately and complete asynchronously.
1520  */
1521 void
1522 secret_service_delete_item_dbus_path (SecretService *self,
1523                                       const gchar *item_path,
1524                                       GCancellable *cancellable,
1525                                       GAsyncReadyCallback callback,
1526                                       gpointer user_data)
1527 {
1528         g_return_if_fail (SECRET_IS_SERVICE (self));
1529         g_return_if_fail (item_path != NULL);
1530         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1531
1532         _secret_service_delete_path (self, item_path, TRUE, cancellable, callback, user_data);
1533 }
1534
1535 /**
1536  * secret_service_delete_item_dbus_path_finish:
1537  * @self: the secret service
1538  * @result: the asynchronous result passed to the callback
1539  * @error: location to place an error on failure
1540  *
1541  * Complete an asynchronous operation to delete a secret item from the secret
1542  * service.
1543  *
1544  * Returns: whether the deletion was successful or not
1545  */
1546 gboolean
1547 secret_service_delete_item_dbus_path_finish (SecretService *self,
1548                                              GAsyncResult *result,
1549                                              GError **error)
1550 {
1551         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1552         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1553         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1554                               _secret_service_delete_path), FALSE);
1555
1556         return _secret_service_delete_path_finish (self, result, error);
1557 }
1558
1559 /**
1560  * secret_service_delete_item_dbus_path_sync:
1561  * @self: the secret service
1562  * @item_path: the D-Bus path of item to delete
1563  * @cancellable: optional cancellation object
1564  * @error: location to place an error on failure
1565  *
1566  * Delete a secret item from the secret service.
1567  *
1568  * The item is represented by its D-Bus object path. If you already have a
1569  * #SecretItem proxy objects, use use secret_item_delete_sync() instead.
1570  *
1571  * This method may block indefinitely and should not be used in user interface
1572  * threads.
1573  *
1574  * Returns: whether the deletion was successful or not
1575  */
1576 gboolean
1577 secret_service_delete_item_dbus_path_sync (SecretService *self,
1578                                            const gchar *item_path,
1579                                            GCancellable *cancellable,
1580                                            GError **error)
1581 {
1582         SecretSync *sync;
1583         gboolean result;
1584
1585         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1586         g_return_val_if_fail (item_path != NULL, FALSE);
1587         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1588         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1589
1590         sync = _secret_sync_new ();
1591         g_main_context_push_thread_default (sync->context);
1592
1593         secret_service_delete_item_dbus_path (self, item_path, cancellable,
1594                                               _secret_sync_on_result, sync);
1595
1596         g_main_loop_run (sync->loop);
1597
1598         result = secret_service_delete_item_dbus_path_finish (self, sync->result, error);
1599
1600         g_main_context_pop_thread_default (sync->context);
1601         _secret_sync_free (sync);
1602
1603         return result;
1604 }
1605
1606 typedef struct {
1607         GCancellable *cancellable;
1608         SecretPrompt *prompt;
1609         gchar *collection_path;
1610 } CollectionClosure;
1611
1612 static void
1613 collection_closure_free (gpointer data)
1614 {
1615         CollectionClosure *closure = data;
1616         g_clear_object (&closure->cancellable);
1617         g_clear_object (&closure->prompt);
1618         g_slice_free (CollectionClosure, closure);
1619 }
1620
1621 static void
1622 on_create_collection_prompt (GObject *source,
1623                              GAsyncResult *result,
1624                              gpointer user_data)
1625 {
1626         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1627         CollectionClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1628         GError *error = NULL;
1629         GVariant *value;
1630
1631         value = secret_service_prompt_finish (SECRET_SERVICE (source), result,
1632                                               G_VARIANT_TYPE ("o"), &error);
1633         if (error != NULL)
1634                 g_simple_async_result_take_error (res, error);
1635         if (value != NULL) {
1636                 closure->collection_path = g_variant_dup_string (value, NULL);
1637                 g_variant_unref (value);
1638         }
1639
1640         g_simple_async_result_complete (res);
1641         g_object_unref (res);
1642 }
1643
1644 static void
1645 on_create_collection_called (GObject *source,
1646                              GAsyncResult *result,
1647                              gpointer user_data)
1648 {
1649         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1650         CollectionClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1651         SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
1652         const gchar *prompt_path = NULL;
1653         const gchar *collection_path = NULL;
1654         GError *error = NULL;
1655         GVariant *retval;
1656
1657         retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
1658         if (error == NULL) {
1659                 g_variant_get (retval, "(&o&o)", &collection_path, &prompt_path);
1660                 if (!_secret_util_empty_path (prompt_path)) {
1661                         closure->prompt = _secret_prompt_instance (self, prompt_path);
1662                         secret_service_prompt (self, closure->prompt,
1663                                                closure->cancellable, on_create_collection_prompt,
1664                                                g_object_ref (res));
1665
1666                 } else {
1667                         closure->collection_path = g_strdup (collection_path);
1668                         g_simple_async_result_complete (res);
1669                 }
1670
1671                 g_variant_unref (retval);
1672
1673         } else {
1674                 _secret_util_strip_remote_error (&error);
1675                 g_simple_async_result_take_error (res, error);
1676                 g_simple_async_result_complete (res);
1677         }
1678
1679         g_object_unref (self);
1680         g_object_unref (res);
1681 }
1682
1683 /**
1684  * secret_service_create_collection_dbus_path:
1685  * @self: a secret service object
1686  * @properties: (element-type utf8 GLib.Variant): hash table of properties for
1687  *              the new collection
1688  * @alias: (allow-none): an alias to check for before creating the new
1689  *         collection, or to assign to the new collection
1690  * @flags: not currently used
1691  * @cancellable: optional cancellation object
1692  * @callback: called when the operation completes
1693  * @user_data: data to be passed to the callback
1694  *
1695  * Create a new collection in the secret service, and return its path.
1696  *
1697  * Using this method requires that you setup a correct hash table of D-Bus
1698  * properties for the new collection. You may prefer to use
1699  * secret_collection_create() which does handles this for you.
1700  *
1701  * An @alias is a well-known tag for a collection, such as 'default' (ie: the
1702  * default collection to store items in). This allows other applications to
1703  * easily identify and share a collection. If a collection with the @alias
1704  * already exists, then instead of creating a new collection, the existing
1705  * collection will be returned. If no collection with this alias exists, then a
1706  * new collection will be created and this alias will be assigned to it.
1707  *
1708  * @properties is a set of properties for the new collection. The keys in the
1709  * hash table should be interface.property strings like
1710  * <literal>org.freedesktop.Secret.Collection.Label</literal>. The values
1711  * in the hash table should be #GVariant values of the properties.
1712  *
1713  * If you wish to have a
1714  *
1715  * This method will return immediately and complete asynchronously. The secret
1716  * service may prompt the user. secret_service_prompt() will be used to handle
1717  * any prompts that are required.
1718  */
1719 void
1720 secret_service_create_collection_dbus_path (SecretService *self,
1721                                             GHashTable *properties,
1722                                             const gchar *alias,
1723                                             SecretCollectionCreateFlags flags,
1724                                             GCancellable *cancellable,
1725                                             GAsyncReadyCallback callback,
1726                                             gpointer user_data)
1727 {
1728         GSimpleAsyncResult *res;
1729         CollectionClosure *closure;
1730         GVariant *params;
1731         GVariant *props;
1732         GDBusProxy *proxy;
1733
1734         g_return_if_fail (SECRET_IS_SERVICE (self));
1735         g_return_if_fail (properties != NULL);
1736         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1737
1738         if (alias == NULL)
1739                 alias = "";
1740
1741         res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1742                                          secret_service_create_collection_dbus_path);
1743         closure = g_slice_new0 (CollectionClosure);
1744         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1745         g_simple_async_result_set_op_res_gpointer (res, closure, collection_closure_free);
1746
1747         props = _secret_util_variant_for_properties (properties);
1748         params = g_variant_new ("(@a{sv}s)", props, alias);
1749         proxy = G_DBUS_PROXY (self);
1750
1751         g_dbus_connection_call (g_dbus_proxy_get_connection (proxy),
1752                                 g_dbus_proxy_get_name (proxy),
1753                                 g_dbus_proxy_get_object_path (proxy),
1754                                 SECRET_SERVICE_INTERFACE,
1755                                 "CreateCollection", params, G_VARIANT_TYPE ("(oo)"),
1756                                 G_DBUS_CALL_FLAGS_NONE, -1,
1757                                 closure->cancellable,
1758                                 on_create_collection_called,
1759                                 g_object_ref (res));
1760
1761         g_object_unref (res);
1762
1763 }
1764
1765 /**
1766  * secret_service_create_collection_dbus_path_finish:
1767  * @self: a secret service object
1768  * @result: the asynchronous result passed to the callback
1769  * @error: location to place an error on failure
1770  *
1771  * Finish asynchronous operation to create a new collection in the secret
1772  * service.
1773  *
1774  * Returns: (transfer full): a new string containing the D-Bus object path
1775  *          of the collection
1776  */
1777 gchar *
1778 secret_service_create_collection_dbus_path_finish (SecretService *self,
1779                                                    GAsyncResult *result,
1780                                                    GError **error)
1781 {
1782         GSimpleAsyncResult *res;
1783         CollectionClosure *closure;
1784         gchar *path;
1785
1786         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1787                               secret_service_create_collection_dbus_path), NULL);
1788         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1789
1790         res = G_SIMPLE_ASYNC_RESULT (result);
1791
1792         if (g_simple_async_result_propagate_error (res, error))
1793                 return NULL;
1794
1795         closure = g_simple_async_result_get_op_res_gpointer (res);
1796         path = closure->collection_path;
1797         closure->collection_path = NULL;
1798         return path;
1799 }
1800
1801 /**
1802  * secret_service_create_collection_dbus_path_sync:
1803  * @self: a secret service object
1804  * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties
1805  *              for the new collection
1806  * @alias: (allow-none): an alias to check for before creating the new
1807  *         collection, or to assign to the new collection
1808  * @flags: not currently used
1809  * @cancellable: optional cancellation object
1810  * @error: location to place an error on failure
1811  *
1812  * Create a new collection in the secret service and return its path.
1813  *
1814  * Using this method requires that you setup a correct hash table of D-Bus
1815  * properties for the new collection. You may prefer to use
1816  * secret_collection_create() which does handles this for you.
1817  *
1818  * An @alias is a well-known tag for a collection, such as 'default' (ie: the
1819  * default collection to store items in). This allows other applications to
1820  * easily identify and share a collection. If a collection with the @alias
1821  * already exists, then instead of creating a new collection, the existing
1822  * collection will be returned. If no collection with this alias exists, then
1823  * a new collection will be created and this alias will be assigned to it.
1824  *
1825  * @properties is a set of properties for the new collection. The keys in the
1826  * hash table should be interface.property strings like
1827  * <literal>org.freedesktop.Secret.Collection.Label</literal>. The values
1828  * in the hash table should be #GVariant values of the properties.
1829  *
1830  * This method may block indefinitely and should not be used in user interface
1831  * threads. The secret service may prompt the user. secret_service_prompt()
1832  * will be used to handle any prompts that are required.
1833  *
1834  * Returns: (transfer full): a new string containing the D-Bus object path
1835  *          of the collection
1836  */
1837 gchar *
1838 secret_service_create_collection_dbus_path_sync (SecretService *self,
1839                                                  GHashTable *properties,
1840                                                  const gchar *alias,
1841                                                  SecretCollectionCreateFlags flags,
1842                                                  GCancellable *cancellable,
1843                                                  GError **error)
1844 {
1845         SecretSync *sync;
1846         gchar *path;
1847
1848         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1849         g_return_val_if_fail (properties != NULL, NULL);
1850         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1851         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1852
1853         sync = _secret_sync_new ();
1854         g_main_context_push_thread_default (sync->context);
1855
1856         secret_service_create_collection_dbus_path (self, properties, alias, flags, cancellable,
1857                                                     _secret_sync_on_result, sync);
1858
1859         g_main_loop_run (sync->loop);
1860
1861         path = secret_service_create_collection_dbus_path_finish (self, sync->result, error);
1862
1863         g_main_context_pop_thread_default (sync->context);
1864         _secret_sync_free (sync);
1865
1866         return path;
1867 }
1868
1869 typedef struct {
1870         GCancellable *cancellable;
1871         GVariant *properties;
1872         SecretValue *value;
1873         gboolean replace;
1874         gchar *collection_path;
1875         SecretPrompt *prompt;
1876         gchar *item_path;
1877 } ItemClosure;
1878
1879 static void
1880 item_closure_free (gpointer data)
1881 {
1882         ItemClosure *closure = data;
1883         g_variant_unref (closure->properties);
1884         secret_value_unref (closure->value);
1885         g_clear_object (&closure->cancellable);
1886         g_free (closure->collection_path);
1887         g_clear_object (&closure->prompt);
1888         g_slice_free (ItemClosure, closure);
1889 }
1890
1891 static void
1892 on_create_item_prompt (GObject *source,
1893                        GAsyncResult *result,
1894                        gpointer user_data)
1895 {
1896         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1897         ItemClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1898         GError *error = NULL;
1899         GVariant *value;
1900
1901         value = secret_service_prompt_finish (SECRET_SERVICE (source), result,
1902                                               G_VARIANT_TYPE ("o"), &error);
1903         if (error != NULL)
1904                 g_simple_async_result_take_error (res, error);
1905         if (value != NULL) {
1906                 closure->item_path = g_variant_dup_string (value, NULL);
1907                 g_variant_unref (value);
1908         }
1909
1910         g_simple_async_result_complete (res);
1911         g_object_unref (res);
1912 }
1913
1914 static void
1915 on_create_item_called (GObject *source,
1916                        GAsyncResult *result,
1917                        gpointer user_data)
1918 {
1919         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1920         ItemClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1921         SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
1922         const gchar *prompt_path = NULL;
1923         const gchar *item_path = NULL;
1924         GError *error = NULL;
1925         GVariant *retval;
1926
1927         retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
1928         if (error == NULL) {
1929                 g_variant_get (retval, "(&o&o)", &item_path, &prompt_path);
1930                 if (!_secret_util_empty_path (prompt_path)) {
1931                         closure->prompt = _secret_prompt_instance (self, prompt_path);
1932                         secret_service_prompt (self, closure->prompt,
1933                                                closure->cancellable, on_create_item_prompt,
1934                                                g_object_ref (res));
1935
1936                 } else {
1937                         closure->item_path = g_strdup (item_path);
1938                         g_simple_async_result_complete (res);
1939                 }
1940
1941                 g_variant_unref (retval);
1942
1943         } else {
1944                 _secret_util_strip_remote_error (&error);
1945                 g_simple_async_result_take_error (res, error);
1946                 g_simple_async_result_complete (res);
1947         }
1948
1949         g_object_unref (self);
1950         g_object_unref (res);
1951 }
1952
1953 static void
1954 on_create_item_session (GObject *source,
1955                         GAsyncResult *result,
1956                         gpointer user_data)
1957 {
1958         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1959         ItemClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1960         SecretService *self = SECRET_SERVICE (source);
1961         SecretSession *session;
1962         GVariant *params;
1963         GError *error = NULL;
1964         GDBusProxy *proxy;
1965
1966         secret_service_ensure_session_finish (self, result, &error);
1967         if (error == NULL) {
1968                 session = _secret_service_get_session (self);
1969                 params = g_variant_new ("(@a{sv}@(oayays)b)",
1970                                         closure->properties,
1971                                         _secret_session_encode_secret (session, closure->value),
1972                                         closure->replace);
1973
1974                 proxy = G_DBUS_PROXY (self);
1975                 g_dbus_connection_call (g_dbus_proxy_get_connection (proxy),
1976                                         g_dbus_proxy_get_name (proxy),
1977                                         closure->collection_path,
1978                                         SECRET_COLLECTION_INTERFACE,
1979                                         "CreateItem", params, G_VARIANT_TYPE ("(oo)"),
1980                                         G_DBUS_CALL_FLAGS_NONE, -1,
1981                                         closure->cancellable,
1982                                         on_create_item_called,
1983                                         g_object_ref (res));
1984         } else {
1985                 g_simple_async_result_take_error (res, error);
1986                 g_simple_async_result_complete (res);
1987         }
1988
1989         g_object_unref (res);
1990 }
1991
1992 /**
1993  * secret_service_create_item_dbus_path:
1994  * @self: a secret service object
1995  * @collection_path: the D-Bus object path of the collection in which to create item
1996  * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties
1997  *              for the new collection
1998  * @value: the secret value to store in the item
1999  * @flags: flags for the creation of the new item
2000  * @cancellable: optional cancellation object
2001  * @callback: called when the operation completes
2002  * @user_data: data to be passed to the callback
2003  *
2004  * Create a new item in a secret service collection and return its D-Bus
2005  * object path.
2006  *
2007  * It is often easier to use secret_password_store() or secret_item_create()
2008  * rather than using this function. Using this method requires that you setup
2009  * a correct hash table of D-Bus @properties for the new collection.
2010  *
2011  * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret
2012  * service will search for an item matching the @attributes, and update that item
2013  * instead of creating a new one.
2014  *
2015  * @properties is a set of properties for the new collection. The keys in the
2016  * hash table should be interface.property strings like
2017  * <literal>org.freedesktop.Secret.Item.Label</literal>. The values
2018  * in the hash table should be #GVariant values of the properties.
2019  *
2020  * This method will return immediately and complete asynchronously. The secret
2021  * service may prompt the user. secret_service_prompt() will be used to handle
2022  * any prompts that are required.
2023  */
2024 void
2025 secret_service_create_item_dbus_path (SecretService *self,
2026                                       const gchar *collection_path,
2027                                       GHashTable *properties,
2028                                       SecretValue *value,
2029                                       SecretItemCreateFlags flags,
2030                                       GCancellable *cancellable,
2031                                       GAsyncReadyCallback callback,
2032                                       gpointer user_data)
2033 {
2034         GSimpleAsyncResult *res;
2035         ItemClosure *closure;
2036
2037         g_return_if_fail (SECRET_IS_SERVICE (self));
2038         g_return_if_fail (collection_path != NULL && g_variant_is_object_path (collection_path));
2039         g_return_if_fail (properties != NULL);
2040         g_return_if_fail (value != NULL);
2041         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
2042
2043         res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
2044                                          secret_service_create_item_dbus_path);
2045         closure = g_slice_new0 (ItemClosure);
2046         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
2047         closure->properties = _secret_util_variant_for_properties (properties);
2048         g_variant_ref_sink (closure->properties);
2049         closure->replace = flags & SECRET_ITEM_CREATE_REPLACE;
2050         closure->value = secret_value_ref (value);
2051         closure->collection_path = g_strdup (collection_path);
2052         g_simple_async_result_set_op_res_gpointer (res, closure, item_closure_free);
2053
2054         secret_service_ensure_session (self, cancellable,
2055                                        on_create_item_session,
2056                                        g_object_ref (res));
2057
2058         g_object_unref (res);
2059 }
2060
2061 /**
2062  * secret_service_create_item_dbus_path_finish:
2063  * @self: a secret service object
2064  * @result: the asynchronous result passed to the callback
2065  * @error: location to place an error on failure
2066  *
2067  * Finish asynchronous operation to create a new item in the secret
2068  * service.
2069  *
2070  * Returns: (transfer full): a new string containing the D-Bus object path
2071  *          of the item
2072  */
2073 gchar *
2074 secret_service_create_item_dbus_path_finish (SecretService *self,
2075                                              GAsyncResult *result,
2076                                              GError **error)
2077 {
2078         GSimpleAsyncResult *res;
2079         ItemClosure *closure;
2080         gchar *path;
2081
2082         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
2083                               secret_service_create_item_dbus_path), NULL);
2084         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2085
2086         res = G_SIMPLE_ASYNC_RESULT (result);
2087
2088         if (g_simple_async_result_propagate_error (res, error))
2089                 return NULL;
2090
2091         closure = g_simple_async_result_get_op_res_gpointer (res);
2092         path = closure->item_path;
2093         closure->item_path = NULL;
2094         return path;
2095 }
2096
2097 /**
2098  * secret_service_create_item_dbus_path_sync:
2099  * @self: a secret service object
2100  * @collection_path: the D-Bus path of the collection in which to create item
2101  * @properties: (element-type utf8 GLib.Variant): hash table of D-Bus properties
2102  *              for the new collection
2103  * @value: the secret value to store in the item
2104  * @flags: flags for the creation of the new item
2105  * @cancellable: optional cancellation object
2106  * @error: location to place an error on failure
2107  *
2108  * Create a new item in a secret service collection and return its D-Bus
2109  * object path.
2110  *
2111  * It is often easier to use secret_password_store_sync() or secret_item_create_sync()
2112  * rather than using this function. Using this method requires that you setup
2113  * a correct hash table of D-Bus @properties for the new collection.
2114  *
2115  * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret
2116  * service will search for an item matching the @attributes, and update that item
2117  * instead of creating a new one.
2118  *
2119  * @properties is a set of properties for the new collection. The keys in the
2120  * hash table should be interface.property strings like
2121  * <literal>org.freedesktop.Secret.Item.Label</literal>. The values
2122  * in the hash table should be #GVariant values of the properties.
2123  *
2124  * This method may block indefinitely and should not be used in user interface
2125  * threads. The secret service may prompt the user. secret_service_prompt()
2126  * will be used to handle any prompts that are required.
2127  *
2128  * Returns: (transfer full): a new string containing the D-Bus object path
2129  *          of the item
2130  */
2131 gchar *
2132 secret_service_create_item_dbus_path_sync (SecretService *self,
2133                                            const gchar *collection_path,
2134                                            GHashTable *properties,
2135                                            SecretValue *value,
2136                                            SecretItemCreateFlags flags,
2137                                            GCancellable *cancellable,
2138                                            GError **error)
2139 {
2140         SecretSync *sync;
2141         gchar *path;
2142
2143         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
2144         g_return_val_if_fail (collection_path != NULL && g_variant_is_object_path (collection_path), NULL);
2145         g_return_val_if_fail (properties != NULL, NULL);
2146         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
2147         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2148
2149         sync = _secret_sync_new ();
2150         g_main_context_push_thread_default (sync->context);
2151
2152         secret_service_create_item_dbus_path (self, collection_path, properties, value, flags,
2153                                               cancellable, _secret_sync_on_result, sync);
2154
2155         g_main_loop_run (sync->loop);
2156
2157         path = secret_service_create_item_dbus_path_finish (self, sync->result, error);
2158
2159         g_main_context_pop_thread_default (sync->context);
2160         _secret_sync_free (sync);
2161
2162         return path;
2163 }
2164
2165 /**
2166  * secret_service_read_alias_dbus_path:
2167  * @self: a secret service object
2168  * @alias: the alias to lookup
2169  * @cancellable: (allow-none): optional cancellation object
2170  * @callback: called when the operation completes
2171  * @user_data: data to pass to the callback
2172  *
2173  * Lookup which collection is assigned to this alias. Aliases help determine
2174  * well known collections, such as 'default'. This method looks up the
2175  * dbus object path of the well known collection.
2176  *
2177  * This method will return immediately and complete asynchronously.
2178  */
2179 void
2180 secret_service_read_alias_dbus_path (SecretService *self,
2181                                      const gchar *alias,
2182                                      GCancellable *cancellable,
2183                                      GAsyncReadyCallback callback,
2184                                      gpointer user_data)
2185 {
2186         g_return_if_fail (SECRET_IS_SERVICE (self));
2187         g_return_if_fail (alias != NULL);
2188         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
2189
2190         g_dbus_proxy_call (G_DBUS_PROXY (self), "ReadAlias",
2191                            g_variant_new ("(s)", alias),
2192                            G_DBUS_CALL_FLAGS_NONE, -1,
2193                            cancellable, callback, user_data);
2194 }
2195
2196 /**
2197  * secret_service_read_alias_dbus_path_finish:
2198  * @self: a secret service object
2199  * @result: asynchronous result passed to callback
2200  * @error: location to place error on failure
2201  *
2202  * Finish an asynchronous operation to lookup which collection is assigned
2203  * to an alias. This method returns the DBus object path of the collection
2204  *
2205  * Returns: (transfer full): the collection dbus object path, or %NULL if
2206  *          none assigned to the alias
2207  */
2208 gchar *
2209 secret_service_read_alias_dbus_path_finish (SecretService *self,
2210                                             GAsyncResult *result,
2211                                             GError **error)
2212 {
2213         gchar *collection_path;
2214         GVariant *retval;
2215
2216         retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, error);
2217
2218         _secret_util_strip_remote_error (error);
2219         if (retval == NULL)
2220                 return NULL;
2221
2222         g_variant_get (retval, "(o)", &collection_path);
2223         g_variant_unref (retval);
2224
2225         if (g_str_equal (collection_path, "/")) {
2226                 g_free (collection_path);
2227                 collection_path = NULL;
2228         }
2229
2230         return collection_path;
2231 }
2232
2233 /**
2234  * secret_service_read_alias_dbus_path_sync:
2235  * @self: a secret service object
2236  * @alias: the alias to lookup
2237  * @cancellable: (allow-none): optional cancellation object
2238  * @error: location to place error on failure
2239  *
2240  * Lookup which collection is assigned to this alias. Aliases help determine
2241  * well known collections, such as 'default'. This method returns the dbus
2242  * object path of the collection.
2243  *
2244  * This method may block and should not be used in user interface threads.
2245  *
2246  * Returns: (transfer full): the collection dbus object path, or %NULL if
2247  *          none assigned to the alias
2248  */
2249 gchar *
2250 secret_service_read_alias_dbus_path_sync (SecretService *self,
2251                                           const gchar *alias,
2252                                           GCancellable *cancellable,
2253                                           GError **error)
2254 {
2255         SecretSync *sync;
2256         gchar *collection_path;
2257
2258         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
2259         g_return_val_if_fail (alias != NULL, NULL);
2260         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
2261         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2262
2263         sync = _secret_sync_new ();
2264         g_main_context_push_thread_default (sync->context);
2265
2266         secret_service_read_alias_dbus_path (self, alias, cancellable, _secret_sync_on_result, sync);
2267
2268         g_main_loop_run (sync->loop);
2269
2270         collection_path = secret_service_read_alias_dbus_path_finish (self, sync->result, error);
2271
2272         g_main_context_pop_thread_default (sync->context);
2273         _secret_sync_free (sync);
2274
2275         return collection_path;
2276 }
2277
2278 /**
2279  * secret_service_set_alias_to_dbus_path:
2280  * @self: a secret service object
2281  * @alias: the alias to assign the collection to
2282  * @collection_path: (allow-none): the dbus object path of the collection to assign to the alias
2283  * @cancellable: (allow-none): optional cancellation object
2284  * @callback: called when the operation completes
2285  * @user_data: data to pass to the callback
2286  *
2287  * Assign a collection to this alias. Aliases help determine
2288  * well known collections, such as 'default'. This method takes the dbus object
2289  * path of the collection to assign to the alias.
2290  *
2291  * This method will return immediately and complete asynchronously.
2292  */
2293 void
2294 secret_service_set_alias_to_dbus_path (SecretService *self,
2295                                        const gchar *alias,
2296                                        const gchar *collection_path,
2297                                        GCancellable *cancellable,
2298                                        GAsyncReadyCallback callback,
2299                                        gpointer user_data)
2300 {
2301         g_return_if_fail (SECRET_IS_SERVICE (self));
2302         g_return_if_fail (alias != NULL);
2303         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
2304
2305         if (collection_path == NULL)
2306                 collection_path = "/";
2307         else
2308                 g_return_if_fail (g_variant_is_object_path (collection_path));
2309
2310         g_dbus_proxy_call (G_DBUS_PROXY (self), "SetAlias",
2311                            g_variant_new ("(so)", alias, collection_path),
2312                            G_DBUS_CALL_FLAGS_NONE, -1, cancellable,
2313                            callback, user_data);
2314 }
2315
2316 /**
2317  * secret_service_set_alias_to_dbus_path_finish:
2318  * @self: a secret service object
2319  * @result: asynchronous result passed to callback
2320  * @error: location to place error on failure
2321  *
2322  * Finish an asynchronous operation to assign a collection to an alias.
2323  *
2324  * Returns: %TRUE if successful
2325  */
2326 gboolean
2327 secret_service_set_alias_to_dbus_path_finish (SecretService *self,
2328                                               GAsyncResult *result,
2329                                               GError **error)
2330 {
2331         GVariant *retval;
2332
2333         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
2334         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2335
2336         retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, error);
2337
2338         _secret_util_strip_remote_error (error);
2339         if (retval == NULL)
2340                 return FALSE;
2341
2342         g_variant_unref (retval);
2343         return TRUE;
2344 }
2345
2346 /**
2347  * secret_service_set_alias_to_dbus_path_sync:
2348  * @self: a secret service object
2349  * @alias: the alias to assign the collection to
2350  * @collection_path: (allow-none): the dbus object path of the collection to assign to the alias
2351  * @cancellable: (allow-none): optional cancellation object
2352  * @error: location to place error on failure
2353  *
2354  * Assign a collection to this alias. Aliases help determine
2355  * well known collections, such as 'default'. This method takes the dbus object
2356  * path of the collection to assign to the alias.
2357  *
2358  * This method may block and should not be used in user interface threads.
2359  *
2360  * Returns: %TRUE if successful
2361  */
2362 gboolean
2363 secret_service_set_alias_to_dbus_path_sync (SecretService *self,
2364                                             const gchar *alias,
2365                                             const gchar *collection_path,
2366                                             GCancellable *cancellable,
2367                                             GError **error)
2368 {
2369         SecretSync *sync;
2370         gboolean ret;
2371
2372         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
2373         g_return_val_if_fail (alias != NULL, FALSE);
2374         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
2375         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2376
2377         if (collection_path == NULL)
2378                 collection_path = "/";
2379         else
2380                 g_return_val_if_fail (g_variant_is_object_path (collection_path), FALSE);
2381
2382         sync = _secret_sync_new ();
2383         g_main_context_push_thread_default (sync->context);
2384
2385         secret_service_set_alias_to_dbus_path (self, alias, collection_path,
2386                                                cancellable, _secret_sync_on_result, sync);
2387
2388         g_main_loop_run (sync->loop);
2389
2390         ret = secret_service_set_alias_to_dbus_path_finish (self, sync->result, error);
2391
2392         g_main_context_pop_thread_default (sync->context);
2393         _secret_sync_free (sync);
2394
2395         return ret;
2396 }
2397
2398 GVariant *
2399 secret_service_prompt_at_dbus_path_sync (SecretService *self,
2400                                          const gchar *prompt_path,
2401                                          GCancellable *cancellable,
2402                                          const GVariantType *return_type,
2403                                          GError **error)
2404 {
2405         SecretPrompt *prompt;
2406         GVariant *retval;
2407
2408         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
2409         g_return_val_if_fail (prompt_path != NULL, NULL);
2410         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
2411         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2412
2413         prompt = _secret_prompt_instance (self, prompt_path);
2414         retval = secret_service_prompt_sync (self, prompt, cancellable, return_type, error);
2415         g_object_unref (prompt);
2416
2417         return retval;
2418 }
2419
2420 /**
2421  * secret_service_prompt_at_dbus_path:
2422  * @self: the secret service
2423  * @prompt_path: the D-Bus object path of the prompt
2424  * @cancellable: optional cancellation object
2425  * @callback: called when the operation completes
2426  * @user_data: data to be passed to the callback
2427  *
2428  * Perform prompting for a #SecretPrompt.
2429  *
2430  * This function is called by other parts of this library to handle prompts
2431  * for the various actions that can require prompting.
2432  *
2433  * Override the #SecretServiceClass <literal>prompt_async</literal> virtual method
2434  * to change the behavior of the propmting. The default behavior is to simply
2435  * run secret_prompt_perform() on the prompt.
2436  */
2437 void
2438 secret_service_prompt_at_dbus_path (SecretService *self,
2439                                     const gchar *prompt_path,
2440                                     GCancellable *cancellable,
2441                                     GAsyncReadyCallback callback,
2442                                     gpointer user_data)
2443 {
2444         SecretPrompt *prompt;
2445
2446         g_return_if_fail (SECRET_IS_SERVICE (self));
2447         g_return_if_fail (prompt_path != NULL);
2448         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
2449
2450         prompt = _secret_prompt_instance (self, prompt_path);
2451         secret_service_prompt (self, prompt, cancellable, callback, user_data);
2452         g_object_unref (prompt);
2453 }
2454
2455 /**
2456  * secret_service_prompt_at_dbus_path_finish:
2457  * @self: the secret service
2458  * @result: the asynchronous result passed to the callback
2459  * @return_type: the variant type of the prompt result
2460  * @error: location to place an error on failure
2461  *
2462  * Complete asynchronous operation to perform prompting for a #SecretPrompt.
2463  *
2464  * Returns a variant result if the prompt was completed and not dismissed. The
2465  * type of result depends on the action the prompt is completing, and is defined
2466  * in the Secret Service DBus API specification.
2467  *
2468  * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred,
2469  *          a variant result if the prompt was successful
2470  */
2471 GVariant *
2472 secret_service_prompt_at_dbus_path_finish (SecretService *self,
2473                                            GAsyncResult *result,
2474                                            const GVariantType *return_type,
2475                                            GError **error)
2476 {
2477         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
2478         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2479         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2480
2481         return secret_service_prompt_finish (self, result, return_type, error);
2482 }