diff options
Diffstat (limited to 'library/gsecret-collection.c')
-rw-r--r-- | library/gsecret-collection.c | 442 |
1 files changed, 289 insertions, 153 deletions
diff --git a/library/gsecret-collection.c b/library/gsecret-collection.c index 3f1a8fa..6c4bc81 100644 --- a/library/gsecret-collection.c +++ b/library/gsecret-collection.c @@ -42,7 +42,18 @@ struct _GSecretCollectionPrivate { GHashTable *items; }; -G_DEFINE_TYPE (GSecretCollection, gsecret_collection, G_TYPE_DBUS_PROXY); +static GInitableIface *gsecret_collection_initable_parent_iface = NULL; + +static GAsyncInitableIface *gsecret_collection_async_initable_parent_iface = NULL; + +static void gsecret_collection_initable_iface (GInitableIface *iface); + +static void gsecret_collection_async_initable_iface (GAsyncInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (GSecretCollection, gsecret_collection, G_TYPE_DBUS_PROXY, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gsecret_collection_initable_iface); + G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, gsecret_collection_async_initable_iface); +); static GHashTable * items_table_new (void) @@ -166,69 +177,63 @@ gsecret_collection_finalize (GObject *obj) G_OBJECT_CLASS (gsecret_collection_parent_class)->finalize (obj); } -typedef struct { - GSecretCollection *collection; - GCancellable *cancellable; - GHashTable *items; - gint items_loading; -} LoadClosure; - -static void -load_closure_free (gpointer data) +static GSecretItem * +collection_lookup_item (GSecretCollection *self, + const gchar *path) { - LoadClosure *closure = data; - g_object_unref (closure->collection); - g_clear_object (&closure->cancellable); - g_hash_table_unref (closure->items); - g_slice_free (LoadClosure, closure); -} + GSecretItem *item = NULL; -static GSimpleAsyncResult * -load_result_new (GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - LoadClosure *closure; + g_mutex_lock (&self->pv->mutex); - res = g_simple_async_result_new (NULL, callback, user_data, load_result_new); - closure = g_slice_new0 (LoadClosure); - closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - closure->items = items_table_new (); - g_simple_async_result_set_op_res_gpointer (res, closure, load_closure_free); + item = g_hash_table_lookup (self->pv->items, path); + if (item != NULL) + g_object_ref (item); + + g_mutex_unlock (&self->pv->mutex); - return res; + return item; } static void -load_items_complete (GSimpleAsyncResult *res) +collection_update_items (GSecretCollection *self, + GHashTable *items) { - LoadClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - GSecretCollection *self = closure->collection; - GHashTable *items; + GHashTable *previous; - g_assert (closure->items_loading == 0); - - g_hash_table_ref (closure->items); + g_hash_table_ref (items); g_mutex_lock (&self->pv->mutex); - items = self->pv->items; - self->pv->items = closure->items; + previous = self->pv->items; + self->pv->items = items; g_mutex_unlock (&self->pv->mutex); - g_hash_table_unref (items); + g_hash_table_unref (previous); +} - g_simple_async_result_complete (res); +typedef struct { + GCancellable *cancellable; + GHashTable *items; + gint items_loading; +} ItemsClosure; + +static void +items_closure_free (gpointer data) +{ + ItemsClosure *closure = data; + g_clear_object (&closure->cancellable); + g_hash_table_unref (closure->items); + g_slice_free (ItemsClosure, closure); } static void -on_item_loading (GObject *source, - GAsyncResult *result, - gpointer user_data) +on_load_item (GObject *source, + GAsyncResult *result, + gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - LoadClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - const gchar *item_path; + ItemsClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretCollection *self = GSECRET_COLLECTION (g_async_result_get_source_object (user_data)); + const gchar *path; GError *error = NULL; GSecretItem *item; @@ -240,57 +245,118 @@ on_item_loading (GObject *source, g_simple_async_result_take_error (res, error); if (item != NULL) { - item_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)); - g_hash_table_insert (closure->items, g_strdup (item_path), item); + path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)); + g_hash_table_insert (closure->items, g_strdup (path), item); } - if (closure->items_loading == 0) - load_items_complete (res); + if (closure->items_loading == 0) { + collection_update_items (self, closure->items); + g_simple_async_result_complete_in_idle (res); + } + g_object_unref (self); g_object_unref (res); } static void -load_items_perform (GSecretCollection *self, - GSimpleAsyncResult *res, - GVariant *item_paths) +collection_load_items_async (GSecretCollection *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - LoadClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + ItemsClosure *closure; GSecretItem *item; + GSimpleAsyncResult *res; + const gchar *path; + GVariant *paths; GVariantIter iter; - gchar *item_path; - - g_assert (GSECRET_IS_COLLECTION (self)); - g_assert (item_paths != NULL); - g_assert (closure->collection == NULL); - closure->collection = g_object_ref (self); + paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items"); + g_return_if_fail (paths != NULL); - g_variant_iter_init (&iter, item_paths); - while (g_variant_iter_loop (&iter, "o", &item_path)) { + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + collection_load_items_async); + closure = g_slice_new0 (ItemsClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + closure->items = items_table_new (); + g_simple_async_result_set_op_res_gpointer (res, closure, items_closure_free); - g_mutex_lock (&self->pv->mutex); - item = g_hash_table_lookup (self->pv->items, item_path); - if (item != NULL) - g_object_ref (item); - g_mutex_unlock (&self->pv->mutex); + g_variant_iter_init (&iter, paths); + while (g_variant_iter_loop (&iter, "&o", &path)) { + item = collection_lookup_item (self, path); + /* No such collection yet create a new one */ if (item == NULL) { - // TODO: xxxxxxxxxxxx; - gsecret_item_new (self->pv->service, item_path, - closure->cancellable, on_item_loading, - g_object_ref (res)); + gsecret_item_new (self->pv->service, path, cancellable, + on_load_item, g_object_ref (res)); closure->items_loading++; } else { - g_hash_table_insert (closure->items, - g_strdup (item_path), item); + g_hash_table_insert (closure->items, g_strdup (path), item); + } + } + + if (closure->items_loading == 0) { + collection_update_items (self, closure->items); + g_simple_async_result_complete_in_idle (res); + } + + g_variant_unref (paths); + g_object_unref (res); +} + +static gboolean +collection_load_items_finish (GSecretCollection *self, + GAsyncResult *result, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return FALSE; + + return TRUE; +} + + +static gboolean +collection_load_items_sync (GSecretCollection *self, + GCancellable *cancellable, + GError **error) +{ + GSecretItem *item; + GHashTable *items; + GVariant *paths; + GVariantIter iter; + const gchar *path; + gboolean ret = TRUE; + + paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items"); + g_return_val_if_fail (paths != NULL, FALSE); + + items = items_table_new (); + + g_variant_iter_init (&iter, paths); + while (g_variant_iter_next (&iter, "&o", &path)) { + item = collection_lookup_item (self, path); + + /* No such collection yet create a new one */ + if (item == NULL) { + item = gsecret_item_new_sync (self->pv->service, path, + cancellable, error); + if (item == NULL) { + ret = FALSE; + break; + } } + g_hash_table_insert (items, g_strdup (path), item); } - if (closure->items_loading == 0) - load_items_complete (res); + if (ret) + collection_update_items (self, items); + + g_hash_table_unref (items); + g_variant_unref (paths); + return ret; } static void @@ -298,8 +364,6 @@ handle_property_changed (GSecretCollection *self, const gchar *property_name, GVariant *value) { - GSimpleAsyncResult *res; - if (g_str_equal (property_name, "Label")) g_object_notify (G_OBJECT (self), "label"); @@ -312,24 +376,8 @@ handle_property_changed (GSecretCollection *self, else if (g_str_equal (property_name, "Modified")) g_object_notify (G_OBJECT (self), "modified"); - else if (g_str_equal (property_name, "Items") && !self->pv->constructing) { - res = load_result_new (self->pv->cancellable, NULL, NULL); - - if (value == NULL) - value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items"); - else - g_variant_ref (value); - if (value == NULL) { - g_warning ("couldn't retrieve Collection Items property"); - g_simple_async_result_complete (res); - } else { - // TODO: yyyy; - load_items_perform (self, res, value); - g_variant_unref (value); - } - - g_object_unref (res); - } + else if (g_str_equal (property_name, "Items") && !self->pv->constructing) + collection_load_items_async (self, self->pv->cancellable, NULL, NULL); } static void @@ -392,49 +440,147 @@ gsecret_collection_class_init (GSecretCollectionClass *klass) g_type_class_add_private (gobject_class, sizeof (GSecretCollectionPrivate)); } -static void -on_collection_new (GObject *source, - GAsyncResult *result, - gpointer user_data) +static gboolean +gsecret_collection_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) { - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); GSecretCollection *self; - GObject *source_object; - GError *error = NULL; - GVariant *item_paths; - GObject *object; GDBusProxy *proxy; - source_object = g_async_result_get_source_object (result); - object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), - result, &error); - g_object_unref (source_object); + if (!gsecret_collection_initable_parent_iface->init (initable, cancellable, error)) + return FALSE; - proxy = G_DBUS_PROXY (object); - if (error == NULL && !_gsecret_util_have_cached_properties (proxy)) { - g_set_error (&error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, - "No such secret collection at path: %s", g_dbus_proxy_get_object_path (proxy)); + proxy = G_DBUS_PROXY (initable); + + if (!_gsecret_util_have_cached_properties (proxy)) { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, + "No such secret collection at path: %s", + g_dbus_proxy_get_object_path (proxy)); + return FALSE; } - if (error == NULL) { - self = GSECRET_COLLECTION (object); - self->pv->constructing = FALSE; + self = GSECRET_COLLECTION (initable); - item_paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (object), "Items"); - g_return_if_fail (item_paths != NULL); - // TODO: yyyy; - load_items_perform (self, res, item_paths); - g_variant_unref (item_paths); + if (!collection_load_items_sync (self, cancellable, error)) + return FALSE; - } else { + return TRUE; +} + +static void +gsecret_collection_initable_iface (GInitableIface *iface) +{ + gsecret_collection_initable_parent_iface = g_type_interface_peek_parent (iface); + + iface->init = gsecret_collection_initable_init; +} + +typedef struct { + GCancellable *cancellable; +} InitClosure; + +static void +init_closure_free (gpointer data) +{ + InitClosure *closure = data; + g_clear_object (&closure->cancellable); + g_slice_free (InitClosure, closure); +} + +static void +on_init_items (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + GSecretCollection *self = GSECRET_COLLECTION (source); + GError *error = NULL; + + if (!collection_load_items_finish (self, result, &error)) g_simple_async_result_take_error (res, error); + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_init_base (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + GSecretCollection *self = GSECRET_COLLECTION (source); + InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GDBusProxy *proxy = G_DBUS_PROXY (self); + GError *error = NULL; + + if (!gsecret_collection_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self), + result, &error)) { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + + } else if (!_gsecret_util_have_cached_properties (proxy)) { + g_simple_async_result_set_error (res, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, + "No such secret collection at path: %s", + g_dbus_proxy_get_object_path (proxy)); g_simple_async_result_complete (res); + + } else { + collection_load_items_async (self, closure->cancellable, + on_init_items, g_object_ref (res)); } - g_clear_object (&object); g_object_unref (res); } +static void +gsecret_collection_async_initable_init_async (GAsyncInitable *initable, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + InitClosure *closure; + + res = g_simple_async_result_new (G_OBJECT (initable), callback, user_data, + gsecret_collection_async_initable_init_async); + closure = g_slice_new0 (InitClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + g_simple_async_result_set_op_res_gpointer (res, closure, init_closure_free); + + gsecret_collection_async_initable_parent_iface->init_async (initable, io_priority, + cancellable, + on_init_base, + g_object_ref (res)); + + g_object_unref (res); +} + +static gboolean +gsecret_collection_async_initable_init_finish (GAsyncInitable *initable, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (initable), + gsecret_collection_async_initable_init_async), FALSE); + + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return FALSE; + + return TRUE; +} + +static void +gsecret_collection_async_initable_iface (GAsyncInitableIface *iface) +{ + gsecret_collection_async_initable_parent_iface = g_type_interface_peek_parent (iface); + + iface->init_async = gsecret_collection_async_initable_init_async; + iface->init_finish = gsecret_collection_async_initable_init_finish; +} + void gsecret_collection_new (GSecretService *service, const gchar *collection_path, @@ -442,22 +588,16 @@ gsecret_collection_new (GSecretService *service, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; GDBusProxy *proxy; g_return_if_fail (GSECRET_IS_SERVICE (service)); g_return_if_fail (collection_path != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - res = load_result_new (cancellable, callback, user_data); proxy = G_DBUS_PROXY (service); g_async_initable_new_async (GSECRET_SERVICE_GET_CLASS (service)->collection_gtype, - G_PRIORITY_DEFAULT, - cancellable, - // TODO: zzzz; - on_collection_new, - g_object_ref (res), + G_PRIORITY_DEFAULT, cancellable, callback, user_data, "g-flags", G_DBUS_CALL_FLAGS_NONE, "g-interface-info", _gsecret_gen_collection_interface_info (), "g-name", g_dbus_proxy_get_name (proxy), @@ -466,27 +606,27 @@ gsecret_collection_new (GSecretService *service, "g-interface-name", GSECRET_COLLECTION_INTERFACE, "service", service, NULL); - - g_object_unref (res); } GSecretCollection * gsecret_collection_new_finish (GAsyncResult *result, GError **error) { - GSimpleAsyncResult *res; - LoadClosure *closure; + GObject *source_object; + GObject *object; - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, load_result_new), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - res = G_SIMPLE_ASYNC_RESULT (result); + source_object = g_async_result_get_source_object (result); + object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), + result, error); + g_object_unref (source_object); - if (g_simple_async_result_propagate_error (res, error)) + if (object == NULL) return NULL; - closure = g_simple_async_result_get_op_res_gpointer (res); - return g_object_ref (closure->collection); + return GSECRET_COLLECTION (object); } GSecretCollection * @@ -495,29 +635,25 @@ gsecret_collection_new_sync (GSecretService *service, GCancellable *cancellable, GError **error) { - GSecretSync *sync; - GSecretCollection *collection; + GDBusProxy *proxy; g_return_val_if_fail (GSECRET_IS_SERVICE (service), NULL); g_return_val_if_fail (collection_path != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - sync = _gsecret_sync_new (); - g_main_context_push_thread_default (sync->context); - - // TODO: xxxxx; - gsecret_collection_new (service, collection_path, cancellable, - _gsecret_sync_on_result, sync); - - g_main_loop_run (sync->loop); - - collection = gsecret_collection_new_finish (sync->result, error); - - g_main_context_pop_thread_default (sync->context); - _gsecret_sync_free (sync); + proxy = G_DBUS_PROXY (service); - return collection; + return g_initable_new (GSECRET_SERVICE_GET_CLASS (service)->collection_gtype, + cancellable, error, + "g-flags", G_DBUS_CALL_FLAGS_NONE, + "g-interface-info", _gsecret_gen_collection_interface_info (), + "g-name", g_dbus_proxy_get_name (proxy), + "g-connection", g_dbus_proxy_get_connection (proxy), + "g-object-path", collection_path, + "g-interface-name", GSECRET_COLLECTION_INTERFACE, + "service", service, + NULL); } void |