tests: Fix up the javascript and python tests
[platform/upstream/libsecret.git] / libsecret / secret-service.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-collection.h"
19 #include "secret-dbus-generated.h"
20 #include "secret-enum-types.h"
21 #include "secret-item.h"
22 #include "secret-paths.h"
23 #include "secret-private.h"
24 #include "secret-service.h"
25 #include "secret-types.h"
26 #include "secret-value.h"
27
28 #include "egg/egg-secure-memory.h"
29
30 /**
31  * SECTION:secret-service
32  * @title: SecretService
33  * @short_description: the Secret Service
34  *
35  * A #SecretService object represents the Secret Service implementation which
36  * runs as a D-Bus service.
37  *
38  * Normally a single #SecretService object can be shared between multiple
39  * callers. The secret_service_get() method is used to access this #SecretService
40  * object. If a new independent #SecretService object is required, use
41  * secret_service_open().
42  *
43  * In order to securely transfer secrets to the Sercret Service, an session
44  * is established. This session can be established while initializing a
45  * #SecretService object by passing the %SECRET_SERVICE_OPEN_SESSION flag
46  * to the secret_service_get() or secret_service_open() functions. In order to
47  * establish a session on an already existing #SecretService, use the
48  * secret_service_ensure_session() function.
49  *
50  * To search for items, use the secret_service_search() method.
51  *
52  * Multiple collections can exist in the Secret Service, each of which contains
53  * secret items. In order to instantiate #SecretCollection objects which
54  * represent those collections while initializing a #SecretService then pass
55  * the %SECRET_SERVICE_LOAD_COLLECTIONS flag to the secret_service_get() or
56  * secret_service_open() functions. In order to establish a session on an already
57  * existing #SecretService, use the secret_service_load_collections() function.
58  * To access the list of collections use secret_service_get_collections().
59  *
60  * Certain actions on the Secret Service require user prompting to complete,
61  * such as creating a collection, or unlocking a collection. When such a prompt
62  * is necessary, then a #SecretPrompt object is created by this library, and
63  * passed to the secret_service_prompt() method. In this way it is handled
64  * automatically.
65  *
66  * In order to customize prompt handling, override the <literal>prompt_async</literal>
67  * and <literal>prompt_finish</literal> virtual methods of the #SecretService class.
68  *
69  * These functions have an unstable API and may change across versions. Use
70  * <literal>libsecret-unstable</literal> package to access them.
71  *
72  * Stability: Unstable
73  */
74
75 /**
76  * SecretService:
77  *
78  * A proxy object representing the Secret Service.
79  */
80
81 /**
82  * SecretServiceClass:
83  * @parent_class: the parent class
84  * @collection_gtype: the #GType of the #SecretCollection objects instantiated
85  *                    by the #SecretService proxy
86  * @item_gtype: the #GType of the #SecretItem objects instantiated by the
87  *              #SecretService proxy
88  * @prompt_async: called to perform asynchronous prompting when necessary
89  * @prompt_finish: called to complete an asynchronous prompt operation
90  * @prompt_sync: called to perform synchronous prompting when necessary
91  * @get_collection_gtype: called to get the GObject type for collections
92  *                        instantiated by the #SecretService proxy
93  * @get_item_gtype: called to get the GObject type for collections
94  *                  instantiated by the #SecretService proxy
95  *
96  * The class for #SecretService.
97  */
98
99 /**
100  * SecretServiceFlags:
101  * @SECRET_SERVICE_NONE: no flags for initializing the #SecretService
102  * @SECRET_SERVICE_OPEN_SESSION: establish a session for transfer of secrets
103  *                               while initializing the #SecretService
104  * @SECRET_SERVICE_LOAD_COLLECTIONS: load collections while initializing the
105  *                                   #SecretService
106  *
107  * Flags which determine which parts of the #SecretService proxy are initialized
108  * during a secret_service_get() or secret_service_open() operation.
109  */
110
111 EGG_SECURE_DEFINE_GLIB_GLOBALS ();
112
113 GQuark _secret_error_quark = 0;
114
115 enum {
116         PROP_0,
117         PROP_FLAGS,
118         PROP_COLLECTIONS
119 };
120
121 struct _SecretServicePrivate {
122         /* No change between construct and finalize */
123         GCancellable *cancellable;
124         SecretServiceFlags init_flags;
125
126         /* Locked by mutex */
127         GMutex mutex;
128         gpointer session;
129         GHashTable *collections;
130 };
131
132 G_LOCK_DEFINE (service_instance);
133 static gpointer service_instance = NULL;
134 static guint service_watch = 0;
135
136 static GInitableIface *secret_service_initable_parent_iface = NULL;
137
138 static GAsyncInitableIface *secret_service_async_initable_parent_iface = NULL;
139
140 static void   secret_service_initable_iface         (GInitableIface *iface);
141
142 static void   secret_service_async_initable_iface   (GAsyncInitableIface *iface);
143
144 G_DEFINE_TYPE_WITH_CODE (SecretService, secret_service, G_TYPE_DBUS_PROXY,
145                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_service_initable_iface);
146                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_service_async_initable_iface);
147 );
148
149 static SecretService *
150 service_get_instance (void)
151 {
152         SecretService *instance = NULL;
153
154         G_LOCK (service_instance);
155         if (service_instance != NULL)
156                 instance = g_object_ref (service_instance);
157         G_UNLOCK (service_instance);
158
159         return instance;
160 }
161
162 static gboolean
163 service_uncache_instance (SecretService *which)
164 {
165         SecretService *instance = NULL;
166         guint watch = 0;
167         gboolean matched = FALSE;
168
169         G_LOCK (service_instance);
170         if (which == NULL || service_instance == which) {
171                 instance = service_instance;
172                 service_instance = NULL;
173                 watch = service_watch;
174                 service_watch = 0;
175                 matched = TRUE;
176         }
177         G_UNLOCK (service_instance);
178
179         if (instance != NULL)
180                 g_object_unref (instance);
181         if (watch != 0)
182                 g_bus_unwatch_name (watch);
183
184         return matched;
185 }
186
187 static void
188 on_service_instance_vanished (GDBusConnection *connection,
189                               const gchar *name,
190                               gpointer user_data)
191 {
192         if (!service_uncache_instance (user_data)) {
193                 g_warning ("Global default SecretService instance out of sync "
194                            "with the watch for its DBus name");
195         }
196 }
197
198 static void
199 service_cache_instance (SecretService *instance)
200 {
201         GDBusProxy *proxy;
202         guint watch;
203
204         g_object_ref (instance);
205         proxy = G_DBUS_PROXY (instance);
206         watch = g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (proxy),
207                                                 g_dbus_proxy_get_name (proxy),
208                                                 G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
209                                                 NULL, on_service_instance_vanished,
210                                                 instance, NULL);
211
212         G_LOCK (service_instance);
213         if (service_instance == NULL) {
214                 service_instance = instance;
215                 instance = NULL;
216                 service_watch = watch;
217                 watch = 0;
218         }
219         G_UNLOCK (service_instance);
220
221         if (instance != NULL)
222                 g_object_unref (instance);
223         if (watch != 0)
224                 g_bus_unwatch_name (watch);
225 }
226
227 static void
228 secret_service_init (SecretService *self)
229 {
230         self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, SECRET_TYPE_SERVICE,
231                                                 SecretServicePrivate);
232
233         g_mutex_init (&self->pv->mutex);
234         self->pv->cancellable = g_cancellable_new ();
235 }
236
237 static void
238 secret_service_get_property (GObject *obj,
239                              guint prop_id,
240                              GValue *value,
241                              GParamSpec *pspec)
242 {
243         SecretService *self = SECRET_SERVICE (obj);
244
245         switch (prop_id) {
246         case PROP_FLAGS:
247                 g_value_set_flags (value, secret_service_get_flags (self));
248                 break;
249         case PROP_COLLECTIONS:
250                 g_value_take_boxed (value, secret_service_get_collections (self));
251                 break;
252         default:
253                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
254                 break;
255         }
256 }
257
258 static void
259 secret_service_set_property (GObject *obj,
260                              guint prop_id,
261                              const GValue *value,
262                              GParamSpec *pspec)
263 {
264         SecretService *self = SECRET_SERVICE (obj);
265
266         switch (prop_id) {
267         case PROP_FLAGS:
268                 self->pv->init_flags = g_value_get_flags (value);
269                 break;
270         default:
271                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
272                 break;
273         }
274 }
275
276 static void
277 secret_service_dispose (GObject *obj)
278 {
279         SecretService *self = SECRET_SERVICE (obj);
280
281         g_cancellable_cancel (self->pv->cancellable);
282
283         G_OBJECT_CLASS (secret_service_parent_class)->dispose (obj);
284 }
285
286 static void
287 secret_service_finalize (GObject *obj)
288 {
289         SecretService *self = SECRET_SERVICE (obj);
290
291         _secret_session_free (self->pv->session);
292         if (self->pv->collections)
293                 g_hash_table_destroy (self->pv->collections);
294         g_clear_object (&self->pv->cancellable);
295         g_mutex_clear (&self->pv->mutex);
296
297         G_OBJECT_CLASS (secret_service_parent_class)->finalize (obj);
298 }
299
300 static GVariant *
301 secret_service_real_prompt_sync (SecretService *self,
302                                  SecretPrompt *prompt,
303                                  GCancellable *cancellable,
304                                  const GVariantType *return_type,
305                                  GError **error)
306 {
307         return secret_prompt_perform_sync (prompt, 0, cancellable, return_type, error);
308 }
309
310 static void
311 on_real_prompt_completed (GObject *source,
312                           GAsyncResult *result,
313                           gpointer user_data)
314 {
315         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
316         GError *error = NULL;
317         GVariant *retval;
318
319         retval = secret_prompt_perform_finish (SECRET_PROMPT (source), result, &error);
320         if (retval != NULL)
321                 g_simple_async_result_set_op_res_gpointer (res, retval, (GDestroyNotify)g_variant_unref);
322         if (error != NULL)
323                 g_simple_async_result_take_error (res, error);
324         g_simple_async_result_complete (res);
325         g_object_unref (res);
326 }
327
328 static void
329 secret_service_real_prompt_async (SecretService *self,
330                                   SecretPrompt *prompt,
331                                   const GVariantType *return_type,
332                                   GCancellable *cancellable,
333                                   GAsyncReadyCallback callback,
334                                   gpointer user_data)
335 {
336         GSimpleAsyncResult *res;
337
338         res =  g_simple_async_result_new (G_OBJECT (self), callback, user_data,
339                                           secret_service_real_prompt_async);
340
341         secret_prompt_perform (prompt, 0, return_type, cancellable,
342                                on_real_prompt_completed,
343                                g_object_ref (res));
344
345         g_object_unref (res);
346 }
347
348 static GVariant *
349 secret_service_real_prompt_finish (SecretService *self,
350                                    GAsyncResult *result,
351                                    GError **error)
352 {
353         GSimpleAsyncResult *res;
354         GVariant *retval;
355
356         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
357                               secret_service_real_prompt_async), NULL);
358
359         res = G_SIMPLE_ASYNC_RESULT (result);
360         if (_secret_util_propagate_error (res, error))
361                 return NULL;
362
363         retval = g_simple_async_result_get_op_res_gpointer (res);
364         if (retval == NULL)
365                 return NULL;
366
367         return g_variant_ref (retval);
368 }
369
370 static void
371 handle_property_changed (SecretService *self,
372                          const gchar *property_name,
373                          GVariant *value)
374 {
375         gboolean perform;
376
377         g_variant_ref_sink (value);
378
379         if (g_str_equal (property_name, "Collections")) {
380
381                 g_mutex_lock (&self->pv->mutex);
382                 perform = self->pv->collections != NULL;
383                 g_mutex_unlock (&self->pv->mutex);
384
385                 if (perform)
386                         secret_service_load_collections (self, self->pv->cancellable, NULL, NULL);
387         }
388
389         g_variant_unref (value);
390 }
391
392 static void
393 secret_service_properties_changed (GDBusProxy *proxy,
394                                    GVariant *changed_properties,
395                                    const gchar* const *invalidated_properties)
396 {
397         SecretService *self = SECRET_SERVICE (proxy);
398         gchar *property_name;
399         GVariantIter iter;
400         GVariant *value;
401
402         g_object_freeze_notify (G_OBJECT (self));
403
404         g_variant_iter_init (&iter, changed_properties);
405         while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value))
406                 handle_property_changed (self, property_name, value);
407
408         g_object_thaw_notify (G_OBJECT (self));
409 }
410
411 static void
412 secret_service_signal (GDBusProxy *proxy,
413                        const gchar *sender_name,
414                        const gchar *signal_name,
415                        GVariant *parameters)
416 {
417         SecretService *self = SECRET_SERVICE (proxy);
418         SecretCollection *collection;
419         const gchar *collection_path;
420         GVariantBuilder builder;
421         gboolean found = FALSE;
422         GVariantIter iter;
423         GVariant *value;
424         GVariant *paths;
425         GVariant *path;
426
427         /*
428          * Remember that these signals come from a time before PropertiesChanged.
429          * We support them because they're in the spec, and ksecretservice uses them.
430          */
431
432         paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
433
434         /* A new collection was added, add it to the Collections property */
435         if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CREATED)) {
436                 g_variant_get (parameters, "(@o)", &value);
437                 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
438                 g_variant_iter_init (&iter, paths);
439                 while ((path = g_variant_iter_next_value (&iter)) != NULL) {
440                         if (g_variant_equal (path, value)) {
441                                 found = TRUE;
442                                 break;
443                         }
444                         g_variant_builder_add_value (&builder, path);
445                         g_variant_unref (path);
446                 }
447                 if (!found) {
448                         g_variant_builder_add_value (&builder, value);
449                         handle_property_changed (self, "Collections", g_variant_builder_end (&builder));
450                 }
451                 g_variant_builder_clear (&builder);
452                 g_variant_unref (value);
453
454         /* A collection was deleted, remove it from the Collections property */
455         } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_DELETED)) {
456                 g_variant_get (parameters, "(@o)", &value);
457                 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
458                 g_variant_iter_init (&iter, paths);
459                 while ((path = g_variant_iter_next_value (&iter)) != NULL) {
460                         if (g_variant_equal (path, value))
461                                 found = TRUE;
462                         else
463                                 g_variant_builder_add_value (&builder, path);
464                         g_variant_unref (path);
465                 }
466                 if (found)
467                         handle_property_changed (self, "Collections", g_variant_builder_end (&builder));
468                 g_variant_unref (value);
469
470         /* The collection changed, update it */
471         } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CHANGED)) {
472                 g_variant_get (parameters, "(&o)", &collection_path);
473
474                 g_mutex_lock (&self->pv->mutex);
475
476                 if (self->pv->collections)
477                         collection = g_hash_table_lookup (self->pv->collections, collection_path);
478                 else
479                         collection = NULL;
480                 if (collection)
481                         g_object_ref (collection);
482
483                 g_mutex_unlock (&self->pv->mutex);
484
485                 if (collection) {
486                         secret_collection_refresh (collection);
487                         g_object_unref (collection);
488                 }
489         }
490
491         g_variant_unref (paths);
492 }
493
494 static GType
495 secret_service_real_get_collection_gtype (SecretService *self)
496 {
497         SecretServiceClass *klass;
498
499         klass = SECRET_SERVICE_GET_CLASS (self);
500         return klass->collection_gtype;
501 }
502
503 static GType
504 secret_service_real_get_item_gtype (SecretService *self)
505 {
506         SecretServiceClass *klass;
507
508         klass = SECRET_SERVICE_GET_CLASS (self);
509         return klass->item_gtype;
510 }
511
512 static void
513 secret_service_class_init (SecretServiceClass *klass)
514 {
515         GObjectClass *object_class = G_OBJECT_CLASS (klass);
516         GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass);
517
518         object_class->get_property = secret_service_get_property;
519         object_class->set_property = secret_service_set_property;
520         object_class->dispose = secret_service_dispose;
521         object_class->finalize = secret_service_finalize;
522
523         proxy_class->g_properties_changed = secret_service_properties_changed;
524         proxy_class->g_signal = secret_service_signal;
525
526         klass->prompt_sync = secret_service_real_prompt_sync;
527         klass->prompt_async = secret_service_real_prompt_async;
528         klass->prompt_finish = secret_service_real_prompt_finish;
529
530         klass->item_gtype = SECRET_TYPE_ITEM;
531         klass->collection_gtype = SECRET_TYPE_COLLECTION;
532         klass->get_item_gtype = secret_service_real_get_item_gtype;
533         klass->get_collection_gtype = secret_service_real_get_collection_gtype;
534
535         /**
536          * SecretService:flags:
537          *
538          * A set of flags describing which parts of the secret service have
539          * been initialized.
540          */
541         g_object_class_install_property (object_class, PROP_FLAGS,
542                      g_param_spec_flags ("flags", "Flags", "Service flags",
543                                          secret_service_flags_get_type (), SECRET_SERVICE_NONE,
544                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
545
546         /**
547          * SecretService:collections:
548          *
549          * A list of #SecretCollection objects representing the collections in
550          * the Secret Service. This list may be %NULL if the collections have
551          * not been loaded.
552          *
553          * To load the collections, specify the %SECRET_SERVICE_LOAD_COLLECTIONS
554          * initialization flag when calling the secret_service_get() or
555          * secret_service_open() functions. Or call the secret_service_load_collections()
556          * method.
557          */
558         g_object_class_install_property (object_class, PROP_COLLECTIONS,
559                      g_param_spec_boxed ("collections", "Collections", "Secret Service Collections",
560                                          _secret_list_get_type (), G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
561
562         g_type_class_add_private (klass, sizeof (SecretServicePrivate));
563
564         /* Initialize this error domain, registers dbus errors */
565         _secret_error_quark = secret_error_get_quark ();
566 }
567
568 typedef struct {
569         GCancellable *cancellable;
570         SecretServiceFlags flags;
571 } InitClosure;
572
573 static void
574 init_closure_free (gpointer data)
575 {
576         InitClosure *closure = data;
577         g_clear_object (&closure->cancellable);
578         g_slice_free (InitClosure, closure);
579 }
580
581 static gboolean
582 service_ensure_for_flags_sync (SecretService *self,
583                                SecretServiceFlags flags,
584                                GCancellable *cancellable,
585                                GError **error)
586 {
587         if (flags & SECRET_SERVICE_OPEN_SESSION)
588                 if (!secret_service_ensure_session_sync (self, cancellable, error))
589                         return FALSE;
590
591         if (flags & SECRET_SERVICE_LOAD_COLLECTIONS)
592                 if (!secret_service_load_collections_sync (self, cancellable, error))
593                         return FALSE;
594
595         return TRUE;
596 }
597
598 static void
599 on_load_collections (GObject *source,
600                      GAsyncResult *result,
601                      gpointer user_data)
602 {
603         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
604         SecretService *self = SECRET_SERVICE (source);
605         GError *error = NULL;
606
607         if (!secret_service_load_collections_finish (self, result, &error))
608                 g_simple_async_result_take_error (res, error);
609
610         g_simple_async_result_complete (res);
611         g_object_unref (res);
612 }
613
614 static void
615 on_ensure_session (GObject *source,
616                    GAsyncResult *result,
617                    gpointer user_data)
618 {
619         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
620         InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
621         SecretService *self = SECRET_SERVICE (source);
622         GError *error = NULL;
623
624         if (!secret_service_ensure_session_finish (self, result, &error)) {
625                 g_simple_async_result_take_error (res, error);
626                 g_simple_async_result_complete (res);
627
628         } else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS) {
629                 secret_service_load_collections (self, closure->cancellable,
630                                                  on_load_collections, g_object_ref (res));
631
632         } else {
633                 g_simple_async_result_complete_in_idle (res);
634         }
635
636         g_object_unref (res);
637 }
638
639 static void
640 service_ensure_for_flags_async (SecretService *self,
641                                 SecretServiceFlags flags,
642                                 GSimpleAsyncResult *res)
643 {
644         InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
645
646         closure->flags = flags;
647
648         if (closure->flags & SECRET_SERVICE_OPEN_SESSION)
649                 secret_service_ensure_session (self, closure->cancellable,
650                                                on_ensure_session, g_object_ref (res));
651
652         else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS)
653                 secret_service_load_collections (self, closure->cancellable,
654                                                  on_load_collections, g_object_ref (res));
655
656         else
657                 g_simple_async_result_complete_in_idle (res);
658 }
659
660 static gboolean
661 secret_service_initable_init (GInitable *initable,
662                               GCancellable *cancellable,
663                               GError **error)
664 {
665         SecretService *self;
666
667         if (!secret_service_initable_parent_iface->init (initable, cancellable, error))
668                 return FALSE;
669
670         self = SECRET_SERVICE (initable);
671         return service_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error);
672 }
673
674 static void
675 secret_service_initable_iface (GInitableIface *iface)
676 {
677         secret_service_initable_parent_iface = g_type_interface_peek_parent (iface);
678
679         iface->init = secret_service_initable_init;
680 }
681
682 static void
683 on_init_base (GObject *source,
684               GAsyncResult *result,
685               gpointer user_data)
686 {
687         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
688         SecretService *self = SECRET_SERVICE (source);
689         GError *error = NULL;
690
691         if (!secret_service_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self),
692                                                                       result, &error)) {
693                 g_simple_async_result_take_error (res, error);
694                 g_simple_async_result_complete (res);
695         } else {
696                 service_ensure_for_flags_async (self, self->pv->init_flags, res);
697         }
698
699         g_object_unref (res);
700 }
701
702 static void
703 secret_service_async_initable_init_async (GAsyncInitable *initable,
704                                           int io_priority,
705                                           GCancellable *cancellable,
706                                           GAsyncReadyCallback callback,
707                                           gpointer user_data)
708 {
709         GSimpleAsyncResult *res;
710         InitClosure *closure;
711
712         res = g_simple_async_result_new (G_OBJECT (initable), callback, user_data,
713                                          secret_service_async_initable_init_async);
714         closure = g_slice_new0 (InitClosure);
715         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
716         g_simple_async_result_set_op_res_gpointer (res, closure, init_closure_free);
717
718         secret_service_async_initable_parent_iface->init_async (initable, io_priority,
719                                                                 cancellable,
720                                                                 on_init_base,
721                                                                 g_object_ref (res));
722
723         g_object_unref (res);
724 }
725
726 static gboolean
727 secret_service_async_initable_init_finish (GAsyncInitable *initable,
728                                            GAsyncResult *result,
729                                            GError **error)
730 {
731         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (initable),
732                               secret_service_async_initable_init_async), FALSE);
733
734         if (_secret_util_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
735                 return FALSE;
736
737         return TRUE;
738 }
739
740 static void
741 secret_service_async_initable_iface (GAsyncInitableIface *iface)
742 {
743         secret_service_async_initable_parent_iface = g_type_interface_peek_parent (iface);
744
745         iface->init_async = secret_service_async_initable_init_async;
746         iface->init_finish = secret_service_async_initable_init_finish;
747 }
748
749 static const gchar *
750 get_default_bus_name (void)
751 {
752         const gchar *bus_name;
753
754         bus_name = g_getenv ("SECRET_SERVICE_BUS_NAME");
755         if (bus_name == NULL)
756                 bus_name = SECRET_SERVICE_BUS_NAME;
757
758         return bus_name;
759 }
760
761 /**
762  * secret_service_get:
763  * @flags: flags for which service functionality to ensure is initialized
764  * @cancellable: optional cancellation object
765  * @callback: called when the operation completes
766  * @user_data: data to be passed to the callback
767  *
768  * Get a #SecretService proxy for the Secret Service. If such a proxy object
769  * already exists, then the same proxy is returned.
770  *
771  * If @flags contains any flags of which parts of the secret service to
772  * ensure are initialized, then those will be initialized before completing.
773  *
774  * This method will return immediately and complete asynchronously.
775  */
776 void
777 secret_service_get (SecretServiceFlags flags,
778                     GCancellable *cancellable,
779                     GAsyncReadyCallback callback,
780                     gpointer user_data)
781 {
782         SecretService *service = NULL;
783         GSimpleAsyncResult *res;
784         InitClosure *closure;
785
786         service = service_get_instance ();
787
788         /* Create a whole new service */
789         if (service == NULL) {
790                 g_async_initable_new_async (SECRET_TYPE_SERVICE, G_PRIORITY_DEFAULT,
791                                             cancellable, callback, user_data,
792                                             "g-flags", G_DBUS_PROXY_FLAGS_NONE,
793                                             "g-interface-info", _secret_gen_service_interface_info (),
794                                             "g-name", get_default_bus_name (),
795                                             "g-bus-type", G_BUS_TYPE_SESSION,
796                                             "g-object-path", SECRET_SERVICE_PATH,
797                                             "g-interface-name", SECRET_SERVICE_INTERFACE,
798                                             "flags", flags,
799                                             NULL);
800
801         /* Just have to ensure that the service matches flags */
802         } else {
803                 res = g_simple_async_result_new (G_OBJECT (service), callback,
804                                                  user_data, secret_service_get);
805                 closure = g_slice_new0 (InitClosure);
806                 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
807                 closure->flags = flags;
808                 g_simple_async_result_set_op_res_gpointer (res, closure, init_closure_free);
809
810                 service_ensure_for_flags_async (service, flags, res);
811
812                 g_object_unref (service);
813                 g_object_unref (res);
814         }
815 }
816
817 /**
818  * secret_service_get_finish:
819  * @result: the asynchronous result passed to the callback
820  * @error: location to place an error on failure
821  *
822  * Complete an asynchronous operation to get a #SecretService proxy for the
823  * Secret Service.
824  *
825  * Returns: (transfer full): a new reference to a #SecretService proxy, which
826  *          should be released with g_object_unref().
827  */
828 SecretService *
829 secret_service_get_finish (GAsyncResult *result,
830                            GError **error)
831 {
832         GObject *service = NULL;
833         GObject *source_object;
834
835         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
836         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
837
838         source_object = g_async_result_get_source_object (result);
839
840         /* Just ensuring that the service matches flags */
841         if (g_simple_async_result_is_valid (result, source_object, secret_service_get)) {
842                 if (!_secret_util_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
843                         service = g_object_ref (source_object);
844
845         /* Creating a whole new service */
846         } else {
847                 service = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
848                 if (service)
849                         service_cache_instance (SECRET_SERVICE (service));
850         }
851
852         if (source_object)
853                 g_object_unref (source_object);
854
855         if (service == NULL)
856                 return NULL;
857
858         return SECRET_SERVICE (service);
859 }
860
861 /**
862  * secret_service_get_sync:
863  * @flags: flags for which service functionality to ensure is initialized
864  * @cancellable: optional cancellation object
865  * @error: location to place an error on failure
866  *
867  * Get a #SecretService proxy for the Secret Service. If such a proxy object
868  * already exists, then the same proxy is returned.
869  *
870  * If @flags contains any flags of which parts of the secret service to
871  * ensure are initialized, then those will be initialized before returning.
872  *
873  * This method may block indefinitely and should not be used in user interface
874  * threads.
875  *
876  * Returns: (transfer full): a new reference to a #SecretService proxy, which
877  *          should be released with g_object_unref().
878  */
879 SecretService *
880 secret_service_get_sync (SecretServiceFlags flags,
881                          GCancellable *cancellable,
882                          GError **error)
883 {
884         SecretService *service = NULL;
885
886         service = service_get_instance ();
887
888         if (service == NULL) {
889                 service = g_initable_new (SECRET_TYPE_SERVICE, cancellable, error,
890                                           "g-flags", G_DBUS_PROXY_FLAGS_NONE,
891                                           "g-interface-info", _secret_gen_service_interface_info (),
892                                           "g-name", get_default_bus_name (),
893                                           "g-bus-type", G_BUS_TYPE_SESSION,
894                                           "g-object-path", SECRET_SERVICE_PATH,
895                                           "g-interface-name", SECRET_SERVICE_INTERFACE,
896                                           "flags", flags,
897                                           NULL);
898
899                 if (service != NULL)
900                         service_cache_instance (service);
901
902         } else {
903                 if (!service_ensure_for_flags_sync (service, flags, cancellable, error)) {
904                         g_object_unref (service);
905                         return NULL;
906                 }
907         }
908
909         return service;
910 }
911
912 /**
913  * secret_service_disconnect:
914  *
915  * Disconnect the default #SecretService proxy returned by secret_service_get()
916  * and secret_service_get_sync().
917  *
918  * It is not necessary to call this function, but you may choose to do so at
919  * program exit. It is useful for testing that memory is not leaked.
920  *
921  * This function is safe to call at any time. But if other objects in this
922  * library are still referenced, then this will not result in all memory
923  * being freed.
924  */
925 void
926 secret_service_disconnect (void)
927 {
928         service_uncache_instance (NULL);
929 }
930
931 /**
932  * secret_service_open:
933  * @service_gtype: the GType of the new secret service
934  * @service_bus_name: (allow-none): the D-Bus service name of the secret service
935  * @flags: flags for which service functionality to ensure is initialized
936  * @cancellable: optional cancellation object
937  * @callback: called when the operation completes
938  * @user_data: data to be passed to the callback
939  *
940  * Create a new #SecretService proxy for the Secret Service.
941  *
942  * This function is rarely used, see secret_service_get() instead.
943  *
944  * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the type
945  * of a derived class.
946  *
947  * If @flags contains any flags of which parts of the secret service to
948  * ensure are initialized, then those will be initialized before returning.
949  *
950  * If @service_bus_name is %NULL then the default is used.
951  *
952  * This method will return immediately and complete asynchronously.
953  */
954 void
955 secret_service_open (GType service_gtype,
956                      const gchar *service_bus_name,
957                      SecretServiceFlags flags,
958                      GCancellable *cancellable,
959                      GAsyncReadyCallback callback,
960                      gpointer user_data)
961 {
962         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
963         g_return_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE));
964
965         if (service_bus_name == NULL)
966                 service_bus_name = get_default_bus_name ();
967
968         g_async_initable_new_async (service_gtype, G_PRIORITY_DEFAULT,
969                                     cancellable, callback, user_data,
970                                     "g-flags", G_DBUS_PROXY_FLAGS_NONE,
971                                     "g-interface-info", _secret_gen_service_interface_info (),
972                                     "g-name", service_bus_name,
973                                     "g-bus-type", G_BUS_TYPE_SESSION,
974                                     "g-object-path", SECRET_SERVICE_PATH,
975                                     "g-interface-name", SECRET_SERVICE_INTERFACE,
976                                     "flags", flags,
977                                     NULL);
978 }
979
980 /**
981  * secret_service_open_finish:
982  * @result: the asynchronous result passed to the callback
983  * @error: location to place an error on failure
984  *
985  * Complete an asynchronous operation to create a new #SecretService proxy for
986  * the Secret Service.
987  *
988  * Returns: (transfer full): a new reference to a #SecretService proxy, which
989  *          should be released with g_object_unref().
990  */
991 SecretService *
992 secret_service_open_finish (GAsyncResult *result,
993                             GError **error)
994 {
995         GObject *source_object;
996         GObject *object;
997
998         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
999         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1000
1001         source_object = g_async_result_get_source_object (result);
1002         object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
1003                                               result, error);
1004         g_object_unref (source_object);
1005
1006         if (object == NULL)
1007                 return NULL;
1008
1009         return SECRET_SERVICE (object);
1010 }
1011
1012 /**
1013  * secret_service_open_sync:
1014  * @service_gtype: the GType of the new secret service
1015  * @service_bus_name: (allow-none): the D-Bus service name of the secret service
1016  * @flags: flags for which service functionality to ensure is initialized
1017  * @cancellable: optional cancellation object
1018  * @error: location to place an error on failure
1019  *
1020  * Create a new #SecretService proxy for the Secret Service.
1021  *
1022  * This function is rarely used, see secret_service_get_sync() instead.
1023  *
1024  * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the
1025  * type of a derived class.
1026  *
1027  * If @flags contains any flags of which parts of the secret service to
1028  * ensure are initialized, then those will be initialized before returning.
1029  *
1030  * If @service_bus_name is %NULL then the default is used.
1031  *
1032  * This method may block indefinitely and should not be used in user interface
1033  * threads.
1034  *
1035  * Returns: (transfer full): a new reference to a #SecretService proxy, which
1036  *          should be released with g_object_unref().
1037  */
1038 SecretService *
1039 secret_service_open_sync (GType service_gtype,
1040                           const gchar *service_bus_name,
1041                           SecretServiceFlags flags,
1042                           GCancellable *cancellable,
1043                           GError **error)
1044 {
1045         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1046         g_return_val_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE), NULL);
1047
1048         if (service_bus_name == NULL)
1049                 service_bus_name = get_default_bus_name ();
1050
1051         return g_initable_new (service_gtype, cancellable, error,
1052                                "g-flags", G_DBUS_PROXY_FLAGS_NONE,
1053                                "g-interface-info", _secret_gen_service_interface_info (),
1054                                "g-name", service_bus_name,
1055                                "g-bus-type", G_BUS_TYPE_SESSION,
1056                                "g-object-path", SECRET_SERVICE_PATH,
1057                                "g-interface-name", SECRET_SERVICE_INTERFACE,
1058                                "flags", flags,
1059                                NULL);
1060 }
1061
1062 /**
1063  * secret_service_get_flags:
1064  * @self: the secret service proxy
1065  *
1066  * Get the flags representing what features of the #SecretService proxy
1067  * have been initialized.
1068  *
1069  * Use secret_service_ensure_session() or secret_service_load_collections()
1070  * to initialize further features and change the flags.
1071  *
1072  * Returns: the flags for features initialized
1073  */
1074 SecretServiceFlags
1075 secret_service_get_flags (SecretService *self)
1076 {
1077         SecretServiceFlags flags = 0;
1078
1079         g_return_val_if_fail (SECRET_IS_SERVICE (self), SECRET_SERVICE_NONE);
1080
1081         g_mutex_lock (&self->pv->mutex);
1082
1083         if (self->pv->session)
1084                 flags |= SECRET_SERVICE_OPEN_SESSION;
1085         if (self->pv->collections)
1086                 flags |= SECRET_SERVICE_LOAD_COLLECTIONS;
1087
1088         g_mutex_unlock (&self->pv->mutex);
1089
1090         return flags;
1091 }
1092
1093 /**
1094  * secret_service_get_collections:
1095  * @self: the secret service proxy
1096  *
1097  * Get a list of #SecretCollection objects representing all the collections
1098  * in the secret service.
1099  *
1100  * If the %SECRET_SERVICE_LOAD_COLLECTIONS flag was not specified when
1101  * initializing #SecretService proxy object, then this method will return
1102  * %NULL. Use secret_service_load_collections() to load the collections.
1103  *
1104  * Returns: (transfer full) (element-type SecretUnstable.Collection) (allow-none): a
1105  *          list of the collections in the secret service
1106  */
1107 GList *
1108 secret_service_get_collections (SecretService *self)
1109 {
1110         GList *l, *collections;
1111
1112         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1113
1114         g_mutex_lock (&self->pv->mutex);
1115
1116         if (self->pv->collections == NULL) {
1117                 collections = NULL;
1118
1119         } else {
1120                 collections = g_hash_table_get_values (self->pv->collections);
1121                 for (l = collections; l != NULL; l = g_list_next (l))
1122                         g_object_ref (l->data);
1123         }
1124
1125         g_mutex_unlock (&self->pv->mutex);
1126
1127         return collections;
1128 }
1129
1130 SecretItem *
1131 _secret_service_find_item_instance (SecretService *self,
1132                                     const gchar *item_path)
1133 {
1134         SecretCollection *collection = NULL;
1135         gchar *collection_path;
1136         SecretItem *item;
1137
1138         collection_path = _secret_util_parent_path (item_path);
1139
1140         collection = _secret_service_find_collection_instance (self, collection_path);
1141
1142         g_free (collection_path);
1143
1144         if (collection == NULL)
1145                 return NULL;
1146
1147         item = _secret_collection_find_item_instance (collection, item_path);
1148         g_object_unref (collection);
1149
1150         return item;
1151 }
1152
1153 SecretCollection *
1154 _secret_service_find_collection_instance (SecretService *self,
1155                                           const gchar *collection_path)
1156 {
1157         SecretCollection *collection = NULL;
1158
1159         g_mutex_lock (&self->pv->mutex);
1160         if (self->pv->collections) {
1161                 collection = g_hash_table_lookup (self->pv->collections, collection_path);
1162                 if (collection != NULL)
1163                         g_object_ref (collection);
1164         }
1165         g_mutex_unlock (&self->pv->mutex);
1166
1167         return collection;
1168 }
1169
1170 SecretSession *
1171 _secret_service_get_session (SecretService *self)
1172 {
1173         SecretSession *session;
1174
1175         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1176
1177         g_mutex_lock (&self->pv->mutex);
1178         session = self->pv->session;
1179         g_mutex_unlock (&self->pv->mutex);
1180
1181         return session;
1182 }
1183
1184 void
1185 _secret_service_take_session (SecretService *self,
1186                               SecretSession *session)
1187 {
1188         g_return_if_fail (SECRET_IS_SERVICE (self));
1189         g_return_if_fail (session != NULL);
1190
1191         g_mutex_lock (&self->pv->mutex);
1192         if (self->pv->session == NULL)
1193                 self->pv->session = session;
1194         else
1195                 _secret_session_free (session);
1196         g_mutex_unlock (&self->pv->mutex);
1197 }
1198
1199 /**
1200  * secret_service_get_session_algorithms:
1201  * @self: the secret service proxy
1202  *
1203  * Get the set of algorithms being used to transfer secrets between this
1204  * secret service proxy and the Secret Service itself.
1205  *
1206  * This will be %NULL if no session has been established. Use
1207  * secret_service_ensure_session() to establish a session.
1208  *
1209  * Returns: (allow-none): a string representing the algorithms for transferring
1210  *          secrets
1211  */
1212 const gchar *
1213 secret_service_get_session_algorithms (SecretService *self)
1214 {
1215         SecretSession *session;
1216         const gchar *algorithms;
1217
1218         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1219
1220         g_mutex_lock (&self->pv->mutex);
1221         session = self->pv->session;
1222         algorithms = session ? _secret_session_get_algorithms (session) : NULL;
1223         g_mutex_unlock (&self->pv->mutex);
1224
1225         /* Session never changes once established, so can return const */
1226         return algorithms;
1227 }
1228
1229 /**
1230  * secret_service_get_session_dbus_path:
1231  * @self: the secret service proxy
1232  *
1233  * Get the D-Bus object path of the session object being used to transfer
1234  * secrets between this secret service proxy and the Secret Service itself.
1235  *
1236  * This will be %NULL if no session has been established. Use
1237  * secret_service_ensure_session() to establish a session.
1238  *
1239  * Returns: (allow-none): a string representing the D-Bus object path of the
1240  *          session
1241  */
1242 const gchar *
1243 secret_service_get_session_dbus_path (SecretService *self)
1244 {
1245         SecretSession *session;
1246         const gchar *path;
1247
1248         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1249
1250         g_mutex_lock (&self->pv->mutex);
1251         session = self->pv->session;
1252         path = session ? _secret_session_get_path (session) : NULL;
1253         g_mutex_unlock (&self->pv->mutex);
1254
1255         /* Session never changes once established, so can return const */
1256         return path;
1257 }
1258
1259 /**
1260  * secret_service_ensure_session:
1261  * @self: the secret service
1262  * @cancellable: optional cancellation object
1263  * @callback: called when the operation completes
1264  * @user_data: data to be passed to the callback
1265  *
1266  * Ensure that the #SecretService proxy has established a session with the
1267  * Secret Service. This session is used to transfer secrets.
1268  *
1269  * It is not normally necessary to call this method, as the session is
1270  * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION
1271  * to secret_service_get() in order to ensure that a session has been established
1272  * by the time you get the #SecretService proxy.
1273  *
1274  * This method will return immediately and complete asynchronously.
1275  */
1276 void
1277 secret_service_ensure_session (SecretService *self,
1278                                GCancellable *cancellable,
1279                                GAsyncReadyCallback callback,
1280                                gpointer user_data)
1281 {
1282         GSimpleAsyncResult *res;
1283         SecretSession *session;
1284
1285         g_return_if_fail (SECRET_IS_SERVICE (self));
1286         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1287
1288         g_mutex_lock (&self->pv->mutex);
1289         session = self->pv->session;
1290         g_mutex_unlock (&self->pv->mutex);
1291
1292         if (session == NULL) {
1293                 _secret_session_open (self, cancellable, callback, user_data);
1294
1295         } else {
1296                 res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1297                                                  secret_service_ensure_session);
1298                 g_simple_async_result_complete_in_idle (res);
1299                 g_object_unref (res);
1300         }
1301 }
1302
1303 /**
1304  * secret_service_ensure_session_finish:
1305  * @self: the secret service
1306  * @result: the asynchronous result passed to the callback
1307  * @error: location to place an error on failure
1308  *
1309  * Finish an asynchronous operation to ensure that the #SecretService proxy
1310  * has established a session with the Secret Service.
1311  *
1312  * Returns: whether a session is established or not
1313  */
1314 gboolean
1315 secret_service_ensure_session_finish (SecretService *self,
1316                                       GAsyncResult *result,
1317                                       GError **error)
1318 {
1319         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1320         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1321
1322         if (!g_simple_async_result_is_valid (result, G_OBJECT (self),
1323                                              secret_service_ensure_session)) {
1324                 if (!_secret_session_open_finish (result, error))
1325                         return FALSE;
1326         }
1327
1328         g_return_val_if_fail (self->pv->session != NULL, FALSE);
1329         return TRUE;
1330 }
1331
1332 /**
1333  * secret_service_ensure_session_sync:
1334  * @self: the secret service
1335  * @cancellable: optional cancellation object
1336  * @error: location to place an error on failure
1337  *
1338  * Ensure that the #SecretService proxy has established a session with the
1339  * Secret Service. This session is used to transfer secrets.
1340  *
1341  * It is not normally necessary to call this method, as the session is
1342  * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION
1343  * to secret_service_get_sync() in order to ensure that a session has been
1344  * established by the time you get the #SecretService proxy.
1345  *
1346  * This method may block indefinitely and should not be used in user interface
1347  * threads.
1348  *
1349  * Returns: whether a session is established or not
1350  */
1351 gboolean
1352 secret_service_ensure_session_sync (SecretService *self,
1353                                     GCancellable *cancellable,
1354                                     GError **error)
1355 {
1356         SecretSync *sync;
1357         gboolean ret;
1358
1359         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1360         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1361         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1362
1363         sync = _secret_sync_new ();
1364         g_main_context_push_thread_default (sync->context);
1365
1366         secret_service_ensure_session (self, cancellable,
1367                                        _secret_sync_on_result, sync);
1368
1369         g_main_loop_run (sync->loop);
1370
1371         ret = secret_service_ensure_session_finish (self, sync->result, error);
1372
1373         g_main_context_pop_thread_default (sync->context);
1374         _secret_sync_free (sync);
1375
1376         return ret;
1377 }
1378
1379 static SecretCollection *
1380 service_lookup_collection (SecretService *self,
1381                            const gchar *path)
1382 {
1383         SecretCollection *collection = NULL;
1384
1385         g_mutex_lock (&self->pv->mutex);
1386
1387         if (self->pv->collections) {
1388                 collection = g_hash_table_lookup (self->pv->collections, path);
1389                 if (collection != NULL)
1390                         g_object_ref (collection);
1391         }
1392
1393         g_mutex_unlock (&self->pv->mutex);
1394
1395         return collection;
1396 }
1397
1398 static void
1399 service_update_collections (SecretService *self,
1400                             GHashTable *collections)
1401 {
1402         GHashTable *previous;
1403
1404         g_hash_table_ref (collections);
1405
1406         g_mutex_lock (&self->pv->mutex);
1407
1408         previous = self->pv->collections;
1409         self->pv->collections = collections;
1410
1411         g_mutex_unlock (&self->pv->mutex);
1412
1413         if (previous != NULL)
1414                 g_hash_table_unref (previous);
1415
1416         g_object_notify (G_OBJECT (self), "collections");
1417 }
1418
1419 typedef struct {
1420         GCancellable *cancellable;
1421         GHashTable *collections;
1422         gint collections_loading;
1423 } EnsureClosure;
1424
1425 static GHashTable *
1426 collections_table_new (void)
1427 {
1428         return g_hash_table_new_full (g_str_hash, g_str_equal,
1429                                       g_free, g_object_unref);
1430 }
1431
1432 static void
1433 ensure_closure_free (gpointer data)
1434 {
1435         EnsureClosure *closure = data;
1436         g_clear_object (&closure->cancellable);
1437         g_hash_table_unref (closure->collections);
1438         g_slice_free (EnsureClosure, closure);
1439 }
1440
1441 static void
1442 on_ensure_collection (GObject *source,
1443                       GAsyncResult *result,
1444                       gpointer user_data)
1445 {
1446         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1447         SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
1448         EnsureClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1449         SecretCollection *collection;
1450         const gchar *path;
1451         GError *error = NULL;
1452
1453         closure->collections_loading--;
1454
1455         collection = secret_collection_new_for_dbus_path_finish (result, &error);
1456
1457         if (error != NULL)
1458                 g_simple_async_result_take_error (res, error);
1459
1460         if (collection != NULL) {
1461                 path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection));
1462                 g_hash_table_insert (closure->collections, g_strdup (path), collection);
1463         }
1464
1465         if (closure->collections_loading == 0) {
1466                 service_update_collections (self, closure->collections);
1467                 g_simple_async_result_complete (res);
1468         }
1469
1470         g_object_unref (self);
1471         g_object_unref (res);
1472 }
1473
1474 /**
1475  * secret_service_load_collections:
1476  * @self: the secret service
1477  * @cancellable: optional cancellation object
1478  * @callback: called when the operation completes
1479  * @user_data: data to be passed to the callback
1480  *
1481  * Ensure that the #SecretService proxy has loaded all the collections present
1482  * in the Secret Service. This affects the result of
1483  * secret_service_get_collections().
1484  *
1485  * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to
1486  * secret_service_get_sync() in order to ensure that the collections have been
1487  * loaded by the time you get the #SecretService proxy.
1488  *
1489  * This method will return immediately and complete asynchronously.
1490  */
1491 void
1492 secret_service_load_collections (SecretService *self,
1493                                  GCancellable *cancellable,
1494                                  GAsyncReadyCallback callback,
1495                                  gpointer user_data)
1496 {
1497         EnsureClosure *closure;
1498         SecretCollection *collection;
1499         GSimpleAsyncResult *res;
1500         const gchar *path;
1501         GVariant *paths;
1502         GVariantIter iter;
1503
1504         g_return_if_fail (SECRET_IS_SERVICE (self));
1505         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1506
1507         paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
1508         g_return_if_fail (paths != NULL);
1509
1510         res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1511                                          secret_service_load_collections);
1512         closure = g_slice_new0 (EnsureClosure);
1513         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1514         closure->collections = collections_table_new ();
1515         g_simple_async_result_set_op_res_gpointer (res, closure, ensure_closure_free);
1516
1517         g_variant_iter_init (&iter, paths);
1518         while (g_variant_iter_loop (&iter, "&o", &path)) {
1519                 collection = service_lookup_collection (self, path);
1520
1521                 /* No such collection yet create a new one */
1522                 if (collection == NULL) {
1523                         secret_collection_new_for_dbus_path (self, path, SECRET_COLLECTION_LOAD_ITEMS,
1524                                                              cancellable, on_ensure_collection, g_object_ref (res));
1525                         closure->collections_loading++;
1526                 } else {
1527                         g_hash_table_insert (closure->collections, g_strdup (path), collection);
1528                 }
1529         }
1530
1531         if (closure->collections_loading == 0) {
1532                 service_update_collections (self, closure->collections);
1533                 g_simple_async_result_complete_in_idle (res);
1534         }
1535
1536         g_variant_unref (paths);
1537         g_object_unref (res);
1538 }
1539
1540 /**
1541  * secret_service_load_collections_finish:
1542  * @self: the secret service
1543  * @result: the asynchronous result passed to the callback
1544  * @error: location to place an error on failure
1545  *
1546  * Complete an asynchronous operation to ensure that the #SecretService proxy
1547  * has loaded all the collections present in the Secret Service.
1548  *
1549  * Returns: whether the load was successful or not
1550  */
1551 gboolean
1552 secret_service_load_collections_finish (SecretService *self,
1553                                         GAsyncResult *result,
1554                                         GError **error)
1555 {
1556         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1557         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1558         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1559                               secret_service_load_collections), FALSE);
1560
1561         if (_secret_util_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1562                 return FALSE;
1563
1564         return TRUE;
1565 }
1566
1567 /**
1568  * secret_service_load_collections_sync:
1569  * @self: the secret service
1570  * @cancellable: optional cancellation object
1571  * @error: location to place an error on failure
1572  *
1573  * Ensure that the #SecretService proxy has loaded all the collections present
1574  * in the Secret Service. This affects the result of
1575  * secret_service_get_collections().
1576  *
1577  * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to
1578  * secret_service_get_sync() in order to ensure that the collections have been
1579  * loaded by the time you get the #SecretService proxy.
1580  *
1581  * This method may block indefinitely and should not be used in user interface
1582  * threads.
1583  *
1584  * Returns: whether the load was successful or not
1585  */
1586 gboolean
1587 secret_service_load_collections_sync (SecretService *self,
1588                                       GCancellable *cancellable,
1589                                       GError **error)
1590 {
1591         SecretCollection *collection;
1592         GHashTable *collections;
1593         GVariant *paths;
1594         GVariantIter iter;
1595         const gchar *path;
1596         gboolean ret = TRUE;
1597
1598         g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
1599         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1600         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1601
1602         paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
1603         g_return_val_if_fail (paths != NULL, FALSE);
1604
1605         collections = collections_table_new ();
1606
1607         g_variant_iter_init (&iter, paths);
1608         while (g_variant_iter_next (&iter, "&o", &path)) {
1609                 collection = service_lookup_collection (self, path);
1610
1611                 /* No such collection yet create a new one */
1612                 if (collection == NULL) {
1613                         collection = secret_collection_new_for_dbus_path_sync (self, path,
1614                                                                                SECRET_COLLECTION_LOAD_ITEMS,
1615                                                                                cancellable, error);
1616                         if (collection == NULL) {
1617                                 ret = FALSE;
1618                                 break;
1619                         }
1620                 }
1621
1622                 g_hash_table_insert (collections, g_strdup (path), collection);
1623         }
1624
1625         if (ret)
1626                 service_update_collections (self, collections);
1627
1628         g_hash_table_unref (collections);
1629         g_variant_unref (paths);
1630         return ret;
1631 }
1632
1633 /**
1634  * secret_service_prompt_sync:
1635  * @self: the secret service
1636  * @prompt: the prompt
1637  * @cancellable: optional cancellation object
1638  * @return_type: the variant type of the prompt result
1639  * @error: location to place an error on failure
1640  *
1641  * Perform prompting for a #SecretPrompt.
1642  *
1643  * Runs a prompt and performs the prompting. Returns a variant result if the
1644  * prompt was completed and not dismissed. The type of result depends on the
1645  * action the prompt is completing, and is defined in the Secret Service DBus
1646  * API specification.
1647  *
1648  * This function is called by other parts of this library to handle prompts
1649  * for the various actions that can require prompting.
1650  *
1651  * Override the #SecretServiceClass <literal>prompt_sync</literal> virtual method
1652  * to change the behavior of the propmting. The default behavior is to simply
1653  * run secret_prompt_perform_sync() on the prompt.
1654  *
1655  * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred,
1656  *          a variant result if the prompt was successful
1657  */
1658 GVariant *
1659 secret_service_prompt_sync (SecretService *self,
1660                             SecretPrompt *prompt,
1661                             GCancellable *cancellable,
1662                             const GVariantType *return_type,
1663                             GError **error)
1664 {
1665         SecretServiceClass *klass;
1666
1667         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1668         g_return_val_if_fail (SECRET_IS_PROMPT (prompt), NULL);
1669         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1670         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1671
1672         klass = SECRET_SERVICE_GET_CLASS (self);
1673         g_return_val_if_fail (klass->prompt_sync != NULL, NULL);
1674
1675         return (klass->prompt_sync) (self, prompt, cancellable, return_type, error);
1676 }
1677
1678 /**
1679  * secret_service_prompt:
1680  * @self: the secret service
1681  * @prompt: the prompt
1682  * @return_type: (allow-none): the variant type of the prompt result
1683  * @cancellable: optional cancellation object
1684  * @callback: called when the operation completes
1685  * @user_data: data to be passed to the callback
1686  *
1687  * Perform prompting for a #SecretPrompt.
1688  *
1689  * This function is called by other parts of this library to handle prompts
1690  * for the various actions that can require prompting.
1691  *
1692  * Override the #SecretServiceClass <literal>prompt_async</literal> virtual method
1693  * to change the behavior of the propmting. The default behavior is to simply
1694  * run secret_prompt_perform() on the prompt.
1695  */
1696 void
1697 secret_service_prompt (SecretService *self,
1698                        SecretPrompt *prompt,
1699                        const GVariantType *return_type,
1700                        GCancellable *cancellable,
1701                        GAsyncReadyCallback callback,
1702                        gpointer user_data)
1703 {
1704         SecretServiceClass *klass;
1705
1706         g_return_if_fail (SECRET_IS_SERVICE (self));
1707         g_return_if_fail (SECRET_IS_PROMPT (prompt));
1708         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1709
1710         klass = SECRET_SERVICE_GET_CLASS (self);
1711         g_return_if_fail (klass->prompt_async != NULL);
1712
1713         (klass->prompt_async) (self, prompt, return_type, cancellable, callback, user_data);
1714 }
1715
1716 /**
1717  * secret_service_prompt_finish:
1718  * @self: the secret service
1719  * @result: the asynchronous result passed to the callback
1720  * @error: location to place an error on failure
1721  *
1722  * Complete asynchronous operation to perform prompting for a #SecretPrompt.
1723  *
1724  * Returns a variant result if the prompt was completed and not dismissed. The
1725  * type of result depends on the action the prompt is completing, and is defined
1726  * in the Secret Service DBus API specification.
1727  *
1728  * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred,
1729  *          a variant result if the prompt was successful
1730  */
1731 GVariant *
1732 secret_service_prompt_finish (SecretService *self,
1733                               GAsyncResult *result,
1734                               GError **error)
1735 {
1736         SecretServiceClass *klass;
1737
1738         g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
1739         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1740         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1741
1742         klass = SECRET_SERVICE_GET_CLASS (self);
1743         g_return_val_if_fail (klass->prompt_finish != NULL, NULL);
1744
1745         return (klass->prompt_finish) (self, result, error);
1746 }
1747
1748 /**
1749  * secret_service_get_collection_gtype:
1750  * @self: the secret service
1751  *
1752  * Get the GObject type for collections instantiated by this service.
1753  * This will always be either #SecretCollection or derived from it.
1754  *
1755  * Returns: the gobject type for collections
1756  */
1757 GType
1758 secret_service_get_collection_gtype (SecretService *self)
1759 {
1760         SecretServiceClass *klass;
1761         GType type;
1762
1763         g_return_val_if_fail (SECRET_IS_SERVICE (self), 0);
1764
1765         klass = SECRET_SERVICE_GET_CLASS (self);
1766         g_return_val_if_fail (klass->get_collection_gtype != NULL,
1767                               SECRET_TYPE_COLLECTION);
1768
1769         type = (klass->get_collection_gtype) (self);
1770         g_return_val_if_fail (g_type_is_a (type, SECRET_TYPE_COLLECTION),
1771                               SECRET_TYPE_COLLECTION);
1772
1773         return type;
1774 }
1775
1776 /**
1777  * secret_service_get_item_gtype:
1778  * @self: the collection
1779  *
1780  * Get the GObject type for items instantiated by this collection.
1781  * This will always be either #SecretItem or derived from it.
1782  *
1783  * Returns: the gobject type for items
1784  */
1785 GType
1786 secret_service_get_item_gtype (SecretService *self)
1787 {
1788         SecretServiceClass *klass;
1789         GType type;
1790
1791         g_return_val_if_fail (SECRET_IS_SERVICE (self), 0);
1792
1793         klass = SECRET_SERVICE_GET_CLASS (self);
1794         g_return_val_if_fail (klass->get_item_gtype != NULL,
1795                               SECRET_TYPE_ITEM);
1796
1797         type = (klass->get_item_gtype) (self);
1798         g_return_val_if_fail (g_type_is_a (type, SECRET_TYPE_ITEM),
1799                               SECRET_TYPE_ITEM);
1800
1801         return type;
1802 }