/* * A demonstration plugin that diverts account storage to an alternate location. * * 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 #define DONT_DIVERT "fakecm/fakeprotocol/dontdivert" #define CONFFILE "mcp-test-diverted-account-plugin.conf" #define PLUGIN_NAME "diverted-keyfile" #define PLUGIN_PRIORITY MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_NORMAL #define PLUGIN_DESCRIPTION \ "Test plugin that grabs all accounts it receives (except '" \ DONT_DIVERT "*') and diverts them to '" CONFFILE \ "' in g_get_user_cache_dir () instead of the usual location." #define DEBUG g_debug typedef struct { GObject parent; GKeyFile *keyfile; gboolean save; gboolean loaded; } AccountDiversionPlugin; typedef struct { GObjectClass parent_class; } AccountDiversionPluginClass; GType account_diversion_plugin_get_type (void) G_GNUC_CONST; static void account_storage_iface_init (McpAccountStorageIface *, gpointer); #define ACCOUNT_DIVERSION_PLUGIN(o) \ (G_TYPE_CHECK_INSTANCE_CAST ((o), account_diversion_plugin_get_type (), \ AccountDiversionPlugin)) G_DEFINE_TYPE_WITH_CODE (AccountDiversionPlugin, account_diversion_plugin, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (MCP_TYPE_ACCOUNT_STORAGE, account_storage_iface_init)); static void account_diversion_plugin_init (AccountDiversionPlugin *self) { DEBUG ("account_diversion_plugin_init"); self->keyfile = g_key_file_new (); self->save = FALSE; self->loaded = FALSE; } static void account_diversion_plugin_class_init (AccountDiversionPluginClass *cls) { DEBUG ("account_diversion_plugin_class_init"); } static gchar * _conf_filename (void) { static gchar *file = NULL; if (file == NULL) { const gchar *dir = g_get_user_cache_dir (); file = g_build_path (G_DIR_SEPARATOR_S, dir, CONFFILE, NULL); } return file; } static gboolean _have_config (void) { const gchar *file = _conf_filename (); DEBUG ("checking for %s", file); return g_file_test (file, G_FILE_TEST_EXISTS); } static void _create_config (void) { gchar *file = _conf_filename (); gchar *dir = g_path_get_dirname (file); g_mkdir_with_parents (dir, 0700); g_free (dir); g_file_set_contents (file, "# diverted accounts\n", -1, NULL); DEBUG ("created %s", file); } static gboolean _set (const McpAccountStorage *self, const McpAccountManager *am, const gchar *account, const gchar *key, const gchar *val) { AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self); if (g_str_has_prefix (account, DONT_DIVERT)) return FALSE; adp->save = TRUE; g_key_file_set_value (adp->keyfile, account, key, val); return TRUE; } static gboolean _get (const McpAccountStorage *self, const McpAccountManager *am, const gchar *account, const gchar *key) { AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self); if (key != NULL) { gchar *v = g_key_file_get_value (adp->keyfile, account, key, NULL); if (v == NULL) return FALSE; mcp_account_manager_set_value (am, account, key, v); g_free (v); } else { gsize i; gsize n; GStrv keys = g_key_file_get_keys (adp->keyfile, account, &n, NULL); if (keys == NULL) n = 0; for (i = 0; i < n; i++) { gchar *v = g_key_file_get_value (adp->keyfile, account, keys[i], NULL); if (v != NULL) mcp_account_manager_set_value (am, account, keys[i], v); g_free (v); } g_strfreev (keys); } return TRUE; } static gboolean _delete (const McpAccountStorage *self, const McpAccountManager *am, const gchar *account, const gchar *key) { AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self); if (key == NULL) { if (g_key_file_remove_group (adp->keyfile, account, NULL)) adp->save = TRUE; } else { gsize n; GStrv keys; if (g_key_file_remove_key (adp->keyfile, account, key, NULL)) adp->save = TRUE; keys = g_key_file_get_keys (adp->keyfile, account, &n, NULL); if (keys == NULL || n == 0) g_key_file_remove_group (adp->keyfile, account, NULL); g_strfreev (keys); } return TRUE; } static gboolean _commit (const McpAccountStorage *self, const McpAccountManager *am) { gsize n; gchar *data; AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self); gboolean rval = FALSE; if (!adp->save) return TRUE; if (!_have_config ()) _create_config (); data = g_key_file_to_data (adp->keyfile, &n, NULL); rval = g_file_set_contents (_conf_filename (), data, n, NULL); adp->save = !rval; g_free (data); return rval; } static GList * _list (const McpAccountStorage *self, const McpAccountManager *am) { gsize i; gsize n; GStrv accounts; GList *rval = NULL; AccountDiversionPlugin *adp = ACCOUNT_DIVERSION_PLUGIN (self); if (!_have_config ()) _create_config (); if (!adp->loaded) adp->loaded = g_key_file_load_from_file (adp->keyfile, _conf_filename (), G_KEY_FILE_KEEP_COMMENTS, NULL); accounts = g_key_file_get_groups (adp->keyfile, &n); for (i = 0; i < n; i++) rval = g_list_prepend (rval, g_strdup (accounts[i])); g_strfreev (accounts); return rval; } static void account_storage_iface_init (McpAccountStorageIface *iface, gpointer unused G_GNUC_UNUSED) { mcp_account_storage_iface_set_name (iface, PLUGIN_NAME); mcp_account_storage_iface_set_desc (iface, PLUGIN_DESCRIPTION); mcp_account_storage_iface_set_priority (iface, PLUGIN_PRIORITY); mcp_account_storage_iface_implement_get (iface, _get); mcp_account_storage_iface_implement_set (iface, _set); mcp_account_storage_iface_implement_delete (iface, _delete); mcp_account_storage_iface_implement_commit (iface, _commit); mcp_account_storage_iface_implement_list (iface, _list); } GObject * mcp_plugin_ref_nth_object (guint n) { DEBUG ("Initializing mcp-account-diversion-plugin (n=%u)", n); switch (n) { case 0: return g_object_new (account_diversion_plugin_get_type (), NULL); default: return NULL; } }