1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
3
* This file is part of mission-control
5
* Copyright (C) 2007 Nokia Corporation.
7
* Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
9
* This library is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Lesser General Public License
11
* version 2.1 as published by the Free Software Foundation.
13
* This library is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26
#include <gconf/gconf-client.h>
30
#include <dbus/dbus.h>
31
#include <dbus/dbus-glib.h>
32
#include <telepathy-glib/dbus.h>
33
#include <libmcclient/mc-account-manager.h>
34
#include <libmcclient/mc-account.h>
36
#define MC_ACCOUNTS_GCONF_BASE "/apps/telepathy/mc/accounts"
37
#define MC_ACCOUNTS_GCONF_KEY_DELETED "deleted"
38
#define MC_ACCOUNTS_GCONF_KEY_PROFILE "profile"
40
#define MC_ACCOUNTS_KEY_MANAGER "manager"
41
#define MC_ACCOUNTS_KEY_PROTOCOL "protocol"
42
#define MC_ACCOUNTS_KEY_PRESETS "presets"
44
#define PROFILE_GROUP "Profile"
46
#define PROFILE_SUFFIX ".profile"
47
#define MANAGER_SUFFIX ".manager"
49
static GMainLoop *main_loop;
50
GConfClient *client = NULL;
51
static gint num_processing_accounts = 0;
58
GHashTable *parameters;
59
GKeyFile *manager_cfg;
66
gchar *normalized_name;
80
account_info_free (AccountInfo *ai)
83
g_free (ai->protocol);
85
g_free (ai->protocol_grp);
86
g_key_file_free (ai->manager_cfg);
87
g_hash_table_destroy (ai->parameters);
89
g_free (ai->avatar.data);
90
g_free (ai->avatar_mime);
91
g_free (ai->display_name);
92
g_free (ai->normalized_name);
98
account_creation_ended (AccountInfo *ai)
100
account_info_free (ai);
101
num_processing_accounts--;
102
if (num_processing_accounts == 0)
103
g_main_loop_quit (main_loop);
107
gc_dup_string (const GConfValue *value)
109
return g_strdup (gconf_value_get_string (value));
113
_mc_manager_get_dirs (void)
115
GSList *dir_list = NULL, *slist;
116
const gchar *dirname;
117
static gchar **manager_dirs = NULL;
120
if (manager_dirs) return (const gchar **)manager_dirs;
122
dirname = g_getenv ("MC_MANAGER_DIR");
123
if (dirname && g_file_test (dirname, G_FILE_TEST_IS_DIR))
124
dir_list = g_slist_prepend (dir_list, (gchar *)dirname);
126
if (MANAGERS_DIR[0] == '/')
128
if (g_file_test (MANAGERS_DIR, G_FILE_TEST_IS_DIR))
129
dir_list = g_slist_prepend (dir_list, MANAGERS_DIR);
133
const gchar * const *dirs;
136
dir = g_build_filename (g_get_user_data_dir(), MANAGERS_DIR, NULL);
137
if (g_file_test (dir, G_FILE_TEST_IS_DIR))
138
dir_list = g_slist_prepend (dir_list, dir);
141
dirs = g_get_system_data_dirs();
142
for (dirname = *dirs; dirname; dirs++, dirname = *dirs)
144
dir = g_build_filename (dirname, MANAGERS_DIR, NULL);
145
if (g_file_test (dir, G_FILE_TEST_IS_DIR))
146
dir_list = g_slist_prepend (dir_list, dir);
151
/* build the string array */
152
n = g_slist_length (dir_list);
153
manager_dirs = g_new (gchar *, n + 1);
154
manager_dirs[n--] = NULL;
155
for (slist = dir_list; slist; slist = slist->next)
156
manager_dirs[n--] = slist->data;
157
g_slist_free (dir_list);
158
return (const gchar **)manager_dirs;
162
_mc_manager_filename (const gchar *unique_name)
164
const gchar **manager_dirs;
165
const gchar *dirname;
166
gchar *filename, *filepath = NULL;
168
manager_dirs = _mc_manager_get_dirs ();
169
if (!manager_dirs) return NULL;
171
filename = g_strconcat (unique_name, MANAGER_SUFFIX, NULL);
172
for (dirname = *manager_dirs; dirname; manager_dirs++, dirname = *manager_dirs)
174
filepath = g_build_filename (dirname, filename, NULL);
175
if (g_file_test (filepath, G_FILE_TEST_EXISTS)) break;
184
_mc_profile_get_dirs (void)
186
GSList *dir_list = NULL, *slist;
187
const gchar *dirname;
188
static gchar **profile_dirs = NULL;
191
if (profile_dirs) return (const gchar **)profile_dirs;
193
dirname = g_getenv ("MC_PROFILE_DIR");
194
if (dirname && g_file_test (dirname, G_FILE_TEST_IS_DIR))
195
dir_list = g_slist_prepend (dir_list, (gchar *)dirname);
197
if (PROFILES_DIR[0] == '/')
199
if (g_file_test (PROFILES_DIR, G_FILE_TEST_IS_DIR))
200
dir_list = g_slist_prepend (dir_list, PROFILES_DIR);
204
const gchar * const *dirs;
207
dir = g_build_filename (g_get_user_data_dir(), PROFILES_DIR, NULL);
208
if (g_file_test (dir, G_FILE_TEST_IS_DIR))
209
dir_list = g_slist_prepend (dir_list, dir);
212
dirs = g_get_system_data_dirs();
213
for (dirname = *dirs; dirname; dirs++, dirname = *dirs)
215
dir = g_build_filename (dirname, PROFILES_DIR, NULL);
216
if (g_file_test (dir, G_FILE_TEST_IS_DIR))
217
dir_list = g_slist_prepend (dir_list, dir);
222
/* build the string array */
223
n = g_slist_length (dir_list);
224
profile_dirs = g_new (gchar *, n + 1);
225
profile_dirs[n--] = NULL;
226
for (slist = dir_list; slist; slist = slist->next)
227
profile_dirs[n--] = slist->data;
228
g_slist_free (dir_list);
229
return (const gchar **)profile_dirs;
233
get_profile_path (const gchar *name)
235
const gchar **profile_dirs;
236
const gchar *dirname;
237
gchar *filename, *filepath = NULL;
239
profile_dirs = _mc_profile_get_dirs ();
240
if (!profile_dirs) return NULL;
242
filename = g_strconcat (name, PROFILE_SUFFIX, NULL);
243
for (dirname = *profile_dirs; dirname; profile_dirs++, dirname = *profile_dirs)
245
filepath = g_build_filename (dirname, filename, NULL);
246
if (g_file_test (filepath, G_FILE_TEST_EXISTS)) break;
255
account_key (const gchar *account, const gchar *key)
257
static gchar buffer[2048];
259
g_snprintf (buffer, sizeof (buffer), "%s/%s/%s", MC_ACCOUNTS_GCONF_BASE, account, key);
264
add_parameter (AccountInfo *ai, const gchar *name, ParamValue pv, gchar signature)
268
value = g_new0(GValue, 1);
272
case DBUS_TYPE_STRING:
273
g_value_init (value, G_TYPE_STRING);
274
g_value_take_string (value, pv.v_string);
276
case DBUS_TYPE_INT16:
277
case DBUS_TYPE_INT32:
278
g_value_init (value, G_TYPE_INT);
279
g_value_set_int (value, pv.v_int);
281
case DBUS_TYPE_UINT16:
282
case DBUS_TYPE_UINT32:
283
g_value_init (value, G_TYPE_UINT);
284
g_value_set_uint (value, (guint)pv.v_int);
286
case DBUS_TYPE_BOOLEAN:
287
g_value_init (value, G_TYPE_BOOLEAN);
288
g_value_set_boolean (value, pv.v_bool);
292
g_hash_table_replace (ai->parameters, g_strdup (name), value);
296
read_gconf_data (AccountInfo *ai, const gchar *unique_name)
298
GSList *entries, *list;
299
gchar dir[200], signature, *avatar_filename = NULL;
303
len = g_snprintf (dir, sizeof (dir), "%s/%s", MC_ACCOUNTS_GCONF_BASE, unique_name);
305
entries = gconf_client_all_entries (client, dir, NULL);
306
for (list = entries; list != NULL; list = list->next)
308
GConfEntry *entry = list->data;
309
const gchar *key = entry->key + len;
310
GConfValue *value = entry->value;
312
if (strncmp (key, "param-", 6) == 0)
316
case GCONF_VALUE_STRING:
317
pv.v_string = gc_dup_string (value);
318
signature = DBUS_TYPE_STRING;
320
case GCONF_VALUE_INT:
321
pv.v_int = gconf_value_get_int (value);
322
signature = DBUS_TYPE_INT32;
324
case GCONF_VALUE_BOOL:
325
pv.v_bool = gconf_value_get_bool (value);
326
signature = DBUS_TYPE_BOOLEAN;
329
g_warning ("Parameter %s has unrecognized type: %u", key, value->type);
332
add_parameter (ai, key + 6, pv, signature);
334
else if (strcmp (key, "alias") == 0)
336
ai->alias = gc_dup_string (value);
338
else if (strcmp (key, "avatar_mime") == 0)
340
ai->avatar_mime = gc_dup_string (value);
342
else if (strcmp (key, "display_name") == 0)
344
ai->display_name = gc_dup_string (value);
346
else if (strcmp (key, "normalized_name") == 0)
348
ai->normalized_name = gc_dup_string (value);
350
else if (strcmp (key, "enabled") == 0)
352
ai->enabled = gconf_value_get_bool (value);
354
else if (strcmp (key, "data_dir") == 0)
356
const gchar *data_dir = gconf_value_get_string (value);
357
avatar_filename = g_build_filename (data_dir, "avatar.bin", NULL);
360
g_slist_foreach (entries, (GFunc)gconf_entry_free, NULL);
361
g_slist_free (entries);
363
/* read the avatar */
364
if (avatar_filename && g_file_test (avatar_filename, G_FILE_TEST_EXISTS))
366
GError *error = NULL;
369
if (g_file_get_contents (avatar_filename, &data, &avatar_len, &error))
371
ai->avatar.data = (gchar *)data;
372
ai->avatar.len = avatar_len;
376
g_warning ("%s: reading file %s failed (%s)", G_STRLOC,
377
avatar_filename, error->message);
378
g_error_free (error);
381
g_free (avatar_filename);
386
parse_profile_param (AccountInfo *ai, GKeyFile *profile, const gchar *key)
388
gchar *param_info, signature, param_str[200];
389
GError *error = NULL;
392
/* read the parameter signature from the manager file */
393
/* key + 8, to skip the "Default-" */
394
g_snprintf (param_str, sizeof (param_str), "param-%s", key + 8);
395
param_info = g_key_file_get_string (ai->manager_cfg, ai->protocol_grp, param_str, NULL);
396
if (!param_info) return FALSE;
397
signature = param_info[0];
402
case DBUS_TYPE_STRING:
403
pv.v_string = g_key_file_get_string (profile, PROFILE_GROUP,
406
case DBUS_TYPE_INT16:
407
case DBUS_TYPE_INT32:
408
case DBUS_TYPE_UINT16:
409
case DBUS_TYPE_UINT32:
410
pv.v_int = g_key_file_get_integer (profile, PROFILE_GROUP,
413
case DBUS_TYPE_BOOLEAN:
414
pv.v_bool = g_key_file_get_boolean (profile, PROFILE_GROUP,
418
g_warning ("%s: skipping parameter %s, unknown type %c", G_STRFUNC, key + 8, signature);
423
g_error_free (error);
427
add_parameter (ai, key + 8, pv, signature);
432
read_manager (AccountInfo *ai)
434
GError *error = NULL;
436
gboolean ret = FALSE;
438
if (!ai->manager) return FALSE;
439
filename = _mc_manager_filename (ai->manager);
441
ai->manager_cfg = g_key_file_new ();
442
if (!ai->manager_cfg)
445
if (!g_key_file_load_from_file (ai->manager_cfg, filename, G_KEY_FILE_NONE, &error))
447
g_warning ("%s: loading %s failed: %s", G_STRFUNC,
448
filename, error->message);
449
g_error_free (error);
450
g_key_file_free (ai->manager_cfg);
454
ai->protocol_grp = g_strdup_printf ("Protocol %s", ai->protocol);
462
_g_value_free (gpointer data)
464
GValue *value = (GValue *) data;
465
g_value_unset (value);
470
set_prop_cb (TpProxy *proxy, const GError *error,
471
gpointer user_data, GObject *weak_object)
473
McAccount *account = MC_ACCOUNT (proxy);
474
AccountInfo *ai = user_data;
477
g_debug ("%s (%s): active calls left: %d",
478
G_STRFUNC, account->name, ai->active_calls);
481
g_warning ("%s failed: %s", G_STRFUNC, error->message);
482
g_object_unref (proxy);
483
account_creation_ended (ai);
486
if (ai->active_calls == 0)
488
g_debug ("No more active calls");
489
account_creation_ended (ai);
494
set_account_prop (McAccount *account, const gchar *iface, const gchar *name,
495
GValue *value, AccountInfo *ai)
497
TpProxyPendingCall *call;
499
call = tp_cli_dbus_properties_call_set (account, -1,
501
set_prop_cb, ai, NULL,
503
g_value_unset (value);
506
g_object_unref (account);
507
account_creation_ended (ai);
515
create_account_cb (TpProxy *proxy, const gchar *obj_path, const GError *error,
516
gpointer user_data, GObject *weak_object)
518
AccountInfo *ai = user_data;
520
GValue value = { 0 };
524
g_debug ("%s called", G_STRFUNC);
527
g_warning ("got error %s", error->message);
528
account_creation_ended (ai);
532
account = mc_account_new (proxy->dbus_daemon, obj_path);
533
g_debug ("Created account %s", account->name);
535
/* Set all account properties */
536
g_value_init (&value, G_TYPE_STRING);
537
g_value_set_static_string (&value, ai->profile);
538
ok = set_account_prop (account,
539
MC_IFACE_ACCOUNT_INTERFACE_COMPAT, "Profile",
543
g_value_init (&value, G_TYPE_STRING);
544
g_value_set_static_string (&value, ai->alias);
545
ok = set_account_prop (account,
546
MC_IFACE_ACCOUNT, "Nickname",
550
g_value_init (&value, G_TYPE_BOOLEAN);
551
g_value_set_boolean (&value, ai->enabled);
552
ok = set_account_prop (account,
553
MC_IFACE_ACCOUNT, "Enabled",
557
if (ai->avatar.data && ai->avatar_mime)
561
type = dbus_g_type_get_struct ("GValueArray",
562
dbus_g_type_get_collection ("GArray",
566
g_value_init (&value, type);
567
g_value_take_boxed (&value, dbus_g_type_specialized_construct (type));
568
va = (GValueArray *) g_value_get_boxed (&value);
569
g_value_set_static_boxed (va->values, &ai->avatar);
570
g_value_set_static_string (va->values + 1, ai->avatar_mime);
571
ok = set_account_prop (account,
572
MC_IFACE_ACCOUNT_INTERFACE_AVATAR, "Avatar",
579
write_account (McAccountManager *am, AccountInfo *ai)
581
TpProxyPendingCall *call;
584
empty = g_hash_table_new (g_str_hash, g_str_equal);
585
call = mc_cli_account_manager_call_create_account (am, -1,
595
g_hash_table_unref (empty);
596
if (!call) return FALSE;
602
convert_account (const gchar *unique_name, McAccountManager *am)
607
GError *error = NULL;
608
gchar *profile_name, *profile_path;
609
gchar **keys, **i_key;
612
key = account_key (unique_name, MC_ACCOUNTS_GCONF_KEY_DELETED);
613
if (gconf_client_get_bool (client, key, NULL)) return TRUE;
615
g_debug ("Converting account %s", unique_name);
617
key = account_key (unique_name, MC_ACCOUNTS_GCONF_KEY_PROFILE);
618
profile_name = gconf_client_get_string (client, key, NULL);
619
if (!profile_name) return FALSE;
621
profile_path = get_profile_path (profile_name);
624
g_warning ("Profile `%s' not found", profile_name);
625
g_free (profile_name);
629
profile = g_key_file_new ();
630
g_key_file_load_from_file (profile, profile_path, 0, &error);
631
g_free (profile_path);
634
g_warning ("Couldn't load profile `%s': %s", profile_name, error->message);
635
g_error_free (error);
636
g_key_file_free (profile);
637
g_free (profile_name);
641
ai = g_new0 (AccountInfo, 1);
642
ai->profile = profile_name;
643
ai->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
644
g_free, _g_value_free);
645
ai->manager = g_key_file_get_string (profile, PROFILE_GROUP, "Manager", NULL);
646
ai->protocol = g_key_file_get_string (profile, PROFILE_GROUP, "Protocol", NULL);
649
keys = g_key_file_get_keys (profile, PROFILE_GROUP, NULL, NULL);
650
for (i_key = keys; *i_key != NULL; i_key++)
652
if (strncmp (*i_key, "Default-", 8) == 0)
654
parse_profile_param (ai, profile, *i_key);
655
g_debug ("Copying param %s from profile", *i_key + 8);
659
g_key_file_free (profile);
661
if (!read_gconf_data (ai, unique_name))
663
account_info_free (ai);
667
num_processing_accounts++;
668
ret = write_account (am, ai);
670
account_info_free (ai);
676
_account_name_from_key (const gchar *key)
678
guint base_len = strlen (MC_ACCOUNTS_GCONF_BASE);
679
const gchar *base, *slash;
681
g_assert (key == strstr (key, MC_ACCOUNTS_GCONF_BASE));
682
g_assert (strlen (key) > base_len + 1);
684
base = key + base_len + 1;
685
slash = strchr (base, '/');
688
return g_strdup (base);
690
return g_strndup (base, slash - base);
694
convert_accounts (McAccountManager *am)
696
GError *error = NULL;
699
dirs = gconf_client_all_dirs (client, MC_ACCOUNTS_GCONF_BASE, &error);
702
g_warning ("gconf_client_all_dirs failed: %s", error->message);
703
g_error_free (error);
707
for (list = dirs; list; list = list->next)
709
gchar *unique_name = _account_name_from_key (list->data);
710
if (!convert_account (unique_name, am))
712
num_processing_accounts--;
713
g_debug ("...FAILED!");
715
g_free (unique_name);
717
g_slist_foreach (dirs, (GFunc)g_free, NULL);
720
g_debug ("processing accounts: %d", num_processing_accounts);
721
if (num_processing_accounts == 0)
722
g_main_loop_quit (main_loop);
727
main (int argc, char **argv)
729
McAccountManager *am;
730
DBusGConnection *dbus_conn;
731
TpDBusDaemon *daemon;
736
dbus_conn = tp_get_bus ();
737
daemon = tp_dbus_daemon_new (dbus_conn);
738
dbus_g_connection_unref (dbus_conn);
740
am = mc_account_manager_new (daemon);
741
g_object_unref (daemon);
743
client = gconf_client_get_default ();
745
g_idle_add ((GSourceFunc)convert_accounts, am);
747
main_loop = g_main_loop_new (NULL, FALSE);
748
g_main_loop_run (main_loop);
751
g_object_unref (client);