From b224cd87c2ba9c056d3b997c666ecb06d36656a8 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 15 Oct 2013 18:10:00 +0100 Subject: [PATCH 3/4] Call IdentifyAccount to get new accounts' names It's exposed through the plugin API so that exemplary plugins can use the same utility functions to decide how to name accounts for the ::created signal, if they want to. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=34640 --- configure.ac | 4 +- mission-control-plugins/account.c | 42 +++++++ mission-control-plugins/account.h | 11 ++ mission-control-plugins/implementation.h | 11 ++ src/mcd-account-manager.c | 136 +++++++++++++-------- src/mcd-storage.c | 78 ++++++++++++ .../account-manager/create-with-properties.py | 5 +- 7 files changed, 234 insertions(+), 53 deletions(-) diff --git a/configure.ac b/configure.ac index fc78f6a..99bcf13 100644 --- a/configure.ac +++ b/configure.ac @@ -220,7 +220,7 @@ AC_DEFINE([TP_SEAL_ENABLE], [], [Define to hide deprecated struct fields]) AC_DEFINE([TP_DISABLE_SINGLE_INCLUDE], [], [Avoid individual headers]) PKG_CHECK_MODULES([GLIB], - [glib-2.0 >= 2.32, gobject-2.0, gmodule-no-export-2.0, gio-2.0]) + [glib-2.0 >= 2.36, gobject-2.0, gmodule-no-export-2.0, gio-2.0]) PKG_CHECK_MODULES([GIO_UNIX], [gio-unix-2.0], [ @@ -231,7 +231,7 @@ PKG_CHECK_MODULES([GIO_UNIX], [gio-unix-2.0], []) AC_DEFINE([GLIB_VERSION_MIN_REQUIRED], [GLIB_VERSION_2_30], [Ignore post 2.30 deprecations]) -AC_DEFINE([GLIB_VERSION_MAX_ALLOWED], [GLIB_VERSION_2_32], [Prevent post 2.32 APIs]) +AC_DEFINE([GLIB_VERSION_MAX_ALLOWED], [GLIB_VERSION_2_36], [Prevent post 2.36 APIs]) dnl Check for MCE, a Maemo service used to determine when the device is idle. PKG_CHECK_MODULES([MCE], mce >= 1.5, [HAVE_MCE=yes], [HAVE_MCE=no]) diff --git a/mission-control-plugins/account.c b/mission-control-plugins/account.c index 62318d4..1744ef6 100644 --- a/mission-control-plugins/account.c +++ b/mission-control-plugins/account.c @@ -290,6 +290,7 @@ mcp_account_manager_parameter_make_secret (const McpAccountManager *mcpa, * Changed in 5.17: instead of a map from string to GValue, the last * argument is the result of calling IdentifyAccount on the parameters, * which normalizes the account's name in a protocol-dependent way. + * Use mcp_account_manager_identify_account_async() to do that. * * Returns: the newly allocated account name, which should be freed * once the caller is done with it. @@ -308,6 +309,47 @@ mcp_account_manager_get_unique_name (McpAccountManager *mcpa, return iface->unique_name (mcpa, manager, protocol, identification); } +void +mcp_account_manager_identify_account_async (McpAccountManager *mcpa, + const gchar *manager, + const gchar *protocol, + GVariant *parameters, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa); + + g_return_if_fail (iface != NULL); + g_return_if_fail (iface->identify_account_async != NULL); + g_return_if_fail (iface->identify_account_finish != NULL); + + g_return_if_fail (manager != NULL); + g_return_if_fail (protocol != NULL); + g_return_if_fail (parameters != NULL); + g_return_if_fail (g_variant_is_of_type (parameters, G_VARIANT_TYPE_VARDICT)); + + iface->identify_account_async (mcpa, manager, protocol, parameters, + cancellable, callback, user_data); +} + +/** + * Returns: (transfer full): a newly allocated string, free with g_free() + */ +gchar * +mcp_account_manager_identify_account_finish (McpAccountManager *mcpa, + GAsyncResult *res, + GError **error) +{ + McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa); + + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (iface->identify_account_async != NULL, NULL); + g_return_val_if_fail (iface->identify_account_finish != NULL, NULL); + + return iface->identify_account_finish (mcpa, res, error); +} + /** * mcp_account_manager_escape_value_from_keyfile: * @mcpa: a #McpAccountManager diff --git a/mission-control-plugins/account.h b/mission-control-plugins/account.h index a476342..4015457 100644 --- a/mission-control-plugins/account.h +++ b/mission-control-plugins/account.h @@ -101,6 +101,17 @@ gboolean mcp_account_manager_init_value_for_attribute ( GValue *value, const gchar *attribute); +void mcp_account_manager_identify_account_async (McpAccountManager *mcpa, + const gchar *manager, + const gchar *protocol, + GVariant *parameters, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gchar *mcp_account_manager_identify_account_finish (McpAccountManager *mcpa, + GAsyncResult *res, + GError **error); + G_END_DECLS #endif diff --git a/mission-control-plugins/implementation.h b/mission-control-plugins/implementation.h index 29d2937..2ad2893 100644 --- a/mission-control-plugins/implementation.h +++ b/mission-control-plugins/implementation.h @@ -128,6 +128,17 @@ struct _McpAccountManagerIface { const gchar *parameter, GVariant *value, McpParameterFlags flags); + + void (* identify_account_async) (McpAccountManager *mcpa, + const gchar *manager, + const gchar *protocol, + GVariant *parameters, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gchar * (* identify_account_finish) (McpAccountManager *mcpa, + GAsyncResult *res, + GError **error); }; G_END_DECLS diff --git a/src/mcd-account-manager.c b/src/mcd-account-manager.c index 0a19de1..029c0c2 100644 --- a/src/mcd-account-manager.c +++ b/src/mcd-account-manager.c @@ -105,6 +105,9 @@ typedef struct typedef struct { McdAccountManager *account_manager; + gchar *cm_name; + gchar *protocol_name; + gchar *display_name; GHashTable *parameters; GHashTable *properties; McdGetAccountCb callback; @@ -650,6 +653,10 @@ mcd_create_account_data_free (McdCreateAccountData *cad) if (G_UNLIKELY (cad->error)) g_error_free (cad->error); + g_free (cad->cm_name); + g_free (cad->protocol_name); + g_free (cad->display_name); + g_slice_free (McdCreateAccountData, cad); } @@ -781,91 +788,120 @@ complete_account_creation (McdAccount *account, cad); } -void -_mcd_account_manager_create_account (McdAccountManager *account_manager, - const gchar *manager, - const gchar *protocol, - const gchar *display_name, - GHashTable *params, - GHashTable *properties, - McdGetAccountCb callback, - gpointer user_data, - GDestroyNotify destroy) +static void +identify_account_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) { - McdAccountManagerPrivate *priv = account_manager->priv; - McdStorage *storage = priv->storage; - McdCreateAccountData *cad; - McdAccount *account; - gchar *unique_name = NULL; + McdStorage *storage = MCD_STORAGE (source_object); + McdCreateAccountData *cad = user_data; const gchar *provider; - GError *e = NULL; - const gchar *id; + gchar *id; + gchar *unique_name; + McdAccount *account; - DEBUG ("called"); - if (G_UNLIKELY (manager == NULL || manager[0] == 0 || - protocol == NULL || protocol[0] == 0)) + id = mcp_account_manager_identify_account_finish ( + MCP_ACCOUNT_MANAGER (storage), result, &cad->error); + + if (id == NULL) { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Invalid parameters"}; - callback (account_manager, NULL, &error, user_data); - if (destroy) - destroy (user_data); + cad->callback (cad->account_manager, NULL, cad->error, cad->user_data); + mcd_create_account_data_free (cad); return; } - provider = tp_asv_get_string (properties, + provider = tp_asv_get_string (cad->properties, TP_PROP_ACCOUNT_INTERFACE_STORAGE_STORAGE_PROVIDER); - id = tp_asv_get_string (params, "account"); - - if (id == NULL) - id = "account"; - unique_name = mcd_storage_create_account (storage, provider, - manager, protocol, id, - &e); + cad->cm_name, cad->protocol_name, + id, &cad->error); if (unique_name == NULL) { - callback (account_manager, NULL, e, user_data); - g_clear_error (&e); - if (destroy) - destroy (user_data); + g_free (id); + cad->callback (cad->account_manager, NULL, cad->error, cad->user_data); + mcd_create_account_data_free (cad); return; } /* create the basic account keys */ mcd_storage_set_string (storage, unique_name, - MC_ACCOUNTS_KEY_MANAGER, manager); + MC_ACCOUNTS_KEY_MANAGER, cad->cm_name); mcd_storage_set_string (storage, unique_name, - MC_ACCOUNTS_KEY_PROTOCOL, protocol); + MC_ACCOUNTS_KEY_PROTOCOL, cad->protocol_name); + g_free (id); - if (display_name != NULL) + if (cad->display_name != NULL) mcd_storage_set_string (storage, unique_name, - MC_ACCOUNTS_KEY_DISPLAY_NAME, display_name); + MC_ACCOUNTS_KEY_DISPLAY_NAME, + cad->display_name); - account = mcd_account_new (account_manager, unique_name, priv->minotaur); + account = mcd_account_new (cad->account_manager, unique_name, + cad->account_manager->priv->minotaur); g_free (unique_name); if (G_LIKELY (account)) { - cad = g_slice_new (McdCreateAccountData); - cad->account_manager = account_manager; - cad->parameters = g_hash_table_ref (params); - cad->properties = (properties ? g_hash_table_ref (properties) : NULL); - cad->callback = callback; - cad->user_data = user_data; - cad->destroy = destroy; - cad->error = NULL; _mcd_account_load (account, complete_account_creation, cad); } else { GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "" }; + cad->callback (cad->account_manager, NULL, &error, cad->user_data); + mcd_create_account_data_free (cad); + } +} + +void +_mcd_account_manager_create_account (McdAccountManager *account_manager, + const gchar *manager, + const gchar *protocol, + const gchar *display_name, + GHashTable *params, + GHashTable *properties, + McdGetAccountCb callback, + gpointer user_data, + GDestroyNotify destroy) +{ + McdAccountManagerPrivate *priv = account_manager->priv; + McdStorage *storage = priv->storage; + McdCreateAccountData *cad; + GValue value = G_VALUE_INIT; + GVariant *variant_params; + + DEBUG ("called"); + if (G_UNLIKELY (manager == NULL || manager[0] == 0 || + protocol == NULL || protocol[0] == 0)) + { + GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, + "Invalid parameters"}; callback (account_manager, NULL, &error, user_data); if (destroy) destroy (user_data); + return; } + + cad = g_slice_new (McdCreateAccountData); + cad->account_manager = account_manager; + cad->cm_name = g_strdup (manager); + cad->protocol_name = g_strdup (protocol); + cad->display_name = g_strdup (display_name); + cad->parameters = g_hash_table_ref (params); + cad->properties = (properties ? g_hash_table_ref (properties) : NULL); + cad->callback = callback; + cad->user_data = user_data; + cad->destroy = destroy; + cad->error = NULL; + + g_value_init (&value, TP_HASH_TYPE_STRING_VARIANT_MAP); + g_value_set_static_boxed (&value, params); + variant_params = dbus_g_value_build_g_variant (&value); + g_value_unset (&value); + + mcp_account_manager_identify_account_async (MCP_ACCOUNT_MANAGER (storage), + manager, protocol, variant_params, NULL, identify_account_cb, cad); + g_variant_unref (variant_params); } static void diff --git a/src/mcd-storage.c b/src/mcd-storage.c index dfe972d..d52e345 100644 --- a/src/mcd-storage.c +++ b/src/mcd-storage.c @@ -611,6 +611,82 @@ unique_name (const McpAccountManager *ma, return NULL; } +static void +identify_account_cb (TpProxy *proxy, + const gchar *identification, + const GError *error, + gpointer task, + GObject *weak_object G_GNUC_UNUSED) +{ + if (error == NULL) + { + g_task_return_pointer (task, g_strdup (identification), g_free); + } + else if (g_error_matches (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED) || + g_error_matches (error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)) + { + g_task_return_pointer (task, g_strdup (g_task_get_task_data (task)), + g_free); + } + else + { + g_task_return_error (task, g_error_copy (error)); + } +} + +static gchar * +identify_account_finish (McpAccountManager *mcpa, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, mcpa), NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +identify_account_async (McpAccountManager *mcpa, + const gchar *manager, + const gchar *protocol_name, + GVariant *parameters, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + McdStorage *self = MCD_STORAGE (mcpa); + GError *error = NULL; + TpProtocol *protocol; + GTask *task; + GValue value = G_VALUE_INIT; + const gchar *base; + + task = g_task_new (self, cancellable, callback, user_data); + + /* in case IdentifyAccount fails and we need to make something up */ + if (!g_variant_lookup (parameters, "account", "&s", &base)) + base = "account"; + + g_task_set_task_data (task, g_strdup (base), g_free); + + protocol = tp_protocol_new (self->dbusd, manager, protocol_name, + NULL, &error); + + if (protocol == NULL) + { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + dbus_g_value_parse_g_variant (parameters, &value); + + tp_cli_protocol_call_identify_account (protocol, -1, + g_value_get_boxed (&value), identify_account_cb, task, g_object_unref, + NULL); + g_object_unref (protocol); + g_value_unset (&value); +} + /* sort in descending order of priority (ie higher prio => earlier in list) */ static gint account_storage_cmp (gconstpointer a, gconstpointer b) @@ -2062,6 +2138,8 @@ plugin_iface_init (McpAccountManagerIface *iface, iface->is_secret = is_secret; iface->make_secret = make_secret; iface->unique_name = unique_name; + iface->identify_account_async = identify_account_async; + iface->identify_account_finish = identify_account_finish; iface->list_keys = list_keys; iface->escape_value_for_keyfile = mcpa_escape_value_for_keyfile; iface->escape_variant_for_keyfile = mcpa_escape_variant_for_keyfile; diff --git a/tests/twisted/account-manager/create-with-properties.py b/tests/twisted/account-manager/create-with-properties.py index 8d02e2d..fb276c4 100644 --- a/tests/twisted/account-manager/create-with-properties.py +++ b/tests/twisted/account-manager/create-with-properties.py @@ -50,7 +50,7 @@ def test(q, bus, mc): assert (cs.ACCOUNT + '.Supersedes') in supported assertContains(cs.ACCOUNT + '.Service', supported) - params = dbus.Dictionary({"account": "anarki@example.com", + params = dbus.Dictionary({"account": "aNaRkI@eXaMpLe.CoM", "password": "secrecy"}, signature='sv') simulated_cm = SimulatedConnectionManager(q, bus) @@ -94,6 +94,9 @@ def test(q, bus, mc): ) account_path = ret.value[0] assert am_signal.args == [account_path, True], am_signal.args + # We called IdentifyAccount, which normalized the silly account name. + # The _xx hex-escaping and the trailing digit are implementation details. + assert account_path.endswith('/anarki_40example_2ecom0'), account_path assert account_path is not None -- 1.8.4.rc3