diff --git a/library/secret-collection.c b/library/secret-collection.c index dbebc25..35305fe 100644 --- a/library/secret-collection.c +++ b/library/secret-collection.c @@ -428,6 +428,87 @@ secret_collection_properties_changed (GDBusProxy *proxy, g_object_thaw_notify (G_OBJECT (self)); } +static void +secret_collection_signal (GDBusProxy *proxy, + const gchar *sender_name, + const gchar *signal_name, + GVariant *parameters) +{ + SecretCollection *self = SECRET_COLLECTION (proxy); + SecretItem *item; + const gchar *item_path; + GVariantBuilder builder; + gboolean found = FALSE; + GVariantIter iter; + GVariant *value; + GVariant *paths; + GVariant *path; + + /* + * Remember that these signals come from a time before PropertiesChanged. + * We support them because they're in the spec, and ksecretservice uses them. + */ + + paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Items"); + + /* A new collection was added, add it to the Collections property */ + if (g_str_equal (signal_name, SECRET_SIGNAL_ITEM_CREATED)) { + g_variant_get (parameters, "@o", &value); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao")); + g_variant_iter_init (&iter, paths); + while ((path = g_variant_iter_next_value (&iter)) != NULL) { + if (g_variant_equal (path, value)) { + found = TRUE; + break; + } + g_variant_builder_add_value (&builder, path); + g_variant_unref (path); + } + if (!found) { + g_variant_builder_add_value (&builder, value); + handle_property_changed (self, "Items", g_variant_builder_end (&builder)); + } + g_variant_builder_clear (&builder); + g_variant_unref (value); + + /* A collection was deleted, remove it from the Collections property */ + } else if (g_str_equal (signal_name, SECRET_SIGNAL_ITEM_DELETED)) { + g_variant_get (parameters, "@o", &value); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao")); + g_variant_iter_init (&iter, paths); + while ((path = g_variant_iter_next_value (&iter)) != NULL) { + if (g_variant_equal (path, value)) + found = TRUE; + else + g_variant_builder_add_value (&builder, path); + g_variant_unref (path); + } + if (found) + handle_property_changed (self, "Items", g_variant_builder_end (&builder)); + g_variant_unref (value); + + /* The collection changed, update it */ + } else if (g_str_equal (signal_name, SECRET_SIGNAL_ITEM_CHANGED)) { + g_variant_get (parameters, "&o", &item_path); + + g_mutex_lock (&self->pv->mutex); + + if (self->pv->items) + item = g_hash_table_lookup (self->pv->items, item_path); + else + item = NULL; + if (item) + g_object_ref (item); + + g_mutex_unlock (&self->pv->mutex); + + secret_item_refresh (item); + g_object_unref (item); + } + + g_variant_unref (paths); +} + static void secret_collection_class_init (SecretCollectionClass *klass) { @@ -440,6 +521,7 @@ secret_collection_class_init (SecretCollectionClass *klass) gobject_class->finalize = secret_collection_finalize; proxy_class->g_properties_changed = secret_collection_properties_changed; + proxy_class->g_signal = secret_collection_signal; /** * SecretCollection:service: diff --git a/library/secret-private.h b/library/secret-private.h index ca21ac0..0aad92a 100644 --- a/library/secret-private.h +++ b/library/secret-private.h @@ -37,7 +37,13 @@ typedef struct _SecretSession SecretSession; #define SECRET_PROMPT_INTERFACE "org.freedesktop.Secret.Prompt" #define SECRET_SERVICE_INTERFACE "org.freedesktop.Secret.Service" -#define SECRET_PROMPT_SIGNAL_COMPLETED "Completed" +#define SECRET_SIGNAL_COLLECTION_CREATED "CollectionCreated" +#define SECRET_SIGNAL_COLLECTION_CHANGED "CollectionChanged" +#define SECRET_SIGNAL_COLLECTION_DELETED "CollectionDeleted" +#define SECRET_SIGNAL_ITEM_CREATED "ItemCreated" +#define SECRET_SIGNAL_ITEM_CHANGED "ItemChanged" +#define SECRET_SIGNAL_ITEM_DELETED "ItemDeleted" +#define SECRET_PROMPT_SIGNAL_COMPLETED "Completed" #define SECRET_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" @@ -56,6 +62,9 @@ gchar * _secret_util_parent_path (const gchar *path gboolean _secret_util_empty_path (const gchar *path); +gint _secret_util_array_index_of (GVariant *array, + GVariant *value); + GType _secret_list_get_type (void) G_GNUC_CONST; GVariant * _secret_util_variant_for_attributes (GHashTable *attributes); diff --git a/library/secret-service.c b/library/secret-service.c index 04fd47d..a9250a5 100644 --- a/library/secret-service.c +++ b/library/secret-service.c @@ -272,6 +272,8 @@ handle_property_changed (SecretService *self, { gboolean perform; + g_variant_ref_sink (value); + if (g_str_equal (property_name, "Collections")) { g_mutex_lock (&self->pv->mutex); @@ -281,6 +283,8 @@ handle_property_changed (SecretService *self, if (perform) secret_service_ensure_collections (self, self->pv->cancellable, NULL, NULL); } + + g_variant_unref (value); } static void @@ -302,6 +306,87 @@ secret_service_properties_changed (GDBusProxy *proxy, g_object_thaw_notify (G_OBJECT (self)); } +static void +secret_service_signal (GDBusProxy *proxy, + const gchar *sender_name, + const gchar *signal_name, + GVariant *parameters) +{ + SecretService *self = SECRET_SERVICE (proxy); + SecretCollection *collection; + const gchar *collection_path; + GVariantBuilder builder; + gboolean found = FALSE; + GVariantIter iter; + GVariant *value; + GVariant *paths; + GVariant *path; + + /* + * Remember that these signals come from a time before PropertiesChanged. + * We support them because they're in the spec, and ksecretservice uses them. + */ + + paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections"); + + /* A new collection was added, add it to the Collections property */ + if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CREATED)) { + g_variant_get (parameters, "@o", &value); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao")); + g_variant_iter_init (&iter, paths); + while ((path = g_variant_iter_next_value (&iter)) != NULL) { + if (g_variant_equal (path, value)) { + found = TRUE; + break; + } + g_variant_builder_add_value (&builder, path); + g_variant_unref (path); + } + if (!found) { + g_variant_builder_add_value (&builder, value); + handle_property_changed (self, "Collections", g_variant_builder_end (&builder)); + } + g_variant_builder_clear (&builder); + g_variant_unref (value); + + /* A collection was deleted, remove it from the Collections property */ + } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_DELETED)) { + g_variant_get (parameters, "@o", &value); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao")); + g_variant_iter_init (&iter, paths); + while ((path = g_variant_iter_next_value (&iter)) != NULL) { + if (g_variant_equal (path, value)) + found = TRUE; + else + g_variant_builder_add_value (&builder, path); + g_variant_unref (path); + } + if (found) + handle_property_changed (self, "Collections", g_variant_builder_end (&builder)); + g_variant_unref (value); + + /* The collection changed, update it */ + } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CHANGED)) { + g_variant_get (parameters, "&o", &collection_path); + + g_mutex_lock (&self->pv->mutex); + + if (self->pv->collections) + collection = g_hash_table_lookup (self->pv->collections, collection_path); + else + collection = NULL; + if (collection) + g_object_ref (collection); + + g_mutex_unlock (&self->pv->mutex); + + secret_collection_refresh (collection); + g_object_unref (collection); + } + + g_variant_unref (paths); +} + static void secret_service_class_init (SecretServiceClass *klass) { @@ -314,6 +399,7 @@ secret_service_class_init (SecretServiceClass *klass) object_class->finalize = secret_service_finalize; proxy_class->g_properties_changed = secret_service_properties_changed; + proxy_class->g_signal = secret_service_signal; klass->prompt_sync = secret_service_real_prompt_sync; klass->prompt_async = secret_service_real_prompt_async;