diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2010-09-14 16:00:12 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2010-09-14 16:00:12 +0100 |
commit | 85e35b0b8e4501ac4eb35fb2fc210eedf0282e3d (patch) | |
tree | 8f9b4c1bb6eec592c322098cf4f919bc67da0ac0 | |
parent | 3116079d37cd389b10525a0f9d799e7fadb16e60 (diff) | |
parent | 9ac2c09945c69c32ca4a6e15a30048c58add2782 (diff) | |
download | telepathy-mission-control-85e35b0b8e4501ac4eb35fb2fc210eedf0282e3d.tar.gz |
Merge branch 'master' into storage-tests
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/mcd-account-compat.c | 101 | ||||
-rw-r--r-- | src/mcd-account-conditions.c | 57 | ||||
-rw-r--r-- | src/mcd-account-manager-query.c | 82 | ||||
-rw-r--r-- | src/mcd-account-manager-sso.c | 3 | ||||
-rw-r--r-- | src/mcd-account-manager.c | 481 | ||||
-rw-r--r-- | src/mcd-account-manager.h | 5 | ||||
-rw-r--r-- | src/mcd-account-priv.h | 8 | ||||
-rw-r--r-- | src/mcd-account-requests.c | 4 | ||||
-rw-r--r-- | src/mcd-account.c | 688 | ||||
-rw-r--r-- | src/mcd-account.h | 3 | ||||
-rw-r--r-- | src/mcd-storage-priv.h | 35 | ||||
-rw-r--r-- | src/mcd-storage.c | 388 | ||||
-rw-r--r-- | src/mcd-storage.h | 151 | ||||
-rw-r--r-- | src/plugin-account.c | 597 | ||||
-rw-r--r-- | src/plugin-account.h | 11 |
16 files changed, 1634 insertions, 983 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 2ec922e5..0b75e728 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -186,6 +186,9 @@ libmcd_convenience_la_SOURCES = \ mcd-transport.c \ mcd-provisioning.c \ mcd-provisioning-factory.c \ + mcd-storage.c \ + mcd-storage.h \ + mcd-storage-priv.h \ plugin-dispatch-operation.c \ plugin-dispatch-operation.h \ plugin-loader.c \ diff --git a/src/mcd-account-compat.c b/src/mcd-account-compat.c index 77ab5245..3fe611c6 100644 --- a/src/mcd-account-compat.c +++ b/src/mcd-account-compat.c @@ -74,8 +74,10 @@ set_profile (TpSvcDBusProperties *self, const gchar *name, const GValue *value, GError **error) { McdAccount *account = MCD_ACCOUNT (self); - const gchar *string, *unique_name; - GKeyFile *keyfile; + const gchar *string; + McdStorage *storage; + const GValue *set; + const gchar *account_name; if (!G_VALUE_HOLDS_STRING (value)) { @@ -88,18 +90,17 @@ set_profile (TpSvcDBusProperties *self, const gchar *name, /* FIXME: should we reject profile changes after account creation? */ /* FIXME: some sort of validation beyond just the type? */ - keyfile = _mcd_account_get_keyfile (account); - unique_name = mcd_account_get_unique_name (account); + account_name = mcd_account_get_unique_name (account); + storage = _mcd_account_get_storage (account); string = g_value_get_string (value); + if (string && string[0] != 0) - g_key_file_set_string (keyfile, unique_name, - name, string); + set = value; else - { - g_key_file_remove_key (keyfile, unique_name, - name, NULL); - } - _mcd_account_write_conf (account); + set = NULL; + + mcd_storage_set_value (storage, account_name, name, set, FALSE); + mcd_storage_commit (storage, account_name); g_signal_emit (account, _mcd_account_signal_profile_set, 0); @@ -110,14 +111,10 @@ static void get_profile (TpSvcDBusProperties *self, const gchar *name, GValue *value) { McdAccount *account = MCD_ACCOUNT (self); - const gchar *unique_name; - GKeyFile *keyfile; - gchar *string; + McdStorage *storage = _mcd_account_get_storage (account); + const gchar *account_name = mcd_account_get_unique_name (account); + gchar *string = mcd_storage_dup_string (storage, account_name, name); - keyfile = _mcd_account_get_keyfile (account); - unique_name = mcd_account_get_unique_name (account); - string = g_key_file_get_string (keyfile, unique_name, - name, NULL); g_value_init (value, G_TYPE_STRING); g_value_take_string (value, string); } @@ -138,8 +135,10 @@ set_secondary_vcard_fields (TpSvcDBusProperties *self, const gchar *name, const GValue *value, GError **error) { McdAccount *account = MCD_ACCOUNT (self); - const gchar *unique_name, **fields, **field; - GKeyFile *keyfile; + McdStorage *storage = _mcd_account_get_storage (account); + const gchar *account_name = mcd_account_get_unique_name (account); + GStrv fields; + const GValue *set = NULL; /* FIXME: some sort of validation beyond just the type? */ @@ -151,25 +150,16 @@ set_secondary_vcard_fields (TpSvcDBusProperties *self, const gchar *name, return FALSE; } - keyfile = _mcd_account_get_keyfile (account); - unique_name = mcd_account_get_unique_name (account); fields = g_value_get_boxed (value); - if (fields) - { - gsize len; - for (field = fields, len = 0; *field; field++, len++); - g_key_file_set_string_list (keyfile, unique_name, - name, fields, len); - } - else - { - g_key_file_remove_key (keyfile, unique_name, - name, NULL); - } - _mcd_account_write_conf (account); + if (fields != NULL) + set = value; + + mcd_storage_set_value (storage, account_name, name, set, FALSE); + mcd_storage_commit (storage, account_name); emit_compat_property_changed (account, name, value); + return TRUE; } @@ -178,16 +168,26 @@ get_secondary_vcard_fields (TpSvcDBusProperties *self, const gchar *name, GValue *value) { McdAccount *account = MCD_ACCOUNT (self); - GKeyFile *keyfile; - const gchar *unique_name; - gchar **fields; - - keyfile = _mcd_account_get_keyfile (account); - unique_name = mcd_account_get_unique_name (account); - fields = g_key_file_get_string_list (keyfile, unique_name, - name, NULL, NULL); + McdStorage *storage = _mcd_account_get_storage (account); + const gchar *account_name = mcd_account_get_unique_name (account); + GValue *fetched; + g_value_init (value, G_TYPE_STRV); - g_value_take_boxed (value, fields); + fetched = + mcd_storage_dup_value (storage, account_name, name, G_TYPE_STRV, NULL); + + if (fetched != NULL) + { + GStrv fields = g_value_get_boxed (fetched); + + g_value_take_boxed (value, fields); + g_slice_free (GValue, fetched); + fetched = NULL; + } + else + { + g_value_take_boxed (value, NULL); + } } @@ -225,20 +225,19 @@ account_compat_iface_init (McSvcAccountInterfaceCompatClass *iface, McProfile * mcd_account_compat_get_mc_profile (McdAccount *account) { - const gchar *unique_name; - GKeyFile *keyfile; gchar *profile_name; McProfile *profile = NULL; + McdStorage *storage = _mcd_account_get_storage (account); + const gchar *account_name = mcd_account_get_unique_name (account); - keyfile = _mcd_account_get_keyfile (account); - unique_name = mcd_account_get_unique_name (account); - profile_name = g_key_file_get_string (keyfile, unique_name, - "Profile", NULL); - if (profile_name) + profile_name = mcd_storage_dup_string (storage, account_name, "Profile"); + + if (profile_name != NULL) { profile = mc_profile_lookup (profile_name); g_free (profile_name); } + return profile; } diff --git a/src/mcd-account-conditions.c b/src/mcd-account-conditions.c index e8cd4e7e..eb647923 100644 --- a/src/mcd-account-conditions.c +++ b/src/mcd-account-conditions.c @@ -45,16 +45,15 @@ static void store_condition (gpointer key, gpointer value, gpointer userdata) { - McdAccount *account = userdata; + McdAccount *account = MCD_ACCOUNT (userdata); + McdStorage *storage = _mcd_account_get_storage (account); + const gchar *account_name = mcd_account_get_unique_name (account); const gchar *name = key, *condition = value; - const gchar *unique_name; gchar condition_key[256]; - GKeyFile *keyfile; - keyfile = _mcd_account_get_keyfile (account); - unique_name = mcd_account_get_unique_name (account); g_snprintf (condition_key, sizeof (condition_key), "condition-%s", name); - g_key_file_set_string (keyfile, unique_name, condition_key, condition); + mcd_storage_set_string (storage, account_name, condition_key, condition, + FALSE); } static gboolean @@ -62,8 +61,8 @@ set_condition (TpSvcDBusProperties *self, const gchar *name, const GValue *value, GError **error) { McdAccount *account = MCD_ACCOUNT (self); - const gchar *unique_name; - GKeyFile *keyfile; + McdStorage *storage = _mcd_account_get_storage (account); + const gchar *account_name = mcd_account_get_unique_name (account); gchar **keys, **key; GHashTable *conditions; @@ -77,31 +76,33 @@ set_condition (TpSvcDBusProperties *self, const gchar *name, return FALSE; } - unique_name = mcd_account_get_unique_name (account); - conditions = g_value_get_boxed (value); - if (_mcd_account_get_always_on (account)) { g_set_error (error, TP_ERRORS, TP_ERROR_PERMISSION_DENIED, "Account %s conditions cannot be changed", - unique_name); + mcd_account_get_unique_name (account)); return FALSE; } - keyfile = _mcd_account_get_keyfile (account); + conditions = g_value_get_boxed (value); + /* first, delete existing conditions */ - keys = g_key_file_get_keys (keyfile, unique_name, NULL, NULL); + keys = mcd_storage_dup_settings (storage, account_name, NULL); + for (key = keys; *key != NULL; key++) { - if (strncmp (*key, "condition-", 10) != 0) continue; - g_key_file_remove_key (keyfile, unique_name, - *key, NULL); + if (strncmp (*key, "condition-", 10) != 0) + continue; + + mcd_storage_set_value (storage, account_name, *key, NULL, FALSE); } + g_strfreev (keys); g_hash_table_foreach (conditions, store_condition, account); - _mcd_account_write_conf (account); + mcd_storage_commit (storage, account_name); + return TRUE; } @@ -130,24 +131,28 @@ account_conditions_iface_init (McSvcAccountInterfaceConditionsClass *iface, GHashTable *mcd_account_get_conditions (McdAccount *account) { - const gchar *unique_name; - GKeyFile *keyfile; gchar **keys, **key, *condition; GHashTable *conditions; + McdStorage *storage = _mcd_account_get_storage (account); + const gchar *account_name = mcd_account_get_unique_name (account); - keyfile = _mcd_account_get_keyfile (account); - unique_name = mcd_account_get_unique_name (account); conditions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - keys = g_key_file_get_keys (keyfile, unique_name, NULL, NULL); + + keys = mcd_storage_dup_settings (storage, account_name, NULL); + for (key = keys; *key != NULL; key++) { - if (strncmp (*key, "condition-", 10) != 0) continue; - condition = g_key_file_get_string (keyfile, unique_name, *key, NULL); + if (strncmp (*key, "condition-", 10) != 0) + continue; + + condition = mcd_storage_dup_string (storage, account_name, *key); DEBUG ("Condition: %s = %s", *key, condition); - g_hash_table_insert (conditions, g_strdup (*key + 10), condition); + g_hash_table_insert (conditions, g_strdup (*key + 10), condition); } + g_strfreev (keys); + return conditions; } diff --git a/src/mcd-account-manager-query.c b/src/mcd-account-manager-query.c index 9e37d64f..4ec82171 100644 --- a/src/mcd-account-manager-query.c +++ b/src/mcd-account-manager-query.c @@ -94,46 +94,56 @@ static gboolean match_account_parameter (McdAccount *account, const gchar *name, const GValue *value) { - const gchar *unique_name; - GKeyFile *keyfile; gboolean match = FALSE; + McdStorage *storage = _mcd_account_get_storage (account); + const gchar *account_name = mcd_account_get_unique_name (account); + GType vtype = G_VALUE_TYPE (value); - unique_name = mcd_account_get_unique_name (account); - keyfile = _mcd_account_get_keyfile (account); - if (g_key_file_has_key (keyfile, unique_name, name, NULL)) + if (mcd_storage_has_value (storage, account_name, name)) { - const gchar *value_str; - gchar *conf_value_str; - gint conf_value_int, value_int; - gboolean conf_value_bool, value_bool; - switch (G_VALUE_TYPE (value)) - { - case G_TYPE_STRING: - conf_value_str = - g_key_file_get_string (keyfile, unique_name, name, - NULL); - value_str = g_value_get_string (value); - if (strcmp (conf_value_str, value_str) == 0) match = TRUE; - g_free (conf_value_str); - break; - case G_TYPE_UINT: - conf_value_int = - g_key_file_get_integer (keyfile, unique_name, name, - NULL); - value_int = (gint)g_value_get_uint (value); - if (conf_value_int == value_int) match = TRUE; - break; - case G_TYPE_BOOLEAN: - conf_value_bool = - g_key_file_get_boolean (keyfile, unique_name, name, - NULL); - value_bool = g_value_get_boolean (value); - if (conf_value_bool == value_bool) match = TRUE; - break; - default: - g_warning ("Unexpected type %s", G_VALUE_TYPE_NAME (value)); - } + GValue *conf = NULL; + + switch (vtype) + { + case G_TYPE_STRING: + case G_TYPE_UINT: + case G_TYPE_BOOLEAN: + conf = mcd_storage_dup_value (storage, account_name, name, vtype, + NULL); + break; + default: + g_warning ("Unexpected type %s", G_VALUE_TYPE_NAME (value)); + } + + if (conf != NULL) + { + if (G_VALUE_TYPE (conf) == vtype) + { + switch (vtype) + { + case G_TYPE_STRING: + match = g_strcmp0 (g_value_get_string (value), + g_value_get_string (conf)) == 0; + break; + + case G_TYPE_UINT: + match = g_value_get_uint (value) == g_value_get_uint (conf); + break; + + case G_TYPE_BOOLEAN: + match = + g_value_get_boolean (value) == g_value_get_boolean (conf); + break; + + default: + break; + } + } + + tp_g_value_slice_free (conf); + } } + return match; } diff --git a/src/mcd-account-manager-sso.c b/src/mcd-account-manager-sso.c index d0c42313..8e1796f3 100644 --- a/src/mcd-account-manager-sso.c +++ b/src/mcd-account-manager-sso.c @@ -1296,6 +1296,9 @@ _load_from_libaccounts (McdAccountManagerSso *sso, mcp_account_manager_set_value (am, name, MC_PROTOCOL_KEY, mc_id[1]); mcp_account_manager_set_value (am, name, MC_IDENTITY_KEY, name); + /* force the services value to be synthesised + cached */ + _get (MCP_ACCOUNT_STORAGE (sso), am, name, SERVICES_KEY); + ag_account_select_service (account, service); g_signal_connect (account, "enabled", diff --git a/src/mcd-account-manager.c b/src/mcd-account-manager.c index c512b3f8..c48e24c0 100644 --- a/src/mcd-account-manager.c +++ b/src/mcd-account-manager.c @@ -44,13 +44,9 @@ #include <telepathy-glib/errors.h> #include <telepathy-glib/interfaces.h> #include <telepathy-glib/svc-account-manager.h> -#include "mcd-account-manager-priv.h" -/* these pseudo-plugins take care of the actual account storage/retrieval */ -#include "mcd-account-manager-default.h" -#if ENABLE_LIBACCOUNTS_SSO -#include "mcd-account-manager-sso.h" -#endif +#include "mcd-account-manager-priv.h" +#include "mcd-storage.h" #include "mcd-account.h" #include "mcd-account-config.h" @@ -82,9 +78,6 @@ static void _mcd_account_manager_constructed (GObject *obj); static const McdDBusProp account_manager_properties[]; static const McdDBusProp sso_properties[]; -static gboolean plugins_cached = FALSE; -static GList *stores = NULL; - static const McdInterfaceData account_manager_interfaces[] = { MCD_IMPLEMENT_IFACE (tp_svc_account_manager_get_type, account_manager, @@ -162,19 +155,6 @@ static void account_loaded (McdAccount *account, const GError *error, gpointer user_data); -/* sort in descending order of priority (ie higher prio => earlier in list) */ -static gint -account_storage_cmp (gconstpointer a, gconstpointer b) -{ - gint pa = mcp_account_storage_priority (a); - gint pb = mcp_account_storage_priority (b); - - if (pa > pb) return -1; - if (pa < pb) return 1; - - return 0; -} - /* calback chain for asynchronously updates from backends: */ static void async_altered_validity_cb (McdAccount *account, gboolean valid, gpointer data) @@ -346,7 +326,7 @@ async_created_manager_cb (McdManager *cm, const GError *error, gpointer data) } /* account created by an McpAccountStorage plugin after the initial setup * - * since the plugin does not have our GKeyFile, we need to poke the plugin * + * since the plugin does not have our cache, we need to poke the plugin * * to fetch the named account explicitly at this point (ie it's a read, not * * not a write, from the plugin's POV: */ static void @@ -367,8 +347,7 @@ created_cb (GObject *storage, const gchar *name, gpointer data) lad->storage = plugin; lad->account_lock = 1; /* will be released at the end of this function */ - /* actually fetch the data into our GKeyFile from the plugin: */ - DEBUG ("-> mcp_account_storage_get"); + /* actually fetch the data into our cache from the plugin: */ if (mcp_account_storage_get (plugin, MCP_ACCOUNT_MANAGER (pa), name, NULL)) { account = mclass->account_new (am, name); @@ -451,15 +430,14 @@ _mcd_account_delete_cb (McdAccount *account, const GError *error, gpointer data) static void deleted_cb (GObject *plugin, const gchar *name, gpointer data) { - GList *store = NULL; McpAccountStorage *storage = MCP_ACCOUNT_STORAGE (plugin); McdAccountManager *manager = MCD_ACCOUNT_MANAGER (data); McdAccount *account = NULL; - McdPluginAccountManager *pa = manager->priv->plugin_manager; account = g_hash_table_lookup (manager->priv->accounts, name); - DEBUG ("%s -> %p", name, account); + DEBUG ("%s reported deletion of %s (%p)", + mcp_account_storage_name (storage), name, account); if (account != NULL) { @@ -467,83 +445,8 @@ deleted_cb (GObject *plugin, const gchar *name, gpointer data) g_hash_table_remove (manager->priv->accounts, name); mcd_account_delete (account, _mcd_account_delete_cb, NULL); } - - /* NOTE: we have to do this here, the mcd_account deletion just * - * steals a copy of your internal storage and erases the entry * - * from underneath us, so we don't even know we had the account * - * after mcd_account_delete: a rumsfeldian unknown unknown */ - /* PS: which will be fixed, but this will do for now */ - for (store = stores; store != NULL; store = g_list_next (store)) - { - McpAccountStorage *p = store->data; - - DEBUG ("MCP:%s -> remove %s", mcp_account_storage_name (p), name); - - /* don't call the plugin who informed us of deletion, it should * - * already have purged its own store and we don't want to risk * - * some sort of crazy keep-on-deleting infinite loop shenanigans */ - if (p != storage) - mcp_account_storage_delete (p, MCP_ACCOUNT_MANAGER (pa), name, NULL); - } } -static void -add_libaccount_plugin_if_enabled (void) -{ -#if ENABLE_LIBACCOUNTS_SSO - McdAccountManagerSso *sso_plugin = mcd_account_manager_sso_new (); - - stores = g_list_insert_sorted (stores, sso_plugin, account_storage_cmp); -#endif -} - -static void -sort_and_cache_plugins (McdAccountManager *self) -{ - const GList *p; - McdAccountManagerDefault *default_plugin = NULL; - - if (plugins_cached) - return; - - /* insert the default storage plugin into the sorted plugin list */ - default_plugin = mcd_account_manager_default_new (); - stores = g_list_insert_sorted (stores, default_plugin, account_storage_cmp); - - /* now poke the pseudo-plugins into the sorted GList of storage plugins */ - add_libaccount_plugin_if_enabled (); - - for (p = mcp_list_objects(); p != NULL; p = g_list_next (p)) - { - if (MCP_IS_ACCOUNT_STORAGE (p->data)) - { - McpAccountStorage *plugin = g_object_ref (p->data); - - stores = g_list_insert_sorted (stores, plugin, account_storage_cmp); - } - } - - for (p = stores; p != NULL; p = g_list_next (p)) - { - McpAccountStorage *plugin = p->data; - - DEBUG ("found plugin %s [%s; priority %d]\n%s", - mcp_account_storage_name (plugin), - g_type_name (G_TYPE_FROM_INSTANCE (plugin)), - mcp_account_storage_priority (plugin), - mcp_account_storage_description (plugin)); - g_signal_connect (plugin, "created", G_CALLBACK (created_cb), self); - g_signal_connect (plugin, "altered", G_CALLBACK (altered_cb), self); - g_signal_connect (plugin, "toggled", G_CALLBACK (toggled_cb), self); - g_signal_connect (plugin, "deleted", G_CALLBACK (deleted_cb), self); - g_signal_connect (plugin, "altered-one", G_CALLBACK (altered_one_cb), - self); - } - - plugins_cached = TRUE; -} - - GQuark mcd_account_manager_error_quark (void) { @@ -716,9 +619,8 @@ static void on_account_removed (McdAccount *account, McdAccountManager *account_manager) { McdAccountManagerPrivate *priv = account_manager->priv; - McdPluginAccountManager *pa = priv->plugin_manager; + McdStorage *storage = MCD_STORAGE (priv->plugin_manager); const gchar *name, *object_path; - GList *store; object_path = mcd_account_get_object_path (account); tp_svc_account_manager_emit_account_removed (account_manager, object_path); @@ -726,30 +628,29 @@ on_account_removed (McdAccount *account, McdAccountManager *account_manager) name = mcd_account_get_unique_name (account); g_hash_table_remove (priv->accounts, name); - for (store = stores; store != NULL; store = g_list_next (store)) - { - McpAccountStorage *plugin = store->data; - - DEBUG ("MCP:%s -> remove %s", mcp_account_storage_name (plugin), name); - mcp_account_storage_delete (plugin, MCP_ACCOUNT_MANAGER (pa), name, NULL); - } - + mcd_storage_delete_account (storage, name); mcd_account_manager_write_conf_async (account_manager, account, NULL, NULL); } +static inline void +disconnect_signal (gpointer instance, gpointer func) +{ + g_signal_handlers_disconnect_matched (instance, + G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, func, NULL); +} + static void unref_account (gpointer data) { McdAccount *account = MCD_ACCOUNT (data); - McdAccountManager *account_manager; DEBUG ("called for %s", mcd_account_get_unique_name (account)); - account_manager = mcd_account_get_account_manager (account); - g_signal_handlers_disconnect_by_func (account, on_account_validity_changed, - account_manager); - g_signal_handlers_disconnect_by_func (account, on_account_removed, - account_manager); + + disconnect_signal (account, on_account_validity_changed); + disconnect_signal (account, on_account_removed); + g_object_unref (account); } @@ -944,6 +845,7 @@ _mcd_account_manager_create_account (McdAccountManager *account_manager, { McdAccountManagerPrivate *priv = account_manager->priv; McpAccountManager *ma = MCP_ACCOUNT_MANAGER (priv->plugin_manager); + McdStorage *storage = MCD_STORAGE (priv->plugin_manager); McdCreateAccountData *cad; McdAccount *account; gchar *unique_name; @@ -965,13 +867,15 @@ _mcd_account_manager_create_account (McdAccountManager *account_manager, g_return_if_fail (unique_name != NULL); /* create the basic account keys */ - g_key_file_set_string (priv->plugin_manager->keyfile, unique_name, - MC_ACCOUNTS_KEY_MANAGER, manager); - g_key_file_set_string (priv->plugin_manager->keyfile, unique_name, - MC_ACCOUNTS_KEY_PROTOCOL, protocol); - if (display_name) - g_key_file_set_string (priv->plugin_manager->keyfile, unique_name, - MC_ACCOUNTS_KEY_DISPLAY_NAME, display_name); + mcd_storage_set_string (storage, unique_name, + MC_ACCOUNTS_KEY_MANAGER, manager, FALSE); + mcd_storage_set_string (storage, unique_name, + MC_ACCOUNTS_KEY_PROTOCOL, protocol, FALSE); + + if (display_name != NULL) + mcd_storage_set_string (storage, unique_name, + MC_ACCOUNTS_KEY_DISPLAY_NAME, display_name, + FALSE); account = MCD_ACCOUNT_MANAGER_GET_CLASS (account_manager)->account_new (account_manager, unique_name); @@ -1049,43 +953,25 @@ sso_get_service_accounts (McSvcAccountManagerInterfaceSSO *iface, gsize len; McdAccountManager *manager = MCD_ACCOUNT_MANAGER (iface); McdAccountManagerPrivate *priv = manager->priv; - GKeyFile *cache = priv->plugin_manager->keyfile; - GStrv accounts = g_key_file_get_groups (cache, &len); + McdStorage *storage = MCD_STORAGE (priv->plugin_manager); + GStrv accounts = mcd_storage_dup_accounts (storage, &len); GList *srv_accounts = NULL; GPtrArray *paths = g_ptr_array_new (); - if (!plugins_cached) - sort_and_cache_plugins (manager); if (len > 0 && accounts != NULL) { guint i = 0; gchar *name; - McpAccountManager *ma = MCP_ACCOUNT_MANAGER (priv->plugin_manager); for (name = accounts[i]; name != NULL; name = accounts[++i]) { - gchar *id = - g_key_file_get_string (cache, name, "libacct-uid", NULL); + gchar *id = mcd_storage_dup_string (storage, name, "libacct-uid"); if (id != NULL) { gchar *supported = - g_key_file_get_string (cache, name, "sso-services", NULL); - - if (supported == NULL) - { - - GList *store = g_list_last (stores); - while (store != NULL) - { - McpAccountStorage *as = store->data; - mcp_account_storage_get (as, ma, name, "sso-services"); - store = g_list_previous (store); - } - supported = g_key_file_get_string (cache, name, - "sso-services", NULL); - } + mcd_storage_dup_string (storage, name, "sso-services"); if (supported != NULL) { @@ -1138,14 +1024,13 @@ sso_get_account (McSvcAccountManagerInterfaceSSO *iface, const guint id, DBusGMethodInvocation *context) { - gsize len; McdAccountManager *manager = MCD_ACCOUNT_MANAGER (iface); McdAccountManagerPrivate *priv = manager->priv; - GKeyFile *cache = priv->plugin_manager->keyfile; - GStrv accounts = g_key_file_get_groups (cache, &len); + McdStorage *storage = MCD_STORAGE (priv->plugin_manager); + GStrv accounts = mcd_storage_dup_accounts (storage, NULL); const gchar *path = NULL; - if (len > 0 && accounts != NULL) + if (accounts != NULL) { guint i = 0; gchar *name; @@ -1154,7 +1039,7 @@ sso_get_account (McSvcAccountManagerInterfaceSSO *iface, for (name = accounts[i]; name != NULL; name = accounts[++i]) { gchar *str_id = - g_key_file_get_string (cache, name, "libacct-uid", NULL); + mcd_storage_dup_string (storage, name, "libacct-uid"); guint64 sso_id = g_ascii_strtoull (str_id, NULL, 10); if (sso_id != 0 && id != 0) @@ -1301,76 +1186,13 @@ properties_iface_init (TpSvcDBusPropertiesClass *iface, gpointer iface_data) static gboolean write_conf (gpointer userdata) { - McdPluginAccountManager *pa = userdata; - GKeyFile *keyfile = pa->keyfile; - GStrv groups; - gchar *group; - gsize i = 0; - GList *store; + McdStorage *storage = MCD_STORAGE (userdata); DEBUG ("called"); g_source_remove (write_conf_id); write_conf_id = 0; - groups = g_key_file_get_groups (keyfile, NULL); - - if (groups == NULL) - return TRUE; - - /* poke the account settings into the local cache of the relevant * - * storage plugins, highest priority plugins get first dibs: * - * Note that the MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_DEFAULT priority * - * plugin is the default keyfile plugin and accepts all settings, * - * so no plugin of a lower priority will be asked to save anything */ - for (group = groups[i]; group != NULL; group = groups[++i]) - { - gsize n_keys; - gsize j = 0; - GStrv keys = g_key_file_get_keys (keyfile, group, &n_keys, NULL); - - if (keys == NULL) - n_keys = 0; - - for (j = 0; j < n_keys; j++) - { - gboolean done = FALSE; - gchar *set = keys[j]; - gchar *val = g_key_file_get_string (keyfile, group, set, NULL); - - for (store = stores; store != NULL; store = g_list_next (store)) - { - McpAccountStorage *plugin = store->data; - McpAccountManager *ma = MCP_ACCOUNT_MANAGER (pa); - const gchar *pn = mcp_account_storage_name (plugin); - - if (done) - { - DEBUG ("MCP:%s -> delete %s.%s", pn, group, set); - mcp_account_storage_delete (plugin, ma, group, set); - } - else - { - done = mcp_account_storage_set (plugin, ma, group, set, val); - DEBUG ("MCP:%s -> %s %s.%s", - pn, done ? "store" : "ignore", group, set); - } - } - } - - g_strfreev (keys); - } - - g_strfreev (groups); - - for (store = stores; store != NULL; store = g_list_next (store)) - { - McpAccountManager *ma = MCP_ACCOUNT_MANAGER (pa); - McpAccountStorage *plugin = store->data; - const gchar *pname = mcp_account_storage_name (plugin); - - DEBUG ("flushing plugin %s to long term storage", pname); - mcp_account_storage_commit (plugin, ma); - } + mcd_storage_commit (storage, NULL); return TRUE; } @@ -1408,18 +1230,9 @@ static void uncork_storage_plugins (McdAccountManager *account_manager) { McdAccountManagerPrivate *priv = MCD_ACCOUNT_MANAGER_PRIV (account_manager); - McpAccountManager *mcp_am = MCP_ACCOUNT_MANAGER (priv->plugin_manager); - GList *store; - /* Allow plugins to register new accounts, highest prio first */ - for (store = stores; store != NULL; store = g_list_next (store)) - { - McpAccountStorage *plugin = store->data; - - DEBUG ("Unblocking async account ops by %s", - mcp_account_storage_name (plugin)); - mcp_account_storage_ready (plugin, mcp_am); - } + mcd_account_manager_write_conf_async (account_manager, NULL, NULL, NULL); + _mcd_plugin_account_manager_ready (priv->plugin_manager); } /** @@ -1433,6 +1246,7 @@ void _mcd_account_manager_setup (McdAccountManager *account_manager) { McdAccountManagerPrivate *priv = account_manager->priv; + McdStorage *storage = MCD_STORAGE (priv->plugin_manager); McdLoadAccountsData *lad; gchar **accounts, **name; @@ -1444,7 +1258,8 @@ _mcd_account_manager_setup (McdAccountManager *account_manager) lad->account_manager = account_manager; lad->account_lock = 1; /* will be released at the end of this function */ - accounts = g_key_file_get_groups (priv->plugin_manager->keyfile, NULL); + accounts = mcd_storage_dup_accounts (storage, NULL); + for (name = accounts; *name != NULL; name++) { gboolean plausible = FALSE; @@ -1462,6 +1277,7 @@ _mcd_account_manager_setup (McdAccountManager *account_manager) account = MCD_ACCOUNT_MANAGER_GET_CLASS (account_manager)->account_new (account_manager, *name); + if (G_UNLIKELY (!account)) { g_warning ("%s: account %s failed to instantiate", G_STRFUNC, @@ -1639,8 +1455,14 @@ static void mcd_account_manager_init (McdAccountManager *account_manager) { McdAccountManagerPrivate *priv; - GList *store = NULL; - McpAccountManager *ma; + guint i = 0; + static struct { const gchar *name; GCallback handler; } sig[] = + { { "created", G_CALLBACK (created_cb) }, + { "altered", G_CALLBACK (altered_cb) }, + { "toggled", G_CALLBACK (toggled_cb) }, + { "deleted", G_CALLBACK (deleted_cb) }, + { "altered-one", G_CALLBACK (altered_one_cb) }, + { NULL, NULL } }; DEBUG (""); @@ -1650,7 +1472,6 @@ mcd_account_manager_init (McdAccountManager *account_manager) account_manager->priv = priv; priv->plugin_manager = mcd_plugin_account_manager_new (); - ma = MCP_ACCOUNT_MANAGER (priv->plugin_manager); priv->accounts = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, unref_account); @@ -1660,40 +1481,13 @@ mcd_account_manager_init (McdAccountManager *account_manager) NULL); DEBUG ("loading plugins"); + mcd_storage_load (MCD_STORAGE (priv->plugin_manager)); - /* not guaranteed to have been called, but idempotent: */ - _mcd_plugin_loader_init (); - - if (!plugins_cached) - sort_and_cache_plugins (account_manager); - - store = g_list_last (stores); - - /* fetch accounts stored in plugins, in reverse priority so higher prio * - * plugins can overwrite lower prio ones' account data */ - while (store != NULL) - { - GList *account; - McpAccountStorage *plugin = store->data; - GList *stored = mcp_account_storage_list (plugin, ma); - const gchar *pname = mcp_account_storage_name (plugin); - const gint prio = mcp_account_storage_priority (plugin); - - DEBUG ("listing from plugin %s [prio: %d]", pname, prio); - for (account = stored; account != NULL; account = g_list_next (account)) - { - gchar *name = account->data; - - DEBUG ("fetching %s from plugin %s [prio: %d]", name, pname, prio); - mcp_account_storage_get (plugin, ma, name, NULL); - - g_free (name); - } - - /* already freed the contents, just need to free the list itself */ - g_list_free (stored); - store = g_list_previous (store); - } + /* hook up all the storage plugin signals to their handlers: */ + for (i = 0; sig[i].name != NULL; i++) + _mcd_plugin_account_manager_connect_signal (sig[i].name, + sig[i].handler, + account_manager); /* initializes the interfaces */ mcd_dbus_init_interfaces_instances (account_manager); @@ -1710,7 +1504,7 @@ _mcd_account_manager_constructed (GObject *obj) * _init() to here and then mcd_plugin_account_manager_new() could take the * TpDBusDaemon * as it should and everyone wins. */ - mcd_plugin_account_manager_set_dbus_daemon (pa, priv->dbus_daemon); + _mcd_plugin_account_manager_set_dbus_daemon (pa, priv->dbus_daemon); } McdAccountManager * @@ -1749,68 +1543,6 @@ mcd_account_manager_get_dbus_daemon (McdAccountManager *account_manager) * with the appropriate error. */ -/* - * update_one_account: - * @account_manager: - * @ma: - * @account: (allow-none): the #McdAccount if it exists, or %NULL - * @account_name: - * @keyfile: - */ -static void -update_one_account (McdAccountManager *account_manager, - McpAccountManager *ma, - McdAccount *account, - const gchar *account_name, - GKeyFile *keyfile) -{ - gsize n_keys = 0; - GStrv keys = g_key_file_get_keys (keyfile, account_name, &n_keys, NULL); - gsize j = 0; - - if (keys == NULL) - n_keys = 0; - - for (j = 0; j < n_keys; j++) - { - gboolean done = FALSE; - gchar *set = keys[j]; - gchar *val = g_key_file_get_value (keyfile, account_name, set, NULL); - GList *store; - - /* the param- prefix gets whacked on in the layer above us: * - * mcd-account et al don't know it exists so don't pass it back */ - if (account != NULL && g_str_has_prefix (set, PARAM_PREFIX)) - { - const gchar *p = set + strlen (PARAM_PREFIX); - - if (mcd_account_parameter_is_secret (account, p)) - mcp_account_manager_parameter_make_secret (ma, account_name, - set); - } - - for (store = stores; store != NULL; store = g_list_next (store)) - { - McpAccountStorage *plugin = store->data; - const gchar *pname = mcp_account_storage_name (plugin); - - if (done) - { - DEBUG ("MCP:%s -> delete %s.%s", pname, account_name, set); - mcp_account_storage_delete (plugin, ma, account_name, set); - } - else - { - done = mcp_account_storage_set (plugin, ma, account_name, set, val); - DEBUG ("MCP:%s -> %s %s.%s", - pname, done ? "store" : "ignore", account_name, set); - } - } - } - - g_strfreev (keys); -} - /** * mcd_account_manager_write_conf_async: * @account_manager: the #McdAccountManager @@ -1826,68 +1558,33 @@ mcd_account_manager_write_conf_async (McdAccountManager *account_manager, McdAccountManagerWriteConfCb callback, gpointer user_data) { - GList *store; - GKeyFile *keyfile; - McpAccountManager *ma; + McdStorage *storage = NULL; + const gchar *account_name = NULL; g_return_if_fail (MCD_IS_ACCOUNT_MANAGER (account_manager)); - keyfile = account_manager->priv->plugin_manager->keyfile; - ma = MCP_ACCOUNT_MANAGER (account_manager->priv->plugin_manager); + storage = MCD_STORAGE (account_manager->priv->plugin_manager); if (account != NULL) { - const gchar *account_name = mcd_account_get_unique_name (account); + account_name = mcd_account_get_unique_name (account); DEBUG ("updating %s", account_name); - update_one_account (account_manager, ma, account, account_name, - keyfile); + mcd_storage_commit (storage, account_name); } else { GStrv groups; gsize n_accounts = 0; - gsize i = 0; - gchar *group; - - groups = g_key_file_get_groups (keyfile, &n_accounts); + groups = mcd_storage_dup_accounts (storage, &n_accounts); DEBUG ("updating all %" G_GSIZE_FORMAT " accounts)", n_accounts); - for (group = groups[i]; group != NULL; group = groups[++i]) - { - McdAccount *group_account = - mcd_account_manager_lookup_account (account_manager, - group); - - /* group_account might be %NULL, but update_one_account tolerates - * that */ - update_one_account (account_manager, ma, group_account, group, - keyfile); - } + mcd_storage_commit (storage, NULL); g_strfreev (groups); } - for (store = stores; store != NULL; store = g_list_next (store)) - { - McpAccountStorage *plugin = store->data; - const gchar *pname = mcp_account_storage_name (plugin); - - DEBUG ("flushing plugin %s to long term storage", pname); - - if (account == NULL) - { - mcp_account_storage_commit (plugin, ma); - } - else - { - const gchar *account_name = mcd_account_get_unique_name (account); - - mcp_account_storage_commit_one (plugin, ma, account_name); - } - } - if (callback != NULL) callback (account_manager, NULL, user_data); } @@ -1923,20 +1620,6 @@ mcd_account_manager_lookup_account_by_path (McdAccountManager *account_manager, object_path + (sizeof (MC_ACCOUNT_DBUS_OBJECT_BASE) - 1)); } -/** - * mcd_account_manager_get_config: - * @account_manager: the #McdAccountManager. - * - * Returns: the #GKeyFile holding the configuration. - */ -GKeyFile * -mcd_account_manager_get_config (McdAccountManager *account_manager) -{ - g_return_val_if_fail (MCD_IS_ACCOUNT_MANAGER (account_manager), NULL); - - return account_manager->priv->plugin_manager->keyfile; -} - /* * _mcd_account_manager_store_account_connections: * @account_manager: the #McdAccountManager. @@ -1983,29 +1666,9 @@ _mcd_account_manager_store_account_connections (McdAccountManager *manager) fclose (file); } -McpAccountStorage * -mcd_account_manager_get_storage_plugin (McdAccountManager *account_manager, - McdAccount *account) +McdStorage * +mcd_account_manager_get_storage (McdAccountManager *account_manager) { - GList *store; - const gchar *account_name = mcd_account_get_unique_name (account); - McpAccountManager *ma = MCP_ACCOUNT_MANAGER ( - account_manager->priv->plugin_manager); - - for (store = stores; store != NULL; store = g_list_next (store)) - { - McpAccountStorage *plugin = store->data; - GList *stored = mcp_account_storage_list (plugin, ma); - GList *iter; - - for (iter = stored; iter != NULL; iter = g_list_next (iter)) - { - gchar *name = iter->data; - - if (g_strcmp0 (name, account_name) == 0) - return plugin; - } - } - - return NULL; + return MCD_STORAGE (account_manager->priv->plugin_manager); } + diff --git a/src/mcd-account-manager.h b/src/mcd-account-manager.h index 39db4622..6c60123a 100644 --- a/src/mcd-account-manager.h +++ b/src/mcd-account-manager.h @@ -26,6 +26,7 @@ #include <telepathy-glib/dbus.h> #include "mission-control-plugins/mission-control-plugins.h" +#include "mcd-storage.h" G_BEGIN_DECLS #define MCD_TYPE_ACCOUNT_MANAGER (mcd_account_manager_get_type ()) @@ -99,8 +100,6 @@ McdAccount *mcd_account_manager_lookup_account (McdAccountManager *account_manag McdAccount *mcd_account_manager_lookup_account_by_path (McdAccountManager *account_manager, const gchar *object_path); -McpAccountStorage *mcd_account_manager_get_storage_plugin ( - McdAccountManager *account_manager, - McdAccount *account); +McdStorage *mcd_account_manager_get_storage (McdAccountManager *manager); #endif diff --git a/src/mcd-account-priv.h b/src/mcd-account-priv.h index 9f0c9179..a8d76f2b 100644 --- a/src/mcd-account-priv.h +++ b/src/mcd-account-priv.h @@ -114,16 +114,16 @@ typedef struct { G_GNUC_INTERNAL GList *_mcd_account_get_online_requests (McdAccount *account); +G_GNUC_INTERNAL McdStorage *_mcd_account_get_storage (McdAccount *account); static inline void _mcd_account_write_conf (McdAccount *account) { - McdAccountManager *account_manager; + McdStorage *storage = _mcd_account_get_storage (account); - account_manager = mcd_account_get_account_manager (account); - g_return_if_fail (MCD_IS_ACCOUNT_MANAGER (account_manager)); + g_return_if_fail (MCD_IS_STORAGE (storage)); - mcd_account_manager_write_conf_async (account_manager, account, NULL, NULL); + mcd_storage_commit (storage, mcd_account_get_unique_name (account)); } G_GNUC_INTERNAL void _mcd_account_compat_class_init (McdAccountClass *klass); diff --git a/src/mcd-account-requests.c b/src/mcd-account-requests.c index e9cfe316..1db1cc09 100644 --- a/src/mcd-account-requests.c +++ b/src/mcd-account-requests.c @@ -190,8 +190,8 @@ _mcd_account_create_request (McdAccount *account, GHashTable *properties, { McdChannel *channel; GHashTable *props; - TpDBusDaemon *dbus_daemon = mcd_account_manager_get_dbus_daemon ( - mcd_account_get_account_manager (account)); + TpDBusDaemon *dbus_daemon = mcd_account_get_dbus_daemon (account); + DBusGConnection *dgc = tp_proxy_get_dbus_connection (dbus_daemon); if (!mcd_account_check_request (account, properties, error)) diff --git a/src/mcd-account.c b/src/mcd-account.c index 2770a789..74af7280 100644 --- a/src/mcd-account.c +++ b/src/mcd-account.c @@ -26,6 +26,7 @@ #include "config.h" #include "mcd-account.h" +#include "mcd-storage-priv.h" #include <stdio.h> #include <string.h> @@ -120,7 +121,10 @@ struct _McdAccountPrivate TpConnection *tp_connection; McdConnection *connection; McdManager *manager; - McdAccountManager *account_manager; + + McdStorage *storage; + TpDBusDaemon *dbus_daemon; + McdTransport *transport; McdAccountConnectionContext *connection_context; GKeyFile *keyfile; /* configuration file */ @@ -181,7 +185,7 @@ enum { PROP_0, PROP_DBUS_DAEMON, - PROP_ACCOUNT_MANAGER, + PROP_STORAGE, PROP_NAME, PROP_ALWAYS_ON, }; @@ -384,242 +388,34 @@ mcd_account_loaded (McdAccount *account) g_object_unref (account); } -static gboolean -keyfile_set_value (GKeyFile *keyfile, - const gchar *group_name, - const gchar *key_name, - const GValue *value, - GError **error) -{ - gchar buf[21]; /* enough for '-' + the 19 digits of 2**63 + '\0' */ - - if (!value) - { - g_key_file_remove_key (keyfile, group_name, key_name, NULL); - DEBUG ("unset param %s", key_name); - return TRUE; - } - - switch (G_VALUE_TYPE (value)) - { - case G_TYPE_STRING: - g_key_file_set_string (keyfile, group_name, key_name, - g_value_get_string (value)); - break; - - case G_TYPE_UINT: - g_snprintf (buf, sizeof (buf), "%u", g_value_get_uint (value)); - g_key_file_set_string (keyfile, group_name, key_name, - buf); - break; - - case G_TYPE_INT: - g_key_file_set_integer (keyfile, group_name, key_name, - g_value_get_int (value)); - break; - - case G_TYPE_BOOLEAN: - g_key_file_set_boolean (keyfile, group_name, key_name, - g_value_get_boolean (value)); - break; - - case G_TYPE_UCHAR: - g_key_file_set_integer (keyfile, group_name, key_name, - g_value_get_uchar (value)); - break; - - case G_TYPE_UINT64: - g_snprintf (buf, sizeof (buf), "%" G_GUINT64_FORMAT, - g_value_get_uint64 (value)); - g_key_file_set_string (keyfile, group_name, key_name, - buf); - break; - - case G_TYPE_INT64: - g_snprintf (buf, sizeof (buf), "%" G_GINT64_FORMAT, - g_value_get_int64 (value)); - g_key_file_set_string (keyfile, group_name, key_name, - buf); - break; - - case G_TYPE_DOUBLE: - g_key_file_set_double (keyfile, group_name, key_name, - g_value_get_double (value)); - break; - - default: - if (G_VALUE_HOLDS (value, G_TYPE_STRV)) - { - gchar **strings = g_value_get_boxed (value); - - g_key_file_set_string_list (keyfile, group_name, key_name, - (const gchar **)strings, - g_strv_length (strings)); - } - else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) - { - const gchar *path = g_value_get_boxed (value); - - g_key_file_set_string (keyfile, group_name, key_name, - path); - } - else - { - g_warning ("Unexpected param type %s", G_VALUE_TYPE_NAME (value)); - return FALSE; - } - } - - return TRUE; -} - static void set_parameter (McdAccount *account, const gchar *name, const GValue *value, McdAccountSetParameterCb callback, gpointer user_data) { McdAccountPrivate *priv = account->priv; + McdStorage *storage = priv->storage; gchar key[MAX_KEY_LENGTH]; - GError *error = NULL; + 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); - keyfile_set_value (priv->keyfile, priv->unique_name, key, - value, &error); + mcd_storage_set_value (storage, account_name, key, value, secret); if (callback != NULL) - { - callback (account, error, user_data); - } - - if (error != NULL) - g_error_free (error); + callback (account, NULL, user_data); /* set_parameter */ } -static GValue * -keyfile_get_value (GKeyFile *keyfile, - const gchar *group_name, - const gchar *key_name, - GType type, - GError **error) -{ - GValue *value = NULL; - gchar *v_string = NULL; - gint64 v_int = 0; - guint64 v_uint = 0; - gboolean v_bool = FALSE; - double v_double = 0.0; - switch (type) - { - case G_TYPE_STRING: - v_string = g_key_file_get_string (keyfile, group_name, - key_name, error); - value = tp_g_value_slice_new_take_string (v_string); - break; - case G_TYPE_INT: - v_int = g_key_file_get_integer (keyfile, group_name, - key_name, error); - value = tp_g_value_slice_new_int (v_int); - break; - case G_TYPE_INT64: - v_int = tp_g_key_file_get_int64 (keyfile, group_name, - key_name, error); - value = tp_g_value_slice_new_int64 (v_int); - break; - case G_TYPE_UINT: - v_uint = tp_g_key_file_get_uint64 (keyfile, - group_name, key_name, error); - if (v_uint > 0xFFFFFFFFU) - { - g_set_error (error, MCD_ACCOUNT_ERROR, - MCD_ACCOUNT_ERROR_GET_PARAMETER, - "Integer is out of range"); - } - else - { - value = tp_g_value_slice_new_uint (v_uint); - } - break; - case G_TYPE_UCHAR: - v_int = g_key_file_get_integer (keyfile, group_name, - key_name, error); - if (v_int < 0 || v_int > 0xFF) - { - g_set_error (error, MCD_ACCOUNT_ERROR, - MCD_ACCOUNT_ERROR_GET_PARAMETER, - "Integer is out of range"); - } - else - { - value = tp_g_value_slice_new (G_TYPE_UCHAR); - g_value_set_uchar (value, v_int); - } - break; - case G_TYPE_UINT64: - v_uint = tp_g_key_file_get_uint64 (keyfile, - group_name, key_name, error); - value = tp_g_value_slice_new_uint64 (v_uint); - break; - - case G_TYPE_BOOLEAN: - v_bool = g_key_file_get_boolean (keyfile, group_name, - key_name, NULL); - - value = tp_g_value_slice_new_boolean (v_bool); - break; - - case G_TYPE_DOUBLE: - v_double = g_key_file_get_double (keyfile, group_name, - key_name, NULL); - - value = tp_g_value_slice_new_double (v_double); - break; - - default: - if (type == G_TYPE_STRV) - { - gchar **v = g_key_file_get_string_list (keyfile, - group_name, key_name, - NULL, error); - - value = tp_g_value_slice_new_take_boxed (G_TYPE_STRV, v); - } - else if (type == DBUS_TYPE_G_OBJECT_PATH) - { - v_string = g_key_file_get_string (keyfile, - group_name, key_name, - error); - - if (!tp_dbus_check_valid_object_path (v_string, NULL)) - { - g_set_error (error, MCD_ACCOUNT_ERROR, - MCD_ACCOUNT_ERROR_GET_PARAMETER, - "Invalid object path %s", v_string); - g_free (v_string); - } - else - { - value = tp_g_value_slice_new_take_object_path (v_string); - } - } - else - { - g_warning ("%s: cannot get property %s, unknown type %s", - G_STRFUNC, key_name, g_type_name (type)); - } - } - - return value; -} static GType mc_param_type (const TpConnectionManagerParam *param); @@ -635,20 +431,23 @@ get_parameter_from_file (McdAccount *account, const gchar *name, McdAccountGetParameterCb callback, gpointer user_data) { McdAccountPrivate *priv = account->priv; + McdStorage *storage = priv->storage; gchar key[MAX_KEY_LENGTH]; const TpConnectionManagerParam *param; GError *error = NULL; GValue *value = NULL; GType type; + const gchar *account_name = mcd_account_get_unique_name (account); param = mcd_manager_get_protocol_param (priv->manager, priv->protocol_name, name); type = mc_param_type (param); g_snprintf (key, sizeof (key), "param-%s", name); - if (g_key_file_has_key (priv->keyfile, priv->unique_name, key, NULL)) + + if (mcd_storage_has_value (storage, account_name, key)) { - value = keyfile_get_value (priv->keyfile, priv->unique_name, key, type, &error); + value = mcd_storage_dup_value (storage, account_name, key, type, &error); } else { @@ -740,26 +539,6 @@ get_account_data_path (McdAccountPrivate *priv) return g_build_filename (base, priv->unique_name, NULL); } -typedef struct -{ - McdAccount *account; - McdAccountDeleteCb callback; - gpointer user_data; -} AccountDeleteData; - -static void -_mcd_account_delete_write_conf_cb (McdAccountManager *account_manager, - const GError *error, - gpointer user_data) -{ - AccountDeleteData *data = (AccountDeleteData *) user_data; - - if (data->callback != NULL) - data->callback (data->account, error, data->user_data); - - g_slice_free (AccountDeleteData, data); -} - static void _mcd_account_delete (McdAccount *account, McdAccountDeleteCb callback, @@ -767,36 +546,20 @@ _mcd_account_delete (McdAccount *account, { McdAccountPrivate *priv = account->priv; gchar *data_dir_str; - GError *kf_error = NULL; - AccountDeleteData *delete_data; + GError *error = NULL; + const gchar *name = mcd_account_get_unique_name (account); /* got to turn the account off before removing it, otherwise we can * * end up with an orphaned CM holding the account online */ - if (!_mcd_account_set_enabled (account, FALSE, FALSE, &kf_error)) + if (!_mcd_account_set_enabled (account, FALSE, FALSE, &error)) { - g_warning ("could not disable account (%s)", kf_error->message); - callback (account, kf_error, user_data); - g_error_free (kf_error); + g_warning ("could not disable account %s (%s)", name, error->message); + callback (account, error, user_data); + g_error_free (error); return; } - if (!g_key_file_remove_group (priv->keyfile, priv->unique_name, - &kf_error)) - { - if (kf_error->domain == G_KEY_FILE_ERROR && - kf_error->code == G_KEY_FILE_ERROR_GROUP_NOT_FOUND) - { - DEBUG ("account not found in key file, doing nothing"); - g_clear_error (&kf_error); - } - else - { - g_warning ("Could not remove group (%s)", kf_error->message); - callback (account, kf_error, user_data); - g_error_free (kf_error); - return; - } - } + mcd_storage_delete_account (priv->storage, name); data_dir_str = get_account_data_path (priv); @@ -823,15 +586,9 @@ _mcd_account_delete (McdAccount *account, g_free (data_dir_str); } - delete_data = g_slice_new0 (AccountDeleteData); - delete_data->account = account; - delete_data->callback = callback; - delete_data->user_data = user_data; - - mcd_account_manager_write_conf_async (priv->account_manager, - account, - _mcd_account_delete_write_conf_cb, - delete_data); + mcd_storage_commit (priv->storage, name); + if (callback != NULL) + callback (account, NULL, user_data); } static void @@ -1123,8 +880,12 @@ mcd_account_set_string_val (McdAccount *account, const gchar *key, const GValue *value, GError **error) { McdAccountPrivate *priv = account->priv; - const gchar *string; + McdStorage *storage = priv->storage; + const gchar *name = mcd_account_get_unique_name (account); + + const gchar *new_string; gchar *old_string; + const GValue *set = value; if (!G_VALUE_HOLDS_STRING (value)) { @@ -1134,28 +895,23 @@ mcd_account_set_string_val (McdAccount *account, const gchar *key, return SET_RESULT_ERROR; } - string = g_value_get_string (value); - old_string = g_key_file_get_string (priv->keyfile, priv->unique_name, - key, NULL); - if (!tp_strdiff (old_string, string)) + old_string = mcd_storage_dup_string (storage, name, key); + new_string = g_value_get_string (value); + + if (!tp_strdiff (old_string, new_string)) { - g_free (old_string); - return SET_RESULT_UNCHANGED; + g_free (old_string); + return SET_RESULT_UNCHANGED; } g_free (old_string); - if (string && string[0] != 0) - g_key_file_set_string (priv->keyfile, priv->unique_name, - key, string); - else - { - g_key_file_remove_key (priv->keyfile, priv->unique_name, - key, NULL); - string = NULL; - } - mcd_account_manager_write_conf_async (priv->account_manager, account, NULL, - NULL); + + if (new_string == NULL || *new_string == '\0') + set = NULL; + + mcd_storage_set_value (storage, name, key, set, FALSE); mcd_account_changed_property (account, key, value); + return SET_RESULT_CHANGED; } @@ -1164,12 +920,22 @@ mcd_account_get_string_val (McdAccount *account, const gchar *key, GValue *value) { McdAccountPrivate *priv = account->priv; - gchar *string; + const gchar *name = mcd_account_get_unique_name (account); + GValue *fetched = NULL; - string = g_key_file_get_string (priv->keyfile, priv->unique_name, - key, NULL); + fetched = + mcd_storage_dup_value (priv->storage, name, key, G_TYPE_STRING, NULL); g_value_init (value, G_TYPE_STRING); - g_value_take_string (value, string); + + if (fetched != NULL) + { + g_value_copy (fetched, value); + tp_g_value_slice_free (fetched); + } + else + { + g_value_set_static_string (value, NULL); + } } static gboolean @@ -1261,24 +1027,26 @@ _mcd_account_set_enabled (McdAccount *account, if (priv->enabled != enabled) { GValue value = { 0, }; + const gchar *name = mcd_account_get_unique_name (account); if (!enabled) mcd_account_request_presence (account, TP_CONNECTION_PRESENCE_TYPE_OFFLINE, "offline", NULL); - g_key_file_set_boolean (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_ENABLED, - enabled); priv->enabled = enabled; - if (write_out) - mcd_account_manager_write_conf_async (priv->account_manager, - account, NULL, NULL); - 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); + + if (write_out) + mcd_storage_commit (priv->storage, name); + mcd_account_changed_property (account, "Enabled", &value); + g_value_unset (&value); if (enabled) @@ -1543,8 +1311,9 @@ set_automatic_presence (TpSvcDBusProperties *self, TpConnectionPresenceType type; gboolean changed = FALSE; GValueArray *va; + const gchar *account_name = mcd_account_get_unique_name (account); - DEBUG ("called for %s", priv->unique_name); + DEBUG ("called for %s", account_name); if (!G_VALUE_HOLDS (value, TP_STRUCT_TYPE_SIMPLE_PRESENCE)) { @@ -1571,45 +1340,55 @@ set_automatic_presence (TpSvcDBusProperties *self, if (priv->auto_presence_type != type) { - g_key_file_set_integer (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AUTO_PRESENCE_TYPE, type); - priv->auto_presence_type = type; - changed = TRUE; + GValue presence = { 0 }; + + 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); + priv->auto_presence_type = type; + changed = TRUE; } + if (tp_strdiff (priv->auto_presence_status, status)) { - if (status && status[0] != 0) - g_key_file_set_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AUTO_PRESENCE_STATUS, - status); - else - g_key_file_remove_key (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AUTO_PRESENCE_STATUS, - NULL); - g_free (priv->auto_presence_status); - priv->auto_presence_status = g_strdup (status); - changed = TRUE; + const gchar *new_status = NULL; + + if (status != NULL && status[0] != 0) + new_status = status; + + mcd_storage_set_string (priv->storage, account_name, + MC_ACCOUNTS_KEY_AUTO_PRESENCE_STATUS, + new_status, FALSE); + + g_free (priv->auto_presence_status); + priv->auto_presence_status = g_strdup (status); + changed = TRUE; } + if (tp_strdiff (priv->auto_presence_message, message)) { - if (message && message[0] != 0) - g_key_file_set_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AUTO_PRESENCE_MESSAGE, - message); - else - g_key_file_remove_key (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AUTO_PRESENCE_MESSAGE, - NULL); - g_free (priv->auto_presence_message); - priv->auto_presence_message = g_strdup (message); - changed = TRUE; + const gchar *new_message = NULL; + + if (!tp_str_empty (message)) + new_message = message; + + mcd_storage_set_string (priv->storage, account_name, + MC_ACCOUNTS_KEY_AUTO_PRESENCE_MESSAGE, + new_message, FALSE); + + g_free (priv->auto_presence_message); + priv->auto_presence_message = g_strdup (message); + changed = TRUE; } + if (changed) { - mcd_account_manager_write_conf_async (priv->account_manager, account, - NULL, NULL); - mcd_account_changed_property (account, name, value); + mcd_storage_commit (priv->storage, account_name); + mcd_account_changed_property (account, name, value); } return TRUE; @@ -1670,13 +1449,14 @@ set_connect_automatically (TpSvcDBusProperties *self, if (priv->connect_automatically != connect_automatically) { - g_key_file_set_boolean (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_CONNECT_AUTOMATICALLY, - connect_automatically); - priv->connect_automatically = connect_automatically; - mcd_account_manager_write_conf_async (priv->account_manager, account, - NULL, NULL); - mcd_account_changed_property (account, name, value); + 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); + + priv->connect_automatically = connect_automatically; + mcd_storage_commit (priv->storage, account_name); + mcd_account_changed_property (account, name, value); if (connect_automatically) { @@ -1878,15 +1658,15 @@ static McpAccountStorage * get_storage_plugin (McdAccount *account) { McdAccountPrivate *priv = account->priv; + const gchar *account_name = mcd_account_get_unique_name (account); if (priv->storage_plugin != NULL) return priv->storage_plugin; - priv->storage_plugin = mcd_account_manager_get_storage_plugin ( - priv->account_manager, account); + priv->storage_plugin = mcd_storage_get_plugin (priv->storage, account_name); - if (priv->storage_plugin != NULL) - g_object_ref (priv->storage_plugin); + if (priv->storage_plugin != NULL) + g_object_ref (priv->storage_plugin); return priv->storage_plugin; } @@ -2565,7 +2345,6 @@ set_parameters_iter_param (McdAccount *account, if (data->new != NULL) { - DEBUG ("Got param %s", data->param->name); data->n_params++; if (G_VALUE_TYPE (data->new) != type) @@ -2703,14 +2482,14 @@ update_parameters_dup_params_cb (McdAccount *account, GHashTable *params, McdAccountPrivate *priv = account->priv; UpdateParametersData *data = (UpdateParametersData *) user_data; GValue value = { 0 }; + const gchar *account_name = mcd_account_get_unique_name (account); g_value_init (&value, TP_HASH_TYPE_STRING_VARIANT_MAP); g_value_take_boxed (&value, params); mcd_account_changed_property (account, "Parameters", &value); g_value_unset (&value); - mcd_account_manager_write_conf_async (priv->account_manager, account, NULL, - NULL); + mcd_storage_commit (priv->storage, account_name); g_ptr_array_add (data->not_yet, NULL); @@ -2825,14 +2604,13 @@ register_dbus_service (McdAccount *self, } g_assert (MCD_IS_ACCOUNT (self)); - /* these are invariants - the account manager is set at construct-time + /* these are invariants - the storage is set at construct-time * and the object path is set in mcd_account_setup, both of which are * run before this callback can possibly be invoked */ - g_assert (self->priv->account_manager != NULL); + g_assert (self->priv->storage != NULL); g_assert (self->priv->object_path != NULL); - dbus_daemon = mcd_account_manager_get_dbus_daemon ( - self->priv->account_manager); + dbus_daemon = self->priv->dbus_daemon; g_return_if_fail (dbus_daemon != NULL); dbus_connection = TP_PROXY (dbus_daemon)->dbus_connection; @@ -2847,55 +2625,46 @@ static gboolean mcd_account_setup (McdAccount *account) { McdAccountPrivate *priv = account->priv; - - priv->keyfile = mcd_account_manager_get_config (priv->account_manager); - if (!priv->keyfile) - { - g_error ("Could not find internal data"); - goto broken_account; - } + McdStorage *storage = priv->storage; + const gchar *name = mcd_account_get_unique_name (account); priv->manager_name = - g_key_file_get_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_MANAGER, NULL); - if (!priv->manager_name) + mcd_storage_dup_string (storage, name, MC_ACCOUNTS_KEY_MANAGER); + + if (priv->manager_name == NULL) { - g_warning ("Account '%s' has no manager", account->priv->unique_name); + g_warning ("Account '%s' has no manager", name); goto broken_account; } priv->protocol_name = - g_key_file_get_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_PROTOCOL, NULL); - if (!priv->protocol_name) + mcd_storage_dup_string (storage, name, MC_ACCOUNTS_KEY_PROTOCOL); + + if (priv->protocol_name == NULL) { g_warning ("Account has no protocol"); goto broken_account; } - priv->object_path = g_strconcat (MC_ACCOUNT_DBUS_OBJECT_BASE, - priv->unique_name, NULL); + priv->object_path = g_strconcat (MC_ACCOUNT_DBUS_OBJECT_BASE, name, NULL); if (!priv->always_on) { priv->enabled = - g_key_file_get_boolean (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_ENABLED, NULL); + mcd_storage_get_boolean (storage, name, MC_ACCOUNTS_KEY_ENABLED); priv->connect_automatically = - g_key_file_get_boolean (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_CONNECT_AUTOMATICALLY, - NULL); + mcd_storage_get_boolean (storage, name, + MC_ACCOUNTS_KEY_CONNECT_AUTOMATICALLY); } priv->has_been_online = - g_key_file_get_boolean (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_HAS_BEEN_ONLINE, NULL); + mcd_storage_get_boolean (storage, name, MC_ACCOUNTS_KEY_HAS_BEEN_ONLINE); /* load the automatic presence */ priv->auto_presence_type = - g_key_file_get_integer (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AUTO_PRESENCE_TYPE, NULL); + mcd_storage_get_integer (storage, name, + MC_ACCOUNTS_KEY_AUTO_PRESENCE_TYPE); /* If invalid or something, force it to AVAILABLE - we want the auto * presence type to be an online status */ @@ -2909,16 +2678,14 @@ mcd_account_setup (McdAccount *account) { g_free (priv->auto_presence_status); priv->auto_presence_status = - g_key_file_get_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AUTO_PRESENCE_STATUS, - NULL); + mcd_storage_dup_string (storage, name, + MC_ACCOUNTS_KEY_AUTO_PRESENCE_STATUS); } g_free (priv->auto_presence_message); priv->auto_presence_message = - g_key_file_get_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AUTO_PRESENCE_MESSAGE, - NULL); + mcd_storage_dup_string (storage, name, + MC_ACCOUNTS_KEY_AUTO_PRESENCE_MESSAGE); /* check the manager */ if (!priv->manager && !load_manager (account)) @@ -2952,13 +2719,16 @@ set_property (GObject *obj, guint prop_id, switch (prop_id) { - case PROP_ACCOUNT_MANAGER: - g_assert (priv->account_manager == NULL); - /* don't keep a reference to the account_manager: we can safely assume - * its lifetime is longer than the McdAccount's */ - priv->account_manager = g_value_get_object (val); + case PROP_STORAGE: + g_assert (priv->storage == NULL); + priv->storage = g_value_dup_object (val); break; + case PROP_DBUS_DAEMON: + g_assert (priv->dbus_daemon == NULL); + priv->dbus_daemon = g_value_dup_object (val); + break; + case PROP_NAME: g_assert (priv->unique_name == NULL); priv->unique_name = g_value_dup_string (val); @@ -2993,8 +2763,7 @@ get_property (GObject *obj, guint prop_id, switch (prop_id) { case PROP_DBUS_DAEMON: - g_value_set_object - (val, mcd_account_manager_get_dbus_daemon (priv->account_manager)); + g_value_set_object (val, priv->dbus_daemon); break; case PROP_NAME: g_value_set_string (val, priv->unique_name); @@ -3076,8 +2845,9 @@ _mcd_account_dispose (GObject *object) } tp_clear_object (&priv->manager); - tp_clear_object (&priv->storage_plugin); + tp_clear_object (&priv->storage); + tp_clear_object (&priv->dbus_daemon); _mcd_account_set_connection_context (self, NULL); _mcd_account_set_connection (self, NULL); @@ -3097,7 +2867,8 @@ _mcd_account_constructor (GType type, guint n_params, priv = account->priv; g_return_val_if_fail (account != NULL, NULL); - if (G_UNLIKELY (!priv->account_manager || !priv->unique_name)) + + if (G_UNLIKELY (!priv->storage || !priv->unique_name)) { g_object_unref (account); return NULL; @@ -3142,12 +2913,13 @@ mcd_account_class_init (McdAccountClass * klass) g_object_class_install_property (object_class, PROP_DBUS_DAEMON, g_param_spec_object ("dbus-daemon", "DBus daemon", "DBus daemon", - TP_TYPE_DBUS_DAEMON, G_PARAM_READABLE)); + TP_TYPE_DBUS_DAEMON, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property - (object_class, PROP_ACCOUNT_MANAGER, - g_param_spec_object ("account-manager", "account-manager", - "account-manager", MCD_TYPE_ACCOUNT_MANAGER, + (object_class, PROP_STORAGE, + g_param_spec_object ("storage", "storage", + "storage", MCD_TYPE_STORAGE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property @@ -3234,26 +3006,30 @@ McdAccount * mcd_account_new (McdAccountManager *account_manager, const gchar *name) { gpointer *obj; + McdStorage *storage = mcd_account_manager_get_storage (account_manager); + TpDBusDaemon *dbus = mcd_account_manager_get_dbus_daemon (account_manager); + obj = g_object_new (MCD_TYPE_ACCOUNT, - "account-manager", account_manager, + "storage", storage, + "dbus-daemon", dbus, "name", name, NULL); return MCD_ACCOUNT (obj); } -/** - * mcd_account_get_account_manager: - * @account: the #McdAccount. - * - * Returns: the #McdAccountManager. - */ -McdAccountManager * -mcd_account_get_account_manager (McdAccount *account) +McdStorage * +_mcd_account_get_storage (McdAccount *account) { - g_return_val_if_fail (MCD_IS_ACCOUNT (account), NULL); - return account->priv->account_manager; + return account->priv->storage; +} + +TpDBusDaemon * +mcd_account_get_dbus_daemon (McdAccount *account) +{ + return account->priv->dbus_daemon; } + /* * mcd_account_is_valid: * @account: the #McdAccount. @@ -3586,21 +3362,21 @@ _mcd_account_set_normalized_name (McdAccount *account, const gchar *name) { McdAccountPrivate *priv = account->priv; GValue value = { 0, }; + const gchar *account_name = mcd_account_get_unique_name (account); DEBUG ("called (%s)", name); - if (name) - g_key_file_set_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_NORMALIZED_NAME, name); - else - g_key_file_remove_key (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_NORMALIZED_NAME, NULL); - - mcd_account_manager_write_conf_async (priv->account_manager, account, NULL, - NULL); g_value_init (&value, G_TYPE_STRING); g_value_set_static_string (&value, name); - mcd_account_changed_property (account, "NormalizedName", &value); + + mcd_storage_set_value (priv->storage, + account_name, + MC_ACCOUNTS_KEY_NORMALIZED_NAME, + &value, FALSE); + mcd_storage_commit (priv->storage, account_name); + mcd_account_changed_property (account, MC_ACCOUNTS_KEY_NORMALIZED_NAME, + &value); + g_value_unset (&value); } @@ -3608,35 +3384,37 @@ gchar * mcd_account_get_normalized_name (McdAccount *account) { McdAccountPrivate *priv = account->priv; + const gchar *account_name = mcd_account_get_unique_name (account); - return g_key_file_get_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_NORMALIZED_NAME, NULL); + return mcd_storage_dup_string (priv->storage, + account_name, + MC_ACCOUNTS_KEY_NORMALIZED_NAME); } void _mcd_account_set_avatar_token (McdAccount *account, const gchar *token) { McdAccountPrivate *priv = account->priv; + const gchar *account_name = mcd_account_get_unique_name (account); DEBUG ("called (%s)", token); - if (token) - g_key_file_set_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AVATAR_TOKEN, token); - else - g_key_file_remove_key (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AVATAR_TOKEN, NULL); + mcd_storage_set_string (priv->storage, + account_name, + MC_ACCOUNTS_KEY_AVATAR_TOKEN, + token, FALSE); - mcd_account_manager_write_conf_async (priv->account_manager, account, NULL, - NULL); + mcd_storage_commit (priv->storage, account_name); } gchar * _mcd_account_get_avatar_token (McdAccount *account) { McdAccountPrivate *priv = account->priv; + const gchar *account_name = mcd_account_get_unique_name (account); - return g_key_file_get_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AVATAR_TOKEN, NULL); + return mcd_storage_dup_string (priv->storage, + account_name, + MC_ACCOUNTS_KEY_AVATAR_TOKEN); } gboolean @@ -3645,6 +3423,7 @@ _mcd_account_set_avatar (McdAccount *account, const GArray *avatar, GError **error) { McdAccountPrivate *priv = MCD_ACCOUNT_PRIV (account); + const gchar *account_name = mcd_account_get_unique_name (account); gchar *data_dir, *filename; DEBUG ("called"); @@ -3672,25 +3451,35 @@ _mcd_account_set_avatar (McdAccount *account, const GArray *avatar, } g_free (filename); - if (mime_type) - g_key_file_set_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AVATAR_MIME, mime_type); + if (mime_type != NULL) + mcd_storage_set_string (priv->storage, + account_name, + MC_ACCOUNTS_KEY_AVATAR_MIME, + mime_type, FALSE); if (token) { gchar *prev_token; prev_token = _mcd_account_get_avatar_token (account); - g_key_file_set_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AVATAR_TOKEN, token); + + mcd_storage_set_string (priv->storage, + account_name, + MC_ACCOUNTS_KEY_AVATAR_TOKEN, + token, FALSE); + if (!prev_token || strcmp (prev_token, token) != 0) tp_svc_account_interface_avatar_emit_avatar_changed (account); + g_free (prev_token); } else { - g_key_file_remove_key (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AVATAR_TOKEN, NULL); + mcd_storage_set_value (priv->storage, + account_name, + MC_ACCOUNTS_KEY_AVATAR_TOKEN, + NULL, FALSE); + /* this is a no-op if the connection doesn't support avatars */ if (priv->connection != NULL) { @@ -3698,8 +3487,8 @@ _mcd_account_set_avatar (McdAccount *account, const GArray *avatar, } } - mcd_account_manager_write_conf_async (priv->account_manager, account, NULL, - NULL); + mcd_storage_commit (priv->storage, account_name); + return TRUE; } @@ -3708,11 +3497,12 @@ _mcd_account_get_avatar (McdAccount *account, GArray **avatar, gchar **mime_type) { McdAccountPrivate *priv = MCD_ACCOUNT_PRIV (account); + const gchar *account_name = mcd_account_get_unique_name (account); gchar *filename; if (mime_type != NULL) - *mime_type = g_key_file_get_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_AVATAR_MIME, NULL); + *mime_type = mcd_storage_dup_string (priv->storage, account_name, + MC_ACCOUNTS_KEY_AVATAR_MIME); if (avatar == NULL) return; @@ -3761,9 +3551,10 @@ gchar * mcd_account_get_alias (McdAccount *account) { McdAccountPrivate *priv = MCD_ACCOUNT_PRIV (account); + const gchar *account_name = mcd_account_get_unique_name (account); - return g_key_file_get_string (priv->keyfile, priv->unique_name, - MC_ACCOUNTS_KEY_ALIAS, NULL); + return mcd_storage_dup_string (priv->storage, account_name, + MC_ACCOUNTS_KEY_ALIAS); } void @@ -3853,6 +3644,7 @@ clear_register_dup_params_cb (McdAccount *self, if (tp_asv_get_boolean (params, "register", NULL)) { GValue value = { 0 }; + const gchar *account_name = mcd_account_get_unique_name (self); _mcd_account_set_parameter (self, "register", NULL, NULL, NULL); @@ -3863,8 +3655,7 @@ clear_register_dup_params_cb (McdAccount *self, mcd_account_changed_property (self, "Parameters", &value); g_value_unset (&value); - mcd_account_manager_write_conf_async (self->priv->account_manager, - self, NULL, NULL); + mcd_storage_commit (self->priv->storage, account_name); } else { @@ -4030,8 +3821,7 @@ _mcd_account_tp_connection_changed (McdAccount *account, mcd_account_changed_property (account, "Connection", &value); g_value_unset (&value); - _mcd_account_manager_store_account_connections - (account->priv->account_manager); + _mcd_storage_store_connections (account->priv->storage); } McdConnection * @@ -4360,17 +4150,19 @@ _mcd_account_set_has_been_online (McdAccount *account) if (!account->priv->has_been_online) { GValue value = { 0 }; - - g_key_file_set_boolean (account->priv->keyfile, - account->priv->unique_name, - MC_ACCOUNTS_KEY_HAS_BEEN_ONLINE, TRUE); - account->priv->has_been_online = TRUE; - mcd_account_manager_write_conf_async (account->priv->account_manager, - account, NULL, NULL); + const gchar *account_name = mcd_account_get_unique_name (account); g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, TRUE); - mcd_account_changed_property (account, "HasBeenOnline", &value); + + mcd_storage_set_value (account->priv->storage, + account_name, + MC_ACCOUNTS_KEY_HAS_BEEN_ONLINE, + &value, FALSE); + 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, + &value); g_value_unset (&value); } } diff --git a/src/mcd-account.h b/src/mcd-account.h index 9e3789cc..0d7b6100 100644 --- a/src/mcd-account.h +++ b/src/mcd-account.h @@ -43,6 +43,7 @@ typedef struct _McdAccountPresencePrivate McdAccountPresencePrivate; #include "mcd-connection.h" #include "mcd-account-manager.h" +#include "mcd-storage.h" struct _McdAccount { @@ -102,7 +103,7 @@ GType mcd_account_get_type (void); McdAccount *mcd_account_new (McdAccountManager *account_manager, const gchar *name); -McdAccountManager *mcd_account_get_account_manager (McdAccount *account); +TpDBusDaemon *mcd_account_get_dbus_daemon (McdAccount *account); void mcd_account_delete (McdAccount *account, McdAccountDeleteCb callback, gpointer user_data); diff --git a/src/mcd-storage-priv.h b/src/mcd-storage-priv.h new file mode 100644 index 00000000..1b550d8f --- /dev/null +++ b/src/mcd-storage-priv.h @@ -0,0 +1,35 @@ +/* Mission Control storage API - interface which provides access to account + * parameter/setting storage + * + * Copyright © 2010 Nokia Corporation + * Copyright © 2010 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <glib-object.h> +#include <mission-control-plugins/mission-control-plugins.h> +#include "mcd-storage.h" + +#ifndef MCD_STORAGE_PRIV_H +#define MCD_STORAGE_PRIV_H + +G_BEGIN_DECLS + +G_GNUC_INTERNAL void _mcd_storage_store_connections (McdStorage *storage); + +G_END_DECLS + +#endif /* MCD_STORAGE_H */ diff --git a/src/mcd-storage.c b/src/mcd-storage.c new file mode 100644 index 00000000..7ca0feff --- /dev/null +++ b/src/mcd-storage.c @@ -0,0 +1,388 @@ +/* Mission Control storage API - interface which provides access to account + * parameter/setting storage + * + * Copyright © 2010 Nokia Corporation + * Copyright © 2010 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mcd-storage-priv.h" +#include "mcd-master.h" +#include "mcd-account-manager-priv.h" + +GType +mcd_storage_get_type (void) +{ + static gsize once = 0; + static GType type = 0; + + if (g_once_init_enter (&once)) + { + static const GTypeInfo info = { + sizeof (McdStorageIface), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, /* instance_size */ + 0, /* n_preallocs */ + NULL, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static (G_TYPE_INTERFACE, "McdStorage", &info, 0); + g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); + g_once_init_leave (&once, 1); + } + + return type; +} + +/** + * 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 + * @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. + * + * 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_string (McdStorage *storage, + const gchar *account, + const gchar *key, + const gchar *value, + gboolean secret) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_return_val_if_fail (account != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (iface->set_string != NULL, FALSE); + + return iface->set_string (storage, account, key, value, secret); +} + +/** + * mcd_storage_set_value: + * @storage: An object implementing the #McdStorage interface + * @account: the unique name of an account + * @key: the key (name) of the parameter or setting + * @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. + * + * 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_value (McdStorage *storage, + const gchar *account, + const gchar *key, + const GValue *value, + gboolean secret) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_return_val_if_fail (account != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (iface->set_value != NULL, FALSE); + + return iface->set_value (storage, account, key, value, secret); +} + +/** + * mcd_storage_commit: + * @storage: An object implementing the #McdStorage interface + * @account: the unique name of an account + * + * Sync the long term storage (whatever it might be) with the current + * state of our internal cache. + */ +void +mcd_storage_commit (McdStorage *storage, const gchar *account) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_return_if_fail (iface->commit != NULL); + + iface->commit (storage, account); +} + +/** + * mcd_storage_load: + * @storage: An object implementing the #McdStorage interface + * + * Load the long term account settings storage into our internal cache. + * Should only really be called during startup, ie before our DBus names + * have been claimed and other people might be relying on responses from us. + */ +void +mcd_storage_load (McdStorage *storage) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_return_if_fail (iface->load != NULL); + + iface->load (storage); +} + +/** + * mcd_storage_dup_accounts: + * @storage: An object implementing the #McdStorage interface + * @n: place for the number of accounts to be written to (or %NULL) + * + * Returns: a newly allocated GStrv containing the unique account names, + * which must be freed by the caller with g_strfreev(). + **/ +GStrv +mcd_storage_dup_accounts (McdStorage *storage, gsize *n) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_return_val_if_fail (iface->dup_accounts != NULL, NULL); + + return iface->dup_accounts (storage, n); +} + +/** + * mcd_storage_dup_settings: + * @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) + * + * Returns: a newly allocated GStrv containing the names of all the + * settings or parameters currently stored for @account. Must be + * freed by the caller with g_strfreev(). + **/ +GStrv +mcd_storage_dup_settings (McdStorage *storage, const gchar *account, gsize *n) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_return_val_if_fail (account != NULL, NULL); + g_return_val_if_fail (iface->dup_settings != NULL, NULL); + + return iface->dup_settings (storage, account, n); +} + +/** + * 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 + * + * Returns: a newly allocated gchar * which must be freed with g_free(). + **/ +gchar * +mcd_storage_dup_string (McdStorage *storage, + const gchar *account, + const gchar *key) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_assert (iface->dup_string != NULL); + g_return_val_if_fail (account != NULL, NULL); + + return iface->dup_string (storage, account, key); +} + +/** + * mcd_storage_dup_value: + * @storage: An object implementing the #McdStorage interface + * @account: unique name of the account + * @key: name of the setting to be retrieved + * @type: the type of #GValue to retrieve + * @error: a place to store any #GError<!-- -->s that occur + * + * Returns: a newly allocated #GValue of type @type, whihc should be freed + * with tp_g_value_slice_free() or g_slice_free() depending on whether the + * the value itself should be freed (the former frees everything, the latter + * only the #GValue container. + * + * If @error is set, but a non-%NULL value was returned, this indicates + * that no value for the @key was found for @account, and the default + * value for @type has been returned. + **/ +GValue * +mcd_storage_dup_value (McdStorage *storage, + const gchar *account, + const gchar *key, + GType type, + GError **error) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_assert (iface->dup_value != NULL); + g_return_val_if_fail (account != NULL, NULL); + + return iface->dup_value (storage, account, key, type, error); +} + +/** + * 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 + * + * Returns: a #gboolean. Unset/unparseable values are returned as %FALSE + **/ +gboolean +mcd_storage_get_boolean (McdStorage *storage, + const gchar *account, + const gchar *key) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_assert (iface->get_boolean != NULL); + g_return_val_if_fail (account != NULL, FALSE); + + return iface->get_boolean (storage, account, key); +} + +/** + * 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 + * + * Returns: a #gint. Unset or non-numeric values are returned as 0 + **/ +gint +mcd_storage_get_integer (McdStorage *storage, + const gchar *account, + const gchar *key) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_assert (iface->get_integer != NULL); + g_return_val_if_fail (account != NULL, 0); + + return iface->get_integer (storage, account, key); +} + + +/** + * mcd_storage_has_value: + * @storage: An object implementing the #McdStorage interface + * @account: unique name of the account + * @key: name of the setting to be retrieved + * + * Returns: a #gboolean: %TRUE if the setting is present in the store, + * %FALSE otherwise. + **/ +gboolean +mcd_storage_has_value (McdStorage *storage, + const gchar *account, + const gchar *key) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_assert (iface->has_value != NULL); + g_return_val_if_fail (account != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + return iface->has_value (storage, account, key); +} + +/** + * mcd_storage_get_plugin: + * @storage: An object implementing the #McdStorage interface + * @account: unique name of the account + * + * Returns: the #McpAccountStorage object which is handling the account, + * if any (if a new account has not yet been flushed to storage this can + * be %NULL). + * + * Plugins are kept in permanent storage and can never be unloaded, so + * the returned pointer need not be reffed or unreffed. (Indeed, it's + * probably safer not to) + **/ +McpAccountStorage * +mcd_storage_get_plugin (McdStorage *storage, const gchar *account) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_assert (iface->get_storage_plugin != NULL); + g_return_val_if_fail (account != NULL, NULL); + + return iface->get_storage_plugin (storage, account); +} + +/** + * mcd_storage_delete_account: + * @storage: An object implementing the #McdStorage interface + * @account: unique name of the account + * + * Removes an account's settings from long term storage. + * This does not handle any of the other logic to do with removing + * accounts, it merely ensures that no trace of the account remains + * in long term storage once mcd_storage_commit() has been called. + */ +void +mcd_storage_delete_account (McdStorage *storage, const gchar *account) +{ + McdStorageIface *iface = MCD_STORAGE_GET_IFACE (storage); + + g_assert (iface != NULL); + g_assert (iface->delete_account != NULL); + g_return_if_fail (account != NULL); + + iface->delete_account (storage, account); +} + +void +_mcd_storage_store_connections (McdStorage *storage) +{ + McdMaster *master = mcd_master_get_default (); + McdAccountManager *account_manager = NULL; + + g_object_get (master, "account-manager", &account_manager, NULL); + + if (account_manager != NULL) + { + _mcd_account_manager_store_account_connections (account_manager); + g_object_unref (account_manager); + } +} diff --git a/src/mcd-storage.h b/src/mcd-storage.h new file mode 100644 index 00000000..e16a7192 --- /dev/null +++ b/src/mcd-storage.h @@ -0,0 +1,151 @@ +/* Mission Control storage API - interface which provides access to account + * parameter/setting storage + * + * Copyright © 2010 Nokia Corporation + * Copyright © 2010 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <glib-object.h> +#include <mission-control-plugins/mission-control-plugins.h> + +#ifndef MCD_STORAGE_H +#define MCD_STORAGE_H + +G_BEGIN_DECLS + +typedef struct _McdStorage McdStorage; +typedef struct _McdStorageIface McdStorageIface; + +struct _McdStorageIface { + GTypeInterface parent; + + void (*load) (McdStorage *storage); + + GStrv (*dup_accounts) (McdStorage *storage, gsize *n); + + GStrv (*dup_settings) (McdStorage *storage, const gchar *account, gsize *n); + + gboolean (*set_string) (McdStorage *storage, + const gchar *account, + const gchar *key, + const gchar *value, + gboolean secret); + + gboolean (*set_value) (McdStorage *storage, + const gchar *account, + const gchar *key, + const GValue *value, + gboolean secret); + + void (*delete_account) (McdStorage *storage, + const gchar *account); + + void (*commit) (McdStorage *storage, const gchar *account); + + gchar * (*dup_string) (McdStorage *storage, + const gchar *account, + const gchar *key); + + GValue * (*dup_value) (McdStorage *storage, + const gchar *account, + const gchar *key, + GType type, + GError **error); + + gboolean (*get_boolean) (McdStorage *storage, + const gchar *account, + const gchar *key); + + gint (*get_integer) (McdStorage *storage, + const gchar *account, + const gchar *key); + + gboolean (*has_value) (McdStorage *storage, + const gchar *account, + const gchar *key); + + McpAccountStorage *(*get_storage_plugin) (McdStorage *storage, + const gchar *account); +}; + +#define MCD_TYPE_STORAGE (mcd_storage_get_type ()) + +#define MCD_STORAGE(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), MCD_TYPE_STORAGE, McdStorage)) + +#define MCD_IS_STORAGE(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((o), MCD_TYPE_STORAGE)) + +#define MCD_STORAGE_GET_IFACE(o) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((o), MCD_TYPE_STORAGE, McdStorageIface)) + +GType mcd_storage_get_type (void); + +void mcd_storage_load (McdStorage *storage); + +GStrv mcd_storage_dup_accounts (McdStorage *storage, gsize *n); + +GStrv mcd_storage_dup_settings (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); + +gboolean mcd_storage_set_value (McdStorage *storage, + const gchar *account, + const gchar *key, + const GValue *value, + gboolean secret); + +void mcd_storage_delete_account (McdStorage *storage, const gchar *account); + +void mcd_storage_commit (McdStorage *storage, const gchar *account); + +gchar *mcd_storage_dup_string (McdStorage *storage, + const gchar *account, + const gchar *key); + +gboolean mcd_storage_has_value (McdStorage *storage, + const gchar *account, + const gchar *key); + +GValue *mcd_storage_dup_value (McdStorage *storage, + const gchar *account, + const gchar *key, + GType type, + GError **error); + +gboolean mcd_storage_get_boolean (McdStorage *storage, + const gchar *account, + const gchar *key); + +gint mcd_storage_get_integer (McdStorage *storage, + const gchar *account, + const gchar *key); + +McpAccountStorage * mcd_storage_get_plugin (McdStorage *storage, + const gchar *account); + +G_GNUC_INTERNAL void _mcd_storage_store_connections (McdStorage *storage); + +G_END_DECLS + +#endif /* MCD_STORAGE_H */ diff --git a/src/plugin-account.c b/src/plugin-account.c index 9960e266..cfdc7cb2 100644 --- a/src/plugin-account.c +++ b/src/plugin-account.c @@ -21,13 +21,22 @@ * */ +#include "plugin-loader.h" #include "plugin-account.h" #include "mission-control-plugins/implementation.h" -#include <glib.h> #include <telepathy-glib/util.h> +/* these pseudo-plugins take care of the actual account storage/retrieval */ +#include "mcd-account-manager-default.h" +#if ENABLE_LIBACCOUNTS_SSO +#include "mcd-account-manager-sso.h" +#endif + +static GList *stores = NULL; +static void sort_and_cache_plugins (void); + enum { PROP_DBUS_DAEMON = 1, }; @@ -36,11 +45,15 @@ struct _McdPluginAccountManagerClass { GObjectClass parent; }; +static void storage_iface_init (McdStorageIface *iface, + gpointer unused G_GNUC_UNUSED); + static void plugin_iface_init (McpAccountManagerIface *iface, gpointer unused G_GNUC_UNUSED); G_DEFINE_TYPE_WITH_CODE (McdPluginAccountManager, mcd_plugin_account_manager, \ G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (MCD_TYPE_STORAGE, storage_iface_init); G_IMPLEMENT_INTERFACE (MCP_TYPE_ACCOUNT_MANAGER, plugin_iface_init)) static void @@ -141,7 +154,7 @@ mcd_plugin_account_manager_new () } void -mcd_plugin_account_manager_set_dbus_daemon (McdPluginAccountManager *self, +_mcd_plugin_account_manager_set_dbus_daemon (McdPluginAccountManager *self, TpDBusDaemon *dbusd) { GValue value = { 0 }; @@ -247,6 +260,586 @@ unique_name (const McpAccountManager *ma, return NULL; } +/* sort in descending order of priority (ie higher prio => earlier in list) */ +static gint +account_storage_cmp (gconstpointer a, gconstpointer b) +{ + gint pa = mcp_account_storage_priority (a); + gint pb = mcp_account_storage_priority (b); + + if (pa > pb) return -1; + if (pa < pb) return 1; + + return 0; +} + +static void +add_libaccount_plugin_if_enabled (void) +{ +#if ENABLE_LIBACCOUNTS_SSO + McdAccountManagerSso *sso_plugin = mcd_account_manager_sso_new (); + + stores = g_list_insert_sorted (stores, sso_plugin, account_storage_cmp); +#endif +} + +static void +sort_and_cache_plugins () +{ + const GList *p; + McdAccountManagerDefault *default_plugin = NULL; + static gboolean plugins_cached = FALSE; + + /* not guaranteed to have been called, but idempotent: */ + _mcd_plugin_loader_init (); + + /* insert the default storage plugin into the sorted plugin list */ + default_plugin = mcd_account_manager_default_new (); + stores = g_list_insert_sorted (stores, default_plugin, account_storage_cmp); + + /* now poke the pseudo-plugins into the sorted GList of storage plugins */ + add_libaccount_plugin_if_enabled (); + + for (p = mcp_list_objects(); p != NULL; p = g_list_next (p)) + { + if (MCP_IS_ACCOUNT_STORAGE (p->data)) + { + McpAccountStorage *plugin = g_object_ref (p->data); + + stores = g_list_insert_sorted (stores, plugin, account_storage_cmp); + } + } + + for (p = stores; p != NULL; p = g_list_next (p)) + { + McpAccountStorage *plugin = p->data; + + DEBUG ("found plugin %s [%s; priority %d]\n%s", + mcp_account_storage_name (plugin), + g_type_name (G_TYPE_FROM_INSTANCE (plugin)), + mcp_account_storage_priority (plugin), + mcp_account_storage_description (plugin)); + } + + plugins_cached = TRUE; +} + +void +_mcd_plugin_account_manager_connect_signal (const gchar *signame, + GCallback func, + gpointer user_data) +{ + GList *p; + + for (p = stores; p != NULL; p = g_list_next (p)) + { + McpAccountStorage *plugin = p->data; + + DEBUG ("connecting handler to %s plugin signal %s ", + mcp_account_storage_name (plugin), signame); + g_signal_connect (plugin, signame, func, user_data); + } +} + +/* implement the McdStorage interface */ +static void +_storage_load (McdStorage *self) +{ + McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self); + GList *store = NULL; + + sort_and_cache_plugins (); + + store = g_list_last (stores); + + /* fetch accounts stored in plugins, in reverse priority so higher prio * + * plugins can overwrite lower prio ones' account data */ + while (store != NULL) + { + GList *account; + McpAccountStorage *plugin = store->data; + GList *stored = mcp_account_storage_list (plugin, ma); + const gchar *pname = mcp_account_storage_name (plugin); + const gint prio = mcp_account_storage_priority (plugin); + + DEBUG ("listing from plugin %s [prio: %d]", pname, prio); + for (account = stored; account != NULL; account = g_list_next (account)) + { + gchar *name = account->data; + + DEBUG ("fetching %s from plugin %s [prio: %d]", name, pname, prio); + mcp_account_storage_get (plugin, ma, name, NULL); + + g_free (name); + } + + /* already freed the contents, just need to free the list itself */ + g_list_free (stored); + store = g_list_previous (store); + } +} + +static GStrv +_storage_dup_accounts (McdStorage *storage, gsize *n) +{ + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + + return g_key_file_get_groups (self->keyfile, n); +} + +static GStrv +_storage_dup_settings (McdStorage *storage, const gchar *account, gsize *n) +{ + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + + return g_key_file_get_keys (self->keyfile, account, n, NULL); +} + +static McpAccountStorage * +_storage_get_plugin (McdStorage *storage, const gchar *account) +{ + GList *store = stores; + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self); + McpAccountStorage *owner = NULL; + + for (; store != NULL && owner == NULL; store = g_list_next (store)) + { + McpAccountStorage *plugin = store->data; + + if (mcp_account_storage_get (plugin, ma, account, "manager")) + owner = plugin; + } + + return owner; +} + +static gchar * +_storage_dup_string (McdStorage *storage, + const gchar *account, + const gchar *key) +{ + gchar *value = NULL; + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + + value = g_key_file_get_string (self->keyfile, account, key, NULL); + + return value; +} + +static gboolean +_storage_has_value (McdStorage *storage, + const gchar *account, + const gchar *key) +{ + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + + return g_key_file_has_key (self->keyfile, account, key, NULL); +} + +static GValue * +_storage_dup_value (McdStorage *storage, + const gchar *account, + const gchar *key, + GType type, + GError **error) +{ + GValue *value = NULL; + gchar *v_string = NULL; + gint64 v_int = 0; + guint64 v_uint = 0; + gboolean v_bool = FALSE; + double v_double = 0.0; + GKeyFile *keyfile = MCD_PLUGIN_ACCOUNT_MANAGER (storage)->keyfile; + + switch (type) + { + case G_TYPE_STRING: + v_string = g_key_file_get_string (keyfile, account, key, error); + value = tp_g_value_slice_new_take_string (v_string); + break; + + case G_TYPE_INT: + v_int = g_key_file_get_integer (keyfile, account, key, error); + value = tp_g_value_slice_new_int (v_int); + break; + + case G_TYPE_INT64: + v_int = tp_g_key_file_get_int64 (keyfile, account, key, error); + value = tp_g_value_slice_new_int64 (v_int); + break; + + case G_TYPE_UINT: + v_uint = tp_g_key_file_get_uint64 (keyfile, account, key, error); + + if (v_uint > 0xFFFFFFFFU) + g_set_error (error, MCD_ACCOUNT_ERROR, + MCD_ACCOUNT_ERROR_GET_PARAMETER, + "Integer is out of range"); + else + value = tp_g_value_slice_new_uint (v_uint); + break; + + case G_TYPE_UCHAR: + v_int = g_key_file_get_integer (keyfile, account, key, error); + + if (v_int < 0 || v_int > 0xFF) + { + g_set_error (error, MCD_ACCOUNT_ERROR, + MCD_ACCOUNT_ERROR_GET_PARAMETER, + "Integer is out of range"); + } + else + { + value = tp_g_value_slice_new (G_TYPE_UCHAR); + g_value_set_uchar (value, v_int); + } + break; + + case G_TYPE_UINT64: + v_uint = tp_g_key_file_get_uint64 (keyfile, account, key, error); + value = tp_g_value_slice_new_uint64 (v_uint); + break; + + case G_TYPE_BOOLEAN: + v_bool = g_key_file_get_boolean (keyfile, account, key, error); + value = tp_g_value_slice_new_boolean (v_bool); + break; + + case G_TYPE_DOUBLE: + v_double = g_key_file_get_double (keyfile, account, key, error); + value = tp_g_value_slice_new_double (v_double); + break; + + default: + if (type == G_TYPE_STRV) + { + gchar **v = + g_key_file_get_string_list (keyfile, account, key, NULL, error); + + value = tp_g_value_slice_new_take_boxed (G_TYPE_STRV, v); + } + else if (type == DBUS_TYPE_G_OBJECT_PATH) + { + v_string = g_key_file_get_string (keyfile, account, key, NULL); + + if (v_string == NULL) + { + g_set_error (error, MCD_ACCOUNT_ERROR, + MCD_ACCOUNT_ERROR_GET_PARAMETER, + "Invalid object path NULL"); + } + else if (!tp_dbus_check_valid_object_path (v_string, NULL)) + { + g_set_error (error, MCD_ACCOUNT_ERROR, + MCD_ACCOUNT_ERROR_GET_PARAMETER, + "Invalid object path %s", v_string); + g_free (v_string); + } + else + { + value = tp_g_value_slice_new_take_object_path (v_string); + } + } + else + { + gchar *message = + g_strdup_printf ("cannot get property %s, unknown type %s", + key, g_type_name (type)); + + g_warning ("%s: %s", G_STRFUNC, message); + g_set_error (error, MCD_ACCOUNT_ERROR, + MCD_ACCOUNT_ERROR_GET_PARAMETER, + "%s", message); + g_free (message); + } + } + + /* This can return a non-NULL GValue * _and_ a non-NULL GError *, * + * indicating a value was not found and the default for that type * + * (eg 0 for integers) has been returned - this matches the behaviour * + * of the old code that this function replaces. If changing this, make * + * sure all our callers are suitable updated */ + + return value; +} + +static gboolean +_storage_get_boolean (McdStorage *storage, + const gchar *account, + const gchar *key) +{ + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + + return g_key_file_get_boolean (self->keyfile, account, key, NULL); +} + +static gint +_storage_get_integer (McdStorage *storage, + const gchar *account, + const gchar *key) +{ + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + + return g_key_file_get_integer (self->keyfile, account, key, NULL); +} + +static void +update_storage (McdPluginAccountManager *self, + const gchar *account, + const gchar *key) +{ + GList *store; + gboolean done = FALSE; + McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self); + gchar *val = NULL; + + /* 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) + done = TRUE; + + for (store = stores; store != NULL; store = g_list_next (store)) + { + McpAccountStorage *plugin = store->data; + const gchar *pn = mcp_account_storage_name (plugin); + + if (done) + { + DEBUG ("MCP:%s -> delete %s.%s", pn, account, key); + mcp_account_storage_delete (plugin, ma, account, key); + } + else + { + done = mcp_account_storage_set (plugin, ma, account, key, val); + DEBUG ("MCP:%s -> %s %s.%s", + pn, done ? "store" : "ignore", account, key); + } + } +} + +static gboolean +_storage_set_string (McdStorage *storage, + const gchar *account, + const gchar *key, + const gchar *val, + gboolean secret) +{ + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + gboolean updated = FALSE; + gchar *old = g_key_file_get_string (self->keyfile, account, key, NULL); + + if (val == NULL) + g_key_file_remove_key (self->keyfile, account, key, NULL); + else + g_key_file_set_string (self->keyfile, account, key, val); + + if (tp_strdiff (old, val)) + { + if (secret) + { + McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self); + + mcp_account_manager_parameter_make_secret (ma, account, key); + } + + update_storage (self, account, key); + updated = TRUE; + } + + g_free (old); + + return updated; +} + +static gboolean +_storage_set_value (McdStorage *storage, + const gchar *name, + const gchar *key, + const GValue *value, + gboolean secret) +{ + if (value == NULL) + { + return _storage_set_string (storage, name, key, NULL, secret); + } + else + { + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + gboolean updated = FALSE; + gchar *old = g_key_file_get_value (self->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_value_get_string (value)); + break; + + case G_TYPE_UINT: + buf = g_strdup_printf ("%u", g_value_get_uint (value)); + break; + + case G_TYPE_INT: + g_key_file_set_integer (self->keyfile, name, key, + g_value_get_int (value)); + break; + + case G_TYPE_BOOLEAN: + g_key_file_set_boolean (self->keyfile, name, key, + g_value_get_boolean (value)); + break; + + case G_TYPE_UCHAR: + buf = g_strdup_printf ("%u", g_value_get_uchar (value)); + break; + + case G_TYPE_UINT64: + buf = g_strdup_printf ("%" G_GUINT64_FORMAT, + g_value_get_uint64 (value)); + break; + + case G_TYPE_INT64: + buf = g_strdup_printf ("%" G_GINT64_FORMAT, + g_value_get_int64 (value)); + break; + + case G_TYPE_DOUBLE: + g_key_file_set_double (self->keyfile, name, key, + g_value_get_double (value)); + break; + + default: + if (G_VALUE_HOLDS (value, G_TYPE_STRV)) + { + gchar **strings = g_value_get_boxed (value); + + g_key_file_set_string_list (self->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_value_get_boxed (value)); + } + else + { + g_warning ("Unexpected param type %s", + G_VALUE_TYPE_NAME (value)); + return FALSE; + } + } + + if (buf != NULL) + g_key_file_set_string (self->keyfile, name, key, buf); + + new = g_key_file_get_value (self->keyfile, name, key, NULL); + + if (tp_strdiff (old, new)) + { + if (secret) + { + McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self); + + mcp_account_manager_parameter_make_secret (ma, name, key); + } + + update_storage (self, name, key); + updated = TRUE; + } + + g_free (buf); + g_free (old); + + return updated; + } +} + +static void +_storage_delete_account (McdStorage *storage, const gchar *account) +{ + GList *store; + McdPluginAccountManager *self = MCD_PLUGIN_ACCOUNT_MANAGER (storage); + McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self); + + g_key_file_remove_group (self->keyfile, account, NULL); + + for (store = stores; store != NULL; store = g_list_next (store)) + { + McpAccountStorage *plugin = store->data; + + mcp_account_storage_delete (plugin, ma, account, NULL); + } +} + +static void +_storage_commit (McdStorage *self, const gchar *account) +{ + GList *store; + McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self); + + for (store = stores; store != NULL; store = g_list_next (store)) + { + McpAccountStorage *plugin = store->data; + const gchar *pname = mcp_account_storage_name (plugin); + + if (account != NULL) + { + DEBUG ("flushing plugin %s %s to long term storage", pname, account); + mcp_account_storage_commit_one (plugin, ma, account); + } + else + { + DEBUG ("flushing plugin %s to long term storage", pname); + mcp_account_storage_commit (plugin, ma); + } + } +} + +void +_mcd_plugin_account_manager_ready (McdPluginAccountManager *self) +{ + GList *store; + McpAccountManager *ma = MCP_ACCOUNT_MANAGER (self); + + for (store = stores; store != NULL; store = g_list_next (store)) + { + McpAccountStorage *plugin = store->data; + const gchar *plugin_name = mcp_account_storage_name (plugin); + + DEBUG ("Unblocking async account ops by %s", plugin_name); + mcp_account_storage_ready (plugin, ma); + } +} + +static void +storage_iface_init (McdStorageIface *iface, + gpointer unused G_GNUC_UNUSED) +{ + iface->load = _storage_load; + iface->dup_accounts = _storage_dup_accounts; + iface->dup_settings = _storage_dup_settings; + + iface->delete_account = _storage_delete_account; + iface->set_string = _storage_set_string; + iface->set_value = _storage_set_value; + iface->commit = _storage_commit; + + iface->has_value = _storage_has_value; + iface->get_storage_plugin = _storage_get_plugin; + iface->dup_value = _storage_dup_value; + iface->dup_string = _storage_dup_string; + iface->get_integer = _storage_get_integer; + iface->get_boolean = _storage_get_boolean; +} static void plugin_iface_init (McpAccountManagerIface *iface, diff --git a/src/plugin-account.h b/src/plugin-account.h index 5c2c3342..27fb731e 100644 --- a/src/plugin-account.h +++ b/src/plugin-account.h @@ -64,9 +64,18 @@ G_GNUC_INTERNAL GType mcd_plugin_account_manager_get_type (void); McdPluginAccountManager *mcd_plugin_account_manager_new (void); -void mcd_plugin_account_manager_set_dbus_daemon (McdPluginAccountManager *self, +G_GNUC_INTERNAL +void _mcd_plugin_account_manager_set_dbus_daemon (McdPluginAccountManager *self, TpDBusDaemon *dbusd); +G_GNUC_INTERNAL +void _mcd_plugin_account_manager_ready (McdPluginAccountManager *self); + +G_GNUC_INTERNAL +void _mcd_plugin_account_manager_connect_signal (const gchar *signal, + GCallback func, + gpointer user_data); + G_END_DECLS #endif |