summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2013-02-13 14:13:42 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2013-02-13 14:13:42 +0000
commit5aeddb8e0a314780585af7b8f19896a2be9815d4 (patch)
treee989c6187a40d59a6f6969b68e161575db574b83
parent128ceb7d37ff5847a9e79f2bafa6127ae97f585b (diff)
parent3975989913b12fa1488d00085d8cdb84e5b3f46d (diff)
Merge branch 'typed-settings-54872'
Reviewed-by: Will Thompson <will.thompson@collabora.co.uk> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54872 [amended to add GLib 2.32 dependency -smcv] Conflicts: src/mcd-account.c
-rw-r--r--configure.ac4
-rw-r--r--mission-control-plugins/account-storage.c47
-rw-r--r--mission-control-plugins/account-storage.h8
-rw-r--r--mission-control-plugins/account.c84
-rw-r--r--mission-control-plugins/account.h15
-rw-r--r--mission-control-plugins/implementation.h12
-rw-r--r--src/mcd-account-addressing.c12
-rw-r--r--src/mcd-account-conditions.c9
-rw-r--r--src/mcd-account-config.h46
-rw-r--r--src/mcd-account-manager.c7
-rw-r--r--src/mcd-account.c110
-rw-r--r--src/mcd-misc.c13
-rw-r--r--src/mcd-misc.h2
-rw-r--r--src/mcd-storage.c858
-rw-r--r--src/mcd-storage.h58
15 files changed, 1064 insertions, 221 deletions
diff --git a/configure.ac b/configure.ac
index fc651e4e..a44d4f67 100644
--- a/configure.ac
+++ b/configure.ac
@@ -265,12 +265,12 @@ AC_DEFINE([TP_SEAL_ENABLE], [], [Define to hide deprecated struct fields])
AC_DEFINE([TP_DISABLE_SINGLE_INCLUDE], [], [Avoid individual headers])
PKG_CHECK_MODULES([GLIB],
- [glib-2.0 >= 2.30, gobject-2.0, gmodule-no-export-2.0, gio-2.0])
+ [glib-2.0 >= 2.32, gobject-2.0, gmodule-no-export-2.0, gio-2.0])
AC_SUBST(GLIB_LIBS)
AC_SUBST(GLIB_CFLAGS)
AC_DEFINE([GLIB_VERSION_MIN_REQUIRED], [GLIB_VERSION_2_30], [Ignore post 2.30 deprecations])
-AC_DEFINE([GLIB_VERSION_MAX_ALLOWED], [GLIB_VERSION_2_30], [Prevent post 2.30 APIs])
+AC_DEFINE([GLIB_VERSION_MAX_ALLOWED], [GLIB_VERSION_2_32], [Prevent post 2.32 APIs])
dnl Check for MCE, a Maemo service used to determine when the device is idle.
PKG_CHECK_MODULES([MCE], mce >= 1.5, [HAVE_MCE=yes], [HAVE_MCE=no])
diff --git a/mission-control-plugins/account-storage.c b/mission-control-plugins/account-storage.c
index beecf75e..59871d5b 100644
--- a/mission-control-plugins/account-storage.c
+++ b/mission-control-plugins/account-storage.c
@@ -67,6 +67,7 @@
* 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;
* }
* </programlisting></example>
*
@@ -110,11 +111,27 @@ enum
static guint signals[NO_SIGNAL] = { 0 };
+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");
+}
+
static void
class_init (gpointer klass,
gpointer data)
{
GType type = G_TYPE_FROM_CLASS (klass);
+ McpAccountStorageIface *iface = klass;
+
+ iface->owns = default_owns;
if (signals[CREATED] != 0)
{
@@ -1096,3 +1113,33 @@ mcp_account_storage_emit_reconnect (McpAccountStorage *storage,
{
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.13.UNRELEASED
+ */
+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 a5b5db50..ef19fd62 100644
--- a/mission-control-plugins/account-storage.h
+++ b/mission-control-plugins/account-storage.h
@@ -127,6 +127,11 @@ struct _McpAccountStorageIface
McpAccountStorageGetAdditionalInfoFunc get_additional_info;
McpAccountStorageGetRestrictionsFunc get_restrictions;
McpAccountStorageCreate create;
+
+ /* Since 5.13.UNRELEASED */
+ gboolean (*owns) (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account);
};
#ifndef __GTK_DOC_IGNORE__
@@ -248,6 +253,9 @@ const gchar *mcp_account_storage_name (const McpAccountStorage *storage);
const gchar *mcp_account_storage_description (const McpAccountStorage *storage);
const gchar *mcp_account_storage_provider (const McpAccountStorage *storage);
+gboolean mcp_account_storage_owns (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account);
void mcp_account_storage_emit_created (McpAccountStorage *storage,
const gchar *account);
G_DEPRECATED_FOR (something that is actually implemented)
diff --git a/mission-control-plugins/account.c b/mission-control-plugins/account.c
index a026d15c..931ed621 100644
--- a/mission-control-plugins/account.c
+++ b/mission-control-plugins/account.c
@@ -237,3 +237,87 @@ mcp_account_manager_get_unique_name (McpAccountManager *mcpa,
return iface->unique_name (mcpa, manager, protocol, params);
}
+
+/**
+ * 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_unescape_value_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
+ *
+ * Attempt to interpret @escaped as a value of @value's type.
+ * If successful, put it in @value and return %TRUE.
+ *
+ * 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.
+ *
+ * Returns: %TRUE if @value was filled in
+ */
+gboolean
+mcp_account_manager_unescape_value_from_keyfile (const McpAccountManager *mcpa,
+ const gchar *escaped,
+ GValue *value,
+ 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);
+
+ return iface->init_value_for_attribute (mcpa, value, attribute);
+}
diff --git a/mission-control-plugins/account.h b/mission-control-plugins/account.h
index d281f625..05f30057 100644
--- a/mission-control-plugins/account.h
+++ b/mission-control-plugins/account.h
@@ -70,6 +70,21 @@ gchar * mcp_account_manager_get_unique_name (McpAccountManager *mcpa,
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);
+
+gboolean mcp_account_manager_unescape_value_from_keyfile (
+ const McpAccountManager *mcpa,
+ const gchar *escaped,
+ GValue *value,
+ GError **error);
+
+gboolean mcp_account_manager_init_value_for_attribute (
+ const McpAccountManager *mcpa,
+ GValue *value,
+ const gchar *attribute);
+
G_END_DECLS
#endif
diff --git a/mission-control-plugins/implementation.h b/mission-control-plugins/implementation.h
index 918f8309..6cbf7a9b 100644
--- a/mission-control-plugins/implementation.h
+++ b/mission-control-plugins/implementation.h
@@ -104,6 +104,18 @@ struct _McpAccountManagerIface {
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);
};
G_END_DECLS
diff --git a/src/mcd-account-addressing.c b/src/mcd-account-addressing.c
index 19d622d4..ec3d8f5e 100644
--- a/src/mcd-account-addressing.c
+++ b/src/mcd-account-addressing.c
@@ -32,8 +32,6 @@
#include "mcd-account-priv.h"
#include "_gen/interfaces.h"
-#define SCHEMES TP_IFACE_ACCOUNT_INTERFACE_ADDRESSING ".URISchemes"
-
static void
addressing_set_uri_scheme_association (TpSvcAccountInterfaceAddressing *iface,
const gchar *uri_scheme,
@@ -49,7 +47,8 @@ addressing_set_uri_scheme_association (TpSvcAccountInterfaceAddressing *iface,
g_value_init (&value, G_TYPE_STRV);
- if (mcd_storage_get_value (storage, account, SCHEMES, &value, NULL))
+ if (mcd_storage_get_attribute (storage, account, MC_ACCOUNTS_KEY_URI_SCHEMES,
+ &value, NULL))
{
schemes = g_value_get_boxed (&value);
old_association = tp_strv_contains ((const gchar * const *) schemes,
@@ -79,8 +78,8 @@ addressing_set_uri_scheme_association (TpSvcAccountInterfaceAddressing *iface,
}
g_ptr_array_add (new_schemes, NULL);
- mcd_storage_set_strv (storage, account, SCHEMES,
- (const gchar * const *) new_schemes->pdata, FALSE);
+ mcd_storage_set_strv (storage, account, MC_ACCOUNTS_KEY_URI_SCHEMES,
+ (const gchar * const *) new_schemes->pdata);
changed = tp_asv_new (
"URISchemes", G_TYPE_STRV, new_schemes->pdata,
@@ -109,7 +108,8 @@ addressing_get_uri_schemes (TpSvcDBusProperties *iface,
g_value_init (value, G_TYPE_STRV);
- if (!mcd_storage_get_value (storage, account, SCHEMES, value, NULL))
+ if (!mcd_storage_get_attribute (storage, account, MC_ACCOUNTS_KEY_URI_SCHEMES,
+ value, NULL))
{
g_value_set_boxed (value, NULL);
}
diff --git a/src/mcd-account-conditions.c b/src/mcd-account-conditions.c
index 8a6af964..b36d6b1f 100644
--- a/src/mcd-account-conditions.c
+++ b/src/mcd-account-conditions.c
@@ -49,8 +49,7 @@ store_condition (gpointer key, gpointer value, gpointer userdata)
gchar condition_key[256];
g_snprintf (condition_key, sizeof (condition_key), "condition-%s", name);
- mcd_storage_set_string (storage, account_name, condition_key, condition,
- FALSE);
+ mcd_storage_set_string (storage, account_name, condition_key, condition);
}
static gboolean
@@ -84,14 +83,14 @@ set_condition (TpSvcDBusProperties *self, const gchar *name,
conditions = g_value_get_boxed (value);
/* first, delete existing conditions */
- keys = mcd_storage_dup_settings (storage, account_name, NULL);
+ keys = mcd_storage_dup_attributes (storage, account_name, NULL);
for (key = keys; *key != NULL; key++)
{
if (strncmp (*key, "condition-", 10) != 0)
continue;
- mcd_storage_set_value (storage, account_name, *key, NULL, FALSE);
+ mcd_storage_set_attribute (storage, account_name, *key, NULL);
}
g_strfreev (keys);
@@ -136,7 +135,7 @@ GHashTable *mcd_account_get_conditions (McdAccount *account)
conditions = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
- keys = mcd_storage_dup_settings (storage, account_name, NULL);
+ keys = mcd_storage_dup_attributes (storage, account_name, NULL);
for (key = keys; *key != NULL; key++)
{
diff --git a/src/mcd-account-config.h b/src/mcd-account-config.h
index 2d6d053f..3124692e 100644
--- a/src/mcd-account-config.h
+++ b/src/mcd-account-config.h
@@ -27,33 +27,53 @@
#ifndef __MCD_ACCOUNT_CONFIG_H__
#define __MCD_ACCOUNT_CONFIG_H__
+#include <telepathy-glib/telepathy-glib-dbus.h>
+
+/* If you add new storable attributes you must also update
+ * known_attributes in mcd-storage.c. */
+
+/* string, 's' */
#define MC_ACCOUNTS_KEY_MANAGER "manager"
#define MC_ACCOUNTS_KEY_PROTOCOL "protocol"
-#define MC_ACCOUNTS_KEY_PRESETS "presets"
-#define MC_ACCOUNTS_KEY_GROUPS "groups"
#define MC_ACCOUNTS_KEY_DISPLAY_NAME "DisplayName"
-#define MC_ACCOUNTS_KEY_ICON_NAME "icon_name"
#define MC_ACCOUNTS_KEY_NORMALIZED_NAME "NormalizedName"
-#define MC_ACCOUNTS_KEY_ENABLED "Enabled"
-#define MC_ACCOUNTS_KEY_DELETED "deleted"
-#define MC_ACCOUNTS_KEY_PROFILE "profile"
-#define MC_ACCOUNTS_KEY_PARAM_ACCOUNT "account"
#define MC_ACCOUNTS_KEY_AVATAR_TOKEN "avatar_token"
#define MC_ACCOUNTS_KEY_AVATAR_MIME "AvatarMime"
-#define MC_ACCOUNTS_KEY_AVATAR_ID "avatar_id"
-#define MC_ACCOUNTS_KEY_AUTO_PRESENCE_TYPE "AutomaticPresenceType"
#define MC_ACCOUNTS_KEY_AUTO_PRESENCE_STATUS "AutomaticPresenceStatus"
#define MC_ACCOUNTS_KEY_AUTO_PRESENCE_MESSAGE "AutomaticPresenceMessage"
+#define MC_ACCOUNTS_KEY_ICON "Icon"
+#define MC_ACCOUNTS_KEY_NICKNAME "Nickname"
+#define MC_ACCOUNTS_KEY_SERVICE "Service"
+/* ... also "condition-*" reserved by mcd-account-conditions.c */
+
+/* unsigned 32-bit integer, 'u' */
+#define MC_ACCOUNTS_KEY_AUTO_PRESENCE_TYPE "AutomaticPresenceType"
+
+/* boolean, 'b' */
+#define MC_ACCOUNTS_KEY_ALWAYS_DISPATCH "always_dispatch"
#define MC_ACCOUNTS_KEY_CONNECT_AUTOMATICALLY "ConnectAutomatically"
+#define MC_ACCOUNTS_KEY_ENABLED "Enabled"
#define MC_ACCOUNTS_KEY_HAS_BEEN_ONLINE "HasBeenOnline"
-#define MC_ACCOUNTS_KEY_DATA_DIR "data_dir"
-#define MC_ACCOUNTS_KEY_ALIAS "Nickname"
-#define MC_ACCOUNTS_KEY_SECONDARY_VCARD_FIELDS "secondary_vcard_fields"
#define MC_ACCOUNTS_KEY_HIDDEN "Hidden"
-#define MC_ACCOUNTS_KEY_ALWAYS_DISPATCH "always_dispatch"
+
+/* string array, 'as' */
+#define MC_ACCOUNTS_KEY_URI_SCHEMES \
+ TP_IFACE_ACCOUNT_INTERFACE_ADDRESSING ".URISchemes"
+
+/* object path array, 'ao' */
#define MC_ACCOUNTS_KEY_SUPERSEDES "Supersedes"
+/* things that previously existed, so they should now be considered
+ * to be reserved */
#define PRESETS_GROUP "Presets"
#define PRESETS_GROUP_DEFAULTS "Defaults"
+#define MC_OLD_ACCOUNTS_KEY_AVATAR_ID "avatar_id"
+#define MC_OLD_ACCOUNTS_KEY_DATA_DIR "data_dir"
+#define MC_OLD_ACCOUNTS_KEY_DELETED "deleted"
+#define MC_OLD_ACCOUNTS_KEY_GROUPS "groups"
+#define MC_OLD_ACCOUNTS_KEY_ICON_NAME "icon_name"
+#define MC_OLD_ACCOUNTS_KEY_PRESETS "presets"
+#define MC_OLD_ACCOUNTS_KEY_PROFILE "profile"
+#define MC_OLD_ACCOUNTS_KEY_SECONDARY_VCARD_FIELDS "secondary_vcard_fields"
#endif /* __MCD_ACCOUNT_CONFIG_H__ */
diff --git a/src/mcd-account-manager.c b/src/mcd-account-manager.c
index 11976173..e597eb1d 100644
--- a/src/mcd-account-manager.c
+++ b/src/mcd-account-manager.c
@@ -915,14 +915,13 @@ _mcd_account_manager_create_account (McdAccountManager *account_manager,
/* create the basic account keys */
mcd_storage_set_string (storage, unique_name,
- MC_ACCOUNTS_KEY_MANAGER, manager, FALSE);
+ MC_ACCOUNTS_KEY_MANAGER, manager);
mcd_storage_set_string (storage, unique_name,
- MC_ACCOUNTS_KEY_PROTOCOL, protocol, FALSE);
+ MC_ACCOUNTS_KEY_PROTOCOL, protocol);
if (display_name != NULL)
mcd_storage_set_string (storage, unique_name,
- MC_ACCOUNTS_KEY_DISPLAY_NAME, display_name,
- FALSE);
+ MC_ACCOUNTS_KEY_DISPLAY_NAME, display_name);
account = mcd_account_new (account_manager, unique_name);
g_free (unique_name);
diff --git a/src/mcd-account.c b/src/mcd-account.c
index b1b20d02..c7b941db 100644
--- a/src/mcd-account.c
+++ b/src/mcd-account.c
@@ -51,7 +51,6 @@
#include "_gen/gtypes.h"
#include "_gen/cli-Connection_Manager_Interface_Account_Storage-body.h"
-#define MAX_KEY_LENGTH (DBUS_MAXIMUM_NAME_LENGTH + 6)
#define MC_OLD_AVATAR_FILENAME "avatar.bin"
#define MCD_ACCOUNT_PRIV(account) (MCD_ACCOUNT (account)->priv)
@@ -382,26 +381,12 @@ _mcd_account_set_parameter (McdAccount *account, const gchar *name,
{
McdAccountPrivate *priv = account->priv;
McdStorage *storage = priv->storage;
- gchar key[MAX_KEY_LENGTH];
const gchar *account_name = mcd_account_get_unique_name (account);
gboolean secret = mcd_account_parameter_is_secret (account, name);
- g_snprintf (key, sizeof (key), "param-%s", name);
-
- mcd_storage_set_value (storage, account_name, key, value, secret);
+ mcd_storage_set_parameter (storage, account_name, name, value, secret);
}
-
-
-
-
-
-
-
-
-
-
-
static GType mc_param_type (const TpConnectionManagerParam *param);
/**
@@ -443,13 +428,11 @@ mcd_account_get_parameter_of_known_type (McdAccount *account,
{
const gchar *account_name = mcd_account_get_unique_name (account);
McdStorage *storage = account->priv->storage;
- gchar key[MAX_KEY_LENGTH];
GValue tmp = G_VALUE_INIT;
- g_snprintf (key, sizeof (key), "param-%s", name);
g_value_init (&tmp, type);
- if (mcd_storage_get_value (storage, account_name, key, &tmp, error))
+ if (mcd_storage_get_parameter (storage, account_name, name, &tmp, error))
{
if (parameter != NULL)
{
@@ -1051,7 +1034,7 @@ mcd_account_set_string_val (McdAccount *account, const gchar *key,
new_string = NULL;
}
- if (mcd_storage_set_string (storage, name, key, new_string, FALSE)) {
+ if (mcd_storage_set_string (storage, name, key, new_string)) {
mcd_storage_commit (storage, name);
mcd_account_changed_property (account, key, value);
return SET_RESULT_CHANGED;
@@ -1069,7 +1052,7 @@ mcd_account_get_string_val (McdAccount *account, const gchar *key,
g_value_init (value, G_TYPE_STRING);
- if (!mcd_storage_get_value (priv->storage, name, key, value, NULL))
+ if (!mcd_storage_get_attribute (priv->storage, name, key, value, NULL))
{
g_value_set_static_string (value, NULL);
}
@@ -1083,8 +1066,8 @@ set_display_name (TpSvcDBusProperties *self, const gchar *name,
McdAccountPrivate *priv = account->priv;
DEBUG ("called for %s", priv->unique_name);
- return (mcd_account_set_string_val (account, name, value, error)
- != SET_RESULT_ERROR);
+ return (mcd_account_set_string_val (account,
+ MC_ACCOUNTS_KEY_DISPLAY_NAME, value, error) != SET_RESULT_ERROR);
}
static void
@@ -1092,7 +1075,7 @@ get_display_name (TpSvcDBusProperties *self, const gchar *name, GValue *value)
{
McdAccount *account = MCD_ACCOUNT (self);
- mcd_account_get_string_val (account, name, value);
+ mcd_account_get_string_val (account, MC_ACCOUNTS_KEY_DISPLAY_NAME, value);
}
static gboolean
@@ -1103,8 +1086,8 @@ set_icon (TpSvcDBusProperties *self, const gchar *name, const GValue *value,
McdAccountPrivate *priv = account->priv;
DEBUG ("called for %s", priv->unique_name);
- return (mcd_account_set_string_val (account, name, value, error)
- != SET_RESULT_ERROR);
+ return (mcd_account_set_string_val (account,
+ MC_ACCOUNTS_KEY_ICON, value, error) != SET_RESULT_ERROR);
}
static void
@@ -1112,7 +1095,7 @@ get_icon (TpSvcDBusProperties *self, const gchar *name, GValue *value)
{
McdAccount *account = MCD_ACCOUNT (self);
- mcd_account_get_string_val (account, name, value);
+ mcd_account_get_string_val (account, MC_ACCOUNTS_KEY_ICON, value);
}
static void
@@ -1176,8 +1159,8 @@ _mcd_account_set_enabled (McdAccount *account,
g_value_init (&value, G_TYPE_BOOLEAN);
g_value_set_boolean (&value, enabled);
- mcd_storage_set_value (priv->storage, name,
- MC_ACCOUNTS_KEY_ENABLED, &value, FALSE);
+ mcd_storage_set_attribute (priv->storage, name,
+ MC_ACCOUNTS_KEY_ENABLED, &value);
if (write_out)
mcd_storage_commit (priv->storage, name);
@@ -1256,7 +1239,8 @@ set_service (TpSvcDBusProperties *self, const gchar *name,
* the appropriate error for us: don't duplicate that logic here */
if (proceed)
{
- ret = mcd_account_set_string_val (account, name, value, error);
+ ret = mcd_account_set_string_val (account, MC_ACCOUNTS_KEY_SERVICE,
+ value, error);
}
else
{
@@ -1275,7 +1259,7 @@ get_service (TpSvcDBusProperties *self, const gchar *name, GValue *value)
{
McdAccount *account = MCD_ACCOUNT (self);
- mcd_account_get_string_val (account, name, value);
+ mcd_account_get_string_val (account, MC_ACCOUNTS_KEY_SERVICE, value);
}
static void
@@ -1345,7 +1329,8 @@ set_nickname (TpSvcDBusProperties *self, const gchar *name,
value = &replacement;
}
- ret = mcd_account_set_string_val (account, name, value, error);
+ ret = mcd_account_set_string_val (account, MC_ACCOUNTS_KEY_NICKNAME,
+ value, error);
if (ret != SET_RESULT_ERROR)
{
@@ -1364,7 +1349,7 @@ get_nickname (TpSvcDBusProperties *self, const gchar *name, GValue *value)
{
McdAccount *account = MCD_ACCOUNT (self);
- mcd_account_get_string_val (account, name, value);
+ mcd_account_get_string_val (account, MC_ACCOUNTS_KEY_NICKNAME, value);
}
static void
@@ -1678,9 +1663,9 @@ set_automatic_presence (TpSvcDBusProperties *self,
g_value_init (&presence, G_TYPE_INT);
g_value_set_int (&presence, type);
- mcd_storage_set_value (priv->storage, account_name,
- MC_ACCOUNTS_KEY_AUTO_PRESENCE_TYPE,
- &presence, FALSE);
+ mcd_storage_set_attribute (priv->storage, account_name,
+ MC_ACCOUNTS_KEY_AUTO_PRESENCE_TYPE,
+ &presence);
priv->auto_presence_type = type;
changed = TRUE;
}
@@ -1694,7 +1679,7 @@ set_automatic_presence (TpSvcDBusProperties *self,
mcd_storage_set_string (priv->storage, account_name,
MC_ACCOUNTS_KEY_AUTO_PRESENCE_STATUS,
- new_status, FALSE);
+ new_status);
g_free (priv->auto_presence_status);
priv->auto_presence_status = g_strdup (status);
@@ -1710,7 +1695,7 @@ set_automatic_presence (TpSvcDBusProperties *self,
mcd_storage_set_string (priv->storage, account_name,
MC_ACCOUNTS_KEY_AUTO_PRESENCE_MESSAGE,
- new_message, FALSE);
+ new_message);
g_free (priv->auto_presence_message);
priv->auto_presence_message = g_strdup (message);
@@ -1783,9 +1768,9 @@ set_connect_automatically (TpSvcDBusProperties *self,
if (priv->connect_automatically != connect_automatically)
{
const gchar *account_name = mcd_account_get_unique_name (account);
- mcd_storage_set_value (priv->storage, account_name,
- MC_ACCOUNTS_KEY_CONNECT_AUTOMATICALLY,
- value, FALSE);
+ mcd_storage_set_attribute (priv->storage, account_name,
+ MC_ACCOUNTS_KEY_CONNECT_AUTOMATICALLY,
+ value);
priv->connect_automatically = connect_automatically;
mcd_storage_commit (priv->storage, account_name);
@@ -1980,7 +1965,8 @@ get_normalized_name (TpSvcDBusProperties *self,
{
McdAccount *account = MCD_ACCOUNT (self);
- mcd_account_get_string_val (account, name, value);
+ mcd_account_get_string_val (account, MC_ACCOUNTS_KEY_NORMALIZED_NAME,
+ value);
}
static gboolean
@@ -2005,8 +1991,8 @@ set_supersedes (TpSvcDBusProperties *svc,
self->priv->supersedes = g_value_dup_boxed (value);
mcd_account_changed_property (self, name, value);
- mcd_storage_set_value (self->priv->storage, self->priv->unique_name,
- MC_ACCOUNTS_KEY_SUPERSEDES, value, FALSE);
+ mcd_storage_set_attribute (self->priv->storage, self->priv->unique_name,
+ MC_ACCOUNTS_KEY_SUPERSEDES, value);
mcd_storage_commit (self->priv->storage, self->priv->unique_name);
return TRUE;
@@ -2229,8 +2215,8 @@ set_hidden (TpSvcDBusProperties *self,
* So for now we check whether the value has changed, and violate the spec
* by making this property mutable (at least with the keyfile backend).
*/
- if (mcd_storage_set_value (priv->storage, account_name,
- MC_ACCOUNTS_KEY_HIDDEN, value, FALSE))
+ if (mcd_storage_set_attribute (priv->storage, account_name,
+ MC_ACCOUNTS_KEY_HIDDEN, value))
{
mcd_storage_commit (priv->storage, account_name);
mcd_account_changed_property (account, MC_ACCOUNTS_KEY_HIDDEN, value);
@@ -3306,8 +3292,8 @@ mcd_account_setup (McdAccount *account)
if (priv->supersedes != NULL)
g_ptr_array_unref (priv->supersedes);
- if (mcd_storage_get_value (storage, name,
- MC_ACCOUNTS_KEY_SUPERSEDES, &value, NULL))
+ if (mcd_storage_get_attribute (storage, name,
+ MC_ACCOUNTS_KEY_SUPERSEDES, &value, NULL))
{
priv->supersedes = g_value_dup_boxed (&value);
}
@@ -4007,10 +3993,8 @@ _mcd_account_set_normalized_name (McdAccount *account, const gchar *name)
g_value_init (&value, G_TYPE_STRING);
g_value_set_static_string (&value, name);
- mcd_storage_set_value (priv->storage,
- account_name,
- MC_ACCOUNTS_KEY_NORMALIZED_NAME,
- &value, FALSE);
+ mcd_storage_set_attribute (priv->storage, account_name,
+ MC_ACCOUNTS_KEY_NORMALIZED_NAME, &value);
mcd_storage_commit (priv->storage, account_name);
mcd_account_changed_property (account, MC_ACCOUNTS_KEY_NORMALIZED_NAME,
&value);
@@ -4028,7 +4012,7 @@ _mcd_account_set_avatar_token (McdAccount *account, const gchar *token)
mcd_storage_set_string (priv->storage,
account_name,
MC_ACCOUNTS_KEY_AVATAR_TOKEN,
- token, FALSE);
+ token);
mcd_storage_commit (priv->storage, account_name);
}
@@ -4077,7 +4061,7 @@ _mcd_account_set_avatar (McdAccount *account, const GArray *avatar,
mcd_storage_set_string (priv->storage,
account_name,
MC_ACCOUNTS_KEY_AVATAR_MIME,
- mime_type, FALSE);
+ mime_type);
if (token)
{
@@ -4088,7 +4072,7 @@ _mcd_account_set_avatar (McdAccount *account, const GArray *avatar,
mcd_storage_set_string (priv->storage,
account_name,
MC_ACCOUNTS_KEY_AVATAR_TOKEN,
- token, FALSE);
+ token);
if (!prev_token || strcmp (prev_token, token) != 0)
tp_svc_account_interface_avatar_emit_avatar_changed (account);
@@ -4097,10 +4081,8 @@ _mcd_account_set_avatar (McdAccount *account, const GArray *avatar,
}
else
{
- mcd_storage_set_value (priv->storage,
- account_name,
- MC_ACCOUNTS_KEY_AVATAR_TOKEN,
- NULL, FALSE);
+ mcd_storage_set_attribute (priv->storage, account_name,
+ MC_ACCOUNTS_KEY_AVATAR_TOKEN, NULL);
mcd_account_send_avatar_to_connection (account, avatar, mime_type);
}
@@ -4211,7 +4193,7 @@ mcd_account_self_contact_notify_alias_cb (McdAccount *self,
g_value_init (&value, G_TYPE_STRING);
g_object_get_property (G_OBJECT (self_contact), "alias", &value);
- mcd_account_set_string_val (self, MC_ACCOUNTS_KEY_ALIAS, &value, NULL);
+ mcd_account_set_string_val (self, MC_ACCOUNTS_KEY_NICKNAME, &value, NULL);
g_value_unset (&value);
}
@@ -4222,7 +4204,7 @@ mcd_account_get_alias (McdAccount *account)
const gchar *account_name = mcd_account_get_unique_name (account);
return mcd_storage_dup_string (priv->storage, account_name,
- MC_ACCOUNTS_KEY_ALIAS);
+ MC_ACCOUNTS_KEY_NICKNAME);
}
static void
@@ -4954,10 +4936,8 @@ _mcd_account_set_has_been_online (McdAccount *account)
g_value_init (&value, G_TYPE_BOOLEAN);
g_value_set_boolean (&value, TRUE);
- mcd_storage_set_value (account->priv->storage,
- account_name,
- MC_ACCOUNTS_KEY_HAS_BEEN_ONLINE,
- &value, FALSE);
+ mcd_storage_set_attribute (account->priv->storage, account_name,
+ MC_ACCOUNTS_KEY_HAS_BEEN_ONLINE, &value);
account->priv->has_been_online = TRUE;
mcd_storage_commit (account->priv->storage, account_name);
mcd_account_changed_property (account, MC_ACCOUNTS_KEY_HAS_BEEN_ONLINE,
diff --git a/src/mcd-misc.c b/src/mcd-misc.c
index c0cc4e13..58b2f667 100644
--- a/src/mcd-misc.c
+++ b/src/mcd-misc.c
@@ -220,3 +220,16 @@ _mcd_chmod_private (const gchar *filename)
return ret;
}
+
+gboolean
+mcd_nullable_variant_equal (GVariant *a,
+ GVariant *b)
+{
+ if (a == b)
+ return TRUE;
+
+ if (a == NULL || b == NULL)
+ return FALSE;
+
+ return g_variant_equal (a, b);
+}
diff --git a/src/mcd-misc.h b/src/mcd-misc.h
index 741a1092..70f95521 100644
--- a/src/mcd-misc.h
+++ b/src/mcd-misc.h
@@ -55,5 +55,7 @@ gboolean mcd_ensure_directory (const gchar *dir, GError **error);
G_GNUC_INTERNAL int _mcd_chmod_private (const gchar *filename);
+gboolean mcd_nullable_variant_equal (GVariant *a, GVariant *b);
+
G_END_DECLS
#endif /* MCD_MISC_H */
diff --git a/src/mcd-storage.c b/src/mcd-storage.c
index 24cb7104..ccbf1cc2 100644
--- a/src/mcd-storage.c
+++ b/src/mcd-storage.c
@@ -26,6 +26,7 @@
#include "mcd-account.h"
#include "mcd-account-config.h"
#include "mcd-debug.h"
+#include "mcd-misc.h"
#include "plugin-loader.h"
#include <string.h>
@@ -45,6 +46,8 @@
# endif
#endif
+#define MAX_KEY_LENGTH (DBUS_MAXIMUM_NAME_LENGTH + 6)
+
static GList *stores = NULL;
static void sort_and_cache_plugins (void);
@@ -63,11 +66,39 @@ 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->keyfile = g_key_file_new ();
- self->secrets = g_key_file_new ();
+ self->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, mcd_storage_account_free);
}
static void
@@ -77,10 +108,8 @@ storage_finalize (GObject *object)
GObjectFinalizeFunc finalize =
G_OBJECT_CLASS (mcd_storage_parent_class)->finalize;
- g_key_file_free (self->keyfile);
- g_key_file_free (self->secrets);
- self->keyfile = NULL;
- self->secrets = NULL;
+ g_hash_table_unref (self->accounts);
+ self->accounts = NULL;
if (finalize != NULL)
finalize (object);
@@ -162,12 +191,213 @@ mcd_storage_new (TpDBusDaemon *dbus_daemon)
}
static gchar *
+mcd_keyfile_escape_variant (GVariant *variant)
+{
+ GValue value = G_VALUE_INIT;
+ gchar *ret;
+
+ dbus_g_value_parse_g_variant (variant, &value);
+
+ if (G_IS_VALUE (&value))
+ {
+ ret = mcd_keyfile_escape_value (&value);
+ g_value_unset (&value);
+ }
+ else
+ {
+ gchar *printed = g_variant_print (variant, TRUE);
+
+ ret = NULL;
+ g_warning ("Unable to translate variant %s", printed);
+ g_free (printed);
+ }
+
+ 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);
- return g_key_file_get_value (self->keyfile, account, key, NULL);
+ 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;
+} known_attributes[] = {
+ /* Please keep this sorted by type, then by name. */
+
+ /* Array of object path */
+ { "ao", MC_ACCOUNTS_KEY_SUPERSEDES },
+
+ /* Array of string */
+ { "as", MC_ACCOUNTS_KEY_URI_SCHEMES },
+
+ /* Booleans */
+ { "b", MC_ACCOUNTS_KEY_ALWAYS_DISPATCH },
+ { "b", MC_ACCOUNTS_KEY_CONNECT_AUTOMATICALLY },
+ { "b", MC_ACCOUNTS_KEY_ENABLED },
+ { "b", MC_ACCOUNTS_KEY_HAS_BEEN_ONLINE },
+ { "b", MC_ACCOUNTS_KEY_HIDDEN },
+
+ /* Strings */
+ { "s", MC_ACCOUNTS_KEY_AUTO_PRESENCE_MESSAGE },
+ { "s", MC_ACCOUNTS_KEY_AUTO_PRESENCE_STATUS },
+ { "s", MC_ACCOUNTS_KEY_AVATAR_MIME },
+ { "s", MC_ACCOUNTS_KEY_AVATAR_TOKEN },
+ { "s", MC_ACCOUNTS_KEY_DISPLAY_NAME },
+ { "s", MC_ACCOUNTS_KEY_ICON },
+ { "s", MC_ACCOUNTS_KEY_MANAGER },
+ { "s", MC_ACCOUNTS_KEY_NICKNAME },
+ { "s", MC_ACCOUNTS_KEY_NORMALIZED_NAME },
+ { "s", MC_ACCOUNTS_KEY_PROTOCOL },
+ { "s", MC_ACCOUNTS_KEY_SERVICE },
+
+ /* Integers */
+ { "u", MC_ACCOUNTS_KEY_AUTO_PRESENCE_TYPE },
+
+ { NULL, NULL }
+};
+
+static const gchar *
+mcd_storage_get_attribute_type (const gchar *attribute)
+{
+ guint i;
+
+ for (i = 0; known_attributes[i].type != NULL; i++)
+ {
+ if (!tp_strdiff (attribute, known_attributes[i].name))
+ return known_attributes[i].type;
+ }
+
+ /* special case for mcd-account-conditions.c */
+ if (g_str_has_prefix (attribute, "condition-"))
+ return "s";
+
+ return NULL;
+}
+
+static gboolean
+mcd_storage_init_value_for_attribute (GValue *value,
+ const gchar *attribute)
+{
+ const gchar *s = mcd_storage_get_attribute_type (attribute);
+
+ if (s == NULL)
+ return FALSE;
+
+ switch (s[0])
+ {
+ case 's':
+ g_value_init (value, G_TYPE_STRING);
+ return TRUE;
+
+ case 'b':
+ g_value_init (value, G_TYPE_BOOLEAN);
+ return TRUE;
+
+ case 'u':
+ /* this seems wrong but it's how we've always done it */
+ g_value_init (value, G_TYPE_INT);
+ return TRUE;
+
+ case 'a':
+ {
+ switch (s[1])
+ {
+ case 'o':
+ g_value_init (value, TP_ARRAY_TYPE_OBJECT_PATH_LIST);
+ return TRUE;
+
+ case 's':
+ g_value_init (value, G_TYPE_STRV);
+ return TRUE;
+ }
+ }
+ break;
+ }
+
+ 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
@@ -177,11 +407,50 @@ set_value (const McpAccountManager *ma,
const gchar *value)
{
McdStorage *self = MCD_STORAGE (ma);
+ McdStorageAccount *sa = ensure_account (self, account);
- if (value != NULL)
- g_key_file_set_value (self->keyfile, account, key, value);
+ 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
- g_key_file_remove_key (self->keyfile, account, key, NULL);
+ {
+ 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
@@ -189,8 +458,27 @@ 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);
- return g_key_file_get_keys (self->keyfile, account, NULL, NULL);
+ 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
@@ -199,8 +487,12 @@ is_secret (const McpAccountManager *ma,
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_key_file_get_boolean (self->secrets, account, key, NULL);
+ return g_hash_table_contains (sa->secrets, key + 6);
}
static void
@@ -208,13 +500,18 @@ 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);
- DEBUG ("flagging %s.%s as secret", account, key);
+ if (!g_str_has_prefix (key, "param-"))
+ return;
- g_key_file_set_boolean (self->secrets, account, key, TRUE);
+ 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
@@ -253,7 +550,7 @@ unique_name (const McpAccountManager *ma,
TP_ACCOUNT_OBJECT_PATH_BASE "%s/%s/%s%u",
esc_manager, esc_protocol, esc_base, i);
- if (!g_key_file_has_group (self->keyfile, path + base_len) &&
+ if (!g_hash_table_contains (self->accounts, path + base_len) &&
dbus_g_connection_lookup_g_object (connection, path) == NULL)
{
gchar *ret = g_strdup (path + base_len);
@@ -413,29 +710,55 @@ GStrv
mcd_storage_dup_accounts (McdStorage *self,
gsize *n)
{
- g_return_val_if_fail (MCD_IS_STORAGE (self), NULL);
+ GPtrArray *ret = g_ptr_array_new ();
+ GHashTableIter iter;
+ gpointer k, v;
+
+ g_hash_table_iter_init (&iter, self->accounts);
- return g_key_file_get_groups (self->keyfile, n);
+ 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_settings:
+ * mcd_storage_dup_attributes:
* @storage: An object implementing the #McdStorage interface
* @account: unique name of the account
- * @n: place for the number of settings to be written to (or %NULL)
+ * @n: place for the number of attributes to be written to (or %NULL)
*
* Returns: a newly allocated GStrv containing the names of all the
- * settings or parameters currently stored for @account. Must be
+ * attributes or parameters currently stored for @account. Must be
* freed by the caller with g_strfreev().
*/
GStrv
-mcd_storage_dup_settings (McdStorage *self,
+mcd_storage_dup_attributes (McdStorage *self,
const gchar *account,
gsize *n)
{
- g_return_val_if_fail (MCD_IS_STORAGE (self), NULL);
+ 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);
- return g_key_file_get_keys (self->keyfile, account, n, NULL);
+ 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);
}
/*
@@ -466,7 +789,7 @@ mcd_storage_get_plugin (McdStorage *self,
{
McpAccountStorage *plugin = store->data;
- if (mcp_account_storage_get (plugin, ma, account, "manager"))
+ if (mcp_account_storage_owns (plugin, ma, account))
owner = plugin;
}
@@ -477,25 +800,27 @@ mcd_storage_get_plugin (McdStorage *self,
* mcd_storage_dup_string:
* @storage: An object implementing the #McdStorage interface
* @account: unique name of the account
- * @key: name of the setting to be retrieved
+ * @attribute: name of the attribute to be retrieved (which must not be a
+ * parameter)
*
* Returns: a newly allocated gchar * which must be freed with g_free().
*/
gchar *
mcd_storage_dup_string (McdStorage *self,
const gchar *account,
- const gchar *key)
+ const gchar *attribute)
{
GValue tmp = G_VALUE_INIT;
gchar *ret;
g_return_val_if_fail (MCD_IS_STORAGE (self), NULL);
g_return_val_if_fail (account != NULL, NULL);
- g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (attribute != NULL, NULL);
+ g_return_val_if_fail (!g_str_has_prefix (attribute, "param-"), NULL);
g_value_init (&tmp, G_TYPE_STRING);
- if (!mcd_storage_get_value (self, account, key, &tmp, NULL))
+ if (!mcd_storage_get_attribute (self, account, attribute, &tmp, NULL))
return NULL;
ret = g_value_dup_string (&tmp);
@@ -503,17 +828,176 @@ mcd_storage_dup_string (McdStorage *self,
return ret;
}
+static gboolean
+mcd_storage_coerce_variant_to_value (GVariant *variant,
+ GValue *value,
+ GError **error)
+{
+ GValue tmp = G_VALUE_INIT;
+ gboolean ret;
+ gchar *escaped;
+
+ dbus_g_value_parse_g_variant (variant, &tmp);
+
+ if (G_VALUE_TYPE (&tmp) == G_VALUE_TYPE (value))
+ {
+ memcpy (value, &tmp, sizeof (tmp));
+ return TRUE;
+ }
+
+ /* This is really pretty stupid but it'll do for now.
+ * FIXME: implement a better similar-type-coercion mechanism than
+ * round-tripping through a GKeyFile. */
+ escaped = mcd_keyfile_escape_value (&tmp);
+ ret = mcd_keyfile_unescape_value (escaped, value, error);
+ g_free (escaped);
+ g_value_unset (&tmp);
+ return ret;
+}
+
/*
- * mcd_storage_get_value:
+ * mcd_storage_get_attribute:
* @storage: An object implementing the #McdStorage interface
* @account: unique name of the account
- * @key: name of the setting to be retrieved
+ * @attribute: name of the attribute to be retrieved, e.g. 'DisplayName'
* @value: location to return the value, initialized to the right #GType
* @error: a place to store any #GError<!-- -->s that occur
*/
gboolean
-mcd_storage_get_value (McdStorage *self,
+mcd_storage_get_attribute (McdStorage *self,
const gchar *account,
+ const gchar *attribute,
+ GValue *value,
+ GError **error)
+{
+ McdStorageAccount *sa;
+ GVariant *variant;
+
+ 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);
+
+ if (sa == 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);
+
+ if (variant == NULL)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
+ "Setting '%s' not stored by account %s", attribute, account);
+ return FALSE;
+ }
+
+ return mcd_storage_coerce_variant_to_value (variant, value, error);
+}
+
+/*
+ * mcd_storage_get_parameter:
+ * @storage: An object implementing the #McdStorage interface
+ * @account: unique name of the account
+ * @parameter: name of the parameter to be retrieved, e.g. 'account'
+ * @value: location to return the value, initialized to the right #GType
+ * @error: a place to store any #GError<!-- -->s that occur
+ */
+gboolean
+mcd_storage_get_parameter (McdStorage *self,
+ const gchar *account,
+ const gchar *parameter,
+ GValue *value,
+ GError **error)
+{
+ McdStorageAccount *sa;
+ const gchar *escaped;
+ GVariant *variant;
+
+ 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 = lookup_account (self, account);
+
+ if (sa == 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);
+
+ /* 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)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
+ "Parameter '%s' not stored by account %s", parameter, account);
+ 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);
+}
+
+/*
+ * @escaped: a keyfile-escaped string
+ * @value: a #GValue initialized with a supported #GType
+ * @error: used to raise an error if %FALSE is returned
+ *
+ * Try to interpret @escaped as a value of the type of @value. If we can,
+ * write the resulting value into @value and return %TRUE.
+ *
+ * Returns: %TRUE if @escaped could be interpreted as a value of that type
+ */
+gboolean
+mcd_keyfile_unescape_value (const gchar *escaped,
+ GValue *value,
+ GError **error)
+{
+ GKeyFile *keyfile;
+ gboolean ret;
+
+ g_return_val_if_fail (escaped != NULL, FALSE);
+ g_return_val_if_fail (G_IS_VALUE (value), FALSE);
+
+ keyfile = g_key_file_new ();
+ g_key_file_set_value (keyfile, "g", "k", escaped);
+ ret = mcd_keyfile_get_value (keyfile, "g", "k", value, error);
+ g_key_file_free (keyfile);
+ return ret;
+}
+
+/*
+ * mcd_keyfile_get_value:
+ * @keyfile: A #GKeyFile
+ * @group: name of a group
+ * @key: name of a key
+ * @value: location to return the value, initialized to the right #GType
+ * @error: a place to store any #GError<!-- -->s that occur
+ */
+gboolean
+mcd_keyfile_get_value (GKeyFile *keyfile,
+ const gchar *group,
const gchar *key,
GValue *value,
GError **error)
@@ -521,8 +1005,9 @@ mcd_storage_get_value (McdStorage *self,
gboolean ret = FALSE;
GType type;
- g_return_val_if_fail (MCD_IS_STORAGE (self), FALSE);
- g_return_val_if_fail (account != NULL, FALSE);
+ g_return_val_if_fail (keyfile != NULL, FALSE);
+ g_return_val_if_fail (group != NULL, FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
g_return_val_if_fail (G_IS_VALUE (value), FALSE);
type = G_VALUE_TYPE (value);
@@ -531,7 +1016,7 @@ mcd_storage_get_value (McdStorage *self,
{
case G_TYPE_STRING:
{
- gchar *v_string = g_key_file_get_string (self->keyfile, account,
+ gchar *v_string = g_key_file_get_string (keyfile, group,
key, error);
if (v_string != NULL)
@@ -546,7 +1031,7 @@ mcd_storage_get_value (McdStorage *self,
case G_TYPE_INT:
{
GError *e = NULL;
- gint v_int = g_key_file_get_integer (self->keyfile, account,
+ gint v_int = g_key_file_get_integer (keyfile, group,
key, &e);
if (e != NULL)
@@ -564,7 +1049,7 @@ mcd_storage_get_value (McdStorage *self,
case G_TYPE_INT64:
{
GError *e = NULL;
- gint64 v_int = tp_g_key_file_get_int64 (self->keyfile, account,
+ gint64 v_int = tp_g_key_file_get_int64 (keyfile, group,
key, &e);
if (e != NULL)
@@ -582,7 +1067,7 @@ mcd_storage_get_value (McdStorage *self,
case G_TYPE_UINT:
{
GError *e = NULL;
- guint64 v_uint = tp_g_key_file_get_uint64 (self->keyfile, account,
+ guint64 v_uint = tp_g_key_file_get_uint64 (keyfile, group,
key, &e);
if (e != NULL)
@@ -607,7 +1092,7 @@ mcd_storage_get_value (McdStorage *self,
case G_TYPE_UCHAR:
{
GError *e = NULL;
- gint v_int = g_key_file_get_integer (self->keyfile, account,
+ gint v_int = g_key_file_get_integer (keyfile, group,
key, &e);
if (e != NULL)
@@ -632,7 +1117,7 @@ mcd_storage_get_value (McdStorage *self,
case G_TYPE_UINT64:
{
GError *e = NULL;
- guint64 v_uint = tp_g_key_file_get_uint64 (self->keyfile, account,
+ guint64 v_uint = tp_g_key_file_get_uint64 (keyfile, group,
key, &e);
if (e != NULL)
@@ -650,7 +1135,7 @@ mcd_storage_get_value (McdStorage *self,
case G_TYPE_BOOLEAN:
{
GError *e = NULL;
- gboolean v_bool = g_key_file_get_boolean (self->keyfile, account,
+ gboolean v_bool = g_key_file_get_boolean (keyfile, group,
key, &e);
if (e != NULL)
@@ -668,7 +1153,7 @@ mcd_storage_get_value (McdStorage *self,
case G_TYPE_DOUBLE:
{
GError *e = NULL;
- gdouble v_double = g_key_file_get_double (self->keyfile, account,
+ gdouble v_double = g_key_file_get_double (keyfile, group,
key, &e);
if (e != NULL)
@@ -686,7 +1171,7 @@ mcd_storage_get_value (McdStorage *self,
default:
if (type == G_TYPE_STRV)
{
- gchar **v = g_key_file_get_string_list (self->keyfile, account,
+ gchar **v = g_key_file_get_string_list (keyfile, group,
key, NULL, error);
if (v != NULL)
@@ -697,7 +1182,7 @@ mcd_storage_get_value (McdStorage *self,
}
else if (type == DBUS_TYPE_G_OBJECT_PATH)
{
- gchar *v_string = g_key_file_get_string (self->keyfile, account,
+ gchar *v_string = g_key_file_get_string (keyfile, group,
key, error);
if (v_string == NULL)
@@ -719,7 +1204,7 @@ mcd_storage_get_value (McdStorage *self,
}
else if (type == TP_ARRAY_TYPE_OBJECT_PATH_LIST)
{
- gchar **v = g_key_file_get_string_list (self->keyfile, account,
+ gchar **v = g_key_file_get_string_list (keyfile, group,
key, NULL, error);
if (v != NULL)
@@ -733,7 +1218,7 @@ mcd_storage_get_value (McdStorage *self,
{
g_set_error (error, MCD_ACCOUNT_ERROR,
MCD_ACCOUNT_ERROR_GET_PARAMETER,
- "Invalid object path %s stored in account", *iter);
+ "Invalid object path %s stored in keyfile", *iter);
g_strfreev (v);
v = NULL;
break;
@@ -757,9 +1242,9 @@ mcd_storage_get_value (McdStorage *self,
else
{
gchar *message =
- g_strdup_printf ("cannot get property %s on account %s, "
+ g_strdup_printf ("cannot get key %s from group %s: "
"unknown type %s",
- key, account, g_type_name (type));
+ key, group, g_type_name (type));
g_warning ("%s: %s", G_STRFUNC, message);
g_set_error (error, MCD_ACCOUNT_ERROR,
@@ -776,24 +1261,25 @@ mcd_storage_get_value (McdStorage *self,
* mcd_storage_get_boolean:
* @storage: An object implementing the #McdStorage interface
* @account: unique name of the account
- * @key: name of the setting to be retrieved
+ * @key: name of the attribute to be retrieved
*
* Returns: a #gboolean. Unset/unparseable values are returned as %FALSE
*/
gboolean
mcd_storage_get_boolean (McdStorage *self,
const gchar *account,
- const gchar *key)
+ const gchar *attribute)
{
GValue tmp = G_VALUE_INIT;
g_return_val_if_fail (MCD_IS_STORAGE (self), FALSE);
g_return_val_if_fail (account != NULL, FALSE);
- g_return_val_if_fail (key != NULL, FALSE);
+ g_return_val_if_fail (attribute != NULL, FALSE);
+ g_return_val_if_fail (!g_str_has_prefix (attribute, "param-"), FALSE);
g_value_init (&tmp, G_TYPE_BOOLEAN);
- if (!mcd_storage_get_value (self, account, key, &tmp, NULL))
+ if (!mcd_storage_get_attribute (self, account, attribute, &tmp, NULL))
return FALSE;
return g_value_get_boolean (&tmp);
@@ -803,24 +1289,25 @@ mcd_storage_get_boolean (McdStorage *self,
* mcd_storage_get_integer:
* @storage: An object implementing the #McdStorage interface
* @account: unique name of the account
- * @key: name of the setting to be retrieved
+ * @attribute: name of the attribute to be retrieved
*
* Returns: a #gint. Unset or non-numeric values are returned as 0
*/
gint
mcd_storage_get_integer (McdStorage *self,
const gchar *account,
- const gchar *key)
+ const gchar *attribute)
{
GValue tmp = G_VALUE_INIT;
g_return_val_if_fail (MCD_IS_STORAGE (self), 0);
g_return_val_if_fail (account != NULL, 0);
- g_return_val_if_fail (key != NULL, 0);
+ g_return_val_if_fail (attribute != NULL, 0);
+ g_return_val_if_fail (!g_str_has_prefix (attribute, "param-"), 0);
g_value_init (&tmp, G_TYPE_INT);
- if (!mcd_storage_get_value (self, account, key, &tmp, NULL))
+ if (!mcd_storage_get_attribute (self, account, attribute, &tmp, NULL))
return FALSE;
return g_value_get_int (&tmp);
@@ -830,24 +1317,19 @@ static void
update_storage (McdStorage *self,
const gchar *account,
const gchar *key,
+ const gchar *escaped,
gboolean secret)
{
GList *store;
gboolean done = FALSE;
McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self);
- gchar *val = NULL;
if (secret)
mcd_storage_make_secret (self, account, key);
- /* don't unescape the value here, we're flushing it to storage *
- * everywhere else should handle escaping on the way in and unescaping *
- * on the way out of the keyfile, but not here: */
- val = g_key_file_get_value (self->keyfile, account, key, NULL);
-
/* we're deleting, which is unconditional, no need to check if anyone *
* claims this setting for themselves */
- if (val == NULL)
+ if (escaped == NULL)
done = TRUE;
for (store = stores; store != NULL; store = g_list_next (store))
@@ -862,23 +1344,19 @@ update_storage (McdStorage *self,
}
else
{
- done = mcp_account_storage_set (plugin, ma, account, key, val);
+ done = mcp_account_storage_set (plugin, ma, account, key, escaped);
DEBUG ("MCP:%s -> %s %s.%s",
pn, done ? "store" : "ignore", account, key);
}
}
-
- g_free (val);
}
/*
* mcd_storage_set_string:
* @storage: An object implementing the #McdStorage interface
* @account: the unique name of an account
- * @key: the key (name) of the parameter or setting
+ * @key: the name of the attribute
* @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) to the
* internal cache.
@@ -892,19 +1370,19 @@ update_storage (McdStorage *self,
gboolean
mcd_storage_set_string (McdStorage *self,
const gchar *account,
- const gchar *key,
- const gchar *val,
- gboolean secret)
+ const gchar *attribute,
+ const gchar *val)
{
gboolean updated;
g_return_val_if_fail (MCD_IS_STORAGE (self), FALSE);
g_return_val_if_fail (account != NULL, FALSE);
- g_return_val_if_fail (key != NULL, FALSE);
+ g_return_val_if_fail (attribute != NULL, FALSE);
+ g_return_val_if_fail (!g_str_has_prefix (attribute, "param-"), FALSE);
if (val == NULL)
{
- updated = mcd_storage_set_value (self, account, key, NULL, secret);
+ updated = mcd_storage_set_attribute (self, account, attribute, NULL);
}
else
{
@@ -912,7 +1390,7 @@ mcd_storage_set_string (McdStorage *self,
g_value_init (&tmp, G_TYPE_STRING);
g_value_set_string (&tmp, val);
- updated = mcd_storage_set_value (self, account, key, &tmp, secret);
+ updated = mcd_storage_set_attribute (self, account, attribute, &tmp);
g_value_unset (&tmp);
}
@@ -920,15 +1398,81 @@ mcd_storage_set_string (McdStorage *self,
}
/*
- * mcd_storage_set_value:
+ * mcd_storage_set_attribute:
* @storage: An object implementing the #McdStorage interface
* @account: the unique name of an account
- * @key: the key (name) of the parameter or setting
+ * @attribute: the name of the attribute, e.g. "DisplayName"
+ * @value: the value to be stored (or %NULL to erase it)
+ *
+ * Copies and stores the supplied @value (or removes it if %NULL) in the
+ * internal cache.
+ *
+ * Returns: a #gboolean indicating whether the cache actually required an
+ * update (so that the caller can decide whether to request a commit to
+ * long term storage or not). %TRUE indicates the cache was updated and
+ * may not be in sync with the store any longer, %FALSE indicates we already
+ * held the value supplied.
+ */
+gboolean
+mcd_storage_set_attribute (McdStorage *self,
+ const gchar *account,
+ const gchar *attribute,
+ const GValue *value)
+{
+ McdStorageAccount *sa;
+ GVariant *old_v;
+ GVariant *new_v;
+ gboolean updated = FALSE;
+
+ 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);
+
+ 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, escaped, FALSE);
+ g_free (escaped);
+ updated = TRUE;
+ }
+
+ tp_clear_pointer (&new_v, g_variant_unref);
+ return updated;
+}
+
+/*
+ * mcd_storage_set_parameter:
+ * @storage: An object implementing the #McdStorage interface
+ * @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) to the
+ * Copies and stores the supplied @value (or removes it if %NULL) in the
* internal cache.
*
* Returns: a #gboolean indicating whether the cache actually required an
@@ -938,40 +1482,138 @@ mcd_storage_set_string (McdStorage *self,
* held the value supplied.
*/
gboolean
-mcd_storage_set_value (McdStorage *self,
- const gchar *name,
- const gchar *key,
+mcd_storage_set_parameter (McdStorage *self,
+ const gchar *account,
+ const gchar *parameter,
const GValue *value,
gboolean secret)
{
+ GVariant *old_v;
+ GVariant *new_v = NULL;
+ const gchar *old_escaped;
+ gchar *new_escaped = NULL;
+ McdStorageAccount *sa;
+ gboolean updated = FALSE;
+
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);
+
+ 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_escaped, secret);
+ return TRUE;
+ }
+
+ 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
+ *
+ * Escape the contents of @value to go in a #GKeyFile. Return the
+ * value that would go in the keyfile.
+ *
+ * For instance, for a boolean value TRUE this would return "true",
+ * and for a string containing one space, it would return "\s".
+ */
+gchar *
+mcd_keyfile_escape_value (const GValue *value)
+{
+ GKeyFile *keyfile;
+ gchar *ret;
+
+ g_return_val_if_fail (G_IS_VALUE (value), NULL);
+
+ keyfile = g_key_file_new ();
+ mcd_keyfile_set_value (keyfile, "g", "k", value);
+ ret = g_key_file_get_value (keyfile, "g", "k", NULL);
+ g_key_file_free (keyfile);
+ return ret;
+}
+
+/*
+ * mcd_keyfile_set_value:
+ * @keyfile: a keyfile
+ * @name: the name of a group
+ * @key: the key in the group
+ * @value: the value to be stored (or %NULL to erase it)
+ *
+ * Copies and stores the supplied @value (or removes it if %NULL) to the
+ * internal cache.
+ *
+ * Returns: a #gboolean indicating whether the cache actually required an
+ * update (so that the caller can decide whether to request a commit to
+ * long term storage or not). %TRUE indicates the cache was updated and
+ * may not be in sync with the store any longer, %FALSE indicates we already
+ * held the value supplied.
+ */
+gboolean
+mcd_keyfile_set_value (GKeyFile *keyfile,
+ const gchar *name,
+ const gchar *key,
+ const GValue *value)
+{
g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (key != NULL, FALSE);
if (value == NULL)
{
- gchar *old = g_key_file_get_value (self->keyfile, name, key, NULL);
+ gchar *old = g_key_file_get_value (keyfile, name, key, NULL);
gboolean updated = (old != NULL);
g_free (old);
- g_key_file_remove_key (self->keyfile, name, key, NULL);
-
- if (updated)
- update_storage (self, name, key, secret);
-
+ g_key_file_remove_key (keyfile, name, key, NULL);
return updated;
}
else
{
gboolean updated = FALSE;
- gchar *old = g_key_file_get_value (self->keyfile, name, key, NULL);
+ gchar *old = g_key_file_get_value (keyfile, name, key, NULL);
gchar *new = NULL;
gchar *buf = NULL;
switch (G_VALUE_TYPE (value))
{
case G_TYPE_STRING:
- g_key_file_set_string (self->keyfile, name, key,
+ g_key_file_set_string (keyfile, name, key,
g_value_get_string (value));
break;
@@ -980,12 +1622,12 @@ mcd_storage_set_value (McdStorage *self,
break;
case G_TYPE_INT:
- g_key_file_set_integer (self->keyfile, name, key,
+ g_key_file_set_integer (keyfile, name, key,
g_value_get_int (value));
break;
case G_TYPE_BOOLEAN:
- g_key_file_set_boolean (self->keyfile, name, key,
+ g_key_file_set_boolean (keyfile, name, key,
g_value_get_boolean (value));
break;
@@ -1004,7 +1646,7 @@ mcd_storage_set_value (McdStorage *self,
break;
case G_TYPE_DOUBLE:
- g_key_file_set_double (self->keyfile, name, key,
+ g_key_file_set_double (keyfile, name, key,
g_value_get_double (value));
break;
@@ -1013,20 +1655,20 @@ mcd_storage_set_value (McdStorage *self,
{
gchar **strings = g_value_get_boxed (value);
- g_key_file_set_string_list (self->keyfile, name, key,
+ g_key_file_set_string_list (keyfile, name, key,
(const gchar **)strings,
g_strv_length (strings));
}
else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH))
{
- g_key_file_set_string (self->keyfile, name, key,
+ g_key_file_set_string (keyfile, name, key,
g_value_get_boxed (value));
}
else if (G_VALUE_HOLDS (value, TP_ARRAY_TYPE_OBJECT_PATH_LIST))
{
GPtrArray *arr = g_value_get_boxed (value);
- g_key_file_set_string_list (self->keyfile, name, key,
+ g_key_file_set_string_list (keyfile, name, key,
(const gchar * const *) arr->pdata, arr->len);
}
else
@@ -1038,15 +1680,12 @@ mcd_storage_set_value (McdStorage *self,
}
if (buf != NULL)
- g_key_file_set_string (self->keyfile, name, key, buf);
+ g_key_file_set_string (keyfile, name, key, buf);
- new = g_key_file_get_value (self->keyfile, name, key, NULL);
+ new = g_key_file_get_value (keyfile, name, key, NULL);
if (tp_strdiff (old, new))
- {
- update_storage (self, name, key, secret);
- updated = TRUE;
- }
+ updated = TRUE;
g_free (new);
g_free (buf);
@@ -1187,7 +1826,7 @@ mcd_storage_delete_account (McdStorage *self,
g_return_if_fail (MCD_IS_STORAGE (self));
g_return_if_fail (account != NULL);
- g_key_file_remove_group (self->keyfile, account, NULL);
+ g_hash_table_remove (self->accounts, account);
for (store = stores; store != NULL; store = g_list_next (store))
{
@@ -1235,11 +1874,9 @@ mcd_storage_commit (McdStorage *self, const gchar *account)
* mcd_storage_set_strv:
* @storage: An object implementing the #McdStorage interface
* @account: the unique name of an account
- * @key: the key (name) of the parameter or setting
+ * @attribute: the name of the attribute
* @strv: the string vector to be stored (where %NULL is treated as equivalent
* to an empty vector)
- * @secret: whether the value is confidential (might get stored in the
- * keyring, for example)
*
* Copies and stores the supplied string vector to the internal cache.
*
@@ -1252,9 +1889,8 @@ mcd_storage_commit (McdStorage *self, const gchar *account)
gboolean
mcd_storage_set_strv (McdStorage *storage,
const gchar *account,
- const gchar *key,
- const gchar * const *strv,
- gboolean secret)
+ const gchar *attribute,
+ const gchar * const *strv)
{
GValue v = G_VALUE_INIT;
static const gchar * const *empty = { NULL };
@@ -1262,11 +1898,12 @@ mcd_storage_set_strv (McdStorage *storage,
g_return_val_if_fail (MCD_IS_STORAGE (storage), FALSE);
g_return_val_if_fail (account != NULL, FALSE);
- g_return_val_if_fail (key != NULL, FALSE);
+ g_return_val_if_fail (attribute != NULL, FALSE);
+ g_return_val_if_fail (!g_str_has_prefix (attribute, "param-"), FALSE);
g_value_init (&v, G_TYPE_STRV);
g_value_set_static_boxed (&v, strv == NULL ? empty : strv);
- ret = mcd_storage_set_value (storage, account, key, &v, secret);
+ ret = mcd_storage_set_attribute (storage, account, attribute, &v);
g_value_unset (&v);
return ret;
}
@@ -1299,6 +1936,9 @@ plugin_iface_init (McpAccountManagerIface *iface,
iface->make_secret = make_secret;
iface->unique_name = unique_name;
iface->list_keys = list_keys;
+ iface->escape_value_for_keyfile = mcpa_escape_value_for_keyfile;
+ iface->unescape_value_from_keyfile = mcpa_unescape_value_from_keyfile;
+ iface->init_value_for_attribute = mcpa_init_value_for_attribute;
}
gboolean
diff --git a/src/mcd-storage.h b/src/mcd-storage.h
index 619e7b69..a856b290 100644
--- a/src/mcd-storage.h
+++ b/src/mcd-storage.h
@@ -1,5 +1,5 @@
/* Mission Control storage API - interface which provides access to account
- * parameter/setting storage
+ * parameter/attribute storage
*
* Copyright © 2010 Nokia Corporation
* Copyright © 2010 Collabora Ltd.
@@ -30,8 +30,8 @@ G_BEGIN_DECLS
typedef struct {
GObject parent;
TpDBusDaemon *dbusd;
- GKeyFile *keyfile;
- GKeyFile *secrets;
+ /* owned string => owned McdStorageAccount */
+ GHashTable *accounts;
} McdStorage;
typedef struct _McdStorageClass McdStorageClass;
@@ -66,25 +66,28 @@ void mcd_storage_load (McdStorage *storage);
GStrv mcd_storage_dup_accounts (McdStorage *storage, gsize *n);
-GStrv mcd_storage_dup_settings (McdStorage *storage,
+GStrv mcd_storage_dup_attributes (McdStorage *storage,
const gchar *account,
gsize *n);
gboolean mcd_storage_set_string (McdStorage *storage,
const gchar *account,
- const gchar *key,
- const gchar *value,
- gboolean secret);
+ const gchar *attribute,
+ const gchar *value);
gboolean mcd_storage_set_strv (McdStorage *storage,
const gchar *account,
- const gchar *key,
- const gchar * const *strv,
- gboolean secret);
+ const gchar *attribute,
+ const gchar * const *strv);
-gboolean mcd_storage_set_value (McdStorage *storage,
+gboolean mcd_storage_set_attribute (McdStorage *storage,
const gchar *account,
- const gchar *key,
+ const gchar *attribute,
+ const GValue *value);
+
+gboolean mcd_storage_set_parameter (McdStorage *storage,
+ const gchar *account,
+ const gchar *parameter,
const GValue *value,
gboolean secret);
@@ -101,21 +104,27 @@ void mcd_storage_commit (McdStorage *storage, const gchar *account);
gchar *mcd_storage_dup_string (McdStorage *storage,
const gchar *account,
- const gchar *key);
+ const gchar *attribute);
-gboolean mcd_storage_get_value (McdStorage *storage,
+gboolean mcd_storage_get_attribute (McdStorage *storage,
const gchar *account,
- const gchar *key,
+ const gchar *attribute,
+ GValue *value,
+ GError **error);
+
+gboolean mcd_storage_get_parameter (McdStorage *storage,
+ const gchar *account,
+ const gchar *parameter,
GValue *value,
GError **error);
gboolean mcd_storage_get_boolean (McdStorage *storage,
const gchar *account,
- const gchar *key);
+ const gchar *attribute);
gint mcd_storage_get_integer (McdStorage *storage,
const gchar *account,
- const gchar *key);
+ const gchar *attribute);
McpAccountStorage * mcd_storage_get_plugin (McdStorage *storage,
const gchar *account);
@@ -126,6 +135,21 @@ gboolean mcd_storage_add_account_from_plugin (McdStorage *storage,
McpAccountStorage *plugin,
const gchar *account);
+gboolean mcd_keyfile_get_value (GKeyFile *keyfile,
+ const gchar *group,
+ const gchar *key,
+ GValue *value,
+ GError **error);
+gboolean mcd_keyfile_set_value (GKeyFile *keyfile,
+ const gchar *name,
+ const gchar *key,
+ const GValue *value);
+
+gchar *mcd_keyfile_escape_value (const GValue *value);
+gboolean mcd_keyfile_unescape_value (const gchar *escaped,
+ GValue *value,
+ GError **error);
+
G_END_DECLS
#endif /* MCD_STORAGE_H */