From 39a51aac94bd37d8357df77d16e2c0b30f048b9b Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 29 Jan 2014 20:20:19 +0000 Subject: [PATCH 1/9] Require account plugins to provide the ability to list parameters Bug: https://bugs.freedesktop.org/show_bug.cgi?id=71093 --- mission-control-plugins/account-storage.c | 133 +++++++++++++++++++++++++++++- mission-control-plugins/account-storage.h | 26 ++++++ src/mcd-account-manager-default.c | 60 ++++++++++++++ src/mcd-storage.c | 43 ++++++++++ tests/twisted/dbus-account-plugin.c | 62 ++++++++++++++ tests/twisted/mcp-account-diversion.c | 41 +++++++++ 6 files changed, 362 insertions(+), 3 deletions(-) diff --git a/mission-control-plugins/account-storage.c b/mission-control-plugins/account-storage.c index 288df07..af31ade 100644 --- a/mission-control-plugins/account-storage.c +++ b/mission-control-plugins/account-storage.c @@ -56,6 +56,7 @@ * iface->desc = "The FOO storage backend"; * iface->provider = "org.freedesktop.Telepathy.MissionControl5.FooStorage"; * + * iface->get_features = foo_plugin_get_features; * iface->delete_async = foo_plugin_delete_async; * iface->delete_finish = foo_plugin_delete_finish; * iface->commit = foo_plugin_commit; @@ -67,6 +68,8 @@ * iface->create = foo_plugin_create; * iface->get_attribute = foo_plugin_get_attribute; * iface->get_parameter = foo_plugin_get_parameter; + * iface->get_typed_parameters = foo_plugin_get_typed_parameters; + * iface->get_untyped_parameters = foo_plugin_get_untyped_parameters; * iface->set_attribute = foo_plugin_set_attribute; * iface->set_parameter = foo_plugin_set_parameter; * } @@ -99,6 +102,15 @@ #endif /* ENABLE_DEBUG */ +/** + * McpAccountStorageFeatures: + * @MCP_ACCOUNT_STORAGE_FEATURE_NONE: no particular features + * @MCP_ACCOUNT_STORAGE_FEATURE_STORE_TYPES: parameters' types are stored + * + * Return various quality-of-implementation details about this account + * storage backend. + */ + enum { CREATED, @@ -205,6 +217,21 @@ default_set_parameter (McpAccountStorage *storage, return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED; } +static gchar ** +default_get_untyped_parameters (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account) +{ + return NULL; +} + +static McpAccountStorageFeatures +default_get_features (McpAccountStorage *storage, + const gchar *account) +{ + return MCP_ACCOUNT_STORAGE_FEATURE_NONE; +} + static void class_init (gpointer klass, gpointer data) @@ -212,6 +239,7 @@ class_init (gpointer klass, GType type = G_TYPE_FROM_CLASS (klass); McpAccountStorageIface *iface = klass; + iface->get_features = default_get_features; iface->create = default_create; iface->delete_async = default_delete_async; iface->delete_finish = default_delete_finish; @@ -222,6 +250,7 @@ class_init (gpointer klass, iface->get_restrictions = default_get_restrictions; iface->set_attribute = default_set_attribute; iface->set_parameter = default_set_parameter; + iface->get_untyped_parameters = default_get_untyped_parameters; if (signals[CREATED] != 0) { @@ -254,12 +283,14 @@ class_init (gpointer klass, * in the backend that the emitting plugin handles. * * Before emitting this signal, the plugin must update its - * internal cache (if any) so that mcp_account_storage_get_attribute() + * internal cache (if any) so that mcp_account_storage_get_attribute(), + * mcp_account_storage_get_typed_parameters() or * or mcp_account_storage_get_parameter() will return the new value * when queried. * - * Note that mcp_account_manager_get_parameter() and - * mcp_account_manager_set_parameter() do not use the + * Note that mcp_account_storage_get_parameter(), + * mcp_account_storage_get_typed_parameters() and + * mcp_account_storage_set_parameter() do not use the * "param-" prefix, but this signal does. * * Should not be fired until mcp_account_storage_ready() has been called @@ -513,6 +544,79 @@ mcp_account_storage_get_parameter (McpAccountStorage *storage, } /** + * mcp_account_storage_get_typed_parameters: + * @storage: an #McpAccountStorage instance + * @am: an #McpAccountManager instance + * @account: the unique name of the account + * + * List all parameters whose types are known, with their values. + * + * Ideally, all parameters are typed parameters, whose + * types are stored alongside the values. This function produces + * those as its return value. + * + * However, the Mission Control API has not traditionally required + * account-storage backends to store parameters' types, so some backends + * will contain untyped parameters, + * returned by mcp_account_storage_get_untyped_parameters(). + * + * This method is mandatory to implement. + * + * Returns: (transfer full): a variant of type %G_VARIANT_TYPE_VARDICT + * containing the typed parameters and their values; %NULL or empty + * if there are no typed parameters + */ +GVariant * +mcp_account_storage_get_typed_parameters (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account) +{ + McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage); + + SDEBUG (storage, "%s", account); + + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (iface->get_typed_parameters != NULL, NULL); + + return iface->get_typed_parameters (storage, am, account); +} + +/** + * mcp_account_storage_get_untyped_parameters: + * @storage: an #McpAccountStorage instance + * @am: an #McpAccountManager instance + * @account: the unique name of the account + * + * List the names of all parameters whose types are unknown. + * The values are not listed, because interpreting the value + * correctly requires a type. + * + * See mcp_account_storage_get_typed_parameters() for more on + * typed vs. untyped parameters. + * + * The default implementation just returns %NULL, and is appropriate + * for "legacy-free" backends that store a type with every parameter. + * + * Returns: (array zero-terminated=1) (transfer full): a #GStrv + * containing the untyped parameters and their values; %NULL or empty + * if there are no untyped parameters + */ +gchar ** +mcp_account_storage_get_untyped_parameters (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account) +{ + McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage); + + SDEBUG (storage, "%s", account); + + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (iface->get_untyped_parameters != NULL, NULL); + + return iface->get_untyped_parameters (storage, am, account); +} + +/** * mcp_account_storage_set_attribute: * @storage: an #McpAccountStorage instance * @am: an #McpAccountManager instance @@ -1114,3 +1218,26 @@ mcp_account_storage_emit_reconnect (McpAccountStorage *storage, SDEBUG (storage, "%s", account); g_signal_emit (storage, signals[RECONNECT], 0, account); } + +/** + * mcp_account_storage_get_features: + * @storage: an #McpAccountStorage instance + * @account: the unique name of the account to inspect + * + * Get the backend's features. The default implementation + * returns %MCP_ACCOUNT_STORAGE_FEATURE_NONE. + * + * Returns: a bitmask of API features that apply to @account + */ +McpAccountStorageFeatures +mcp_account_storage_get_features (McpAccountStorage *storage, + const gchar *account) +{ + McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage); + + g_return_val_if_fail (iface != NULL, MCP_ACCOUNT_STORAGE_FEATURE_NONE); + g_return_val_if_fail (iface->get_features != NULL, + MCP_ACCOUNT_STORAGE_FEATURE_NONE); + + return iface->get_features (storage, account); +} diff --git a/mission-control-plugins/account-storage.h b/mission-control-plugins/account-storage.h index fd6daee..2e0c420 100644 --- a/mission-control-plugins/account-storage.h +++ b/mission-control-plugins/account-storage.h @@ -47,6 +47,12 @@ typedef enum { MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED } McpAccountStorageSetResult; +typedef enum /*< flags >*/ +{ + MCP_ACCOUNT_STORAGE_FEATURE_NONE = 0, + MCP_ACCOUNT_STORAGE_FEATURE_STORE_TYPES = (1 << 0) +} McpAccountStorageFeatures; + /* API for plugins to implement */ typedef struct _McpAccountStorage McpAccountStorage; typedef struct _McpAccountStorageIface McpAccountStorageIface; @@ -155,6 +161,16 @@ struct _McpAccountStorageIface const gchar *parameter, GVariant *val, McpParameterFlags flags); + + GVariant *(*get_typed_parameters) (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account); + gchar **(*get_untyped_parameters) (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account); + + McpAccountStorageFeatures (*get_features) (McpAccountStorage *storage, + const gchar *account); }; /* virtual methods */ @@ -217,6 +233,12 @@ GVariant *mcp_account_storage_get_parameter (McpAccountStorage *storage, const gchar *parameter, const GVariantType *type, McpParameterFlags *flags); +GVariant *mcp_account_storage_get_typed_parameters (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account); +gchar **mcp_account_storage_get_untyped_parameters (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account); McpAccountStorageSetResult mcp_account_storage_set_attribute ( McpAccountStorage *storage, @@ -233,6 +255,10 @@ McpAccountStorageSetResult mcp_account_storage_set_parameter ( GVariant *value, McpParameterFlags flags); +McpAccountStorageFeatures mcp_account_storage_get_features ( + McpAccountStorage *storage, + const gchar *account); + void mcp_account_storage_emit_created (McpAccountStorage *storage, const gchar *account); void mcp_account_storage_emit_altered_one (McpAccountStorage *storage, diff --git a/src/mcd-account-manager-default.c b/src/mcd-account-manager-default.c index e9f2bf2..13ac310 100644 --- a/src/mcd-account-manager-default.c +++ b/src/mcd-account-manager-default.c @@ -314,6 +314,56 @@ get_parameter (McpAccountStorage *self, str, type, NULL); } +static GVariant * +get_typed_parameters (McpAccountStorage *self, + McpAccountManager *am, + const gchar *account) +{ + McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self); + McdDefaultStoredAccount *sa = lookup_stored_account (amd, account); + GVariantBuilder asv; + GHashTableIter iter; + gpointer k, v; + + g_return_val_if_fail (sa != NULL, NULL); + g_return_val_if_fail (!sa->absent, NULL); + + g_variant_builder_init (&asv, G_VARIANT_TYPE_VARDICT); + + g_hash_table_iter_init (&iter, sa->parameters); + + while (g_hash_table_iter_next (&iter, &k, &v)) + g_variant_builder_add (&asv, "{sv}", k, v); + + return g_variant_ref_sink (g_variant_builder_end (&asv)); +} + +static gchar ** +get_untyped_parameters (McpAccountStorage *self, + McpAccountManager *am, + const gchar *account) +{ + McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self); + McdDefaultStoredAccount *sa = lookup_stored_account (amd, account); + GPtrArray *arr; + GHashTableIter iter; + gpointer k; + + g_return_val_if_fail (sa != NULL, NULL); + g_return_val_if_fail (!sa->absent, NULL); + + arr = g_ptr_array_sized_new (g_hash_table_size (sa->untyped_parameters) + 1); + + g_hash_table_iter_init (&iter, sa->untyped_parameters); + + while (g_hash_table_iter_next (&iter, &k, NULL)) + g_ptr_array_add (arr, g_strdup (k)); + + g_ptr_array_add (arr, NULL); + + return (gchar **) g_ptr_array_free (arr, FALSE); +} + static gchar * _create (McpAccountStorage *self, McpAccountManager *am, @@ -971,6 +1021,13 @@ _list (McpAccountStorage *self, return rval; } +static McpAccountStorageFeatures +get_features (McpAccountStorage *storage, + const gchar *account) +{ + return MCP_ACCOUNT_STORAGE_FEATURE_STORE_TYPES; +} + static void account_storage_iface_init (McpAccountStorageIface *iface, gpointer unused G_GNUC_UNUSED) @@ -979,8 +1036,11 @@ account_storage_iface_init (McpAccountStorageIface *iface, iface->desc = PLUGIN_DESCRIPTION; iface->priority = PLUGIN_PRIORITY; + iface->get_features = get_features; iface->get_attribute = get_attribute; iface->get_parameter = get_parameter; + iface->get_typed_parameters = get_typed_parameters; + iface->get_untyped_parameters = get_untyped_parameters; iface->set_attribute = set_attribute; iface->set_parameter = set_parameter; iface->create = _create; diff --git a/src/mcd-storage.c b/src/mcd-storage.c index 828d5a1..7e503a8 100644 --- a/src/mcd-storage.c +++ b/src/mcd-storage.c @@ -1942,6 +1942,8 @@ mcd_storage_add_account_from_plugin (McdStorage *self, GError **error) { McpAccountStorage *other = g_hash_table_lookup (self->accounts, account); + GVariant *parameters; + gchar **untyped_parameters; if (other != NULL) { @@ -1956,5 +1958,46 @@ mcd_storage_add_account_from_plugin (McdStorage *self, g_hash_table_insert (self->accounts, g_strdup (account), g_object_ref (plugin)); + + parameters = mcp_account_storage_get_typed_parameters (plugin, + (McpAccountManager *) self, account); + untyped_parameters = mcp_account_storage_get_untyped_parameters (plugin, + (McpAccountManager *) self, account); + + DEBUG ("Account parameters for %s", account); + + if (parameters != NULL) + { + GVariantIter iter; + gchar *k; + GVariant *v; + + g_variant_iter_init (&iter, parameters); + + while (g_variant_iter_loop (&iter, "{sv}", &k, &v)) + { + /* Don't debug-log the values in case they're sensitive: we + * can't know whether the parameter has the SECRET flag here */ + DEBUG ("%s: type '%s'", k, g_variant_get_type_string (v)); + } + } + + if (untyped_parameters != NULL) + { + gsize i; + + for (i = 0; untyped_parameters[i] != NULL; i++) + { + DEBUG ("%s: type not stored", untyped_parameters[i]); + } + } + + DEBUG ("End of parameters"); + + if (parameters != NULL) + g_variant_unref (parameters); + + g_strfreev (untyped_parameters); + return TRUE; } diff --git a/tests/twisted/dbus-account-plugin.c b/tests/twisted/dbus-account-plugin.c index 446a2ad..4f92a37 100644 --- a/tests/twisted/dbus-account-plugin.c +++ b/tests/twisted/dbus-account-plugin.c @@ -1028,6 +1028,57 @@ test_dbus_account_plugin_get_parameter (McpAccountStorage *storage, } } +static GVariant * +test_dbus_account_plugin_get_typed_parameters (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account_name) +{ + TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage); + Account *account = lookup_account (self, account_name); + GVariantBuilder asv; + GHashTableIter iter; + gpointer k, v; + + g_return_val_if_fail (self->active, NULL); + g_return_val_if_fail (account != NULL, NULL); + + g_variant_builder_init (&asv, G_VARIANT_TYPE_VARDICT); + + g_hash_table_iter_init (&iter, account->parameters); + + while (g_hash_table_iter_next (&iter, &k, &v)) + g_variant_builder_add (&asv, "{sv}", k, v); + + return g_variant_ref_sink (g_variant_builder_end (&asv)); +} + +static gchar ** +test_dbus_account_plugin_get_untyped_parameters (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account_name) +{ + TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage); + Account *account = lookup_account (self, account_name); + GPtrArray *arr; + GHashTableIter iter; + gpointer k; + + g_return_val_if_fail (self->active, NULL); + g_return_val_if_fail (account != NULL, NULL); + + arr = g_ptr_array_sized_new ( + g_hash_table_size (account->untyped_parameters) + 1); + + g_hash_table_iter_init (&iter, account->untyped_parameters); + + while (g_hash_table_iter_next (&iter, &k, NULL)) + g_ptr_array_add (arr, g_strdup (k)); + + g_ptr_array_add (arr, NULL); + + return (gchar **) g_ptr_array_free (arr, FALSE); +} + static McpAccountStorageSetResult test_dbus_account_plugin_set_attribute (McpAccountStorage *storage, McpAccountManager *am, @@ -1490,6 +1541,13 @@ test_dbus_account_plugin_get_restrictions (McpAccountStorage *storage, return account->restrictions; } +static McpAccountStorageFeatures +test_dbus_account_plugin_get_features (McpAccountStorage *storage, + const gchar *account) +{ + return MCP_ACCOUNT_STORAGE_FEATURE_STORE_TYPES; +} + static void account_storage_iface_init (McpAccountStorageIface *iface) { @@ -1498,8 +1556,12 @@ account_storage_iface_init (McpAccountStorageIface *iface) /* this should be higher priority than the diverted-keyfile one */ iface->priority = MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_NORMAL + 100; + iface->get_features = test_dbus_account_plugin_get_features; iface->get_attribute = test_dbus_account_plugin_get_attribute; iface->get_parameter = test_dbus_account_plugin_get_parameter; + iface->get_typed_parameters = test_dbus_account_plugin_get_typed_parameters; + iface->get_untyped_parameters = + test_dbus_account_plugin_get_untyped_parameters; iface->set_attribute = test_dbus_account_plugin_set_attribute; iface->set_parameter = test_dbus_account_plugin_set_parameter; iface->list = test_dbus_account_plugin_list; diff --git a/tests/twisted/mcp-account-diversion.c b/tests/twisted/mcp-account-diversion.c index 466d3ee..d4a8630 100644 --- a/tests/twisted/mcp-account-diversion.c +++ b/tests/twisted/mcp-account-diversion.c @@ -250,6 +250,43 @@ _get_parameter (McpAccountStorage *self, return ret; } +static GVariant * +get_typed_parameters (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account_name) +{ + /* this plugin can't store parameters' types */ + return NULL; +} + +static gchar ** +get_untyped_parameters (McpAccountStorage *storage, + McpAccountManager *am, + const gchar *account_name) +{ + AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (storage); + gchar **keys; + gsize i; + GPtrArray *arr; + + keys = g_key_file_get_keys (adp->keyfile, account_name, &i, NULL); + + if (keys == NULL) + return NULL; + + arr = g_ptr_array_sized_new (i); + + for (i = 0; keys[i] != NULL; i++) + { + if (g_str_has_prefix (keys[i], "param-")) + g_ptr_array_add (arr, g_strdup (keys[i] + 6)); + } + + g_strfreev (keys); + g_ptr_array_add (arr, NULL); + return (gchar **) g_ptr_array_free (arr, FALSE); +} + static gboolean _commit (McpAccountStorage *self, McpAccountManager *am, const gchar *account_name); @@ -384,8 +421,12 @@ account_storage_iface_init (McpAccountStorageIface *iface, iface->desc = PLUGIN_DESCRIPTION; iface->priority = PLUGIN_PRIORITY; + /* we don't override get_features - we only have the basics anyway */ + iface->get_attribute = _get_attribute; iface->get_parameter = _get_parameter; + iface->get_typed_parameters = get_typed_parameters; + iface->get_untyped_parameters = get_untyped_parameters; iface->set_attribute = _set_attribute; iface->set_parameter = _set_parameter; iface->delete_async = delete_async; -- 1.9.rc1