~ubuntu-branches/ubuntu/precise/telepathy-mission-control-5/precise

« back to all changes in this revision

Viewing changes to src/mcd-account-manager-sso.c

Tags: upstream-5.5.2
Import upstream version 5.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * A pseudo-plugin that stores/fetches accounts in/from the SSO via libaccounts
 
3
 *
 
4
 * Copyright © 2010 Nokia Corporation
 
5
 * Copyright © 2010 Collabora Ltd.
 
6
 *
 
7
 * This library is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU Lesser General Public
 
9
 * License as published by the Free Software Foundation; either
 
10
 * version 2.1 of the License, or (at your option) any later version.
 
11
 *
 
12
 * This library is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * Lesser General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU Lesser General Public
 
18
 * License along with this library; if not, write to the Free Software
 
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
#include "mcd-account-manager-sso.h"
 
24
#include "mcd-debug.h"
 
25
 
 
26
#include <string.h>
 
27
#include <ctype.h>
 
28
 
 
29
/* IMPORTANT IMPLEMENTATION NOTE:
 
30
 *
 
31
 * Note for implementors: save_param is for saving account parameters (in MC
 
32
 * terms) - anything that ends up stored as "param-" in the standard gkeyfile
 
33
 * save_value is for everything else.
 
34
 *
 
35
 * Whether such a value is stored in the global section of an SSO account or
 
36
 * in the IM specific section is orthogonal to the above, and in the mapping
 
37
 * is not necessarily from MC "name" to SSO "name", or from MC "param-name"
 
38
 * to SSO "parameters/name" - so be careful when making such decisions.
 
39
 *
 
40
 * The existing mappings have been arrived at empirically.
 
41
 */
 
42
 
 
43
#define PLUGIN_PRIORITY (MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_KEYRING + 10)
 
44
#define PLUGIN_NAME "maemo-libaccounts"
 
45
#define PLUGIN_DESCRIPTION \
 
46
  "Account storage in the Maemo SSO store via libaccounts-glib API"
 
47
 
 
48
#define PARAM_PREFIX_MC "param-"
 
49
#define PARAM_PREFIX    "parameters/"
 
50
#define LIBACCT_ID_KEY  "libacct-uid"
 
51
 
 
52
#define AG_LABEL_KEY   "name"
 
53
#define MC_LABEL_KEY   "DisplayName"
 
54
 
 
55
#define AG_ACCOUNT_KEY "username"
 
56
#define MC_ACCOUNT_KEY "account"
 
57
#define PASSWORD_KEY   "password"
 
58
 
 
59
#define MC_CMANAGER_KEY "manager"
 
60
#define MC_PROTOCOL_KEY "protocol"
 
61
#define MC_IDENTITY_KEY "tmc-uid"
 
62
 
 
63
typedef enum {
 
64
  DELAYED_CREATE,
 
65
  DELAYED_DELETE,
 
66
} DelayedSignal;
 
67
 
 
68
typedef struct {
 
69
  DelayedSignal signal;
 
70
  AgAccountId account_id;
 
71
} DelayedSignalData;
 
72
 
 
73
static gboolean _sso_account_enabled (AgAccount *account,
 
74
    AgService *service);
 
75
 
 
76
static void account_storage_iface_init (McpAccountStorageIface *,
 
77
    gpointer);
 
78
 
 
79
static gchar *
 
80
_ag_accountid_to_mc_key (const McdAccountManagerSso *sso,
 
81
    AgAccountId id,
 
82
    gboolean create);
 
83
 
 
84
static gchar * get_mc_param_key (const gchar *key);
 
85
 
 
86
static void
 
87
save_value (AgAccount *account,
 
88
    const gchar *key,
 
89
    const gchar *val);
 
90
 
 
91
static void _ag_account_stored_cb (AgAccount *acct,
 
92
    const GError *err,
 
93
    gpointer ignore);
 
94
 
 
95
G_DEFINE_TYPE_WITH_CODE (McdAccountManagerSso, mcd_account_manager_sso,
 
96
    G_TYPE_OBJECT,
 
97
    G_IMPLEMENT_INTERFACE (MCP_TYPE_ACCOUNT_STORAGE,
 
98
        account_storage_iface_init));
 
99
 
 
100
static gchar *
 
101
_gvalue_to_string (const GValue *val)
 
102
{
 
103
  switch (G_VALUE_TYPE (val))
 
104
    {
 
105
      case G_TYPE_STRING:
 
106
        return g_value_dup_string (val);
 
107
      case G_TYPE_BOOLEAN:
 
108
        return g_strdup (g_value_get_boolean (val) ? "true" : "false");
 
109
      case G_TYPE_CHAR:
 
110
        return g_strdup_printf ("%c", g_value_get_uchar (val));
 
111
      case G_TYPE_UCHAR:
 
112
        return g_strdup_printf ("%c", g_value_get_char (val));
 
113
      case G_TYPE_INT:
 
114
        return g_strdup_printf ("%i", g_value_get_int (val));
 
115
      case G_TYPE_UINT:
 
116
        return g_strdup_printf ("%u", g_value_get_uint (val));
 
117
      case G_TYPE_LONG:
 
118
        return g_strdup_printf ("%ld", g_value_get_long (val));
 
119
      case G_TYPE_ULONG:
 
120
        return g_strdup_printf ("%lu", g_value_get_ulong (val));
 
121
      case G_TYPE_INT64:
 
122
        return g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (val));
 
123
      case G_TYPE_UINT64:
 
124
        return g_strdup_printf ("%" G_GUINT64_FORMAT, g_value_get_uint64 (val));
 
125
      case G_TYPE_ENUM:
 
126
        return g_strdup_printf ("%d" , g_value_get_enum (val));
 
127
      case G_TYPE_FLAGS:
 
128
        return g_strdup_printf ("%u", g_value_get_flags (val));
 
129
      case G_TYPE_FLOAT:
 
130
        return g_strdup_printf ("%f", g_value_get_float (val));
 
131
      case G_TYPE_DOUBLE:
 
132
        return g_strdup_printf ("%g", g_value_get_double (val));
 
133
      default:
 
134
        DEBUG ("Unsupported type %s", G_VALUE_TYPE_NAME (val));
 
135
        return NULL;
 
136
    }
 
137
}
 
138
 
 
139
/* Is an AG key corresponding to an MC _parameter_ global? */
 
140
static gboolean _ag_key_is_global (const gchar *key)
 
141
{
 
142
  return
 
143
    g_str_equal (key, AG_ACCOUNT_KEY) ||
 
144
    g_str_equal (key, PASSWORD_KEY) ||
 
145
    g_str_equal (key, AG_LABEL_KEY);
 
146
}
 
147
 
 
148
/* Is an AG key corresponding to an MC non-parameter service specific? */
 
149
static gboolean _ag_value_is_local (const gchar *key)
 
150
{
 
151
  return g_str_equal (key, MC_IDENTITY_KEY);
 
152
}
 
153
 
 
154
static gboolean
 
155
_ag_account_select_default_im_service (AgAccount *account)
 
156
{
 
157
  gboolean have_im_service = FALSE;
 
158
  GList *first = ag_account_list_services_by_type (account, "IM");
 
159
 
 
160
  if (first != NULL && first->data != NULL)
 
161
    {
 
162
      have_im_service = TRUE;
 
163
      DEBUG ("default IM service %s", ag_service_get_name (first->data));
 
164
      ag_account_select_service (account, first->data);
 
165
    }
 
166
 
 
167
  ag_service_list_free (first);
 
168
 
 
169
  return have_im_service;
 
170
}
 
171
 
 
172
static AgSettingSource
 
173
_ag_account_global_value (AgAccount *account,
 
174
    const gchar *key,
 
175
    GValue *value)
 
176
{
 
177
  AgSettingSource src = AG_SETTING_SOURCE_NONE;
 
178
  AgService *service = ag_account_get_selected_service (account);
 
179
 
 
180
  if (service != NULL)
 
181
    {
 
182
      ag_account_select_service (account, NULL);
 
183
      src = ag_account_get_value (account, key, value);
 
184
      ag_account_select_service (account, service);
 
185
    }
 
186
  else
 
187
    {
 
188
      src = ag_account_get_value (account, key, value);
 
189
    }
 
190
 
 
191
  return src;
 
192
}
 
193
 
 
194
static AgSettingSource
 
195
_ag_account_local_value (AgAccount *account,
 
196
    const gchar *key,
 
197
    GValue *value)
 
198
{
 
199
  AgSettingSource src = AG_SETTING_SOURCE_NONE;
 
200
  AgService *service = ag_account_get_selected_service (account);
 
201
 
 
202
  if (service != NULL)
 
203
    {
 
204
      src = ag_account_get_value (account, key, value);
 
205
    }
 
206
  else
 
207
    {
 
208
      _ag_account_select_default_im_service (account);
 
209
      src = ag_account_get_value (account, key, value);
 
210
      ag_account_select_service (account, NULL);
 
211
    }
 
212
 
 
213
  return src;
 
214
}
 
215
 
 
216
static void _sso_toggled (GObject *object,
 
217
    const gchar *service_name,
 
218
    gboolean enabled,
 
219
    gpointer data)
 
220
{
 
221
  AgAccount *account = AG_ACCOUNT (object);
 
222
  AgAccountId id = account->id;
 
223
  McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (data);
 
224
  McpAccountStorage *mcpa = MCP_ACCOUNT_STORAGE (sso);
 
225
  gboolean on = FALSE;
 
226
  const gchar *name = NULL;
 
227
  AgService *service = NULL;
 
228
  AgManager *manager = NULL;
 
229
 
 
230
  /* If the account manager isn't ready, account state changes are of no   *
 
231
   * interest to us: it will pick up the then-current state of the account *
 
232
   * when it does become ready, and anything that happens between now and  *
 
233
   * then is not important:                                                */
 
234
  if (!sso->ready)
 
235
    return;
 
236
 
 
237
  manager = ag_account_get_manager (account);
 
238
  service = ag_manager_get_service (manager, service_name);
 
239
 
 
240
  /* non IM services are of no interest to us, we don't handle them */
 
241
  if (service != NULL)
 
242
    {
 
243
      const gchar *service_type = ag_service_get_service_type (service);
 
244
 
 
245
      if (!g_str_equal (service_type, "IM"))
 
246
        return;
 
247
    }
 
248
 
 
249
  on = _sso_account_enabled (account, service);
 
250
  name = g_hash_table_lookup (sso->id_name_map, GUINT_TO_POINTER (id));
 
251
 
 
252
  if (name != NULL)
 
253
    {
 
254
      const gchar *value = on ? "true" : "false";
 
255
      McpAccountManager *am = sso->manager_interface;
 
256
 
 
257
      mcp_account_manager_set_value (am, name, "Enabled", value);
 
258
      g_signal_emit_by_name (mcpa, "toggled", name, on);
 
259
    }
 
260
  else
 
261
    {
 
262
      DEBUG ("received enabled=%u signal for unknown SSO account %u", on, id);
 
263
    }
 
264
}
 
265
 
 
266
static void _sso_deleted (GObject *object,
 
267
    AgAccountId id,
 
268
    gpointer data)
 
269
{
 
270
  McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (data);
 
271
 
 
272
  if (sso->ready)
 
273
    {
 
274
      const gchar *name =
 
275
        g_hash_table_lookup (sso->id_name_map, GUINT_TO_POINTER (id));
 
276
 
 
277
      /* if the account was in our cache, then this was a 3rd party delete *
 
278
       * op that someone did behind our back: fire the signal and clean up */
 
279
      if (name != NULL)
 
280
        {
 
281
          McpAccountStorage *mcpa = MCP_ACCOUNT_STORAGE (sso);
 
282
          gchar *signalled_name = g_strdup (name);
 
283
 
 
284
          /* forget id->name map first, so the signal can't start a loop */
 
285
          g_hash_table_remove (sso->id_name_map, GUINT_TO_POINTER (id));
 
286
          g_hash_table_remove (sso->accounts, signalled_name);
 
287
          g_signal_emit_by_name (mcpa, "deleted", signalled_name);
 
288
 
 
289
          g_free (signalled_name);
 
290
        }
 
291
    }
 
292
  else
 
293
    {
 
294
      DelayedSignalData *sig_data = g_slice_new0 (DelayedSignalData);
 
295
 
 
296
      sig_data->signal = DELAYED_DELETE;
 
297
      sig_data->account_id = id;
 
298
      g_queue_push_tail (sso->pending_signals, sig_data);
 
299
    }
 
300
}
 
301
 
 
302
static void _sso_account_enable (AgAccount *account,
 
303
    AgService *service,
 
304
    gboolean on)
 
305
{
 
306
  AgService *original = ag_account_get_selected_service (account);
 
307
 
 
308
  /* turn the local enabled flag on/off as required */
 
309
  if (service != NULL)
 
310
    ag_account_select_service (account, service);
 
311
  else
 
312
    _ag_account_select_default_im_service (account);
 
313
 
 
314
  ag_account_set_enabled (account, on);
 
315
 
 
316
  /* if we are turning the account on, the global flag must also be set *
 
317
   * NOTE: this isn't needed when turning the account off               */
 
318
  if (on)
 
319
    {
 
320
      ag_account_select_service (account, NULL);
 
321
      ag_account_set_enabled (account, on);
 
322
    }
 
323
 
 
324
  ag_account_select_service (account, original);
 
325
}
 
326
 
 
327
static gboolean _sso_account_enabled (AgAccount *account,
 
328
    AgService *service)
 
329
{
 
330
  gboolean local  = FALSE;
 
331
  gboolean global = FALSE;
 
332
  AgService *original = ag_account_get_selected_service (account);
 
333
 
 
334
  if (service == NULL)
 
335
    {
 
336
      _ag_account_select_default_im_service (account);
 
337
      local = ag_account_get_enabled (account);
 
338
    }
 
339
  else
 
340
    {
 
341
      if (original != service)
 
342
        ag_account_select_service (account, service);
 
343
 
 
344
      local = ag_account_get_enabled (account);
 
345
    }
 
346
 
 
347
  ag_account_select_service (account, NULL);
 
348
  global = ag_account_get_enabled (account);
 
349
 
 
350
  ag_account_select_service (account, original);
 
351
 
 
352
  DEBUG ("_sso_account_enabled: global:%d && local:%d", global, local);
 
353
 
 
354
  return local && global;
 
355
}
 
356
 
 
357
static void _sso_created (GObject *object,
 
358
    AgAccountId id,
 
359
    gpointer data)
 
360
{
 
361
  AgManager *ag_manager = AG_MANAGER (object);
 
362
  McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (data);
 
363
  gchar *name =
 
364
    g_hash_table_lookup (sso->id_name_map, GUINT_TO_POINTER (id));
 
365
 
 
366
  if (sso->ready)
 
367
    {
 
368
      /* if we already know the account's name, we shouldn't fire the new *
 
369
       * account signal as it is one we (and our superiors) already have  */
 
370
      if (name == NULL)
 
371
        {
 
372
          McpAccountStorage *mcpa = MCP_ACCOUNT_STORAGE (sso);
 
373
          AgAccount *account = ag_manager_get_account (ag_manager, id);
 
374
 
 
375
          if (account != NULL)
 
376
            {
 
377
              /* this will be owned by the ag account hash, do not free it */
 
378
              name = _ag_accountid_to_mc_key (sso, id, TRUE);
 
379
 
 
380
              if (name != NULL)
 
381
                {
 
382
                  g_hash_table_insert (sso->accounts, name, account);
 
383
                  g_hash_table_insert (sso->id_name_map, GUINT_TO_POINTER (id),
 
384
                      g_strdup (name));
 
385
 
 
386
                  save_value (account, MC_IDENTITY_KEY, name);
 
387
 
 
388
                  ag_account_store (account, _ag_account_stored_cb, NULL);
 
389
 
 
390
                  g_signal_emit_by_name (mcpa, "created", name);
 
391
 
 
392
                  g_signal_connect (account, "enabled",
 
393
                      G_CALLBACK (_sso_toggled), data);
 
394
 
 
395
                  /* this doesn't seem to fire when we expect it to, but this *
 
396
                   * is the right place to hook it up:                        */
 
397
                  /* ag_account_watch_dir (account, "", _sso_updated, sso);   */
 
398
                }
 
399
              else
 
400
                {
 
401
                  DEBUG ("SSO account #%u is unnameable, ignoring it", id);
 
402
                }
 
403
            }
 
404
        }
 
405
    }
 
406
  else
 
407
    {
 
408
      DelayedSignalData *sig_data = g_slice_new0 (DelayedSignalData);
 
409
 
 
410
      sig_data->signal = DELAYED_CREATE;
 
411
      sig_data->account_id = id;
 
412
      g_queue_push_tail (sso->pending_signals, sig_data);
 
413
    }
 
414
}
 
415
 
 
416
static void
 
417
mcd_account_manager_sso_init (McdAccountManagerSso *self)
 
418
{
 
419
  DEBUG ("mcd_account_manager_sso_init");
 
420
  self->ag_manager = ag_manager_new ();
 
421
  self->accounts =
 
422
    g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 
423
  self->id_name_map =
 
424
    g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
 
425
 
 
426
  self->pending_signals = g_queue_new ();
 
427
 
 
428
  self->services = ag_manager_list_services (self->ag_manager);
 
429
 
 
430
  g_signal_connect(self->ag_manager, "account-deleted",
 
431
      G_CALLBACK (_sso_deleted), self);
 
432
  g_signal_connect(self->ag_manager, "account-created",
 
433
      G_CALLBACK (_sso_created), self);
 
434
}
 
435
 
 
436
static void
 
437
mcd_account_manager_sso_class_init (McdAccountManagerSsoClass *cls)
 
438
{
 
439
  DEBUG ("mcd_account_manager_sso_class_init");
 
440
}
 
441
 
 
442
static void
 
443
_ag_account_stored_cb (AgAccount *acct, const GError *err, gpointer ignore)
 
444
{
 
445
  GValue uid = { 0 };
 
446
  const gchar *name = NULL;
 
447
  AgSettingSource src = AG_SETTING_SOURCE_NONE;
 
448
 
 
449
  g_value_init (&uid, G_TYPE_STRING);
 
450
 
 
451
  src = _ag_account_local_value (acct, MC_IDENTITY_KEY, &uid);
 
452
 
 
453
  if (src != AG_SETTING_SOURCE_NONE && G_VALUE_HOLDS_STRING (&uid))
 
454
    {
 
455
      name = g_value_get_string (&uid);
 
456
      DEBUG ("%p:%s stored: %s", acct, name, err ? err->message : "-");
 
457
      g_value_unset (&uid);
 
458
    }
 
459
  else
 
460
    {
 
461
      DEBUG ("%p:%s not stored? %s", acct,
 
462
          ag_account_get_display_name (acct), err ? err->message : "-");
 
463
    }
 
464
}
 
465
 
 
466
static gchar *
 
467
_ag_accountid_to_mc_key (const McdAccountManagerSso *sso,
 
468
    AgAccountId id,
 
469
    gboolean create)
 
470
{
 
471
  AgAccount *acct = ag_manager_get_account (sso->ag_manager, id);
 
472
  AgSettingSource src = AG_SETTING_SOURCE_NONE;
 
473
  GValue value = { 0 };
 
474
 
 
475
  DEBUG ("AG Account ID: %u", id);
 
476
 
 
477
  g_value_init (&value, G_TYPE_STRING);
 
478
 
 
479
  /* first look for the stored TMC uid */
 
480
  src = _ag_account_local_value (acct, MC_IDENTITY_KEY, &value);
 
481
 
 
482
  /* if we found something, our work here is done: */
 
483
  if (src != AG_SETTING_SOURCE_NONE)
 
484
    {
 
485
      gchar *uid = g_value_dup_string (&value);
 
486
      g_value_unset (&value);
 
487
      return uid;
 
488
    }
 
489
 
 
490
  if (!create)
 
491
    return NULL;
 
492
 
 
493
  DEBUG ("no " MC_IDENTITY_KEY " found, synthesising one:\n");
 
494
 
 
495
  src = _ag_account_global_value (acct, AG_ACCOUNT_KEY, &value);
 
496
 
 
497
  DEBUG (AG_ACCOUNT_KEY ": %s; type: %s",
 
498
      src ? "exists" : "missing",
 
499
      src ? (G_VALUE_TYPE_NAME (&value)) : "n/a" );
 
500
 
 
501
  if (src != AG_SETTING_SOURCE_NONE && G_VALUE_HOLDS_STRING (&value))
 
502
    {
 
503
      AgAccountSettingIter setting;
 
504
      const gchar *k;
 
505
      const GValue *v;
 
506
      GValue cmanager = { 0 };
 
507
      GValue protocol = { 0 };
 
508
      const gchar *cman, *proto;
 
509
      McpAccountManager *am = sso->manager_interface;
 
510
      AgService *service = ag_account_get_selected_service (acct);
 
511
      GHashTable *params = g_hash_table_new_full (g_str_hash, g_str_equal,
 
512
          g_free, NULL);
 
513
      gchar *name = NULL;
 
514
 
 
515
      g_value_init (&cmanager, G_TYPE_STRING);
 
516
      g_value_init (&protocol, G_TYPE_STRING);
 
517
 
 
518
      /* if we weren't on a service when got here, pick the most likely one: */
 
519
      if (service == NULL)
 
520
        _ag_account_select_default_im_service (acct);
 
521
 
 
522
      ag_account_get_value (acct, MC_CMANAGER_KEY, &cmanager);
 
523
      cman = g_value_get_string (&cmanager);
 
524
 
 
525
      if (cman == NULL)
 
526
        goto cleanup;
 
527
 
 
528
      ag_account_get_value (acct, MC_PROTOCOL_KEY, &protocol);
 
529
      proto = g_value_get_string (&protocol);
 
530
 
 
531
      if (proto == NULL)
 
532
        goto cleanup;
 
533
 
 
534
      g_hash_table_insert (params, g_strdup (MC_ACCOUNT_KEY), &value);
 
535
 
 
536
      /* prepare the hash of MC param keys -> GValue */
 
537
      /* NOTE: some AG bare settings map to MC parameters,   *
 
538
       * so we must iterate over all AG settings, parameters *
 
539
       * and bare settings included                          */
 
540
 
 
541
      /* first any matching global values: */
 
542
      ag_account_select_service (acct, NULL);
 
543
      ag_account_settings_iter_init (acct, &setting, NULL);
 
544
 
 
545
      while (ag_account_settings_iter_next (&setting, &k, &v))
 
546
        {
 
547
          gchar *mc_key = get_mc_param_key (k);
 
548
 
 
549
          if (mc_key != NULL && g_str_has_prefix (mc_key, PARAM_PREFIX_MC))
 
550
            {
 
551
              gchar *param_key = g_strdup (mc_key + strlen (PARAM_PREFIX_MC));
 
552
 
 
553
              g_hash_table_insert (params, param_key, (gpointer) v);
 
554
            }
 
555
 
 
556
          g_free (mc_key);
 
557
        }
 
558
 
 
559
      /* then any service specific settings */
 
560
      if (service != NULL)
 
561
        ag_account_select_service (acct, service);
 
562
      else
 
563
        _ag_account_select_default_im_service (acct);
 
564
 
 
565
      ag_account_settings_iter_init (acct, &setting, NULL);
 
566
      while (ag_account_settings_iter_next (&setting, &k, &v))
 
567
        {
 
568
          gchar *mc_key = get_mc_param_key (k);
 
569
 
 
570
          if (mc_key != NULL && g_str_has_prefix (mc_key, PARAM_PREFIX_MC))
 
571
            {
 
572
              gchar *param_key = g_strdup (mc_key + strlen (PARAM_PREFIX_MC));
 
573
 
 
574
              g_hash_table_insert (params, param_key, (gpointer) v);
 
575
            }
 
576
 
 
577
          g_free (mc_key);
 
578
        }
 
579
 
 
580
      name = mcp_account_manager_get_unique_name (am, cman, proto, params);
 
581
 
 
582
    cleanup:
 
583
      ag_account_select_service (acct, service);
 
584
      g_hash_table_unref (params);
 
585
      g_value_unset (&value);
 
586
      g_value_unset (&cmanager);
 
587
      g_value_unset (&protocol);
 
588
 
 
589
      DEBUG (MC_IDENTITY_KEY " value %p:%s synthesised", name, name);
 
590
      return name;
 
591
    }
 
592
 
 
593
  DEBUG (MC_IDENTITY_KEY "not synthesised, returning NULL");
 
594
  return NULL;
 
595
}
 
596
 
 
597
static AgAccount *
 
598
get_ag_account (const McdAccountManagerSso *sso,
 
599
    const McpAccountManager *am,
 
600
    const gchar *name,
 
601
    AgAccountId *id)
 
602
{
 
603
  AgAccount *account;
 
604
 
 
605
  g_return_val_if_fail (id != NULL, NULL);
 
606
 
 
607
  /* we have a cached account, just return that */
 
608
  account = g_hash_table_lookup (sso->accounts, name);
 
609
  if (account != NULL)
 
610
    {
 
611
      *id = account->id;
 
612
      return account;
 
613
    }
 
614
 
 
615
  *id = 0;
 
616
 
 
617
  return NULL;
 
618
}
 
619
 
 
620
static void
 
621
save_param (AgAccount *account,
 
622
    const gchar *key,
 
623
    const gchar *val)
 
624
{
 
625
  const gchar *pkey = key + strlen (PARAM_PREFIX_MC);
 
626
  gchar *param_key = NULL;
 
627
  gboolean global = FALSE;
 
628
  AgService *service = ag_account_get_selected_service (account);
 
629
 
 
630
  /* username and password are parameters in MC but not in AG: *
 
631
   * also it's 'username' in AG but 'account' in MC            */
 
632
  if (g_str_equal (pkey, MC_ACCOUNT_KEY))
 
633
    param_key = g_strdup (AG_ACCOUNT_KEY);
 
634
  else if (g_str_equal (pkey, PASSWORD_KEY))
 
635
    param_key = g_strdup (PASSWORD_KEY);
 
636
  else
 
637
    param_key = g_strdup_printf (PARAM_PREFIX "%s", pkey);
 
638
 
 
639
  global = _ag_key_is_global (param_key);
 
640
 
 
641
  if (global)
 
642
    ag_account_select_service (account, NULL);
 
643
  else if (service == NULL)
 
644
    _ag_account_select_default_im_service (account);
 
645
 
 
646
  if (val != NULL)
 
647
    {
 
648
      GValue value = { 0 };
 
649
 
 
650
      g_value_init (&value, G_TYPE_STRING);
 
651
      g_value_set_string (&value, val);
 
652
      ag_account_set_value (account, param_key, &value);
 
653
      g_value_unset (&value);
 
654
    }
 
655
  else
 
656
    {
 
657
      ag_account_set_value (account, param_key, NULL);
 
658
    }
 
659
 
 
660
  /* leave the selected service as we found it: */
 
661
  ag_account_select_service (account, service);
 
662
 
 
663
  g_free (param_key);
 
664
}
 
665
 
 
666
static void
 
667
save_value (AgAccount *account,
 
668
    const gchar *key,
 
669
    const gchar *val)
 
670
{
 
671
  AgService *service = NULL;
 
672
  gboolean local = FALSE;
 
673
 
 
674
  /* special cases, never saved */
 
675
  if (g_str_equal (key, MC_CMANAGER_KEY) || g_str_equal (key, MC_PROTOCOL_KEY))
 
676
    return;
 
677
 
 
678
  /* values, unlike parameters, are _mostly_ global - not service specific */
 
679
  service = ag_account_get_selected_service (account);
 
680
  local = _ag_value_is_local (key);
 
681
 
 
682
  /* Enabled is both a global and a local value, for extra fun: */
 
683
  if (g_str_equal (key, "Enabled"))
 
684
    {
 
685
      gboolean on = g_str_equal (val, "true");
 
686
 
 
687
      DEBUG ("setting enabled flag: '%d'", on);
 
688
      _sso_account_enable (account, NULL, on);
 
689
 
 
690
      goto cleanup;
 
691
    }
 
692
 
 
693
  /* pick the right service/global section of SSO, and switch if necessary */
 
694
  if (local && service == NULL)
 
695
    _ag_account_select_default_im_service (account);
 
696
  else if (!local && service != NULL)
 
697
    ag_account_select_service (account, NULL);
 
698
 
 
699
  /* yet another special case mapping */
 
700
  if (g_str_equal (key, MC_LABEL_KEY))
 
701
    key = AG_LABEL_KEY;
 
702
 
 
703
  if (val == NULL)
 
704
    {
 
705
      ag_account_set_value (account, key, NULL);
 
706
    }
 
707
  else
 
708
    {
 
709
      GValue value = { 0 };
 
710
      g_value_init (&value, G_TYPE_STRING);
 
711
      g_value_set_string (&value, val);
 
712
      ag_account_set_value (account, key, &value);
 
713
      g_value_unset (&value);
 
714
    }
 
715
 
 
716
 cleanup:
 
717
  /* leave the slected service as we found it */
 
718
  ag_account_select_service (account, service);
 
719
}
 
720
 
 
721
static gboolean
 
722
_set (const McpAccountStorage *self,
 
723
    const McpAccountManager *am,
 
724
    const gchar *acct,
 
725
    const gchar *key,
 
726
    const gchar *val)
 
727
{
 
728
  AgAccountId id;
 
729
  McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self);
 
730
  AgAccount *account = get_ag_account (sso, am, acct, &id);
 
731
 
 
732
  /* we no longer create accounts in libaccount: either an account exists *
 
733
   * in libaccount as a result of some 3rd party intervention, or it is   *
 
734
   * not an account that this plugin should ever concern itself with      */
 
735
  g_return_val_if_fail (key != NULL, FALSE);
 
736
 
 
737
  if (account != NULL)
 
738
    {
 
739
      if (g_str_equal (key, "sso-services"))
 
740
        return TRUE;
 
741
 
 
742
      if (g_str_has_prefix (key, PARAM_PREFIX_MC))
 
743
        save_param (account, key, val);
 
744
      else
 
745
        save_value (account, key, val);
 
746
 
 
747
      sso->save = TRUE;
 
748
      return TRUE;
 
749
    }
 
750
 
 
751
  /* no account and we couldn't/wouldn't create one */
 
752
  return FALSE;
 
753
}
 
754
 
 
755
/* get the MC parameter key corresponding to an SSO key          *
 
756
 * note that not all MC parameters correspond to SSO parameters, *
 
757
 * some correspond to values instead                             */
 
758
/* NOTE: value keys are passed through unchanged */
 
759
/* NOTE: except for "name", which maps to "DisplayName" */
 
760
static gchar *
 
761
get_mc_param_key (const gchar *key)
 
762
{
 
763
  /* these two are parameters in MC but not in AG */
 
764
  if (g_str_equal (key, AG_ACCOUNT_KEY))
 
765
    return g_strdup (PARAM_PREFIX_MC MC_ACCOUNT_KEY);
 
766
 
 
767
  if (g_str_equal (key, PASSWORD_KEY))
 
768
    return g_strdup (PARAM_PREFIX_MC PASSWORD_KEY);
 
769
 
 
770
  /* yet another special case */
 
771
  if (g_str_equal (key, AG_LABEL_KEY))
 
772
    return g_strdup (MC_LABEL_KEY);
 
773
 
 
774
  /* now check for regular params */
 
775
  if (g_str_has_prefix (key, PARAM_PREFIX))
 
776
    return g_strdup_printf (PARAM_PREFIX_MC "%s", key + strlen (PARAM_PREFIX));
 
777
 
 
778
  return g_strdup (key);
 
779
}
 
780
 
 
781
/* get the SSO key corresponding to an MC parameter */
 
782
/* NOTE: value keys are passed through unchanged */
 
783
static gchar *
 
784
get_ag_param_key (const gchar *key)
 
785
{
 
786
  if (g_str_equal (key, PARAM_PREFIX_MC MC_ACCOUNT_KEY))
 
787
    return g_strdup (AG_ACCOUNT_KEY);
 
788
 
 
789
  if (g_str_equal (key, PARAM_PREFIX_MC PASSWORD_KEY))
 
790
    return g_strdup (PASSWORD_KEY);
 
791
 
 
792
  if (g_str_has_prefix (key, PARAM_PREFIX_MC))
 
793
    return g_strdup_printf (PARAM_PREFIX "%s", key + strlen (PARAM_PREFIX_MC));
 
794
 
 
795
  return g_strdup (key);
 
796
}
 
797
 
 
798
static gboolean
 
799
_get (const McpAccountStorage *self,
 
800
    const McpAccountManager *am,
 
801
    const gchar *acct,
 
802
    const gchar *key)
 
803
{
 
804
  AgAccountId id;
 
805
  McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self);
 
806
  AgAccount *account = get_ag_account (sso, am, acct, &id);
 
807
  AgService *service = ag_account_get_selected_service (account);
 
808
 
 
809
  if (account == NULL)
 
810
    return FALSE;
 
811
 
 
812
  if (key != NULL)
 
813
    {
 
814
      if (g_str_equal (key, "Enabled"))
 
815
        {
 
816
          const gchar *v = NULL;
 
817
 
 
818
          v = _sso_account_enabled (account, service) ? "true" : "false";
 
819
          mcp_account_manager_set_value (am, acct, key, v);
 
820
        }
 
821
      else if (g_str_equal (key, "sso-services"))
 
822
        {
 
823
          GString *result = g_string_new ("");
 
824
          AgManager * agm = ag_account_get_manager (account);
 
825
          GList *services = ag_manager_list_services (agm);
 
826
          GList *item = NULL;
 
827
 
 
828
          for (item = services; item != NULL; item = g_list_next (item))
 
829
            {
 
830
              const gchar *name = ag_service_get_name (item->data);
 
831
 
 
832
              g_string_append_printf (result, "%s;", name);
 
833
            }
 
834
 
 
835
          mcp_account_manager_set_value (am, acct, key, result->str);
 
836
 
 
837
          ag_service_list_free (services);
 
838
          g_string_free (result, TRUE);
 
839
        }
 
840
      else
 
841
        {
 
842
          gchar *k = get_ag_param_key (key);
 
843
          GValue v = { 0 };
 
844
          AgSettingSource src = AG_SETTING_SOURCE_NONE;
 
845
 
 
846
          g_value_init (&v, G_TYPE_STRING);
 
847
 
 
848
          if (_ag_key_is_global (k))
 
849
            {
 
850
              src = _ag_account_global_value (account, k, &v);
 
851
            }
 
852
          else
 
853
            {
 
854
              src = _ag_account_local_value (account, k, &v);
 
855
            }
 
856
 
 
857
          if (src != AG_SETTING_SOURCE_NONE)
 
858
            {
 
859
              gchar *val = _gvalue_to_string (&v);
 
860
 
 
861
              mcp_account_manager_set_value (am, acct, key, val);
 
862
 
 
863
              g_free (val);
 
864
            }
 
865
 
 
866
          g_value_unset (&v);
 
867
          g_free (k);
 
868
        }
 
869
    }
 
870
  else
 
871
    {
 
872
      AgAccountSettingIter setting;
 
873
      const gchar *k;
 
874
      const GValue *v;
 
875
      const gchar *on = NULL;
 
876
 
 
877
      /* pick the IM service if we haven't got one set */
 
878
      if (service == NULL)
 
879
        _ag_account_select_default_im_service (account);
 
880
 
 
881
      ag_account_settings_iter_init (account, &setting, NULL);
 
882
      while (ag_account_settings_iter_next (&setting, &k, &v))
 
883
        {
 
884
          if (!_ag_key_is_global (k))
 
885
            {
 
886
              gchar *mc_key = get_mc_param_key (k);
 
887
              gchar *value = _gvalue_to_string (v);
 
888
 
 
889
              mcp_account_manager_set_value (am, acct, mc_key, value);
 
890
 
 
891
              g_free (value);
 
892
              g_free (mc_key);
 
893
            }
 
894
        }
 
895
 
 
896
      /* deselect any service we may have to get global settings */
 
897
      ag_account_select_service (account, NULL);
 
898
      ag_account_settings_iter_init (account, &setting, NULL);
 
899
 
 
900
      while (ag_account_settings_iter_next (&setting, &k, &v))
 
901
        {
 
902
          if (_ag_key_is_global (k))
 
903
            {
 
904
              gchar *mc_key = get_mc_param_key (k);
 
905
              gchar *value  = _gvalue_to_string (v);
 
906
 
 
907
              mcp_account_manager_set_value (am, acct, mc_key, value);
 
908
 
 
909
              g_free (value);
 
910
              g_free (mc_key);
 
911
            }
 
912
        }
 
913
 
 
914
      /* special case, actually two separate but related flags in SSO */
 
915
      on = _sso_account_enabled (account, NULL) ? "true" : "false";
 
916
      mcp_account_manager_set_value (am, acct, "Enabled", on);
 
917
    }
 
918
 
 
919
  /* leave the selected service as we found it */
 
920
  ag_account_select_service (account, service);
 
921
  return TRUE;
 
922
}
 
923
 
 
924
static gboolean
 
925
_delete (const McpAccountStorage *self,
 
926
      const McpAccountManager *am,
 
927
      const gchar *acct,
 
928
      const gchar *key)
 
929
{
 
930
  AgAccountId id;
 
931
  McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self);
 
932
  AgAccount *account = get_ag_account (sso, am, acct, &id);
 
933
 
 
934
  /* have no values for this account, nothing to do here: */
 
935
  if (account == NULL)
 
936
    return TRUE;
 
937
 
 
938
  if (key == NULL)
 
939
    {
 
940
      ag_account_delete (account);
 
941
      g_hash_table_remove (sso->accounts, acct);
 
942
      g_hash_table_remove (sso->id_name_map, GUINT_TO_POINTER (id));
 
943
    }
 
944
  else
 
945
    {
 
946
      if (g_str_has_prefix (key, PARAM_PREFIX_MC))
 
947
        save_param (account, key, NULL);
 
948
      else
 
949
        save_value (account, key, NULL);
 
950
    }
 
951
 
 
952
  return TRUE;
 
953
}
 
954
 
 
955
static gboolean
 
956
_commit (const McpAccountStorage *self,
 
957
    const McpAccountManager *am)
 
958
{
 
959
  GHashTableIter iter;
 
960
  McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self);
 
961
  gchar *key;
 
962
  AgAccount *account;
 
963
 
 
964
  if (!sso->save)
 
965
    return TRUE;
 
966
 
 
967
  /* FIXME: implement commit_one(), and use account_name if it's non-NULL */
 
968
 
 
969
  g_hash_table_iter_init (&iter, sso->accounts);
 
970
 
 
971
  while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &account))
 
972
    {
 
973
      /* this value ties MC accounts to SSO accounts */
 
974
      save_value (account, MC_IDENTITY_KEY, key);
 
975
      ag_account_store (account, _ag_account_stored_cb, NULL);
 
976
    }
 
977
 
 
978
  /* any pending changes should now have been pushed, clear the save-me flag */
 
979
  sso->save = FALSE;
 
980
 
 
981
  return TRUE;
 
982
}
 
983
 
 
984
static void
 
985
_load_from_libaccounts (McdAccountManagerSso *sso,
 
986
    const McpAccountManager *am)
 
987
{
 
988
  GList *ag_id;
 
989
  GList *ag_ids = ag_manager_list_by_service_type (sso->ag_manager, "IM");
 
990
 
 
991
  for (ag_id = ag_ids; ag_id != NULL; ag_id = g_list_next (ag_id))
 
992
    {
 
993
      const gchar *key;
 
994
      const GValue *val;
 
995
      AgAccountSettingIter iter;
 
996
      AgAccountId id = GPOINTER_TO_UINT (ag_id->data);
 
997
      AgAccount *account = ag_manager_get_account (sso->ag_manager, id);
 
998
      const gchar *enabled = NULL;
 
999
 
 
1000
      if (account != NULL)
 
1001
        {
 
1002
          AgService *service = ag_account_get_selected_service (account);
 
1003
          gchar *name = _ag_accountid_to_mc_key (sso, id, FALSE);
 
1004
 
 
1005
          if (name != NULL)
 
1006
            {
 
1007
              gchar *ident = g_strdup_printf ("%u", id);
 
1008
              GStrv mc_id = g_strsplit (name, "/", 3);
 
1009
 
 
1010
              /* cache the account object, and the ID->name maping: the  *
 
1011
               * latter is required because we might receive an async    *
 
1012
               * delete signal with the ID after libaccounts-glib has    *
 
1013
               * purged all its account data, so we couldn't rely on the *
 
1014
               * MC_IDENTITY_KEY setting.                                */
 
1015
              g_hash_table_insert (sso->accounts, name, account);
 
1016
              g_hash_table_insert (sso->id_name_map, GUINT_TO_POINTER (id),
 
1017
                  g_strdup (name));
 
1018
 
 
1019
              if (service == NULL)
 
1020
                _ag_account_select_default_im_service (account);
 
1021
 
 
1022
              ag_account_settings_iter_init (account, &iter, NULL);
 
1023
 
 
1024
              while (ag_account_settings_iter_next (&iter, &key, &val))
 
1025
                {
 
1026
                  if (!_ag_key_is_global (key))
 
1027
                    {
 
1028
                      gchar *mc_key = get_mc_param_key (key);
 
1029
                      gchar *value = _gvalue_to_string (val);
 
1030
 
 
1031
                      mcp_account_manager_set_value (am, name, mc_key, value);
 
1032
                      g_free (value);
 
1033
                      g_free (mc_key);
 
1034
                    }
 
1035
                }
 
1036
 
 
1037
              ag_account_select_service (account, NULL);
 
1038
              ag_account_settings_iter_init (account, &iter, NULL);
 
1039
 
 
1040
              while (ag_account_settings_iter_next (&iter, &key, &val))
 
1041
                {
 
1042
                  if (_ag_key_is_global (key))
 
1043
                    {
 
1044
                      gchar *mc_key = get_mc_param_key (key);
 
1045
                      gchar *value = _gvalue_to_string (val);
 
1046
 
 
1047
                      mcp_account_manager_set_value (am, name, mc_key, value);
 
1048
                      g_free (value);
 
1049
                      g_free (mc_key);
 
1050
                    }
 
1051
                }
 
1052
 
 
1053
              /* special case, actually two separate but related flags in SSO */
 
1054
              enabled = _sso_account_enabled (account, NULL) ? "true": "false";
 
1055
 
 
1056
              mcp_account_manager_set_value (am, name, "Enabled", enabled);
 
1057
              mcp_account_manager_set_value (am, name, LIBACCT_ID_KEY, ident);
 
1058
              mcp_account_manager_set_value (am, name, MC_CMANAGER_KEY, mc_id[0]);
 
1059
              mcp_account_manager_set_value (am, name, MC_PROTOCOL_KEY, mc_id[1]);
 
1060
              mcp_account_manager_set_value (am, name, MC_IDENTITY_KEY, name);
 
1061
 
 
1062
              ag_account_select_service (account, service);
 
1063
 
 
1064
              g_signal_connect (account, "enabled",
 
1065
                  G_CALLBACK (_sso_toggled), sso);
 
1066
 
 
1067
              /* this doesn't seem to fire when we expect it to, but this *
 
1068
               * is the right place to hook it up:                        */
 
1069
              /* ag_account_watch_dir (account, "", _sso_updated, sso);   */
 
1070
 
 
1071
              g_strfreev (mc_id);
 
1072
              g_free (ident);
 
1073
            }
 
1074
        }
 
1075
      else
 
1076
        {
 
1077
          DelayedSignalData *data = g_slice_new0 (DelayedSignalData);
 
1078
 
 
1079
          data->account_id = id;
 
1080
          g_queue_push_tail (sso->pending_signals, data);
 
1081
        }
 
1082
    }
 
1083
 
 
1084
  sso->loaded = TRUE;
 
1085
  ag_manager_list_free (ag_ids);
 
1086
}
 
1087
 
 
1088
static GList *
 
1089
_list (const McpAccountStorage *self,
 
1090
    const McpAccountManager *am)
 
1091
{
 
1092
  GList *rval = NULL;
 
1093
  McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self);
 
1094
  GList *ag_ids = NULL;
 
1095
  GList *ag_id;
 
1096
 
 
1097
  if (!sso->loaded)
 
1098
    _load_from_libaccounts (sso, am);
 
1099
 
 
1100
  ag_ids = ag_manager_list_by_service_type (sso->ag_manager, "IM");
 
1101
 
 
1102
  for (ag_id = ag_ids; ag_id != NULL; ag_id = g_list_next (ag_id))
 
1103
    {
 
1104
      AgAccountId id = GPOINTER_TO_UINT (ag_id->data);
 
1105
      gchar *name = NULL;
 
1106
 
 
1107
      name = _ag_accountid_to_mc_key (sso, id, FALSE);
 
1108
 
 
1109
      if (name != NULL)
 
1110
        {
 
1111
          DEBUG ("\naccount %s listed", name);
 
1112
          rval = g_list_prepend (rval, name);
 
1113
        }
 
1114
      else
 
1115
        {
 
1116
          DelayedSignalData *data = g_slice_new0 (DelayedSignalData);
 
1117
 
 
1118
          DEBUG ("\naccount %u delayed", id);
 
1119
          data->signal = DELAYED_CREATE;
 
1120
          data->account_id = id;
 
1121
          g_queue_push_tail (sso->pending_signals, data);
 
1122
        }
 
1123
    }
 
1124
 
 
1125
  ag_manager_list_free (ag_ids);
 
1126
 
 
1127
  return rval;
 
1128
}
 
1129
 
 
1130
static void
 
1131
_ready (const McpAccountStorage *self,
 
1132
    const McpAccountManager *am)
 
1133
{
 
1134
  McdAccountManagerSso *sso = MCD_ACCOUNT_MANAGER_SSO (self);
 
1135
 
 
1136
  if (sso->ready)
 
1137
    return;
 
1138
 
 
1139
  g_assert (sso->manager_interface == NULL);
 
1140
  sso->manager_interface = g_object_ref (G_OBJECT (am));
 
1141
  sso->ready = TRUE;
 
1142
 
 
1143
  while (g_queue_get_length (sso->pending_signals) > 0)
 
1144
    {
 
1145
      DelayedSignalData *data = g_queue_pop_head (sso->pending_signals);
 
1146
      GObject *signal_source = G_OBJECT (sso->ag_manager);
 
1147
 
 
1148
      switch (data->signal)
 
1149
        {
 
1150
          case DELAYED_CREATE:
 
1151
            _sso_created (signal_source, data->account_id, sso);
 
1152
            break;
 
1153
          case DELAYED_DELETE:
 
1154
            _sso_deleted (signal_source, data->account_id, sso);
 
1155
            break;
 
1156
          default:
 
1157
            g_assert_not_reached ();
 
1158
        }
 
1159
 
 
1160
      g_slice_free (DelayedSignalData, data);
 
1161
    }
 
1162
 
 
1163
  g_queue_free (sso->pending_signals);
 
1164
  sso->pending_signals = NULL;
 
1165
}
 
1166
 
 
1167
static void
 
1168
account_storage_iface_init (McpAccountStorageIface *iface,
 
1169
    gpointer unused G_GNUC_UNUSED)
 
1170
{
 
1171
  mcp_account_storage_iface_set_name (iface, PLUGIN_NAME);
 
1172
  mcp_account_storage_iface_set_desc (iface, PLUGIN_DESCRIPTION);
 
1173
  mcp_account_storage_iface_set_priority (iface, PLUGIN_PRIORITY);
 
1174
 
 
1175
  mcp_account_storage_iface_implement_get (iface, _get);
 
1176
  mcp_account_storage_iface_implement_set (iface, _set);
 
1177
  mcp_account_storage_iface_implement_delete (iface, _delete);
 
1178
  mcp_account_storage_iface_implement_commit (iface, _commit);
 
1179
  mcp_account_storage_iface_implement_list (iface, _list);
 
1180
  mcp_account_storage_iface_implement_ready (iface, _ready);
 
1181
}
 
1182
 
 
1183
McdAccountManagerSso *
 
1184
mcd_account_manager_sso_new (void)
 
1185
{
 
1186
  return g_object_new (MCD_TYPE_ACCOUNT_MANAGER_SSO, NULL);
 
1187
}