Bump version number
[platform/upstream/libsecret.git] / library / secret-item.c
1 /* libsecret - GLib wrapper for Secret Service
2  *
3  * Copyright 2012 Red Hat Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation; either version 2.1 of the licence or (at
8  * your option) any later version.
9  *
10  * See the included COPYING file for more information.
11  *
12  * Author: Stef Walter <stefw@gnome.org>
13  */
14
15 #include "config.h"
16
17 #include "secret-collection.h"
18 #include "secret-dbus-generated.h"
19 #include "secret-enum-types.h"
20 #include "secret-item.h"
21 #include "secret-paths.h"
22 #include "secret-private.h"
23 #include "secret-service.h"
24 #include "secret-types.h"
25 #include "secret-value.h"
26
27 #include <glib/gi18n-lib.h>
28
29 /**
30  * SECTION:secret-item
31  * @title: SecretItem
32  * @short_description: A secret item
33  *
34  * #SecretItem represents a secret item stored in the Secret Service.
35  *
36  * Each item has a value, represented by a #SecretValue, which can be
37  * retrieved by secret_item_get_secret() or set by secret_item_set_secret().
38  * The item is only available when the item is not locked.
39  *
40  * Items can be locked or unlocked using the secret_service_lock() or
41  * secret_service_unlock() functions. The Secret Service may not be able to
42  * unlock individual items, and may unlock an entire collection when a single
43  * item is unlocked.
44  *
45  * Each item has a set of attributes, which are used to locate the item later.
46  * These are not stored or transferred in a secure manner. Each attribute has
47  * a string name and a string value. Use secret_service_search() to search for
48  * items based on their attributes, and secret_item_set_attributes() to change
49  * the attributes associated with an item.
50  *
51  * Items can be created with secret_item_create() or secret_service_store().
52  *
53  * Stability: Unstable
54  */
55
56 /**
57  * SecretItem:
58  *
59  * A proxy object representing a secret item in the Secret Service.
60  */
61
62 /**
63  * SecretItemClass:
64  * @parent_class: the parent class
65  *
66  * The class for #SecretItem.
67  */
68
69 /**
70  * SecretItemFlags:
71  * @SECRET_ITEM_NONE: no flags
72  * @SECRET_ITEM_LOAD_SECRET: a secret has been (or should be) loaded for #SecretItem
73  *
74  * Flags which determine which parts of the #SecretItem proxy are initialized.
75  */
76
77 /**
78  * SecretItemCreateFlags:
79  * @SECRET_ITEM_CREATE_NONE: no flags
80  * @SECRET_ITEM_CREATE_REPLACE: replace an item with the same attributes.
81  *
82  * Flags for secret_item_create().
83  */
84
85 enum {
86         PROP_0,
87         PROP_SERVICE,
88         PROP_FLAGS,
89         PROP_ATTRIBUTES,
90         PROP_LABEL,
91         PROP_LOCKED,
92         PROP_CREATED,
93         PROP_MODIFIED
94 };
95
96 struct _SecretItemPrivate {
97         /* No changes between construct and finalize */
98         SecretService *service;
99         SecretItemFlags init_flags;
100         GCancellable *cancellable;
101
102         /* Locked by mutex */
103         GMutex mutex;
104         SecretValue *value;
105 };
106
107 static GInitableIface *secret_item_initable_parent_iface = NULL;
108
109 static GAsyncInitableIface *secret_item_async_initable_parent_iface = NULL;
110
111 static void   secret_item_initable_iface         (GInitableIface *iface);
112
113 static void   secret_item_async_initable_iface   (GAsyncInitableIface *iface);
114
115 G_DEFINE_TYPE_WITH_CODE (SecretItem, secret_item, G_TYPE_DBUS_PROXY,
116                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_item_initable_iface);
117                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_item_async_initable_iface);
118 );
119
120 static void
121 secret_item_init (SecretItem *self)
122 {
123         self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, SECRET_TYPE_ITEM, SecretItemPrivate);
124         self->pv->cancellable = g_cancellable_new ();
125         g_mutex_init (&self->pv->mutex);
126 }
127
128 static void
129 on_set_attributes (GObject *source,
130                    GAsyncResult *result,
131                    gpointer user_data)
132 {
133         SecretItem *self = SECRET_ITEM (user_data);
134         GError *error = NULL;
135
136         secret_item_set_attributes_finish (self, result, &error);
137         if (error != NULL) {
138                 g_warning ("couldn't set SecretItem Attributes: %s", error->message);
139                 g_error_free (error);
140         }
141
142         g_object_unref (self);
143 }
144
145 static void
146 on_set_label (GObject *source,
147               GAsyncResult *result,
148               gpointer user_data)
149 {
150         SecretItem *self = SECRET_ITEM (user_data);
151         GError *error = NULL;
152
153         secret_item_set_label_finish (self, result, &error);
154         if (error != NULL) {
155                 g_warning ("couldn't set SecretItem Label: %s", error->message);
156                 g_error_free (error);
157         }
158
159         g_object_unref (self);
160 }
161
162
163 static void
164 item_take_service (SecretItem *self,
165                    SecretService *service)
166 {
167         if (service == NULL)
168                 return;
169
170         g_return_if_fail (self->pv->service == NULL);
171
172         self->pv->service = service;
173         g_object_add_weak_pointer (G_OBJECT (self->pv->service),
174                                    (gpointer *)&self->pv->service);
175
176         /* Yes, we expect that the service will stay around */
177         g_object_unref (service);
178 }
179
180 static void
181 secret_item_set_property (GObject *obj,
182                           guint prop_id,
183                           const GValue *value,
184                           GParamSpec *pspec)
185 {
186         SecretItem *self = SECRET_ITEM (obj);
187
188         switch (prop_id) {
189         case PROP_SERVICE:
190                 item_take_service (self, g_value_dup_object (value));
191                 break;
192         case PROP_FLAGS:
193                 self->pv->init_flags = g_value_get_flags (value);
194                 break;
195         case PROP_ATTRIBUTES:
196                 secret_item_set_attributes (self, NULL, g_value_get_boxed (value),
197                                             self->pv->cancellable, on_set_attributes,
198                                             g_object_ref (self));
199                 break;
200         case PROP_LABEL:
201                 secret_item_set_label (self, g_value_get_string (value),
202                                        self->pv->cancellable, on_set_label,
203                                        g_object_ref (self));
204                 break;
205         default:
206                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
207                 break;
208         }
209 }
210
211 static void
212 secret_item_get_property (GObject *obj,
213                           guint prop_id,
214                           GValue *value,
215                           GParamSpec *pspec)
216 {
217         SecretItem *self = SECRET_ITEM (obj);
218
219         switch (prop_id) {
220         case PROP_SERVICE:
221                 g_value_set_object (value, self->pv->service);
222                 break;
223         case PROP_FLAGS:
224                 g_value_set_flags (value, secret_item_get_flags (self));
225                 break;
226         case PROP_ATTRIBUTES:
227                 g_value_take_boxed (value, secret_item_get_attributes (self));
228                 break;
229         case PROP_LABEL:
230                 g_value_take_string (value, secret_item_get_label (self));
231                 break;
232         case PROP_LOCKED:
233                 g_value_set_boolean (value, secret_item_get_locked (self));
234                 break;
235         case PROP_CREATED:
236                 g_value_set_uint64 (value, secret_item_get_created (self));
237                 break;
238         case PROP_MODIFIED:
239                 g_value_set_uint64 (value, secret_item_get_modified (self));
240                 break;
241         default:
242                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
243                 break;
244         }
245 }
246
247 static void
248 secret_item_dispose (GObject *obj)
249 {
250         SecretItem *self = SECRET_ITEM (obj);
251
252         g_cancellable_cancel (self->pv->cancellable);
253
254         G_OBJECT_CLASS (secret_item_parent_class)->dispose (obj);
255 }
256
257 static void
258 secret_item_finalize (GObject *obj)
259 {
260         SecretItem *self = SECRET_ITEM (obj);
261
262         if (self->pv->service)
263                 g_object_remove_weak_pointer (G_OBJECT (self->pv->service),
264                                               (gpointer *)&self->pv->service);
265
266         g_object_unref (self->pv->cancellable);
267         g_mutex_clear (&self->pv->mutex);
268
269         G_OBJECT_CLASS (secret_item_parent_class)->finalize (obj);
270 }
271
272 static void
273 handle_property_changed (GObject *object,
274                          const gchar *property_name)
275 {
276         if (g_str_equal (property_name, "Attributes"))
277                 g_object_notify (object, "attributes");
278
279         else if (g_str_equal (property_name, "Label"))
280                 g_object_notify (object, "label");
281
282         else if (g_str_equal (property_name, "Locked"))
283                 g_object_notify (object, "locked");
284
285         else if (g_str_equal (property_name, "Created"))
286                 g_object_notify (object, "created");
287
288         else if (g_str_equal (property_name, "Modified"))
289                 g_object_notify (object, "modified");
290 }
291
292 static void
293 secret_item_properties_changed (GDBusProxy *proxy,
294                                 GVariant *changed_properties,
295                                 const gchar* const *invalidated_properties)
296 {
297         GObject *obj = G_OBJECT (proxy);
298         gchar *property_name;
299         GVariantIter iter;
300         GVariant *value;
301
302         g_object_freeze_notify (obj);
303
304         g_variant_iter_init (&iter, changed_properties);
305         while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value))
306                 handle_property_changed (obj, property_name);
307
308         g_object_thaw_notify (obj);
309 }
310
311 static void
312 secret_item_class_init (SecretItemClass *klass)
313 {
314         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
315         GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass);
316
317         gobject_class->get_property = secret_item_get_property;
318         gobject_class->set_property = secret_item_set_property;
319         gobject_class->dispose = secret_item_dispose;
320         gobject_class->finalize = secret_item_finalize;
321
322         proxy_class->g_properties_changed = secret_item_properties_changed;
323
324         /**
325          * SecretItem:service:
326          *
327          * The #SecretService object that this item is associated with and
328          * uses to interact with the actual D-Bus Secret Service.
329          */
330         g_object_class_install_property (gobject_class, PROP_SERVICE,
331                     g_param_spec_object ("service", "Service", "Secret Service",
332                                          SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
333
334         /**
335          * SecretService:flags:
336          *
337          * A set of flags describing which parts of the secret item have
338          * been initialized.
339          */
340         g_object_class_install_property (gobject_class, PROP_FLAGS,
341                      g_param_spec_flags ("flags", "Flags", "Item flags",
342                                          secret_item_flags_get_type (), SECRET_ITEM_NONE,
343                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
344
345         /**
346          * SecretItem:attributes:
347          *
348          * The attributes set on this item. Attributes are used to locate an
349          * item. They are not guaranteed to be stored or transferred securely.
350          *
351          * Type: GLib.HashTable(utf8,utf8)
352          * Transfer: full
353          */
354         g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
355                      g_param_spec_boxed ("attributes", "Attributes", "Item attributes",
356                                          G_TYPE_HASH_TABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
357
358         /**
359          * SecretItem:label:
360          *
361          * The human readable label for the item.
362          *
363          * Setting this property will result in the label of the item being
364          * set asynchronously. To properly track the changing of the label use the
365          * secret_item_set_label() function.
366          */
367         g_object_class_install_property (gobject_class, PROP_LABEL,
368                     g_param_spec_string ("label", "Label", "Item label",
369                                          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
370
371         /**
372          * SecretItem:locked:
373          *
374          * Whether the item is locked or not. An item may not be independently
375          * lockable separate from other items in its collection.
376          *
377          * To lock or unlock a item use the secret_service_lock() or
378          * secret_service_unlock() functions.
379          */
380         g_object_class_install_property (gobject_class, PROP_LOCKED,
381                    g_param_spec_boolean ("locked", "Locked", "Item locked",
382                                          TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
383
384         /**
385          * SecretItem:created:
386          *
387          * The date and time (in seconds since the UNIX epoch) that this
388          * item was created.
389          */
390         g_object_class_install_property (gobject_class, PROP_CREATED,
391                     g_param_spec_uint64 ("created", "Created", "Item creation date",
392                                          0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
393
394         /**
395          * SecretItem:modified:
396          *
397          * The date and time (in seconds since the UNIX epoch) that this
398          * item was last modified.
399          */
400         g_object_class_install_property (gobject_class, PROP_MODIFIED,
401                     g_param_spec_uint64 ("modified", "Modified", "Item modified date",
402                                          0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
403
404         g_type_class_add_private (gobject_class, sizeof (SecretItemPrivate));
405 }
406
407 typedef struct {
408         GCancellable *cancellable;
409 } InitClosure;
410
411 static void
412 init_closure_free (gpointer data)
413 {
414         InitClosure *closure = data;
415         g_clear_object (&closure->cancellable);
416         g_slice_free (InitClosure, closure);
417 }
418
419 static gboolean
420 item_ensure_for_flags_sync (SecretItem *self,
421                             SecretItemFlags flags,
422                             GCancellable *cancellable,
423                             GError **error)
424 {
425         if (flags & SECRET_ITEM_LOAD_SECRET && !secret_item_get_locked (self)) {
426                 if (!secret_item_load_secret_sync (self, cancellable, error))
427                         return FALSE;
428         }
429
430         return TRUE;
431 }
432
433
434 static void
435 on_init_load_secret (GObject *source,
436                      GAsyncResult *result,
437                      gpointer user_data)
438 {
439         GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
440         SecretItem *self = SECRET_ITEM (source);
441         GError *error = NULL;
442
443         if (!secret_item_load_secret_finish (self, result, &error))
444                 g_simple_async_result_take_error (async, error);
445
446         g_simple_async_result_complete (async);
447         g_object_unref (async);
448 }
449
450 static void
451 item_ensure_for_flags_async (SecretItem *self,
452                              SecretItemFlags flags,
453                              GSimpleAsyncResult *async)
454 {
455         InitClosure *init = g_simple_async_result_get_op_res_gpointer (async);
456
457         if (flags & SECRET_ITEM_LOAD_SECRET && !secret_item_get_locked (self))
458                 secret_item_load_secret (self, init->cancellable,
459                                          on_init_load_secret, g_object_ref (async));
460
461         else
462                 g_simple_async_result_complete (async);
463 }
464
465 static gboolean
466 secret_item_initable_init (GInitable *initable,
467                            GCancellable *cancellable,
468                            GError **error)
469 {
470         SecretItem *self;
471         SecretService *service;
472         GDBusProxy *proxy;
473
474         if (!secret_item_initable_parent_iface->init (initable, cancellable, error))
475                 return FALSE;
476
477         proxy = G_DBUS_PROXY (initable);
478
479         if (!_secret_util_have_cached_properties (proxy)) {
480                 g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
481                              "No such secret item at path: %s",
482                              g_dbus_proxy_get_object_path (proxy));
483                 return FALSE;
484         }
485
486         self = SECRET_ITEM (initable);
487         if (!self->pv->service) {
488                 service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error);
489                 if (service == NULL)
490                         return FALSE;
491                 else
492                         item_take_service (self, service);
493         }
494
495         return item_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error);
496 }
497
498 static void
499 secret_item_initable_iface (GInitableIface *iface)
500 {
501         secret_item_initable_parent_iface = g_type_interface_peek_parent (iface);
502
503         iface->init = secret_item_initable_init;
504 }
505
506 static void
507 on_init_service (GObject *source,
508                  GAsyncResult *result,
509                  gpointer user_data)
510 {
511         GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
512         SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
513         SecretService *service;
514         GError *error = NULL;
515
516         service = secret_service_get_finish (result, &error);
517         if (error == NULL) {
518                 item_take_service (self, service);
519                 item_ensure_for_flags_async (self, self->pv->init_flags, async);
520
521         } else {
522                 g_simple_async_result_take_error (async, error);
523                 g_simple_async_result_complete (async);
524         }
525
526         g_object_unref (self);
527         g_object_unref (async);
528 }
529
530 static void
531 on_init_base (GObject *source,
532               GAsyncResult *result,
533               gpointer user_data)
534 {
535         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
536         InitClosure *init = g_simple_async_result_get_op_res_gpointer (res);
537         SecretItem *self = SECRET_ITEM (source);
538         GDBusProxy *proxy = G_DBUS_PROXY (self);
539         GError *error = NULL;
540
541         if (!secret_item_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self),
542                                                                    result, &error)) {
543                 g_simple_async_result_take_error (res, error);
544                 g_simple_async_result_complete (res);
545
546         } else if (!_secret_util_have_cached_properties (proxy)) {
547                 g_simple_async_result_set_error (res, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
548                                                  "No such secret item at path: %s",
549                                                  g_dbus_proxy_get_object_path (proxy));
550                 g_simple_async_result_complete (res);
551
552         } else if (self->pv->service == NULL) {
553                 secret_service_get (SECRET_SERVICE_NONE, init->cancellable,
554                                     on_init_service, g_object_ref (res));
555
556         } else {
557                 item_ensure_for_flags_async (self, self->pv->init_flags, res);
558         }
559
560         g_object_unref (res);
561 }
562
563 static void
564 secret_item_async_initable_init_async (GAsyncInitable *initable,
565                                        int io_priority,
566                                        GCancellable *cancellable,
567                                        GAsyncReadyCallback callback,
568                                        gpointer user_data)
569 {
570         GSimpleAsyncResult *res;
571         InitClosure *init;
572
573         res = g_simple_async_result_new (G_OBJECT (initable), callback, user_data,
574                                          secret_item_async_initable_init_async);
575         init = g_slice_new0 (InitClosure);
576         init->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
577         g_simple_async_result_set_op_res_gpointer (res, init, init_closure_free);
578
579         secret_item_async_initable_parent_iface->init_async (initable, io_priority,
580                                                              cancellable,
581                                                              on_init_base,
582                                                              g_object_ref (res));
583
584         g_object_unref (res);
585 }
586
587 static gboolean
588 secret_item_async_initable_init_finish (GAsyncInitable *initable,
589                                         GAsyncResult *result,
590                                         GError **error)
591 {
592         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (initable),
593                               secret_item_async_initable_init_async), FALSE);
594
595         if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
596                 return FALSE;
597
598         return TRUE;
599 }
600
601 static void
602 secret_item_async_initable_iface (GAsyncInitableIface *iface)
603 {
604         secret_item_async_initable_parent_iface = g_type_interface_peek_parent (iface);
605
606         iface->init_async = secret_item_async_initable_init_async;
607         iface->init_finish = secret_item_async_initable_init_finish;
608 }
609
610 /**
611  * secret_item_refresh:
612  * @self: the collection
613  *
614  * Refresh the properties on this item. This fires off a request to
615  * refresh, and the properties will be updated later.
616  *
617  * Calling this method is not normally necessary, as the secret service
618  * will notify the client when properties change.
619  */
620 void
621 secret_item_refresh (SecretItem *self)
622 {
623         g_return_if_fail (SECRET_IS_ITEM (self));
624
625         _secret_util_get_properties (G_DBUS_PROXY (self),
626                                      secret_item_refresh,
627                                      NULL, NULL, NULL);
628 }
629
630 void
631 _secret_item_set_cached_secret (SecretItem *self,
632                                 SecretValue *value)
633 {
634         SecretValue *other = NULL;
635         gboolean updated = FALSE;
636
637         g_return_if_fail (SECRET_IS_ITEM (self));
638
639         if (value != NULL)
640                 secret_value_ref (value);
641
642         g_mutex_lock (&self->pv->mutex);
643
644         if (value != self->pv->value) {
645                 other = self->pv->value;
646                 self->pv->value = value;
647                 updated = TRUE;
648         } else {
649                 other = value;
650         }
651
652         g_mutex_unlock (&self->pv->mutex);
653
654         if (other != NULL)
655                 secret_value_unref (other);
656
657         if (updated)
658                 g_object_notify (G_OBJECT (self), "flags");
659 }
660
661 typedef struct {
662         GCancellable *cancellable;
663         SecretItem *item;
664         SecretValue *value;
665 } CreateClosure;
666
667 static void
668 create_closure_free (gpointer data)
669 {
670         CreateClosure *closure = data;
671         g_clear_object (&closure->cancellable);
672         g_clear_object (&closure->item);
673         secret_value_unref (closure->value);
674         g_slice_free (CreateClosure, closure);
675 }
676
677 static void
678 on_create_item (GObject *source,
679                 GAsyncResult *result,
680                 gpointer user_data)
681 {
682         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
683         CreateClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
684         GError *error = NULL;
685
686         closure->item = secret_item_new_for_dbus_path_finish (result, &error);
687         if (error != NULL)
688                 g_simple_async_result_take_error (res, error);
689
690         /* As a convenince mark down the SecretValue on the item */
691         _secret_item_set_cached_secret (closure->item, closure->value);
692
693         g_simple_async_result_complete (res);
694         g_object_unref (res);
695 }
696
697 static void
698 on_create_path (GObject *source,
699                 GAsyncResult *result,
700                 gpointer user_data)
701 {
702         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
703         CreateClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
704         SecretService *service = SECRET_SERVICE (source);
705         GError *error = NULL;
706         gchar *path;
707
708         path = secret_service_create_item_dbus_path_finish (service, result, &error);
709         if (error == NULL) {
710                 secret_item_new_for_dbus_path (service, path, SECRET_ITEM_NONE,
711                                                closure->cancellable, on_create_item,
712                                                g_object_ref (res));
713         } else {
714                 g_simple_async_result_take_error (res, error);
715                 g_simple_async_result_complete (res);
716         }
717
718         g_object_unref (res);
719 }
720
721 static GHashTable *
722 item_properties_new (const gchar *label,
723                      const SecretSchema *schema,
724                      GHashTable *attributes)
725 {
726         const gchar *schema_name = NULL;
727         GHashTable *properties;
728         GVariant *value;
729
730         if (schema != NULL)
731                 schema_name = schema->name;
732
733         properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
734                                             (GDestroyNotify)g_variant_unref);
735
736         value = g_variant_new_string (label);
737         g_hash_table_insert (properties,
738                              SECRET_ITEM_INTERFACE ".Label",
739                              g_variant_ref_sink (value));
740
741         value = _secret_attributes_to_variant (attributes, schema_name);
742         g_hash_table_insert (properties,
743                              SECRET_ITEM_INTERFACE ".Attributes",
744                              g_variant_ref_sink (value));
745
746         return properties;
747 }
748
749 /**
750  * secret_item_create:
751  * @collection: a secret collection to create this item in
752  * @schema: (allow-none): the schema for the attributes
753  * @attributes: (element-type utf8 utf8): attributes for the new item
754  * @label: label for the new item
755  * @value: secret value for the new item
756  * @flags: flags for the creation of the new item
757  * @cancellable: optional cancellation object
758  * @callback: called when the operation completes
759  * @user_data: data to pass to the callback
760  *
761  * Create a new item in the secret service.
762  *
763  * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret
764  * service will search for an item matching the @attributes, and update that item
765  * instead of creating a new one.
766  *
767  * This method may block indefinitely and should not be used in user interface
768  * threads. The secret service may prompt the user. secret_service_prompt()
769  * will be used to handle any prompts that are required.
770  */
771 void
772 secret_item_create (SecretCollection *collection,
773                     const SecretSchema *schema,
774                     GHashTable *attributes,
775                     const gchar *label,
776                     SecretValue *value,
777                     SecretItemCreateFlags flags,
778                     GCancellable *cancellable,
779                     GAsyncReadyCallback callback,
780                     gpointer user_data)
781 {
782         SecretService *service = NULL;
783         const gchar *collection_path;
784         GSimpleAsyncResult *res;
785         CreateClosure *closure;
786         GHashTable *properties;
787
788         g_return_if_fail (SECRET_IS_COLLECTION (collection));
789         g_return_if_fail (label != NULL);
790         g_return_if_fail (attributes != NULL);
791         g_return_if_fail (value != NULL);
792         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
793
794         /* Warnings raised already */
795         if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
796                 return;
797
798         res = g_simple_async_result_new (NULL, callback, user_data,
799                                          secret_item_create);
800         closure = g_slice_new0 (CreateClosure);
801         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
802         closure->value = secret_value_ref (value);
803         g_simple_async_result_set_op_res_gpointer (res, closure, create_closure_free);
804
805         properties = item_properties_new (label, schema, attributes);
806         g_object_get (collection, "service", &service, NULL);
807
808         collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection));
809
810         secret_service_create_item_dbus_path (service, collection_path, properties,
811                                               value, flags, cancellable,
812                                               on_create_path, g_object_ref (res));
813
814         g_hash_table_unref (properties);
815         g_object_unref (service);
816         g_object_unref (res);
817 }
818
819 /**
820  * secret_item_create_finish:
821  * @result: the asynchronous result passed to the callback
822  * @error: location to place an error on failure
823  *
824  * Finish operation to create a new item in the secret service.
825  *
826  * Returns: (transfer full): the new item, which should be unreferenced
827  *          with g_object_unref()
828  */
829 SecretItem *
830 secret_item_create_finish (GAsyncResult *result,
831                            GError **error)
832 {
833         GSimpleAsyncResult *res;
834         CreateClosure *closure;
835
836         g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
837                               secret_item_create), NULL);
838         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
839
840         res = G_SIMPLE_ASYNC_RESULT (result);
841
842         if (g_simple_async_result_propagate_error (res, error))
843                 return NULL;
844
845         closure = g_simple_async_result_get_op_res_gpointer (res);
846         if (closure->item == NULL)
847                 return NULL;
848
849         return g_object_ref (closure->item);
850 }
851
852 /**
853  * secret_item_create_sync:
854  * @collection: a secret collection to create this item in
855  * @schema: (allow-none): the schema for the attributes
856  * @attributes: (element-type utf8 utf8): attributes for the new item
857  * @label: label for the new item
858  * @value: secret value for the new item
859  * @flags: flags for the creation of the new item
860  * @cancellable: optional cancellation object
861  * @error: location to place an error on failure
862  *
863  * Create a new item in the secret service.
864  *
865  * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret
866  * service will search for an item matching the @attributes, and update that item
867  * instead of creating a new one.
868  *
869  * This method may block indefinitely and should not be used in user interface
870  * threads. The secret service may prompt the user. secret_service_prompt()
871  * will be used to handle any prompts that are required.
872  *
873  * Returns: (transfer full): the new item, which should be unreferenced
874  *          with g_object_unref()
875  */
876 SecretItem *
877 secret_item_create_sync (SecretCollection *collection,
878                          const SecretSchema *schema,
879                          GHashTable *attributes,
880                          const gchar *label,
881                          SecretValue *value,
882                          SecretItemCreateFlags flags,
883                          GCancellable *cancellable,
884                          GError **error)
885 {
886         SecretService *service = NULL;
887         const gchar *collection_path;
888         SecretItem *item = NULL;
889         GHashTable *properties;
890         gchar *path;
891
892         g_return_val_if_fail (SECRET_IS_COLLECTION (collection), NULL);
893         g_return_val_if_fail (label != NULL, NULL);
894         g_return_val_if_fail (attributes != NULL, NULL);
895         g_return_val_if_fail (value != NULL, NULL);
896         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
897         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
898
899         /* Warnings raised already */
900         if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
901                 return NULL;
902
903         properties = item_properties_new (label, schema, attributes);
904         g_object_get (collection, "service", &service, NULL);
905
906         collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection));
907
908         path = secret_service_create_item_dbus_path_sync (service, collection_path, properties,
909                                                           value, flags, cancellable, error);
910
911         if (path != NULL) {
912                 item = secret_item_new_for_dbus_path_sync (service, path, SECRET_ITEM_NONE,
913                                                            cancellable, error);
914                 g_free (path);
915         }
916
917         g_hash_table_unref (properties);
918         g_object_unref (service);
919
920         return item;
921 }
922
923 static void
924 on_item_deleted (GObject *source,
925                  GAsyncResult *result,
926                  gpointer user_data)
927 {
928         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
929         SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
930         GError *error = NULL;
931
932         if (_secret_service_delete_path_finish (SECRET_SERVICE (source), result, &error))
933                 g_simple_async_result_set_op_res_gboolean (res, TRUE);
934
935         if (error != NULL)
936                 g_simple_async_result_take_error (res, error);
937
938         g_simple_async_result_complete (res);
939         g_object_unref (self);
940         g_object_unref (res);
941 }
942
943 /**
944  * secret_item_delete:
945  * @self: an item
946  * @cancellable: optional cancellation object
947  * @callback: called when the operation completes
948  * @user_data: data to pass to the callback
949  *
950  * Delete this item.
951  *
952  * This method returns immediately and completes asynchronously. The secret
953  * service may prompt the user. secret_service_prompt() will be used to handle
954  * any prompts that show up.
955  */
956 void
957 secret_item_delete (SecretItem *self,
958                     GCancellable *cancellable,
959                     GAsyncReadyCallback callback,
960                     gpointer user_data)
961 {
962         GSimpleAsyncResult *res;
963         const gchar *object_path;
964
965         g_return_if_fail (SECRET_IS_ITEM (self));
966         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
967
968         object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self));
969         res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
970                                          secret_item_delete);
971
972         _secret_service_delete_path (self->pv->service, object_path, TRUE,
973                                      cancellable, on_item_deleted, g_object_ref (res));
974
975         g_object_unref (res);
976 }
977
978 /**
979  * secret_item_delete_finish:
980  * @self: an item
981  * @result: asynchronous result passed to the callback
982  * @error: location to place an error on failure
983  *
984  * Complete asynchronous operation to delete the secret item.
985  *
986  * Returns: whether the item was successfully deleted or not
987  */
988 gboolean
989 secret_item_delete_finish (SecretItem *self,
990                            GAsyncResult *result,
991                            GError **error)
992 {
993         GSimpleAsyncResult *res;
994
995         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
996         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
997         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
998                               secret_item_delete), FALSE);
999
1000         res = G_SIMPLE_ASYNC_RESULT (result);
1001
1002         if (g_simple_async_result_propagate_error (res, error))
1003                 return FALSE;
1004
1005         return g_simple_async_result_get_op_res_gboolean (res);
1006 }
1007
1008 /**
1009  * secret_item_delete_sync:
1010  * @self: an item
1011  * @cancellable: optional cancellation object
1012  * @error: location to place an error on failure
1013  *
1014  * Delete this secret item.
1015  *
1016  * This method may block indefinitely and should not be used in user
1017  * interface threads. The secret service may prompt the user.
1018  * secret_service_prompt() will be used to handle any prompts that show up.
1019  *
1020  * Returns: whether the item was successfully deleted or not
1021  */
1022 gboolean
1023 secret_item_delete_sync (SecretItem *self,
1024                          GCancellable *cancellable,
1025                          GError **error)
1026 {
1027         SecretSync *sync;
1028         gboolean ret;
1029
1030         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1031         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1032         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1033
1034         sync = _secret_sync_new ();
1035         g_main_context_push_thread_default (sync->context);
1036
1037         secret_item_delete (self, cancellable, _secret_sync_on_result, sync);
1038
1039         g_main_loop_run (sync->loop);
1040
1041         ret = secret_item_delete_finish (self, sync->result, error);
1042
1043         g_main_context_pop_thread_default (sync->context);
1044         _secret_sync_free (sync);
1045
1046         return ret;
1047 }
1048
1049 /**
1050  * secret_item_get_flags:
1051  * @self: the secret item proxy
1052  *
1053  * Get the flags representing what features of the #SecretItem proxy
1054  * have been initialized.
1055  *
1056  * Use secret_item_load_secret() to initialize further features
1057  * and change the flags.
1058  *
1059  * Returns: the flags for features initialized
1060  */
1061 SecretItemFlags
1062 secret_item_get_flags (SecretItem *self)
1063 {
1064         SecretServiceFlags flags = 0;
1065
1066         g_return_val_if_fail (SECRET_IS_ITEM (self), SECRET_ITEM_NONE);
1067
1068         g_mutex_lock (&self->pv->mutex);
1069
1070         if (self->pv->value)
1071                 flags |= SECRET_ITEM_LOAD_SECRET;
1072
1073         g_mutex_unlock (&self->pv->mutex);
1074
1075         return flags;
1076
1077 }
1078
1079 /**
1080  * secret_item_get_service:
1081  * @self: an item
1082  *
1083  * Get the Secret Service object that this item was created with.
1084  *
1085  * Returns: (transfer none): the Secret Service object
1086  */
1087 SecretService *
1088 secret_item_get_service (SecretItem *self)
1089 {
1090         g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1091         return self->pv->service;
1092 }
1093
1094
1095 /**
1096  * secret_item_get_secret:
1097  * @self: an item
1098  *
1099  * Get the secret value of this item. If this item is locked or the secret
1100  * has not yet been loaded then this will return %NULL.
1101  *
1102  * To load the secret call the secret_item_load_secret() method.
1103  *
1104  * Returns: (transfer full) (allow-none): the secret value which should be
1105  *          released with secret_value_unref(), or %NULL
1106  */
1107 SecretValue *
1108 secret_item_get_secret (SecretItem *self)
1109 {
1110         SecretValue *value = NULL;
1111
1112         g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1113
1114         g_mutex_lock (&self->pv->mutex);
1115
1116         if (self->pv->value)
1117                 value = secret_value_ref (self->pv->value);
1118
1119         g_mutex_unlock (&self->pv->mutex);
1120
1121         return value;
1122 }
1123
1124
1125 typedef struct {
1126         GCancellable *cancellable;
1127 } LoadClosure;
1128
1129 static void
1130 load_closure_free (gpointer data)
1131 {
1132         LoadClosure *closure = data;
1133         g_clear_object (&closure->cancellable);
1134         g_slice_free (LoadClosure, closure);
1135 }
1136
1137 static void
1138 on_item_load_secret (GObject *source,
1139                      GAsyncResult *result,
1140                      gpointer user_data)
1141 {
1142         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1143         SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
1144         SecretSession *session;
1145         GError *error = NULL;
1146         SecretValue *value;
1147         GVariant *retval;
1148         GVariant *child;
1149
1150         retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
1151         if (error == NULL) {
1152                 child = g_variant_get_child_value (retval, 0);
1153                 g_variant_unref (retval);
1154
1155                 session = _secret_service_get_session (self->pv->service);
1156                 value = _secret_session_decode_secret (session, child);
1157                 g_variant_unref (child);
1158
1159                 if (value == NULL) {
1160                         g_set_error (&error, SECRET_ERROR, SECRET_ERROR_PROTOCOL,
1161                                      _("Received invalid secret from the secret storage"));
1162                 } else {
1163                         _secret_item_set_cached_secret (self, value);
1164                         secret_value_unref (value);
1165                 }
1166         }
1167
1168         if (error != NULL) {
1169                 _secret_util_strip_remote_error (&error);
1170                 g_simple_async_result_take_error (res, error);
1171         }
1172
1173         g_simple_async_result_complete (res);
1174         g_object_unref (res);
1175 }
1176
1177 static void
1178 on_load_ensure_session (GObject *source,
1179                         GAsyncResult *result,
1180                         gpointer user_data)
1181 {
1182         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1183         SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
1184         LoadClosure *load = g_simple_async_result_get_op_res_gpointer (res);
1185         const gchar *session_path;
1186         GError *error = NULL;
1187
1188         secret_service_ensure_session_finish (self->pv->service, result, &error);
1189         if (error != NULL) {
1190                 g_simple_async_result_take_error (res, error);
1191                 g_simple_async_result_complete (res);
1192
1193         } else {
1194                 session_path = secret_service_get_session_dbus_path (self->pv->service);
1195                 g_assert (session_path != NULL && session_path[0] != '\0');
1196                 g_dbus_proxy_call (G_DBUS_PROXY (self), "GetSecret",
1197                                    g_variant_new ("(o)", session_path),
1198                                    G_DBUS_CALL_FLAGS_NONE, -1, load->cancellable,
1199                                    on_item_load_secret, g_object_ref (res));
1200         }
1201
1202         g_object_unref (self);
1203         g_object_unref (res);
1204 }
1205
1206 /**
1207  * secret_item_load_secret:
1208  * @self: an item proxy
1209  * @cancellable: optional cancellation object
1210  * @callback: called when the operation completes
1211  * @user_data: data to pass to the callback
1212  *
1213  * Load the secret value of this item.
1214  *
1215  * Each item has a single secret which might be a password or some
1216  * other secret binary value.
1217  *
1218  * This function will fail if the secret item is locked.
1219  *
1220  * This function returns immediately and completes asynchronously.
1221  */
1222 void
1223 secret_item_load_secret (SecretItem *self,
1224                          GCancellable *cancellable,
1225                          GAsyncReadyCallback callback,
1226                          gpointer user_data)
1227 {
1228         GSimpleAsyncResult *res;
1229         LoadClosure *closure;
1230
1231         g_return_if_fail (SECRET_IS_ITEM (self));
1232         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1233
1234         res = g_simple_async_result_new (G_OBJECT (self), callback,
1235                                          user_data, secret_item_load_secret);
1236         closure = g_slice_new0 (LoadClosure);
1237         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1238         g_simple_async_result_set_op_res_gpointer (res, closure, load_closure_free);
1239
1240         secret_service_ensure_session (self->pv->service, cancellable,
1241                                        on_load_ensure_session,
1242                                        g_object_ref (res));
1243
1244         g_object_unref (res);
1245 }
1246
1247 /**
1248  * secret_item_load_secret_finish:
1249  * @self: an item proxy
1250  * @result: asynchronous result passed to callback
1251  * @error: location to place error on failure
1252  *
1253  * Complete asynchronous operation to load the secret value of this item.
1254  *
1255  * The newly loaded secret value can be accessed by calling
1256  * secret_item_get_secret().
1257  *
1258  * Returns: whether the secret item succesfully loaded or not
1259  */
1260 gboolean
1261 secret_item_load_secret_finish (SecretItem *self,
1262                                 GAsyncResult *result,
1263                                 GError **error)
1264 {
1265         GSimpleAsyncResult *res;
1266
1267         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1268                               secret_item_load_secret), FALSE);
1269
1270         res = G_SIMPLE_ASYNC_RESULT (result);
1271         if (g_simple_async_result_propagate_error (res, error))
1272                 return FALSE;
1273
1274         return TRUE;
1275 }
1276
1277 /**
1278  * secret_item_load_secret_sync:
1279  * @self: an item
1280  * @cancellable: optional cancellation object
1281  * @error: location to place error on failure
1282  *
1283  * Load the secret value of this item.
1284  *
1285  * Each item has a single secret which might be a password or some
1286  * other secret binary value.
1287  *
1288  * This function may block indefinetely. Use the asynchronous version
1289  * in user interface threads.
1290  *
1291  * Returns: whether the secret item succesfully loaded or not
1292  */
1293 gboolean
1294 secret_item_load_secret_sync (SecretItem *self,
1295                               GCancellable *cancellable,
1296                               GError **error)
1297 {
1298         SecretSync *sync;
1299         gboolean result;
1300
1301         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1302         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1303         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1304
1305         sync = _secret_sync_new ();
1306         g_main_context_push_thread_default (sync->context);
1307
1308         secret_item_load_secret (self, cancellable, _secret_sync_on_result, sync);
1309
1310         g_main_loop_run (sync->loop);
1311
1312         result = secret_item_load_secret_finish (self, sync->result, error);
1313
1314         g_main_context_pop_thread_default (sync->context);
1315         _secret_sync_free (sync);
1316
1317         return result;
1318 }
1319
1320 typedef struct {
1321         SecretService *service;
1322         GCancellable *cancellable;
1323         GVariant *in;
1324         GHashTable *items;
1325 } LoadsClosure;
1326
1327 static void
1328 loads_closure_free (gpointer data)
1329 {
1330         LoadsClosure *loads = data;
1331         if (loads->in)
1332                 g_variant_unref (loads->in);
1333         if (loads->service)
1334                 g_object_unref (loads->service);
1335         g_clear_object (&loads->cancellable);
1336         g_slice_free (LoadsClosure, loads);
1337 }
1338
1339 static void
1340 on_get_secrets_complete (GObject *source,
1341                          GAsyncResult *result,
1342                          gpointer user_data)
1343 {
1344         GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1345         LoadsClosure *loads = g_simple_async_result_get_op_res_gpointer (async);
1346         GHashTable *with_paths;
1347         GError *error = NULL;
1348         GHashTableIter iter;
1349         const gchar *path;
1350         SecretValue *value;
1351         SecretItem *item;
1352         GVariant *retval;
1353
1354         retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
1355         if (retval != NULL) {
1356                 with_paths = _secret_service_decode_get_secrets_all (loads->service, retval);
1357                 g_return_if_fail (with_paths != NULL);
1358
1359                 g_hash_table_iter_init (&iter, with_paths);
1360                 while (g_hash_table_iter_next (&iter, (gpointer *)&path, (gpointer *)&value)) {
1361                         item = g_hash_table_lookup (loads->items, path);
1362                         if (item != NULL)
1363                                 _secret_item_set_cached_secret (item, value);
1364                 }
1365
1366                 g_hash_table_unref (with_paths);
1367                 g_variant_unref (retval);
1368         }
1369
1370         if (error != NULL) {
1371                 _secret_util_strip_remote_error (&error);
1372                 g_simple_async_result_take_error (async, error);
1373         }
1374
1375         g_simple_async_result_complete (async);
1376         g_object_unref (async);
1377 }
1378
1379 static void
1380 on_loads_secrets_session (GObject *source,
1381                           GAsyncResult *result,
1382                           gpointer user_data)
1383 {
1384         GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1385         LoadsClosure *loads = g_simple_async_result_get_op_res_gpointer (async);
1386         GError *error = NULL;
1387         const gchar *session;
1388
1389         secret_service_ensure_session_finish (SECRET_SERVICE (source), result, &error);
1390         if (error != NULL) {
1391                 g_simple_async_result_take_error (async, error);
1392                 g_simple_async_result_complete (async);
1393
1394         } else {
1395                 session = secret_service_get_session_dbus_path (SECRET_SERVICE (source));
1396                 g_dbus_proxy_call (G_DBUS_PROXY (source), "GetSecrets",
1397                                    g_variant_new ("(@aoo)", loads->in, session),
1398                                    G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
1399                                    loads->cancellable, on_get_secrets_complete,
1400                                    g_object_ref (async));
1401         }
1402
1403         g_object_unref (async);
1404 }
1405
1406 /**
1407  * secret_item_load_secrets:
1408  * @items: (element-type Secret.Item): the items to retrieve secrets for
1409  * @cancellable: optional cancellation object
1410  * @callback: called when the operation completes
1411  * @user_data: data to pass to the callback
1412  *
1413  * Load the secret values for an secret items stored in the service.
1414  *
1415  * The @items must all have the same SecretItem::service property.
1416  *
1417  * This function returns immediately and completes asynchronously.
1418  */
1419 void
1420 secret_item_load_secrets (GList *items,
1421                           GCancellable *cancellable,
1422                           GAsyncReadyCallback callback,
1423                           gpointer user_data)
1424 {
1425         GSimpleAsyncResult *async;
1426         LoadsClosure *loads;
1427         GPtrArray *paths;
1428         const gchar *path;
1429         GList *l;
1430
1431         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1432
1433         for (l = items; l != NULL; l = g_list_next (l))
1434                 g_return_if_fail (SECRET_IS_ITEM (l->data));
1435
1436         async = g_simple_async_result_new (NULL, callback, user_data,
1437                                            secret_item_load_secrets);
1438         loads = g_slice_new0 (LoadsClosure);
1439         loads->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1440         loads->items = g_hash_table_new_full (g_str_hash, g_str_equal,
1441                                               g_free, g_object_unref);
1442
1443         paths = g_ptr_array_new ();
1444         for (l = items; l != NULL; l = g_list_next (l)) {
1445                 if (secret_item_get_locked (l->data))
1446                         continue;
1447
1448                 if (loads->service == NULL) {
1449                         loads->service = secret_item_get_service (l->data);
1450                         if (loads->service)
1451                                 g_object_ref (loads->service);
1452                 }
1453
1454                 path = g_dbus_proxy_get_object_path (l->data);
1455                 g_hash_table_insert (loads->items, g_strdup (path), g_object_ref (l->data));
1456                 g_ptr_array_add (paths, (gpointer)path);
1457         }
1458
1459         loads->in = g_variant_new_objv ((const gchar * const *)paths->pdata, paths->len);
1460         g_variant_ref_sink (loads->in);
1461
1462         g_ptr_array_free (paths, TRUE);
1463         g_simple_async_result_set_op_res_gpointer (async, loads, loads_closure_free);
1464
1465         if (loads->service) {
1466                 secret_service_ensure_session (loads->service, cancellable,
1467                                                on_loads_secrets_session,
1468                                                g_object_ref (async));
1469         } else {
1470                 g_simple_async_result_complete_in_idle (async);
1471         }
1472
1473         g_object_unref (async);
1474 }
1475
1476 /**
1477  * secret_item_load_secrets_finish:
1478  * @result: asynchronous result passed to callback
1479  * @error: location to place an error on failure
1480  *
1481  * Complete asynchronous operation to load the secret values for
1482  * secret items stored in the service.
1483  *
1484  * Items that are locked will not have their secrets loaded.
1485  *
1486  * Returns: whether the operation succeded or not
1487  */
1488 gboolean
1489 secret_item_load_secrets_finish (GAsyncResult *result,
1490                                  GError **error)
1491 {
1492         GSimpleAsyncResult *async;
1493
1494         g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
1495                               secret_item_load_secrets), FALSE);
1496         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1497
1498         async = G_SIMPLE_ASYNC_RESULT (result);
1499         if (g_simple_async_result_propagate_error (async, error))
1500                 return FALSE;
1501
1502         return TRUE;
1503 }
1504
1505 /**
1506  * secret_item_load_secrets_sync:
1507  * @items: (element-type Secret.Item): the items to retrieve secrets for
1508  * @cancellable: optional cancellation object
1509  * @error: location to place an error on failure
1510  *
1511  * Load the secret values for an secret items stored in the service.
1512  *
1513  * The @items must all have the same SecretItem::service property.
1514  *
1515  * This method may block indefinitely and should not be used in user interface
1516  * threads.
1517  *
1518  * Items that are locked will not have their secrets loaded.
1519  *
1520  * Returns: whether the operation succeded or not
1521  */
1522 gboolean
1523 secret_item_load_secrets_sync (GList *items,
1524                                GCancellable *cancellable,
1525                                GError **error)
1526 {
1527         SecretSync *sync;
1528         gboolean ret;
1529         GList *l;
1530
1531         for (l = items; l != NULL; l = g_list_next (l))
1532                 g_return_val_if_fail (SECRET_IS_ITEM (l->data), FALSE);
1533
1534         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1535         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1536
1537         sync = _secret_sync_new ();
1538         g_main_context_push_thread_default (sync->context);
1539
1540         secret_item_load_secrets (items, cancellable,
1541                                   _secret_sync_on_result, sync);
1542
1543         g_main_loop_run (sync->loop);
1544
1545         ret = secret_item_load_secrets_finish (sync->result, error);
1546
1547         g_main_context_pop_thread_default (sync->context);
1548         _secret_sync_free (sync);
1549
1550         return ret;
1551 }
1552
1553 typedef struct {
1554         GCancellable *cancellable;
1555         SecretValue *value;
1556 } SetClosure;
1557
1558 static void
1559 set_closure_free (gpointer data)
1560 {
1561         SetClosure *set = data;
1562         g_clear_object (&set->cancellable);
1563         secret_value_unref (set->value);
1564         g_slice_free (SetClosure, set);
1565 }
1566
1567 static void
1568 on_item_set_secret (GObject *source,
1569                     GAsyncResult *result,
1570                     gpointer user_data)
1571 {
1572         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1573         SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
1574         SetClosure *set = g_simple_async_result_get_op_res_gpointer (res);
1575         GError *error = NULL;
1576         GVariant *retval;
1577
1578         retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
1579
1580         if (error == NULL) {
1581                 _secret_item_set_cached_secret (self, set->value);
1582         } else {
1583                 _secret_util_strip_remote_error (&error);
1584                 g_simple_async_result_take_error (res, error);
1585         }
1586         if (retval != NULL)
1587                 g_variant_unref (retval);
1588
1589         g_simple_async_result_complete (res);
1590         g_object_unref (self);
1591         g_object_unref (res);
1592 }
1593
1594 static void
1595 on_set_ensure_session (GObject *source,
1596                        GAsyncResult *result,
1597                        gpointer user_data)
1598 {
1599         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1600         SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
1601         SetClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1602         SecretSession *session;
1603         GVariant *encoded;
1604         GError *error = NULL;
1605
1606         secret_service_ensure_session_finish (self->pv->service, result, &error);
1607         if (error != NULL) {
1608                 g_simple_async_result_take_error (res, error);
1609                 g_simple_async_result_complete (res);
1610
1611         } else {
1612                 session = _secret_service_get_session (self->pv->service);
1613                 encoded = _secret_session_encode_secret (session, closure->value);
1614                 g_dbus_proxy_call (G_DBUS_PROXY (self), "SetSecret",
1615                                    g_variant_new ("(@(oayays))", encoded),
1616                                    G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, closure->cancellable,
1617                                    on_item_set_secret, g_object_ref (res));
1618         }
1619
1620         g_object_unref (self);
1621         g_object_unref (res);
1622 }
1623
1624 /**
1625  * secret_item_set_secret:
1626  * @self: an item
1627  * @value: a new secret value
1628  * @cancellable: optional cancellation object
1629  * @callback: called when the operation completes
1630  * @user_data: data to pass to the callback
1631  *
1632  * Set the secret value of this item.
1633  *
1634  * Each item has a single secret which might be a password or some
1635  * other secret binary value.
1636  *
1637  * This function returns immediately and completes asynchronously.
1638  */
1639 void
1640 secret_item_set_secret (SecretItem *self,
1641                         SecretValue *value,
1642                         GCancellable *cancellable,
1643                         GAsyncReadyCallback callback,
1644                         gpointer user_data)
1645 {
1646         GSimpleAsyncResult *res;
1647         SetClosure *closure;
1648
1649         g_return_if_fail (SECRET_IS_ITEM (self));
1650         g_return_if_fail (value != NULL);
1651         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1652
1653         res = g_simple_async_result_new (G_OBJECT (self), callback,
1654                                          user_data, secret_item_set_secret);
1655         closure = g_slice_new0 (SetClosure);
1656         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1657         closure->value = secret_value_ref (value);
1658         g_simple_async_result_set_op_res_gpointer (res, closure, set_closure_free);
1659
1660         secret_service_ensure_session (self->pv->service, cancellable,
1661                                        on_set_ensure_session,
1662                                        g_object_ref (res));
1663
1664         g_object_unref (res);
1665 }
1666
1667 /**
1668  * secret_item_set_secret_finish:
1669  * @self: an item
1670  * @result: asynchronous result passed to callback
1671  * @error: location to place error on failure
1672  *
1673  * Complete asynchronous operation to set the secret value of this item.
1674  *
1675  * Returns: whether the change was successful or not
1676  */
1677 gboolean
1678 secret_item_set_secret_finish (SecretItem *self,
1679                                GAsyncResult *result,
1680                                GError **error)
1681 {
1682         GSimpleAsyncResult *res;
1683
1684         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1685                               secret_item_set_secret), FALSE);
1686
1687         res = G_SIMPLE_ASYNC_RESULT (result);
1688         if (g_simple_async_result_propagate_error (res, error))
1689                 return FALSE;
1690
1691         return TRUE;
1692 }
1693
1694 /**
1695  * secret_item_set_secret_sync:
1696  * @self: an item
1697  * @value: a new secret value
1698  * @cancellable: optional cancellation object
1699  * @error: location to place error on failure
1700  *
1701  * Set the secret value of this item.
1702  *
1703  * Each item has a single secret which might be a password or some
1704  * other secret binary value.
1705  *
1706  * This function may block indefinetely. Use the asynchronous version
1707  * in user interface threads.
1708  *
1709  * Returns: whether the change was successful or not
1710  */
1711 gboolean
1712 secret_item_set_secret_sync (SecretItem *self,
1713                              SecretValue *value,
1714                              GCancellable *cancellable,
1715                              GError **error)
1716 {
1717         SecretSync *sync;
1718         gboolean ret;
1719
1720         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1721         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1722         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1723
1724         sync = _secret_sync_new ();
1725         g_main_context_push_thread_default (sync->context);
1726
1727         secret_item_set_secret (self, value, cancellable, _secret_sync_on_result, sync);
1728
1729         g_main_loop_run (sync->loop);
1730
1731         ret = secret_item_set_secret_finish (self, sync->result, error);
1732
1733         g_main_context_pop_thread_default (sync->context);
1734         _secret_sync_free (sync);
1735
1736         return ret;
1737 }
1738
1739 /**
1740  * secret_item_get_schema_name:
1741  * @self: an item
1742  *
1743  * Gets the name of the schema that this item was stored with. This is also
1744  * available at the <literal>xdg:schema</literal> attribute.
1745  *
1746  * Returns: (transfer full): the schema name
1747  */
1748 gchar *
1749 secret_item_get_schema_name (SecretItem *self)
1750 {
1751         gchar *schema_name;
1752         GVariant *variant;
1753
1754         g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1755
1756         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Attributes");
1757         g_return_val_if_fail (variant != NULL, NULL);
1758
1759         g_variant_lookup (variant, "xdg:schema", "s", &schema_name);
1760         g_variant_unref (variant);
1761
1762         return schema_name;
1763 }
1764
1765 /**
1766  * secret_item_get_attributes:
1767  * @self: an item
1768  *
1769  * Set the attributes of this item.
1770  *
1771  * The @attributes are a mapping of string keys to string values.
1772  * Attributes are used to search for items. Attributes are not stored
1773  * or transferred securely by the secret service.
1774  *
1775  * Do not modify the attributes returned by this method. Use
1776  * secret_item_set_attributes() instead.
1777  *
1778  * Returns: (transfer full) (element-type utf8 utf8): a new reference
1779  *          to the attributes, which should not be modified, and
1780  *          released with g_hash_table_unref()
1781  */
1782 GHashTable *
1783 secret_item_get_attributes (SecretItem *self)
1784 {
1785         GHashTable *attributes;
1786         GVariant *variant;
1787
1788         g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1789
1790         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Attributes");
1791         g_return_val_if_fail (variant != NULL, NULL);
1792
1793         attributes = _secret_attributes_for_variant (variant);
1794         g_variant_unref (variant);
1795
1796         return attributes;
1797 }
1798
1799 /**
1800  * secret_item_set_attributes:
1801  * @self: an item
1802  * @schema: (allow-none): the schema for the attributes
1803  * @attributes: (element-type utf8 utf8): a new set of attributes
1804  * @cancellable: optional cancellation object
1805  * @callback: called when the asynchronous operation completes
1806  * @user_data: data to pass to the callback
1807  *
1808  * Set the attributes of this item.
1809  *
1810  * The @attributes are a mapping of string keys to string values.
1811  * Attributes are used to search for items. Attributes are not stored
1812  * or transferred securely by the secret service.
1813  *
1814  * This function returns immediately and completes asynchronously.
1815  */
1816 void
1817 secret_item_set_attributes (SecretItem *self,
1818                             const SecretSchema *schema,
1819                             GHashTable *attributes,
1820                             GCancellable *cancellable,
1821                             GAsyncReadyCallback callback,
1822                             gpointer user_data)
1823 {
1824         const gchar *schema_name = NULL;
1825
1826         g_return_if_fail (SECRET_IS_ITEM (self));
1827         g_return_if_fail (attributes != NULL);
1828
1829         if (schema != NULL) {
1830                 if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
1831                         return; /* Warnings raised already */
1832                 schema_name = schema->name;
1833         }
1834
1835         _secret_util_set_property (G_DBUS_PROXY (self), "Attributes",
1836                                    _secret_attributes_to_variant (attributes, schema_name),
1837                                    secret_item_set_attributes, cancellable,
1838                                    callback, user_data);
1839 }
1840
1841 /**
1842  * secret_item_set_attributes_finish:
1843  * @self: an item
1844  * @result: asynchronous result passed to the callback
1845  * @error: location to place error on failure
1846  *
1847  * Complete operation to set the attributes of this item.
1848  *
1849  * Returns: whether the change was successful or not
1850  */
1851 gboolean
1852 secret_item_set_attributes_finish (SecretItem *self,
1853                                    GAsyncResult *result,
1854                                    GError **error)
1855 {
1856         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1857
1858         return _secret_util_set_property_finish (G_DBUS_PROXY (self),
1859                                                  secret_item_set_attributes,
1860                                                  result, error);
1861 }
1862
1863 /**
1864  * secret_item_set_attributes_sync:
1865  * @self: an item
1866  * @schema: (allow-none): the schema for the attributes
1867  * @attributes: (element-type utf8 utf8): a new set of attributes
1868  * @cancellable: optional cancellation object
1869  * @error: location to place error on failure
1870  *
1871  * Set the attributes of this item.
1872  *
1873  * The @attributes are a mapping of string keys to string values.
1874  * Attributes are used to search for items. Attributes are not stored
1875  * or transferred securely by the secret service.
1876  *
1877  * This function may block indefinetely. Use the asynchronous version
1878  * in user interface threads.
1879  *
1880  * Returns: whether the change was successful or not
1881  */
1882 gboolean
1883 secret_item_set_attributes_sync (SecretItem *self,
1884                                  const SecretSchema *schema,
1885                                  GHashTable *attributes,
1886                                  GCancellable *cancellable,
1887                                  GError **error)
1888 {
1889         const gchar *schema_name = NULL;
1890
1891         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1892         g_return_val_if_fail (attributes != NULL, FALSE);
1893
1894         if (schema != NULL) {
1895                 if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
1896                         return FALSE; /* Warnings raised already */
1897                 schema_name = schema->name;
1898         }
1899
1900         return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Attributes",
1901                                                _secret_attributes_to_variant (attributes, schema_name),
1902                                                cancellable, error);
1903 }
1904
1905 /**
1906  * secret_item_get_label:
1907  * @self: an item
1908  *
1909  * Get the label of this item.
1910  *
1911  * Returns: (transfer full): the label, which should be freed with g_free()
1912  */
1913 gchar *
1914 secret_item_get_label (SecretItem *self)
1915 {
1916         GVariant *variant;
1917         gchar *label;
1918
1919         g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1920
1921         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Label");
1922         g_return_val_if_fail (variant != NULL, NULL);
1923
1924         label = g_variant_dup_string (variant, NULL);
1925         g_variant_unref (variant);
1926
1927         return label;
1928 }
1929
1930 /**
1931  * secret_item_set_label:
1932  * @self: an item
1933  * @label: a new label
1934  * @cancellable: optional cancellation object
1935  * @callback: called when the operation completes
1936  * @user_data: data to pass to the callback
1937  *
1938  * Set the label of this item.
1939  *
1940  * This function returns immediately and completes asynchronously.
1941  */
1942 void
1943 secret_item_set_label (SecretItem *self,
1944                        const gchar *label,
1945                        GCancellable *cancellable,
1946                        GAsyncReadyCallback callback,
1947                        gpointer user_data)
1948 {
1949         g_return_if_fail (SECRET_IS_ITEM (self));
1950         g_return_if_fail (label != NULL);
1951
1952         _secret_util_set_property (G_DBUS_PROXY (self), "Label",
1953                                    g_variant_new_string (label),
1954                                    secret_item_set_label,
1955                                    cancellable, callback, user_data);
1956 }
1957
1958 /**
1959  * secret_item_set_label_finish:
1960  * @self: an item
1961  * @result: asynchronous result passed to callback
1962  * @error: location to place error on failure
1963  *
1964  * Complete asynchronous operation to set the label of this collection.
1965  *
1966  * Returns: whether the change was successful or not
1967  */
1968 gboolean
1969 secret_item_set_label_finish (SecretItem *self,
1970                               GAsyncResult *result,
1971                               GError **error)
1972 {
1973         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1974
1975         return _secret_util_set_property_finish (G_DBUS_PROXY (self),
1976                                                  secret_item_set_label,
1977                                                  result, error);
1978 }
1979
1980 /**
1981  * secret_item_set_label_sync:
1982  * @self: an item
1983  * @label: a new label
1984  * @cancellable: optional cancellation object
1985  * @error: location to place error on failure
1986  *
1987  * Set the label of this item.
1988  *
1989  * This function may block indefinetely. Use the asynchronous version
1990  * in user interface threads.
1991  *
1992  * Returns: whether the change was successful or not
1993  */
1994 gboolean
1995 secret_item_set_label_sync (SecretItem *self,
1996                             const gchar *label,
1997                             GCancellable *cancellable,
1998                             GError **error)
1999 {
2000         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
2001         g_return_val_if_fail (label != NULL, FALSE);
2002
2003         return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Label",
2004                                                g_variant_new_string (label),
2005                                                cancellable, error);
2006 }
2007
2008 /**
2009  * secret_item_get_locked:
2010  * @self: an item
2011  *
2012  * Get whether the item is locked or not.
2013  *
2014  * Depending on the secret service an item may not be able to be locked
2015  * independently from the collection that it is in.
2016  *
2017  * Returns: whether the item is locked or not
2018  */
2019 gboolean
2020 secret_item_get_locked (SecretItem *self)
2021 {
2022         GVariant *variant;
2023         gboolean locked;
2024
2025         g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE);
2026
2027         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Locked");
2028         g_return_val_if_fail (variant != NULL, TRUE);
2029
2030         locked = g_variant_get_boolean (variant);
2031         g_variant_unref (variant);
2032
2033         return locked;
2034 }
2035
2036 /**
2037  * secret_item_get_created:
2038  * @self: an item
2039  *
2040  * Get the created date and time of the item. The return value is
2041  * the number of seconds since the unix epoch, January 1st 1970.
2042  *
2043  * Returns: the created date and time
2044  */
2045 guint64
2046 secret_item_get_created (SecretItem *self)
2047 {
2048         GVariant *variant;
2049         guint64 created;
2050
2051         g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE);
2052
2053         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Created");
2054         g_return_val_if_fail (variant != NULL, 0);
2055
2056         created = g_variant_get_uint64 (variant);
2057         g_variant_unref (variant);
2058
2059         return created;
2060 }
2061
2062 /**
2063  * secret_item_get_modified:
2064  * @self: an item
2065  *
2066  * Get the modified date and time of the item. The return value is
2067  * the number of seconds since the unix epoch, January 1st 1970.
2068  *
2069  * Returns: the modified date and time
2070  */
2071 guint64
2072 secret_item_get_modified (SecretItem *self)
2073 {
2074         GVariant *variant;
2075         guint64 modified;
2076
2077         g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE);
2078
2079         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Modified");
2080         g_return_val_if_fail (variant != NULL, 0);
2081
2082         modified = g_variant_get_uint64 (variant);
2083         g_variant_unref (variant);
2084
2085         return modified;
2086 }