diff options
Diffstat (limited to 'src/mcd-account-manager-sso.c')
-rw-r--r-- | src/mcd-account-manager-sso.c | 1745 |
1 files changed, 0 insertions, 1745 deletions
diff --git a/src/mcd-account-manager-sso.c b/src/mcd-account-manager-sso.c deleted file mode 100644 index 186c6368..00000000 --- a/src/mcd-account-manager-sso.c +++ /dev/null @@ -1,1745 +0,0 @@ -/* - * A pseudo-plugin that stores/fetches accounts in/from the SSO via libaccounts - * - * Copyright © 2010-2011 Nokia Corporation - * Copyright © 2010-2011 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 "config.h" -#include "mcd-account-manager-sso.h" -#include "mcd-debug.h" - -#include <telepathy-glib/telepathy-glib.h> - -#include <libaccounts-glib/ag-account.h> -#include <libaccounts-glib/ag-service.h> - -#include <string.h> -#include <ctype.h> - -#define PLUGIN_PRIORITY (MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_KEYRING + 10) -#define PLUGIN_NAME "maemo-libaccounts" -#define PLUGIN_DESCRIPTION \ - "Account storage in the Maemo SSO store via libaccounts-glib API" -#define PLUGIN_PROVIDER "org.maemo.Telepathy.Account.Storage.LibAccounts" - -#define MCPP "param-" -#define AGPP "parameters/" -#define LIBACCT_ID_KEY "libacct-uid" - -#define MC_ENABLED_KEY "Enabled" -#define AG_ENABLED_KEY "enabled" - -#define AG_LABEL_KEY "name" -#define MC_LABEL_KEY "DisplayName" - -#define AG_ACCOUNT_KEY "username" -#define MC_ACCOUNT_KEY "account" -#define PASSWORD_KEY "password" -#define AG_ACCOUNT_ALT_KEY AGPP "account" - -#define MC_CMANAGER_KEY "manager" -#define MC_PROTOCOL_KEY "protocol" -#define MC_IDENTITY_KEY "tmc-uid" - -#define SERVICES_KEY "sso-services" - -#define MC_SERVICE_KEY "Service" - -#define AG_ACCOUNT_WRITE_INTERVAL 5 - -static const gchar *exported_settings[] = { "CredentialsId", NULL }; - -typedef enum { - DELAYED_CREATE, - DELAYED_DELETE, -} DelayedSignal; - -typedef struct { - gchar *mc_name; - gchar *ag_name; - gboolean global; /* global ag setting or service specific? */ - gboolean readable; /* does the _standard_ read method copy this into MC? */ - gboolean writable; /* does the _standard_ write method copy this into AG? */ - gboolean freeable; /* should clear_setting_data deallocate the names? */ -} Setting; - -#define GLOBAL TRUE -#define SERVICE FALSE -#define READABLE TRUE -#define UNREADABLE FALSE -#define WRITABLE TRUE -#define UNWRITABLE FALSE - -typedef enum { - SETTING_MC, - SETTING_AG, -} SettingType; - -/* IMPORTANT IMPLEMENTATION NOTE: - * - * The mapping between telepathy settings and parameter names - * and ag account (libaccounts) settings, and whether those settings - * are stored in the global or service specific ag section is a - * finicky beast - the mapping below has been arrived at empirically - * Take care when altering it. - * - * Settings not mentioned explicitly are: - * • given the same name on both MC and AG sides - * • assigned to the service specific section - * • automatically prefixed (param- vs parameters/) for each side if necessary - * - * So if your setting fits these criteria, you do not need to add it at all. - */ -Setting setting_map[] = { - { MC_ENABLED_KEY , AG_ENABLED_KEY , GLOBAL , UNREADABLE, UNWRITABLE }, - { MCPP MC_ACCOUNT_KEY, AG_ACCOUNT_KEY , GLOBAL , READABLE , UNWRITABLE }, - { MCPP PASSWORD_KEY , PASSWORD_KEY , GLOBAL , READABLE , WRITABLE }, - { MC_LABEL_KEY , AG_LABEL_KEY , GLOBAL , READABLE , WRITABLE }, - { LIBACCT_ID_KEY , LIBACCT_ID_KEY , GLOBAL , UNREADABLE, UNWRITABLE }, - { MC_IDENTITY_KEY , MC_IDENTITY_KEY, SERVICE, READABLE , WRITABLE }, - { MC_CMANAGER_KEY , MC_CMANAGER_KEY, SERVICE, READABLE , UNWRITABLE }, - { MC_PROTOCOL_KEY , MC_PROTOCOL_KEY, SERVICE, READABLE , UNWRITABLE }, - { MC_SERVICE_KEY , MC_SERVICE_KEY , SERVICE, UNREADABLE, UNWRITABLE }, - { SERVICES_KEY , SERVICES_KEY , GLOBAL , UNREADABLE, UNWRITABLE }, - { NULL } -}; - -typedef struct { - DelayedSignal signal; - AgAccountId account_id; -} DelayedSignalData; - -typedef struct { - McdAccountManagerSso *sso; - struct { - AgAccountWatch service; - AgAccountWatch global; - } watch; -} WatchData; - -static Setting * -setting_data (const gchar *name, SettingType type) -{ - guint i = 0; - static Setting parameter = { NULL, NULL, SERVICE, READABLE, WRITABLE, TRUE }; - const gchar *prefix; - - for (; setting_map[i].mc_name != NULL; i++) - { - const gchar *setting_name = NULL; - - if (type == SETTING_MC) - setting_name = setting_map[i].mc_name; - else - setting_name = setting_map[i].ag_name; - - if (g_strcmp0 (name, setting_name) == 0) - return &setting_map[i]; - } - - prefix = (type == SETTING_MC) ? MCPP : AGPP; - - if (!g_str_has_prefix (name, prefix)) - { /* a non-parameter setting */ - parameter.mc_name = g_strdup (name); - parameter.ag_name = g_strdup (name); - } - else - { /* a setting that is a parameter on both sides (AG & MC) */ - const guint plength = strlen (prefix); - - parameter.mc_name = g_strdup_printf ("%s%s", MCPP, name + plength); - parameter.ag_name = g_strdup_printf ("%s%s", AGPP, name + plength); - } - - return ¶meter; -} - -static void -clear_setting_data (Setting *setting) -{ - if (setting == NULL) - return; - - if (!setting->freeable) - return; - - g_free (setting->mc_name); - g_free (setting->ag_name); - setting->mc_name = NULL; - setting->ag_name = NULL; -} - -static gboolean _sso_account_enabled ( - McdAccountManagerSso *self, - AgAccount *account, - AgService *service); - -static void account_storage_iface_init (McpAccountStorageIface *, - gpointer); - -static gchar * -_ag_accountid_to_mc_key (McdAccountManagerSso *sso, - AgAccountId id, - gboolean create); - -static void _ag_account_stored_cb (AgAccount *acct, - const GError *err, - gpointer ignore); - -static void _sso_created (GObject *object, - AgAccountId id, - gpointer user_data); - -static void _sso_toggled (GObject *object, - AgAccountId id, - gpointer data); - -static gboolean save_setting ( - McdAccountManagerSso *self, - AgAccount *account, - const Setting *setting, - const gchar *val); - -G_DEFINE_TYPE_WITH_CODE (McdAccountManagerSso, mcd_account_manager_sso, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (MCP_TYPE_ACCOUNT_STORAGE, - account_storage_iface_init)); - -static gchar * -_gvalue_to_string (const GValue *val) -{ - switch (G_VALUE_TYPE (val)) - { - case G_TYPE_STRING: - return g_value_dup_string (val); - case G_TYPE_BOOLEAN: - return g_strdup (g_value_get_boolean (val) ? "true" : "false"); - case G_TYPE_CHAR: - return g_strdup_printf ("%c", g_value_get_uchar (val)); - case G_TYPE_UCHAR: - return g_strdup_printf ("%c", g_value_get_char (val)); - case G_TYPE_INT: - return g_strdup_printf ("%i", g_value_get_int (val)); - case G_TYPE_UINT: - return g_strdup_printf ("%u", g_value_get_uint (val)); - case G_TYPE_LONG: - return g_strdup_printf ("%ld", g_value_get_long (val)); - case G_TYPE_ULONG: - return g_strdup_printf ("%lu", g_value_get_ulong (val)); - case G_TYPE_INT64: - return g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (val)); - case G_TYPE_UINT64: - return g_strdup_printf ("%" G_GUINT64_FORMAT, g_value_get_uint64 (val)); - case G_TYPE_ENUM: - return g_strdup_printf ("%d" , g_value_get_enum (val)); - case G_TYPE_FLAGS: - return g_strdup_printf ("%u", g_value_get_flags (val)); - case G_TYPE_FLOAT: - return g_strdup_printf ("%f", g_value_get_float (val)); - case G_TYPE_DOUBLE: - return g_strdup_printf ("%g", g_value_get_double (val)); - default: - DEBUG ("Unsupported type %s", G_VALUE_TYPE_NAME (val)); - return NULL; - } -} - -static const gchar * -account_manager_sso_get_service_type (McdAccountManagerSso *self) -{ - McdAccountManagerSsoClass *klass = MCD_ACCOUNT_MANAGER_SSO_GET_CLASS (self); - - g_assert (klass->service_type != NULL); - - return klass->service_type; -} - -static gboolean -_ag_account_select_default_im_service ( - McdAccountManagerSso *self, - AgAccount *account) -{ - const gchar *service_type = account_manager_sso_get_service_type (self); - gboolean have_service = FALSE; - GList *first = ag_account_list_services_by_type (account, service_type); - - if (first != NULL && first->data != NULL) - { - have_service = TRUE; - DEBUG ("default %s service %s", service_type, - ag_service_get_name (first->data)); - ag_account_select_service (account, first->data); - } - - ag_service_list_free (first); - - return have_service; -} - -static AgSettingSource -_ag_account_global_value (AgAccount *account, - const gchar *key, - GValue *value) -{ - AgSettingSource src = AG_SETTING_SOURCE_NONE; - AgService *service = ag_account_get_selected_service (account); - - if (service != NULL) - { - ag_account_select_service (account, NULL); - src = ag_account_get_value (account, key, value); - ag_account_select_service (account, service); - } - else - { - src = ag_account_get_value (account, key, value); - } - - return src; -} - -static AgSettingSource -_ag_account_local_value ( - McdAccountManagerSso *self, - AgAccount *account, - const gchar *key, - GValue *value) -{ - AgSettingSource src = AG_SETTING_SOURCE_NONE; - AgService *service = ag_account_get_selected_service (account); - - if (service != NULL) - { - src = ag_account_get_value (account, key, value); - } - else - { - _ag_account_select_default_im_service (self, account); - src = ag_account_get_value (account, key, value); - ag_account_select_service (account, NULL); - } - - return src; -} - -/* AG_ACCOUNT_ALT_KEY from service overrides global AG_ACCOUNT_KEY if set */ -static void -_maybe_set_account_param_from_service ( - McdAccountManagerSso *self, - const McpAccountManager *am, - AgAccount *ag_account, - const gchar *mc_account) -{ - Setting *setting = setting_data (AG_ACCOUNT_KEY, SETTING_AG); - AgSettingSource source = AG_SETTING_SOURCE_NONE; - GValue ag_value = G_VALUE_INIT; - - g_return_if_fail (setting != NULL); - g_return_if_fail (ag_account != NULL); - - g_value_init (&ag_value, G_TYPE_STRING); - - source = _ag_account_local_value (self, ag_account, AG_ACCOUNT_ALT_KEY, - &ag_value); - - if (source != AG_SETTING_SOURCE_NONE) - { - gchar *value = _gvalue_to_string (&ag_value); - - DEBUG ("overriding global %s param with %s: %s", - AG_ACCOUNT_KEY, AG_ACCOUNT_ALT_KEY, value); - mcp_account_manager_set_value (am, mc_account, setting->mc_name, value); - g_free (value); - } - - g_value_unset (&ag_value); - clear_setting_data (setting); -} - -static WatchData * -make_watch_data (McdAccountManagerSso *sso) -{ - WatchData *data = g_slice_new0 (WatchData); - - data->sso = g_object_ref (sso); - - return data; -} - -static void -free_watch_data (gpointer data) -{ - WatchData *wd = data; - - if (wd == NULL) - return; - - tp_clear_object (&wd->sso); - g_slice_free (WatchData, wd); -} - -static void unwatch_account_keys (McdAccountManagerSso *sso, - AgAccountId id) -{ - gpointer watch_key = GUINT_TO_POINTER (id); - WatchData *wd = g_hash_table_lookup (sso->watches, watch_key); - AgAccount *account = ag_manager_get_account (sso->ag_manager, id); - - if (wd != NULL && account != NULL) - { - ag_account_remove_watch (account, wd->watch.global); - ag_account_remove_watch (account, wd->watch.service); - } - - g_hash_table_remove (sso->watches, watch_key); -} - -/* There are two types of ag watch: ag_account_watch_key and * - * ag_account_watch_dir. _key passees us the watched key when invoking this * - * callback, dir watches only a prefix, and passes the watched prefix * - * (not the actual updated setting) - we now watch with _dir since _key * - * doesn't allow us to watch for keys-that-are-not-set at creation time * - * (since those cannot be known in advance): This means that in this * - * callback we must compare what we have in MC with what's in AG and issue * - * update notices accordingly (and remember to handle deleted keys). * - * It also means the const gchar *what-was-updated parameter is not useful */ -static void _sso_updated (AgAccount *account, - const gchar *unused, - gpointer data) -{ - WatchData *wd = data; - McdAccountManagerSso *sso = wd->sso; - McpAccountManager *am = sso->manager_interface; - McpAccountStorage *mcpa = MCP_ACCOUNT_STORAGE (sso); - gpointer id = GUINT_TO_POINTER (account->id); - const gchar *name = g_hash_table_lookup (sso->id_name_map, id); - AgService *service = ag_account_get_selected_service (account); - GStrv keys = NULL; - GHashTable *unseen = NULL; - GHashTableIter deleted_iter = { 0 }; - const gchar *deleted_key; - guint i; - gboolean params_updated = FALSE; - const gchar *immutables[] = { MC_SERVICE_KEY, SERVICES_KEY, NULL }; - - /* account has no name yet: might be time to create it */ - if (name == NULL) - return _sso_created (G_OBJECT (sso->ag_manager), account->id, sso); - - DEBUG ("update for account %s", name); - - /* list the keys we know about so we can tell if one has been deleted */ - keys = mcp_account_manager_list_keys (am, name); - unseen = g_hash_table_new (g_str_hash, g_str_equal); - - for (i = 0; keys != NULL && keys[i] != NULL; i++) - g_hash_table_insert (unseen, keys[i], GUINT_TO_POINTER (TRUE)); - - /* now iterate over ag settings, global then service specific: */ - ag_account_select_service (account, NULL); - - for (i = 0; i < 2; i++) - { - AgAccountSettingIter iter = { 0 }; - const gchar *ag_key = NULL; - const GValue *ag_val = NULL; - - if (i == 1) - _ag_account_select_default_im_service (sso, account); - - ag_account_settings_iter_init (account, &iter, NULL); - - while (ag_account_settings_iter_next (&iter, &ag_key, &ag_val)) - { - Setting *setting = setting_data (ag_key, SETTING_AG); - const gchar *mc_key; - gchar *ag_str; - gchar *mc_str; - - if (setting == NULL) - continue; - - mc_key = setting->mc_name; - mc_str = mcp_account_manager_get_value (am, name, mc_key); - ag_str = _gvalue_to_string (ag_val); - g_hash_table_remove (unseen, mc_key); - - if (tp_strdiff (ag_str, mc_str)) - { - mcp_account_manager_set_value (am, name, mc_key, ag_str); - - if (sso->ready) - { - if (g_str_has_prefix (mc_key, MCPP)) - params_updated = TRUE; - else - mcp_account_storage_emit_altered_one (mcpa, name, mc_key); - } - } - - g_free (mc_str); - g_free (ag_str); - clear_setting_data (setting); - } - } - - /* special case values always exist and therefore cannot be deleted */ - for (i = 0; immutables[i] != NULL; i++) - { - Setting *immutable = setting_data (immutables[i], SETTING_AG); - - g_hash_table_remove (unseen, immutable->ag_name); - clear_setting_data (immutable); - } - - /* signal (and update) deleted settings: */ - g_hash_table_iter_init (&deleted_iter, unseen); - - while (g_hash_table_iter_next (&deleted_iter, (gpointer *)&deleted_key, NULL)) - { - mcp_account_manager_set_value (am, name, deleted_key, NULL); - - if (g_str_has_prefix (deleted_key, MCPP)) - params_updated = TRUE; - else - mcp_account_storage_emit_altered_one (mcpa, name, deleted_key); - } - - g_hash_table_unref (unseen); - g_strfreev (keys); - - if (params_updated) - mcp_account_storage_emit_altered_one (mcpa, name, "Parameters"); - - /* put the selected service back the way it was when we found it */ - ag_account_select_service (account, service); -} - -static void watch_for_updates (McdAccountManagerSso *sso, - AgAccount *account) -{ - WatchData *data; - gpointer id = GUINT_TO_POINTER (account->id); - AgService *service; - - /* already watching account? let's be idempotent */ - if (g_hash_table_lookup (sso->watches, id) != NULL) - return; - - DEBUG ("watching AG ID %u for updates", account->id); - - service = ag_account_get_selected_service (account); - - data = make_watch_data (sso); - - ag_account_select_service (account, NULL); - data->watch.global = ag_account_watch_dir (account, "", _sso_updated, data); - - _ag_account_select_default_im_service (sso, account); - data->watch.service = ag_account_watch_dir (account, "", _sso_updated, data); - - g_hash_table_insert (sso->watches, id, data); - ag_account_select_service (account, service); -} - -static void _sso_toggled (GObject *object, - AgAccountId id, - gpointer data) -{ - AgManager *manager = AG_MANAGER (object); - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (data); - McpAccountStorage *mcpa = MCP_ACCOUNT_STORAGE (sso); - AgAccount *account = NULL; - gboolean on = FALSE; - const gchar *name = NULL; - - /* If the account manager isn't ready, account state changes are of no * - * interest to us: it will pick up the then-current state of the account * - * when it does become ready, and anything that happens between now and * - * then is not important: */ - if (!sso->ready) - return; - - account = ag_manager_get_account (manager, id); - - if (account != NULL) - { - on = _sso_account_enabled (sso, account, NULL); - name = g_hash_table_lookup (sso->id_name_map, GUINT_TO_POINTER (id)); - } - - if (name != NULL) - { - const gchar *value = on ? "true" : "false"; - McpAccountManager *am = sso->manager_interface; - - mcp_account_manager_set_value (am, name, "Enabled", value); - mcp_account_storage_emit_toggled (mcpa, name, on); - } - else - { - DEBUG ("received enabled=%u signal for unknown SSO account %u", on, id); - } -} - -static void _sso_deleted (GObject *object, - AgAccountId id, - gpointer user_data) -{ - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (user_data); - - if (sso->ready) - { - const gchar *name = - g_hash_table_lookup (sso->id_name_map, GUINT_TO_POINTER (id)); - - /* if the account was in our cache, then this was a 3rd party delete * - * op that someone did behind our back: fire the signal and clean up */ - if (name != NULL) - { - McpAccountStorage *mcpa = MCP_ACCOUNT_STORAGE (sso); - gchar *signalled_name = g_strdup (name); - - /* forget id->name map first, so the signal can't start a loop */ - g_hash_table_remove (sso->id_name_map, GUINT_TO_POINTER (id)); - g_hash_table_remove (sso->accounts, signalled_name); - - /* stop watching for updates */ - unwatch_account_keys (sso, id); - - mcp_account_storage_emit_deleted (mcpa, signalled_name); - - g_free (signalled_name); - } - } - else - { - DelayedSignalData *sig_data = g_slice_new0 (DelayedSignalData); - - sig_data->signal = DELAYED_DELETE; - sig_data->account_id = id; - g_queue_push_tail (sso->pending_signals, sig_data); - } -} - -/* return TRUE if we actually changed any state, FALSE otherwise */ -static gboolean _sso_account_enable ( - McdAccountManagerSso *self, - AgAccount *account, - AgService *service, - gboolean on) -{ - AgService *original = ag_account_get_selected_service (account); - - /* the setting account is already in one of the global+service - configurations that corresponds to our current state: don't touch it */ - if (_sso_account_enabled (self, account, service) == on) - return FALSE; - - /* turn the local enabled flag on/off as required */ - if (service != NULL) - ag_account_select_service (account, service); - else - _ag_account_select_default_im_service (self, account); - - ag_account_set_enabled (account, on); - - /* if we are turning the account on, the global flag must also be set * - * NOTE: this isn't needed when turning the account off */ - if (on) - { - ag_account_select_service (account, NULL); - ag_account_set_enabled (account, on); - } - - ag_account_select_service (account, original); - - return TRUE; -} - -static gboolean _sso_account_enabled ( - McdAccountManagerSso *self, - AgAccount *account, - AgService *service) -{ - gboolean local = FALSE; - gboolean global = FALSE; - AgService *original = ag_account_get_selected_service (account); - - if (service == NULL) - { - _ag_account_select_default_im_service (self, account); - local = ag_account_get_enabled (account); - } - else - { - if (original != service) - ag_account_select_service (account, service); - - local = ag_account_get_enabled (account); - } - - ag_account_select_service (account, NULL); - global = ag_account_get_enabled (account); - - ag_account_select_service (account, original); - - DEBUG ("_sso_account_enabled: global:%d && local:%d", global, local); - - return local && global; -} - -static void _sso_created (GObject *object, - AgAccountId id, - gpointer user_data) -{ - AgManager *ag_manager = AG_MANAGER (object); - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (user_data); - gchar *name = - g_hash_table_lookup (sso->id_name_map, GUINT_TO_POINTER (id)); - - if (sso->ready) - { - /* if we already know the account's name, we shouldn't fire the new * - * account signal as it is one we (and our superiors) already have * - * This could happen as a result of multiple updates being set off * - * before we are ready, for example */ - if (name == NULL) - { - McpAccountStorage *mcpa = MCP_ACCOUNT_STORAGE (sso); - AgAccount *account = ag_manager_get_account (ag_manager, id); - - if (account != NULL) - { - /* this will be owned by the ag account hash, do not free it */ - name = _ag_accountid_to_mc_key (sso, id, TRUE); - - if (name != NULL) - { - Setting *setting = setting_data (MC_IDENTITY_KEY, SETTING_MC); - - g_hash_table_insert (sso->accounts, name, account); - g_hash_table_insert (sso->id_name_map, GUINT_TO_POINTER (id), - g_strdup (name)); - - save_setting (sso, account, setting, name); - - ag_account_store (account, _ag_account_stored_cb, sso); - - mcp_account_storage_emit_created (mcpa, name); - - clear_setting_data (setting); - } - else - { - /* not enough data to name the account: wait for an update */ - DEBUG ("SSO account #%u is currently unnameable", id); - } - - /* in either case, add the account to the watched list */ - watch_for_updates (sso, account); - } - } - } - else - { - DelayedSignalData *sig_data = g_slice_new0 (DelayedSignalData); - - sig_data->signal = DELAYED_CREATE; - sig_data->account_id = id; - g_queue_push_tail (sso->pending_signals, sig_data); - } -} - -static void -mcd_account_manager_sso_init (McdAccountManagerSso *self) -{ - self->accounts = - g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - self->id_name_map = - g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); - self->watches = - g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) free_watch_data); - self->pending_signals = g_queue_new (); - -} - -static void -mcd_account_manager_sso_constructed (GObject *object) -{ - McdAccountManagerSso *self = MCD_ACCOUNT_MANAGER_SSO (object); - GObjectClass *parent_class = - G_OBJECT_CLASS (mcd_account_manager_sso_parent_class); - const gchar *service_type = account_manager_sso_get_service_type (self); - - if (parent_class->constructed != NULL) - parent_class->constructed (object); - - DEBUG ("Watching for services of type '%s'", service_type); - self->ag_manager = ag_manager_new_for_service_type (service_type); - - g_signal_connect(self->ag_manager, "enabled-event", - G_CALLBACK (_sso_toggled), self); - g_signal_connect(self->ag_manager, "account-deleted", - G_CALLBACK (_sso_deleted), self); - g_signal_connect(self->ag_manager, "account-created", - G_CALLBACK (_sso_created), self); -} - -static void -mcd_account_manager_sso_class_init (McdAccountManagerSsoClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->constructed = mcd_account_manager_sso_constructed; - - klass->service_type = "IM"; -} - -static void -_ag_account_stored_cb ( - AgAccount *account, - const GError *err, - gpointer user_data) -{ - McdAccountManagerSso *self = MCD_ACCOUNT_MANAGER_SSO (user_data); - GValue uid = G_VALUE_INIT; - const gchar *name = NULL; - AgSettingSource src = AG_SETTING_SOURCE_NONE; - - g_value_init (&uid, G_TYPE_STRING); - - src = _ag_account_local_value (self, account, MC_IDENTITY_KEY, &uid); - - if (src != AG_SETTING_SOURCE_NONE && G_VALUE_HOLDS_STRING (&uid)) - { - name = g_value_get_string (&uid); - DEBUG ("%p:%s stored: %s", account, name, err ? err->message : "-"); - g_value_unset (&uid); - } - else - { - DEBUG ("%p:%s not stored? %s", acct, - ag_account_get_display_name (account), err ? err->message : "-"); - } -} - -static gchar * -_ag_accountid_to_mc_key (McdAccountManagerSso *sso, - AgAccountId id, - gboolean create) -{ - AgAccount *account = ag_manager_get_account (sso->ag_manager, id); - AgSettingSource src = AG_SETTING_SOURCE_NONE; - AgService *service = NULL; - GValue value = G_VALUE_INIT; - - if (account == NULL) - { - DEBUG ("AG Account ID %u invalid", id); - return NULL; - } - - service = ag_account_get_selected_service (account); - - DEBUG ("AG Account ID: %u", id); - - g_value_init (&value, G_TYPE_STRING); - - /* first look for the stored TMC uid */ - src = _ag_account_local_value (sso, account, MC_IDENTITY_KEY, &value); - - /* if we found something, our work here is done: */ - if (src != AG_SETTING_SOURCE_NONE) - { - gchar *uid = g_value_dup_string (&value); - g_value_unset (&value); - return uid; - } - - if (!create) - { - g_value_unset (&value); - return NULL; - } - - DEBUG ("no " MC_IDENTITY_KEY " found, synthesising one:"); - - src = _ag_account_global_value (account, AG_ACCOUNT_KEY, &value); - - /* fall back to the alernative account-naming setting if necessary: */ - if (src == AG_SETTING_SOURCE_NONE) - { - _ag_account_select_default_im_service (sso, account); - src = _ag_account_local_value (sso, account, AG_ACCOUNT_ALT_KEY, &value); - } - - if (src != AG_SETTING_SOURCE_NONE && G_VALUE_HOLDS_STRING (&value)) - { - AgAccountSettingIter iter; - const gchar *k; - const GValue *v; - GValue cmanager = G_VALUE_INIT; - GValue protocol = G_VALUE_INIT; - const gchar *cman, *proto; - McpAccountManager *am = sso->manager_interface; - GHashTable *params = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - gchar *name = NULL; - - g_value_init (&cmanager, G_TYPE_STRING); - g_value_init (&protocol, G_TYPE_STRING); - - /* if we weren't on a service when got here, pick the most likely one: */ - if (service == NULL) - _ag_account_select_default_im_service (sso, account); - - ag_account_get_value (account, MC_CMANAGER_KEY, &cmanager); - cman = g_value_get_string (&cmanager); - - if (cman == NULL) - goto cleanup; - - ag_account_get_value (account, MC_PROTOCOL_KEY, &protocol); - proto = g_value_get_string (&protocol); - - if (proto == NULL) - goto cleanup; - - /* prepare the hash of MC param keys -> GValue */ - /* NOTE: some AG bare settings map to MC parameters, * - * so we must iterate over all AG settings, parameters * - * and bare settings included */ - - /* first any matching global values: */ - ag_account_select_service (account, NULL); - ag_account_settings_iter_init (account, &iter, NULL); - - while (ag_account_settings_iter_next (&iter, &k, &v)) - { - Setting *setting = setting_data (k, SETTING_AG); - - if (setting != NULL && g_str_has_prefix (setting->mc_name, MCPP)) - { - gchar *param_key = g_strdup (setting->mc_name + strlen (MCPP)); - - g_hash_table_insert (params, param_key, (gpointer) v); - } - - clear_setting_data (setting); - } - - /* then any service specific settings */ - if (service != NULL) - ag_account_select_service (account, service); - else - _ag_account_select_default_im_service (sso, account); - - ag_account_settings_iter_init (account, &iter, NULL); - while (ag_account_settings_iter_next (&iter, &k, &v)) - { - Setting *setting = setting_data (k, SETTING_AG); - - if (setting != NULL && g_str_has_prefix (setting->mc_name, MCPP)) - { - gchar *param_key = g_strdup (setting->mc_name + strlen (MCPP)); - - g_hash_table_insert (params, param_key, (gpointer) v); - } - - clear_setting_data (setting); - } - - /* we want this to override any other settings for uid generation */ - g_hash_table_insert (params, g_strdup (MC_ACCOUNT_KEY), &value); - - name = mcp_account_manager_get_unique_name (am, cman, proto, params); - - cleanup: - ag_account_select_service (account, service); - g_hash_table_unref (params); - g_value_unset (&value); - g_value_unset (&cmanager); - g_value_unset (&protocol); - - DEBUG (MC_IDENTITY_KEY " value %p:%s synthesised", name, name); - return name; - } - else - { - g_value_unset (&value); - } - - DEBUG (MC_IDENTITY_KEY " not synthesised, returning NULL"); - return NULL; -} - -static AgAccount * -get_ag_account (const McdAccountManagerSso *sso, - const McpAccountManager *am, - const gchar *name, - AgAccountId *id) -{ - AgAccount *account; - - g_return_val_if_fail (id != NULL, NULL); - - /* we have a cached account, just return that */ - account = g_hash_table_lookup (sso->accounts, name); - if (account != NULL) - { - *id = account->id; - return account; - } - - *id = 0; - - return NULL; -} - -/* returns true if it actually changed an account's state */ -static gboolean -save_setting ( - McdAccountManagerSso *self, - AgAccount *account, - const Setting *setting, - const gchar *val) -{ - gboolean changed = FALSE; - AgService *service = ag_account_get_selected_service (account); - - if (!setting->writable) - return FALSE; - - if (setting->global) - ag_account_select_service (account, NULL); - else if (service == NULL) - _ag_account_select_default_im_service (self, account); - - if (setting->readable) - { - GValue old = G_VALUE_INIT; - AgSettingSource src = AG_SETTING_SOURCE_NONE; - - g_value_init (&old, G_TYPE_STRING); - - if (setting->global) - src = _ag_account_global_value (account, setting->ag_name, &old); - else - src = _ag_account_local_value (self, account, setting->ag_name, &old); - - /* unsetting an already unset value, bail out */ - if (val == NULL && src == AG_SETTING_SOURCE_NONE) - goto done; - - /* assigning a value to one which _is_ set: check it actually changed */ - if (val != NULL && src != AG_SETTING_SOURCE_NONE) - { - gchar *str = _gvalue_to_string (&old); - gboolean noop = g_strcmp0 (str, val) == 0; - - g_value_unset (&old); - g_free (str); - - if (noop) - goto done; - } - } - - /* if we got this far, we're changing the stored state: */ - changed = TRUE; - - if (val != NULL) - { - GValue value = G_VALUE_INIT; - - g_value_init (&value, G_TYPE_STRING); - g_value_set_string (&value, val); - ag_account_set_value (account, setting->ag_name, &value); - g_value_unset (&value); - } - else - { - ag_account_set_value (account, setting->ag_name, NULL); - } - - /* leave the selected service as we found it: */ - done: - ag_account_select_service (account, service); - - return changed; -} - -static gboolean -_set (const McpAccountStorage *self, - const McpAccountManager *am, - const gchar *account_suffix, - const gchar *key, - const gchar *val) -{ - AgAccountId id; - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self); - AgAccount *account = get_ag_account (sso, am, account_suffix, &id); - Setting *setting = NULL; - gboolean updated = FALSE; - - /* can't store a setting with no name */ - g_return_val_if_fail (key != NULL, FALSE); - - /* we no longer create accounts in libaccount: either an account exists * - * in libaccount as a result of some 3rd party intervention, or it is * - * not an account that this plugin should ever concern itself with */ - - if (account != NULL) - setting = setting_data (key, SETTING_MC); - else - return FALSE; - - if (setting != NULL) - { - /* Enabled is both a global and a local value, for extra fun: */ - if (g_str_equal (setting->mc_name, MC_ENABLED_KEY)) - { - gboolean on = g_str_equal (val, "true"); - - DEBUG ("setting enabled flag: '%d'", on); - updated = _sso_account_enable (sso, account, NULL, on); - } - else - { - updated = save_setting (sso, account, setting, val); - } - - if (updated) - sso->save = TRUE; - - clear_setting_data (setting); - } - - /* whether or not we stored this value, if we got this far it's our * - * setting and no-one else is allowed to claim it: so return TRUE */ - return TRUE; -} - -/* Implements the half of the _get method where key is not NULL. */ -static void -account_manager_sso_get_one ( - McdAccountManagerSso *sso, - const McpAccountManager *am, - const gchar *account_suffix, - const gchar *key, - AgAccount *account, - AgService *service) -{ - if (g_str_equal (key, MC_ENABLED_KEY)) - { - const gchar *v = NULL; - - v = _sso_account_enabled (sso, account, service) ? "true" : "false"; - mcp_account_manager_set_value (am, account_suffix, key, v); - } - else if (g_str_equal (key, SERVICES_KEY)) - { - GString *result = g_string_new (""); - AgManager * agm = ag_account_get_manager (account); - GList *services = ag_manager_list_services (agm); - GList *item = NULL; - - for (item = services; item != NULL; item = g_list_next (item)) - { - const gchar *name = ag_service_get_name (item->data); - - g_string_append_printf (result, "%s;", name); - } - - mcp_account_manager_set_value (am, account_suffix, key, result->str); - - ag_service_list_free (services); - g_string_free (result, TRUE); - } - else if (g_str_equal (key, MC_SERVICE_KEY)) - { - const gchar *service_name = NULL; - AgService *im_service = NULL; - - _ag_account_select_default_im_service (sso, account); - im_service = ag_account_get_selected_service (account); - service_name = ag_service_get_name (im_service); - mcp_account_manager_set_value (am, account_suffix, key, service_name); - } - else - { - GValue v = G_VALUE_INIT; - AgSettingSource src = AG_SETTING_SOURCE_NONE; - Setting *setting = setting_data (key, SETTING_MC); - - if (setting == NULL) - return; - - g_value_init (&v, G_TYPE_STRING); - - if (setting->global) - src = _ag_account_global_value (account, setting->ag_name, &v); - else - src = _ag_account_local_value (sso, account, setting->ag_name, &v); - - if (src != AG_SETTING_SOURCE_NONE) - { - gchar *val = _gvalue_to_string (&v); - - mcp_account_manager_set_value (am, account_suffix, key, val); - - g_free (val); - } - - if (g_str_equal (key, MCPP MC_ACCOUNT_KEY)) - _maybe_set_account_param_from_service (sso, am, account, - account_suffix); - - g_value_unset (&v); - clear_setting_data (setting); - } -} - -/* Implements the half of the _get method where key == NULL, which is an - * instruction from MC that we should look up all of this account's properties - * and stash them with mcp_account_manager_set_value(). - */ -static void -account_manager_sso_get_all ( - McdAccountManagerSso *sso, - const McpAccountManager *am, - const gchar *account_suffix, - AgAccount *account, - AgService *service) -{ - AgAccountSettingIter ag_setting; - const gchar *k; - const GValue *v; - const gchar *on = NULL; - AgService *im_service = NULL; - - /* pick the IM service if we haven't got one set */ - if (service == NULL) - _ag_account_select_default_im_service (sso, account); - - /* special case, not stored as a normal setting */ - im_service = ag_account_get_selected_service (account); - mcp_account_manager_set_value (am, account_suffix, MC_SERVICE_KEY, - ag_service_get_name (im_service)); - - ag_account_settings_iter_init (account, &ag_setting, NULL); - while (ag_account_settings_iter_next (&ag_setting, &k, &v)) - { - Setting *setting = setting_data (k, SETTING_AG); - - if (setting != NULL && setting->readable && !setting->global) - { - gchar *value = _gvalue_to_string (v); - - mcp_account_manager_set_value (am, account_suffix, - setting->mc_name, value); - - g_free (value); - } - - clear_setting_data (setting); - } - - /* deselect any service we may have to get global settings */ - ag_account_select_service (account, NULL); - ag_account_settings_iter_init (account, &ag_setting, NULL); - - while (ag_account_settings_iter_next (&ag_setting, &k, &v)) - { - Setting *setting = setting_data (k, SETTING_AG); - - if (setting != NULL && setting->readable && setting->global) - { - gchar *value = _gvalue_to_string (v); - - mcp_account_manager_set_value (am, account_suffix, - setting->mc_name, value); - - g_free (value); - } - - clear_setting_data (setting); - } - - /* special case, actually two separate but related flags in SSO */ - on = _sso_account_enabled (sso, account, NULL) ? "true" : "false"; - mcp_account_manager_set_value (am, account_suffix, MC_ENABLED_KEY, on); - - _maybe_set_account_param_from_service (sso, am, account, account_suffix); -} - -gboolean -_mcd_account_manager_sso_get ( - const McpAccountStorage *self, - const McpAccountManager *am, - const gchar *account_suffix, - const gchar *key) -{ - AgAccountId id; - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self); - AgAccount *account = get_ag_account (sso, am, account_suffix, &id); - AgService *service = ag_account_get_selected_service (account); - - if (account == NULL) - return FALSE; - - /* Delegate to one of the two relatively-orthogonal meanings of this - * method... */ - if (key != NULL) - account_manager_sso_get_one (sso, am, account_suffix, key, account, - service); - else - account_manager_sso_get_all (sso, am, account_suffix, account, service); - - /* leave the selected service as we found it */ - ag_account_select_service (account, service); - return TRUE; -} - -static gboolean -_delete (const McpAccountStorage *self, - const McpAccountManager *am, - const gchar *account_suffix, - const gchar *key) -{ - AgAccountId id; - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self); - AgAccount *account = get_ag_account (sso, am, account_suffix, &id); - gboolean updated = FALSE; - - /* have no values for this account, nothing to do here: */ - if (account == NULL) - return TRUE; - - if (key == NULL) - { - ag_account_delete (account); - g_hash_table_remove (sso->accounts, account_suffix); - g_hash_table_remove (sso->id_name_map, GUINT_TO_POINTER (id)); - - /* stop watching for updates */ - unwatch_account_keys (sso, id); - updated = TRUE; - } - else - { - Setting *setting = setting_data (key, SETTING_MC); - - if (setting != NULL) - updated = save_setting (sso, account, setting, NULL); - - clear_setting_data (setting); - } - - if (updated) - sso->save = TRUE; - - return TRUE; -} - -static gboolean -_commit_real (gpointer user_data) -{ - McpAccountStorage *self = MCP_ACCOUNT_STORAGE (user_data); - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self); - GHashTableIter iter; - gchar *key; - AgAccount *account; - - g_hash_table_iter_init (&iter, sso->accounts); - - /* for each account, set its telepathy uid MC_IDENTITY_KEY in the * - * AgAccount structure, and then flush any changes to said account * - * to long term storage with ag_account_store() * - * The actual changes are those pushed into the AgAccount in _set * - * and _delete */ - while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &account)) - { - Setting *setting = setting_data (MC_IDENTITY_KEY, SETTING_MC); - /* this value ties MC accounts to SSO accounts */ - save_setting (sso, account, setting, key); - ag_account_store (account, _ag_account_stored_cb, sso); - } - - sso->commit_source = 0; - - /* any pending changes should now have been pushed, clear the save-me flag */ - sso->save = FALSE; - - return FALSE; -} - -static gboolean -_commit (const McpAccountStorage *self, - const McpAccountManager *am) -{ - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self); - - if (!sso->save) - return TRUE; - - if (sso->commit_source == 0) - { - DEBUG ("Deferring commit for %d seconds", AG_ACCOUNT_WRITE_INTERVAL); - sso->commit_source = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, - AG_ACCOUNT_WRITE_INTERVAL, - _commit_real, g_object_ref (sso), g_object_unref); - } - else - { - DEBUG ("Already deferred commit"); - } - - return TRUE; -} - -static void -_load_from_libaccounts (McdAccountManagerSso *sso, - const McpAccountManager *am) -{ - GList *ag_ids = ag_manager_list_by_service_type (sso->ag_manager, - account_manager_sso_get_service_type (sso)); - GList *ag_id; - - for (ag_id = ag_ids; ag_id != NULL; ag_id = g_list_next (ag_id)) - { - const gchar *key; - const GValue *val; - AgAccountSettingIter iter; - AgAccountId id = GPOINTER_TO_UINT (ag_id->data); - AgAccount *account = ag_manager_get_account (sso->ag_manager, id); - - if (account != NULL) - { - AgService *service = ag_account_get_selected_service (account); - gchar *name = _ag_accountid_to_mc_key (sso, id, FALSE); - - if (name != NULL) - { - AgService *im_service = NULL; - gchar *ident = g_strdup_printf ("%u", id); - GStrv mc_id = g_strsplit (name, "/", 3); - gboolean enabled; - - /* cache the account object, and the ID->name maping: the * - * latter is required because we might receive an async * - * delete signal with the ID after libaccounts-glib has * - * purged all its account data, so we couldn't rely on the * - * MC_IDENTITY_KEY setting. */ - g_hash_table_insert (sso->accounts, name, account); - g_hash_table_insert (sso->id_name_map, GUINT_TO_POINTER (id), - g_strdup (name)); - - if (service == NULL) - _ag_account_select_default_im_service (sso, account); - - /* special case, not stored as a normal setting */ - im_service = ag_account_get_selected_service (account); - mcp_account_manager_set_value (am, name, MC_SERVICE_KEY, - ag_service_get_name (im_service)); - - ag_account_settings_iter_init (account, &iter, NULL); - - while (ag_account_settings_iter_next (&iter, &key, &val)) - { - Setting *setting = setting_data (key, SETTING_AG); - - if (setting != NULL && !setting->global && setting->readable) - { - gchar *value = _gvalue_to_string (val); - - mcp_account_manager_set_value (am, name, setting->mc_name, - value); - - g_free (value); - } - - clear_setting_data (setting); - } - - ag_account_select_service (account, NULL); - ag_account_settings_iter_init (account, &iter, NULL); - - while (ag_account_settings_iter_next (&iter, &key, &val)) - { - Setting *setting = setting_data (key, SETTING_AG); - - if (setting != NULL && setting->global && setting->readable) - { - gchar *value = _gvalue_to_string (val); - - mcp_account_manager_set_value (am, name, setting->mc_name, - value); - - g_free (value); - } - - clear_setting_data (setting); - } - - /* special case, actually two separate but related flags in SSO */ - enabled = _sso_account_enabled (sso, account, NULL); - - mcp_account_manager_set_value (am, name, MC_ENABLED_KEY, - enabled ? "true" : "false"); - mcp_account_manager_set_value (am, name, LIBACCT_ID_KEY, ident); - mcp_account_manager_set_value (am, name, MC_CMANAGER_KEY, mc_id[0]); - mcp_account_manager_set_value (am, name, MC_PROTOCOL_KEY, mc_id[1]); - mcp_account_manager_set_value (am, name, MC_IDENTITY_KEY, name); - _maybe_set_account_param_from_service (sso, am, account, name); - - /* force the services value to be synthesised + cached */ - _mcd_account_manager_sso_get (MCP_ACCOUNT_STORAGE (sso), am, - name, SERVICES_KEY); - - ag_account_select_service (account, service); - - watch_for_updates (sso, account); - - g_strfreev (mc_id); - g_free (ident); - } - } - } - - sso->loaded = TRUE; - ag_manager_list_free (ag_ids); -} - -static GList * -_list (const McpAccountStorage *self, - const McpAccountManager *am) -{ - GList *rval = NULL; - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self); - GList *ag_ids = NULL; - GList *ag_id; - - if (!sso->loaded) - _load_from_libaccounts (sso, am); - - ag_ids = ag_manager_list_by_service_type (sso->ag_manager, - account_manager_sso_get_service_type (sso)); - - for (ag_id = ag_ids; ag_id != NULL; ag_id = g_list_next (ag_id)) - { - AgAccountId id = GPOINTER_TO_UINT (ag_id->data); - gchar *name = NULL; - - name = _ag_accountid_to_mc_key (sso, id, FALSE); - - if (name != NULL) - { - DEBUG ("account %s listed", name); - rval = g_list_prepend (rval, name); - } - else - { - DelayedSignalData *data = g_slice_new0 (DelayedSignalData); - - DEBUG ("account %u delayed", id); - data->signal = DELAYED_CREATE; - data->account_id = id; - g_queue_push_tail (sso->pending_signals, data); - } - } - - ag_manager_list_free (ag_ids); - - return rval; -} - -static void -_ready (const McpAccountStorage *self, - const McpAccountManager *am) -{ - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self); - - if (sso->ready) - return; - - g_assert (sso->manager_interface == NULL); - sso->manager_interface = g_object_ref (G_OBJECT (am)); - sso->ready = TRUE; - - while (g_queue_get_length (sso->pending_signals) > 0) - { - DelayedSignalData *data = g_queue_pop_head (sso->pending_signals); - GObject *signal_source = G_OBJECT (sso->ag_manager); - - switch (data->signal) - { - case DELAYED_CREATE: - _sso_created (signal_source, data->account_id, sso); - break; - case DELAYED_DELETE: - _sso_deleted (signal_source, data->account_id, sso); - break; - default: - g_assert_not_reached (); - } - - g_slice_free (DelayedSignalData, data); - } - - g_queue_free (sso->pending_signals); - sso->pending_signals = NULL; -} - -static gboolean -_find_account (McdAccountManagerSso *sso, - const gchar *account_name, - AgAccountId *account_id) -{ - GList *ag_ids = NULL; - GList *ag_id; - gboolean found = FALSE; - - g_return_val_if_fail (account_id != NULL, found); - - ag_ids = ag_manager_list_by_service_type (sso->ag_manager, - account_manager_sso_get_service_type (sso)); - - for (ag_id = ag_ids; ag_id != NULL; ag_id = g_list_next (ag_id)) - { - AgAccountId id = GPOINTER_TO_UINT (ag_id->data); - gchar *name = NULL; - - name = _ag_accountid_to_mc_key (sso, id, FALSE); - - if (g_strcmp0 (name, account_name) == 0) - { - found = TRUE; - *account_id = id; - } - - g_free (name); - - if (found) - break; - } - - ag_manager_list_free (ag_ids); - - return found; -} - -static void -_get_identifier (const McpAccountStorage *self, - const gchar *account, - GValue *identifier) -{ - AgAccountId account_id = 0; - - if (!_find_account (MCD_ACCOUNT_MANAGER_SSO (self), account, &account_id)) - g_warning ("Didn't find account %s in %s", account, PLUGIN_NAME); - - g_value_init (identifier, G_TYPE_UINT); - - g_value_set_uint (identifier, account_id); -} - -static GHashTable * -_get_additional_info (const McpAccountStorage *self, - const gchar *account_suffix) -{ - AgAccountId account_id = 0; - McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self); - GHashTable *additional_info = NULL; - AgAccount *account; - AgService *service; - AgAccountSettingIter iter; - const GValue *val; - const gchar *key; - - if (!_find_account (sso, account_suffix, &account_id)) - { - g_warning ("Didn't find account %s in %s", account_suffix, PLUGIN_NAME); - return NULL; - } - - account = ag_manager_get_account (sso->ag_manager, account_id); - - g_return_val_if_fail (account != NULL, NULL); - - service = ag_account_get_selected_service (account); - - additional_info = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, (GDestroyNotify) tp_g_value_slice_free); - - if (service == NULL) - _ag_account_select_default_im_service (sso, account); - - ag_account_settings_iter_init (account, &iter, NULL); - - while (ag_account_settings_iter_next (&iter, &key, &val)) - { - if (tp_strv_contains (exported_settings, key)) - g_hash_table_insert (additional_info, g_strdup (key), - tp_g_value_slice_dup (val)); - } - - ag_account_select_service (account, NULL); - ag_account_settings_iter_init (account, &iter, NULL); - - while (ag_account_settings_iter_next (&iter, &key, &val)) - { - if (tp_strv_contains (exported_settings, key)) - g_hash_table_insert (additional_info, g_strdup (key), - tp_g_value_slice_dup (val)); - } - - ag_account_select_service (account, service); - - g_object_unref (account); - - return additional_info; -} - -static void -account_storage_iface_init (McpAccountStorageIface *iface, - gpointer unused G_GNUC_UNUSED) -{ - iface->name = PLUGIN_NAME; - iface->desc = PLUGIN_DESCRIPTION; - iface->priority = PLUGIN_PRIORITY; - iface->provider = PLUGIN_PROVIDER; - - iface->get = _mcd_account_manager_sso_get; - iface->set = _set; - iface->delete = _delete; - iface->commit = _commit; - iface->list = _list; - iface->ready = _ready; - iface->get_identifier = _get_identifier; - iface->get_additional_info = _get_additional_info; -} - -McdAccountManagerSso * -mcd_account_manager_sso_new (void) -{ - return g_object_new (MCD_TYPE_ACCOUNT_MANAGER_SSO, NULL); -} |