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-item.h"
20 #include "secret-paths.h"
21 #include "secret-private.h"
22 #include "secret-service.h"
23 #include "secret-types.h"
24
25 #include "libsecret/secret-enum-types.h"
26
27 #include <glib/gi18n-lib.h>
28
29 /**
30 * SECTION:secret-collection
31 * @title: SecretCollection
32 * @short_description: A collection of secret items
33 *
34 * #SecretCollection represents a collection of secret items stored in the
35 * Secret Service.
36 *
37 * A collection can be in a locked or unlocked state. Use secret_service_lock()
38 * or secret_service_unlock() to lock or unlock the collection.
39 *
40 * Use the SecretCollection::items property or secret_collection_get_items() to
41 * lookup the items in the collection. There may not be any items exposed when
42 * the collection is locked.
43 *
44 * Stability: Stable
45 */
46
47 /**
48 * SecretCollection:
49 *
50 * A proxy object representing a collection of secrets in the Secret Service.
51 */
52
53 /**
54 * SecretCollectionClass:
55 * @parent_class: the parent class
56 *
57 * The class for #SecretCollection.
58 */
59
60 /**
61 * SecretCollectionFlags:
62 * @SECRET_COLLECTION_NONE: no flags
63 * @SECRET_COLLECTION_LOAD_ITEMS: items have or should be loaded
64 *
65 * Flags which determine which parts of the #SecretCollection proxy are initialized.
66 */
67
68 /**
69 * SecretCollectionCreateFlags:
70 * @SECRET_COLLECTION_CREATE_NONE: no flags
71 *
72 * Flags for secret_collection_create().
73 */
74
75 /**
76 * SECRET_COLLECTION_DEFAULT:
77 *
78 * An alias to the default collection. This can be passed to secret_password_store()
79 * secret_collection_for_alias().
80 */
81
82 /**
83 * SECRET_COLLECTION_SESSION:
84 *
85 * An alias to the session collection, which will be cleared when the user ends
86 * the session. This can be passed to secret_password_store(),
87 * secret_collection_for_alias() or similar functions.
88 */
89
90 enum {
91 PROP_0,
92 PROP_SERVICE,
93 PROP_FLAGS,
94 PROP_ITEMS,
95 PROP_LABEL,
96 PROP_LOCKED,
97 PROP_CREATED,
98 PROP_MODIFIED
99 };
100
101 struct _SecretCollectionPrivate {
102 /* Doesn't change between construct and finalize */
103 SecretService *service;
104 GCancellable *cancellable;
105 gboolean constructing;
106 SecretCollectionFlags init_flags;
107
108 /* Protected by mutex */
109 GMutex mutex;
110 GHashTable *items;
111 };
112
113 static GInitableIface *secret_collection_initable_parent_iface = NULL;
114
115 static GAsyncInitableIface *secret_collection_async_initable_parent_iface = NULL;
116
117 static void secret_collection_initable_iface (GInitableIface *iface);
118
119 static void secret_collection_async_initable_iface (GAsyncInitableIface *iface);
120
121 G_DEFINE_TYPE_WITH_CODE (SecretCollection, secret_collection, G_TYPE_DBUS_PROXY,
122 G_ADD_PRIVATE (SecretCollection)
123 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_collection_initable_iface);
124 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_collection_async_initable_iface);
125 );
126
127 static GHashTable *
items_table_new(void)128 items_table_new (void)
129 {
130 return g_hash_table_new_full (g_str_hash, g_str_equal,
131 g_free, g_object_unref);
132 }
133
134 static void
secret_collection_init(SecretCollection * self)135 secret_collection_init (SecretCollection *self)
136 {
137 self->pv = secret_collection_get_instance_private (self);
138
139 g_mutex_init (&self->pv->mutex);
140 self->pv->cancellable = g_cancellable_new ();
141 self->pv->constructing = TRUE;
142 }
143
144 static void
on_set_label(GObject * source,GAsyncResult * result,gpointer user_data)145 on_set_label (GObject *source,
146 GAsyncResult *result,
147 gpointer user_data)
148 {
149 SecretCollection *self = SECRET_COLLECTION (user_data);
150 GError *error = NULL;
151
152 secret_collection_set_label_finish (self, result, &error);
153 if (error != NULL) {
154 g_warning ("couldn't set SecretCollection Label: %s", error->message);
155 g_error_free (error);
156 }
157
158 g_object_unref (self);
159 }
160
161 static void
collection_take_service(SecretCollection * self,SecretService * service)162 collection_take_service (SecretCollection *self,
163 SecretService *service)
164 {
165 if (service == NULL)
166 return;
167
168 g_return_if_fail (self->pv->service == NULL);
169
170 self->pv->service = service;
171 g_object_add_weak_pointer (G_OBJECT (self->pv->service),
172 (gpointer *)&self->pv->service);
173
174 /* Yes, we expect that the service will stay around */
175 g_object_unref (service);
176 }
177
178 static void
secret_collection_set_property(GObject * obj,guint prop_id,const GValue * value,GParamSpec * pspec)179 secret_collection_set_property (GObject *obj,
180 guint prop_id,
181 const GValue *value,
182 GParamSpec *pspec)
183 {
184 SecretCollection *self = SECRET_COLLECTION (obj);
185
186 switch (prop_id) {
187 case PROP_SERVICE:
188 collection_take_service (self, g_value_dup_object (value));
189 break;
190 case PROP_FLAGS:
191 self->pv->init_flags = g_value_get_flags (value);
192 break;
193 case PROP_LABEL:
194 secret_collection_set_label (self, g_value_get_string (value),
195 self->pv->cancellable, on_set_label,
196 g_object_ref (self));
197 break;
198 default:
199 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
200 break;
201 }
202 }
203
204 static void
secret_collection_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)205 secret_collection_get_property (GObject *obj,
206 guint prop_id,
207 GValue *value,
208 GParamSpec *pspec)
209 {
210 SecretCollection *self = SECRET_COLLECTION (obj);
211
212 switch (prop_id) {
213 case PROP_SERVICE:
214 g_value_set_object (value, self->pv->service);
215 break;
216 case PROP_FLAGS:
217 g_value_set_flags (value, secret_collection_get_flags (self));
218 break;
219 case PROP_ITEMS:
220 g_value_take_boxed (value, secret_collection_get_items (self));
221 break;
222 case PROP_LABEL:
223 g_value_take_string (value, secret_collection_get_label (self));
224 break;
225 case PROP_LOCKED:
226 g_value_set_boolean (value, secret_collection_get_locked (self));
227 break;
228 case PROP_CREATED:
229 g_value_set_uint64 (value, secret_collection_get_created (self));
230 break;
231 case PROP_MODIFIED:
232 g_value_set_uint64 (value, secret_collection_get_modified (self));
233 break;
234 default:
235 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
236 break;
237 }
238 }
239
240 static void
secret_collection_dispose(GObject * obj)241 secret_collection_dispose (GObject *obj)
242 {
243 SecretCollection *self = SECRET_COLLECTION (obj);
244
245 g_cancellable_cancel (self->pv->cancellable);
246
247 G_OBJECT_CLASS (secret_collection_parent_class)->dispose (obj);
248 }
249
250 static void
secret_collection_finalize(GObject * obj)251 secret_collection_finalize (GObject *obj)
252 {
253 SecretCollection *self = SECRET_COLLECTION (obj);
254
255 if (self->pv->service)
256 g_object_remove_weak_pointer (G_OBJECT (self->pv->service),
257 (gpointer *)&self->pv->service);
258
259 g_mutex_clear (&self->pv->mutex);
260 if (self->pv->items)
261 g_hash_table_destroy (self->pv->items);
262 g_object_unref (self->pv->cancellable);
263
264 G_OBJECT_CLASS (secret_collection_parent_class)->finalize (obj);
265 }
266
267 static void
collection_update_items(SecretCollection * self,GHashTable * items)268 collection_update_items (SecretCollection *self,
269 GHashTable *items)
270 {
271 GHashTable *previous;
272
273 g_hash_table_ref (items);
274
275 g_mutex_lock (&self->pv->mutex);
276 previous = self->pv->items;
277 self->pv->items = items;
278 g_mutex_unlock (&self->pv->mutex);
279
280 if (previous != NULL)
281 g_hash_table_unref (previous);
282
283 g_object_notify (G_OBJECT (self), "items");
284 }
285
286 static void
handle_property_changed(SecretCollection * self,const gchar * property_name,GVariant * value)287 handle_property_changed (SecretCollection *self,
288 const gchar *property_name,
289 GVariant *value)
290 {
291 gboolean perform;
292
293 if (g_str_equal (property_name, "Label")) {
294 g_object_notify (G_OBJECT (self), "label");
295
296 } else if (g_str_equal (property_name, "Locked")) {
297 g_object_notify (G_OBJECT (self), "locked");
298
299 } else if (g_str_equal (property_name, "Created")) {
300 g_object_notify (G_OBJECT (self), "created");
301
302 } else if (g_str_equal (property_name, "Modified")) {
303 g_object_notify (G_OBJECT (self), "modified");
304
305 } else if (g_str_equal (property_name, "Items") && !self->pv->constructing) {
306 g_mutex_lock (&self->pv->mutex);
307 perform = self->pv->items != NULL;
308 g_mutex_unlock (&self->pv->mutex);
309
310 if (perform)
311 secret_collection_load_items (self, self->pv->cancellable, NULL, NULL);
312 }
313 }
314
315 static void
secret_collection_properties_changed(GDBusProxy * proxy,GVariant * changed_properties,const gchar * const * invalidated_properties)316 secret_collection_properties_changed (GDBusProxy *proxy,
317 GVariant *changed_properties,
318 const gchar* const *invalidated_properties)
319 {
320 SecretCollection *self = SECRET_COLLECTION (proxy);
321 gchar *property_name;
322 GVariantIter iter;
323 GVariant *value;
324
325 g_object_freeze_notify (G_OBJECT (self));
326
327 g_variant_iter_init (&iter, changed_properties);
328 while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value))
329 handle_property_changed (self, property_name, value);
330
331 g_object_thaw_notify (G_OBJECT (self));
332 }
333
334 static void
secret_collection_signal(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters)335 secret_collection_signal (GDBusProxy *proxy,
336 const gchar *sender_name,
337 const gchar *signal_name,
338 GVariant *parameters)
339 {
340 SecretCollection *self = SECRET_COLLECTION (proxy);
341 SecretItem *item;
342 const gchar *item_path;
343 GVariantBuilder builder;
344 gboolean found = FALSE;
345 GVariantIter iter;
346 GVariant *value;
347 GVariant *paths;
348 GVariant *path;
349
350 /*
351 * Remember that these signals come from a time before PropertiesChanged.
352 * We support them because they're in the spec, and ksecretservice uses them.
353 */
354
355 paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items");
356
357 /* A new collection was added, add it to the Collections property */
358 if (g_str_equal (signal_name, SECRET_SIGNAL_ITEM_CREATED)) {
359 g_variant_get (parameters, "(@o)", &value);
360 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
361 g_variant_iter_init (&iter, paths);
362 while ((path = g_variant_iter_next_value (&iter)) != NULL) {
363 if (g_variant_equal (path, value)) {
364 found = TRUE;
365 break;
366 }
367 g_variant_builder_add_value (&builder, path);
368 g_variant_unref (path);
369 }
370 if (!found) {
371 g_variant_builder_add_value (&builder, value);
372 handle_property_changed (self, "Items", g_variant_builder_end (&builder));
373 }
374 g_variant_builder_clear (&builder);
375 g_variant_unref (value);
376
377 /* A collection was deleted, remove it from the Collections property */
378 } else if (g_str_equal (signal_name, SECRET_SIGNAL_ITEM_DELETED)) {
379 g_variant_get (parameters, "(@o)", &value);
380 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
381 g_variant_iter_init (&iter, paths);
382 while ((path = g_variant_iter_next_value (&iter)) != NULL) {
383 if (g_variant_equal (path, value))
384 found = TRUE;
385 else
386 g_variant_builder_add_value (&builder, path);
387 g_variant_unref (path);
388 }
389 if (found)
390 handle_property_changed (self, "Items", g_variant_builder_end (&builder));
391 g_variant_unref (value);
392
393 /* The collection changed, update it */
394 } else if (g_str_equal (signal_name, SECRET_SIGNAL_ITEM_CHANGED)) {
395 g_variant_get (parameters, "(&o)", &item_path);
396
397 g_mutex_lock (&self->pv->mutex);
398
399 if (self->pv->items)
400 item = g_hash_table_lookup (self->pv->items, item_path);
401 else
402 item = NULL;
403 if (item)
404 g_object_ref (item);
405
406 g_mutex_unlock (&self->pv->mutex);
407
408 if (item) {
409 secret_item_refresh (item);
410 g_object_unref (item);
411 }
412 }
413
414 g_variant_unref (paths);
415 }
416
417 static void
secret_collection_class_init(SecretCollectionClass * klass)418 secret_collection_class_init (SecretCollectionClass *klass)
419 {
420 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
421 GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass);
422
423 gobject_class->get_property = secret_collection_get_property;
424 gobject_class->set_property = secret_collection_set_property;
425 gobject_class->dispose = secret_collection_dispose;
426 gobject_class->finalize = secret_collection_finalize;
427
428 proxy_class->g_properties_changed = secret_collection_properties_changed;
429 proxy_class->g_signal = secret_collection_signal;
430
431 /**
432 * SecretCollection:service:
433 *
434 * The #SecretService object that this collection is associated with and
435 * uses to interact with the actual D-Bus Secret Service.
436 */
437 g_object_class_install_property (gobject_class, PROP_SERVICE,
438 g_param_spec_object ("service", "Service", "Secret Service",
439 SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
440
441 /**
442 * SecretCollection:flags:
443 *
444 * A set of flags describing which parts of the secret collection have
445 * been initialized.
446 */
447 g_object_class_install_property (gobject_class, PROP_FLAGS,
448 g_param_spec_flags ("flags", "Flags", "Collection flags",
449 secret_collection_flags_get_type (), SECRET_COLLECTION_NONE,
450 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
451
452 /**
453 * SecretCollection:items:
454 *
455 * A list of #SecretItem objects representing the items that are in
456 * this collection. This list will be empty if the collection is locked.
457 */
458 g_object_class_install_property (gobject_class, PROP_ITEMS,
459 g_param_spec_boxed ("items", "Items", "Items in collection",
460 _secret_list_get_type (), G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
461
462 /**
463 * SecretCollection:label:
464 *
465 * The human readable label for the collection.
466 *
467 * Setting this property will result in the label of the collection being
468 * set asynchronously. To properly track the changing of the label use the
469 * secret_collection_set_label() function.
470 */
471 g_object_class_install_property (gobject_class, PROP_LABEL,
472 g_param_spec_string ("label", "Label", "Item label",
473 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
474
475 /**
476 * SecretCollection:locked:
477 *
478 * Whether the collection is locked or not.
479 *
480 * To lock or unlock a collection use the secret_service_lock() or
481 * secret_service_unlock() functions.
482 */
483 g_object_class_install_property (gobject_class, PROP_LOCKED,
484 g_param_spec_boolean ("locked", "Locked", "Item locked",
485 TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
486
487 /**
488 * SecretCollection:created:
489 *
490 * The date and time (in seconds since the UNIX epoch) that this
491 * collection was created.
492 */
493 g_object_class_install_property (gobject_class, PROP_CREATED,
494 g_param_spec_uint64 ("created", "Created", "Item creation date",
495 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
496
497 /**
498 * SecretCollection:modified:
499 *
500 * The date and time (in seconds since the UNIX epoch) that this
501 * collection was last modified.
502 */
503 g_object_class_install_property (gobject_class, PROP_MODIFIED,
504 g_param_spec_uint64 ("modified", "Modified", "Item modified date",
505 0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
506 }
507
508 static gboolean
collection_ensure_for_flags_sync(SecretCollection * self,SecretCollectionFlags flags,GCancellable * cancellable,GError ** error)509 collection_ensure_for_flags_sync (SecretCollection *self,
510 SecretCollectionFlags flags,
511 GCancellable *cancellable,
512 GError **error)
513 {
514 SecretCollectionFlags want_flags;
515
516 want_flags = flags & ~secret_collection_get_flags (self);
517
518 if (want_flags & SECRET_COLLECTION_LOAD_ITEMS) {
519 if (!secret_collection_load_items_sync (self, cancellable, error))
520 return FALSE;
521 }
522
523 return TRUE;
524 }
525
526 static gboolean
secret_collection_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)527 secret_collection_initable_init (GInitable *initable,
528 GCancellable *cancellable,
529 GError **error)
530 {
531 SecretCollection *self;
532 SecretService *service;
533 GDBusProxy *proxy;
534
535 if (!secret_collection_initable_parent_iface->init (initable, cancellable, error))
536 return FALSE;
537
538 proxy = G_DBUS_PROXY (initable);
539
540 if (!_secret_util_have_cached_properties (proxy)) {
541 g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
542 "No such secret collection at path: %s",
543 g_dbus_proxy_get_object_path (proxy));
544 return FALSE;
545 }
546
547 self = SECRET_COLLECTION (initable);
548
549 if (self->pv->service == NULL) {
550 service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error);
551 if (service == NULL)
552 return FALSE;
553 else
554 collection_take_service (self, service);
555 }
556
557 if (!collection_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error))
558 return FALSE;
559
560 self->pv->constructing = FALSE;
561 return TRUE;
562 }
563
564 static void
secret_collection_initable_iface(GInitableIface * iface)565 secret_collection_initable_iface (GInitableIface *iface)
566 {
567 secret_collection_initable_parent_iface = g_type_interface_peek_parent (iface);
568
569 iface->init = secret_collection_initable_init;
570 }
571
572 typedef struct {
573 GCancellable *cancellable;
574 } InitClosure;
575
576 static void
init_closure_free(gpointer data)577 init_closure_free (gpointer data)
578 {
579 InitClosure *closure = data;
580 g_clear_object (&closure->cancellable);
581 g_slice_free (InitClosure, closure);
582 }
583
584 static void
on_ensure_items(GObject * source,GAsyncResult * result,gpointer user_data)585 on_ensure_items (GObject *source,
586 GAsyncResult *result,
587 gpointer user_data)
588 {
589 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
590 SecretCollection *self = SECRET_COLLECTION (source);
591 GError *error = NULL;
592
593 if (!secret_collection_load_items_finish (self, result, &error))
594 g_simple_async_result_take_error (res, error);
595
596 g_simple_async_result_complete (res);
597 g_object_unref (res);
598 }
599
600 static void
collection_ensure_for_flags_async(SecretCollection * self,SecretCollectionFlags flags,GCancellable * cancellable,GSimpleAsyncResult * async)601 collection_ensure_for_flags_async (SecretCollection *self,
602 SecretCollectionFlags flags,
603 GCancellable *cancellable,
604 GSimpleAsyncResult *async)
605 {
606 SecretCollectionFlags want_flags;
607
608 want_flags = flags & ~secret_collection_get_flags (self);
609
610 if (want_flags & SECRET_COLLECTION_LOAD_ITEMS) {
611 secret_collection_load_items (self, cancellable,
612 on_ensure_items, g_object_ref (async));
613
614 } else {
615 g_simple_async_result_complete (async);
616 }
617 }
618
619 static void
on_init_service(GObject * source,GAsyncResult * result,gpointer user_data)620 on_init_service (GObject *source,
621 GAsyncResult *result,
622 gpointer user_data)
623 {
624 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
625 SecretCollection *self = SECRET_COLLECTION (g_async_result_get_source_object (user_data));
626 InitClosure *init = g_simple_async_result_get_op_res_gpointer (async);
627 SecretService *service;
628 GError *error = NULL;
629
630 service = secret_service_get_finish (result, &error);
631 if (error == NULL) {
632 collection_take_service (self, service);
633 collection_ensure_for_flags_async (self, self->pv->init_flags,
634 init->cancellable, async);
635
636 } else {
637 g_simple_async_result_take_error (async, error);
638 g_simple_async_result_complete (async);
639 }
640
641 g_object_unref (self);
642 g_object_unref (async);
643 }
644
645 static void
on_init_base(GObject * source,GAsyncResult * result,gpointer user_data)646 on_init_base (GObject *source,
647 GAsyncResult *result,
648 gpointer user_data)
649 {
650 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
651 SecretCollection *self = SECRET_COLLECTION (source);
652 InitClosure *init = g_simple_async_result_get_op_res_gpointer (res);
653 GDBusProxy *proxy = G_DBUS_PROXY (self);
654 GError *error = NULL;
655
656 if (!secret_collection_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self),
657 result, &error)) {
658 g_simple_async_result_take_error (res, error);
659 g_simple_async_result_complete (res);
660
661 } else if (!_secret_util_have_cached_properties (proxy)) {
662 g_simple_async_result_set_error (res, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
663 "No such secret collection at path: %s",
664 g_dbus_proxy_get_object_path (proxy));
665 g_simple_async_result_complete (res);
666
667 } else if (self->pv->service == NULL) {
668 secret_service_get (SECRET_SERVICE_NONE, init->cancellable,
669 on_init_service, g_object_ref (res));
670
671 } else {
672 collection_ensure_for_flags_async (self, self->pv->init_flags,
673 init->cancellable, res);
674 }
675
676 g_object_unref (res);
677 }
678
679 static void
secret_collection_async_initable_init_async(GAsyncInitable * initable,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)680 secret_collection_async_initable_init_async (GAsyncInitable *initable,
681 int io_priority,
682 GCancellable *cancellable,
683 GAsyncReadyCallback callback,
684 gpointer user_data)
685 {
686 GSimpleAsyncResult *res;
687 InitClosure *closure;
688
689 res = g_simple_async_result_new (G_OBJECT (initable), callback, user_data,
690 secret_collection_async_initable_init_async);
691 closure = g_slice_new0 (InitClosure);
692 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
693 g_simple_async_result_set_op_res_gpointer (res, closure, init_closure_free);
694
695 secret_collection_async_initable_parent_iface->init_async (initable, io_priority,
696 cancellable,
697 on_init_base,
698 g_object_ref (res));
699
700 g_object_unref (res);
701 }
702
703 static gboolean
secret_collection_async_initable_init_finish(GAsyncInitable * initable,GAsyncResult * result,GError ** error)704 secret_collection_async_initable_init_finish (GAsyncInitable *initable,
705 GAsyncResult *result,
706 GError **error)
707 {
708 SecretCollection *self = SECRET_COLLECTION (initable);
709
710 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (initable),
711 secret_collection_async_initable_init_async), FALSE);
712
713 if (_secret_util_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
714 return FALSE;
715
716 self->pv->constructing = FALSE;
717 return TRUE;
718 }
719
720 static void
secret_collection_async_initable_iface(GAsyncInitableIface * iface)721 secret_collection_async_initable_iface (GAsyncInitableIface *iface)
722 {
723 secret_collection_async_initable_parent_iface = g_type_interface_peek_parent (iface);
724
725 iface->init_async = secret_collection_async_initable_init_async;
726 iface->init_finish = secret_collection_async_initable_init_finish;
727 }
728
729 typedef struct {
730 GCancellable *cancellable;
731 GHashTable *items;
732 gint items_loading;
733 } ItemsClosure;
734
735 static void
items_closure_free(gpointer data)736 items_closure_free (gpointer data)
737 {
738 ItemsClosure *closure = data;
739 g_clear_object (&closure->cancellable);
740 g_hash_table_unref (closure->items);
741 g_slice_free (ItemsClosure, closure);
742 }
743
744 static void
on_load_item(GObject * source,GAsyncResult * result,gpointer user_data)745 on_load_item (GObject *source,
746 GAsyncResult *result,
747 gpointer user_data)
748 {
749 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
750 ItemsClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
751 SecretCollection *self = SECRET_COLLECTION (g_async_result_get_source_object (user_data));
752 const gchar *path;
753 GError *error = NULL;
754 SecretItem *item;
755
756 closure->items_loading--;
757
758 item = secret_item_new_for_dbus_path_finish (result, &error);
759
760 if (error != NULL)
761 g_simple_async_result_take_error (res, error);
762
763 if (item != NULL) {
764 path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item));
765 g_hash_table_insert (closure->items, g_strdup (path), item);
766 }
767
768 if (closure->items_loading == 0) {
769 collection_update_items (self, closure->items);
770 g_simple_async_result_complete_in_idle (res);
771 }
772
773 g_object_unref (self);
774 g_object_unref (res);
775 }
776
777 /**
778 * secret_collection_load_items:
779 * @self: the secret collection
780 * @cancellable: optional cancellation object
781 * @callback: called when the operation completes
782 * @user_data: data to be passed to the callback
783 *
784 * Ensure that the #SecretCollection proxy has loaded all the items present
785 * in the Secret Service. This affects the result of
786 * secret_collection_get_items().
787 *
788 * For collections returned from secret_service_get_collections() the items
789 * will have already been loaded.
790 *
791 * This method will return immediately and complete asynchronously.
792 */
793 void
secret_collection_load_items(SecretCollection * self,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)794 secret_collection_load_items (SecretCollection *self,
795 GCancellable *cancellable,
796 GAsyncReadyCallback callback,
797 gpointer user_data)
798 {
799 ItemsClosure *closure;
800 SecretItem *item;
801 GSimpleAsyncResult *res;
802 const gchar *path;
803 GVariant *paths;
804 GVariantIter iter;
805
806 g_return_if_fail (SECRET_IS_COLLECTION (self));
807 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
808
809 paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items");
810 g_return_if_fail (paths != NULL);
811
812 res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
813 secret_collection_load_items);
814 closure = g_slice_new0 (ItemsClosure);
815 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
816 closure->items = items_table_new ();
817 g_simple_async_result_set_op_res_gpointer (res, closure, items_closure_free);
818
819 g_variant_iter_init (&iter, paths);
820 while (g_variant_iter_loop (&iter, "&o", &path)) {
821 item = _secret_collection_find_item_instance (self, path);
822
823 /* No such collection yet create a new one */
824 if (item == NULL) {
825 secret_item_new_for_dbus_path (self->pv->service, path, SECRET_ITEM_NONE,
826 cancellable, on_load_item, g_object_ref (res));
827 closure->items_loading++;
828
829 } else {
830 g_hash_table_insert (closure->items, g_strdup (path), item);
831 }
832 }
833
834 if (closure->items_loading == 0) {
835 collection_update_items (self, closure->items);
836 g_simple_async_result_complete_in_idle (res);
837 }
838
839 g_variant_unref (paths);
840 g_object_unref (res);
841 }
842
843 /**
844 * secret_collection_load_items_finish:
845 * @self: the secret collection
846 * @result: the asynchronous result passed to the callback
847 * @error: location to place an error on failure
848 *
849 * Complete an asynchronous operation to ensure that the #SecretCollection proxy
850 * has loaded all the items present in the Secret Service.
851 *
852 * Returns: whether the load was successful or not
853 */
854 gboolean
secret_collection_load_items_finish(SecretCollection * self,GAsyncResult * result,GError ** error)855 secret_collection_load_items_finish (SecretCollection *self,
856 GAsyncResult *result,
857 GError **error)
858 {
859 g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE);
860 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
861 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
862 secret_collection_load_items), FALSE);
863
864 if (_secret_util_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
865 return FALSE;
866
867 return TRUE;
868 }
869
870 /**
871 * secret_collection_load_items_sync:
872 * @self: the secret collection
873 * @cancellable: optional cancellation object
874 * @error: location to place an error on failure
875 *
876 * Ensure that the #SecretCollection proxy has loaded all the items present
877 * in the Secret Service. This affects the result of
878 * secret_collection_get_items().
879 *
880 * For collections returned from secret_service_get_collections() the items
881 * will have already been loaded.
882 *
883 * This method may block indefinitely and should not be used in user interface
884 * threads.
885 *
886 * Returns: whether the load was successful or not
887 */
888 gboolean
secret_collection_load_items_sync(SecretCollection * self,GCancellable * cancellable,GError ** error)889 secret_collection_load_items_sync (SecretCollection *self,
890 GCancellable *cancellable,
891 GError **error)
892 {
893 SecretItem *item;
894 GHashTable *items;
895 GVariant *paths;
896 GVariantIter iter;
897 const gchar *path;
898 gboolean ret = TRUE;
899
900 g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE);
901 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
902 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
903
904 paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items");
905 g_return_val_if_fail (paths != NULL, FALSE);
906
907 items = items_table_new ();
908
909 g_variant_iter_init (&iter, paths);
910 while (g_variant_iter_next (&iter, "&o", &path)) {
911 item = _secret_collection_find_item_instance (self, path);
912
913 /* No such collection yet create a new one */
914 if (item == NULL) {
915 item = secret_item_new_for_dbus_path_sync (self->pv->service, path,
916 SECRET_ITEM_NONE,
917 cancellable, error);
918 if (item == NULL) {
919 ret = FALSE;
920 break;
921 }
922 }
923
924 g_hash_table_insert (items, g_strdup (path), item);
925 }
926
927 if (ret)
928 collection_update_items (self, items);
929
930 g_hash_table_unref (items);
931 g_variant_unref (paths);
932 return ret;
933 }
934
935 /**
936 * secret_collection_refresh:
937 * @self: the collection
938 *
939 * Refresh the properties on this collection. This fires off a request to
940 * refresh, and the properties will be updated later.
941 *
942 * Calling this method is not normally necessary, as the secret service
943 * will notify the client when properties change.
944 */
945 void
secret_collection_refresh(SecretCollection * self)946 secret_collection_refresh (SecretCollection *self)
947 {
948 g_return_if_fail (SECRET_IS_COLLECTION (self));
949
950 _secret_util_get_properties (G_DBUS_PROXY (self),
951 secret_collection_refresh,
952 self->pv->cancellable, NULL, NULL);
953 }
954
955 typedef struct {
956 GCancellable *cancellable;
957 SecretCollection *collection;
958 GHashTable *properties;
959 gchar *alias;
960 SecretCollectionCreateFlags flags;
961 } CreateClosure;
962
963 static void
create_closure_free(gpointer data)964 create_closure_free (gpointer data)
965 {
966 CreateClosure *closure = data;
967 g_clear_object (&closure->cancellable);
968 g_clear_object (&closure->collection);
969 g_hash_table_unref (closure->properties);
970 g_free (closure->alias);
971 g_slice_free (CreateClosure, closure);
972 }
973
974 static void
on_create_collection(GObject * source,GAsyncResult * result,gpointer user_data)975 on_create_collection (GObject *source,
976 GAsyncResult *result,
977 gpointer user_data)
978 {
979 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
980 CreateClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
981 GError *error = NULL;
982
983 closure->collection = secret_collection_new_for_dbus_path_finish (result, &error);
984 if (error != NULL)
985 g_simple_async_result_take_error (res, error);
986
987 g_simple_async_result_complete (res);
988 g_object_unref (res);
989 }
990
991 static void
on_create_path(GObject * source,GAsyncResult * result,gpointer user_data)992 on_create_path (GObject *source,
993 GAsyncResult *result,
994 gpointer user_data)
995 {
996 GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
997 CreateClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
998 SecretService *service = SECRET_SERVICE (source);
999 GError *error = NULL;
1000 gchar *path;
1001
1002 path = secret_service_create_collection_dbus_path_finish (service, result, &error);
1003 if (error == NULL) {
1004 secret_collection_new_for_dbus_path (service, path, SECRET_COLLECTION_LOAD_ITEMS,
1005 closure->cancellable,
1006 on_create_collection, g_object_ref (res));
1007 } else {
1008 g_simple_async_result_take_error (res, error);
1009 g_simple_async_result_complete (res);
1010 }
1011
1012 g_object_unref (res);
1013 g_free (path);
1014 }
1015
1016 static void
on_create_service(GObject * source,GAsyncResult * result,gpointer user_data)1017 on_create_service (GObject *source,
1018 GAsyncResult *result,
1019 gpointer user_data)
1020 {
1021 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1022 CreateClosure *create = g_simple_async_result_get_op_res_gpointer (async);
1023 GError *error = NULL;
1024 SecretService *service;
1025
1026 service = secret_service_get_finish (result, &error);
1027 if (error == NULL) {
1028 secret_service_create_collection_dbus_path (service, create->properties,
1029 create->alias, create->flags,
1030 create->cancellable,
1031 on_create_path, g_object_ref (async));
1032 g_object_unref (service);
1033
1034 } else {
1035 g_simple_async_result_take_error (async, error);
1036 g_simple_async_result_complete (async);
1037 }
1038
1039 g_object_unref (async);
1040 }
1041
1042 GHashTable *
_secret_collection_properties_new(const gchar * label)1043 _secret_collection_properties_new (const gchar *label)
1044 {
1045 GHashTable *properties;
1046 GVariant *value;
1047
1048 properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
1049 (GDestroyNotify)g_variant_unref);
1050 value = g_variant_new_string (label);
1051 g_hash_table_insert (properties,
1052 SECRET_COLLECTION_INTERFACE ".Label",
1053 g_variant_ref_sink (value));
1054
1055 return properties;
1056 }
1057
1058 /**
1059 * secret_collection_create:
1060 * @service: (allow-none): a secret service object
1061 * @label: label for the new collection
1062 * @alias: (allow-none): alias to assign to the collection
1063 * @flags: currently unused
1064 * @cancellable: optional cancellation object
1065 * @callback: called when the operation completes
1066 * @user_data: data to pass to the callback
1067 *
1068 * Create a new collection in the secret service.
1069 *
1070 * This method returns immediately and completes asynchronously. The secret
1071 * service may prompt the user. secret_service_prompt() will be used to handle
1072 * any prompts that are required.
1073 *
1074 * An @alias is a well-known tag for a collection, such as 'default' (ie: the
1075 * default collection to store items in). This allows other applications to
1076 * easily identify and share a collection. If you specify an @alias, and a
1077 * collection with that alias already exists, then a new collection will not
1078 * be created. The previous one will be returned instead.
1079 *
1080 * If @service is NULL, then secret_service_get() will be called to get
1081 * the default #SecretService proxy.
1082 *
1083 */
1084 void
secret_collection_create(SecretService * service,const gchar * label,const gchar * alias,SecretCollectionCreateFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1085 secret_collection_create (SecretService *service,
1086 const gchar *label,
1087 const gchar *alias,
1088 SecretCollectionCreateFlags flags,
1089 GCancellable *cancellable,
1090 GAsyncReadyCallback callback,
1091 gpointer user_data)
1092 {
1093 GSimpleAsyncResult *res;
1094 CreateClosure *closure;
1095
1096 g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
1097 g_return_if_fail (label != NULL);
1098 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1099
1100 res = g_simple_async_result_new (NULL, callback, user_data,
1101 secret_collection_create);
1102 closure = g_slice_new0 (CreateClosure);
1103 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1104 closure->properties = _secret_collection_properties_new (label);
1105 closure->alias = g_strdup (alias);
1106 closure->flags = flags;
1107 g_simple_async_result_set_op_res_gpointer (res, closure, create_closure_free);
1108
1109 if (service == NULL) {
1110 secret_service_get (SECRET_SERVICE_NONE, cancellable,
1111 on_create_service, g_object_ref (res));
1112
1113 } else {
1114 secret_service_create_collection_dbus_path (service, closure->properties,
1115 closure->alias, closure->flags,
1116 closure->cancellable,
1117 on_create_path, g_object_ref (res));
1118 }
1119
1120 g_object_unref (res);
1121 }
1122
1123 /**
1124 * secret_collection_create_finish:
1125 * @result: the asynchronous result passed to the callback
1126 * @error: location to place an error on failure
1127 *
1128 * Finish operation to create a new collection in the secret service.
1129 *
1130 * Returns: (transfer full): the new collection, which should be unreferenced
1131 * with g_object_unref()
1132 */
1133 SecretCollection *
secret_collection_create_finish(GAsyncResult * result,GError ** error)1134 secret_collection_create_finish (GAsyncResult *result,
1135 GError **error)
1136 {
1137 GSimpleAsyncResult *res;
1138 CreateClosure *closure;
1139
1140 g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
1141 secret_collection_create), NULL);
1142 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1143
1144 res = G_SIMPLE_ASYNC_RESULT (result);
1145
1146 if (_secret_util_propagate_error (res, error))
1147 return NULL;
1148
1149 closure = g_simple_async_result_get_op_res_gpointer (res);
1150 if (closure->collection == NULL)
1151 return NULL;
1152
1153 return g_object_ref (closure->collection);
1154 }
1155
1156 /**
1157 * secret_collection_create_sync:
1158 * @service: (allow-none): a secret service object
1159 * @label: label for the new collection
1160 * @alias: (allow-none): alias to assign to the collection
1161 * @flags: currently unused
1162 * @cancellable: optional cancellation object
1163 * @error: location to place an error on failure
1164 *
1165 * Create a new collection in the secret service.
1166 *
1167 * This method may block indefinitely and should not be used in user interface
1168 * threads. The secret service may prompt the user. secret_service_prompt()
1169 * will be used to handle any prompts that are required.
1170 *
1171 * An @alias is a well-known tag for a collection, such as 'default' (ie: the
1172 * default collection to store items in). This allows other applications to
1173 * easily identify and share a collection. If you specify an @alias, and a
1174 * collection with that alias already exists, then a new collection will not
1175 * be created. The previous one will be returned instead.
1176 *
1177 * If @service is NULL, then secret_service_get_sync() will be called to get
1178 * the default #SecretService proxy.
1179 *
1180 * Returns: (transfer full): the new collection, which should be unreferenced
1181 * with g_object_unref()
1182 */
1183 SecretCollection *
secret_collection_create_sync(SecretService * service,const gchar * label,const gchar * alias,SecretCollectionCreateFlags flags,GCancellable * cancellable,GError ** error)1184 secret_collection_create_sync (SecretService *service,
1185 const gchar *label,
1186 const gchar *alias,
1187 SecretCollectionCreateFlags flags,
1188 GCancellable *cancellable,
1189 GError **error)
1190 {
1191 SecretCollection *collection;
1192 GHashTable *properties;
1193 gchar *path;
1194
1195 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
1196 g_return_val_if_fail (label != NULL, NULL);
1197 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1198 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1199
1200 if (service == NULL) {
1201 service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error);
1202 if (service == NULL)
1203 return NULL;
1204 } else {
1205 g_object_ref (service);
1206 }
1207
1208 properties = _secret_collection_properties_new (label);
1209
1210 path = secret_service_create_collection_dbus_path_sync (service, properties, alias,
1211 flags, cancellable, error);
1212
1213 g_hash_table_unref (properties);
1214
1215 if (path == NULL) {
1216 g_object_unref (service);
1217 return NULL;
1218 }
1219
1220 collection = secret_collection_new_for_dbus_path_sync (service, path,
1221 SECRET_COLLECTION_LOAD_ITEMS,
1222 cancellable, error);
1223
1224 g_object_unref (service);
1225 g_free (path);
1226
1227 return collection;
1228 }
1229
1230 typedef struct {
1231 SecretCollection *collection;
1232 GCancellable *cancellable;
1233 GHashTable *items;
1234 gchar **paths;
1235 guint loading;
1236 SecretSearchFlags flags;
1237 } SearchClosure;
1238
1239 static void
search_closure_free(gpointer data)1240 search_closure_free (gpointer data)
1241 {
1242 SearchClosure *closure = data;
1243 g_object_unref (closure->collection);
1244 g_clear_object (&closure->cancellable);
1245 g_hash_table_unref (closure->items);
1246 g_strfreev (closure->paths);
1247 g_slice_free (SearchClosure, closure);
1248 }
1249
1250 static void
search_closure_take_item(SearchClosure * closure,SecretItem * item)1251 search_closure_take_item (SearchClosure *closure,
1252 SecretItem *item)
1253 {
1254 const gchar *path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item));
1255 g_hash_table_insert (closure->items, (gpointer)path, item);
1256 }
1257
1258 static void
on_search_secrets(GObject * source,GAsyncResult * result,gpointer user_data)1259 on_search_secrets (GObject *source,
1260 GAsyncResult *result,
1261 gpointer user_data)
1262 {
1263 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1264
1265 /* Note that we ignore any unlock failure */
1266 secret_item_load_secrets_finish (result, NULL);
1267
1268 g_simple_async_result_complete (async);
1269 g_object_unref (async);
1270 }
1271
1272 static void
on_search_unlocked(GObject * source,GAsyncResult * result,gpointer user_data)1273 on_search_unlocked (GObject *source,
1274 GAsyncResult *result,
1275 gpointer user_data)
1276 {
1277 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1278 SearchClosure *search = g_simple_async_result_get_op_res_gpointer (async);
1279 GList *items;
1280
1281 /* Note that we ignore any unlock failure */
1282 secret_service_unlock_finish (SECRET_SERVICE (source), result, NULL, NULL);
1283
1284 /* If loading secrets ... locked items automatically ignored */
1285 if (search->flags & SECRET_SEARCH_LOAD_SECRETS) {
1286 items = g_hash_table_get_values (search->items);
1287 secret_item_load_secrets (items, search->cancellable,
1288 on_search_secrets, g_object_ref (async));
1289 g_list_free (items);
1290
1291 /* No additional options, just complete */
1292 } else {
1293 g_simple_async_result_complete (async);
1294 }
1295
1296 g_object_unref (async);
1297 }
1298
1299 static void
secret_search_unlock_load_or_complete(GSimpleAsyncResult * async,SearchClosure * search)1300 secret_search_unlock_load_or_complete (GSimpleAsyncResult *async,
1301 SearchClosure *search)
1302 {
1303 GList *items;
1304
1305 /* If unlocking then unlock all the locked items */
1306 if (search->flags & SECRET_SEARCH_UNLOCK) {
1307 items = g_hash_table_get_values (search->items);
1308 secret_service_unlock (secret_collection_get_service (search->collection),
1309 items, search->cancellable,
1310 on_search_unlocked, g_object_ref (async));
1311 g_list_free (items);
1312
1313 /* If loading secrets ... locked items automatically ignored */
1314 } else if (search->flags & SECRET_SEARCH_LOAD_SECRETS) {
1315 items = g_hash_table_get_values (search->items);
1316 secret_item_load_secrets (items, search->cancellable,
1317 on_search_secrets, g_object_ref (async));
1318 g_list_free (items);
1319
1320 /* No additional options, just complete */
1321 } else {
1322 g_simple_async_result_complete (async);
1323 }
1324 }
1325
1326 static void
on_search_loaded(GObject * source,GAsyncResult * result,gpointer user_data)1327 on_search_loaded (GObject *source,
1328 GAsyncResult *result,
1329 gpointer user_data)
1330 {
1331 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1332 SearchClosure *search = g_simple_async_result_get_op_res_gpointer (async);
1333 GError *error = NULL;
1334 SecretItem *item;
1335
1336 search->loading--;
1337
1338 item = secret_item_new_for_dbus_path_finish (result, &error);
1339 if (error != NULL)
1340 g_simple_async_result_take_error (async, error);
1341
1342 if (item != NULL)
1343 search_closure_take_item (search, item);
1344
1345 /* We're done loading, lets go to the next step */
1346 if (search->loading == 0)
1347 secret_search_unlock_load_or_complete (async, search);
1348
1349 g_object_unref (async);
1350 }
1351
1352 static void
on_search_paths(GObject * source,GAsyncResult * result,gpointer user_data)1353 on_search_paths (GObject *source,
1354 GAsyncResult *result,
1355 gpointer user_data)
1356 {
1357 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1358 SearchClosure *search = g_simple_async_result_get_op_res_gpointer (async);
1359 SecretCollection *self = search->collection;
1360 SecretService *service = secret_collection_get_service (self);
1361 GError *error = NULL;
1362 SecretItem *item;
1363 gint want = 1;
1364 gint i;
1365
1366 search->paths = secret_collection_search_for_dbus_paths_finish (self, result, &error);
1367 if (error == NULL) {
1368 want = 1;
1369 if (search->flags & SECRET_SEARCH_ALL)
1370 want = G_MAXINT;
1371
1372 for (i = 0; i < want && search->paths[i] != NULL; i++) {
1373 item = _secret_collection_find_item_instance (self, search->paths[i]);
1374 if (item == NULL) {
1375 secret_item_new_for_dbus_path (service, search->paths[i], SECRET_ITEM_NONE,
1376 search->cancellable, on_search_loaded,
1377 g_object_ref (async));
1378 search->loading++;
1379 } else {
1380 search_closure_take_item (search, item);
1381 }
1382
1383 }
1384
1385 /* No items loading, complete operation now */
1386 if (search->loading == 0)
1387 secret_search_unlock_load_or_complete (async, search);
1388
1389 } else {
1390 g_simple_async_result_take_error (async, error);
1391 g_simple_async_result_complete (async);
1392 }
1393
1394 g_object_unref (async);
1395 }
1396
1397 /**
1398 * secret_collection_search:
1399 * @self: a secret collection
1400 * @schema: (allow-none): the schema for the attributes
1401 * @attributes: (element-type utf8 utf8): search for items matching these attributes
1402 * @flags: search option flags
1403 * @cancellable: optional cancellation object
1404 * @callback: called when the operation completes
1405 * @user_data: data to pass to the callback
1406 *
1407 * Search for items matching the @attributes in the @collection.
1408 * The @attributes should be a table of string keys and string values.
1409 *
1410 * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the
1411 * search will be returned. Otherwise only the first item will be returned.
1412 * This is almost always the unlocked item that was most recently stored.
1413 *
1414 * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked
1415 * if necessary. In either case, locked and unlocked items will match the
1416 * search and be returned. If the unlock fails, the search does not fail.
1417 *
1418 * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items will have
1419 * their secret values loaded and available via secret_item_get_secret().
1420 *
1421 * This function returns immediately and completes asynchronously.
1422 */
1423 void
secret_collection_search(SecretCollection * self,const SecretSchema * schema,GHashTable * attributes,SecretSearchFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1424 secret_collection_search (SecretCollection *self,
1425 const SecretSchema *schema,
1426 GHashTable *attributes,
1427 SecretSearchFlags flags,
1428 GCancellable *cancellable,
1429 GAsyncReadyCallback callback,
1430 gpointer user_data)
1431 {
1432 GSimpleAsyncResult *async;
1433 SearchClosure *search;
1434
1435 g_return_if_fail (SECRET_IS_COLLECTION (self));
1436 g_return_if_fail (attributes != NULL);
1437 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1438
1439 /* Warnings raised already */
1440 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1441 return;
1442
1443 async = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1444 secret_collection_search);
1445 search = g_slice_new0 (SearchClosure);
1446 search->collection = g_object_ref (self);
1447 search->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
1448 search->items = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
1449 search->flags = flags;
1450 g_simple_async_result_set_op_res_gpointer (async, search, search_closure_free);
1451
1452 secret_collection_search_for_dbus_paths (self, schema, attributes,
1453 cancellable, on_search_paths,
1454 g_object_ref (async));
1455
1456 g_object_unref (async);
1457 }
1458
1459 /**
1460 * secret_collection_search_finish:
1461 * @self: the secret collection
1462 * @result: asynchronous result passed to callback
1463 * @error: location to place error on failure
1464 *
1465 * Complete asynchronous operation to search for items in a collection.
1466 *
1467 * Returns: (transfer full) (element-type Secret.Item):
1468 * a list of items that matched the search
1469 */
1470 GList *
secret_collection_search_finish(SecretCollection * self,GAsyncResult * result,GError ** error)1471 secret_collection_search_finish (SecretCollection *self,
1472 GAsyncResult *result,
1473 GError **error)
1474 {
1475 GSimpleAsyncResult *async;
1476 SearchClosure *search;
1477 GList *items = NULL;
1478 SecretItem *item;
1479 guint i;
1480
1481 g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL);
1482 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1483 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1484 secret_collection_search), NULL);
1485
1486 async = G_SIMPLE_ASYNC_RESULT (result);
1487 if (_secret_util_propagate_error (async, error))
1488 return NULL;
1489
1490 search = g_simple_async_result_get_op_res_gpointer (async);
1491
1492 for (i = 0; search->paths[i]; i++) {
1493 item = g_hash_table_lookup (search->items, search->paths[i]);
1494 if (item != NULL)
1495 items = g_list_prepend (items, g_object_ref (item));
1496 }
1497
1498 return g_list_reverse (items);
1499 }
1500
1501 static gboolean
collection_load_items_sync(SecretCollection * self,GCancellable * cancellable,gchar ** paths,GList ** items,gint want,GError ** error)1502 collection_load_items_sync (SecretCollection *self,
1503 GCancellable *cancellable,
1504 gchar **paths,
1505 GList **items,
1506 gint want,
1507 GError **error)
1508 {
1509 SecretService *service = secret_collection_get_service (self);
1510 SecretItem *item;
1511 gint have = 0;
1512 guint i;
1513
1514 for (i = 0; have < want && paths[i] != NULL; i++) {
1515 item = _secret_collection_find_item_instance (self, paths[i]);
1516 if (item == NULL)
1517 item = secret_item_new_for_dbus_path_sync (service, paths[i], SECRET_ITEM_NONE,
1518 cancellable, error);
1519 if (item == NULL) {
1520 return FALSE;
1521
1522 } else {
1523 *items = g_list_prepend (*items, item);
1524 have++;
1525 }
1526 }
1527
1528 return TRUE;
1529 }
1530
1531 /**
1532 * secret_collection_search_sync:
1533 * @self: a secret collection
1534 * @schema: (allow-none): the schema for the attributes
1535 * @attributes: (element-type utf8 utf8): search for items matching these attributes
1536 * @flags: search option flags
1537 * @cancellable: optional cancellation object
1538 * @error: location to place error on failure
1539 *
1540 * Search for items matching the @attributes in the @collection.
1541 * The @attributes should be a table of string keys and string values.
1542 *
1543 * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the
1544 * search will be returned. Otherwise only the first item will be returned.
1545 * This is almost always the unlocked item that was most recently stored.
1546 *
1547 * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked
1548 * if necessary. In either case, locked and unlocked items will match the
1549 * search and be returned. If the unlock fails, the search does not fail.
1550 *
1551 * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items will have
1552 * their secret values loaded and available via secret_item_get_secret().
1553 *
1554 * This function may block indefinitely. Use the asynchronous version
1555 * in user interface threads.
1556 *
1557 * Returns: (transfer full) (element-type Secret.Item):
1558 * a list of items that matched the search
1559 */
1560 GList *
secret_collection_search_sync(SecretCollection * self,const SecretSchema * schema,GHashTable * attributes,SecretSearchFlags flags,GCancellable * cancellable,GError ** error)1561 secret_collection_search_sync (SecretCollection *self,
1562 const SecretSchema *schema,
1563 GHashTable *attributes,
1564 SecretSearchFlags flags,
1565 GCancellable *cancellable,
1566 GError **error)
1567 {
1568 gchar **paths = NULL;
1569 GList *items = NULL;
1570 gboolean ret;
1571 gint want;
1572
1573 g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL);
1574 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1575 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1576
1577 /* Warnings raised already */
1578 if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE))
1579 return NULL;
1580
1581 paths = secret_collection_search_for_dbus_paths_sync (self, schema, attributes,
1582 cancellable, error);
1583 if (paths == NULL)
1584 return NULL;
1585
1586 ret = TRUE;
1587
1588 want = 1;
1589 if (flags & SECRET_SEARCH_ALL)
1590 want = G_MAXINT;
1591
1592 ret = collection_load_items_sync (self, cancellable, paths,
1593 &items, want, error);
1594
1595 g_strfreev (paths);
1596
1597 if (!ret)
1598 return NULL;
1599
1600 if (flags & SECRET_SEARCH_UNLOCK) {
1601 secret_service_unlock_sync (secret_collection_get_service (self),
1602 items, cancellable, NULL, NULL);
1603 }
1604
1605 if (flags & SECRET_SEARCH_LOAD_SECRETS)
1606 secret_item_load_secrets_sync (items, NULL, NULL);
1607
1608 return items;
1609 }
1610
1611 static void
on_service_delete_path(GObject * source,GAsyncResult * result,gpointer user_data)1612 on_service_delete_path (GObject *source,
1613 GAsyncResult *result,
1614 gpointer user_data)
1615 {
1616 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
1617 GError *error = NULL;
1618
1619 _secret_service_delete_path_finish (SECRET_SERVICE (source), result, &error);
1620 if (error != NULL)
1621 g_simple_async_result_take_error (async, error);
1622 g_simple_async_result_complete (async);
1623 g_object_unref (async);
1624 }
1625 /**
1626 * secret_collection_delete:
1627 * @self: a collection
1628 * @cancellable: optional cancellation object
1629 * @callback: called when the operation completes
1630 * @user_data: data to pass to the callback
1631 *
1632 * Delete this collection.
1633 *
1634 * This method returns immediately and completes asynchronously. The secret
1635 * service may prompt the user. secret_service_prompt() will be used to handle
1636 * any prompts that show up.
1637 */
1638 void
secret_collection_delete(SecretCollection * self,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1639 secret_collection_delete (SecretCollection *self,
1640 GCancellable *cancellable,
1641 GAsyncReadyCallback callback,
1642 gpointer user_data)
1643 {
1644 GSimpleAsyncResult *async;
1645 const gchar *object_path;
1646
1647 g_return_if_fail (SECRET_IS_COLLECTION (self));
1648 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1649
1650 async = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
1651 secret_collection_delete);
1652
1653 object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self));
1654 _secret_service_delete_path (self->pv->service, object_path, FALSE,
1655 cancellable, on_service_delete_path,
1656 g_object_ref (async));
1657
1658 g_object_unref (async);
1659 }
1660
1661 /**
1662 * secret_collection_delete_finish:
1663 * @self: a collection
1664 * @result: asynchronous result passed to the callback
1665 * @error: location to place an error on failure
1666 *
1667 * Complete operation to delete this collection.
1668 *
1669 * Returns: whether the collection was successfully deleted or not
1670 */
1671 gboolean
secret_collection_delete_finish(SecretCollection * self,GAsyncResult * result,GError ** error)1672 secret_collection_delete_finish (SecretCollection *self,
1673 GAsyncResult *result,
1674 GError **error)
1675 {
1676 g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE);
1677 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1678 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
1679 secret_collection_delete), FALSE);
1680
1681 if (_secret_util_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1682 return FALSE;
1683
1684 return TRUE;
1685 }
1686
1687 /**
1688 * secret_collection_delete_sync:
1689 * @self: a collection
1690 * @cancellable: optional cancellation object
1691 * @error: location to place an error on failure
1692 *
1693 * Delete this collection.
1694 *
1695 * This method may block indefinitely and should not be used in user
1696 * interface threads. The secret service may prompt the user.
1697 * secret_service_prompt() will be used to handle any prompts that show up.
1698 *
1699 * Returns: whether the collection was successfully deleted or not
1700 */
1701 gboolean
secret_collection_delete_sync(SecretCollection * self,GCancellable * cancellable,GError ** error)1702 secret_collection_delete_sync (SecretCollection *self,
1703 GCancellable *cancellable,
1704 GError **error)
1705 {
1706 SecretSync *sync;
1707 gboolean ret;
1708
1709 g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE);
1710 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1711 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1712
1713 sync = _secret_sync_new ();
1714 g_main_context_push_thread_default (sync->context);
1715
1716 secret_collection_delete (self, cancellable, _secret_sync_on_result, sync);
1717
1718 g_main_loop_run (sync->loop);
1719
1720 ret = secret_collection_delete_finish (self, sync->result, error);
1721
1722 g_main_context_pop_thread_default (sync->context);
1723 _secret_sync_free (sync);
1724
1725 return ret;
1726 }
1727
1728 /**
1729 * secret_collection_get_service:
1730 * @self: a collection
1731 *
1732 * Get the Secret Service object that this collection was created with.
1733 *
1734 * Returns: (transfer none): the Secret Service object
1735 */
1736 SecretService *
secret_collection_get_service(SecretCollection * self)1737 secret_collection_get_service (SecretCollection *self)
1738 {
1739 g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL);
1740 return self->pv->service;
1741 }
1742
1743 /**
1744 * secret_collection_get_flags:
1745 * @self: the secret collection proxy
1746 *
1747 * Get the flags representing what features of the #SecretCollection proxy
1748 * have been initialized.
1749 *
1750 * Use secret_collection_load_items() to initialize further features
1751 * and change the flags.
1752 *
1753 * Returns: the flags for features initialized
1754 */
1755 SecretCollectionFlags
secret_collection_get_flags(SecretCollection * self)1756 secret_collection_get_flags (SecretCollection *self)
1757 {
1758 SecretCollectionFlags flags = 0;
1759
1760 g_return_val_if_fail (SECRET_IS_COLLECTION (self), SECRET_COLLECTION_NONE);
1761
1762 g_mutex_lock (&self->pv->mutex);
1763
1764 if (self->pv->items)
1765 flags |= SECRET_COLLECTION_LOAD_ITEMS;
1766
1767 g_mutex_unlock (&self->pv->mutex);
1768
1769 return flags;
1770 }
1771
1772 /**
1773 * secret_collection_get_items:
1774 * @self: a collection
1775 *
1776 * Get the list of items in this collection.
1777 *
1778 * Returns: (transfer full) (element-type Secret.Item): a list of items,
1779 * when done, the list should be freed with g_list_free, and each item should
1780 * be released with g_object_unref()
1781 */
1782 GList *
secret_collection_get_items(SecretCollection * self)1783 secret_collection_get_items (SecretCollection *self)
1784 {
1785 GList *l, *items = NULL;
1786
1787 g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL);
1788
1789 g_mutex_lock (&self->pv->mutex);
1790 if (self->pv->items)
1791 items = g_hash_table_get_values (self->pv->items);
1792 for (l = items; l != NULL; l = g_list_next (l))
1793 g_object_ref (l->data);
1794 g_mutex_unlock (&self->pv->mutex);
1795
1796 return items;
1797 }
1798
1799 SecretItem *
_secret_collection_find_item_instance(SecretCollection * self,const gchar * item_path)1800 _secret_collection_find_item_instance (SecretCollection *self,
1801 const gchar *item_path)
1802 {
1803 SecretItem *item = NULL;
1804
1805 g_mutex_lock (&self->pv->mutex);
1806 if (self->pv->items)
1807 item = g_hash_table_lookup (self->pv->items, item_path);
1808 if (item != NULL)
1809 g_object_ref (item);
1810 g_mutex_unlock (&self->pv->mutex);
1811
1812 return item;
1813 }
1814
1815 /**
1816 * secret_collection_get_label:
1817 * @self: a collection
1818 *
1819 * Get the label of this collection.
1820 *
1821 * Returns: (transfer full): the label, which should be freed with g_free()
1822 */
1823 gchar *
secret_collection_get_label(SecretCollection * self)1824 secret_collection_get_label (SecretCollection *self)
1825 {
1826 GVariant *variant;
1827 gchar *label;
1828
1829 g_return_val_if_fail (SECRET_IS_COLLECTION (self), NULL);
1830
1831 variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Label");
1832 g_return_val_if_fail (variant != NULL, NULL);
1833
1834 label = g_variant_dup_string (variant, NULL);
1835 g_variant_unref (variant);
1836
1837 return label;
1838 }
1839
1840 /**
1841 * secret_collection_set_label:
1842 * @self: a collection
1843 * @label: a new label
1844 * @cancellable: optional cancellation object
1845 * @callback: called when the operation completes
1846 * @user_data: data to pass to the callback
1847 *
1848 * Set the label of this collection.
1849 *
1850 * This function returns immediately and completes asynchronously.
1851 */
1852 void
secret_collection_set_label(SecretCollection * self,const gchar * label,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1853 secret_collection_set_label (SecretCollection *self,
1854 const gchar *label,
1855 GCancellable *cancellable,
1856 GAsyncReadyCallback callback,
1857 gpointer user_data)
1858 {
1859 g_return_if_fail (SECRET_IS_COLLECTION (self));
1860 g_return_if_fail (label != NULL);
1861
1862 _secret_util_set_property (G_DBUS_PROXY (self), "Label",
1863 g_variant_new_string (label),
1864 secret_collection_set_label,
1865 cancellable, callback, user_data);
1866 }
1867
1868 /**
1869 * secret_collection_set_label_finish:
1870 * @self: a collection
1871 * @result: asynchronous result passed to callback
1872 * @error: location to place error on failure
1873 *
1874 * Complete asynchronous operation to set the label of this collection.
1875 *
1876 * Returns: whether the change was successful or not
1877 */
1878 gboolean
secret_collection_set_label_finish(SecretCollection * self,GAsyncResult * result,GError ** error)1879 secret_collection_set_label_finish (SecretCollection *self,
1880 GAsyncResult *result,
1881 GError **error)
1882 {
1883 g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE);
1884
1885 return _secret_util_set_property_finish (G_DBUS_PROXY (self),
1886 secret_collection_set_label,
1887 result, error);
1888 }
1889
1890 /**
1891 * secret_collection_set_label_sync:
1892 * @self: a collection
1893 * @label: a new label
1894 * @cancellable: optional cancellation object
1895 * @error: location to place error on failure
1896 *
1897 * Set the label of this collection.
1898 *
1899 * This function may block indefinitely. Use the asynchronous version
1900 * in user interface threads.
1901 *
1902 * Returns: whether the change was successful or not
1903 */
1904 gboolean
secret_collection_set_label_sync(SecretCollection * self,const gchar * label,GCancellable * cancellable,GError ** error)1905 secret_collection_set_label_sync (SecretCollection *self,
1906 const gchar *label,
1907 GCancellable *cancellable,
1908 GError **error)
1909 {
1910 g_return_val_if_fail (SECRET_IS_COLLECTION (self), FALSE);
1911 g_return_val_if_fail (label != NULL, FALSE);
1912
1913 return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Label",
1914 g_variant_new_string (label),
1915 cancellable, error);
1916 }
1917
1918 /**
1919 * secret_collection_get_locked:
1920 * @self: a collection
1921 *
1922 * Get whether the collection is locked or not.
1923 *
1924 * Use secret_service_lock() or secret_service_unlock() to lock or unlock the
1925 * collection.
1926 *
1927 * Returns: whether the collection is locked or not
1928 */
1929 gboolean
secret_collection_get_locked(SecretCollection * self)1930 secret_collection_get_locked (SecretCollection *self)
1931 {
1932 GVariant *variant;
1933 gboolean locked;
1934
1935 g_return_val_if_fail (SECRET_IS_COLLECTION (self), TRUE);
1936
1937 variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Locked");
1938 g_return_val_if_fail (variant != NULL, TRUE);
1939
1940 locked = g_variant_get_boolean (variant);
1941 g_variant_unref (variant);
1942
1943 return locked;
1944 }
1945
1946 /**
1947 * secret_collection_get_created:
1948 * @self: a collection
1949 *
1950 * Get the created date and time of the collection. The return value is
1951 * the number of seconds since the unix epoch, January 1st 1970.
1952 *
1953 * Returns: the created date and time
1954 */
1955 guint64
secret_collection_get_created(SecretCollection * self)1956 secret_collection_get_created (SecretCollection *self)
1957 {
1958 GVariant *variant;
1959 guint64 created;
1960
1961 g_return_val_if_fail (SECRET_IS_COLLECTION (self), TRUE);
1962
1963 variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Created");
1964 g_return_val_if_fail (variant != NULL, 0);
1965
1966 created = g_variant_get_uint64 (variant);
1967 g_variant_unref (variant);
1968
1969 return created;
1970 }
1971
1972 /**
1973 * secret_collection_get_modified:
1974 * @self: a collection
1975 *
1976 * Get the modified date and time of the collection. The return value is
1977 * the number of seconds since the unix epoch, January 1st 1970.
1978 *
1979 * Returns: the modified date and time
1980 */
1981 guint64
secret_collection_get_modified(SecretCollection * self)1982 secret_collection_get_modified (SecretCollection *self)
1983 {
1984 GVariant *variant;
1985 guint64 modified;
1986
1987 g_return_val_if_fail (SECRET_IS_COLLECTION (self), TRUE);
1988
1989 variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Modified");
1990 g_return_val_if_fail (variant != NULL, 0);
1991
1992 modified = g_variant_get_uint64 (variant);
1993 g_variant_unref (variant);
1994
1995 return modified;
1996 }
1997
1998
1999 typedef struct {
2000 GCancellable *cancellable;
2001 gchar *alias;
2002 SecretCollectionFlags flags;
2003 SecretCollection *collection;
2004 } ReadClosure;
2005
2006 static void
read_closure_free(gpointer data)2007 read_closure_free (gpointer data)
2008 {
2009 ReadClosure *read = data;
2010 g_free (read->alias);
2011 if (read->collection)
2012 g_object_unref (read->collection);
2013 if (read->cancellable)
2014 g_object_unref (read->cancellable);
2015 g_slice_free (ReadClosure, read);
2016 }
2017
2018 static void
on_read_alias_collection(GObject * source,GAsyncResult * result,gpointer user_data)2019 on_read_alias_collection (GObject *source,
2020 GAsyncResult *result,
2021 gpointer user_data)
2022 {
2023 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
2024 ReadClosure *read = g_simple_async_result_get_op_res_gpointer (async);
2025 GError *error = NULL;
2026
2027 read->collection = secret_collection_new_for_dbus_path_finish (result, &error);
2028 if (error != NULL)
2029 g_simple_async_result_take_error (async, error);
2030
2031 g_simple_async_result_complete (async);
2032 g_object_unref (async);
2033 }
2034
2035 static void
on_read_alias_path(GObject * source,GAsyncResult * result,gpointer user_data)2036 on_read_alias_path (GObject *source,
2037 GAsyncResult *result,
2038 gpointer user_data)
2039 {
2040 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
2041 ReadClosure *read = g_simple_async_result_get_op_res_gpointer (async);
2042 SecretService *self = SECRET_SERVICE (source);
2043 GError *error = NULL;
2044 gchar *collection_path;
2045
2046 collection_path = secret_service_read_alias_dbus_path_finish (self, result, &error);
2047 if (error == NULL) {
2048
2049 /* No collection for this alias */
2050 if (collection_path == NULL) {
2051 g_simple_async_result_complete (async);
2052
2053 } else {
2054 read->collection = _secret_service_find_collection_instance (self,
2055 collection_path);
2056 if (read->collection != NULL) {
2057
2058 /* Make sure collection has necessary flags */
2059 collection_ensure_for_flags_async (read->collection, read->flags,
2060 read->cancellable, async);
2061
2062 /* No collection loaded, but valid path, load */
2063 } else {
2064 secret_collection_new_for_dbus_path (self, collection_path,
2065 read->flags,
2066 read->cancellable,
2067 on_read_alias_collection,
2068 g_object_ref (async));
2069 }
2070 }
2071
2072 } else {
2073 g_simple_async_result_take_error (async, error);
2074 g_simple_async_result_complete (async);
2075 }
2076
2077 g_free (collection_path);
2078 g_object_unref (async);
2079 }
2080
2081 static void
on_read_alias_service(GObject * source,GAsyncResult * result,gpointer user_data)2082 on_read_alias_service (GObject *source,
2083 GAsyncResult *result,
2084 gpointer user_data)
2085 {
2086 GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
2087 ReadClosure *read = g_simple_async_result_get_op_res_gpointer (async);
2088 SecretService *service;
2089 GError *error = NULL;
2090
2091 service = secret_service_get_finish (result, &error);
2092 if (error == NULL) {
2093 secret_service_read_alias_dbus_path (service, read->alias, read->cancellable,
2094 on_read_alias_path, g_object_ref (async));
2095 g_object_unref (service);
2096
2097 } else {
2098 g_simple_async_result_take_error (async, error);
2099 g_simple_async_result_complete (async);
2100 }
2101
2102 g_object_unref (async);
2103 }
2104
2105 /**
2106 * secret_collection_for_alias:
2107 * @service: (allow-none): a secret service object
2108 * @alias: the alias to lookup
2109 * @flags: options for the collection initialization
2110 * @cancellable: (allow-none): optional cancellation object
2111 * @callback: called when the operation completes
2112 * @user_data: data to pass to the callback
2113 *
2114 * Lookup which collection is assigned to this alias. Aliases help determine
2115 * well known collections, such as 'default'.
2116 *
2117 * If @service is NULL, then secret_service_get() will be called to get
2118 * the default #SecretService proxy.
2119 *
2120 * This method will return immediately and complete asynchronously.
2121 */
2122 void
secret_collection_for_alias(SecretService * service,const gchar * alias,SecretCollectionFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2123 secret_collection_for_alias (SecretService *service,
2124 const gchar *alias,
2125 SecretCollectionFlags flags,
2126 GCancellable *cancellable,
2127 GAsyncReadyCallback callback,
2128 gpointer user_data)
2129 {
2130 GSimpleAsyncResult *async;
2131 ReadClosure *read;
2132
2133 g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
2134 g_return_if_fail (alias != NULL);
2135 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
2136
2137 async = g_simple_async_result_new (NULL, callback, user_data,
2138 secret_collection_for_alias);
2139 read = g_slice_new0 (ReadClosure);
2140 read->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
2141 read->alias = g_strdup (alias);
2142 read->flags = flags;
2143 g_simple_async_result_set_op_res_gpointer (async, read, read_closure_free);
2144
2145 if (service == NULL) {
2146 secret_service_get (SECRET_SERVICE_NONE, cancellable,
2147 on_read_alias_service, g_object_ref (async));
2148 } else {
2149 secret_service_read_alias_dbus_path (service, read->alias, read->cancellable,
2150 on_read_alias_path, g_object_ref (async));
2151 }
2152
2153 g_object_unref (async);
2154 }
2155
2156 /**
2157 * secret_collection_for_alias_finish:
2158 * @result: asynchronous result passed to callback
2159 * @error: location to place error on failure
2160 *
2161 * Finish an asynchronous operation to lookup which collection is assigned
2162 * to an alias.
2163 *
2164 * Returns: (transfer full): the collection, or %NULL if none assigned to the alias
2165 */
2166 SecretCollection *
secret_collection_for_alias_finish(GAsyncResult * result,GError ** error)2167 secret_collection_for_alias_finish (GAsyncResult *result,
2168 GError **error)
2169 {
2170 GSimpleAsyncResult *async;
2171 ReadClosure *read;
2172
2173 g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
2174 secret_collection_for_alias), NULL);
2175 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2176
2177 async = G_SIMPLE_ASYNC_RESULT (result);
2178 if (_secret_util_propagate_error (async, error))
2179 return NULL;
2180 read = g_simple_async_result_get_op_res_gpointer (async);
2181 if (read->collection)
2182 g_object_ref (read->collection);
2183 return read->collection;
2184 }
2185
2186 /**
2187 * secret_collection_for_alias_sync:
2188 * @service: (allow-none): a secret service object
2189 * @alias: the alias to lookup
2190 * @flags: options for the collection initialization
2191 * @cancellable: (allow-none): optional cancellation object
2192 * @error: location to place error on failure
2193 *
2194 * Lookup which collection is assigned to this alias. Aliases help determine
2195 * well known collections, such as 'default'.
2196 *
2197 * If @service is NULL, then secret_service_get_sync() will be called to get
2198 * the default #SecretService proxy.
2199 *
2200 * This method may block and should not be used in user interface threads.
2201 *
2202 * Returns: (transfer full): the collection, or %NULL if none assigned to the alias
2203 */
2204 SecretCollection *
secret_collection_for_alias_sync(SecretService * service,const gchar * alias,SecretCollectionFlags flags,GCancellable * cancellable,GError ** error)2205 secret_collection_for_alias_sync (SecretService *service,
2206 const gchar *alias,
2207 SecretCollectionFlags flags,
2208 GCancellable *cancellable,
2209 GError **error)
2210 {
2211 SecretCollection *collection;
2212 gchar *collection_path;
2213
2214 g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
2215 g_return_val_if_fail (alias != NULL, NULL);
2216 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
2217 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2218
2219 collection_path = secret_service_read_alias_dbus_path_sync (service, alias,
2220 cancellable, error);
2221 /* No collection for this alias */
2222 if (collection_path == NULL)
2223 return NULL;
2224
2225 collection = _secret_service_find_collection_instance (service,
2226 collection_path);
2227
2228 if (collection != NULL) {
2229
2230 /* Have a collection with all necessary flags */
2231 if (!collection_ensure_for_flags_sync (collection, flags,
2232 cancellable, error)) {
2233 g_object_unref (collection);
2234 collection = NULL;
2235 }
2236
2237 /* No collection loaded, but valid path, load */
2238 } else {
2239 collection = secret_collection_new_for_dbus_path_sync (service, collection_path,
2240 flags, cancellable, error);
2241 }
2242
2243 g_free (collection_path);
2244 return collection;
2245 }
2246