diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-02-13 14:13:42 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-02-13 14:13:42 +0000 |
commit | 5aeddb8e0a314780585af7b8f19896a2be9815d4 (patch) | |
tree | e989c6187a40d59a6f6969b68e161575db574b83 | |
parent | 128ceb7d37ff5847a9e79f2bafa6127ae97f585b (diff) | |
parent | 3975989913b12fa1488d00085d8cdb84e5b3f46d (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.ac | 4 | ||||
-rw-r--r-- | mission-control-plugins/account-storage.c | 47 | ||||
-rw-r--r-- | mission-control-plugins/account-storage.h | 8 | ||||
-rw-r--r-- | mission-control-plugins/account.c | 84 | ||||
-rw-r--r-- | mission-control-plugins/account.h | 15 | ||||
-rw-r--r-- | mission-control-plugins/implementation.h | 12 | ||||
-rw-r--r-- | src/mcd-account-addressing.c | 12 | ||||
-rw-r--r-- | src/mcd-account-conditions.c | 9 | ||||
-rw-r--r-- | src/mcd-account-config.h | 46 | ||||
-rw-r--r-- | src/mcd-account-manager.c | 7 | ||||
-rw-r--r-- | src/mcd-account.c | 110 | ||||
-rw-r--r-- | src/mcd-misc.c | 13 | ||||
-rw-r--r-- | src/mcd-misc.h | 2 | ||||
-rw-r--r-- | src/mcd-storage.c | 858 | ||||
-rw-r--r-- | src/mcd-storage.h | 58 |
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 */ |