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