summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--mission-control-plugins/account-storage.c598
-rw-r--r--mission-control-plugins/account-storage.h203
-rw-r--r--mission-control-plugins/account.c286
-rw-r--r--mission-control-plugins/account.h45
-rw-r--r--mission-control-plugins/implementation.h48
-rw-r--r--mission-control-plugins/loader.c15
-rw-r--r--mission-control-plugins/mission-control-plugins.h9
-rw-r--r--src/mcd-account-addressing.c4
-rw-r--r--src/mcd-account-manager-default.c517
-rw-r--r--src/mcd-account-manager-default.h1
-rw-r--r--src/mcd-account-manager.c278
-rw-r--r--src/mcd-account-manager.h9
-rw-r--r--src/mcd-account.c283
-rw-r--r--src/mcd-account.h23
-rw-r--r--src/mcd-storage.c826
-rw-r--r--src/mcd-storage.h22
-rw-r--r--tests/twisted/Makefile.am9
-rw-r--r--tests/twisted/account-manager/auto-connect.py9
-rw-r--r--tests/twisted/account-manager/avatar-refresh.py22
-rw-r--r--tests/twisted/account-manager/bad-cm.py11
-rw-r--r--tests/twisted/account-storage/5-12.py29
-rw-r--r--tests/twisted/account-storage/5-14.py29
-rw-r--r--tests/twisted/account-storage/create-new.py136
-rw-r--r--tests/twisted/account-storage/default-keyring-storage.py317
-rw-r--r--tests/twisted/account-storage/load-keyfiles.py274
-rw-r--r--tests/twisted/account-storage/storage_helper.py174
-rw-r--r--tests/twisted/dbus-account-plugin.c521
-rw-r--r--tests/twisted/mc-debug-server.c30
-rw-r--r--tests/twisted/mcp-account-diversion.c259
-rw-r--r--tests/twisted/mctest.py38
31 files changed, 2341 insertions, 2686 deletions
diff --git a/configure.ac b/configure.ac
index 6a2f35aa..22b7f0a4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -35,7 +35,7 @@ esac
# If API has been removed or changed since last release, change MCP_API (which
# is part of the directory name under /usr/include) to the version that
# changed it
-MCP_API_VERSION=5.15
+MCP_API_VERSION=5.18
AC_SUBST([MCP_API_VERSION])
# If ABI has been removed or changed since last release
diff --git a/mission-control-plugins/account-storage.c b/mission-control-plugins/account-storage.c
index b51c1264..288df077 100644
--- a/mission-control-plugins/account-storage.c
+++ b/mission-control-plugins/account-storage.c
@@ -56,18 +56,17 @@
* iface->desc = "The FOO storage backend";
* iface->provider = "org.freedesktop.Telepathy.MissionControl5.FooStorage";
*
- * iface->get = foo_plugin_get;
- * iface->set = foo_plugin_get;
- * iface->delete = foo_plugin_delete;
+ * iface->delete_async = foo_plugin_delete_async;
+ * iface->delete_finish = foo_plugin_delete_finish;
* iface->commit = foo_plugin_commit;
- * iface->commit_one = foo_plugin_commit_one;
* iface->list = foo_plugin_list;
* iface->ready = foo_plugin_ready;
* iface->get_identifier = foo_plugin_get_identifier;
* iface->get_additional_info = foo_plugin_get_additional_info;
* iface->get_restrictions = foo_plugin_get_restrictions;
* iface->create = foo_plugin_create;
- * iface->owns = foo_plugin_owns;
+ * iface->get_attribute = foo_plugin_get_attribute;
+ * iface->get_parameter = foo_plugin_get_parameter;
* iface->set_attribute = foo_plugin_set_attribute;
* iface->set_parameter = foo_plugin_set_parameter;
* }
@@ -112,17 +111,79 @@ enum
static guint signals[NO_SIGNAL] = { 0 };
-static gboolean
-default_set (const McpAccountStorage *storage,
- const McpAccountManager *am,
+static void
+default_delete_async (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *account,
- const gchar *key,
- const gchar *val)
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- return FALSE;
+ g_task_report_new_error (storage, callback, user_data,
+ default_delete_async, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED,
+ "This storage plugin cannot delete accounts");
+}
+
+static gboolean
+default_delete_finish (McpAccountStorage *storage,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
}
static gboolean
+default_commit (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account)
+{
+ return FALSE;
+}
+
+static gchar *
+default_create (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *manager,
+ const gchar *protocol,
+ const gchar *identification,
+ GError **error)
+{
+ g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED,
+ "This storage does not implement the create() function");
+ return NULL;
+}
+
+static void
+default_ready (McpAccountStorage *storage,
+ McpAccountManager *am)
+{
+ /* do nothing */
+}
+
+static void
+default_get_identifier (McpAccountStorage *storage,
+ const gchar *account,
+ GValue *identifier)
+{
+ g_value_init (identifier, G_TYPE_STRING);
+ g_value_set_string (identifier, account);
+}
+
+static GHashTable *
+default_get_additional_info (McpAccountStorage *storage,
+ const gchar *account)
+{
+ return g_hash_table_new (g_str_hash, g_str_equal);
+}
+
+static TpStorageRestrictionFlags
+default_get_restrictions (McpAccountStorage *storage,
+ const gchar *account)
+{
+ return 0;
+}
+
+static McpAccountStorageSetResult
default_set_attribute (McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account,
@@ -130,10 +191,10 @@ default_set_attribute (McpAccountStorage *storage,
GVariant *value,
McpAttributeFlags flags)
{
- return FALSE;
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
}
-static gboolean
+static McpAccountStorageSetResult
default_set_parameter (McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account,
@@ -141,20 +202,7 @@ default_set_parameter (McpAccountStorage *storage,
GVariant *value,
McpParameterFlags flags)
{
- return FALSE;
-}
-
-static gboolean
-default_owns (McpAccountStorage *storage,
- McpAccountManager *am,
- const gchar *account)
-{
- /* This has the side-effect of pushing the "manager" key back into @am,
- * but that should be a no-op in practice: we always call this
- * method in priority order and stop at the first one that says "yes",
- * and @am's idea of what "manager" is should have come from that same
- * plugin anyway. */
- return mcp_account_storage_get (storage, am, account, "manager");
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
}
static void
@@ -164,8 +212,14 @@ class_init (gpointer klass,
GType type = G_TYPE_FROM_CLASS (klass);
McpAccountStorageIface *iface = klass;
- iface->owns = default_owns;
- iface->set = default_set;
+ iface->create = default_create;
+ iface->delete_async = default_delete_async;
+ iface->delete_finish = default_delete_finish;
+ iface->commit = default_commit;
+ iface->ready = default_ready;
+ iface->get_identifier = default_get_identifier;
+ iface->get_additional_info = default_get_additional_info;
+ iface->get_restrictions = default_get_restrictions;
iface->set_attribute = default_set_attribute;
iface->set_parameter = default_set_parameter;
@@ -193,20 +247,20 @@ class_init (gpointer klass,
/**
* McpAccountStorage::altered-one
* @account: the unique name of the altered account
- * @name: the name of the altered property (its key)
+ * @name: either an attribute name such as DisplayName,
+ * or "param-" plus a parameter name, e.g. "param-require-encryption"
*
* Emitted if an external entity alters an account
* in the backend that the emitting plugin handles.
*
- * Before emitting this signal, the plugin must call
- * either mcp_account_manager_set_attribute(),
- * either mcp_account_manager_set_parameter() or
- * mcp_account_manager_set_value() to push the new value
- * into the account manager.
+ * Before emitting this signal, the plugin must update its
+ * internal cache (if any) so that mcp_account_storage_get_attribute()
+ * or mcp_account_storage_get_parameter() will return the new value
+ * when queried.
*
- * Note that mcp_account_manager_set_parameter() does not use the
- * "param-" prefix, but this signal and mcp_account_manager_set_value()
- * both do.
+ * Note that mcp_account_manager_get_parameter() and
+ * mcp_account_manager_set_parameter() do not use the
+ * "param-" prefix, but this signal does.
*
* Should not be fired until mcp_account_storage_ready() has been called
*/
@@ -239,8 +293,11 @@ class_init (gpointer klass,
* Emitted if an external entity enables/disables an account
* in the backend the emitting plugin handles. This is similar to
* emitting #McpAccountStorage::altered-one for the attribute
- * "Enabled", except that the plugin is not required to call
- * a function like mcp_account_manager_set_value() first.
+ * "Enabled".
+ *
+ * Before emitting this signal, the plugin must update its
+ * internal cache (if any) so that mcp_account_storage_get_attribute()
+ * will return the new value for Enabled when queried.
*
* Should not be fired until mcp_account_storage_ready() has been called
*
@@ -316,7 +373,6 @@ mcp_account_storage_get_type (void)
* @commit: implementation of mcp_account_storage_commit()
* @list: implementation of mcp_account_storage_list()
* @ready: implementation of mcp_account_storage_ready()
- * @commit_one: implementation of mcp_account_storage_commit_one()
* @get_identifier: implementation of mcp_account_storage_get_identifier()
* @get_additional_info: implementation of
* mcp_account_storage_get_additional_info()
@@ -361,7 +417,7 @@ mcp_account_storage_get_type (void)
* Returns: the priority of this plugin
**/
gint
-mcp_account_storage_priority (const McpAccountStorage *storage)
+mcp_account_storage_priority (McpAccountStorage *storage)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
@@ -371,111 +427,89 @@ mcp_account_storage_priority (const McpAccountStorage *storage)
}
/**
- * McpAccountStorageGetFunc:
- * @storage: the account storage plugin
- * @am: object used to call back into the account manager
- * @account: the unique name of the account
- * @key: the setting whose value we wish to fetch: either an attribute
- * like "DisplayName", or "param-" plus a parameter like "account"
- *
- * An implementation of mcp_account_storage_get().
- *
- * Returns: %TRUE if @storage is responsible for @account
- */
-
-/**
- * mcp_account_storage_get:
+ * mcp_account_storage_get_attribute:
* @storage: an #McpAccountStorage instance
* @am: an #McpAccountManager instance
* @account: the unique name of the account
- * @key: the setting whose value we wish to fetch: either an attribute
- * like "DisplayName", or "param-" plus a parameter like "account"
- *
- * Get a value from the plugin's in-memory cache.
- * Before emitting this signal, the plugin must call
- * either mcp_account_manager_set_attribute(),
- * mcp_account_manager_set_parameter(),
- * or mcp_account_manager_set_value() and (if appropriate)
- * mcp_account_manager_parameter_make_secret()
- * before returning from this method call.
- *
- * Note that mcp_account_manager_set_parameter() does not use the
- * "param-" prefix, even if called from this function.
- *
- * If @key is %NULL the plugin should iterate through all attributes and
- * parameters, and push each of them into @am, as if this method had
- * been called once for each attribute or parameter. It must then return
- * %TRUE if any attributes or parameters were found, or %FALSE if it
- * was not responsible for @account.
- *
- * Returns: %TRUE if @storage is responsible for @account
+ * @attribute: the name of an attribute, e.g. "DisplayName"
+ * @type: the expected type of @attribute, as a hint for
+ * legacy account storage plugins that do not store attributes' types
+ * @flags: (allow-none) (out): used to return attribute flags
+ *
+ * Retrieve an attribute.
+ *
+ * There is no default implementation.
+ * All account storage plugins must override this method.
+ *
+ * The returned variant does not necessarily have to match @type:
+ * Mission Control will coerce it to an appropriate type if required. In
+ * particular, plugins that store strongly-typed attributes may return
+ * the stored type, not the expected type, if they differ.
+ *
+ * Returns: (transfer full): the value of the attribute, or %NULL if it
+ * is not present
*/
-gboolean
-mcp_account_storage_get (const McpAccountStorage *storage,
+GVariant *
+mcp_account_storage_get_attribute (McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account,
- const gchar *key)
+ const gchar *attribute,
+ const GVariantType *type,
+ McpAttributeFlags *flags)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
- SDEBUG (storage, "");
+ SDEBUG (storage, "%s.%s (type '%.*s')", account, attribute,
+ (int) g_variant_type_get_string_length (type),
+ g_variant_type_peek_string (type));
+
g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (iface->get != NULL, FALSE);
+ g_return_val_if_fail (iface->get_attribute != NULL, FALSE);
- return iface->get (storage, am, account, key);
+ return iface->get_attribute (storage, am, account, attribute, type, flags);
}
/**
- * McpAccountStorageSetFunc:
- * @storage: an #McpAccountStorage instance
- * @am: an #McpAccountManager instance
- * @account: the unique name of the account
- * @key: the setting whose value we wish to store: either an attribute
- * like "DisplayName", or "param-" plus a parameter like "account"
- * @val: a non-%NULL value for @key
- *
- * An implementation of mcp_account_storage_set().
- *
- * Returns: %TRUE if @storage is responsible for @account
- */
-
-/**
- * mcp_account_storage_set:
+ * mcp_account_storage_get_parameter:
* @storage: an #McpAccountStorage instance
* @am: an #McpAccountManager instance
* @account: the unique name of the account
- * @key: the non-%NULL setting whose value we wish to store: either an
- * attribute like "DisplayName", or "param-" plus a parameter like "account"
- * @value: a value to associate with @key, escaped as if for a #GKeyFile
+ * @parameter: the name of a parameter, e.g. "require-encryption"
+ * @type: the expected type of @parameter, as a hint for
+ * legacy account storage plugins that do not store parameters' types
+ * @flags: (allow-none) (out): used to return parameter flags
*
- * The plugin is expected to either quickly and synchronously
- * update its internal cache of values with @value, or to
- * decline to store the setting.
+ * Retrieve a parameter.
*
- * The plugin is not expected to write to its long term storage
- * at this point. It can expect Mission Control to call either
- * mcp_account_storage_commit() or mcp_account_storage_commit_one()
- * after a short delay.
+ * There is no default implementation.
+ * All account storage plugins must override this method.
*
- * Plugins that implement mcp_storage_set_attribute() and
- * mcp_account_storage_set_parameter() can just return %FALSE here.
- * There is a default implementation, which just returns %FALSE.
+ * The returned variant does not necessarily have to match @type:
+ * Mission Control will coerce it to an appropriate type if required. In
+ * particular, plugins that store strongly-typed parameters may return
+ * the stored type, not the expected type, if they differ.
*
- * Returns: %TRUE if the attribute was claimed, %FALSE otherwise
+ * Returns: (transfer full): the value of the parameter, or %NULL if it
+ * is not present
*/
-gboolean
-mcp_account_storage_set (const McpAccountStorage *storage,
- const McpAccountManager *am,
+GVariant *
+mcp_account_storage_get_parameter (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *account,
- const gchar *key,
- const gchar *value)
+ const gchar *parameter,
+ const GVariantType *type,
+ McpParameterFlags *flags)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
- SDEBUG (storage, "");
+ SDEBUG (storage, "%s.%s (type '%.*s')", account, parameter,
+ (int) g_variant_type_get_string_length (type),
+ g_variant_type_peek_string (type));
+
g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->get_parameter != NULL, FALSE);
- return iface->set (storage, am, account, key, value);
+ return iface->get_parameter (storage, am, account, parameter, type, flags);
}
/**
@@ -484,7 +518,8 @@ mcp_account_storage_set (const McpAccountStorage *storage,
* @am: an #McpAccountManager instance
* @account: the unique name of the account
* @attribute: the name of an attribute, e.g. "DisplayName"
- * @value: a value to associate with @attribute
+ * @value: (allow-none): a value to associate with @attribute,
+ * or %NULL to delete
* @flags: flags influencing how the attribute is to be stored
*
* Store an attribute.
@@ -496,15 +531,14 @@ mcp_account_storage_set (const McpAccountStorage *storage,
* The plugin is not expected to write to its long term storage
* at this point.
*
- * There is a default implementation, which just returns %FALSE.
- * Mission Control will call mcp_account_storage_set() instead,
- * using a keyfile-escaped version of @value.
+ * There is a default implementation, which just returns %FALSE for read-only
+ * storage plugins.
*
* Returns: %TRUE if the attribute was claimed, %FALSE otherwise
*
* Since: 5.15.0
*/
-gboolean
+McpAccountStorageSetResult
mcp_account_storage_set_attribute (McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account,
@@ -514,9 +548,13 @@ mcp_account_storage_set_attribute (McpAccountStorage *storage,
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
- SDEBUG (storage, "");
- g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (iface->set_attribute != NULL, FALSE);
+ SDEBUG (storage, "%s.%s (type '%s')", account, attribute,
+ value == NULL ? "null" : g_variant_get_type_string (value));
+
+ g_return_val_if_fail (iface != NULL,
+ MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
+ g_return_val_if_fail (iface->set_attribute != NULL,
+ MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
return iface->set_attribute (storage, am, account, attribute, value, flags);
}
@@ -528,7 +566,8 @@ mcp_account_storage_set_attribute (McpAccountStorage *storage,
* @account: the unique name of the account
* @parameter: the name of a parameter, e.g. "account" (note that there
* is no "param-" prefix here)
- * @value: a value to associate with @parameter
+ * @value: (allow-none): a value to associate with @parameter,
+ * or %NULL to delete
* @flags: flags influencing how the parameter is to be stored
*
* Store a parameter.
@@ -540,16 +579,14 @@ mcp_account_storage_set_attribute (McpAccountStorage *storage,
* The plugin is not expected to write to its long term storage
* at this point.
*
- * There is a default implementation, which just returns %FALSE.
- * Mission Control will call mcp_account_storage_set() instead,
- * using "param-" + @parameter as key and a keyfile-escaped version
- * of @value as value.
+ * There is a default implementation, which just returns %FALSE for read-only
+ * storage plugins.
*
* Returns: %TRUE if the parameter was claimed, %FALSE otherwise
*
* Since: 5.15.0
*/
-gboolean
+McpAccountStorageSetResult
mcp_account_storage_set_parameter (McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account,
@@ -559,9 +596,14 @@ mcp_account_storage_set_parameter (McpAccountStorage *storage,
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
- SDEBUG (storage, "");
+ SDEBUG (storage, "%s.%s (type '%s')", account, parameter,
+ value == NULL ? "null" : g_variant_get_type_string (value));
+
g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (iface->set_parameter != NULL, FALSE);
+ g_return_val_if_fail (iface != NULL,
+ MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
+ g_return_val_if_fail (iface->set_parameter != NULL,
+ MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
return iface->set_parameter (storage, am, account, parameter, value, flags);
}
@@ -603,13 +645,20 @@ mcp_account_storage_set_parameter (McpAccountStorage *storage,
* #McpAccountStorage::created signal should not be emitted for this account,
* not even when mcp_account_storage_commit() will be called.
*
+ * The default implementation just returns %NULL, and is appropriate for
+ * read-only storage.
+ *
+ * Since Mission Control 5.17, all storage plugins in which new accounts
+ * can be created by Mission Control must implement this method.
+ * Previously, it was not mandatory.
+ *
* Returns: (transfer full): the newly allocated account name, which should
* be freed once the caller is done with it, or %NULL if that couldn't
* be done.
*/
gchar *
-mcp_account_storage_create (const McpAccountStorage *storage,
- const McpAccountManager *am,
+mcp_account_storage_create (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *manager,
const gchar *protocol,
const gchar *identification,
@@ -617,76 +666,84 @@ mcp_account_storage_create (const McpAccountStorage *storage,
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
- g_return_val_if_fail (iface != NULL, NULL);
+ SDEBUG (storage, "%s/%s \"%s\"", manager, protocol, identification);
- if (iface->create == NULL)
- {
- g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED,
- "This storage does not implement create function");
- return NULL;
- }
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->create != NULL, NULL);
return iface->create (storage, am, manager, protocol, identification, error);
}
/**
- * McpAccountStorageDeleteFunc:
+ * mcp_account_storage_delete_async:
* @storage: an #McpAccountStorage instance
* @am: an #McpAccountManager instance
* @account: the unique name of the account
- * @key: (allow-none): the setting whose value we wish to store - either an
- * attribute like "DisplayName", or "param-" plus a parameter like
- * "account" - or %NULL to delete the entire account
+ * @cancellable: (allow-none): optionally used to (try to) cancel the operation
+ * @callback: called on success or failure
+ * @user_data: data for @callback
*
- * An implementation of mcp_account_storage_delete().
+ * Delete the account @account, and commit the change,
+ * emitting #McpAccountStorage::deleted afterwards.
*
- * Returns: %TRUE if the setting or settings are not
- * the plugin's cache after this operation, %FALSE otherwise.
+ * Unlike the 'delete' virtual method in earlier MC versions, this
+ * function is expected to commit the change to long-term storage,
+ * is expected to emit #McpAccountStorage::deleted, and is
+ * not called for the deletion of individual attributes or parameters.
+ *
+ * The default implementation just returns failure (asynchronously),
+ * and is appropriate for read-only storage.
+ *
+ * Implementations that override delete_async must also override
+ * delete_finish.
*/
+void
+mcp_account_storage_delete_async (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
+
+ SDEBUG (storage, "%s", account);
+
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->delete_async != NULL);
+
+ iface->delete_async (storage, am, account, cancellable, callback, user_data);
+}
/**
- * mcp_account_storage_delete:
+ * mcp_account_storage_delete_finish:
* @storage: an #McpAccountStorage instance
- * @am: an #McpAccountManager instance
- * @account: the unique name of the account
- * @key: (allow-none): the setting whose value we wish to store - either an
- * attribute like "DisplayName", or "param-" plus a parameter like
- * "account" - or %NULL to delete the entire account
- *
- * The plugin is expected to remove the setting for @key from its
- * internal cache and to remember that its state has changed, so
- * that it can delete said setting from its long term storage if
- * its long term storage method makes this necessary.
+ * @res: the result of mcp_account_storage_delete_async()
+ * @error: used to raise an error if %FALSE is returned
*
- * If @key is %NULL, the plugin should forget all its settings for
- * @account,and remember to delete the entire account from its storage later.
+ * Process the result of mcp_account_storage_delete_async().
*
- * The plugin is not expected to update its long term storage at
- * this point.
- *
- * Returns: %TRUE if the setting or settings are not
- * the plugin's cache after this operation, %FALSE otherwise.
- * This is very unlikely to ever be %FALSE, as a plugin is always
- * expected to be able to manipulate its own cache.
+ * Returns: %TRUE on success, %FALSE if the account could not be deleted
*/
gboolean
-mcp_account_storage_delete (const McpAccountStorage *storage,
- const McpAccountManager *am,
- const gchar *account,
- const gchar *key)
+mcp_account_storage_delete_finish (McpAccountStorage *storage,
+ GAsyncResult *result,
+ GError **error)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
SDEBUG (storage, "");
g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->delete_finish != NULL, FALSE);
- return iface->delete (storage, am, account, key);
+ return iface->delete_finish (storage, result, error);
}
/**
* McpAccountStorageCommitFunc:
* @storage: an #McpAccountStorage instance
* @am: an #McpAccountManager instance
+ * @account: the unique suffix of an account's object path
*
* An implementation of mcp_account_storage_commit().
*
@@ -697,6 +754,7 @@ mcp_account_storage_delete (const McpAccountStorage *storage,
* mcp_account_storage_commit:
* @storage: an #McpAccountStorage instance
* @am: an #McpAccountManager instance
+ * @account: the unique suffix of an account's object path
*
* The plugin is expected to write its cache to long term storage,
* deleting, adding or updating entries in said storage as needed.
@@ -705,87 +763,28 @@ mcp_account_storage_delete (const McpAccountStorage *storage,
* not required to have finished its commit operation when it returns,
* merely to have started the operation.
*
- * If the @commit_one method is implemented, it will be called preferentially
- * if only one account is to be committed. If the @commit_one method is
- * implemented but @commit is not, @commit_one will be called with
- * @account_name = %NULL to commit all accounts.
+ * The default implementation just returns %FALSE, and is appropriate for
+ * read-only storage.
*
- * Returns: %TRUE if the commit process was started (but not necessarily
- * completed) successfully; %FALSE if there was a problem that was immediately
- * obvious.
- */
-gboolean
-mcp_account_storage_commit (const McpAccountStorage *storage,
- const McpAccountManager *am)
-{
- McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
-
- SDEBUG (storage, "committing all accounts");
- g_return_val_if_fail (iface != NULL, FALSE);
-
- if (iface->commit != NULL)
- {
- return iface->commit (storage, am);
- }
- else if (iface->commit_one != NULL)
- {
- return iface->commit_one (storage, am, NULL);
- }
- else
- {
- SDEBUG (storage,
- "neither commit nor commit_one is implemented; cannot save accounts");
- return FALSE;
- }
-}
-
-/**
- * McpAccountStorageCommitOneFunc:
- * @storage: an #McpAccountStorage instance
- * @am: an #McpAccountManager instance
- * @account: (allow-none): the unique suffix of an account's object path,
- * or %NULL
- *
- * An implementation of mcp_account_storage_commit_one().
- *
- * Returns: %TRUE if the commit process was started successfully
- */
-
-/**
- * mcp_account_storage_commit_one:
- * @storage: an #McpAccountStorage instance
- * @am: an #McpAccountManager instance
- * @account: (allow-none): the unique suffix of an account's object path,
- * or %NULL if all accounts are to be committed and
- * mcp_account_storage_commit() is unimplemented
- *
- * The same as mcp_account_storage_commit(), but only commit the given
- * account. This is optional to implement; the default implementation
- * is to call @commit.
- *
- * If both mcp_account_storage_commit_one() and mcp_account_storage_commit()
- * are implemented, Mission Control will never pass @account = %NULL to
- * this method.
+ * Mission Control 5.17+ no longer requires plugins to cope with
+ * account == NULL.
*
* Returns: %TRUE if the commit process was started (but not necessarily
* completed) successfully; %FALSE if there was a problem that was immediately
* obvious.
*/
gboolean
-mcp_account_storage_commit_one (const McpAccountStorage *storage,
- const McpAccountManager *am,
+mcp_account_storage_commit (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *account)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
SDEBUG (storage, "called for %s", account ? account : "<all accounts>");
g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->commit != NULL, FALSE);
- if (iface->commit_one != NULL)
- return iface->commit_one (storage, am, account);
- else
- /* Fall back to plain ->commit() */
- return mcp_account_storage_commit (storage, am);
+ return iface->commit (storage, am, account);
}
/**
@@ -809,19 +808,23 @@ mcp_account_storage_commit_one (const McpAccountStorage *storage,
* This method is called only at initialisation time, before the dbus name
* has been claimed, and is the only one permitted to block.
*
+ * There is no default implementation. All implementations of this interface
+ * must override this method.
+ *
* Returns: (element-type utf8) (transfer full): a list of account names that
* the plugin has settings for. The account names should be freed with
* g_free(), and the list with g_list_free(), when the caller is done with
* them.
*/
GList *
-mcp_account_storage_list (const McpAccountStorage *storage,
- const McpAccountManager *am)
+mcp_account_storage_list (McpAccountStorage *storage,
+ McpAccountManager *am)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
SDEBUG (storage, "");
g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->list != NULL, NULL);
return iface->list (storage, am);
}
@@ -842,20 +845,22 @@ mcp_account_storage_list (const McpAccountStorage *storage,
* Informs the plugin that it is now permitted to create new accounts,
* ie it can now fire its "created", "altered-one", "toggled" and "deleted"
* signals.
+ *
+ * The default implementation does nothing. It should be overridden by
+ * any plugin that will emit "created", "altered-one", "toggled" and/or
+ * "deleted".
*/
void
-mcp_account_storage_ready (const McpAccountStorage *storage,
- const McpAccountManager *am)
+mcp_account_storage_ready (McpAccountStorage *storage,
+ McpAccountManager *am)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
+ SDEBUG (storage, "");
g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->ready != NULL);
- /* plugins that can't create accounts from external sources don't *
- * need to implement this method, as they can never fire the async *
- * account change signals: */
- if (iface->ready != NULL)
- iface->ready (storage, am);
+ iface->ready (storage, am);
}
/**
@@ -878,30 +883,25 @@ mcp_account_storage_ready (const McpAccountStorage *storage,
* Get the storage-specific identifier for this account. The type is variant,
* hence the GValue.
*
+ * The default implementation returns @account as a %G_TYPE_STRING.
+ *
* This method will only be called for the storage plugin that "owns"
* the account.
*/
void
-mcp_account_storage_get_identifier (const McpAccountStorage *storage,
+mcp_account_storage_get_identifier (McpAccountStorage *storage,
const gchar *account,
GValue *identifier)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
- SDEBUG (storage, "");
+ SDEBUG (storage, "%s", account);
g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->get_identifier != NULL);
g_return_if_fail (identifier != NULL);
g_return_if_fail (!G_IS_VALUE (identifier));
- if (iface->get_identifier == NULL)
- {
- g_value_init (identifier, G_TYPE_STRING);
- g_value_set_string (identifier, account);
- }
- else
- {
- iface->get_identifier (storage, account, identifier);
- }
+ iface->get_identifier (storage, account, identifier);
}
/**
@@ -926,26 +926,22 @@ mcp_account_storage_get_identifier (const McpAccountStorage *storage,
* This method will only be called for the storage plugin that "owns"
* the account.
*
+ * The default implementation returns an empty map.
+ *
* Returns: (transfer container) (element-type utf8 GObject.Value): additional
- * storage-specific information
+ * storage-specific information, which must not be %NULL
*/
GHashTable *
-mcp_account_storage_get_additional_info (const McpAccountStorage *storage,
+mcp_account_storage_get_additional_info (McpAccountStorage *storage,
const gchar *account)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
- GHashTable *ret = NULL;
- SDEBUG (storage, "");
+ SDEBUG (storage, "%s", account);
g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->get_additional_info != NULL, FALSE);
- if (iface->get_additional_info != NULL)
- ret = iface->get_additional_info (storage, account);
-
- if (ret == NULL)
- ret = g_hash_table_new (g_str_hash, g_str_equal);
-
- return ret;
+ return iface->get_additional_info (storage, account);
}
/**
@@ -966,21 +962,22 @@ mcp_account_storage_get_additional_info (const McpAccountStorage *storage,
* This method will only be called for the storage plugin that "owns"
* the account.
*
+ * The default implementation returns 0, i.e. no restrictions.
+ *
* Returns: a bitmask of %TpStorageRestrictionFlags with the restrictions to
* account storage.
*/
TpStorageRestrictionFlags
-mcp_account_storage_get_restrictions (const McpAccountStorage *storage,
+mcp_account_storage_get_restrictions (McpAccountStorage *storage,
const gchar *account)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
+ SDEBUG (storage, "%s", account);
g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->get_restrictions != NULL, 0);
- if (iface->get_restrictions == NULL)
- return 0;
- else
- return iface->get_restrictions (storage, account);
+ return iface->get_restrictions (storage, account);
}
/**
@@ -992,7 +989,7 @@ mcp_account_storage_get_restrictions (const McpAccountStorage *storage,
* Returns: the plugin's name (for logging etc)
*/
const gchar *
-mcp_account_storage_name (const McpAccountStorage *storage)
+mcp_account_storage_name (McpAccountStorage *storage)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
@@ -1010,7 +1007,7 @@ mcp_account_storage_name (const McpAccountStorage *storage)
* Returns: the plugin's description (for logging etc)
*/
const gchar *
-mcp_account_storage_description (const McpAccountStorage *storage)
+mcp_account_storage_description (McpAccountStorage *storage)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
@@ -1029,7 +1026,7 @@ mcp_account_storage_description (const McpAccountStorage *storage)
* was provided in #McpAccountStorageIface.provider.
*/
const gchar *
-mcp_account_storage_provider (const McpAccountStorage *storage)
+mcp_account_storage_provider (McpAccountStorage *storage)
{
McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
@@ -1039,7 +1036,7 @@ mcp_account_storage_provider (const McpAccountStorage *storage)
}
/**
- * mcp_account_storage_emit_create:
+ * mcp_account_storage_emit_created:
* @storage: an #McpAccountStorage instance
* @account: the unique name of the created account
*
@@ -1049,6 +1046,7 @@ void
mcp_account_storage_emit_created (McpAccountStorage *storage,
const gchar *account)
{
+ SDEBUG (storage, "%s", account);
g_signal_emit (storage, signals[CREATED], 0, account);
}
@@ -1066,6 +1064,7 @@ mcp_account_storage_emit_altered_one (McpAccountStorage *storage,
const gchar *account,
const gchar *key)
{
+ SDEBUG (storage, "%s", account);
g_signal_emit (storage, signals[ALTERED_ONE], 0, account, key);
}
@@ -1080,6 +1079,7 @@ void
mcp_account_storage_emit_deleted (McpAccountStorage *storage,
const gchar *account)
{
+ SDEBUG (storage, "%s", account);
g_signal_emit (storage, signals[DELETED], 0, account);
}
@@ -1096,6 +1096,7 @@ mcp_account_storage_emit_toggled (McpAccountStorage *storage,
const gchar *account,
gboolean enabled)
{
+ SDEBUG (storage, "%s: Enabled=%s", account, enabled ? "True" : "False");
g_signal_emit (storage, signals[TOGGLED], 0, account, enabled);
}
@@ -1110,35 +1111,6 @@ void
mcp_account_storage_emit_reconnect (McpAccountStorage *storage,
const gchar *account)
{
+ SDEBUG (storage, "%s", account);
g_signal_emit (storage, signals[RECONNECT], 0, account);
}
-
-/**
- * mcp_account_storage_owns:
- * @storage: an #McpAccountStorage instance
- * @am: an #McpAccountManager instance
- * @account: the unique name (object-path tail) of an account
- *
- * Check whether @account is stored in @storage. The highest-priority
- * plugin for which this function returns %TRUE is considered to be
- * responsible for @account.
- *
- * There is a default implementation, which calls mcp_account_storage_get()
- * for the well-known key "manager".
- *
- * Returns: %TRUE if @account is stored in @storage
- *
- * Since: 5.15.0
- */
-gboolean
-mcp_account_storage_owns (McpAccountStorage *storage,
- McpAccountManager *am,
- const gchar *account)
-{
- McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
-
- g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (iface->owns != NULL, FALSE);
-
- return iface->owns (storage, am, account);
-}
diff --git a/mission-control-plugins/account-storage.h b/mission-control-plugins/account-storage.h
index 5c111025..fd6daee1 100644
--- a/mission-control-plugins/account-storage.h
+++ b/mission-control-plugins/account-storage.h
@@ -30,7 +30,22 @@ G_BEGIN_DECLS
#define MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_READONLY -1
#define MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_DEFAULT 0
#define MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_NORMAL 100
-#define MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_KEYRING 10000
+
+typedef enum /*< flags >*/
+{
+ MCP_PARAMETER_FLAG_NONE = 0
+} McpParameterFlags;
+
+typedef enum /*< flags >*/
+{
+ MCP_ATTRIBUTE_FLAG_NONE = 0
+} McpAttributeFlags;
+
+typedef enum {
+ MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED = 0,
+ MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED,
+ MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED
+} McpAccountStorageSetResult;
/* API for plugins to implement */
typedef struct _McpAccountStorage McpAccountStorage;
@@ -58,52 +73,15 @@ struct _McpAccountStorage { };
GType mcp_account_storage_get_type (void);
-/* Virtual method implementation signatures */
-typedef gboolean (*McpAccountStorageGetFunc) (
- const McpAccountStorage *storage,
- const McpAccountManager *am,
- const gchar *account,
- const gchar *key);
-typedef gboolean (*McpAccountStorageSetFunc) (
- const McpAccountStorage *storage,
- const McpAccountManager *am,
- const gchar *account,
- const gchar *key,
- const gchar *val);
typedef gchar * (*McpAccountStorageCreate) (
- const McpAccountStorage *storage,
- const McpAccountManager *am,
+ McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *manager,
const gchar *protocol,
const gchar *identification,
GError **error);
-typedef gboolean (*McpAccountStorageDeleteFunc) (
- const McpAccountStorage *storage,
- const McpAccountManager *am,
- const gchar *account,
- const gchar *key);
-typedef GList * (*McpAccountStorageListFunc) (
- const McpAccountStorage *storage,
- const McpAccountManager *am);
-typedef gboolean (*McpAccountStorageCommitFunc) (
- const McpAccountStorage *storage,
- const McpAccountManager *am);
-typedef gboolean (*McpAccountStorageCommitOneFunc) (
- const McpAccountStorage *storage,
- const McpAccountManager *am,
- const gchar *account);
-typedef void (*McpAccountStorageReadyFunc) (
- const McpAccountStorage *storage,
- const McpAccountManager *am);
-typedef void (*McpAccountStorageGetIdentifierFunc) (
- const McpAccountStorage *storage,
- const gchar *account,
- GValue *identifier);
-typedef GHashTable * (*McpAccountStorageGetAdditionalInfoFunc) (
- const McpAccountStorage *storage,
- const gchar *account);
typedef TpStorageRestrictionFlags (*McpAccountStorageGetRestrictionsFunc) (
- const McpAccountStorage *storage,
+ McpAccountStorage *storage,
const gchar *account);
struct _McpAccountStorageIface
@@ -115,29 +93,63 @@ struct _McpAccountStorageIface
const gchar *desc;
const gchar *provider;
- McpAccountStorageSetFunc set;
- McpAccountStorageGetFunc get;
- McpAccountStorageDeleteFunc delete;
- McpAccountStorageCommitFunc commit;
- McpAccountStorageListFunc list;
- McpAccountStorageReadyFunc ready;
- McpAccountStorageCommitOneFunc commit_one;
- McpAccountStorageGetIdentifierFunc get_identifier;
- McpAccountStorageGetAdditionalInfoFunc get_additional_info;
- McpAccountStorageGetRestrictionsFunc get_restrictions;
- McpAccountStorageCreate create;
-
- /* Since 5.15.0 */
- gboolean (*owns) (McpAccountStorage *storage,
+ void (*delete_async) (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*delete_finish) (McpAccountStorage *storage,
+ GAsyncResult *res,
+ GError **error);
+
+ gboolean (*commit) (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account);
+
+ GList * (*list) (McpAccountStorage *storage,
+ McpAccountManager *am);
+
+ void (*ready) (McpAccountStorage *storage,
+ McpAccountManager *am);
+
+ void (*get_identifier) (McpAccountStorage *storage,
+ const gchar *account,
+ GValue *identifier);
+
+ GHashTable * (*get_additional_info) (McpAccountStorage *storage,
+ const gchar *account);
+
+ TpStorageRestrictionFlags (*get_restrictions) (McpAccountStorage *storage,
+ const gchar *account);
+
+ gchar * (*create) (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *manager,
+ const gchar *protocol,
+ const gchar *identification,
+ GError **error);
+
+ GVariant *(*get_attribute) (McpAccountStorage *storage,
McpAccountManager *am,
- const gchar *account);
- gboolean (*set_attribute) (McpAccountStorage *storage,
+ const gchar *account,
+ const gchar *attribute,
+ const GVariantType *type,
+ McpAttributeFlags *flags);
+ GVariant *(*get_parameter) (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account,
+ const gchar *parameter,
+ const GVariantType *type,
+ McpParameterFlags *flags);
+
+ McpAccountStorageSetResult (*set_attribute) (McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account,
const gchar *attribute,
GVariant *val,
McpAttributeFlags flags);
- gboolean (*set_parameter) (McpAccountStorage *storage,
+ McpAccountStorageSetResult (*set_parameter) (McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account,
const gchar *parameter,
@@ -146,74 +158,75 @@ struct _McpAccountStorageIface
};
/* virtual methods */
-gint mcp_account_storage_priority (const McpAccountStorage *storage);
+gint mcp_account_storage_priority (McpAccountStorage *storage);
-gboolean mcp_account_storage_get (const McpAccountStorage *storage,
+gchar * mcp_account_storage_create (McpAccountStorage *storage,
McpAccountManager *am,
- const gchar *account,
- const gchar *key);
-
-gboolean mcp_account_storage_set (const McpAccountStorage *storage,
- const McpAccountManager *am,
- const gchar *account,
- const gchar *key,
- const gchar *value);
-
-gchar * mcp_account_storage_create (const McpAccountStorage *storage,
- const McpAccountManager *am,
const gchar *manager,
const gchar *protocol,
const gchar *identification,
GError **error);
-gboolean mcp_account_storage_delete (const McpAccountStorage *storage,
- const McpAccountManager *am,
+void mcp_account_storage_delete_async (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *account,
- const gchar *key);
-
-void mcp_account_storage_ready (const McpAccountStorage *storage,
- const McpAccountManager *am);
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mcp_account_storage_delete_finish (McpAccountStorage *storage,
+ GAsyncResult *result,
+ GError **error);
-gboolean
-mcp_account_storage_commit (const McpAccountStorage *storage,
- const McpAccountManager *am);
+void mcp_account_storage_ready (McpAccountStorage *storage,
+ McpAccountManager *am);
gboolean
-mcp_account_storage_commit_one (const McpAccountStorage *storage,
- const McpAccountManager *am,
+mcp_account_storage_commit (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *account);
-GList *mcp_account_storage_list (const McpAccountStorage *storage,
- const McpAccountManager *am);
+GList *mcp_account_storage_list (McpAccountStorage *storage,
+ McpAccountManager *am);
-void mcp_account_storage_get_identifier (const McpAccountStorage *storage,
+void mcp_account_storage_get_identifier (McpAccountStorage *storage,
const gchar *account,
GValue *identifier);
GHashTable *mcp_account_storage_get_additional_info (
- const McpAccountStorage *storage,
+ McpAccountStorage *storage,
const gchar *account);
TpStorageRestrictionFlags mcp_account_storage_get_restrictions (
- const McpAccountStorage *storage,
+ McpAccountStorage *storage,
const gchar *account);
-const gchar *mcp_account_storage_name (const McpAccountStorage *storage);
+const gchar *mcp_account_storage_name (McpAccountStorage *storage);
-const gchar *mcp_account_storage_description (const McpAccountStorage *storage);
-const gchar *mcp_account_storage_provider (const McpAccountStorage *storage);
+const gchar *mcp_account_storage_description (McpAccountStorage *storage);
+const gchar *mcp_account_storage_provider (McpAccountStorage *storage);
-gboolean mcp_account_storage_owns (McpAccountStorage *storage,
- McpAccountManager *am,
- const gchar *account);
+GVariant *mcp_account_storage_get_attribute (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account,
+ const gchar *attribute,
+ const GVariantType *type,
+ McpAttributeFlags *flags);
+GVariant *mcp_account_storage_get_parameter (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account,
+ const gchar *parameter,
+ const GVariantType *type,
+ McpParameterFlags *flags);
-gboolean mcp_account_storage_set_attribute (McpAccountStorage *storage,
+McpAccountStorageSetResult mcp_account_storage_set_attribute (
+ McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account,
const gchar *attribute,
GVariant *value,
McpAttributeFlags flags);
-gboolean mcp_account_storage_set_parameter (McpAccountStorage *storage,
+McpAccountStorageSetResult mcp_account_storage_set_parameter (
+ McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account,
const gchar *parameter,
diff --git a/mission-control-plugins/account.c b/mission-control-plugins/account.c
index 1744ef6a..2c194616 100644
--- a/mission-control-plugins/account.c
+++ b/mission-control-plugins/account.c
@@ -74,207 +74,6 @@ mcp_account_manager_get_type (void)
}
/**
- * mcp_account_manager_set_value:
- * @mcpa: an #McpAccountManager instance
- * @account: the unique name of an account
- * @key: the setting whose value we wish to change: either an attribute
- * like "DisplayName", or "param-" plus a parameter like "account"
- * @value: the new value, escaped as if for a #GKeyFile, or %NULL to delete
- * the setting/parameter
- *
- * Inform Mission Control that @key has changed its value to @value.
- *
- * This function may either be called from mcp_account_storage_get(),
- * or just before emitting #McpAccountStorage::altered-one.
- *
- * New plugins should call mcp_account_manager_set_attribute() or
- * mcp_account_manager_set_parameter() instead.
- */
-void
-mcp_account_manager_set_value (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *key,
- const gchar *value)
-{
- McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
-
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->set_value != NULL);
-
- iface->set_value (mcpa, account, key, value);
-}
-
-/**
- * mcp_account_manager_set_attribute:
- * @mcpa: an #McpAccountManager instance
- * @account: the unique name of an account
- * @attribute: the name of an attribute, such as "DisplayName"
- * @value: (allow-none): the new value, or %NULL to delete the attribute
- * @flags: flags for the new value (only used if @value is non-%NULL)
- *
- * Inform Mission Control that @attribute has changed its value to @value.
- *
- * If @value is a floating reference, Mission Control will take ownership
- * of it, much like g_variant_builder_add_value().
- *
- * This function may either be called from mcp_account_storage_get(),
- * or just before emitting #McpAccountStorage::altered-one.
- */
-void
-mcp_account_manager_set_attribute (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *attribute,
- GVariant *value,
- McpAttributeFlags flags)
-{
- McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
-
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->set_attribute != NULL);
-
- iface->set_attribute (mcpa, account, attribute, value, flags);
-}
-
-/**
- * mcp_account_manager_set_parameter:
- * @mcpa: an #McpAccountManager instance
- * @account: the unique name of an account
- * @parameter: the name of a parameter, such as "account", without
- * the "param-" prefix
- * @value: (allow-none): the new value, or %NULL to delete the parameter
- * @flags: flags for the new value (only used if @value is non-%NULL)
- *
- * Inform Mission Control that @parameter has changed its value to @value.
- *
- * If @value is a floating reference, Mission Control will take ownership
- * of it, much like g_variant_builder_add_value().
- *
- * This function may either be called from mcp_account_storage_get(),
- * or just before emitting #McpAccountStorage::altered-one.
- */
-void
-mcp_account_manager_set_parameter (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *parameter,
- GVariant *value,
- McpParameterFlags flags)
-{
- McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
-
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->set_parameter != NULL);
-
- iface->set_parameter (mcpa, account, parameter, value, flags);
-}
-
-/**
- * mcp_account_manage_list_keys:
- * @mcpa: a #McpAccountManager instance
- * @account: the unique name of an account
- *
- * <!-- -->
- *
- * Returns: (transfer full): a list of all keys (attributes and
- * "param-"-prefixed parameters) stored for @account by any plugin
- */
-GStrv
-mcp_account_manager_list_keys (const McpAccountManager *mcpa,
- const gchar *account)
-{
- McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
-
- g_return_val_if_fail (iface != NULL, NULL);
- g_return_val_if_fail (iface->list_keys != NULL, NULL);
- g_return_val_if_fail (account != NULL, NULL);
-
- return iface->list_keys (mcpa, account);
-}
-
-/**
- * mcp_account_manager_get_value:
- * @mcpa: an #McpAccountManager instance
- * @account: the unique name of an account
- * @key: the setting whose value we wish to fetch: either an attribute
- * like "DisplayName", or "param-" plus a parameter like "account"
- *
- * Fetch a copy of the current value of an account setting held by
- * the account manager.
- *
- * Returns: (transfer full): the value of @key
- */
-gchar *
-mcp_account_manager_get_value (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *key)
-{
- McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
-
- g_return_val_if_fail (iface != NULL, NULL);
- g_return_val_if_fail (iface->set_value != NULL, NULL);
-
- return iface->get_value (mcpa, account, key);
-}
-
-/**
- * mcp_account_manager_parameter_is_secret:
- * @mcpa: an #McpAccountManager instance
- * @account: the unique name of an account
- * @key: the constant string "param-", plus a parameter name like
- * "account" or "password"
- *
- * Determine whether a given account parameter is secret.
- * Generally this is determined by MC and passed down to plugins,
- * but any #McpAccountStorage plugin may decide a parameter is
- * secret, in which case the return value for this call will
- * indicate that fact too.
- *
- * For historical reasons, this function only operates on parameters,
- * but requires its argument to be prefixed with "param-".
- *
- * Returns: %TRUE for secret settings, %FALSE otherwise
- */
-gboolean
-mcp_account_manager_parameter_is_secret (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *key)
-{
- McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
-
- g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (iface->is_secret != NULL, FALSE);
-
- return iface->is_secret (mcpa, account, key);
-}
-
-/**
- * mcp_account_manager_parameter_make_secret:
- * @mcpa: an #McpAccountManager instance
- * @account: the unique name of an account
- * @key: the constant string "param-", plus a parameter name like
- * "account" or "password"
- *
- * Flag an account setting as secret for the lifetime of this
- * #McpAccountManager. For instance, this should be called if
- * @key has been retrieved from gnome-keyring.
- *
- * For historical reasons, this function only operates on parameters,
- * but requires its argument to be prefixed with "param-".
- */
-void
-mcp_account_manager_parameter_make_secret (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *key)
-{
- McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
-
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->make_secret != NULL);
-
- g_debug ("%s.%s should be secret", account, key);
- iface->make_secret (mcpa, account, key);
-}
-
-/**
* mcp_account_manager_get_unique_name:
* @mcpa: an #McpAccountManager instance
* @manager: the name of the manager
@@ -351,34 +150,6 @@ mcp_account_manager_identify_account_finish (McpAccountManager *mcpa,
}
/**
- * mcp_account_manager_escape_value_from_keyfile:
- * @mcpa: a #McpAccountManager
- * @value: a value with a supported #GType
- *
- * Escape @value so it could be passed to g_key_file_set_value().
- * For instance, escaping the boolean value TRUE returns "true",
- * and escaping the string value containing one space returns "\s".
- *
- * It is a programming error to use an unsupported type.
- * The supported types are currently %G_TYPE_STRING, %G_TYPE_BOOLEAN,
- * %G_TYPE_INT, %G_TYPE_UINT, %G_TYPE_INT64, %G_TYPE_UINT64, %G_TYPE_UCHAR,
- * %G_TYPE_STRV, %DBUS_TYPE_G_OBJECT_PATH and %TP_ARRAY_TYPE_OBJECT_PATH_LIST.
- *
- * Returns: the escaped form of @value
- */
-gchar *
-mcp_account_manager_escape_value_for_keyfile (const McpAccountManager *mcpa,
- const GValue *value)
-{
- McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
-
- g_return_val_if_fail (iface != NULL, NULL);
- g_return_val_if_fail (iface->escape_value_for_keyfile != NULL, NULL);
-
- return iface->escape_value_for_keyfile (mcpa, value);
-}
-
-/**
* mcp_account_manager_escape_variant_for_keyfile:
* @mcpa: a #McpAccountManager
* @variant: a #GVariant with a supported #GVariantType
@@ -409,57 +180,30 @@ mcp_account_manager_escape_variant_for_keyfile (const McpAccountManager *mcpa,
}
/**
- * mcp_account_manager_unescape_value_from_keyfile:
+ * mcp_account_manager_unescape_variant_from_keyfile:
* @mcpa: a #McpAccountManager
- * @escaped: an escaped string as returned by g_key_file_get_value()
- * @value: a value to populate, with a supported #GType
- * @error: used to raise an error if %FALSE is returned
+ * @escaped: a string that could have come from g_key_file_get_value()
+ * @type: the type of the variant to which to unescape
*
- * Attempt to interpret @escaped as a value of @value's type.
- * If successful, put it in @value and return %TRUE.
+ * Unescape @escaped as if it had appeared in a #GKeyFile, with syntax
+ * appropriate for @type.
*
- * It is a programming error to try to escape an unsupported type.
- * The supported types are currently %G_TYPE_STRING, %G_TYPE_BOOLEAN,
- * %G_TYPE_INT, %G_TYPE_UINT, %G_TYPE_INT64, %G_TYPE_UINT64, %G_TYPE_UCHAR,
- * %G_TYPE_STRV, %DBUS_TYPE_G_OBJECT_PATH and %TP_ARRAY_TYPE_OBJECT_PATH_LIST.
+ * It is a programming error to use an unsupported type.
*
- * Returns: %TRUE if @value was filled in
+ * Returns: (transfer full): the unescaped form of @escaped
+ * (*not* a floating reference)
*/
-gboolean
-mcp_account_manager_unescape_value_from_keyfile (const McpAccountManager *mcpa,
+GVariant *
+mcp_account_manager_unescape_variant_from_keyfile (
+ const McpAccountManager *mcpa,
const gchar *escaped,
- GValue *value,
+ const GVariantType *type,
GError **error)
{
McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
- g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (iface->unescape_value_from_keyfile != NULL, FALSE);
-
- return iface->unescape_value_from_keyfile (mcpa, escaped, value, error);
-}
-
-/**
- * mcp_account_manager_init_value_for_attribute:
- * @mcpa: a #McpAccountManager
- * @value: a zero-filled value to initialize
- * @attribute: a supported Mission Control attribute
- *
- * If @attribute is a known Mission Control attribute, initialize @value
- * with an appropriate type for @attribute and return %TRUE. Otherwise,
- * return %FALSE.
- *
- * Returns: %TRUE if @value was initialized
- */
-gboolean
-mcp_account_manager_init_value_for_attribute (const McpAccountManager *mcpa,
- GValue *value,
- const gchar *attribute)
-{
- McpAccountManagerIface *iface = MCP_ACCOUNT_MANAGER_GET_IFACE (mcpa);
-
- g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (iface->init_value_for_attribute != NULL, FALSE);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->unescape_variant_from_keyfile != NULL, NULL);
- return iface->init_value_for_attribute (mcpa, value, attribute);
+ return iface->unescape_variant_from_keyfile (mcpa, escaped, type, error);
}
diff --git a/mission-control-plugins/account.h b/mission-control-plugins/account.h
index 4015457b..2a46c3ab 100644
--- a/mission-control-plugins/account.h
+++ b/mission-control-plugins/account.h
@@ -45,62 +45,21 @@ typedef struct _McpAccountManagerIface McpAccountManagerIface;
GType mcp_account_manager_get_type (void) G_GNUC_CONST;
-void mcp_account_manager_set_value (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *key,
- const gchar *value);
-
-void mcp_account_manager_set_attribute (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *attribute,
- GVariant *value,
- McpAttributeFlags flags);
-
-void mcp_account_manager_set_parameter (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *parameter,
- GVariant *value,
- McpParameterFlags flags);
-
-gchar * mcp_account_manager_get_value (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *key);
-
-gboolean mcp_account_manager_parameter_is_secret (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *key);
-
-void mcp_account_manager_parameter_make_secret (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *key);
-
gchar * mcp_account_manager_get_unique_name (McpAccountManager *mcpa,
const gchar *manager,
const gchar *protocol,
const gchar *identification);
-GStrv mcp_account_manager_list_keys (const McpAccountManager *mcpa,
- const gchar *account);
-
-gchar *mcp_account_manager_escape_value_for_keyfile (
- const McpAccountManager *mcpa,
- const GValue *value);
-
gchar *mcp_account_manager_escape_variant_for_keyfile (
const McpAccountManager *mcpa,
GVariant *variant);
-gboolean mcp_account_manager_unescape_value_from_keyfile (
+GVariant *mcp_account_manager_unescape_variant_from_keyfile (
const McpAccountManager *mcpa,
const gchar *escaped,
- GValue *value,
+ const GVariantType *type,
GError **error);
-gboolean mcp_account_manager_init_value_for_attribute (
- const McpAccountManager *mcpa,
- GValue *value,
- const gchar *attribute);
-
void mcp_account_manager_identify_account_async (McpAccountManager *mcpa,
const gchar *manager,
const gchar *protocol,
diff --git a/mission-control-plugins/implementation.h b/mission-control-plugins/implementation.h
index 2ad28938..59096f93 100644
--- a/mission-control-plugins/implementation.h
+++ b/mission-control-plugins/implementation.h
@@ -77,57 +77,17 @@ struct _McpDispatchOperationIface {
struct _McpAccountManagerIface {
GTypeInterface parent;
- void (*set_value) (const McpAccountManager *ma,
- const gchar *acct,
- const gchar *key,
- const gchar *value);
-
- gchar * (*get_value) (const McpAccountManager *ma,
- const gchar *acct,
- const gchar *key);
-
- gboolean (*is_secret) (const McpAccountManager *ma,
- const gchar *acct,
- const gchar *key);
-
- void (* make_secret) (const McpAccountManager *ma,
- const gchar *acct,
- const gchar *key);
-
gchar * (* unique_name) (const McpAccountManager *ma,
const gchar *manager,
const gchar *protocol,
const gchar *identification);
- GStrv (* list_keys) (const McpAccountManager *ma,
- const gchar *acct);
-
- gchar * (* escape_value_for_keyfile) (const McpAccountManager *mcpa,
- const GValue *value);
-
- gboolean (* unescape_value_from_keyfile) (const McpAccountManager *mcpa,
- const gchar *escaped,
- GValue *value,
- GError **error);
-
- gboolean (* init_value_for_attribute) (const McpAccountManager *mcpa,
- GValue *value,
- const gchar *attribute);
-
gchar * (* escape_variant_for_keyfile) (const McpAccountManager *mcpa,
GVariant *variant);
-
- void (* set_attribute) (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *attribute,
- GVariant *value,
- McpAttributeFlags flags);
-
- void (* set_parameter) (const McpAccountManager *mcpa,
- const gchar *account,
- const gchar *parameter,
- GVariant *value,
- McpParameterFlags flags);
+ GVariant *(* unescape_variant_from_keyfile) (const McpAccountManager *mcpa,
+ const gchar *escaped,
+ const GVariantType *type,
+ GError **error);
void (* identify_account_async) (McpAccountManager *mcpa,
const gchar *manager,
diff --git a/mission-control-plugins/loader.c b/mission-control-plugins/loader.c
index 640d1d87..a23028b3 100644
--- a/mission-control-plugins/loader.c
+++ b/mission-control-plugins/loader.c
@@ -62,6 +62,21 @@ static gboolean debugging = FALSE;
#endif
/**
+ * MCP_API_VERSION_5_18:
+ *
+ * Defined to allow simple plugin implementations to support both Mission
+ * Control 5.16 and 5.18 plugin APIs:
+ *
+ * |[
+ * #ifdef MCP_API_VERSION_5_18
+ * ... // implement MC 5.18 API
+ * #else
+ * ... // implement MC 5.16 API
+ * #endif
+ * ]|
+ */
+
+/**
* mcp_set_debug:
* @debug: whether to log debug output
*
diff --git a/mission-control-plugins/mission-control-plugins.h b/mission-control-plugins/mission-control-plugins.h
index 13d87e6f..186da91d 100644
--- a/mission-control-plugins/mission-control-plugins.h
+++ b/mission-control-plugins/mission-control-plugins.h
@@ -25,14 +25,7 @@
#include <glib-object.h>
#include <telepathy-glib/telepathy-glib.h>
-typedef enum {
- MCP_PARAMETER_FLAG_NONE = 0,
- MCP_PARAMETER_FLAG_SECRET = TP_CONN_MGR_PARAM_FLAG_SECRET
-} McpParameterFlags;
-
-typedef enum {
- MCP_ATTRIBUTE_FLAG_NONE = 0
-} McpAttributeFlags;
+#define MCP_API_VERSION_5_18 (518)
#define _MCP_IN_MISSION_CONTROL_PLUGINS_H
#include <mission-control-plugins/account.h>
diff --git a/src/mcd-account-addressing.c b/src/mcd-account-addressing.c
index ec3d8f5e..c9740c78 100644
--- a/src/mcd-account-addressing.c
+++ b/src/mcd-account-addressing.c
@@ -48,7 +48,7 @@ addressing_set_uri_scheme_association (TpSvcAccountInterfaceAddressing *iface,
g_value_init (&value, G_TYPE_STRV);
if (mcd_storage_get_attribute (storage, account, MC_ACCOUNTS_KEY_URI_SCHEMES,
- &value, NULL))
+ G_VARIANT_TYPE_STRING_ARRAY, &value, NULL))
{
schemes = g_value_get_boxed (&value);
old_association = tp_strv_contains ((const gchar * const *) schemes,
@@ -109,7 +109,7 @@ addressing_get_uri_schemes (TpSvcDBusProperties *iface,
g_value_init (value, G_TYPE_STRV);
if (!mcd_storage_get_attribute (storage, account, MC_ACCOUNTS_KEY_URI_SCHEMES,
- value, NULL))
+ G_VARIANT_TYPE_STRING_ARRAY, value, NULL))
{
g_value_set_boxed (value, NULL);
}
diff --git a/src/mcd-account-manager-default.c b/src/mcd-account-manager-default.c
index 85b5e4e5..e9f2bf20 100644
--- a/src/mcd-account-manager-default.c
+++ b/src/mcd-account-manager-default.c
@@ -47,13 +47,19 @@ typedef struct {
/* owned string, parameter (without "param-") => owned string, value
* parameters of unknwn type to be stored in the variant-file */
GHashTable *untyped_parameters;
- /* TRUE if the entire account is pending deletion */
- gboolean pending_deletion;
/* TRUE if the account doesn't really exist, but is here to stop us
* loading it from a lower-priority file */
gboolean absent;
+ /* TRUE if this account needs saving */
+ gboolean dirty;
} McdDefaultStoredAccount;
+static GVariant *
+variant_ref0 (GVariant *v)
+{
+ return (v == NULL ? NULL : g_variant_ref (v));
+}
+
static McdDefaultStoredAccount *
lookup_stored_account (McdAccountManagerDefault *self,
const gchar *account)
@@ -79,7 +85,6 @@ ensure_stored_account (McdAccountManagerDefault *self,
g_hash_table_insert (self->accounts, g_strdup (account), sa);
}
- sa->pending_deletion = FALSE;
sa->absent = FALSE;
return sa;
}
@@ -156,7 +161,6 @@ mcd_account_manager_default_init (McdAccountManagerDefault *self)
self->directory = account_directory_in (g_get_user_data_dir ());
self->accounts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
stored_account_free);
- self->save = FALSE;
self->loaded = FALSE;
}
@@ -166,7 +170,7 @@ mcd_account_manager_default_class_init (McdAccountManagerDefaultClass *cls)
DEBUG ("mcd_account_manager_default_class_init");
}
-static gboolean
+static McpAccountStorageSetResult
set_parameter (McpAccountStorage *self,
McpAccountManager *am,
const gchar *account,
@@ -177,22 +181,48 @@ set_parameter (McpAccountStorage *self,
McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self);
McdDefaultStoredAccount *sa;
- sa = ensure_stored_account (amd, account);
- amd->save = TRUE;
+ sa = lookup_stored_account (amd, account);
+ g_return_val_if_fail (sa != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
+ g_return_val_if_fail (!sa->absent, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
+
+ if (val == NULL)
+ {
+ gboolean changed = FALSE;
+
+ changed = g_hash_table_remove (sa->parameters, parameter);
+ /* deliberately not ||= - if we removed it from parameters, we
+ * still want to remove it from untyped_parameters if it was there */
+ changed |= g_hash_table_remove (sa->untyped_parameters, parameter);
- /* remove it from all sets, then re-add it to the right one if
- * non-null */
- g_hash_table_remove (sa->parameters, parameter);
- g_hash_table_remove (sa->untyped_parameters, parameter);
+ if (!changed)
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
+ }
+ else
+ {
+ GVariant *old;
- if (val != NULL)
- g_hash_table_insert (sa->parameters, g_strdup (parameter),
- g_variant_ref (val));
+ old = g_hash_table_lookup (sa->parameters, parameter);
- return TRUE;
+ if (old != NULL && g_variant_equal (old, val))
+ {
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
+ }
+
+ /* We haven't checked whether it's in untyped_parameters with the
+ * same value - but if it is, we want to migrate it to parameters
+ * anyway (in order to record its type), so treat it as having
+ * actually changed. */
+
+ g_hash_table_remove (sa->untyped_parameters, parameter);
+ g_hash_table_insert (sa->parameters, g_strdup (parameter),
+ g_variant_ref (val));
+ }
+
+ sa->dirty = TRUE;
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
}
-static gboolean
+static McpAccountStorageSetResult
set_attribute (McpAccountStorage *self,
McpAccountManager *am,
const gchar *account,
@@ -201,214 +231,195 @@ set_attribute (McpAccountStorage *self,
McpAttributeFlags flags)
{
McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self);
- McdDefaultStoredAccount *sa = ensure_stored_account (amd, account);
+ McdDefaultStoredAccount *sa;
- amd->save = TRUE;
+ sa = lookup_stored_account (amd, account);
+ g_return_val_if_fail (sa != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
+ g_return_val_if_fail (!sa->absent, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
- if (val != NULL)
- g_hash_table_insert (sa->attributes, g_strdup (attribute),
- g_variant_ref (val));
+ if (val == NULL)
+ {
+ if (!g_hash_table_remove (sa->attributes, attribute))
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
+ }
else
- g_hash_table_remove (sa->attributes, attribute);
+ {
+ GVariant *old;
- return TRUE;
-}
+ old = g_hash_table_lookup (sa->attributes, attribute);
-static gboolean
-_set (const McpAccountStorage *self,
- const McpAccountManager *am,
- const gchar *account,
- const gchar *key,
- const gchar *val)
-{
- return FALSE;
+ if (old != NULL && g_variant_equal (old, val))
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
+
+ g_hash_table_insert (sa->attributes, g_strdup (attribute),
+ g_variant_ref (val));
+ }
+
+ sa->dirty = TRUE;
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
}
-static gboolean
-get_parameter (const McpAccountStorage *self,
- const McpAccountManager *am,
+static GVariant *
+get_attribute (McpAccountStorage *self,
+ McpAccountManager *am,
const gchar *account,
- const gchar *prefixed,
- const gchar *parameter)
+ const gchar *attribute,
+ const GVariantType *type,
+ McpAttributeFlags *flags)
{
McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self);
McdDefaultStoredAccount *sa = lookup_stored_account (amd, account);
- if (parameter != NULL)
- {
- gchar *v = NULL;
- GVariant *variant = NULL;
-
- if (sa == NULL || sa->absent)
- return FALSE;
-
- variant = g_hash_table_lookup (sa->parameters, parameter);
+ if (flags != NULL)
+ *flags = 0;
- if (variant != NULL)
- {
- mcp_account_manager_set_parameter (am, account, parameter,
- variant, MCP_PARAMETER_FLAG_NONE);
- return TRUE;
- }
-
- v = g_hash_table_lookup (sa->untyped_parameters, parameter);
+ g_return_val_if_fail (sa != NULL, NULL);
+ g_return_val_if_fail (!sa->absent, NULL);
- if (v == NULL)
- return FALSE;
-
- mcp_account_manager_set_value (am, account, prefixed, v);
- }
- else
- {
- g_assert_not_reached ();
- }
-
- return TRUE;
+ /* ignore @type, we store every attribute with its type anyway; MC will
+ * coerce values to an appropriate type if needed */
+ return variant_ref0 (g_hash_table_lookup (sa->attributes, attribute));
}
-static gboolean
-_get (const McpAccountStorage *self,
- const McpAccountManager *am,
+static GVariant *
+get_parameter (McpAccountStorage *self,
+ McpAccountManager *am,
const gchar *account,
- const gchar *key)
+ const gchar *parameter,
+ const GVariantType *type,
+ McpParameterFlags *flags)
{
McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self);
McdDefaultStoredAccount *sa = lookup_stored_account (amd, account);
+ GVariant *variant;
+ gchar *str;
- if (sa == NULL || sa->absent)
- return FALSE;
-
- if (key != NULL)
- {
- GVariant *v = NULL;
-
- if (g_str_has_prefix (key, "param-"))
- {
- return get_parameter (self, am, account, key, key + 6);
- }
-
- v = g_hash_table_lookup (sa->attributes, key);
-
- if (v == NULL)
- return FALSE;
-
- mcp_account_manager_set_attribute (am, account, key, v,
- MCP_ATTRIBUTE_FLAG_NONE);
- }
- else
- {
- GHashTableIter iter;
- gpointer k, v;
-
- g_hash_table_iter_init (&iter, sa->attributes);
+ if (flags != NULL)
+ *flags = 0;
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- if (v != NULL)
- mcp_account_manager_set_attribute (am, account, k,
- v, MCP_ATTRIBUTE_FLAG_NONE);
- }
+ g_return_val_if_fail (sa != NULL, NULL);
+ g_return_val_if_fail (!sa->absent, NULL);
- g_hash_table_iter_init (&iter, sa->parameters);
+ variant = g_hash_table_lookup (sa->parameters, parameter);
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- if (v != NULL)
- mcp_account_manager_set_parameter (am, account, k, v,
- MCP_PARAMETER_FLAG_NONE);
- }
+ if (variant != NULL)
+ return g_variant_ref (variant);
- g_hash_table_iter_init (&iter, sa->untyped_parameters);
+ str = g_hash_table_lookup (sa->untyped_parameters, parameter);
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- if (v != NULL)
- {
- gchar *prefixed = g_strdup_printf ("param-%s",
- (const gchar *) k);
-
- mcp_account_manager_set_value (am, account, prefixed, v);
- g_free (prefixed);
- }
- }
- }
+ if (str == NULL)
+ return NULL;
- return TRUE;
+ return mcp_account_manager_unescape_variant_from_keyfile (am,
+ str, type, NULL);
}
static gchar *
-_create (const McpAccountStorage *self,
- const McpAccountManager *am,
+_create (McpAccountStorage *self,
+ McpAccountManager *am,
const gchar *manager,
const gchar *protocol,
const gchar *identification,
GError **error)
{
+ McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self);
gchar *unique_name;
- /* See comment in plugin-account.c::_storage_create_account() before changing
- * this implementation, it's more subtle than it looks */
unique_name = mcp_account_manager_get_unique_name (MCP_ACCOUNT_MANAGER (am),
manager, protocol,
identification);
g_return_val_if_fail (unique_name != NULL, NULL);
+ ensure_stored_account (amd, unique_name);
return unique_name;
}
-static gboolean
-_delete (const McpAccountStorage *self,
- const McpAccountManager *am,
- const gchar *account,
- const gchar *key)
+static void
+delete_async (McpAccountStorage *self,
+ McpAccountManager *am,
+ const gchar *account,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self);
McdDefaultStoredAccount *sa = lookup_stored_account (amd, account);
+ GTask *task;
+ gchar *filename = NULL;
+ const gchar * const *iter;
- if (sa == NULL || sa->absent)
- {
- /* Apparently we never had this account anyway. The plugin API
- * considers this to be "success". */
- return TRUE;
- }
+ task = g_task_new (amd, cancellable, callback, user_data);
- if (key == NULL)
- {
- amd->save = TRUE;
+ g_return_if_fail (sa != NULL);
+ g_return_if_fail (!sa->absent);
- /* flag the whole account as purged */
- sa->pending_deletion = TRUE;
- g_hash_table_remove_all (sa->attributes);
- g_hash_table_remove_all (sa->parameters);
- g_hash_table_remove_all (sa->untyped_parameters);
- }
- else
+ filename = account_file_in (g_get_user_data_dir (), account);
+
+ DEBUG ("Deleting account %s from %s", account, filename);
+
+ if (g_unlink (filename) != 0)
{
- if (g_str_has_prefix (key, "param-"))
- {
- if (g_hash_table_remove (sa->parameters, key + 6))
- amd->save = TRUE;
+ int e = errno;
- if (g_hash_table_remove (sa->untyped_parameters, key + 6))
- amd->save = TRUE;
- }
- else
+ /* ENOENT is OK, anything else is more upsetting */
+ if (e != ENOENT)
{
- if (g_hash_table_remove (sa->attributes, key))
- amd->save = TRUE;
+ WARNING ("Unable to delete %s: %s", filename,
+ g_strerror (e));
+ g_task_return_new_error (task, G_IO_ERROR, g_io_error_from_errno (e),
+ "Unable to delete %s: %s", filename, g_strerror (e));
+ goto finally;
}
+ }
+
+ for (iter = g_get_system_data_dirs ();
+ iter != NULL && *iter != NULL;
+ iter++)
+ {
+ gchar *other = account_file_in (*iter, account);
+ gboolean other_exists = g_file_test (other, G_FILE_TEST_EXISTS);
+
+ g_free (other);
- /* if that was the last attribute or parameter, the account is gone
- * too */
- if (g_hash_table_size (sa->attributes) == 0 &&
- g_hash_table_size (sa->untyped_parameters) == 0 &&
- g_hash_table_size (sa->parameters) == 0)
+ if (other_exists)
{
- sa->pending_deletion = TRUE;
+ GError *error = NULL;
+
+ /* There is a lower-priority file that would provide this
+ * account. We can't delete a file from XDG_DATA_DIRS which
+ * are conceptually read-only, but we can mask it with an
+ * empty file (prior art: systemd) */
+ if (!g_file_set_contents (filename, "", 0, &error))
+ {
+ g_prefix_error (&error,
+ "Unable to save empty account file to %s: ", filename);
+ WARNING ("%s", error->message);
+ g_task_return_error (task, error);
+ g_free (filename);
+ goto finally;
+ }
+
+ break;
}
}
- return TRUE;
+ /* clean up the mess */
+ g_hash_table_remove (amd->accounts, account);
+ mcp_account_storage_emit_deleted (self, account);
+
+ g_task_return_boolean (task, TRUE);
+
+finally:
+ g_free (filename);
+ g_object_unref (task);
+}
+
+static gboolean
+delete_finish (McpAccountStorage *storage,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
}
static gboolean
@@ -426,60 +437,21 @@ am_default_commit_one (McdAccountManagerDefault *self,
gboolean ret;
GError *error = NULL;
- filename = account_file_in (g_get_user_data_dir (), account_name);
-
- if (sa->pending_deletion)
- {
- const gchar * const *iter;
+ g_return_val_if_fail (sa != NULL, FALSE);
+ g_return_val_if_fail (!sa->absent, FALSE);
- DEBUG ("Deleting account %s from %s", account_name, filename);
-
- if (g_unlink (filename) != 0)
- {
- int e = errno;
-
- /* ENOENT is OK, anything else is more upsetting */
- if (e != ENOENT)
- {
- WARNING ("Unable to delete %s: %s", filename,
- g_strerror (e));
- g_free (filename);
- return FALSE;
- }
- }
-
- for (iter = g_get_system_data_dirs ();
- iter != NULL && *iter != NULL;
- iter++)
- {
- gchar *other = account_file_in (*iter, account_name);
- gboolean other_exists = g_file_test (other, G_FILE_TEST_EXISTS);
-
- g_free (other);
-
- if (other_exists)
- {
- /* There is a lower-priority file that would provide this
- * account. We can't delete a file from XDG_DATA_DIRS which
- * are conceptually read-only, but we can mask it with an
- * empty file (prior art: systemd) */
- if (!g_file_set_contents (filename, "", 0, &error))
- {
- WARNING ("Unable to save empty account file to %s: %s",
- filename, error->message);
- g_clear_error (&error);
- g_free (filename);
- return FALSE;
- }
-
- break;
- }
- }
+ if (!sa->dirty)
+ return TRUE;
- g_free (filename);
- return TRUE;
+ if (!mcd_ensure_directory (self->directory, &error))
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return FALSE;
}
+ filename = account_file_in (g_get_user_data_dir (), account_name);
+
DEBUG ("Saving account %s to %s", account_name, filename);
g_variant_builder_init (&attrs_builder, G_VARIANT_TYPE_VARDICT);
@@ -520,6 +492,7 @@ am_default_commit_one (McdAccountManagerDefault *self,
if (g_file_set_contents (filename, content_text, -1, &error))
{
+ sa->dirty = FALSE;
ret = TRUE;
}
else
@@ -536,57 +509,19 @@ am_default_commit_one (McdAccountManagerDefault *self,
}
static gboolean
-_commit (const McpAccountStorage *self,
- const McpAccountManager *am,
+_commit (McpAccountStorage *self,
+ McpAccountManager *am,
const gchar *account)
{
McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self);
- gboolean all_succeeded = TRUE;
- GError *error = NULL;
- GHashTableIter outer;
- gpointer account_p, sa_p;
-
- if (!amd->save)
- return TRUE;
-
- DEBUG ("Saving accounts to %s", amd->directory);
-
- if (!mcd_ensure_directory (amd->directory, &error))
- {
- g_warning ("%s", error->message);
- g_clear_error (&error);
- /* fall through anyway: writing to the files will fail, but it does
- * give us a chance to commit to the keyring too */
- }
-
- g_hash_table_iter_init (&outer, amd->accounts);
-
- while (g_hash_table_iter_next (&outer, &account_p, &sa_p))
- {
- if (account == NULL || !tp_strdiff (account, account_p))
- {
- if (!am_default_commit_one (amd, account_p, sa_p))
- all_succeeded = FALSE;
- }
- }
-
- if (all_succeeded)
- {
- amd->save = FALSE;
- }
-
- g_hash_table_iter_init (&outer, amd->accounts);
+ McdDefaultStoredAccount *sa = lookup_stored_account (amd, account);
- /* forget about any entirely removed accounts */
- while (g_hash_table_iter_next (&outer, NULL, &sa_p))
- {
- McdDefaultStoredAccount *sa = sa_p;
+ g_return_val_if_fail (sa != NULL, FALSE);
+ g_return_val_if_fail (!sa->absent, FALSE);
- if (sa->pending_deletion)
- g_hash_table_iter_remove (&outer);
- }
+ DEBUG ("Saving account %s to %s", account, amd->directory);
- return all_succeeded;
+ return am_default_commit_one (amd, account, sa);
}
static gboolean
@@ -633,7 +568,7 @@ am_default_load_keyfile (McdAccountManagerDefault *self,
GStrv keys = g_key_file_get_keys (keyfile, account, &m, NULL);
/* We're going to need to migrate this account. */
- self->save = TRUE;
+ sa->dirty = TRUE;
for (j = 0; j < m; j++)
{
@@ -649,7 +584,7 @@ am_default_load_keyfile (McdAccountManagerDefault *self,
}
else
{
- const gchar *type = mcd_storage_get_attribute_type (key);
+ const GVariantType *type = mcd_storage_get_attribute_type (key);
GVariant *variant = NULL;
if (type == NULL)
@@ -661,7 +596,7 @@ am_default_load_keyfile (McdAccountManagerDefault *self,
else
{
variant = mcd_keyfile_get_variant (keyfile,
- account, key, G_VARIANT_TYPE (type), &error);
+ account, key, type, &error);
}
if (variant == NULL)
@@ -873,14 +808,15 @@ am_default_load_directory (McdAccountManagerDefault *self,
}
static GList *
-_list (const McpAccountStorage *self,
- const McpAccountManager *am)
+_list (McpAccountStorage *self,
+ McpAccountManager *am)
{
GList *rval = NULL;
McdAccountManagerDefault *amd = MCD_ACCOUNT_MANAGER_DEFAULT (self);
GHashTableIter hash_iter;
gchar *migrate_from = NULL;
gpointer k, v;
+ gboolean save = FALSE;
if (!amd->loaded)
{
@@ -956,7 +892,7 @@ _list (const McpAccountStorage *self,
if (!am_default_load_keyfile (amd, migrate_from))
tp_clear_pointer (&migrate_from, g_free);
amd->loaded = TRUE;
- amd->save = TRUE;
+ save = TRUE;
}
else
{
@@ -968,14 +904,45 @@ _list (const McpAccountStorage *self,
{
DEBUG ("Creating initial account data");
amd->loaded = TRUE;
- amd->save = TRUE;
+ save = TRUE;
+ }
+
+ if (!save)
+ {
+ g_hash_table_iter_init (&hash_iter, amd->accounts);
+
+ while (g_hash_table_iter_next (&hash_iter, NULL, &v))
+ {
+ McdDefaultStoredAccount *sa = v;
+
+ if (sa->dirty)
+ {
+ save = TRUE;
+ break;
+ }
+ }
}
- if (amd->save)
+ if (save)
{
+ gboolean all_succeeded = TRUE;
+
DEBUG ("Saving initial or migrated account data");
- if (_commit (self, am, NULL))
+ g_hash_table_iter_init (&hash_iter, amd->accounts);
+
+ while (g_hash_table_iter_next (&hash_iter, &k, &v))
+ {
+ McdDefaultStoredAccount *sa = v;
+
+ if (sa->absent)
+ continue;
+
+ if (!am_default_commit_one (amd, k, v))
+ all_succeeded = FALSE;
+ }
+
+ if (all_succeeded)
{
if (migrate_from != NULL)
{
@@ -995,7 +962,10 @@ _list (const McpAccountStorage *self,
while (g_hash_table_iter_next (&hash_iter, &k, &v))
{
- rval = g_list_prepend (rval, g_strdup (k));
+ McdDefaultStoredAccount *sa = v;
+
+ if (!sa->absent)
+ rval = g_list_prepend (rval, g_strdup (k));
}
return rval;
@@ -1009,13 +979,14 @@ account_storage_iface_init (McpAccountStorageIface *iface,
iface->desc = PLUGIN_DESCRIPTION;
iface->priority = PLUGIN_PRIORITY;
- iface->get = _get;
- iface->set = _set;
+ iface->get_attribute = get_attribute;
+ iface->get_parameter = get_parameter;
iface->set_attribute = set_attribute;
iface->set_parameter = set_parameter;
iface->create = _create;
- iface->delete = _delete;
- iface->commit_one = _commit;
+ iface->delete_async = delete_async;
+ iface->delete_finish = delete_finish;
+ iface->commit = _commit;
iface->list = _list;
}
diff --git a/src/mcd-account-manager-default.h b/src/mcd-account-manager-default.h
index e16e062f..fb2cb75e 100644
--- a/src/mcd-account-manager-default.h
+++ b/src/mcd-account-manager-default.h
@@ -51,7 +51,6 @@ typedef struct {
GObject parent;
GHashTable *accounts;
gchar *directory;
- gboolean save;
gboolean loaded;
} _McdAccountManagerDefault;
diff --git a/src/mcd-account-manager.c b/src/mcd-account-manager.c
index 81afa31d..5ff7bc9c 100644
--- a/src/mcd-account-manager.c
+++ b/src/mcd-account-manager.c
@@ -110,6 +110,7 @@ typedef struct
gchar *cm_name;
gchar *protocol_name;
gchar *display_name;
+ gchar *provider;
GHashTable *parameters;
GHashTable *properties;
McdGetAccountCb callback;
@@ -133,8 +134,6 @@ enum
PROP_CLIENT_FACTORY
};
-static guint write_conf_id = 0;
-
static void register_dbus_service (McdAccountManager *account_manager);
static void release_setup_lock (McdAccountManager *account_manager);
static void setup_account_loaded (McdAccount *account,
@@ -176,7 +175,7 @@ async_altered_one_manager_cb (McdManager *cm,
static void
-altered_one_cb (GObject *storage,
+altered_one_cb (McpAccountStorage *storage,
const gchar *account_name,
const gchar *key,
gpointer data)
@@ -186,6 +185,7 @@ altered_one_cb (GObject *storage,
McdAccount *account = NULL;
McdManager *cm = NULL;
const gchar *cm_name = NULL;
+ McpAccountStorage *its_plugin;
account = mcd_account_manager_lookup_account (am, account_name);
@@ -195,6 +195,18 @@ altered_one_cb (GObject *storage,
return;
}
+ its_plugin = mcd_account_get_storage_plugin (account);
+
+ if (storage != its_plugin)
+ {
+ DEBUG ("Ignoring altered-one from plugin %s because account %s "
+ "belongs to %s",
+ mcp_account_storage_name (storage),
+ account_name,
+ mcp_account_storage_name (its_plugin));
+ return;
+ }
+
/* in theory, the CM is already ready by this point, but make sure: */
cm_name = mcd_account_get_manager_name (account);
@@ -277,11 +289,12 @@ created_cb (GObject *storage_plugin_obj,
McdMaster *master = mcd_master_get_default ();
McdManager *cm = NULL;
const gchar *cm_name = NULL;
+ GError *error = NULL;
/* actually fetch the data into our cache from the plugin: */
- if (mcd_storage_add_account_from_plugin (storage, plugin, name))
+ if (mcd_storage_add_account_from_plugin (storage, plugin, name, &error))
{
- account = mcd_account_new (am, name, priv->minotaur);
+ account = mcd_account_new (am, name, priv->minotaur, plugin);
g_assert (MCD_IS_ACCOUNT (account));
lad = g_slice_new (McdLoadAccountsData);
@@ -292,7 +305,8 @@ created_cb (GObject *storage_plugin_obj,
}
else
{
- /* that function already warned about it */
+ WARNING ("%s", error->message);
+ g_clear_error (&error);
goto finish;
}
@@ -333,6 +347,7 @@ toggled_cb (GObject *plugin, const gchar *name, gboolean on, gpointer data)
McdAccountManager *manager = MCD_ACCOUNT_MANAGER (data);
McdAccount *account = NULL;
GError *error = NULL;
+ McpAccountStorage *its_plugin;
account = mcd_account_manager_lookup_account (manager, name);
@@ -346,6 +361,18 @@ toggled_cb (GObject *plugin, const gchar *name, gboolean on, gpointer data)
return;
}
+ its_plugin = mcd_account_get_storage_plugin (account);
+
+ if (storage_plugin != its_plugin)
+ {
+ DEBUG ("Ignoring toggled signal from plugin %s because account %s "
+ "belongs to %s",
+ mcp_account_storage_name (storage_plugin),
+ name,
+ mcp_account_storage_name (its_plugin));
+ return;
+ }
+
_mcd_account_set_enabled (account, on, FALSE,
MCD_DBUS_PROP_SET_FLAG_ALREADY_IN_STORAGE, &error);
@@ -381,11 +408,27 @@ reconnect_cb (GObject *plugin, const gchar *name, gpointer data)
}
static void
-_mcd_account_delete_cb (McdAccount *account, const GError *error, gpointer data)
+mcd_account_delete_debug_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
{
- /* no need to do anything other than release the account ref, which *
- * should be the last ref we hold by the time this rolls arouns: */
- g_object_unref (account);
+ McdAccount *account = MCD_ACCOUNT (source);
+ GError *error = NULL;
+
+ if (mcd_account_delete_finish (account, res, &error))
+ {
+ DEBUG ("successfully deleted account %s (%s)",
+ mcd_account_get_unique_name (account),
+ (const gchar *) user_data);
+ }
+ else
+ {
+ WARNING ("could not delete account %s (%s): %s #%d: %s",
+ mcd_account_get_unique_name (account),
+ (const gchar *) user_data,
+ g_quark_to_string (error->domain), error->code, error->message);
+ g_clear_error (&error);
+ }
}
/* a backend plugin notified us that an account was vaporised: remove it */
@@ -404,14 +447,28 @@ deleted_cb (GObject *plugin, const gchar *name, gpointer data)
if (account != NULL)
{
const gchar * object_path = mcd_account_get_object_path (account);
+ McpAccountStorage *its_plugin = mcd_account_get_storage_plugin (
+ account);
+
+ if (storage_plugin != its_plugin)
+ {
+ DEBUG ("Ignoring deleted signal from plugin %s because account %s "
+ "belongs to %s",
+ mcp_account_storage_name (storage_plugin),
+ name,
+ mcp_account_storage_name (its_plugin));
+ return;
+ }
g_object_ref (account);
/* this unhooks the account's signal handlers */
g_hash_table_remove (manager->priv->accounts, name);
tp_svc_account_manager_emit_account_removed (manager, object_path);
- mcd_account_delete (account,
- MCD_DBUS_PROP_SET_FLAG_ALREADY_IN_STORAGE,
- _mcd_account_delete_cb, NULL);
+ mcd_account_delete_async (account,
+ MCD_DBUS_PROP_SET_FLAG_ALREADY_IN_STORAGE,
+ mcd_account_delete_debug_cb,
+ "in response to McpAccountStorage::deleted");
+ g_object_unref (account);
}
}
@@ -579,7 +636,6 @@ static void
on_account_removed (McdAccount *account, McdAccountManager *account_manager)
{
McdAccountManagerPrivate *priv = account_manager->priv;
- McdStorage *storage = priv->storage;
const gchar *name, *object_path;
object_path = mcd_account_get_object_path (account);
@@ -589,10 +645,6 @@ on_account_removed (McdAccount *account, McdAccountManager *account_manager)
name = mcd_account_get_unique_name (account);
g_hash_table_remove (priv->accounts, name);
-
- mcd_storage_delete_account (storage, name);
- mcd_account_manager_write_conf_async (account_manager, account, NULL,
- NULL);
}
static inline void
@@ -672,6 +724,7 @@ mcd_create_account_data_free (McdCreateAccountData *cad)
if (cad->destroy != NULL)
cad->destroy (cad->user_data);
+ g_free (cad->provider);
g_free (cad->cm_name);
g_free (cad->protocol_name);
g_free (cad->display_name);
@@ -722,13 +775,18 @@ complete_account_creation_finish (McdAccount *account,
if (!cad->ok)
{
- mcd_account_delete (account, MCD_DBUS_PROP_SET_FLAG_NONE,
- NULL, NULL);
+ mcd_account_delete_async (account,
+ MCD_DBUS_PROP_SET_FLAG_NONE,
+ mcd_account_delete_debug_cb,
+ "while recovering from failure to create");
tp_clear_object (&account);
}
- mcd_account_manager_write_conf_async (account_manager, account, NULL,
- NULL);
+ if (account != NULL)
+ {
+ mcd_storage_commit (account_manager->priv->storage,
+ mcd_account_get_unique_name (account));
+ }
if (cad->callback != NULL)
cad->callback (account_manager, account, cad->error, cad->user_data);
@@ -815,10 +873,10 @@ identify_account_cb (GObject *source_object,
{
McdStorage *storage = MCD_STORAGE (source_object);
McdCreateAccountData *cad = user_data;
- const gchar *provider;
gchar *id;
gchar *unique_name;
McdAccount *account;
+ McpAccountStorage *plugin;
id = mcp_account_manager_identify_account_finish (
MCP_ACCOUNT_MANAGER (storage), result, &cad->error);
@@ -830,12 +888,9 @@ identify_account_cb (GObject *source_object,
return;
}
- provider = tp_asv_get_string (cad->properties,
- TP_PROP_ACCOUNT_INTERFACE_STORAGE_STORAGE_PROVIDER);
-
- unique_name = mcd_storage_create_account (storage, provider,
+ unique_name = mcd_storage_create_account (storage, cad->provider,
cad->cm_name, cad->protocol_name,
- id, &cad->error);
+ id, &plugin, &cad->error);
if (unique_name == NULL)
{
@@ -858,8 +913,10 @@ identify_account_cb (GObject *source_object,
cad->display_name);
account = mcd_account_new (cad->account_manager, unique_name,
- cad->account_manager->priv->minotaur);
+ cad->account_manager->priv->minotaur,
+ plugin);
g_free (unique_name);
+ g_object_unref (plugin);
if (G_LIKELY (account))
{
@@ -902,18 +959,33 @@ _mcd_account_manager_create_account (McdAccountManager *account_manager,
return;
}
- cad = g_slice_new (McdCreateAccountData);
+ cad = g_slice_new0 (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;
+ if (properties != NULL)
+ {
+ cad->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) tp_g_value_slice_free);
+
+ tp_g_hash_table_update (cad->properties, properties,
+ (GBoxedCopyFunc) g_strdup,
+ (GBoxedCopyFunc) tp_g_value_slice_dup);
+
+ /* special case: "construct-only" */
+ cad->provider = g_strdup (tp_asv_get_string (cad->properties,
+ TP_PROP_ACCOUNT_INTERFACE_STORAGE_STORAGE_PROVIDER));
+ g_hash_table_remove (cad->properties,
+ TP_PROP_ACCOUNT_INTERFACE_STORAGE_STORAGE_PROVIDER);
+ }
+
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);
@@ -1061,20 +1133,6 @@ properties_iface_init (TpSvcDBusPropertiesClass *iface, gpointer iface_data)
#undef IMPLEMENT
}
-static gboolean
-write_conf (gpointer userdata)
-{
- McdStorage *storage = MCD_STORAGE (userdata);
-
- DEBUG ("called");
- g_source_remove (write_conf_id);
- write_conf_id = 0;
-
- mcd_storage_commit (storage, NULL);
-
- return TRUE;
-}
-
static void
release_setup_lock (McdAccountManager *self)
{
@@ -1136,15 +1194,6 @@ setup_account_loaded (McdAccount *account,
g_object_unref (self);
}
-static void
-uncork_storage_plugins (McdAccountManager *account_manager)
-{
- McdAccountManagerPrivate *priv = MCD_ACCOUNT_MANAGER_PRIV (account_manager);
-
- mcd_account_manager_write_conf_async (account_manager, NULL, NULL, NULL);
- mcd_storage_ready (priv->storage);
-}
-
typedef struct
{
McdAccountManager *self;
@@ -1176,12 +1225,13 @@ migrate_ctx_free (MigrateCtx *ctx)
static void
-migrate_delete_account_cb (McdAccount *account,
- const GError *error,
- gpointer user_data)
+migrate_delete_account_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
{
MigrateCtx *ctx = user_data;
+ mcd_account_delete_debug_cb (source, res, "after migrating it");
migrate_ctx_free (ctx);
}
@@ -1205,8 +1255,8 @@ migrate_create_account_cb (McdAccountManager *account_manager,
DEBUG ("Account %s migrated, removing it",
mcd_account_get_unique_name (ctx->account));
- mcd_account_delete (ctx->account, MCD_DBUS_PROP_SET_FLAG_NONE,
- migrate_delete_account_cb, ctx);
+ mcd_account_delete_async (ctx->account, MCD_DBUS_PROP_SET_FLAG_NONE,
+ migrate_delete_account_cb, ctx);
}
static void
@@ -1233,7 +1283,9 @@ migrate_butterfly_haze_ready (McdManager *manager,
/* Parameters; the only mandatory one is 'account' */
if (!mcd_account_get_parameter_of_known_type (ctx->account,
- "account", G_TYPE_STRING,
+ "account",
+ G_VARIANT_TYPE_STRING,
+ G_TYPE_STRING,
&v, NULL))
{
_mcd_account_set_enabled (ctx->account, FALSE, TRUE,
@@ -1247,7 +1299,9 @@ migrate_butterfly_haze_ready (McdManager *manager,
/* If MC is storing the password, let's copy that too, so Empathy
* can migrate it somewhere better. */
if (mcd_account_get_parameter_of_known_type (ctx->account,
- "password", G_TYPE_STRING,
+ "password",
+ G_VARIANT_TYPE_STRING,
+ G_TYPE_STRING,
&password_v, NULL))
{
g_hash_table_insert (parameters, "password", &password_v);
@@ -1384,9 +1438,9 @@ _mcd_account_manager_setup (McdAccountManager *account_manager)
{
McdAccountManagerPrivate *priv = account_manager->priv;
McdStorage *storage = priv->storage;
- gchar **accounts, **name;
+ GHashTable *accounts;
GHashTableIter iter;
- gpointer v;
+ gpointer k, v;
/* for simplicity we don't support re-entrant setup */
g_return_if_fail (priv->setup_lock == 0);
@@ -1397,29 +1451,35 @@ _mcd_account_manager_setup (McdAccountManager *account_manager)
list_connection_names_cb, NULL, NULL,
(GObject *)account_manager);
- accounts = mcd_storage_dup_accounts (storage, NULL);
+ accounts = mcd_storage_get_accounts (storage);
+ g_hash_table_iter_init (&iter, accounts);
- for (name = accounts; *name != NULL; name++)
+ while (g_hash_table_iter_next (&iter, &k, &v))
{
gboolean plausible = FALSE;
const gchar *manager = NULL;
const gchar *protocol = NULL;
+ const gchar *account_name = k;
+ McpAccountStorage *plugin = v;
McdAccount *account = mcd_account_manager_lookup_account (
- account_manager, *name);
+ account_manager, account_name);
if (account != NULL)
{
- /* FIXME: this shouldn't really happen */
- DEBUG ("already have account %p called '%s'; skipping", account, *name);
+ /* FIXME: can't happen? We shouldn't create any accounts before
+ * we got here, and there can't be any duplicates in @accounts */
+ DEBUG ("already have account %p called '%s'; skipping",
+ account, account_name);
continue;
}
- account = mcd_account_new (account_manager, *name, priv->minotaur);
+ account = mcd_account_new (account_manager, account_name,
+ priv->minotaur, plugin);
if (G_UNLIKELY (!account))
{
g_warning ("%s: account %s failed to instantiate", G_STRFUNC,
- *name);
+ account_name);
continue;
}
@@ -1434,7 +1494,7 @@ _mcd_account_manager_setup (McdAccountManager *account_manager)
const gchar *dbg_protocol = (protocol == NULL) ? "(nil)" : protocol;
g_warning ("%s: account %s has implausible manager/protocol: %s/%s",
- G_STRFUNC, *name, dbg_manager, dbg_protocol);
+ G_STRFUNC, account_name, dbg_manager, dbg_protocol);
g_object_unref (account);
continue;
}
@@ -1445,9 +1505,18 @@ _mcd_account_manager_setup (McdAccountManager *account_manager)
g_object_ref (account_manager));
g_object_unref (account);
}
- g_strfreev (accounts);
- uncork_storage_plugins (account_manager);
+ /* FIXME: why do we need to commit the accounts at this point?
+ * It was added to uncork_storage_plugins() in 3d5b5e7a248d
+ * without explanation */
+ g_hash_table_iter_init (&iter, account_manager->priv->accounts);
+ while (g_hash_table_iter_next (&iter, &k, NULL))
+ {
+ mcd_storage_commit (storage, k);
+ }
+
+ /* uncork signals from storage plugins */
+ mcd_storage_ready (priv->storage);
migrate_accounts (account_manager);
@@ -1533,12 +1602,6 @@ _mcd_account_manager_finalize (GObject *object)
{
McdAccountManagerPrivate *priv = MCD_ACCOUNT_MANAGER_PRIV (object);
- if (write_conf_id)
- {
- write_conf (priv->storage);
- g_assert (write_conf_id == 0);
- }
-
tp_clear_object (&priv->storage);
g_free (priv->account_connections_dir);
remove (priv->account_connections_file);
@@ -1690,63 +1753,6 @@ mcd_account_manager_get_connectivity_monitor (McdAccountManager *self)
return self->priv->minotaur;
}
-/**
- * McdAccountManagerWriteConfCb:
- * @account_manager: the #McdAccountManager
- * @error: a set #GError on failure or %NULL if there was no error
- * @user_data: user data
- *
- * The callback from mcd_account_manager_write_conf_async(). If the config
- * writing was successful, @error will be %NULL, otherwise it will be set
- * with the appropriate error.
- */
-
-/**
- * mcd_account_manager_write_conf_async:
- * @account_manager: the #McdAccountManager
- * @account: the account to be written, or %NULL to flush all accounts
- * @callback: a callback to be called on write success or failure
- * @user_data: data to be passed to @callback
- *
- * Write the account manager configuration to disk.
- */
-void
-mcd_account_manager_write_conf_async (McdAccountManager *account_manager,
- McdAccount *account,
- McdAccountManagerWriteConfCb callback,
- gpointer user_data)
-{
- McdStorage *storage = NULL;
- const gchar *account_name = NULL;
-
- g_return_if_fail (MCD_IS_ACCOUNT_MANAGER (account_manager));
-
- storage = account_manager->priv->storage;
-
- if (account != NULL)
- {
- account_name = mcd_account_get_unique_name (account);
-
- DEBUG ("updating %s", account_name);
- mcd_storage_commit (storage, account_name);
- }
- else
- {
- GStrv groups;
- gsize n_accounts = 0;
-
- groups = mcd_storage_dup_accounts (storage, &n_accounts);
- DEBUG ("updating all %" G_GSIZE_FORMAT " accounts", n_accounts);
-
- mcd_storage_commit (storage, NULL);
-
- g_strfreev (groups);
- }
-
- if (callback != NULL)
- callback (account_manager, NULL, user_data);
-}
-
GHashTable *
_mcd_account_manager_get_accounts (McdAccountManager *account_manager)
{
diff --git a/src/mcd-account-manager.h b/src/mcd-account-manager.h
index 922f4896..f33c2949 100644
--- a/src/mcd-account-manager.h
+++ b/src/mcd-account-manager.h
@@ -66,15 +66,6 @@ McdAccountManager *mcd_account_manager_new (
TpDBusDaemon *mcd_account_manager_get_dbus_daemon
(McdAccountManager *account_manager);
-typedef void (McdAccountManagerWriteConfCb) (McdAccountManager *account_manager,
- const GError *error,
- gpointer user_data);
-
-void mcd_account_manager_write_conf_async (McdAccountManager *account_manager,
- McdAccount *account,
- McdAccountManagerWriteConfCb callback,
- gpointer user_data);
-
McdAccount *mcd_account_manager_lookup_account (McdAccountManager *account_manager,
const gchar *name);
McdAccount *mcd_account_manager_lookup_account_by_path (McdAccountManager *account_manager,
diff --git a/src/mcd-account.c b/src/mcd-account.c
index 7b51afb8..28e3602c 100644
--- a/src/mcd-account.c
+++ b/src/mcd-account.c
@@ -181,6 +181,7 @@ enum
PROP_DBUS_DAEMON,
PROP_CONNECTIVITY_MONITOR,
PROP_STORAGE,
+ PROP_STORAGE_PLUGIN,
PROP_NAME,
};
@@ -314,6 +315,20 @@ mcd_account_loaded (McdAccount *account)
g_return_if_fail (!account->priv->loaded);
account->priv->loaded = TRUE;
+ if (account->priv->invalid_reason == NULL)
+ {
+ DEBUG ("account %s is now loaded and valid",
+ account->priv->unique_name);
+ }
+ else
+ {
+ DEBUG ("account %s is now loaded, but not valid: %s #%d: %s",
+ account->priv->unique_name,
+ g_quark_to_string (account->priv->invalid_reason->domain),
+ account->priv->invalid_reason->code,
+ account->priv->invalid_reason->message);
+ }
+
/* invoke all the callbacks */
g_object_ref (account);
@@ -378,12 +393,12 @@ _mcd_account_set_parameter (McdAccount *account, const gchar *name,
McdAccountPrivate *priv = account->priv;
McdStorage *storage = priv->storage;
const gchar *account_name = mcd_account_get_unique_name (account);
- gboolean secret = mcd_account_parameter_is_secret (account, name);
- mcd_storage_set_parameter (storage, account_name, name, value, secret);
+ mcd_storage_set_parameter (storage, account_name, name, value);
}
-static GType mc_param_type (const TpConnectionManagerParam *param);
+static GType mc_param_type (const TpConnectionManagerParam *param,
+ const GVariantType **variant_type_out);
/**
* mcd_account_get_parameter:
@@ -406,18 +421,22 @@ mcd_account_get_parameter (McdAccount *account, const gchar *name,
McdAccountPrivate *priv = account->priv;
const TpConnectionManagerParam *param;
GType type;
+ const GVariantType *variant_type;
+ gboolean ret;
param = mcd_manager_get_protocol_param (priv->manager,
priv->protocol_name, name);
- type = mc_param_type (param);
+ type = mc_param_type (param, &variant_type);
- return mcd_account_get_parameter_of_known_type (account, name,
- type, parameter, error);
+ ret = mcd_account_get_parameter_of_known_type (account, name,
+ variant_type, type, parameter, error);
+ return ret;
}
gboolean
mcd_account_get_parameter_of_known_type (McdAccount *account,
const gchar *name,
+ const GVariantType *variant_type,
GType type,
GValue *parameter,
GError **error)
@@ -428,7 +447,8 @@ mcd_account_get_parameter_of_known_type (McdAccount *account,
g_value_init (&tmp, type);
- if (mcd_storage_get_parameter (storage, account_name, name, &tmp, error))
+ if (mcd_storage_get_parameter (storage, account_name, name, variant_type,
+ &tmp, error))
{
if (parameter != NULL)
{
@@ -675,16 +695,19 @@ static TpStorageRestrictionFlags mcd_account_get_storage_restrictions (
McdAccount *account);
void
-mcd_account_delete (McdAccount *account,
- McdDBusPropSetFlags flags,
- McdAccountDeleteCb callback,
- gpointer user_data)
+mcd_account_delete_async (McdAccount *account,
+ McdDBusPropSetFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
McdAccountPrivate *priv = account->priv;
gchar *data_dir_str;
GError *error = NULL;
const gchar *name = mcd_account_get_unique_name (account);
TpConnectionManager *cm = mcd_account_get_cm (account);
+ GTask *task;
+
+ task = g_task_new (account, NULL, callback, user_data);
/* We don't really have a flag for "cannot delete accounts" yet, but
* it seems reasonable that if you can't disable it or put it
@@ -695,16 +718,18 @@ mcd_account_delete (McdAccount *account,
(TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_ENABLED |
TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_PRESENCE)) != 0)
{
- g_set_error (&error, TP_ERROR, TP_ERROR_PERMISSION_DENIED,
+ g_task_return_new_error (task, TP_ERROR, TP_ERROR_PERMISSION_DENIED,
"Storage plugin for %s does not allow deleting it",
name);
- callback (account, error, user_data);
- g_error_free (error);
+ g_object_unref (task);
return;
}
- /* if the CM implements CM.I.AccountStorage, we need to tell the CM
- * to forget any account credentials it knows */
+ /* If the CM implements CM.I.AccountStorage, we need to tell the CM
+ * to forget any account credentials it knows.
+ *
+ * FIXME: put this in the main flow rather than doing it async and
+ * throwing away its result? */
if (tp_proxy_has_interface_by_id (cm,
MC_IFACE_QUARK_CONNECTION_MANAGER_INTERFACE_ACCOUNT_STORAGE))
{
@@ -729,12 +754,13 @@ mcd_account_delete (McdAccount *account,
flags, &error))
{
g_warning ("could not disable account %s (%s)", name, error->message);
- callback (account, error, user_data);
- g_error_free (error);
+ g_task_return_error (task, error);
+ g_object_unref (task);
return;
}
- mcd_storage_delete_account (priv->storage, name);
+ if ((flags & MCD_DBUS_PROP_SET_FLAG_ALREADY_IN_STORAGE) == 0)
+ mcd_storage_delete_account (priv->storage, name);
data_dir_str = get_old_account_data_path (priv);
@@ -761,20 +787,25 @@ mcd_account_delete (McdAccount *account,
g_free (data_dir_str);
}
- mcd_storage_commit (priv->storage, name);
-
- if (callback != NULL)
- callback (account, NULL, user_data);
-
- /* If the account was not removed via the DBus Account interface code *
- * path and something is holding a ref to it so it does not get disposed, *
- * then this signal may not get fired, so we make sure it _does_ here */
if (!priv->removed)
{
- DEBUG ("Forcing Account.Removed for %s", name);
+ DEBUG ("emitting Account.Removed for %s", name);
priv->removed = TRUE;
tp_svc_account_emit_removed (account);
}
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+gboolean
+mcd_account_delete_finish (McdAccount *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
}
void
@@ -782,10 +813,29 @@ _mcd_account_load (McdAccount *account, McdAccountLoadCb callback,
gpointer user_data)
{
if (account->priv->loaded)
+ {
+ if (account->priv->invalid_reason == NULL)
+ {
+ DEBUG ("account %s already loaded and valid",
+ account->priv->unique_name);
+ }
+ else
+ {
+ DEBUG ("account %s already loaded, but not valid: %s #%d: %s",
+ account->priv->unique_name,
+ g_quark_to_string (account->priv->invalid_reason->domain),
+ account->priv->invalid_reason->code,
+ account->priv->invalid_reason->message);
+ }
+
callback (account, NULL, user_data);
+ }
else
+ {
+ DEBUG ("account %s not yet loaded", account->priv->unique_name);
_mcd_object_call_when_ready (account, account_ready_quark,
(McdReadyCb)callback, user_data);
+ }
}
static void
@@ -1081,7 +1131,8 @@ mcd_account_get_string_val (McdAccount *account, const gchar *key,
g_value_init (value, G_TYPE_STRING);
- if (!mcd_storage_get_attribute (priv->storage, name, key, value, NULL))
+ if (!mcd_storage_get_attribute (priv->storage, name, key,
+ G_VARIANT_TYPE_STRING, value, NULL))
{
g_value_set_static_string (value, NULL);
}
@@ -2076,58 +2127,16 @@ get_supersedes (TpSvcDBusProperties *svc,
g_value_set_boxed (value, self->priv->supersedes);
}
-static McpAccountStorage *
-get_storage_plugin (McdAccount *account)
-{
- McdAccountPrivate *priv = account->priv;
- const gchar *account_name = mcd_account_get_unique_name (account);
-
- if (priv->storage_plugin != NULL)
- return priv->storage_plugin;
-
- priv->storage_plugin = mcd_storage_get_plugin (priv->storage, account_name);
-
- if (priv->storage_plugin != NULL)
- g_object_ref (priv->storage_plugin);
-
- return priv->storage_plugin;
-}
-
static void
get_storage_provider (TpSvcDBusProperties *self,
const gchar *name, GValue *value)
{
McdAccount *account = MCD_ACCOUNT (self);
- McpAccountStorage *storage_plugin = get_storage_plugin (account);
g_value_init (value, G_TYPE_STRING);
- if (storage_plugin != NULL)
- g_value_set_string (value, mcp_account_storage_provider (storage_plugin));
- else
- g_value_set_static_string (value, "");
-}
-
-static gboolean
-set_storage_provider (TpSvcDBusProperties *self,
- const gchar *name,
- const GValue *value,
- McdDBusPropSetFlags flags,
- GError **error)
-{
- McdAccount *account = MCD_ACCOUNT (self);
- McpAccountStorage *storage_plugin = get_storage_plugin (account);
- const gchar *current_provider = mcp_account_storage_provider (storage_plugin);
-
- if (!G_VALUE_HOLDS_STRING (value) ||
- tp_strdiff (g_value_get_string (value), current_provider))
- {
- g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
- "Cannot change provider, it is defined at account creation only");
- return FALSE;
- }
-
- return TRUE;
+ g_value_set_string (value,
+ mcp_account_storage_provider (account->priv->storage_plugin));
}
static void
@@ -2136,22 +2145,13 @@ get_storage_identifier (TpSvcDBusProperties *self,
{
McdAccount *account = MCD_ACCOUNT (self);
- McpAccountStorage *storage_plugin = get_storage_plugin (account);
GValue identifier = G_VALUE_INIT;
g_value_init (value, G_TYPE_VALUE);
- if (storage_plugin != NULL)
- {
- mcp_account_storage_get_identifier (
- storage_plugin, account->priv->unique_name, &identifier);
- }
- else
- {
- g_value_init (&identifier, G_TYPE_UINT);
-
- g_value_set_uint (&identifier, 0);
- }
+ mcp_account_storage_get_identifier (
+ account->priv->storage_plugin, account->priv->unique_name,
+ &identifier);
g_value_set_boxed (value, &identifier);
@@ -2164,15 +2164,11 @@ get_storage_specific_info (TpSvcDBusProperties *self,
{
GHashTable *storage_specific_info;
McdAccount *account = MCD_ACCOUNT (self);
- McpAccountStorage *storage_plugin = get_storage_plugin (account);
g_value_init (value, TP_HASH_TYPE_STRING_VARIANT_MAP);
- if (storage_plugin != NULL)
- storage_specific_info = mcp_account_storage_get_additional_info (
- storage_plugin, account->priv->unique_name);
- else
- storage_specific_info = g_hash_table_new (g_str_hash, g_str_equal);
+ storage_specific_info = mcp_account_storage_get_additional_info (
+ account->priv->storage_plugin, account->priv->unique_name);
g_value_take_boxed (value, storage_specific_info);
}
@@ -2180,11 +2176,7 @@ get_storage_specific_info (TpSvcDBusProperties *self,
static TpStorageRestrictionFlags
mcd_account_get_storage_restrictions (McdAccount *self)
{
- McpAccountStorage *storage_plugin = get_storage_plugin (self);
-
- g_return_val_if_fail (storage_plugin != NULL, 0);
-
- return mcp_account_storage_get_restrictions (storage_plugin,
+ return mcp_account_storage_get_restrictions (self->priv->storage_plugin,
self->priv->unique_name);
}
@@ -2228,7 +2220,7 @@ static const McdDBusProp account_avatar_properties[] = {
};
static const McdDBusProp account_storage_properties[] = {
- { "StorageProvider", set_storage_provider, get_storage_provider },
+ { "StorageProvider", NULL, get_storage_provider },
{ "StorageIdentifier", NULL, get_storage_identifier },
{ "StorageSpecificInformation", NULL, get_storage_specific_info },
{ "StorageRestrictions", NULL, get_storage_restrictions },
@@ -2366,10 +2358,13 @@ properties_iface_init (TpSvcDBusPropertiesClass *iface, gpointer iface_data)
}
static GType
-mc_param_type (const TpConnectionManagerParam *param)
+mc_param_type (const TpConnectionManagerParam *param,
+ const GVariantType **variant_type_out)
{
const gchar *dbus_signature;
+ *variant_type_out = NULL;
+
if (G_UNLIKELY (param == NULL))
return G_TYPE_INVALID;
@@ -2381,37 +2376,49 @@ mc_param_type (const TpConnectionManagerParam *param)
switch (dbus_signature[0])
{
case DBUS_TYPE_STRING:
+ *variant_type_out = G_VARIANT_TYPE_STRING;
return G_TYPE_STRING;
case DBUS_TYPE_BYTE:
+ *variant_type_out = G_VARIANT_TYPE_BYTE;
return G_TYPE_UCHAR;
case DBUS_TYPE_INT16:
case DBUS_TYPE_INT32:
+ *variant_type_out = G_VARIANT_TYPE_INT32;
return G_TYPE_INT;
case DBUS_TYPE_UINT16:
case DBUS_TYPE_UINT32:
+ *variant_type_out = G_VARIANT_TYPE_UINT32;
return G_TYPE_UINT;
case DBUS_TYPE_BOOLEAN:
+ *variant_type_out = G_VARIANT_TYPE_BOOLEAN;
return G_TYPE_BOOLEAN;
case DBUS_TYPE_DOUBLE:
+ *variant_type_out = G_VARIANT_TYPE_DOUBLE;
return G_TYPE_DOUBLE;
case DBUS_TYPE_OBJECT_PATH:
+ *variant_type_out = G_VARIANT_TYPE_OBJECT_PATH;
return DBUS_TYPE_G_OBJECT_PATH;
case DBUS_TYPE_INT64:
+ *variant_type_out = G_VARIANT_TYPE_INT64;
return G_TYPE_INT64;
case DBUS_TYPE_UINT64:
+ *variant_type_out = G_VARIANT_TYPE_UINT64;
return G_TYPE_UINT64;
case DBUS_TYPE_ARRAY:
if (dbus_signature[1] == DBUS_TYPE_STRING)
+ {
+ *variant_type_out = G_VARIANT_TYPE_STRING_ARRAY;
return G_TYPE_STRV;
+ }
/* other array types are not supported:
* fall through the default case */
default:
@@ -2428,25 +2435,24 @@ typedef struct
} RemoveMethodData;
static void
-account_remove_delete_cb (McdAccount *account, const GError *error,
+account_remove_delete_cb (GObject *source,
+ GAsyncResult *res,
gpointer user_data)
{
RemoveMethodData *data = (RemoveMethodData *) user_data;
+ GError *error = NULL;
- if (error != NULL)
+ if (!mcd_account_delete_finish (MCD_ACCOUNT (source), res, &error))
{
dbus_g_method_return_error (data->context, (GError *) error);
+ g_error_free (error);
return;
}
- if (!data->self->priv->removed)
- {
- data->self->priv->removed = TRUE;
- tp_svc_account_emit_removed (data->self);
- }
+ /* mcd_account_delete() is meant to have deleted it */
+ g_warn_if_fail (data->self->priv->removed);
tp_svc_account_return_from_remove (data->context);
-
g_slice_free (RemoveMethodData, data);
}
@@ -2461,8 +2467,8 @@ account_remove (TpSvcAccount *svc, DBusGMethodInvocation *context)
data->context = context;
DEBUG ("called");
- mcd_account_delete (self, MCD_DBUS_PROP_SET_FLAG_NONE,
- account_remove_delete_cb, data);
+ mcd_account_delete_async (self, MCD_DBUS_PROP_SET_FLAG_NONE,
+ account_remove_delete_cb, data);
}
/*
@@ -2489,11 +2495,13 @@ mcd_account_altered_by_plugin (McdAccount *account,
const McdDBusProp *prop = NULL;
GValue value = G_VALUE_INIT;
GError *error = NULL;
+ const GVariantType *variant_type = NULL;
DEBUG ("%s", name);
if (tp_strdiff (name, "Parameters") &&
- !mcd_storage_init_value_for_attribute (&value, name))
+ !mcd_storage_init_value_for_attribute (&value, name,
+ &variant_type))
{
WARNING ("plugin wants to alter %s but I don't know what "
"type that ought to be", name);
@@ -2506,7 +2514,8 @@ mcd_account_altered_by_plugin (McdAccount *account,
}
else if (!mcd_storage_get_attribute (account->priv->storage,
account->priv->unique_name,
- name, &value, &error))
+ name, variant_type, &value,
+ &error))
{
WARNING ("cannot get new value of %s: %s", name, error->message);
g_error_free (error);
@@ -2695,6 +2704,7 @@ check_one_parameter_update (McdAccount *account,
const TpConnectionManagerParam *param =
tp_protocol_get_param (protocol, name);
GType type;
+ const GVariantType *variant_type;
if (param == NULL)
{
@@ -2704,15 +2714,18 @@ check_one_parameter_update (McdAccount *account,
return FALSE;
}
- type = mc_param_type (param);
+ type = mc_param_type (param, &variant_type);
if (G_VALUE_TYPE (new_value) != type)
{
/* FIXME: use D-Bus type names, not GType names. */
g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
- "parameter '%s' must be of type %s, not %s",
+ "parameter '%s' must be of type %s ('%.*s'), not %s",
tp_connection_manager_param_get_name (param),
- g_type_name (type), G_VALUE_TYPE_NAME (new_value));
+ g_type_name (type),
+ (int) g_variant_type_get_string_length (variant_type),
+ g_variant_type_peek_string (variant_type),
+ G_VALUE_TYPE_NAME (new_value));
return FALSE;
}
@@ -3297,7 +3310,8 @@ mcd_account_setup (McdAccount *account)
g_free (priv->auto_presence_message);
if (mcd_storage_get_attribute (storage, name,
- MC_ACCOUNTS_KEY_AUTOMATIC_PRESENCE, &value,
+ MC_ACCOUNTS_KEY_AUTOMATIC_PRESENCE,
+ G_VARIANT_TYPE ("(uss)"), &value,
NULL))
{
GValueArray *va = g_value_get_boxed (&value);
@@ -3369,7 +3383,9 @@ mcd_account_setup (McdAccount *account)
g_ptr_array_unref (priv->supersedes);
if (mcd_storage_get_attribute (storage, name,
- MC_ACCOUNTS_KEY_SUPERSEDES, &value, NULL))
+ MC_ACCOUNTS_KEY_SUPERSEDES,
+ G_VARIANT_TYPE_OBJECT_PATH_ARRAY,
+ &value, NULL))
{
priv->supersedes = g_value_dup_boxed (&value);
}
@@ -3417,6 +3433,11 @@ set_property (GObject *obj, guint prop_id,
priv->storage = g_value_dup_object (val);
break;
+ case PROP_STORAGE_PLUGIN:
+ g_assert (priv->storage_plugin == NULL);
+ priv->storage_plugin = g_value_dup_object (val);
+ break;
+
case PROP_DBUS_DAEMON:
g_assert (priv->dbus_daemon == NULL);
priv->dbus_daemon = g_value_dup_object (val);
@@ -3503,6 +3524,9 @@ _mcd_account_dispose (GObject *object)
if (!self->priv->removed)
{
+ /* this can happen in certain account-creation error paths,
+ * as far as I can see */
+ DEBUG ("Account never emitted Removed, emitting it now");
self->priv->removed = TRUE;
tp_svc_account_emit_removed (self);
}
@@ -3678,6 +3702,12 @@ mcd_account_class_init (McdAccountClass * klass)
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
+ (object_class, PROP_STORAGE_PLUGIN,
+ g_param_spec_object ("storage-plugin", "storage-plugin",
+ "Storage plugin", MCP_TYPE_ACCOUNT_STORAGE,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property
(object_class, PROP_NAME,
g_param_spec_string ("name", "Unique name", "Unique name",
NULL,
@@ -3753,7 +3783,8 @@ mcd_account_init (McdAccount *account)
McdAccount *
mcd_account_new (McdAccountManager *account_manager,
const gchar *name,
- McdConnectivityMonitor *connectivity)
+ McdConnectivityMonitor *connectivity,
+ McpAccountStorage *storage_plugin)
{
gpointer *obj;
McdStorage *storage = mcd_account_manager_get_storage (account_manager);
@@ -3761,6 +3792,7 @@ mcd_account_new (McdAccountManager *account_manager,
obj = g_object_new (MCD_TYPE_ACCOUNT,
"storage", storage,
+ "storage-plugin", storage_plugin,
"dbus-daemon", dbus,
"connectivity-monitor", connectivity,
"name", name,
@@ -3774,6 +3806,12 @@ _mcd_account_get_storage (McdAccount *account)
return account->priv->storage;
}
+McpAccountStorage *
+mcd_account_get_storage_plugin (McdAccount *account)
+{
+ return account->priv->storage_plugin;
+}
+
/*
* mcd_account_is_valid:
* @account: the #McdAccount.
@@ -5156,19 +5194,6 @@ _mcd_account_needs_dispatch (McdAccount *self)
return self->priv->always_dispatch;
}
-gboolean
-mcd_account_parameter_is_secret (McdAccount *self, const gchar *name)
-{
- McdAccountPrivate *priv = self->priv;
- const TpConnectionManagerParam *param;
-
- param = mcd_manager_get_protocol_param (priv->manager,
- priv->protocol_name, name);
-
- return (param != NULL &&
- tp_connection_manager_param_is_secret (param));
-}
-
void
_mcd_account_set_changing_presence (McdAccount *self, gboolean value)
{
diff --git a/src/mcd-account.h b/src/mcd-account.h
index 59d8d9e3..a0b29afb 100644
--- a/src/mcd-account.h
+++ b/src/mcd-account.h
@@ -61,9 +61,6 @@ GQuark mcd_account_error_quark (void);
typedef void (*McdAccountLoadCb) (McdAccount *account,
const GError *error,
gpointer user_data);
-typedef void (*McdAccountDeleteCb) (McdAccount *account,
- const GError *error,
- gpointer user_data);
struct _McdAccountClass
{
@@ -83,12 +80,16 @@ GType mcd_account_get_type (void);
McdAccount *mcd_account_new (McdAccountManager *account_manager,
const gchar *name,
- McdConnectivityMonitor *minotaur);
+ McdConnectivityMonitor *minotaur,
+ McpAccountStorage *storage_plugin);
-void mcd_account_delete (McdAccount *account,
- McdDBusPropSetFlags flags,
- McdAccountDeleteCb callback,
- gpointer user_data);
+void mcd_account_delete_async (McdAccount *account,
+ McdDBusPropSetFlags flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mcd_account_delete_finish (McdAccount *account,
+ GAsyncResult *result,
+ GError **error);
const gchar *mcd_account_get_unique_name (McdAccount *account);
const gchar *mcd_account_get_object_path (McdAccount *account);
@@ -129,9 +130,6 @@ McdConnection *mcd_account_get_connection (McdAccount *account);
gboolean mcd_account_check_request (McdAccount *account, GHashTable *request,
GError **error);
-gboolean mcd_account_parameter_is_secret (McdAccount *self,
- const gchar *name);
-
void mcd_account_altered_by_plugin (McdAccount *account, const gchar *name);
gchar * mcd_account_dup_display_name (McdAccount *self);
@@ -142,6 +140,7 @@ gboolean mcd_account_get_parameter (McdAccount *account, const gchar *name,
gboolean mcd_account_get_parameter_of_known_type (McdAccount *account,
const gchar *name,
+ const GVariantType *variant_type,
GType type,
GValue *parameter,
GError **error);
@@ -161,6 +160,8 @@ void mcd_account_connection_proceed (McdAccount *account, gboolean success);
void mcd_account_connection_proceed_with_reason
(McdAccount *account, gboolean success, TpConnectionStatusReason reason);
+McpAccountStorage *mcd_account_get_storage_plugin (McdAccount *account);
+
G_END_DECLS
#endif
diff --git a/src/mcd-storage.c b/src/mcd-storage.c
index f82cb797..828d5a1b 100644
--- a/src/mcd-storage.c
+++ b/src/mcd-storage.c
@@ -61,39 +61,11 @@ G_DEFINE_TYPE_WITH_CODE (McdStorage, mcd_storage,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (MCP_TYPE_ACCOUNT_MANAGER, plugin_iface_init))
-typedef struct {
- /* owned string => GVariant
- * e.g. { 'DisplayName': <'Frederick Bloggs'> } */
- GHashTable *attributes;
- /* owned string => owned GVariant
- * e.g. { 'account': <'fred@example.com'>, 'password': <'foo'> } */
- GHashTable *parameters;
- /* owned string => owned string escaped as if for a keyfile
- * e.g. { 'account': 'fred@example.com', 'password': 'foo' }
- * keys of @parameters and @escaped_parameters are disjoint */
- GHashTable *escaped_parameters;
- /* set of owned strings
- * e.g. { 'password': 'password' } */
- GHashTable *secrets;
-} McdStorageAccount;
-
-static void
-mcd_storage_account_free (gpointer p)
-{
- McdStorageAccount *sa = p;
-
- g_hash_table_unref (sa->attributes);
- g_hash_table_unref (sa->parameters);
- g_hash_table_unref (sa->escaped_parameters);
- g_hash_table_unref (sa->secrets);
- g_slice_free (McdStorageAccount, sa);
-}
-
static void
mcd_storage_init (McdStorage *self)
{
self->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, mcd_storage_account_free);
+ g_free, g_object_unref);
}
static void
@@ -200,84 +172,6 @@ mcd_keyfile_escape_variant (GVariant *variant)
return ret;
}
-static McdStorageAccount *
-lookup_account (McdStorage *self,
- const gchar *account)
-{
- return g_hash_table_lookup (self->accounts, account);
-}
-
-static McdStorageAccount *
-ensure_account (McdStorage *self,
- const gchar *account)
-{
- McdStorageAccount *sa = lookup_account (self, account);
-
- if (sa == NULL)
- {
- sa = g_slice_new (McdStorageAccount);
- sa->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, (GDestroyNotify) g_variant_unref);
- sa->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, (GDestroyNotify) g_variant_unref);
- sa->escaped_parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_free);
- sa->secrets = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- g_hash_table_insert (self->accounts, g_strdup (account), sa);
- }
-
- return sa;
-}
-
-static gchar *
-get_value (const McpAccountManager *ma,
- const gchar *account,
- const gchar *key)
-{
- McdStorage *self = MCD_STORAGE (ma);
- McdStorageAccount *sa = lookup_account (self, account);
- GVariant *variant;
- gchar *ret;
-
- if (sa == NULL)
- return NULL;
-
- if (g_str_has_prefix (key, "param-"))
- {
- variant = g_hash_table_lookup (sa->parameters, key + 6);
-
- if (variant != NULL)
- {
- ret = mcd_keyfile_escape_variant (variant);
- g_variant_unref (variant);
- return ret;
- }
- else
- {
- /* OK, we don't have it as a variant. How about the keyfile-escaped
- * version? */
- return g_strdup (g_hash_table_lookup (sa->escaped_parameters,
- key + 6));
- }
- }
- else
- {
- variant = g_hash_table_lookup (sa->attributes, key);
-
- if (variant != NULL)
- {
- ret = mcd_keyfile_escape_variant (variant);
- g_variant_unref (variant);
- return ret;
- }
- else
- {
- return NULL;
- }
- }
-}
-
static struct {
const gchar *type;
const gchar *name;
@@ -318,7 +212,7 @@ static struct {
{ NULL, NULL }
};
-const gchar *
+const GVariantType *
mcd_storage_get_attribute_type (const gchar *attribute)
{
guint i;
@@ -326,7 +220,7 @@ mcd_storage_get_attribute_type (const gchar *attribute)
for (i = 0; known_attributes[i].type != NULL; i++)
{
if (!tp_strdiff (attribute, known_attributes[i].name))
- return known_attributes[i].type;
+ return G_VARIANT_TYPE (known_attributes[i].type);
}
return NULL;
@@ -334,14 +228,18 @@ mcd_storage_get_attribute_type (const gchar *attribute)
gboolean
mcd_storage_init_value_for_attribute (GValue *value,
- const gchar *attribute)
+ const gchar *attribute,
+ const GVariantType **variant_type)
{
- const gchar *s = mcd_storage_get_attribute_type (attribute);
+ const GVariantType *s = mcd_storage_get_attribute_type (attribute);
if (s == NULL)
return FALSE;
- switch (s[0])
+ if (variant_type != NULL)
+ *variant_type = s;
+
+ switch (g_variant_type_peek_string (s)[0])
{
case 's':
g_value_init (value, G_TYPE_STRING);
@@ -358,7 +256,7 @@ mcd_storage_init_value_for_attribute (GValue *value,
case 'a':
{
- switch (s[1])
+ switch (g_variant_type_peek_string (s)[1])
{
case 'o':
g_value_init (value, TP_ARRAY_TYPE_OBJECT_PATH_LIST);
@@ -373,7 +271,7 @@ mcd_storage_init_value_for_attribute (GValue *value,
case '(':
{
- if (!tp_strdiff (s, "(uss)"))
+ if (g_variant_type_equal (s, G_VARIANT_TYPE ("(uss)")))
{
g_value_init (value, TP_STRUCT_TYPE_SIMPLE_PRESENCE);
return TRUE;
@@ -385,181 +283,6 @@ mcd_storage_init_value_for_attribute (GValue *value,
return FALSE;
}
-static gboolean
-mcpa_init_value_for_attribute (const McpAccountManager *mcpa,
- GValue *value,
- const gchar *attribute)
-{
- return mcd_storage_init_value_for_attribute (value, attribute);
-}
-
-static void
-mcpa_set_attribute (const McpAccountManager *ma,
- const gchar *account,
- const gchar *attribute,
- GVariant *value,
- McpAttributeFlags flags)
-{
- McdStorage *self = MCD_STORAGE (ma);
- McdStorageAccount *sa = ensure_account (self, account);
-
- if (value != NULL)
- {
- g_hash_table_insert (sa->attributes, g_strdup (attribute),
- g_variant_ref_sink (value));
- }
- else
- {
- g_hash_table_remove (sa->attributes, attribute);
- }
-}
-
-static void
-mcpa_set_parameter (const McpAccountManager *ma,
- const gchar *account,
- const gchar *parameter,
- GVariant *value,
- McpParameterFlags flags)
-{
- McdStorage *self = MCD_STORAGE (ma);
- McdStorageAccount *sa = ensure_account (self, account);
-
- g_hash_table_remove (sa->parameters, parameter);
- g_hash_table_remove (sa->escaped_parameters, parameter);
-
- if (value != NULL)
- g_hash_table_insert (sa->parameters, g_strdup (parameter),
- g_variant_ref_sink (value));
-
- if (flags & MCP_PARAMETER_FLAG_SECRET)
- {
- DEBUG ("flagging %s parameter %s as secret", account, parameter);
- g_hash_table_add (sa->secrets, g_strdup (parameter));
- }
-}
-
-static void
-set_value (const McpAccountManager *ma,
- const gchar *account,
- const gchar *key,
- const gchar *value)
-{
- McdStorage *self = MCD_STORAGE (ma);
- McdStorageAccount *sa = ensure_account (self, account);
-
- if (g_str_has_prefix (key, "param-"))
- {
- g_hash_table_remove (sa->parameters, key + 6);
- g_hash_table_remove (sa->escaped_parameters, key + 6);
-
- if (value != NULL)
- g_hash_table_insert (sa->escaped_parameters, g_strdup (key + 6),
- g_strdup (value));
- }
- else
- {
- if (value != NULL)
- {
- GValue tmp = G_VALUE_INIT;
- GError *error = NULL;
-
- if (!mcd_storage_init_value_for_attribute (&tmp, key))
- {
- g_warning ("Not sure what the type of '%s' is, assuming string",
- key);
- g_value_init (&tmp, G_TYPE_STRING);
- }
-
- if (mcd_keyfile_unescape_value (value, &tmp, &error))
- {
- g_hash_table_insert (sa->attributes, g_strdup (key),
- g_variant_ref_sink (dbus_g_value_build_g_variant (&tmp)));
- g_value_unset (&tmp);
- }
- else
- {
- g_warning ("Could not decode attribute '%s':'%s' from plugin: %s",
- key, value, error->message);
- g_error_free (error);
- g_hash_table_remove (sa->attributes, key);
- }
- }
- else
- {
- g_hash_table_remove (sa->attributes, key);
- }
- }
-}
-
-static GStrv
-list_keys (const McpAccountManager *ma,
- const gchar * account)
-{
- McdStorage *self = MCD_STORAGE (ma);
- GPtrArray *ret = g_ptr_array_new ();
- McdStorageAccount *sa = lookup_account (self, account);
-
- if (sa != NULL)
- {
- GHashTableIter iter;
- gpointer k;
-
- g_hash_table_iter_init (&iter, sa->attributes);
-
- while (g_hash_table_iter_next (&iter, &k, NULL))
- g_ptr_array_add (ret, g_strdup (k));
-
- g_hash_table_iter_init (&iter, sa->parameters);
-
- while (g_hash_table_iter_next (&iter, &k, NULL))
- g_ptr_array_add (ret, g_strdup_printf ("param-%s", (gchar *) k));
- }
-
- g_ptr_array_add (ret, NULL);
- return (GStrv) g_ptr_array_free (ret, FALSE);
-}
-
-static gboolean
-is_secret (const McpAccountManager *ma,
- const gchar *account,
- const gchar *key)
-{
- McdStorage *self = MCD_STORAGE (ma);
- McdStorageAccount *sa = lookup_account (self, account);
-
- if (sa == NULL || !g_str_has_prefix (key, "param-"))
- return FALSE;
-
- return g_hash_table_contains (sa->secrets, key + 6);
-}
-
-static void
-mcd_storage_make_secret (McdStorage *self,
- const gchar *account,
- const gchar *key)
-{
- McdStorageAccount *sa;
-
- g_return_if_fail (MCD_IS_STORAGE (self));
- g_return_if_fail (account != NULL);
- g_return_if_fail (key != NULL);
-
- if (!g_str_has_prefix (key, "param-"))
- return;
-
- DEBUG ("flagging %s parameter %s as secret", account, key + 6);
- sa = ensure_account (self, account);
- g_hash_table_add (sa->secrets, g_strdup (key + 6));
-}
-
-static void
-make_secret (const McpAccountManager *ma,
- const gchar *account,
- const gchar *key)
-{
- mcd_storage_make_secret (MCD_STORAGE (ma), account, key);
-}
-
static gchar *
unique_name (const McpAccountManager *ma,
const gchar *manager,
@@ -606,17 +329,26 @@ identify_account_cb (TpProxy *proxy,
{
if (error == NULL)
{
+ DEBUG ("identified account: %s", identification);
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))
+ else if (g_error_matches (error, TP_ERROR, TP_ERROR_INVALID_HANDLE) ||
+ g_error_matches (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT))
{
- g_task_return_pointer (task, g_strdup (g_task_get_task_data (task)),
- g_free);
+ /* The connection manager didn't like our account parameters.
+ * Give up now. */
+ DEBUG ("failed to identify account: %s #%d: %s",
+ g_quark_to_string (error->domain), error->code, error->message);
+ g_task_return_error (task, g_error_copy (error));
}
else
{
- g_task_return_error (task, g_error_copy (error));
+ /* We weren't able to identify the account, but carry on and hope
+ * for the best... */
+ DEBUG ("ignoring failure to identify account: %s #%d: %s",
+ g_quark_to_string (error->domain), error->code, error->message);
+ g_task_return_pointer (task, g_strdup (g_task_get_task_data (task)),
+ g_free);
}
}
@@ -677,8 +409,8 @@ identify_account_async (McpAccountManager *mcpa,
static gint
account_storage_cmp (gconstpointer a, gconstpointer b)
{
- gint pa = mcp_account_storage_priority (a);
- gint pb = mcp_account_storage_priority (b);
+ gint pa = mcp_account_storage_priority ((McpAccountStorage *) a);
+ gint pb = mcp_account_storage_priority ((McpAccountStorage *) b);
if (pa > pb) return -1;
if (pa < pb) return 1;
@@ -766,11 +498,9 @@ mcd_storage_load (McdStorage *self)
sort_and_cache_plugins ();
- store = g_list_last (stores);
-
- /* fetch accounts stored in plugins, in reverse priority so higher prio *
- * plugins can overwrite lower prio ones' account data */
- while (store != NULL)
+ /* fetch accounts stored in plugins, highest priority first, so that
+ * low priority plugins can be overidden by high priority */
+ for (store = stores; store != NULL; store = store->next)
{
GList *account;
McpAccountStorage *plugin = store->data;
@@ -781,80 +511,38 @@ mcd_storage_load (McdStorage *self)
DEBUG ("listing from plugin %s [prio: %d]", pname, prio);
for (account = stored; account != NULL; account = g_list_next (account))
{
+ GError *error = NULL;
gchar *name = account->data;
DEBUG ("fetching %s from plugin %s [prio: %d]", name, pname, prio);
- mcd_storage_add_account_from_plugin (self, plugin, name);
+
+ if (!mcd_storage_add_account_from_plugin (self, plugin, name,
+ &error))
+ {
+ DEBUG ("%s", error->message);
+ g_clear_error (&error);
+ }
+
g_free (name);
}
/* already freed the contents, just need to free the list itself */
g_list_free (stored);
- store = g_list_previous (store);
}
}
/*
- * mcd_storage_dup_accounts:
+ * mcd_storage_get_accounts:
* @storage: An object implementing the #McdStorage interface
* @n: place for the number of accounts to be written to (or %NULL)
*
- * Returns: a newly allocated GStrv containing the unique account names,
- * which must be freed by the caller with g_strfreev().
+ * Returns: (transfer none) (element-type utf8 Mcp.AccountStorage): a
+ * map from account object path tail to plugin
*/
-GStrv
-mcd_storage_dup_accounts (McdStorage *self,
- gsize *n)
+GHashTable *
+mcd_storage_get_accounts (McdStorage *self)
{
- GPtrArray *ret = g_ptr_array_new ();
- GHashTableIter iter;
- gpointer k, v;
-
- g_hash_table_iter_init (&iter, self->accounts);
-
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- McdStorageAccount *sa = v;
-
- if (g_hash_table_size (sa->attributes) > 0)
- g_ptr_array_add (ret, g_strdup (k));
- }
-
- g_ptr_array_add (ret, NULL);
- return (GStrv) g_ptr_array_free (ret, FALSE);
-}
-
-/*
- * mcd_storage_dup_attributes:
- * @storage: An object implementing the #McdStorage interface
- * @account: unique name of the account
- * @n: place for the number of attributes to be written to (or %NULL)
- *
- * Returns: a newly allocated GStrv containing the names of all the
- * attributes or parameters currently stored for @account. Must be
- * freed by the caller with g_strfreev().
- */
-GStrv
-mcd_storage_dup_attributes (McdStorage *self,
- const gchar *account,
- gsize *n)
-{
- GPtrArray *ret = g_ptr_array_new ();
- McdStorageAccount *sa = lookup_account (self, account);
-
- if (sa != NULL)
- {
- GHashTableIter iter;
- gpointer k;
-
- g_hash_table_iter_init (&iter, sa->attributes);
-
- while (g_hash_table_iter_next (&iter, &k, NULL))
- g_ptr_array_add (ret, g_strdup (k));
- }
-
- g_ptr_array_add (ret, NULL);
- return (GStrv) g_ptr_array_free (ret, FALSE);
+ return self->accounts;
}
/*
@@ -874,22 +562,15 @@ McpAccountStorage *
mcd_storage_get_plugin (McdStorage *self,
const gchar *account)
{
- GList *store = stores;
- McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self);
- McpAccountStorage *owner = NULL;
+ McpAccountStorage *plugin;
g_return_val_if_fail (MCD_IS_STORAGE (self), NULL);
g_return_val_if_fail (account != NULL, NULL);
- for (; store != NULL && owner == NULL; store = g_list_next (store))
- {
- McpAccountStorage *plugin = store->data;
-
- if (mcp_account_storage_owns (plugin, ma, account))
- owner = plugin;
- }
+ plugin = g_hash_table_lookup (self->accounts, account);
+ g_return_val_if_fail (plugin != NULL, NULL);
- return owner;
+ return plugin;
}
/*
@@ -916,7 +597,8 @@ mcd_storage_dup_string (McdStorage *self,
g_value_init (&tmp, G_TYPE_STRING);
- if (!mcd_storage_get_attribute (self, account, attribute, &tmp, NULL))
+ if (!mcd_storage_get_attribute (self, account, attribute,
+ G_VARIANT_TYPE_STRING, &tmp, NULL))
return NULL;
ret = g_value_dup_string (&tmp);
@@ -963,36 +645,42 @@ gboolean
mcd_storage_get_attribute (McdStorage *self,
const gchar *account,
const gchar *attribute,
+ const GVariantType *type,
GValue *value,
GError **error)
{
- McdStorageAccount *sa;
+ McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self);
+ McpAccountStorage *plugin;
GVariant *variant;
+ gboolean ret;
g_return_val_if_fail (MCD_IS_STORAGE (self), FALSE);
g_return_val_if_fail (account != NULL, FALSE);
g_return_val_if_fail (attribute != NULL, FALSE);
g_return_val_if_fail (!g_str_has_prefix (attribute, "param-"), FALSE);
- sa = lookup_account (self, account);
+ plugin = g_hash_table_lookup (self->accounts, account);
- if (sa == NULL)
+ if (plugin == NULL)
{
g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
"Account %s does not exist", account);
return FALSE;
}
- variant = g_hash_table_lookup (sa->attributes, attribute);
+ variant = mcp_account_storage_get_attribute (plugin, ma, account,
+ attribute, type, NULL);
if (variant == NULL)
{
g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
- "Setting '%s' not stored by account %s", attribute, account);
+ "Account %s has no attribute '%s'", account, attribute);
return FALSE;
}
- return mcd_storage_coerce_variant_to_value (variant, value, error);
+ ret = mcd_storage_coerce_variant_to_value (variant, value, error);
+ g_variant_unref (variant);
+ return ret;
}
/*
@@ -1007,52 +695,42 @@ gboolean
mcd_storage_get_parameter (McdStorage *self,
const gchar *account,
const gchar *parameter,
+ const GVariantType *type,
GValue *value,
GError **error)
{
- McdStorageAccount *sa;
- const gchar *escaped;
+ McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self);
+ McpAccountStorage *plugin;
GVariant *variant;
+ gboolean ret;
g_return_val_if_fail (MCD_IS_STORAGE (self), FALSE);
g_return_val_if_fail (account != NULL, FALSE);
g_return_val_if_fail (parameter != NULL, FALSE);
+ g_return_val_if_fail (!g_str_has_prefix (parameter, "param-"), FALSE);
- sa = lookup_account (self, account);
+ plugin = g_hash_table_lookup (self->accounts, account);
- if (sa == NULL)
+ if (plugin == NULL)
{
g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
"Account %s does not exist", account);
return FALSE;
}
- variant = g_hash_table_lookup (sa->parameters, parameter);
-
- if (variant != NULL)
- return mcd_storage_coerce_variant_to_value (variant, value, error);
+ variant = mcp_account_storage_get_parameter (plugin, ma, account,
+ parameter, type, NULL);
- /* OK, we don't have it as a variant. How about the keyfile-escaped
- * version? */
- escaped = g_hash_table_lookup (sa->escaped_parameters, parameter);
-
- if (escaped == NULL)
+ if (variant == NULL)
{
g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
- "Parameter '%s' not stored by account %s", parameter, account);
+ "Account %s has no parameter '%s'", account, parameter);
return FALSE;
}
- return mcd_keyfile_unescape_value (escaped, value, error);
-}
-
-static gboolean
-mcpa_unescape_value_from_keyfile (const McpAccountManager *unused G_GNUC_UNUSED,
- const gchar *escaped,
- GValue *value,
- GError **error)
-{
- return mcd_keyfile_unescape_value (escaped, value, error);
+ ret = mcd_storage_coerce_variant_to_value (variant, value, error);
+ g_variant_unref (variant);
+ return ret;
}
/*
@@ -1508,7 +1186,8 @@ mcd_storage_get_boolean (McdStorage *self,
g_value_init (&tmp, G_TYPE_BOOLEAN);
- if (!mcd_storage_get_attribute (self, account, attribute, &tmp, NULL))
+ if (!mcd_storage_get_attribute (self, account, attribute,
+ G_VARIANT_TYPE_BOOLEAN, &tmp, NULL))
return FALSE;
return g_value_get_boolean (&tmp);
@@ -1536,65 +1215,60 @@ mcd_storage_get_integer (McdStorage *self,
g_value_init (&tmp, G_TYPE_INT);
- if (!mcd_storage_get_attribute (self, account, attribute, &tmp, NULL))
+ if (!mcd_storage_get_attribute (self, account, attribute,
+ G_VARIANT_TYPE_INT32, &tmp, NULL))
return FALSE;
return g_value_get_int (&tmp);
}
-static void
+static gboolean
update_storage (McdStorage *self,
const gchar *account,
+ gboolean parameter,
const gchar *key,
- GVariant *variant,
- const gchar *escaped,
- gboolean secret)
+ GVariant *variant)
{
- GList *store;
- gboolean done = FALSE;
- gboolean parameter = g_str_has_prefix (key, "param-");
McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self);
+ gboolean updated = FALSE;
+ McpAccountStorage *plugin;
+ const gchar *pn;
+ McpAccountStorageSetResult res;
- if (secret)
- mcd_storage_make_secret (self, account, key);
+ plugin = g_hash_table_lookup (self->accounts, account);
+ g_return_val_if_fail (plugin != NULL, FALSE);
+ pn = mcp_account_storage_name (plugin);
- /* we're deleting, which is unconditional, no need to check if anyone *
- * claims this setting for themselves */
- if (escaped == NULL)
- done = TRUE;
+ if (parameter)
+ res = mcp_account_storage_set_parameter (plugin, ma, account,
+ key, variant, MCP_PARAMETER_FLAG_NONE);
+ else
+ res = mcp_account_storage_set_attribute (plugin, ma, account,
+ key, variant, MCP_ATTRIBUTE_FLAG_NONE);
- for (store = stores; store != NULL; store = g_list_next (store))
+ switch (res)
{
- McpAccountStorage *plugin = store->data;
- const gchar *pn = mcp_account_storage_name (plugin);
+ case MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED:
+ DEBUG ("MCP:%s -> store %s %s.%s", pn,
+ parameter ? "parameter" : "attribute", account, key);
+ updated = TRUE;
+ break;
- if (done)
- {
- DEBUG ("MCP:%s -> delete %s.%s", pn, account, key);
- mcp_account_storage_delete (plugin, ma, account, key);
- }
- else if (variant != NULL && !parameter &&
- mcp_account_storage_set_attribute (plugin, ma, account, key, variant,
- MCP_ATTRIBUTE_FLAG_NONE))
- {
- done = TRUE;
- DEBUG ("MCP:%s -> store attribute %s.%s", pn, account, key);
- }
- else if (variant != NULL && parameter &&
- mcp_account_storage_set_parameter (plugin, ma, account, key + 6,
- variant,
- secret ? MCP_PARAMETER_FLAG_SECRET : MCP_PARAMETER_FLAG_NONE))
- {
- done = TRUE;
- DEBUG ("MCP:%s -> store parameter %s.%s", pn, account, key);
- }
- else
- {
- done = mcp_account_storage_set (plugin, ma, account, key, escaped);
- DEBUG ("MCP:%s -> %s %s.%s",
- pn, done ? "store" : "ignore", account, key);
- }
+ case MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED:
+ DEBUG ("MCP:%s -> failed to store %s %s.%s",
+ pn, parameter ? "parameter" : "attribute", account, key);
+ break;
+
+ case MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED:
+ DEBUG ("MCP:%s -> no change to %s %s.%s",
+ pn, parameter ? "parameter" : "attribute", account, key);
+ break;
+
+ default:
+ g_warn_if_reached ();
}
+
+ return updated;
}
/*
@@ -1665,45 +1339,24 @@ mcd_storage_set_attribute (McdStorage *self,
const gchar *attribute,
const GValue *value)
{
- McdStorageAccount *sa;
- GVariant *old_v;
GVariant *new_v;
gboolean updated = FALSE;
+ McpAccountStorage *plugin;
g_return_val_if_fail (MCD_IS_STORAGE (self), FALSE);
g_return_val_if_fail (account != NULL, FALSE);
g_return_val_if_fail (attribute != NULL, FALSE);
g_return_val_if_fail (!g_str_has_prefix (attribute, "param-"), FALSE);
- sa = ensure_account (self, account);
+ plugin = g_hash_table_lookup (self->accounts, account);
+ g_return_val_if_fail (plugin != NULL, FALSE);
if (value != NULL)
new_v = g_variant_ref_sink (dbus_g_value_build_g_variant (value));
else
new_v = NULL;
- old_v = g_hash_table_lookup (sa->attributes, attribute);
-
- if (!mcd_nullable_variant_equal (old_v, new_v))
- {
- gchar *escaped = NULL;
-
- /* First put it in the attributes hash table. (Watch out, this might
- * invalidate old_v.) */
- if (new_v == NULL)
- g_hash_table_remove (sa->attributes, attribute);
- else
- g_hash_table_insert (sa->attributes, g_strdup (attribute),
- g_variant_ref (new_v));
-
- /* OK now we have to escape it in a stupid way for plugins */
- if (value != NULL)
- escaped = mcd_keyfile_escape_value (value);
-
- update_storage (self, account, attribute, new_v, escaped, FALSE);
- g_free (escaped);
- updated = TRUE;
- }
+ updated = update_storage (self, account, FALSE, attribute, new_v);
tp_clear_pointer (&new_v, g_variant_unref);
return updated;
@@ -1715,8 +1368,6 @@ mcd_storage_set_attribute (McdStorage *self,
* @account: the unique name of an account
* @parameter: the name of the parameter, e.g. "account"
* @value: the value to be stored (or %NULL to erase it)
- * @secret: whether the value is confidential (might get stored in the
- * keyring, for example)
*
* Copies and stores the supplied @value (or removes it if %NULL) in the
* internal cache.
@@ -1731,66 +1382,30 @@ gboolean
mcd_storage_set_parameter (McdStorage *self,
const gchar *account,
const gchar *parameter,
- const GValue *value,
- gboolean secret)
+ const GValue *value)
{
- GVariant *old_v;
GVariant *new_v = NULL;
- const gchar *old_escaped;
- gchar *new_escaped = NULL;
- McdStorageAccount *sa;
gboolean updated = FALSE;
+ McpAccountStorage *plugin;
g_return_val_if_fail (MCD_IS_STORAGE (self), FALSE);
g_return_val_if_fail (account != NULL, FALSE);
g_return_val_if_fail (parameter != NULL, FALSE);
- sa = ensure_account (self, account);
+ plugin = g_hash_table_lookup (self->accounts, account);
+ g_return_val_if_fail (plugin != NULL, FALSE);
if (value != NULL)
{
- new_escaped = mcd_keyfile_escape_value (value);
new_v = g_variant_ref_sink (dbus_g_value_build_g_variant (value));
}
- old_v = g_hash_table_lookup (sa->parameters, parameter);
- old_escaped = g_hash_table_lookup (sa->escaped_parameters, parameter);
-
- if (old_v != NULL)
- updated = !mcd_nullable_variant_equal (old_v, new_v);
- else if (old_escaped != NULL)
- updated = tp_strdiff (old_escaped, new_escaped);
- else
- updated = (value != NULL);
-
- if (updated)
- {
- gchar key[MAX_KEY_LENGTH];
-
- g_hash_table_remove (sa->parameters, parameter);
- g_hash_table_remove (sa->escaped_parameters, parameter);
-
- if (new_v != NULL)
- g_hash_table_insert (sa->parameters, g_strdup (parameter),
- g_variant_ref (new_v));
-
- g_snprintf (key, sizeof (key), "param-%s", parameter);
- update_storage (self, account, key, new_v, new_escaped, secret);
- return TRUE;
- }
+ updated = update_storage (self, account, TRUE, parameter, new_v);
- g_free (new_escaped);
tp_clear_pointer (&new_v, g_variant_unref);
return updated;
}
-static gchar *
-mcpa_escape_value_for_keyfile (const McpAccountManager *unused G_GNUC_UNUSED,
- const GValue *value)
-{
- return mcd_keyfile_escape_value (value);
-}
-
/*
* @value: a populated #GValue of a supported #GType
*
@@ -2047,6 +1662,7 @@ mcd_keyfile_set_variant (GKeyFile *keyfile,
* @manager: the name of the manager
* @protocol: the name of the protocol
* @identification: the result of IdentifyAccount
+ * @plugin_out: (out) (transfer full): the plugin we used
* @error: a #GError to fill when returning %NULL
*
* Create a new account in storage. This should not store any
@@ -2062,10 +1678,15 @@ mcd_storage_create_account (McdStorage *self,
const gchar *manager,
const gchar *protocol,
const gchar *identification,
+ McpAccountStorage **plugin_out,
GError **error)
{
GList *store;
McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self);
+ gchar *ret;
+
+ if (plugin_out != NULL)
+ *plugin_out = NULL;
g_return_val_if_fail (MCD_IS_STORAGE (self), NULL);
g_return_val_if_fail (!tp_str_empty (manager), NULL);
@@ -2080,8 +1701,21 @@ mcd_storage_create_account (McdStorage *self,
if (!tp_strdiff (mcp_account_storage_provider (plugin), provider))
{
- return mcp_account_storage_create (plugin, ma, manager,
+ ret = mcp_account_storage_create (plugin, ma, manager,
protocol, identification, error);
+ if (mcd_storage_add_account_from_plugin (self, plugin, ret,
+ error))
+ {
+ if (plugin_out != NULL)
+ *plugin_out = g_object_ref (plugin);
+
+ return ret;
+ }
+ else
+ {
+ g_free (ret);
+ return NULL;
+ }
}
}
@@ -2093,50 +1727,30 @@ mcd_storage_create_account (McdStorage *self,
/* No provider specified, let's pick the first plugin able to create this
* account in priority order.
- *
- * FIXME: This is rather subtle, and relies on the fact that accounts
- * aren't always strongly tied to a single plugin.
- *
- * For plugins that only store their accounts set up specifically
- * through them (like the libaccounts/SSO pseudo-plugin,
- * McdAccountManagerSSO), create() will fail as unimplemented,
- * and we'll fall through to the next plugin. Eventually we'll
- * reach the default keyfile+gnome-keyring plugin, or another
- * plugin that accepts arbitrary accounts. When set() is called,
- * the libaccounts/SSO plugin will reject that too, and again,
- * we'll fall through to a plugin that accepts arbitrary
- * accounts.
- *
- * Plugins that will accept arbitrary accounts being created
- * via D-Bus (like the default keyfile+gnome-keyring plugin,
- * and the account-diversion plugin in tests/twisted)
- * should, in principle, implement create() to be successful.
- * If they do, their create() will succeed, and later, so will
- * their set().
- *
- * We can't necessarily rely on all such plugins implementing
- * create(), because it isn't a mandatory part of the plugin
- * API (it was added later). However, as it happens, the
- * default plugin returns successfully from create() without
- * really doing anything. When we iterate through the accounts again
- * to call set(), higher-priority plugins are given a second
- * chance to intercept that; so we end up with create() in
- * the default plugin being followed by set() from the
- * higher-priority plugin. In theory that's bad because it
- * splits the account across two plugins, but in practice
- * it isn't a problem because the default plugin's create()
- * doesn't really do anything anyway.
*/
for (store = stores; store != NULL; store = g_list_next (store))
{
McpAccountStorage *plugin = store->data;
- gchar *ret;
ret = mcp_account_storage_create (plugin, ma, manager, protocol,
identification, error);
if (ret != NULL)
- return ret;
+ {
+ if (mcd_storage_add_account_from_plugin (self, plugin, ret,
+ error))
+ {
+ if (plugin_out != NULL)
+ *plugin_out = g_object_ref (plugin);
+
+ return ret;
+ }
+ else
+ {
+ g_free (ret);
+ return NULL;
+ }
+ }
g_clear_error (error);
}
@@ -2150,6 +1764,29 @@ mcd_storage_create_account (McdStorage *self,
return NULL;
}
+static void
+delete_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ const gchar *account_name = user_data;
+
+ if (mcp_account_storage_delete_finish (MCP_ACCOUNT_STORAGE (source),
+ res, &error))
+ {
+ DEBUG ("deleted account %s", account_name);
+ }
+ else
+ {
+ DEBUG ("could not delete account %s (but no way to signal that): "
+ "%s #%d: %s", account_name,
+ g_quark_to_string (error->domain), error->code, error->message);
+ g_error_free (error);
+ }
+
+ g_free (user_data);
+}
/*
* mcd_storage_delete_account:
@@ -2165,20 +1802,19 @@ void
mcd_storage_delete_account (McdStorage *self,
const gchar *account)
{
- GList *store;
McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self);
+ McpAccountStorage *plugin;
g_return_if_fail (MCD_IS_STORAGE (self));
g_return_if_fail (account != NULL);
- g_hash_table_remove (self->accounts, account);
-
- for (store = stores; store != NULL; store = g_list_next (store))
- {
- McpAccountStorage *plugin = store->data;
+ plugin = g_hash_table_lookup (self->accounts, account);
+ g_return_if_fail (plugin != NULL);
- mcp_account_storage_delete (plugin, ma, account, NULL);
- }
+ /* FIXME: stop ignoring the error (if any), and make this method async
+ * in order to pass the error up to McdAccount */
+ mcp_account_storage_delete_async (plugin, ma, account, NULL,
+ delete_cb, g_strdup (account));
}
/*
@@ -2192,27 +1828,21 @@ mcd_storage_delete_account (McdStorage *self,
void
mcd_storage_commit (McdStorage *self, const gchar *account)
{
- GList *store;
McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self);
+ McpAccountStorage *plugin;
+ const gchar *pname;
g_return_if_fail (MCD_IS_STORAGE (self));
+ g_return_if_fail (account != NULL);
- for (store = stores; store != NULL; store = g_list_next (store))
- {
- McpAccountStorage *plugin = store->data;
- const gchar *pname = mcp_account_storage_name (plugin);
+ plugin = g_hash_table_lookup (self->accounts, account);
+ g_return_if_fail (plugin != NULL);
- if (account != NULL)
- {
- DEBUG ("flushing plugin %s %s to long term storage", pname, account);
- mcp_account_storage_commit_one (plugin, ma, account);
- }
- else
- {
- DEBUG ("flushing plugin %s to long term storage", pname);
- mcp_account_storage_commit (plugin, ma);
- }
- }
+ pname = mcp_account_storage_name (plugin);
+
+ /* FIXME: fd.o #29563: this should be async, really */
+ DEBUG ("flushing plugin %s %s to long term storage", pname, account);
+ mcp_account_storage_commit (plugin, ma, account);
}
/*
@@ -2269,40 +1899,62 @@ mcd_storage_ready (McdStorage *self)
}
}
+static GVariant *
+mcpa_unescape_variant_from_keyfile (const McpAccountManager *mcpa,
+ const gchar *escaped,
+ const GVariantType *type,
+ GError **error)
+{
+ GKeyFile *keyfile;
+ GVariant *ret;
+
+ g_return_val_if_fail (escaped != NULL, NULL);
+ g_return_val_if_fail (type != NULL, NULL);
+
+ keyfile = g_key_file_new ();
+ g_key_file_set_value (keyfile, "g", "k", escaped);
+ ret = mcd_keyfile_get_variant (keyfile, "g", "k", type, error);
+ g_key_file_free (keyfile);
+
+ if (ret != NULL)
+ g_variant_ref_sink (ret);
+
+ return ret;
+}
+
static void
plugin_iface_init (McpAccountManagerIface *iface,
gpointer unused G_GNUC_UNUSED)
{
DEBUG ();
- iface->get_value = get_value;
- iface->set_value = set_value;
- iface->set_attribute = mcpa_set_attribute;
- iface->set_parameter = mcpa_set_parameter;
- 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;
- iface->unescape_value_from_keyfile = mcpa_unescape_value_from_keyfile;
- iface->init_value_for_attribute = mcpa_init_value_for_attribute;
+ iface->unescape_variant_from_keyfile = mcpa_unescape_variant_from_keyfile;
}
gboolean
mcd_storage_add_account_from_plugin (McdStorage *self,
McpAccountStorage *plugin,
- const gchar *account)
+ const gchar *account,
+ GError **error)
{
- if (!mcp_account_storage_get (plugin, MCP_ACCOUNT_MANAGER (self),
- account, NULL))
+ McpAccountStorage *other = g_hash_table_lookup (self->accounts, account);
+
+ if (other != NULL)
{
- g_warning ("plugin %s disowned account %s",
- mcp_account_storage_name (plugin), account);
+ g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
+ "account %s already exists in plugin '%s', cannot create "
+ "for plugin '%s'",
+ account,
+ mcp_account_storage_name (other),
+ mcp_account_storage_name (plugin));
return FALSE;
}
+ g_hash_table_insert (self->accounts, g_strdup (account),
+ g_object_ref (plugin));
return TRUE;
}
diff --git a/src/mcd-storage.h b/src/mcd-storage.h
index e4408451..c2624a40 100644
--- a/src/mcd-storage.h
+++ b/src/mcd-storage.h
@@ -30,7 +30,7 @@ G_BEGIN_DECLS
typedef struct {
GObject parent;
TpDBusDaemon *dbusd;
- /* owned string => owned McdStorageAccount */
+ /* owned string => owned McpAccountStorage */
GHashTable *accounts;
} McdStorage;
@@ -64,11 +64,7 @@ void mcd_storage_connect_signal (const gchar *signal,
void mcd_storage_load (McdStorage *storage);
-GStrv mcd_storage_dup_accounts (McdStorage *storage, gsize *n);
-
-GStrv mcd_storage_dup_attributes (McdStorage *storage,
- const gchar *account,
- gsize *n);
+GHashTable *mcd_storage_get_accounts (McdStorage *storage);
gboolean mcd_storage_set_string (McdStorage *storage,
const gchar *account,
@@ -88,14 +84,14 @@ gboolean mcd_storage_set_attribute (McdStorage *storage,
gboolean mcd_storage_set_parameter (McdStorage *storage,
const gchar *account,
const gchar *parameter,
- const GValue *value,
- gboolean secret);
+ const GValue *value);
gchar *mcd_storage_create_account (McdStorage *storage,
const gchar *provider,
const gchar *manager,
const gchar *protocol,
const gchar *identification,
+ McpAccountStorage **plugin_out,
GError **error);
void mcd_storage_delete_account (McdStorage *storage, const gchar *account);
@@ -109,12 +105,14 @@ gchar *mcd_storage_dup_string (McdStorage *storage,
gboolean mcd_storage_get_attribute (McdStorage *storage,
const gchar *account,
const gchar *attribute,
+ const GVariantType *type,
GValue *value,
GError **error);
gboolean mcd_storage_get_parameter (McdStorage *storage,
const gchar *account,
const gchar *parameter,
+ const GVariantType *type,
GValue *value,
GError **error);
@@ -133,7 +131,8 @@ G_GNUC_INTERNAL void _mcd_storage_store_connections (McdStorage *storage);
gboolean mcd_storage_add_account_from_plugin (McdStorage *storage,
McpAccountStorage *plugin,
- const gchar *account);
+ const gchar *account,
+ GError **error);
GVariant *mcd_keyfile_get_variant (GKeyFile *keyfile,
const gchar *group,
@@ -159,9 +158,10 @@ gboolean mcd_keyfile_unescape_value (const gchar *escaped,
GValue *value,
GError **error);
-const gchar *mcd_storage_get_attribute_type (const gchar *attribute);
+const GVariantType *mcd_storage_get_attribute_type (const gchar *attribute);
gboolean mcd_storage_init_value_for_attribute (GValue *value,
- const gchar *attribute);
+ const gchar *attribute,
+ const GVariantType **variant_type);
G_END_DECLS
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index 587d6b0c..2a96647f 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -74,8 +74,12 @@ TWISTED_BASIC_TESTS = \
# account-storage/*.py need their own instances.
TWISTED_SPECIAL_BUILD_TESTS = \
account-manager/connectivity.py \
- account-storage/default-keyring-storage.py \
- account-storage/diverted-storage.py
+ account-storage/diverted-storage.py \
+ account-storage/5-12.py \
+ account-storage/5-14.py \
+ account-storage/create-new.py \
+ account-storage/load-keyfiles.py \
+ $(NULL)
# Tests that are usually too slow to run.
TWISTED_SLOW_TESTS = \
@@ -105,6 +109,7 @@ TWISTED_OTHER_FILES = \
fakeconnectivity.py \
mctest.py \
servicetest.py \
+ account-storage/storage_helper.py \
telepathy/clients/README \
telepathy/clients/AbiWord.client \
telepathy/clients/Logger.client \
diff --git a/tests/twisted/account-manager/auto-connect.py b/tests/twisted/account-manager/auto-connect.py
index 46b13364..28cfb2ab 100644
--- a/tests/twisted/account-manager/auto-connect.py
+++ b/tests/twisted/account-manager/auto-connect.py
@@ -21,6 +21,7 @@ import dbus
"""
import os
+import os.path
import dbus
import dbus.service
@@ -65,8 +66,12 @@ def preseed(q, bus, fake_accounts_service):
'password': r'\\\\ionstorm\\\\',
})
- os.makedirs(accounts_dir + '/' + account_id)
- avatar_bin = open(accounts_dir + '/' + account_id + '/avatar.bin', 'w')
+ avatar_filename = account_id
+ avatar_filename = avatar_filename.replace('/', '-') + '.avatar'
+ avatar_filename = (os.environ['XDG_DATA_HOME'] +
+ '/telepathy/mission-control/' + avatar_filename)
+ os.makedirs(os.path.dirname(avatar_filename))
+ avatar_bin = open(avatar_filename, 'w')
avatar_bin.write('Deus Ex')
avatar_bin.close()
diff --git a/tests/twisted/account-manager/avatar-refresh.py b/tests/twisted/account-manager/avatar-refresh.py
index f76d7fb6..d914c439 100644
--- a/tests/twisted/account-manager/avatar-refresh.py
+++ b/tests/twisted/account-manager/avatar-refresh.py
@@ -90,15 +90,6 @@ class Account(object):
avatar_bin = open(avatar_filename, 'w')
avatar_bin.write(local_avatar)
avatar_bin.close()
- elif not avatars_persist:
- self.avatar_location = 'old'
- # exercise migration from ~/.mission-control in a
- # situation where MC should "win"
- os.makedirs(accounts_dir + '/' + self.id)
- avatar_bin = open(
- accounts_dir + '/' + self.id + '/avatar.bin', 'w')
- avatar_bin.write(local_avatar)
- avatar_bin.close()
else:
# store it in the normal location
self.avatar_location = 'home'
@@ -258,18 +249,7 @@ class Account(object):
self.test_migration(bus, q, conn, account_proxy)
def test_migration(self, bus, q, conn, account_proxy):
- if self.avatar_location == 'old':
- # The avatar got migrated to the new location.
- assert not os.path.exists(os.environ['MC_ACCOUNT_DIR'] + '/' +
- self.id + '/avatar.bin')
- assert not os.path.exists(os.environ['MC_ACCOUNT_DIR'] + '/fakecm')
- avatar_filename = self.id
- avatar_filename = avatar_filename.replace('/', '-') + '.avatar'
- avatar_filename = (os.environ['XDG_DATA_HOME'] +
- '/telepathy/mission-control/' + avatar_filename)
- assertEquals(conn.avatar[0], ''.join(open(avatar_filename,
- 'r').readlines()))
- elif self.avatar_location == 'datadir' and self.winner == 'service':
+ if self.avatar_location == 'datadir' and self.winner == 'service':
# The avatar wasn't deleted from $XDG_DATA_DIRS, but it was
# overridden.
assert not os.path.exists(os.environ['MC_ACCOUNT_DIR'] + '/' +
diff --git a/tests/twisted/account-manager/bad-cm.py b/tests/twisted/account-manager/bad-cm.py
index 74277b46..008ac605 100644
--- a/tests/twisted/account-manager/bad-cm.py
+++ b/tests/twisted/account-manager/bad-cm.py
@@ -22,11 +22,12 @@
import dbus
from servicetest import call_async, assertEquals, assertContains
-from mctest import exec_test, AccountManager
+from mctest import (exec_test, SimulatedConnectionManager, AccountManager)
import constants as cs
def test(q, bus, mc):
am = AccountManager(bus)
+ simulated_cm = SimulatedConnectionManager(q, bus)
def call_create(cm='fakecm', protocol='fakeprotocol', parameters=None):
if parameters is None:
@@ -74,5 +75,13 @@ def test(q, bus, mc):
assertEquals(cs.INVALID_ARGUMENT, e.name)
assertContains("password", e.message)
+ # Create an account that will fail IdentifyAccount
+ call_create(parameters={ "account": "",
+ "password": "ohai",
+ })
+ e = q.expect('dbus-error', method='CreateAccount')
+ assertEquals(cs.INVALID_HANDLE, e.name)
+ assertContains("Invalid account name", e.message)
+
if __name__ == '__main__':
exec_test(test, {})
diff --git a/tests/twisted/account-storage/5-12.py b/tests/twisted/account-storage/5-12.py
new file mode 100644
index 00000000..9075d767
--- /dev/null
+++ b/tests/twisted/account-storage/5-12.py
@@ -0,0 +1,29 @@
+# Test for a former default account storage backend:
+# ~/.mission-control/accounts.cfg, as used in MC 5.0 to 5.13.1
+#
+# Copyright (C) 2009-2010 Nokia Corporation
+# Copyright (C) 2009-2014 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+from storage_helper import test_keyfile
+from mctest import exec_test
+
+def test_5_12(q, bus, mc):
+ test_keyfile(q, bus, mc, '5.12')
+
+if __name__ == '__main__':
+ exec_test(test_5_12, {}, preload_mc=False, use_fake_accounts_service=False)
diff --git a/tests/twisted/account-storage/5-14.py b/tests/twisted/account-storage/5-14.py
new file mode 100644
index 00000000..42deb3ec
--- /dev/null
+++ b/tests/twisted/account-storage/5-14.py
@@ -0,0 +1,29 @@
+# Test for a former default account storage backend:
+# XDG_DATA_HOME/telepathy/mission-control/accounts.cfg, as used in MC 5.14
+#
+# Copyright (C) 2009-2010 Nokia Corporation
+# Copyright (C) 2009-2014 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+from storage_helper import test_keyfile
+from mctest import exec_test
+
+def test_5_14(q, bus, mc):
+ test_keyfile(q, bus, mc, '5.14')
+
+if __name__ == '__main__':
+ exec_test(test_5_14, {}, preload_mc=False, use_fake_accounts_service=False)
diff --git a/tests/twisted/account-storage/create-new.py b/tests/twisted/account-storage/create-new.py
new file mode 100644
index 00000000..f77624a9
--- /dev/null
+++ b/tests/twisted/account-storage/create-new.py
@@ -0,0 +1,136 @@
+# Test for "stringified GVariant per account" storage backend introduced in
+# Mission Control 5.16, when creating a new account stored in this default
+# backend
+#
+# Copyright (C) 2009-2010 Nokia Corporation
+# Copyright (C) 2009-2014 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import time
+import os
+import os.path
+import signal
+
+import dbus
+import dbus.service
+
+from servicetest import (
+ EventPattern, assertEquals,
+ )
+from mctest import (
+ exec_test, create_fakecm_account, connect_to_mc,
+ )
+from storage_helper import (account_store)
+import constants as cs
+
+def test(q, bus, mc):
+ ctl_dir = os.environ['MC_ACCOUNT_DIR']
+ old_key_file_name = os.path.join(ctl_dir, 'accounts.cfg')
+ newer_key_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
+ 'telepathy', 'mission-control', 'accounts.cfg')
+ new_variant_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
+ 'telepathy', 'mission-control',
+ 'fakecm-fakeprotocol-dontdivert_40example_2ecom0.account')
+
+ account_manager, properties, interfaces = connect_to_mc(q, bus, mc)
+
+ assert properties.get('ValidAccounts') == [], \
+ properties.get('ValidAccounts')
+ assert properties.get('InvalidAccounts') == [], \
+ properties.get('InvalidAccounts')
+
+ params = dbus.Dictionary({"account": "dontdivert@example.com",
+ "password": "secrecy",
+ "snakes": dbus.UInt32(23)}, signature='sv')
+ (simulated_cm, account) = create_fakecm_account(q, bus, mc, params)
+
+ account_path = account.__dbus_object_path__
+
+ # Check the account is correctly created
+ properties = account_manager.GetAll(cs.AM,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties is not None
+ assert properties.get('ValidAccounts') == [account_path], properties
+ account_path = properties['ValidAccounts'][0]
+ assert isinstance(account_path, dbus.ObjectPath), repr(account_path)
+ assert properties.get('InvalidAccounts') == [], properties
+
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ # Alter some miscellaneous r/w properties
+
+ account_props.Set(cs.ACCOUNT, 'DisplayName', 'Work account')
+ account_props.Set(cs.ACCOUNT, 'Icon', 'im-jabber')
+ account_props.Set(cs.ACCOUNT, 'Nickname', 'Joe Bloggs')
+ account_props.Set(cs.ACCOUNT, 'ConnectAutomatically', True)
+ account_props.Set(cs.ACCOUNT, 'AutomaticPresence',
+ (dbus.UInt32(cs.PRESENCE_EXTENDED_AWAY), 'xa',
+ 'never online'))
+
+ # .. let's check the keyfile
+ assert not os.path.exists(old_key_file_name)
+ assert not os.path.exists(newer_key_file_name)
+ assert os.path.exists(new_variant_file_name)
+ assert 'Joe Bloggs' in open(new_variant_file_name).read()
+ assertEquals("'fakecm'", account_store('get', 'variant-file', 'manager'))
+ assertEquals("'fakeprotocol'", account_store('get', 'variant-file',
+ 'protocol'))
+ assertEquals("'Work account'", account_store('get', 'variant-file',
+ 'DisplayName'))
+ assertEquals("'im-jabber'", account_store('get', 'variant-file',
+ 'Icon'))
+ assertEquals("'Joe Bloggs'", account_store('get', 'variant-file',
+ 'Nickname'))
+ assertEquals('true', account_store('get', 'variant-file',
+ 'ConnectAutomatically'))
+ assertEquals("(uint32 4, 'xa', 'never online')",
+ account_store('get', 'variant-file', 'AutomaticPresence'))
+ assertEquals("'dontdivert@example.com'",
+ account_store('get', 'variant-file', 'param-account'))
+ assertEquals("uint32 23",
+ account_store('get', 'variant-file', 'param-snakes'))
+ assertEquals("'secrecy'",
+ account_store('get', 'variant-file', 'param-password'))
+
+ assertEquals({'password': 'secrecy', 'account': 'dontdivert@example.com',
+ 'snakes': 23}, account.Properties.Get(cs.ACCOUNT, 'Parameters'))
+
+ # Delete the account
+ assert account_iface.Remove() is None
+ account_event, account_manager_event = q.expect_many(
+ EventPattern('dbus-signal',
+ path=account_path,
+ signal='Removed',
+ interface=cs.ACCOUNT,
+ args=[]
+ ),
+ EventPattern('dbus-signal',
+ path=cs.AM_PATH,
+ signal='AccountRemoved',
+ interface=cs.AM,
+ args=[account_path]
+ ),
+ )
+
+ # Check the account is correctly deleted
+ assert not os.path.exists(old_key_file_name)
+ assert not os.path.exists(newer_key_file_name)
+ assert not os.path.exists(new_variant_file_name)
+
+if __name__ == '__main__':
+ exec_test(test, {}, timeout=10, use_fake_accounts_service=False)
diff --git a/tests/twisted/account-storage/default-keyring-storage.py b/tests/twisted/account-storage/default-keyring-storage.py
deleted file mode 100644
index 27b45e51..00000000
--- a/tests/twisted/account-storage/default-keyring-storage.py
+++ /dev/null
@@ -1,317 +0,0 @@
-# Test for default account storage backend.
-#
-# Copyright (C) 2009-2010 Nokia Corporation
-# Copyright (C) 2009-2010 Collabora Ltd.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-# 02110-1301 USA
-
-import time
-import os
-import os.path
-import signal
-
-import dbus
-import dbus.service
-
-from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
- call_async, assertEquals, assertContains, assertDoesNotContain
-from mctest import (
- exec_test, create_fakecm_account, get_fakecm_account, connect_to_mc,
- keyfile_read, tell_mc_to_die, resuscitate_mc
- )
-import constants as cs
-
-# This doesn't escape its parameters before passing them to the shell,
-# so be careful.
-def account_store(op, backend, key=None, value=None,
- account='fakecm/fakeprotocol/dontdivert_40example_2ecom0'):
- cmd = [ '../account-store', op, backend, account ]
- if key:
- cmd.append(key)
- if value:
- cmd.append(value)
-
- lines = os.popen(' '.join(cmd)).read()
- ret = []
- for line in lines.split('\n'):
- if line.startswith('** '):
- continue
-
- if line:
- ret.append(line)
-
- if len(ret) > 0:
- return ret[0]
- else:
- return None
-
-def test(q, bus, mc):
- ctl_dir = os.environ['MC_ACCOUNT_DIR']
- old_key_file_name = os.path.join(ctl_dir, 'accounts.cfg')
- newer_key_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
- 'telepathy', 'mission-control', 'accounts.cfg')
- new_variant_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
- 'telepathy', 'mission-control',
- 'fakecm-fakeprotocol-dontdivert_40example_2ecom0.account')
- group = 'fakecm/fakeprotocol/dontdivert_40example_2ecom0'
-
- account_manager, properties, interfaces = connect_to_mc(q, bus, mc)
-
- assert properties.get('ValidAccounts') == [], \
- properties.get('ValidAccounts')
- assert properties.get('InvalidAccounts') == [], \
- properties.get('InvalidAccounts')
-
- params = dbus.Dictionary({"account": "dontdivert@example.com",
- "password": "secrecy",
- "snakes": dbus.UInt32(23)}, signature='sv')
- (simulated_cm, account) = create_fakecm_account(q, bus, mc, params)
-
- account_path = account.__dbus_object_path__
-
- # Check the account is correctly created
- properties = account_manager.GetAll(cs.AM,
- dbus_interface=cs.PROPERTIES_IFACE)
- assert properties is not None
- assert properties.get('ValidAccounts') == [account_path], properties
- account_path = properties['ValidAccounts'][0]
- assert isinstance(account_path, dbus.ObjectPath), repr(account_path)
- assert properties.get('InvalidAccounts') == [], properties
-
- account_iface = dbus.Interface(account, cs.ACCOUNT)
- account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
-
- # Alter some miscellaneous r/w properties
-
- account_props.Set(cs.ACCOUNT, 'DisplayName', 'Work account')
- account_props.Set(cs.ACCOUNT, 'Icon', 'im-jabber')
- account_props.Set(cs.ACCOUNT, 'Nickname', 'Joe Bloggs')
- account_props.Set(cs.ACCOUNT, 'ConnectAutomatically', True)
- account_props.Set(cs.ACCOUNT, 'AutomaticPresence',
- (dbus.UInt32(cs.PRESENCE_EXTENDED_AWAY), 'xa',
- 'never online'))
-
- tell_mc_to_die(q, bus)
-
- # .. let's check the keyfile
- assert not os.path.exists(old_key_file_name)
- assert not os.path.exists(newer_key_file_name)
- assert 'Joe Bloggs' in open(new_variant_file_name).read()
- assertEquals("'fakecm'", account_store('get', 'variant-file', 'manager'))
- assertEquals("'fakeprotocol'", account_store('get', 'variant-file',
- 'protocol'))
- assertEquals("'Work account'", account_store('get', 'variant-file',
- 'DisplayName'))
- assertEquals("'im-jabber'", account_store('get', 'variant-file',
- 'Icon'))
- assertEquals("'Joe Bloggs'", account_store('get', 'variant-file',
- 'Nickname'))
- assertEquals('true', account_store('get', 'variant-file',
- 'ConnectAutomatically'))
- assertEquals("(uint32 4, 'xa', 'never online')",
- account_store('get', 'variant-file', 'AutomaticPresence'))
- assertEquals("'dontdivert@example.com'",
- account_store('get', 'variant-file', 'param-account'))
- assertEquals("uint32 23",
- account_store('get', 'variant-file', 'param-snakes'))
- assertEquals("'secrecy'",
- account_store('get', 'variant-file', 'param-password'))
-
- # Reactivate MC
- account_manager, properties, interfaces = resuscitate_mc(q, bus, mc)
- account = get_fakecm_account(bus, mc, account_path)
- account_iface = dbus.Interface(account, cs.ACCOUNT)
-
- assertEquals({'password': 'secrecy', 'account': 'dontdivert@example.com',
- 'snakes': 23}, account.Properties.Get(cs.ACCOUNT, 'Parameters'))
-
- # Delete the account
- assert account_iface.Remove() is None
- account_event, account_manager_event = q.expect_many(
- EventPattern('dbus-signal',
- path=account_path,
- signal='Removed',
- interface=cs.ACCOUNT,
- args=[]
- ),
- EventPattern('dbus-signal',
- path=cs.AM_PATH,
- signal='AccountRemoved',
- interface=cs.AM,
- args=[account_path]
- ),
- )
-
- # Check the account is correctly deleted
- assert not os.path.exists(old_key_file_name)
- assert not os.path.exists(newer_key_file_name)
- assert not os.path.exists(new_variant_file_name)
-
- # Tell MC to die, again
- tell_mc_to_die(q, bus)
-
- low_prio_variant_file_name = os.path.join(
- os.environ['XDG_DATA_DIRS'].split(':')[0],
- 'telepathy', 'mission-control',
- 'fakecm-fakeprotocol-dontdivert_40example_2ecom0.account')
- os.makedirs(os.path.dirname(low_prio_variant_file_name), 0700)
-
- # This is deliberately a lower-priority location
- open(low_prio_variant_file_name, 'w').write(
-"""{
-'manager': <'fakecm'>,
-'protocol': <'fakeprotocol'>,
-'DisplayName': <'New and improved account'>,
-'AutomaticPresence': <(uint32 2, 'available', '')>,
-'KeyFileParameters': <{
- 'account': 'dontdivert@example.com',
- 'password': 'password_in_variant_file',
- 'snakes': '42'
- }>
-}
-""")
-
- # This version of this account will be used
- open(new_variant_file_name.replace('.account', 'priority.account'),
- 'w').write("""{
-'manager': <'fakecm'>,
-'protocol': <'fakeprotocol'>,
-'DisplayName': <'Visible'>,
-'AutomaticPresence': <(uint32 2, 'available', '')>,
-'KeyFileParameters': <{'account': 'dontdivert@example.com',
- 'password': 'password_in_variant_file'}>
-}
-""")
- # This one won't, because it's "masked" by the higher-priority one
- open(low_prio_variant_file_name.replace('.account', 'priority.account'),
- 'w').write("""{
-'manager': <'fakecm'>,
-'protocol': <'fakeprotocol'>,
-'DisplayName': <'Hidden'>,
-'Nickname': <'Hidden'>,
-'AutomaticPresence': <(uint32 2, 'available', '')>,
-'KeyFileParameters': <{'account': 'dontdivert@example.com',
- 'password': 'password_in_variant_file'}>
-}
-""")
-
- # This empty file is considered to "mask" the lower-priority one
- open(new_variant_file_name.replace('.account', 'masked.account'),
- 'w').write('')
- open(low_prio_variant_file_name.replace('.account', 'masked.account'),
- 'w').write("""{
-'manager': <'fakecm'>,
-'protocol': <'fakeprotocol'>,
-'AutomaticPresence': <(uint32 2, 'available', '')>,
-'KeyFileParameters': <{'account': 'dontdivert@example.com',
- 'password': 'password_in_variant_file'}>
-}
-""")
-
- account_manager, properties, interfaces = resuscitate_mc(q, bus, mc)
- assertContains(account_path, properties['ValidAccounts'])
- account = get_fakecm_account(bus, mc, account_path)
- account_iface = dbus.Interface(account, cs.ACCOUNT)
-
- assertEquals(42,
- account.Properties.Get(cs.ACCOUNT, 'Parameters')['snakes'])
- assertEquals(dbus.UInt32,
- type(account.Properties.Get(cs.ACCOUNT, 'Parameters')['snakes']))
-
- # Files in lower-priority XDG locations aren't copied until something
- # actually changes, and they aren't deleted.
- assert not os.path.exists(new_variant_file_name)
- assert os.path.exists(low_prio_variant_file_name)
-
- # Delete the password (only), like Empathy 3.0-3.4 do when migrating
- account_iface.UpdateParameters({}, ['password'])
- q.expect('dbus-signal',
- path=account_path,
- signal='AccountPropertyChanged',
- interface=cs.ACCOUNT,
- predicate=(lambda e:
- 'Parameters' in e.args[0]),
- )
-
- # test that "masking" works
- assertDoesNotContain(account_path + "masked", properties['ValidAccounts'])
- assertDoesNotContain(account_path + "masked",
- properties['InvalidAccounts'])
-
- # test that priority works
- assertContains(account_path + "priority", properties['ValidAccounts'])
- priority_account = get_fakecm_account(bus, mc, account_path + "priority")
- assertEquals('', priority_account.Properties.Get(cs.ACCOUNT, 'Nickname'))
- assertEquals('Visible',
- priority_account.Properties.Get(cs.ACCOUNT, 'DisplayName'))
-
- # test what happens when we delete an account that has a lower-priority
- # "other self"
- assert priority_account.Remove() is None
-
- # Tell MC to die yet again
- tell_mc_to_die(q, bus)
-
- # Check the account has copied (not moved! XDG_DATA_DIRS are,
- # conceptually, read-only) from the old to the new name
- assert not os.path.exists(old_key_file_name)
- assert not os.path.exists(newer_key_file_name)
- assert os.path.exists(low_prio_variant_file_name)
- assert os.path.exists(new_variant_file_name)
- assert open(new_variant_file_name.replace('.account', 'masked.account'),
- 'r').read() == ''
- assert open(new_variant_file_name.replace('.account', 'priority.account'),
- 'r').read() == ''
-
- pwd = account_store('get', 'variant-file', 'param-password')
- assertEquals(None, pwd)
-
- # Write out an account configuration in the old keyfile, to test
- # migration from there
- os.remove(new_variant_file_name)
- os.remove(new_variant_file_name.replace('.account', 'masked.account'))
- os.remove(new_variant_file_name.replace('.account', 'priority.account'))
- os.remove(low_prio_variant_file_name)
- os.remove(low_prio_variant_file_name.replace('.account', 'masked.account'))
- os.remove(low_prio_variant_file_name.replace('.account', 'priority.account'))
- open(old_key_file_name, 'w').write(
-r"""# Telepathy accounts
-[%s]
-manager=fakecm
-protocol=fakeprotocol
-param-account=dontdivert@example.com
-DisplayName=Ye olde account
-AutomaticPresence=2;available;;
-""" % group)
-
- account_manager, properties, interfaces = resuscitate_mc(q, bus, mc)
- account = get_fakecm_account(bus, mc, account_path)
- account_iface = dbus.Interface(account, cs.ACCOUNT)
-
- # This time it *does* get deleted automatically during MC startup,
- # after copying its contents to the new name/format
- assert not os.path.exists(old_key_file_name)
- assert not os.path.exists(low_prio_variant_file_name)
- assertEquals("'Ye olde account'",
- account_store('get', 'variant-file', 'DisplayName'))
-
-if __name__ == '__main__':
- ctl_dir = os.environ['MC_ACCOUNT_DIR']
- try:
- os.mkdir(ctl_dir, 0700)
- except OSError:
- pass
- exec_test(test, {}, timeout=10, use_fake_accounts_service=False)
diff --git a/tests/twisted/account-storage/load-keyfiles.py b/tests/twisted/account-storage/load-keyfiles.py
new file mode 100644
index 00000000..dfba53b4
--- /dev/null
+++ b/tests/twisted/account-storage/load-keyfiles.py
@@ -0,0 +1,274 @@
+# Test for "stringified GVariant per account" storage backend introduced in
+# Mission Control 5.16, when loading pre-prepared files
+#
+# Copyright (C) 2009-2010 Nokia Corporation
+# Copyright (C) 2009-2014 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import errno
+import os
+import os.path
+
+import dbus
+
+from servicetest import (
+ assertEquals, assertContains, assertDoesNotContain,
+ )
+from mctest import (
+ MC, exec_test, get_fakecm_account, connect_to_mc,
+ SimulatedConnectionManager,
+ )
+from storage_helper import (
+ account_store,
+ )
+import constants as cs
+
+def test(q, bus, mc):
+ simulated_cm = SimulatedConnectionManager(q, bus)
+
+ ctl_dir = os.environ['MC_ACCOUNT_DIR']
+ old_key_file_name = os.path.join(ctl_dir, 'accounts.cfg')
+ newer_key_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
+ 'telepathy', 'mission-control', 'accounts.cfg')
+
+ # We do several scenarios in one MC run, to speed up testing a bit.
+ scenarios = ('low', 'priority', 'masked', 'migration', 'absentcm')
+
+ variant_file_names = {}
+ low_prio_variant_file_names = {}
+ account_paths = {}
+ tails = {}
+
+ for s in scenarios:
+ variant_file_names[s] = os.path.join(os.environ['XDG_DATA_HOME'],
+ 'telepathy', 'mission-control',
+ 'fakecm-fakeprotocol-dontdivert%s_40example_2ecom0.account'
+ % s)
+ tails[s] = ('fakecm/fakeprotocol/dontdivert%s_40example_2ecom0' % s)
+ account_paths[s] = cs.ACCOUNT_PATH_PREFIX + tails[s]
+ low_prio_variant_file_names[s] = os.path.join(
+ os.environ['XDG_DATA_DIRS'].split(':')[0],
+ 'telepathy', 'mission-control',
+ 'fakecm-fakeprotocol-dontdivert%s_40example_2ecom0.account' %
+ s)
+
+ try:
+ os.makedirs(os.path.dirname(variant_file_names[s]), 0700)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ try:
+ os.makedirs(os.path.dirname(low_prio_variant_file_names[s]), 0700)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ # This is deliberately a lower-priority location
+ open(low_prio_variant_file_names['low'], 'w').write(
+"""{
+'manager': <'fakecm'>,
+'protocol': <'fakeprotocol'>,
+'DisplayName': <'Account in a low-priority location'>,
+'AutomaticPresence': <(uint32 2, 'available', '')>,
+'Parameters': <{
+ 'account': <'dontdivertlow@example.com'>,
+ 'password': <'password_in_variant_file'>,
+ 'snakes': <uint32 42>
+ }>
+}
+""")
+
+ # This is in a lower-priority location and we don't know the
+ # parameters' types yet
+ open(low_prio_variant_file_names['migration'], 'w').write(
+"""{
+'manager': <'fakecm'>,
+'protocol': <'fakeprotocol'>,
+'DisplayName': <'Account in a low-priority location with KeyFileParameters'>,
+'AutomaticPresence': <(uint32 2, 'available', '')>,
+'KeyFileParameters': <{
+ 'account': 'dontdivertmigration@example.com',
+ 'password': 'password_in_variant_file',
+ 'snakes': '42'
+ }>
+}
+""")
+
+ # This is in a lower-priority location, and we don't know the
+ # parameters' types, and we can't learn them by asking the CM
+ # because it isn't installed
+ open(low_prio_variant_file_names['absentcm'], 'w').write(
+"""{
+'manager': <'absentcm'>,
+'protocol': <'absentprotocol'>,
+'DisplayName': <'Account in a low-priority location with absent CM'>,
+'AutomaticPresence': <(uint32 2, 'available', '')>,
+'KeyFileParameters': <{
+ 'account': 'dontdivertabsentcm@example.com',
+ 'password': 'hello',
+ 'snakes': '42'
+ }>
+}
+""")
+
+ # This version of this account will be used
+ open(variant_file_names['priority'], 'w').write("""{
+'manager': <'fakecm'>,
+'protocol': <'fakeprotocol'>,
+'DisplayName': <'Visible'>,
+'AutomaticPresence': <(uint32 2, 'available', '')>,
+'KeyFileParameters': <{'account': 'dontdivertpriority@example.com',
+ 'password': 'password_in_variant_file',
+ 'snakes': '42'
+ }>
+}
+""")
+ # This one won't, because it's "masked" by the higher-priority one
+ open(low_prio_variant_file_names['priority'], 'w').write("""{
+'manager': <'fakecm'>,
+'protocol': <'fakeprotocol'>,
+'DisplayName': <'Hidden'>,
+'Nickname': <'Hidden'>,
+'AutomaticPresence': <(uint32 2, 'available', '')>,
+'KeyFileParameters': <{'account': 'dontdivertpriority@example.com',
+ 'password': 'password_in_variant_file',
+ 'snakes': '42'
+ }>
+}
+""")
+
+ # This empty file is considered to "mask" the lower-priority one
+ open(variant_file_names['masked'], 'w').write('')
+ open(low_prio_variant_file_names['masked'], 'w').write("""{
+'manager': <'fakecm'>,
+'protocol': <'fakeprotocol'>,
+'AutomaticPresence': <(uint32 2, 'available', '')>,
+'KeyFileParameters': <{'account': 'dontdivert@example.com',
+ 'password': 'password_in_variant_file',
+ 'snakes': '42'
+ }>
+}
+""")
+
+ mc = MC(q, bus)
+ account_manager, properties, interfaces = connect_to_mc(q, bus, mc)
+
+ for s in scenarios:
+ if s == 'masked':
+ assertDoesNotContain(account_paths[s], properties['ValidAccounts'])
+ assertDoesNotContain(account_paths[s], properties['InvalidAccounts'])
+ elif s == 'absentcm':
+ assertContains(account_paths[s], properties['InvalidAccounts'])
+ assertDoesNotContain(account_paths[s], properties['ValidAccounts'])
+ else:
+ assertContains(account_paths[s], properties['ValidAccounts'])
+ assertDoesNotContain(account_paths[s], properties['InvalidAccounts'])
+
+ accounts = {}
+ account_ifaces = {}
+
+ for s in scenarios:
+ if s != 'masked':
+ accounts[s] = get_fakecm_account(bus, mc, account_paths[s])
+ account_ifaces[s] = dbus.Interface(accounts[s], cs.ACCOUNT)
+
+ if s not in ('masked', 'absentcm'):
+ # We can't get untyped parameters if we don't know what types
+ # the CM gives them.
+ assertEquals(42, accounts[s].Properties.Get(cs.ACCOUNT,
+ 'Parameters')['snakes'])
+ assertEquals(dbus.UInt32,
+ type(accounts[s].Properties.Get(cs.ACCOUNT,
+ 'Parameters')['snakes']))
+
+ # Files in lower-priority XDG locations aren't copied until something
+ # actually changes, and they aren't deleted.
+
+ if s == 'low':
+ assert os.path.exists(low_prio_variant_file_names[s])
+
+ # Delete the password (only), like Empathy 3.0-3.4 do when migrating.
+ # This results in the higher-priority file being written out.
+ account_ifaces['low'].UpdateParameters({}, ['password'])
+ q.expect('dbus-signal',
+ path=account_paths['low'],
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT,
+ predicate=(lambda e:
+ 'Parameters' in e.args[0]),
+ )
+ # Check the account has copied (not moved! XDG_DATA_DIRS are,
+ # conceptually, read-only) 'low' from the old to the new name
+ assert not os.path.exists(old_key_file_name)
+ assert not os.path.exists(newer_key_file_name)
+ assert os.path.exists(low_prio_variant_file_names['low'])
+ assert os.path.exists(variant_file_names['low'])
+
+ # test that priority works
+ assertContains(account_paths["priority"], properties['ValidAccounts'])
+ assertEquals('',
+ accounts['priority'].Properties.Get(cs.ACCOUNT, 'Nickname'))
+ assertEquals('Visible',
+ accounts['priority'].Properties.Get(cs.ACCOUNT, 'DisplayName'))
+
+ # test what happens when we delete an account that has a lower-priority
+ # "other self": it becomes masked
+ assert accounts['priority'].Remove() is None
+ assert not os.path.exists(old_key_file_name)
+ assert not os.path.exists(newer_key_file_name)
+ assert os.path.exists(low_prio_variant_file_names['priority'])
+ assert os.path.exists(variant_file_names['priority'])
+ assert open(variant_file_names['priority'], 'r').read() == ''
+ assertContains('password_in_variant_file',
+ open(low_prio_variant_file_names['priority'], 'r').read())
+
+ # The masked account is still masked
+ assert open(variant_file_names['masked'], 'r').read() == ''
+
+ # Teach the one that knows its CM that the 'password' is a string.
+ # This results in the higher-priority file being written out.
+ account_ifaces['migration'].UpdateParameters({'password': 'hello'}, [])
+ q.expect('dbus-signal',
+ path=account_paths['migration'],
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT,
+ predicate=(lambda e:
+ 'Parameters' in e.args[0]),
+ )
+ # Check the account has copied (not moved! XDG_DATA_DIRS are,
+ # conceptually, read-only) 'migration' from the old to the new name
+ assert not os.path.exists(old_key_file_name)
+ assert not os.path.exists(newer_key_file_name)
+ assert os.path.exists(low_prio_variant_file_names['migration'])
+ assert os.path.exists(variant_file_names['migration'])
+ assertEquals("'hello'", account_store('get', 'variant-file',
+ 'param-password', account=tails['migration']))
+ # Parameters whose types are still unknown are copied too, but their
+ # types are still unknown
+ assertEquals("keyfile-escaped '42'", account_store('get', 'variant-file',
+ 'param-snakes', account=tails['migration']))
+
+ # 'absentcm' is still only in the low-priority location: we can't
+ # known the types of its parameters
+ assert not os.path.exists(old_key_file_name)
+ assert not os.path.exists(newer_key_file_name)
+ assert os.path.exists(low_prio_variant_file_names['absentcm'])
+ assert not os.path.exists(variant_file_names['absentcm'])
+
+if __name__ == '__main__':
+ exec_test(test, {}, preload_mc=False, use_fake_accounts_service=False)
diff --git a/tests/twisted/account-storage/storage_helper.py b/tests/twisted/account-storage/storage_helper.py
new file mode 100644
index 00000000..ebbe78e6
--- /dev/null
+++ b/tests/twisted/account-storage/storage_helper.py
@@ -0,0 +1,174 @@
+# Helper code for former default account storage backends
+#
+# Copyright (C) 2009-2010 Nokia Corporation
+# Copyright (C) 2009-2014 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import errno
+import os
+import os.path
+
+import dbus
+
+from servicetest import (
+ assertEquals, assertContains, assertLength,
+ )
+from mctest import (
+ exec_test, get_fakecm_account, connect_to_mc,
+ MC, SimulatedConnectionManager,
+ )
+import constants as cs
+
+# This doesn't escape its parameters before passing them to the shell,
+# so be careful.
+def account_store(op, backend, key=None, value=None,
+ account='fakecm/fakeprotocol/dontdivert_40example_2ecom0'):
+ cmd = [ '../account-store', op, backend, account ]
+ if key:
+ cmd.append(key)
+ if value:
+ cmd.append(value)
+
+ lines = os.popen(' '.join(cmd)).read()
+ ret = []
+ for line in lines.split('\n'):
+ if line.startswith('** '):
+ continue
+
+ if line:
+ ret.append(line)
+
+ if len(ret) > 0:
+ return ret[0]
+ else:
+ return None
+
+def test_keyfile(q, bus, mc, how_old='5.12'):
+ simulated_cm = SimulatedConnectionManager(q, bus)
+
+ if how_old == '5.12':
+ # This is not actually ~/.mission-control, but it uses the same
+ # code paths.
+ dot_mission_control = os.environ['MC_ACCOUNT_DIR']
+ old_key_file_name = os.path.join(dot_mission_control, 'accounts.cfg')
+
+ os.makedirs(dot_mission_control +
+ '/fakecm/fakeprotocol/dontdivert1_40example_2ecom0')
+ avatar_bin = open(dot_mission_control +
+ '/fakecm/fakeprotocol/dontdivert1_40example_2ecom0/avatar.bin',
+ 'w')
+ avatar_bin.write('hello, world')
+ avatar_bin.close()
+ elif how_old == '5.14':
+ # Same format, different location.
+ old_key_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
+ 'telepathy', 'mission-control', 'accounts.cfg')
+
+ # exercise override of an avatar in XDG_DATA_DIRS
+ avatar_dir = (os.environ['XDG_DATA_DIRS'].split(':')[0] +
+ '/telepathy/mission-control')
+ os.makedirs(avatar_dir)
+ avatar_bin = open(avatar_dir +
+ '/fakecm-fakeprotocol-dontdivert1_40example_2ecom0.avatar',
+ 'w')
+ avatar_bin.write('hello, world')
+ avatar_bin.close()
+ else:
+ raise AssertionError('Unsupported value for how_old')
+
+ a1_new_variant_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
+ 'telepathy', 'mission-control',
+ 'fakecm-fakeprotocol-dontdivert1_40example_2ecom0.account')
+ a1_tail = 'fakecm/fakeprotocol/dontdivert1_40example_2ecom0'
+
+ a2_new_variant_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
+ 'telepathy', 'mission-control',
+ 'fakecm-fakeprotocol-dontdivert2_40example_2ecom0.account')
+ a2_tail = 'fakecm/fakeprotocol/dontdivert2_40example_2ecom0'
+
+ try:
+ os.makedirs(os.path.dirname(old_key_file_name), 0700)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ open(old_key_file_name, 'w').write(
+r"""# Telepathy accounts
+[%s]
+manager=fakecm
+protocol=fakeprotocol
+param-account=dontdivert1@example.com
+param-password=1
+DisplayName=First among equals
+AutomaticPresence=2;available;;
+AvatarMime=text/plain
+avatar_token=hello, world
+
+[%s]
+manager=fakecm
+protocol=fakeprotocol
+param-account=dontdivert2@example.com
+param-password=2
+DisplayName=Second to none
+AutomaticPresence=2;available;;
+""" % (a1_tail, a2_tail))
+
+ mc = MC(q, bus)
+ account_manager, properties, interfaces = connect_to_mc(q, bus, mc)
+
+ # During MC startup, it moved the old keyfile's contents into
+ # variant-based files, and deleted the old keyfile.
+ assert not os.path.exists(old_key_file_name)
+ assert os.path.exists(a1_new_variant_file_name)
+ assert os.path.exists(a2_new_variant_file_name)
+ assertEquals("'First among equals'",
+ account_store('get', 'variant-file', 'DisplayName',
+ account=a1_tail))
+ assertEquals("'Second to none'",
+ account_store('get', 'variant-file', 'DisplayName',
+ account=a2_tail))
+ # MC doesn't currently ensure that parameters are stored with their
+ # proper types.
+ assertEquals("keyfile-escaped 'dontdivert1@example.com'",
+ account_store('get', 'variant-file', 'param-account',
+ account=a1_tail))
+ assertEquals("keyfile-escaped 'dontdivert2@example.com'",
+ account_store('get', 'variant-file', 'param-account',
+ account=a2_tail))
+
+ # Also, MC has both accounts in memory...
+ assertContains(cs.ACCOUNT_PATH_PREFIX + a1_tail,
+ properties['ValidAccounts'])
+ account = get_fakecm_account(bus, mc, cs.ACCOUNT_PATH_PREFIX + a1_tail)
+ assertEquals('dontdivert1@example.com',
+ account.Properties.Get(cs.ACCOUNT, 'Parameters')['account'])
+ assertEquals('First among equals',
+ account.Properties.Get(cs.ACCOUNT, 'DisplayName'))
+ assertEquals((dbus.ByteArray('hello, world'), 'text/plain'),
+ account.Properties.Get(cs.ACCOUNT_IFACE_AVATAR, 'Avatar',
+ byte_arrays=True))
+
+ assertContains(cs.ACCOUNT_PATH_PREFIX + a2_tail,
+ properties['ValidAccounts'])
+ account = get_fakecm_account(bus, mc, cs.ACCOUNT_PATH_PREFIX + a2_tail)
+ assertEquals('dontdivert2@example.com',
+ account.Properties.Get(cs.ACCOUNT, 'Parameters')['account'])
+ assertEquals('Second to none',
+ account.Properties.Get(cs.ACCOUNT, 'DisplayName'))
+
+ # ... and no other accounts.
+ assertLength(2, properties['ValidAccounts'])
diff --git a/tests/twisted/dbus-account-plugin.c b/tests/twisted/dbus-account-plugin.c
index a8a2e4df..446a2ad7 100644
--- a/tests/twisted/dbus-account-plugin.c
+++ b/tests/twisted/dbus-account-plugin.c
@@ -27,6 +27,8 @@
#include <telepathy-glib/telepathy-glib-dbus.h>
#define DEBUG(format, ...) g_debug ("%s: " format, G_STRFUNC, ##__VA_ARGS__)
+#define CRITICAL(format, ...) \
+ g_critical ("%s: " format, G_STRFUNC, ##__VA_ARGS__)
#define TESTDOT "org.freedesktop.Telepathy.Test."
#define TESTSLASH "/org/freedesktop/Telepathy/Test/"
@@ -54,7 +56,7 @@ typedef struct {
GHashTable *parameter_flags;
/* set of strings */
GHashTable *uncommitted_parameters;
- enum { UNCOMMITTED_CREATION, UNCOMMITTED_DELETION } flags;
+ enum { UNCOMMITTED_CREATION = 1 } flags;
TpStorageRestrictionFlags restrictions;
} Account;
@@ -183,7 +185,6 @@ ensure_account (TestDBusAccountPlugin *self,
g_hash_table_insert (self->accounts, g_strdup (account_name), account);
}
- account->flags &= ~UNCOMMITTED_DELETION;
return account;
}
@@ -211,18 +212,14 @@ service_vanished_cb (GDBusConnection *bus,
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (user_data);
GHashTableIter iter;
- gpointer k, v;
+ gpointer k;
self->active = FALSE;
g_hash_table_iter_init (&iter, self->accounts);
- while (g_hash_table_iter_next (&iter, &k, &v))
+ while (g_hash_table_iter_next (&iter, &k, NULL))
{
- Account *account = v;
-
- if ((account->flags & UNCOMMITTED_DELETION) == 0)
- mcp_account_storage_emit_deleted (MCP_ACCOUNT_STORAGE (self), k);
-
+ mcp_account_storage_emit_deleted (MCP_ACCOUNT_STORAGE (self), k);
g_hash_table_iter_remove (&iter);
}
@@ -376,7 +373,7 @@ test_dbus_account_plugin_process_account_deletion (TestDBusAccountPlugin *self,
if (account == NULL)
{
- g_warning ("accounts service deleted %s but we don't "
+ CRITICAL ("accounts service deleted %s but we don't "
"have any record of that account", account_name);
}
else
@@ -414,7 +411,7 @@ test_dbus_account_plugin_process_attributes (TestDBusAccountPlugin *self,
if (account == NULL)
{
- g_warning ("accounts service altered %s but we don't "
+ CRITICAL ("accounts service altered %s but we don't "
"have any record of that account", account_name);
}
else
@@ -448,8 +445,6 @@ test_dbus_account_plugin_process_attributes (TestDBusAccountPlugin *self,
g_hash_table_insert (account->attributes,
g_strdup (attr), g_variant_ref (value));
- mcp_account_manager_set_attribute (self->feedback,
- account_name, attr, value, flags);
mcp_account_storage_emit_altered_one (
MCP_ACCOUNT_STORAGE (self), account_name, attr);
@@ -473,8 +468,6 @@ test_dbus_account_plugin_process_attributes (TestDBusAccountPlugin *self,
DEBUG ("%s deleted", attr);
g_hash_table_remove (account->attributes, attr);
- mcp_account_manager_set_attribute (self->feedback,
- account_name, attr, NULL, 0);
mcp_account_storage_emit_altered_one (
MCP_ACCOUNT_STORAGE (self), account_name, attr);
@@ -525,7 +518,7 @@ test_dbus_account_plugin_process_parameters (TestDBusAccountPlugin *self,
if (account == NULL)
{
- g_warning ("accounts service altered %s but we don't "
+ CRITICAL ("accounts service altered %s but we don't "
"have any record of that account", account_name);
}
else
@@ -557,8 +550,6 @@ test_dbus_account_plugin_process_parameters (TestDBusAccountPlugin *self,
g_hash_table_insert (account->parameters,
g_strdup (param), g_variant_ref (value));
key = g_strdup_printf ("param-%s", param);
- mcp_account_manager_set_parameter (self->feedback,
- account_name, param, value, flags);
mcp_account_storage_emit_altered_one (
MCP_ACCOUNT_STORAGE (self), account_name, key);
g_free (key);
@@ -586,11 +577,10 @@ test_dbus_account_plugin_process_parameters (TestDBusAccountPlugin *self,
(stored == NULL ||
!g_variant_equal (value, stored)))
{
+ g_hash_table_remove (account->parameters, param);
g_hash_table_insert (account->untyped_parameters,
g_strdup (param), g_strdup (escaped));
key = g_strdup_printf ("param-%s", param);
- mcp_account_manager_set_value (self->feedback,
- account_name, key, escaped);
mcp_account_storage_emit_altered_one (
MCP_ACCOUNT_STORAGE (self), account_name, key);
g_free (key);
@@ -620,8 +610,6 @@ test_dbus_account_plugin_process_parameters (TestDBusAccountPlugin *self,
g_hash_table_remove (account->untyped_parameters,
param);
key = g_strdup_printf ("param-%s", param);
- mcp_account_manager_set_parameter (self->feedback,
- account_name, param, NULL, 0);
mcp_account_storage_emit_altered_one (
MCP_ACCOUNT_STORAGE (self), account_name, key);
g_free (key);
@@ -760,8 +748,8 @@ parameters_changed_cb (GDBusConnection *bus,
}
static GList *
-test_dbus_account_plugin_list (const McpAccountStorage *storage,
- const McpAccountManager *am)
+test_dbus_account_plugin_list (McpAccountStorage *storage,
+ McpAccountManager *am)
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
GError *error = NULL;
@@ -870,8 +858,8 @@ test_dbus_account_plugin_list (const McpAccountStorage *storage,
}
static void
-test_dbus_account_plugin_ready (const McpAccountStorage *storage,
- const McpAccountManager *am)
+test_dbus_account_plugin_ready (McpAccountStorage *storage,
+ McpAccountManager *am)
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
@@ -885,8 +873,8 @@ test_dbus_account_plugin_ready (const McpAccountStorage *storage,
}
static gchar *
-test_dbus_account_plugin_create (const McpAccountStorage *storage,
- const McpAccountManager *am,
+test_dbus_account_plugin_create (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *manager,
const gchar *protocol,
const gchar *identifier,
@@ -908,218 +896,139 @@ test_dbus_account_plugin_create (const McpAccountStorage *storage,
return name;
}
-static gboolean
-test_dbus_account_plugin_delete (const McpAccountStorage *storage,
- const McpAccountManager *am,
+static void delete_account_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data);
+
+static void
+test_dbus_account_plugin_delete_async (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *account_name,
- const gchar *key)
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
Account *account = lookup_account (self, account_name);
+ GTask *task = g_task_new (self, cancellable, callback, user_data);
- DEBUG ("called");
-
- if (account == NULL || !self->active)
- return FALSE;
-
- if (key == NULL)
- {
- account->flags |= UNCOMMITTED_DELETION;
- g_hash_table_remove_all (account->attributes);
- g_hash_table_remove_all (account->parameters);
- g_hash_table_remove_all (account->untyped_parameters);
- g_hash_table_remove_all (account->attribute_flags);
- g_hash_table_remove_all (account->parameter_flags);
-
- account->flags &= ~UNCOMMITTED_CREATION;
- g_hash_table_remove_all (account->uncommitted_attributes);
- g_hash_table_remove_all (account->uncommitted_parameters);
+ g_task_set_task_data (task, g_strdup (user_data), g_free);
- g_dbus_connection_emit_signal (self->bus, NULL,
- TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
- "DeferringDelete", g_variant_new_parsed ("(%o,)", account->path),
- NULL);
- }
- else if (g_str_has_prefix (key, "param-"))
- {
- g_hash_table_remove (account->parameters, key + 6);
- g_hash_table_remove (account->untyped_parameters, key + 6);
- g_hash_table_remove (account->parameter_flags, key + 6);
- g_hash_table_add (account->uncommitted_parameters, g_strdup (key + 6));
+ DEBUG ("called");
- g_dbus_connection_emit_signal (self->bus, NULL,
- TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
- "DeferringDeleteParameter",
- g_variant_new_parsed ("(%o, %s)", account->path, key + 6), NULL);
- }
- else
- {
- g_hash_table_remove (account->attributes, key);
- g_hash_table_remove (account->attribute_flags, key);
- g_hash_table_add (account->uncommitted_attributes, g_strdup (key));
+ g_return_if_fail (self->active);
+ g_return_if_fail (account != NULL);
- g_dbus_connection_emit_signal (self->bus, NULL,
- TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
- "DeferringDeleteAttribute",
- g_variant_new_parsed ("(%o, %s)", account->path, key), NULL);
- }
+ /* deletion used to be delayed, so the regression tests will expect this
+ * to happen - leave them unmodified for now */
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "DeferringDelete", g_variant_new_parsed ("(%o,)", account->path),
+ NULL);
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "CommittingOne", g_variant_new_parsed ("(%o,)", account->path), NULL);
- return TRUE;
+ g_dbus_connection_call (self->bus,
+ TEST_DBUS_ACCOUNT_SERVICE,
+ TEST_DBUS_ACCOUNT_SERVICE_PATH,
+ TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ "DeleteAccount",
+ g_variant_new_parsed ("(%s,)", account_name),
+ G_VARIANT_TYPE_UNIT,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* no cancellable */
+ delete_account_cb,
+ task);
}
static gboolean
-test_dbus_account_plugin_get (const McpAccountStorage *storage,
- const McpAccountManager *am,
+test_dbus_account_plugin_delete_finish (McpAccountStorage *storage,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static GVariant *
+test_dbus_account_plugin_get_attribute (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *account_name,
- const gchar *key)
+ const gchar *attribute,
+ const GVariantType *type,
+ McpAttributeFlags *flags)
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
Account *account = lookup_account (self, account_name);
+ GVariant *v;
- if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
- return FALSE;
-
- if (key == NULL)
- {
- GHashTableIter iter;
- gpointer k, v;
-
- /* get everything */
- g_dbus_connection_emit_signal (self->bus, NULL,
- TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
- "GetAllKeys",
- g_variant_new_parsed ("(%o,)", account->path), NULL);
-
- g_hash_table_iter_init (&iter, account->attributes);
-
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- gchar *escaped = mcp_account_manager_escape_variant_for_keyfile (am,
- v);
-
- mcp_account_manager_set_value (am, account_name, k, escaped);
- g_free (escaped);
- }
-
- g_hash_table_iter_init (&iter, account->untyped_parameters);
-
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- gchar *param_foo;
- McpParameterFlags flags;
-
- param_foo = g_strdup_printf ("param-%s", (const gchar *) k);
- mcp_account_manager_set_value (am, account_name, param_foo, v);
+ if (flags != NULL)
+ *flags = 0;
- flags = GPOINTER_TO_UINT (g_hash_table_lookup (
- account->parameter_flags, k));
+ g_return_val_if_fail (self->active, NULL);
+ g_return_val_if_fail (account != NULL, NULL);
- if (flags & MCP_PARAMETER_FLAG_SECRET)
- mcp_account_manager_parameter_make_secret (am, account_name,
- param_foo);
+ v = g_hash_table_lookup (account->attributes, attribute);
- g_free (param_foo);
- }
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "GetAttribute",
+ g_variant_new_parsed ("(%o, %s)", account->path, attribute), NULL);
- g_hash_table_iter_init (&iter, account->parameters);
+ if (v != NULL)
+ {
+ return g_variant_ref (v);
+ }
+ else
+ {
+ return NULL;
+ }
+}
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- gchar *param_foo;
- guint32 flags;
- gchar *escaped = mcp_account_manager_escape_variant_for_keyfile (am,
- v);
+static GVariant *
+test_dbus_account_plugin_get_parameter (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account_name,
+ const gchar *parameter,
+ const GVariantType *type,
+ McpParameterFlags *flags)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account = lookup_account (self, account_name);
+ GVariant *v;
+ const gchar *s;
- param_foo = g_strdup_printf ("param-%s", (const gchar *) k);
- mcp_account_manager_set_value (am, account_name, param_foo, escaped);
- g_free (escaped);
+ if (flags != NULL)
+ *flags = 0;
- flags = GPOINTER_TO_UINT (g_hash_table_lookup (account->parameter_flags,
- k));
+ g_return_val_if_fail (self->active, NULL);
+ g_return_val_if_fail (account != NULL, NULL);
- if (flags & MCP_PARAMETER_FLAG_SECRET)
- mcp_account_manager_parameter_make_secret (am, account_name,
- param_foo);
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "GetParameter",
+ g_variant_new_parsed ("(%o, %s)", account->path, parameter), NULL);
- g_free (param_foo);
- }
+ v = g_hash_table_lookup (account->parameters, parameter);
+ s = g_hash_table_lookup (account->untyped_parameters, parameter);
- return TRUE;
+ if (v != NULL)
+ {
+ return g_variant_ref (v);
}
-
- /* get one parameter */
-
- if (g_str_has_prefix (key, "param-"))
+ else if (s != NULL)
{
- GVariant *v = g_hash_table_lookup (account->parameters, key + 6);
- const gchar *s = g_hash_table_lookup (account->untyped_parameters, key + 6);
- guint32 flags = GPOINTER_TO_UINT (
- g_hash_table_lookup (account->parameter_flags, key + 6));
-
- g_dbus_connection_emit_signal (self->bus, NULL,
- TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
- "GetParameter",
- g_variant_new_parsed ("(%o, %s)", account->path, key + 6), NULL);
-
- if (flags & MCP_PARAMETER_FLAG_SECRET)
- mcp_account_manager_parameter_make_secret (am, account_name, key);
-
- if (v != NULL)
- {
- gchar *escaped = mcp_account_manager_escape_variant_for_keyfile (am,
- v);
-
- mcp_account_manager_set_value (am, account_name, key, escaped);
- g_free (escaped);
- }
- else if (s != NULL)
- {
- mcp_account_manager_set_value (am, account_name, key, s);
- }
- else
- {
- return FALSE;
- }
+ return mcp_account_manager_unescape_variant_from_keyfile (am,
+ s, type, NULL);
}
else
{
- GVariant *v = g_hash_table_lookup (account->attributes, key);
-
- g_dbus_connection_emit_signal (self->bus, NULL,
- TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
- "GetAttribute",
- g_variant_new_parsed ("(%o, %s)", account->path, key), NULL);
-
- if (v != NULL)
- {
- gchar *escaped = mcp_account_manager_escape_variant_for_keyfile (am,
- v);
-
- mcp_account_manager_set_value (am, account_name, key, escaped);
- g_free (escaped);
- }
- else
- {
- return FALSE;
- }
+ return NULL;
}
-
- return TRUE;
-}
-
-static gboolean
-test_dbus_account_plugin_set (const McpAccountStorage *storage,
- const McpAccountManager *am,
- const gchar *account_name,
- const gchar *key,
- const gchar *value)
-{
- /* Now that we implement set_attribute and set_parameter, this no longer
- * needs a real implementation. */
- return FALSE;
}
-static gboolean
+static McpAccountStorageSetResult
test_dbus_account_plugin_set_attribute (McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account_name,
@@ -1129,17 +1038,40 @@ test_dbus_account_plugin_set_attribute (McpAccountStorage *storage,
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
Account *account = lookup_account (self, account_name);
+ GVariant *old;
+ guint old_flags;
g_return_val_if_fail (account_name != NULL, FALSE);
g_return_val_if_fail (attribute != NULL, FALSE);
- /* for deletions, MC would call delete() instead */
- g_return_val_if_fail (value != NULL, FALSE);
DEBUG ("%s of %s", attribute, account_name);
- if (!self->active || account == NULL ||
- (account->flags & UNCOMMITTED_DELETION))
- return FALSE;
+ g_return_val_if_fail (self->active, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
+ g_return_val_if_fail (account != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
+
+ if (value == NULL)
+ {
+ if (!g_hash_table_contains (account->attributes, attribute))
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
+
+ g_hash_table_remove (account->attributes, attribute);
+ g_hash_table_remove (account->attribute_flags, attribute);
+ g_hash_table_add (account->uncommitted_attributes, g_strdup (attribute));
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "DeferringDeleteAttribute",
+ g_variant_new_parsed ("(%o, %s)", account->path, attribute), NULL);
+
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
+ }
+
+ old = g_hash_table_lookup (account->attributes, attribute);
+ old_flags = GPOINTER_TO_UINT (g_hash_table_lookup (
+ account->attribute_flags, attribute));
+
+ if (old != NULL && g_variant_equal (old, value) && old_flags == flags)
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
g_hash_table_insert (account->attributes, g_strdup (attribute),
g_variant_ref (value));
@@ -1153,10 +1085,10 @@ test_dbus_account_plugin_set_attribute (McpAccountStorage *storage,
g_variant_new_parsed ("(%o, %s, %v)", account->path, attribute, value),
NULL);
- return TRUE;
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
}
-static gboolean
+static McpAccountStorageSetResult
test_dbus_account_plugin_set_parameter (McpAccountStorage *storage,
McpAccountManager *am,
const gchar *account_name,
@@ -1166,17 +1098,42 @@ test_dbus_account_plugin_set_parameter (McpAccountStorage *storage,
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
Account *account = lookup_account (self, account_name);
+ GVariant *old;
+ guint old_flags;
g_return_val_if_fail (account_name != NULL, FALSE);
g_return_val_if_fail (parameter != NULL, FALSE);
- /* for deletions, MC would call delete() instead */
- g_return_val_if_fail (value != NULL, FALSE);
DEBUG ("%s of %s", parameter, account_name);
- if (!self->active || account == NULL ||
- (account->flags & UNCOMMITTED_DELETION))
- return FALSE;
+ g_return_val_if_fail (self->active, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
+ g_return_val_if_fail (account != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
+
+ if (value == NULL)
+ {
+ if (!g_hash_table_contains (account->parameters, parameter) &&
+ !g_hash_table_contains (account->untyped_parameters, parameter))
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
+
+ g_hash_table_remove (account->parameters, parameter);
+ g_hash_table_remove (account->untyped_parameters, parameter);
+ g_hash_table_remove (account->parameter_flags, parameter);
+ g_hash_table_add (account->uncommitted_parameters, g_strdup (parameter));
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "DeferringDeleteParameter",
+ g_variant_new_parsed ("(%o, %s)", account->path, parameter), NULL);
+
+ return TRUE;
+ }
+
+ old = g_hash_table_lookup (account->parameters, parameter);
+ old_flags = GPOINTER_TO_UINT (g_hash_table_lookup (
+ account->parameter_flags, parameter));
+
+ if (old != NULL && g_variant_equal (old, value) && old_flags == flags)
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
g_hash_table_remove (account->untyped_parameters, parameter);
g_hash_table_insert (account->parameters, g_strdup (parameter),
@@ -1191,37 +1148,7 @@ test_dbus_account_plugin_set_parameter (McpAccountStorage *storage,
g_variant_new_parsed ("(%o, %s, %v)", account->path, parameter, value),
NULL);
- return TRUE;
-}
-
-static gboolean
-test_dbus_account_plugin_commit (const McpAccountStorage *storage,
- const McpAccountManager *am)
-{
- TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
- GHashTableIter iter;
- gpointer k;
-
- DEBUG ("called");
-
- if (!self->active)
- return FALSE;
-
- g_dbus_connection_emit_signal (self->bus, NULL,
- TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
- "CommittingAll", NULL, NULL);
-
- g_hash_table_iter_init (&iter, self->accounts);
-
- while (g_hash_table_iter_next (&iter, &k, NULL))
- {
- if (!mcp_account_storage_commit_one (storage, am, k))
- {
- g_warning ("declined to commit account %s", (const gchar *) k);
- }
- }
-
- return TRUE;
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
}
static void
@@ -1229,27 +1156,31 @@ delete_account_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
- AsyncData *ad = user_data;
+ GTask *task = user_data;
GVariant *tuple;
GError *error = NULL;
+ TestDBusAccountPlugin *self = g_task_get_source_object (task);
+ const gchar *account_name = g_task_get_task_data (task);
- tuple = g_dbus_connection_call_finish (ad->self->bus, res, &error);
+ tuple = g_dbus_connection_call_finish (self->bus, res, &error);
if (tuple != NULL)
{
- g_hash_table_remove (ad->self->accounts, ad->account_name);
+ /* we'll emit ::deleted when we see the signal, which probably
+ * already happened */
+ g_hash_table_remove (self->accounts, account_name);
g_variant_unref (tuple);
+ g_task_return_boolean (task, TRUE);
}
else
{
- g_warning ("Unable to delete account %s: %s", ad->account_name,
- error->message);
- g_clear_error (&error);
- /* FIXME: we could roll back the deletion by claiming that
- * the service re-created the account? */
+ g_prefix_error (&error, "Unable to delete account %s: ",
+ account_name);
+ g_warning ("%s", error->message);
+ g_task_return_error (task, error);
}
- async_data_free (ad);
+ g_object_unref (task);
}
static void
@@ -1355,12 +1286,12 @@ update_parameters_cb (GObject *source_object,
}
static gboolean
-test_dbus_account_plugin_commit_one (const McpAccountStorage *storage,
- const McpAccountManager *am,
+test_dbus_account_plugin_commit (McpAccountStorage *storage,
+ McpAccountManager *am,
const gchar *account_name)
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
- Account *account = lookup_account (self, account_name);
+ Account *account;
GHashTableIter iter;
gpointer k;
GVariantBuilder a_sv_builder;
@@ -1370,36 +1301,15 @@ test_dbus_account_plugin_commit_one (const McpAccountStorage *storage,
DEBUG ("%s", account_name);
- /* MC does not call @commit_one with parameter %NULL (meaning "all accounts")
- * if we also implement commit(), which, as it happens, we do */
- g_return_val_if_fail (account_name != NULL, FALSE);
+ account = lookup_account (self, account_name);
- if (!self->active || account == NULL)
- return FALSE;
+ g_return_val_if_fail (self->active, FALSE);
+ g_return_val_if_fail (account != NULL, FALSE);
g_dbus_connection_emit_signal (self->bus, NULL,
TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
"CommittingOne", g_variant_new_parsed ("(%o,)", account->path), NULL);
- if (account->flags & UNCOMMITTED_DELETION)
- {
- g_dbus_connection_call (self->bus,
- TEST_DBUS_ACCOUNT_SERVICE,
- TEST_DBUS_ACCOUNT_SERVICE_PATH,
- TEST_DBUS_ACCOUNT_SERVICE_IFACE,
- "DeleteAccount",
- g_variant_new_parsed ("(%s,)", account_name),
- G_VARIANT_TYPE_UNIT,
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL, /* no cancellable */
- delete_account_cb,
- async_data_new (self, account_name));
-
- /* this doesn't mean we succeeded: it means we tried */
- return TRUE;
- }
-
if (account->flags & UNCOMMITTED_CREATION)
{
g_dbus_connection_call (self->bus,
@@ -1526,7 +1436,7 @@ test_dbus_account_plugin_commit_one (const McpAccountStorage *storage,
}
static void
-test_dbus_account_plugin_get_identifier (const McpAccountStorage *storage,
+test_dbus_account_plugin_get_identifier (McpAccountStorage *storage,
const gchar *account_name,
GValue *identifier)
{
@@ -1535,8 +1445,8 @@ test_dbus_account_plugin_get_identifier (const McpAccountStorage *storage,
DEBUG ("%s", account_name);
- if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
- return;
+ g_return_if_fail (self->active);
+ g_return_if_fail (account != NULL);
/* Our "library-specific unique identifier" is just the object-path
* as a string. */
@@ -1545,7 +1455,7 @@ test_dbus_account_plugin_get_identifier (const McpAccountStorage *storage,
}
static GHashTable *
-test_dbus_account_plugin_get_additional_info (const McpAccountStorage *storage,
+test_dbus_account_plugin_get_additional_info (McpAccountStorage *storage,
const gchar *account_name)
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
@@ -1554,8 +1464,8 @@ test_dbus_account_plugin_get_additional_info (const McpAccountStorage *storage,
DEBUG ("%s", account_name);
- if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
- return NULL;
+ g_return_val_if_fail (self->active, NULL);
+ g_return_val_if_fail (account != NULL, NULL);
ret = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) tp_g_value_slice_free);
@@ -1566,7 +1476,7 @@ test_dbus_account_plugin_get_additional_info (const McpAccountStorage *storage,
}
static guint
-test_dbus_account_plugin_get_restrictions (const McpAccountStorage *storage,
+test_dbus_account_plugin_get_restrictions (McpAccountStorage *storage,
const gchar *account_name)
{
TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
@@ -1574,28 +1484,12 @@ test_dbus_account_plugin_get_restrictions (const McpAccountStorage *storage,
DEBUG ("%s", account_name);
- if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
- return 0;
+ g_return_val_if_fail (self->active, 0);
+ g_return_val_if_fail (account != NULL, 0);
return account->restrictions;
}
-static gboolean
-test_dbus_account_plugin_owns (McpAccountStorage *storage,
- McpAccountManager *am,
- const gchar *account_name)
-{
- TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
- Account *account = lookup_account (self, account_name);
-
- DEBUG ("%s", account_name);
-
- if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
- return FALSE;
-
- return TRUE;
-}
-
static void
account_storage_iface_init (McpAccountStorageIface *iface)
{
@@ -1604,18 +1498,17 @@ 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 = test_dbus_account_plugin_get;
- iface->set = test_dbus_account_plugin_set;
+ iface->get_attribute = test_dbus_account_plugin_get_attribute;
+ iface->get_parameter = test_dbus_account_plugin_get_parameter;
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;
iface->ready = test_dbus_account_plugin_ready;
- iface->delete = test_dbus_account_plugin_delete;
+ iface->delete_async = test_dbus_account_plugin_delete_async;
+ iface->delete_finish = test_dbus_account_plugin_delete_finish;
iface->commit = test_dbus_account_plugin_commit;
- iface->commit_one = test_dbus_account_plugin_commit_one;
iface->get_identifier = test_dbus_account_plugin_get_identifier;
iface->get_additional_info = test_dbus_account_plugin_get_additional_info;
iface->get_restrictions = test_dbus_account_plugin_get_restrictions;
iface->create = test_dbus_account_plugin_create;
- iface->owns = test_dbus_account_plugin_owns;
}
diff --git a/tests/twisted/mc-debug-server.c b/tests/twisted/mc-debug-server.c
index 48f02484..559f3f58 100644
--- a/tests/twisted/mc-debug-server.c
+++ b/tests/twisted/mc-debug-server.c
@@ -154,6 +154,7 @@ main (int argc, char **argv)
{
GError *error = NULL;
GDBusConnection *gdbus = NULL;
+ GDBusConnection *gdbus_system = NULL;
DBusConnection *connection = NULL;
int ret = 1;
GMainLoop *teardown_loop;
@@ -174,26 +175,18 @@ main (int argc, char **argv)
G_LOG_FATAL_MASK | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
gdbus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-
- if (gdbus == NULL)
- {
- g_warning ("%s", error->message);
- g_error_free (error);
- error = NULL;
- goto out;
- }
-
+ g_assert_no_error (error);
+ g_assert (gdbus != NULL);
g_dbus_connection_set_exit_on_close (gdbus, FALSE);
- bus_daemon = tp_dbus_daemon_dup (&error);
+ gdbus_system = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (gdbus_system != NULL);
+ g_dbus_connection_set_exit_on_close (gdbus_system, FALSE);
- if (bus_daemon == NULL)
- {
- g_warning ("%s", error->message);
- g_error_free (error);
- error = NULL;
- goto out;
- }
+ bus_daemon = tp_dbus_daemon_dup (&error);
+ g_assert_no_error (error);
+ g_assert (bus_daemon != NULL);
/* It appears that dbus-glib registers a filter that wrongly returns
* DBUS_HANDLER_RESULT_HANDLED for signals, so for *our* filter to have any
@@ -230,14 +223,13 @@ main (int argc, char **argv)
g_main_loop_run (teardown_loop);
-out:
-
if (connection != NULL)
{
dbus_connection_flush (connection);
}
tp_clear_object (&gdbus);
+ tp_clear_object (&gdbus_system);
tp_clear_object (&bus_daemon);
dbus_shutdown ();
diff --git a/tests/twisted/mcp-account-diversion.c b/tests/twisted/mcp-account-diversion.c
index 923f51b4..466d3ee3 100644
--- a/tests/twisted/mcp-account-diversion.c
+++ b/tests/twisted/mcp-account-diversion.c
@@ -111,109 +111,201 @@ _create_config (void)
DEBUG ("created %s", file);
}
-static gboolean
-_set (const McpAccountStorage *self,
- const McpAccountManager *am,
- const gchar *account,
- const gchar *key,
- const gchar *val)
+static McpAccountStorageSetResult
+_set (McpAccountStorage *self,
+ McpAccountManager *am,
+ const gchar *account,
+ const gchar *key,
+ GVariant *val,
+ McpParameterFlags flags)
{
AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self);
+ gchar *val_str;
+ gboolean changed;
if (g_str_has_prefix (account, DONT_DIVERT))
- return FALSE;
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
- adp->save = TRUE;
- g_key_file_set_value (adp->keyfile, account, key, val);
-
- return TRUE;
-}
+ if (val == NULL)
+ {
+ gsize n;
+ GStrv keys;
-static gboolean
-_get (const McpAccountStorage *self,
- const McpAccountManager *am,
- const gchar *account,
- const gchar *key)
-{
- AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self);
+ if (g_key_file_remove_key (adp->keyfile, account, key, NULL))
+ {
+ adp->save = TRUE;
+ changed = TRUE;
+ }
- if (key != NULL)
- {
- gchar *v = g_key_file_get_value (adp->keyfile, account, key, NULL);
+ keys = g_key_file_get_keys (adp->keyfile, account, &n, NULL);
- if (v == NULL)
- return FALSE;
+ if (keys == NULL || n == 0)
+ g_key_file_remove_group (adp->keyfile, account, NULL);
- mcp_account_manager_set_value (am, account, key, v);
- g_free (v);
+ g_strfreev (keys);
}
else
{
- gsize i;
- gsize n;
- GStrv keys = g_key_file_get_keys (adp->keyfile, account, &n, NULL);
+ gchar *old;
- if (keys == NULL)
- n = 0;
+ val_str = mcp_account_manager_escape_variant_for_keyfile (am, val);
- for (i = 0; i < n; i++)
- {
- gchar *v = g_key_file_get_value (adp->keyfile, account, keys[i], NULL);
+ old = g_key_file_get_value (adp->keyfile, account, key, NULL);
- if (v != NULL)
- mcp_account_manager_set_value (am, account, keys[i], v);
-
- g_free (v);
+ if (tp_strdiff (old, val_str))
+ {
+ g_key_file_set_value (adp->keyfile, account, key, val_str);
+ adp->save = TRUE;
+ changed = TRUE;
}
- g_strfreev (keys);
+ g_free (val_str);
+ g_free (old);
}
- return TRUE;
+ if (changed)
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
+ else
+ return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
}
-static gboolean
-_delete (const McpAccountStorage *self,
- const McpAccountManager *am,
+static McpAccountStorageSetResult
+_set_attribute (McpAccountStorage *self,
+ McpAccountManager *am,
const gchar *account,
- const gchar *key)
+ const gchar *attribute,
+ GVariant *val,
+ McpAttributeFlags flags)
+{
+ return _set (self, am, account, attribute, val, flags);
+}
+
+static McpAccountStorageSetResult
+_set_parameter (McpAccountStorage *self,
+ McpAccountManager *am,
+ const gchar *account,
+ const gchar *parameter,
+ GVariant *val,
+ McpParameterFlags flags)
+{
+ gchar *param = g_strdup_printf ("param-%s", parameter);
+ gboolean ret;
+
+ ret = _set (self, am, account, param, val, flags);
+ g_free (param);
+
+ return ret;
+}
+
+static GVariant *
+_get_attribute (McpAccountStorage *self,
+ McpAccountManager *am,
+ const gchar *account,
+ const gchar *attribute,
+ const GVariantType *type,
+ McpAttributeFlags *flags)
{
AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self);
+ gchar *v;
+ GVariant *ret;
- if (key == NULL)
- {
- if (g_key_file_remove_group (adp->keyfile, account, NULL))
- adp->save = TRUE;
- }
- else
- {
- gsize n;
- GStrv keys;
+ if (flags != NULL)
+ *flags = 0;
- if (g_key_file_remove_key (adp->keyfile, account, key, NULL))
- adp->save = TRUE;
+ v = g_key_file_get_value (adp->keyfile, account, attribute, NULL);
- keys = g_key_file_get_keys (adp->keyfile, account, &n, NULL);
+ if (v == NULL)
+ return NULL;
- if (keys == NULL || n == 0)
- g_key_file_remove_group (adp->keyfile, account, NULL);
+ ret = mcp_account_manager_unescape_variant_from_keyfile (am, v, type, NULL);
+ g_free (v);
+ return ret;
+}
- g_strfreev (keys);
+static GVariant *
+_get_parameter (McpAccountStorage *self,
+ McpAccountManager *am,
+ const gchar *account,
+ const gchar *parameter,
+ const GVariantType *type,
+ McpParameterFlags *flags)
+{
+ AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self);
+ gchar *key;
+ gchar *v;
+ GVariant *ret;
+
+ if (flags != NULL)
+ *flags = 0;
+
+ key = g_strdup_printf ("param-%s", parameter);
+ v = g_key_file_get_value (adp->keyfile, account, key, NULL);
+ g_free (key);
+
+ if (v == NULL)
+ return NULL;
+
+ ret = mcp_account_manager_unescape_variant_from_keyfile (am, v, type, NULL);
+ g_free (v);
+ return ret;
+}
+
+static gboolean _commit (McpAccountStorage *self,
+ McpAccountManager *am,
+ const gchar *account_name);
+
+static void
+delete_async (McpAccountStorage *self,
+ McpAccountManager *am,
+ const gchar *account,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self);
+ GTask *task = g_task_new (adp, cancellable, callback, user_data);
+
+ if (g_key_file_remove_group (adp->keyfile, account, NULL))
+ adp->save = TRUE;
+
+ if (_commit (self, am, account))
+ {
+ mcp_account_storage_emit_deleted (self, account);
+ g_task_return_boolean (task, TRUE);
+ }
+ else
+ {
+ g_task_return_new_error (task, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
+ "_commit()'s error handling is not good enough to know why "
+ "I couldn't commit the deletion of %s", account);
}
- return TRUE;
+ g_object_unref (task);
}
+static gboolean
+delete_finish (McpAccountStorage *storage,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
static gboolean
-_commit (const McpAccountStorage *self,
- const McpAccountManager *am)
+_commit (McpAccountStorage *self,
+ McpAccountManager *am,
+ const gchar *account_name G_GNUC_UNUSED)
{
gsize n;
gchar *data;
AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self);
gboolean rval = FALSE;
+ /* This simple implementation ignores account_name and commits everything:
+ * we're writing out the whole keyfile anyway. If MC is looping over
+ * accounts, the second and subsequent accounts will find that
+ * adp->save is false, so there's no write-amplification. */
+
if (!adp->save)
return TRUE;
@@ -229,8 +321,8 @@ _commit (const McpAccountStorage *self,
}
static GList *
-_list (const McpAccountStorage *self,
- const McpAccountManager *am)
+_list (McpAccountStorage *self,
+ McpAccountManager *am)
{
gsize i;
gsize n;
@@ -255,6 +347,35 @@ _list (const McpAccountStorage *self,
return rval;
}
+static gchar *
+create (McpAccountStorage *self,
+ McpAccountManager *am,
+ const gchar *manager,
+ const gchar *protocol,
+ const gchar *identification,
+ GError **error)
+{
+ gchar *unique_name;
+
+ unique_name = mcp_account_manager_get_unique_name (MCP_ACCOUNT_MANAGER (am),
+ manager, protocol,
+ identification);
+
+ g_return_val_if_fail (unique_name != NULL, NULL);
+
+ if (g_str_has_prefix (unique_name, DONT_DIVERT))
+ {
+ g_free (unique_name);
+ return NULL;
+ }
+
+ /* No need to actually create anything: we'll happily return values
+ * from get(., ., ., NULL) regardless of whether we have that account
+ * in our list */
+
+ return unique_name;
+}
+
static void
account_storage_iface_init (McpAccountStorageIface *iface,
gpointer unused G_GNUC_UNUSED)
@@ -263,11 +384,15 @@ account_storage_iface_init (McpAccountStorageIface *iface,
iface->desc = PLUGIN_DESCRIPTION;
iface->priority = PLUGIN_PRIORITY;
- iface->get = _get;
- iface->set = _set;
- iface->delete = _delete;
+ iface->get_attribute = _get_attribute;
+ iface->get_parameter = _get_parameter;
+ iface->set_attribute = _set_attribute;
+ iface->set_parameter = _set_parameter;
+ iface->delete_async = delete_async;
+ iface->delete_finish = delete_finish;
iface->commit = _commit;
iface->list = _list;
+ iface->create = create;
}
diff --git a/tests/twisted/mctest.py b/tests/twisted/mctest.py
index 35ccec97..2229525b 100644
--- a/tests/twisted/mctest.py
+++ b/tests/twisted/mctest.py
@@ -1018,12 +1018,11 @@ class SimulatedConnectionManager(object):
for protocol_name in protocol_names:
assert '-' not in protocol_name
- q.add_dbus_method_impl(self.IdentifyAccount,
- path=self.object_path + '/' + protocol_name,
- interface=cs.PROTOCOL, method='IdentifyAccount')
- q.add_dbus_method_impl(self.NormalizeContact,
- path=self.object_path + '/' + protocol_name,
- interface=cs.PROTOCOL, method='NormalizeContact')
+
+ q.add_dbus_method_impl(self.IdentifyAccount,
+ interface=cs.PROTOCOL, method='IdentifyAccount')
+ q.add_dbus_method_impl(self.NormalizeContact,
+ interface=cs.PROTOCOL, method='NormalizeContact')
def release_name(self):
del self._bus_name_ref
@@ -1132,11 +1131,32 @@ class SimulatedConnectionManager(object):
}, signature='a{sv}', bus=self.bus)
def IdentifyAccount(self, e):
+ if e.path.startswith(self.object_path + '/'):
+ protocol = e.path[len(self.object_path + '/'):]
+
+ if protocol not in self.protocol_names:
+ self.q.dbus_raise(e.message, cs.DBUS_ERROR_UNKNOWN_METHOD,
+ 'Not my protocol')
+ return
+ else:
+ self.q.dbus_raise(e.message, cs.DBUS_ERROR_UNKNOWN_METHOD,
+ 'Not even my object path')
+ return
+
+ if protocol in ('serializable', 'defaults') and 's' in e.args[0]:
+ ret = e.args[0]['s'].lower()
+ if ret:
+ self.q.dbus_return(e.message, ret, signature='s')
+ return
+
if 'account' in e.args[0]:
ret = e.args[0]['account'].lower()
- else:
- ret = 'account'
- self.q.dbus_return(e.message, ret, signature='s')
+ if ret:
+ self.q.dbus_return(e.message, ret, signature='s')
+ return
+
+ self.q.dbus_raise(e.message, cs.INVALID_HANDLE,
+ 'Invalid account name %r' % e.args[0].get('account'))
def NormalizeContact(self, e):
self.q.dbus_return(e.message, e.args[0].lower(), signature='s')