Update documentation for to have correct headers
[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          * SecretService: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 (g_simple_async_result_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 (g_simple_async_result_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 (g_simple_async_result_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                 _secret_util_strip_remote_error (&error);
1173                 g_simple_async_result_take_error (res, error);
1174         }
1175
1176         g_simple_async_result_complete (res);
1177         g_object_unref (res);
1178 }
1179
1180 static void
1181 on_load_ensure_session (GObject *source,
1182                         GAsyncResult *result,
1183                         gpointer user_data)
1184 {
1185         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1186         SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
1187         LoadClosure *load = g_simple_async_result_get_op_res_gpointer (res);
1188         const gchar *session_path;
1189         GError *error = NULL;
1190
1191         secret_service_ensure_session_finish (self->pv->service, result, &error);
1192         if (error != NULL) {
1193                 g_simple_async_result_take_error (res, error);
1194                 g_simple_async_result_complete (res);
1195
1196         } else {
1197                 session_path = secret_service_get_session_dbus_path (self->pv->service);
1198                 g_assert (session_path != NULL && session_path[0] != '\0');
1199                 g_dbus_proxy_call (G_DBUS_PROXY (self), "GetSecret",
1200                                    g_variant_new ("(o)", session_path),
1201                                    G_DBUS_CALL_FLAGS_NONE, -1, load->cancellable,
1202                                    on_item_load_secret, g_object_ref (res));
1203         }
1204
1205         g_object_unref (self);
1206         g_object_unref (res);
1207 }
1208
1209 /**
1210  * secret_item_load_secret:
1211  * @self: an item proxy
1212  * @cancellable: optional cancellation object
1213  * @callback: called when the operation completes
1214  * @user_data: data to pass to the callback
1215  *
1216  * Load the secret value of this item.
1217  *
1218  * Each item has a single secret which might be a password or some
1219  * other secret binary value.
1220  *
1221  * This function will fail if the secret item is locked.
1222  *
1223  * This function returns immediately and completes asynchronously.
1224  */
1225 void
1226 secret_item_load_secret (SecretItem *self,
1227                          GCancellable *cancellable,
1228                          GAsyncReadyCallback callback,
1229                          gpointer user_data)
1230 {
1231         GSimpleAsyncResult *res;
1232         LoadClosure *closure;
1233
1234         g_return_if_fail (SECRET_IS_ITEM (self));
1235         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1236
1237         res = g_simple_async_result_new (G_OBJECT (self), callback,
1238                                          user_data, secret_item_load_secret);
1239         closure = g_slice_new0 (LoadClosure);
1240         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1241         g_simple_async_result_set_op_res_gpointer (res, closure, load_closure_free);
1242
1243         secret_service_ensure_session (self->pv->service, cancellable,
1244                                        on_load_ensure_session,
1245                                        g_object_ref (res));
1246
1247         g_object_unref (res);
1248 }
1249
1250 /**
1251  * secret_item_load_secret_finish:
1252  * @self: an item proxy
1253  * @result: asynchronous result passed to callback
1254  * @error: location to place error on failure
1255  *
1256  * Complete asynchronous operation to load the secret value of this item.
1257  *
1258  * The newly loaded secret value can be accessed by calling
1259  * secret_item_get_secret().
1260  *
1261  * Returns: whether the secret item succesfully loaded or not
1262  */
1263 gboolean
1264 secret_item_load_secret_finish (SecretItem *self,
1265                                 GAsyncResult *result,
1266                                 GError **error)
1267 {
1268         GSimpleAsyncResult *res;
1269
1270         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1271                               secret_item_load_secret), FALSE);
1272
1273         res = G_SIMPLE_ASYNC_RESULT (result);
1274         if (g_simple_async_result_propagate_error (res, error))
1275                 return FALSE;
1276
1277         return TRUE;
1278 }
1279
1280 /**
1281  * secret_item_load_secret_sync:
1282  * @self: an item
1283  * @cancellable: optional cancellation object
1284  * @error: location to place error on failure
1285  *
1286  * Load the secret value of this item.
1287  *
1288  * Each item has a single secret which might be a password or some
1289  * other secret binary value.
1290  *
1291  * This function may block indefinetely. Use the asynchronous version
1292  * in user interface threads.
1293  *
1294  * Returns: whether the secret item succesfully loaded or not
1295  */
1296 gboolean
1297 secret_item_load_secret_sync (SecretItem *self,
1298                               GCancellable *cancellable,
1299                               GError **error)
1300 {
1301         SecretSync *sync;
1302         gboolean result;
1303
1304         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1305         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1306         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1307
1308         sync = _secret_sync_new ();
1309         g_main_context_push_thread_default (sync->context);
1310
1311         secret_item_load_secret (self, cancellable, _secret_sync_on_result, sync);
1312
1313         g_main_loop_run (sync->loop);
1314
1315         result = secret_item_load_secret_finish (self, sync->result, error);
1316
1317         g_main_context_pop_thread_default (sync->context);
1318         _secret_sync_free (sync);
1319
1320         return result;
1321 }
1322
1323 typedef struct {
1324         SecretService *service;
1325         GCancellable *cancellable;
1326         GVariant *in;
1327         GHashTable *items;
1328 } LoadsClosure;
1329
1330 static void
1331 loads_closure_free (gpointer data)
1332 {
1333         LoadsClosure *loads = data;
1334         if (loads->in)
1335                 g_variant_unref (loads->in);
1336         if (loads->service)
1337                 g_object_unref (loads->service);
1338         g_clear_object (&loads->cancellable);
1339         g_slice_free (LoadsClosure, loads);
1340 }
1341
1342 static void
1343 on_get_secrets_complete (GObject *source,
1344                          GAsyncResult *result,
1345                          gpointer user_data)
1346 {
1347         GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1348         LoadsClosure *loads = g_simple_async_result_get_op_res_gpointer (async);
1349         GHashTable *with_paths;
1350         GError *error = NULL;
1351         GHashTableIter iter;
1352         const gchar *path;
1353         SecretValue *value;
1354         SecretItem *item;
1355         GVariant *retval;
1356
1357         retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
1358         if (retval != NULL) {
1359                 with_paths = _secret_service_decode_get_secrets_all (loads->service, retval);
1360                 g_return_if_fail (with_paths != NULL);
1361
1362                 g_hash_table_iter_init (&iter, with_paths);
1363                 while (g_hash_table_iter_next (&iter, (gpointer *)&path, (gpointer *)&value)) {
1364                         item = g_hash_table_lookup (loads->items, path);
1365                         if (item != NULL)
1366                                 _secret_item_set_cached_secret (item, value);
1367                 }
1368
1369                 g_hash_table_unref (with_paths);
1370                 g_variant_unref (retval);
1371         }
1372
1373         if (error != NULL) {
1374                 _secret_util_strip_remote_error (&error);
1375                 g_simple_async_result_take_error (async, error);
1376         }
1377
1378         g_simple_async_result_complete (async);
1379         g_object_unref (async);
1380 }
1381
1382 static void
1383 on_loads_secrets_session (GObject *source,
1384                           GAsyncResult *result,
1385                           gpointer user_data)
1386 {
1387         GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1388         LoadsClosure *loads = g_simple_async_result_get_op_res_gpointer (async);
1389         GError *error = NULL;
1390         const gchar *session;
1391
1392         secret_service_ensure_session_finish (SECRET_SERVICE (source), result, &error);
1393         if (error != NULL) {
1394                 g_simple_async_result_take_error (async, error);
1395                 g_simple_async_result_complete (async);
1396
1397         } else {
1398                 session = secret_service_get_session_dbus_path (SECRET_SERVICE (source));
1399                 g_dbus_proxy_call (G_DBUS_PROXY (source), "GetSecrets",
1400                                    g_variant_new ("(@aoo)", loads->in, session),
1401                                    G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
1402                                    loads->cancellable, on_get_secrets_complete,
1403                                    g_object_ref (async));
1404         }
1405
1406         g_object_unref (async);
1407 }
1408
1409 /**
1410  * secret_item_load_secrets:
1411  * @items: (element-type SecretUnstable.Item): the items to retrieve secrets for
1412  * @cancellable: optional cancellation object
1413  * @callback: called when the operation completes
1414  * @user_data: data to pass to the callback
1415  *
1416  * Load the secret values for an secret items stored in the service.
1417  *
1418  * The @items must all have the same SecretItem::service property.
1419  *
1420  * This function returns immediately and completes asynchronously.
1421  */
1422 void
1423 secret_item_load_secrets (GList *items,
1424                           GCancellable *cancellable,
1425                           GAsyncReadyCallback callback,
1426                           gpointer user_data)
1427 {
1428         GSimpleAsyncResult *async;
1429         LoadsClosure *loads;
1430         GPtrArray *paths;
1431         const gchar *path;
1432         GList *l;
1433
1434         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1435
1436         for (l = items; l != NULL; l = g_list_next (l))
1437                 g_return_if_fail (SECRET_IS_ITEM (l->data));
1438
1439         async = g_simple_async_result_new (NULL, callback, user_data,
1440                                            secret_item_load_secrets);
1441         loads = g_slice_new0 (LoadsClosure);
1442         loads->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1443         loads->items = g_hash_table_new_full (g_str_hash, g_str_equal,
1444                                               g_free, g_object_unref);
1445
1446         paths = g_ptr_array_new ();
1447         for (l = items; l != NULL; l = g_list_next (l)) {
1448                 if (secret_item_get_locked (l->data))
1449                         continue;
1450
1451                 if (loads->service == NULL) {
1452                         loads->service = secret_item_get_service (l->data);
1453                         if (loads->service)
1454                                 g_object_ref (loads->service);
1455                 }
1456
1457                 path = g_dbus_proxy_get_object_path (l->data);
1458                 g_hash_table_insert (loads->items, g_strdup (path), g_object_ref (l->data));
1459                 g_ptr_array_add (paths, (gpointer)path);
1460         }
1461
1462         loads->in = g_variant_new_objv ((const gchar * const *)paths->pdata, paths->len);
1463         g_variant_ref_sink (loads->in);
1464
1465         g_ptr_array_free (paths, TRUE);
1466         g_simple_async_result_set_op_res_gpointer (async, loads, loads_closure_free);
1467
1468         if (loads->service) {
1469                 secret_service_ensure_session (loads->service, cancellable,
1470                                                on_loads_secrets_session,
1471                                                g_object_ref (async));
1472         } else {
1473                 g_simple_async_result_complete_in_idle (async);
1474         }
1475
1476         g_object_unref (async);
1477 }
1478
1479 /**
1480  * secret_item_load_secrets_finish:
1481  * @result: asynchronous result passed to callback
1482  * @error: location to place an error on failure
1483  *
1484  * Complete asynchronous operation to load the secret values for
1485  * secret items stored in the service.
1486  *
1487  * Items that are locked will not have their secrets loaded.
1488  *
1489  * Returns: whether the operation succeded or not
1490  */
1491 gboolean
1492 secret_item_load_secrets_finish (GAsyncResult *result,
1493                                  GError **error)
1494 {
1495         GSimpleAsyncResult *async;
1496
1497         g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
1498                               secret_item_load_secrets), FALSE);
1499         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1500
1501         async = G_SIMPLE_ASYNC_RESULT (result);
1502         if (g_simple_async_result_propagate_error (async, error))
1503                 return FALSE;
1504
1505         return TRUE;
1506 }
1507
1508 /**
1509  * secret_item_load_secrets_sync:
1510  * @items: (element-type SecretUnstable.Item): the items to retrieve secrets for
1511  * @cancellable: optional cancellation object
1512  * @error: location to place an error on failure
1513  *
1514  * Load the secret values for an secret items stored in the service.
1515  *
1516  * The @items must all have the same SecretItem::service property.
1517  *
1518  * This method may block indefinitely and should not be used in user interface
1519  * threads.
1520  *
1521  * Items that are locked will not have their secrets loaded.
1522  *
1523  * Returns: whether the operation succeded or not
1524  */
1525 gboolean
1526 secret_item_load_secrets_sync (GList *items,
1527                                GCancellable *cancellable,
1528                                GError **error)
1529 {
1530         SecretSync *sync;
1531         gboolean ret;
1532         GList *l;
1533
1534         for (l = items; l != NULL; l = g_list_next (l))
1535                 g_return_val_if_fail (SECRET_IS_ITEM (l->data), FALSE);
1536
1537         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1538         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1539
1540         sync = _secret_sync_new ();
1541         g_main_context_push_thread_default (sync->context);
1542
1543         secret_item_load_secrets (items, cancellable,
1544                                   _secret_sync_on_result, sync);
1545
1546         g_main_loop_run (sync->loop);
1547
1548         ret = secret_item_load_secrets_finish (sync->result, error);
1549
1550         g_main_context_pop_thread_default (sync->context);
1551         _secret_sync_free (sync);
1552
1553         return ret;
1554 }
1555
1556 typedef struct {
1557         GCancellable *cancellable;
1558         SecretValue *value;
1559 } SetClosure;
1560
1561 static void
1562 set_closure_free (gpointer data)
1563 {
1564         SetClosure *set = data;
1565         g_clear_object (&set->cancellable);
1566         secret_value_unref (set->value);
1567         g_slice_free (SetClosure, set);
1568 }
1569
1570 static void
1571 on_item_set_secret (GObject *source,
1572                     GAsyncResult *result,
1573                     gpointer user_data)
1574 {
1575         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1576         SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
1577         SetClosure *set = g_simple_async_result_get_op_res_gpointer (res);
1578         GError *error = NULL;
1579         GVariant *retval;
1580
1581         retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
1582
1583         if (error == NULL) {
1584                 _secret_item_set_cached_secret (self, set->value);
1585         } else {
1586                 _secret_util_strip_remote_error (&error);
1587                 g_simple_async_result_take_error (res, error);
1588         }
1589         if (retval != NULL)
1590                 g_variant_unref (retval);
1591
1592         g_simple_async_result_complete (res);
1593         g_object_unref (self);
1594         g_object_unref (res);
1595 }
1596
1597 static void
1598 on_set_ensure_session (GObject *source,
1599                        GAsyncResult *result,
1600                        gpointer user_data)
1601 {
1602         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
1603         SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
1604         SetClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
1605         SecretSession *session;
1606         GVariant *encoded;
1607         GError *error = NULL;
1608
1609         secret_service_ensure_session_finish (self->pv->service, result, &error);
1610         if (error != NULL) {
1611                 g_simple_async_result_take_error (res, error);
1612                 g_simple_async_result_complete (res);
1613
1614         } else {
1615                 session = _secret_service_get_session (self->pv->service);
1616                 encoded = _secret_session_encode_secret (session, closure->value);
1617                 g_dbus_proxy_call (G_DBUS_PROXY (self), "SetSecret",
1618                                    g_variant_new ("(@(oayays))", encoded),
1619                                    G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, closure->cancellable,
1620                                    on_item_set_secret, g_object_ref (res));
1621         }
1622
1623         g_object_unref (self);
1624         g_object_unref (res);
1625 }
1626
1627 /**
1628  * secret_item_set_secret:
1629  * @self: an item
1630  * @value: a new secret value
1631  * @cancellable: optional cancellation object
1632  * @callback: called when the operation completes
1633  * @user_data: data to pass to the callback
1634  *
1635  * Set the secret value of this item.
1636  *
1637  * Each item has a single secret which might be a password or some
1638  * other secret binary value.
1639  *
1640  * This function returns immediately and completes asynchronously.
1641  */
1642 void
1643 secret_item_set_secret (SecretItem *self,
1644                         SecretValue *value,
1645                         GCancellable *cancellable,
1646                         GAsyncReadyCallback callback,
1647                         gpointer user_data)
1648 {
1649         GSimpleAsyncResult *res;
1650         SetClosure *closure;
1651
1652         g_return_if_fail (SECRET_IS_ITEM (self));
1653         g_return_if_fail (value != NULL);
1654         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1655
1656         res = g_simple_async_result_new (G_OBJECT (self), callback,
1657                                          user_data, secret_item_set_secret);
1658         closure = g_slice_new0 (SetClosure);
1659         closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1660         closure->value = secret_value_ref (value);
1661         g_simple_async_result_set_op_res_gpointer (res, closure, set_closure_free);
1662
1663         secret_service_ensure_session (self->pv->service, cancellable,
1664                                        on_set_ensure_session,
1665                                        g_object_ref (res));
1666
1667         g_object_unref (res);
1668 }
1669
1670 /**
1671  * secret_item_set_secret_finish:
1672  * @self: an item
1673  * @result: asynchronous result passed to callback
1674  * @error: location to place error on failure
1675  *
1676  * Complete asynchronous operation to set the secret value of this item.
1677  *
1678  * Returns: whether the change was successful or not
1679  */
1680 gboolean
1681 secret_item_set_secret_finish (SecretItem *self,
1682                                GAsyncResult *result,
1683                                GError **error)
1684 {
1685         GSimpleAsyncResult *res;
1686
1687         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1688                               secret_item_set_secret), FALSE);
1689
1690         res = G_SIMPLE_ASYNC_RESULT (result);
1691         if (g_simple_async_result_propagate_error (res, error))
1692                 return FALSE;
1693
1694         return TRUE;
1695 }
1696
1697 /**
1698  * secret_item_set_secret_sync:
1699  * @self: an item
1700  * @value: a new secret value
1701  * @cancellable: optional cancellation object
1702  * @error: location to place error on failure
1703  *
1704  * Set the secret value of this item.
1705  *
1706  * Each item has a single secret which might be a password or some
1707  * other secret binary value.
1708  *
1709  * This function may block indefinetely. Use the asynchronous version
1710  * in user interface threads.
1711  *
1712  * Returns: whether the change was successful or not
1713  */
1714 gboolean
1715 secret_item_set_secret_sync (SecretItem *self,
1716                              SecretValue *value,
1717                              GCancellable *cancellable,
1718                              GError **error)
1719 {
1720         SecretSync *sync;
1721         gboolean ret;
1722
1723         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1724         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1725         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1726
1727         sync = _secret_sync_new ();
1728         g_main_context_push_thread_default (sync->context);
1729
1730         secret_item_set_secret (self, value, cancellable, _secret_sync_on_result, sync);
1731
1732         g_main_loop_run (sync->loop);
1733
1734         ret = secret_item_set_secret_finish (self, sync->result, error);
1735
1736         g_main_context_pop_thread_default (sync->context);
1737         _secret_sync_free (sync);
1738
1739         return ret;
1740 }
1741
1742 /**
1743  * secret_item_get_schema_name:
1744  * @self: an item
1745  *
1746  * Gets the name of the schema that this item was stored with. This is also
1747  * available at the <literal>xdg:schema</literal> attribute.
1748  *
1749  * Returns: (transfer full): the schema name
1750  */
1751 gchar *
1752 secret_item_get_schema_name (SecretItem *self)
1753 {
1754         gchar *schema_name;
1755         GVariant *variant;
1756
1757         g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1758
1759         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Attributes");
1760         g_return_val_if_fail (variant != NULL, NULL);
1761
1762         g_variant_lookup (variant, "xdg:schema", "s", &schema_name);
1763         g_variant_unref (variant);
1764
1765         return schema_name;
1766 }
1767
1768 /**
1769  * secret_item_get_attributes:
1770  * @self: an item
1771  *
1772  * Set the attributes of this item.
1773  *
1774  * The @attributes are a mapping of string keys to string values.
1775  * Attributes are used to search for items. Attributes are not stored
1776  * or transferred securely by the secret service.
1777  *
1778  * Do not modify the attributes returned by this method. Use
1779  * secret_item_set_attributes() instead.
1780  *
1781  * Returns: (transfer full) (element-type utf8 utf8): a new reference
1782  *          to the attributes, which should not be modified, and
1783  *          released with g_hash_table_unref()
1784  */
1785 GHashTable *
1786 secret_item_get_attributes (SecretItem *self)
1787 {
1788         GHashTable *attributes;
1789         GVariant *variant;
1790
1791         g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1792
1793         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Attributes");
1794         g_return_val_if_fail (variant != NULL, NULL);
1795
1796         attributes = _secret_attributes_for_variant (variant);
1797         g_variant_unref (variant);
1798
1799         return attributes;
1800 }
1801
1802 /**
1803  * secret_item_set_attributes:
1804  * @self: an item
1805  * @schema: (allow-none): the schema for the attributes
1806  * @attributes: (element-type utf8 utf8): a new set of attributes
1807  * @cancellable: optional cancellation object
1808  * @callback: called when the asynchronous operation completes
1809  * @user_data: data to pass to the callback
1810  *
1811  * Set the attributes of this item.
1812  *
1813  * The @attributes are a mapping of string keys to string values.
1814  * Attributes are used to search for items. Attributes are not stored
1815  * or transferred securely by the secret service.
1816  *
1817  * This function returns immediately and completes asynchronously.
1818  */
1819 void
1820 secret_item_set_attributes (SecretItem *self,
1821                             const SecretSchema *schema,
1822                             GHashTable *attributes,
1823                             GCancellable *cancellable,
1824                             GAsyncReadyCallback callback,
1825                             gpointer user_data)
1826 {
1827         const gchar *schema_name = NULL;
1828
1829         g_return_if_fail (SECRET_IS_ITEM (self));
1830         g_return_if_fail (attributes != NULL);
1831
1832         if (schema != NULL) {
1833                 if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
1834                         return; /* Warnings raised already */
1835                 schema_name = schema->name;
1836         }
1837
1838         _secret_util_set_property (G_DBUS_PROXY (self), "Attributes",
1839                                    _secret_attributes_to_variant (attributes, schema_name),
1840                                    secret_item_set_attributes, cancellable,
1841                                    callback, user_data);
1842 }
1843
1844 /**
1845  * secret_item_set_attributes_finish:
1846  * @self: an item
1847  * @result: asynchronous result passed to the callback
1848  * @error: location to place error on failure
1849  *
1850  * Complete operation to set the attributes of this item.
1851  *
1852  * Returns: whether the change was successful or not
1853  */
1854 gboolean
1855 secret_item_set_attributes_finish (SecretItem *self,
1856                                    GAsyncResult *result,
1857                                    GError **error)
1858 {
1859         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1860
1861         return _secret_util_set_property_finish (G_DBUS_PROXY (self),
1862                                                  secret_item_set_attributes,
1863                                                  result, error);
1864 }
1865
1866 /**
1867  * secret_item_set_attributes_sync:
1868  * @self: an item
1869  * @schema: (allow-none): the schema for the attributes
1870  * @attributes: (element-type utf8 utf8): a new set of attributes
1871  * @cancellable: optional cancellation object
1872  * @error: location to place error on failure
1873  *
1874  * Set the attributes of this item.
1875  *
1876  * The @attributes are a mapping of string keys to string values.
1877  * Attributes are used to search for items. Attributes are not stored
1878  * or transferred securely by the secret service.
1879  *
1880  * This function may block indefinetely. Use the asynchronous version
1881  * in user interface threads.
1882  *
1883  * Returns: whether the change was successful or not
1884  */
1885 gboolean
1886 secret_item_set_attributes_sync (SecretItem *self,
1887                                  const SecretSchema *schema,
1888                                  GHashTable *attributes,
1889                                  GCancellable *cancellable,
1890                                  GError **error)
1891 {
1892         const gchar *schema_name = NULL;
1893
1894         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1895         g_return_val_if_fail (attributes != NULL, FALSE);
1896
1897         if (schema != NULL) {
1898                 if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
1899                         return FALSE; /* Warnings raised already */
1900                 schema_name = schema->name;
1901         }
1902
1903         return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Attributes",
1904                                                _secret_attributes_to_variant (attributes, schema_name),
1905                                                cancellable, error);
1906 }
1907
1908 /**
1909  * secret_item_get_label:
1910  * @self: an item
1911  *
1912  * Get the label of this item.
1913  *
1914  * Returns: (transfer full): the label, which should be freed with g_free()
1915  */
1916 gchar *
1917 secret_item_get_label (SecretItem *self)
1918 {
1919         GVariant *variant;
1920         gchar *label;
1921
1922         g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1923
1924         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Label");
1925         g_return_val_if_fail (variant != NULL, NULL);
1926
1927         label = g_variant_dup_string (variant, NULL);
1928         g_variant_unref (variant);
1929
1930         return label;
1931 }
1932
1933 /**
1934  * secret_item_set_label:
1935  * @self: an item
1936  * @label: a new label
1937  * @cancellable: optional cancellation object
1938  * @callback: called when the operation completes
1939  * @user_data: data to pass to the callback
1940  *
1941  * Set the label of this item.
1942  *
1943  * This function returns immediately and completes asynchronously.
1944  */
1945 void
1946 secret_item_set_label (SecretItem *self,
1947                        const gchar *label,
1948                        GCancellable *cancellable,
1949                        GAsyncReadyCallback callback,
1950                        gpointer user_data)
1951 {
1952         g_return_if_fail (SECRET_IS_ITEM (self));
1953         g_return_if_fail (label != NULL);
1954
1955         _secret_util_set_property (G_DBUS_PROXY (self), "Label",
1956                                    g_variant_new_string (label),
1957                                    secret_item_set_label,
1958                                    cancellable, callback, user_data);
1959 }
1960
1961 /**
1962  * secret_item_set_label_finish:
1963  * @self: an item
1964  * @result: asynchronous result passed to callback
1965  * @error: location to place error on failure
1966  *
1967  * Complete asynchronous operation to set the label of this collection.
1968  *
1969  * Returns: whether the change was successful or not
1970  */
1971 gboolean
1972 secret_item_set_label_finish (SecretItem *self,
1973                               GAsyncResult *result,
1974                               GError **error)
1975 {
1976         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1977
1978         return _secret_util_set_property_finish (G_DBUS_PROXY (self),
1979                                                  secret_item_set_label,
1980                                                  result, error);
1981 }
1982
1983 /**
1984  * secret_item_set_label_sync:
1985  * @self: an item
1986  * @label: a new label
1987  * @cancellable: optional cancellation object
1988  * @error: location to place error on failure
1989  *
1990  * Set the label of this item.
1991  *
1992  * This function may block indefinetely. Use the asynchronous version
1993  * in user interface threads.
1994  *
1995  * Returns: whether the change was successful or not
1996  */
1997 gboolean
1998 secret_item_set_label_sync (SecretItem *self,
1999                             const gchar *label,
2000                             GCancellable *cancellable,
2001                             GError **error)
2002 {
2003         g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
2004         g_return_val_if_fail (label != NULL, FALSE);
2005
2006         return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Label",
2007                                                g_variant_new_string (label),
2008                                                cancellable, error);
2009 }
2010
2011 /**
2012  * secret_item_get_locked:
2013  * @self: an item
2014  *
2015  * Get whether the item is locked or not.
2016  *
2017  * Depending on the secret service an item may not be able to be locked
2018  * independently from the collection that it is in.
2019  *
2020  * Returns: whether the item is locked or not
2021  */
2022 gboolean
2023 secret_item_get_locked (SecretItem *self)
2024 {
2025         GVariant *variant;
2026         gboolean locked;
2027
2028         g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE);
2029
2030         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Locked");
2031         g_return_val_if_fail (variant != NULL, TRUE);
2032
2033         locked = g_variant_get_boolean (variant);
2034         g_variant_unref (variant);
2035
2036         return locked;
2037 }
2038
2039 /**
2040  * secret_item_get_created:
2041  * @self: an item
2042  *
2043  * Get the created date and time of the item. The return value is
2044  * the number of seconds since the unix epoch, January 1st 1970.
2045  *
2046  * Returns: the created date and time
2047  */
2048 guint64
2049 secret_item_get_created (SecretItem *self)
2050 {
2051         GVariant *variant;
2052         guint64 created;
2053
2054         g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE);
2055
2056         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Created");
2057         g_return_val_if_fail (variant != NULL, 0);
2058
2059         created = g_variant_get_uint64 (variant);
2060         g_variant_unref (variant);
2061
2062         return created;
2063 }
2064
2065 /**
2066  * secret_item_get_modified:
2067  * @self: an item
2068  *
2069  * Get the modified date and time of the item. The return value is
2070  * the number of seconds since the unix epoch, January 1st 1970.
2071  *
2072  * Returns: the modified date and time
2073  */
2074 guint64
2075 secret_item_get_modified (SecretItem *self)
2076 {
2077         GVariant *variant;
2078         guint64 modified;
2079
2080         g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE);
2081
2082         variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Modified");
2083         g_return_val_if_fail (variant != NULL, 0);
2084
2085         modified = g_variant_get_uint64 (variant);
2086         g_variant_unref (variant);
2087
2088         return modified;
2089 }