]> git.0d.be Git - empathy.git/blob - src/empathy-import-mc4-accounts.c
Add api to ask if we have importer our mc4 accounts
[empathy.git] / src / empathy-import-mc4-accounts.c
1 /*
2  * Copyright (C) 2008 Collabora Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA  02110-1301  USA
18  *
19  * Authors: Arnaud Maillet <arnaud.maillet@collabora.co.uk>
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <glib.h>
25 #include <glib/gi18n.h>
26 #include <gconf/gconf-client.h>
27 #include <telepathy-glib/util.h>
28 #include <dbus/dbus-protocol.h>
29 #include <gnome-keyring.h>
30 #include <libempathy/empathy-account-manager.h>
31 #include <libempathy/empathy-account-settings.h>
32 #include <libempathy/empathy-connection-managers.h>
33
34 #include "empathy-import-mc4-accounts.h"
35
36 #define DEBUG_FLAG EMPATHY_DEBUG_IMPORT_MC4_ACCOUNTS
37 #include <libempathy/empathy-debug.h>
38
39 #define MC_ACCOUNTS_GCONF_BASE "/apps/telepathy/mc/accounts"
40 #define IMPORTED_MC4_ACCOUNTS "/apps/empathy/accounts/imported_mc4_accounts"
41
42 typedef struct
43 {
44   gchar *profile;
45   gchar *protocol;
46 } ProfileProtocolMapItem;
47
48 static ProfileProtocolMapItem profile_protocol_map[] =
49 {
50   { "ekiga", "sip" },
51   { "fwd", "sip" },
52   { "gtalk", "jabber" },
53   { "msn-haze", "msn" },
54   { "salut", "local-xmpp" },
55   { "sipphone", "sip" },
56   { "sofiasip", "sip" },
57 };
58
59 static gchar *
60 _account_name_from_key (const gchar *key)
61 {
62   guint base_len = strlen (MC_ACCOUNTS_GCONF_BASE);
63   const gchar *base, *slash;
64
65   g_assert (g_str_has_prefix (key, MC_ACCOUNTS_GCONF_BASE));
66   g_assert (strlen (key) > base_len + 1);
67
68   base = key + base_len + 1;
69   slash = strchr (base, '/');
70
71   if (slash == NULL)
72     return g_strdup (base);
73   else
74     return g_strndup (base, slash - base);
75 }
76
77 static gchar *
78 _param_name_from_key (const gchar *key)
79 {
80  const gchar *base, *slash;
81  gchar *account_name;
82
83  account_name = _account_name_from_key (key);
84  base = strstr (key, account_name);
85  slash = strchr (base, '/');
86  g_free (account_name);
87
88  return g_strdup (slash+1);
89 }
90
91 static gchar *
92 _create_default_display_name (const gchar *protocol)
93 {
94   if (!tp_strdiff (protocol, "local-xmpp"))
95     return g_strdup (_("People Nearby"));
96
97   return g_strdup_printf ("%s account", protocol);
98 }
99
100 static const gchar *
101 _get_manager_for_protocol (EmpathyConnectionManagers *managers,
102     const gchar *protocol)
103 {
104   GList *cms = empathy_connection_managers_get_cms (managers);
105   GList *l;
106   TpConnectionManager *haze = NULL;
107   TpConnectionManager *cm = NULL;
108
109   for (l = cms; l; l = l->next)
110     {
111       TpConnectionManager *tp_cm = l->data;
112
113       /* Only use haze if no other cm provides this account */
114       if (!tp_strdiff (tp_connection_manager_get_name (tp_cm), "haze"))
115         {
116           haze = tp_cm;
117           continue;
118         }
119
120       if (tp_connection_manager_has_protocol (tp_cm, protocol))
121         {
122           cm = tp_cm;
123           goto out;
124         }
125     }
126
127   if (haze != NULL && tp_connection_manager_has_protocol (haze, protocol))
128     return tp_connection_manager_get_name (haze);
129
130 out:
131   return cm != NULL ? tp_connection_manager_get_name (cm) : NULL;
132 }
133
134 static void
135 _create_account_cb (GObject *source,
136   GAsyncResult *result,
137   gpointer user_data)
138 {
139   EmpathyAccount *account;
140   GError *error = NULL;
141
142   if (!empathy_account_settings_apply_finish (
143       EMPATHY_ACCOUNT_SETTINGS (source), result, &error))
144     {
145       DEBUG ("Failed to create account: %s",
146           error ? error->message : "No error given");
147       g_error_free (error);
148       goto out;
149     }
150
151   DEBUG ("account created\n");
152   account = empathy_account_settings_get_account (
153     EMPATHY_ACCOUNT_SETTINGS (source));
154   empathy_account_set_enabled_async (account,
155       GPOINTER_TO_INT (user_data), NULL, NULL);
156
157 out:
158   g_object_unref (source);
159 }
160
161 static gchar *
162 _get_protocol_from_profile (const gchar *profile)
163 {
164   gint i;
165
166   DEBUG ("profile: %s\n", profile);
167
168   for (i = 0; i < G_N_ELEMENTS (profile_protocol_map); i++)
169     if (!tp_strdiff (profile, profile_protocol_map[i].profile))
170       return g_strdup (profile_protocol_map[i].protocol);
171
172   return g_strdup (profile);
173 }
174
175 static void
176 _set_password_from_keyring (EmpathyAccountSettings *settings,
177     const gchar *account_name, const gchar *key)
178 {
179   GnomeKeyringResult res;
180   gchar *password;
181   GnomeKeyringPasswordSchema keyring_schema = {
182       GNOME_KEYRING_ITEM_GENERIC_SECRET,
183       {
184         { "account", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
185         { "param", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
186         { NULL, 0 }
187       }
188    };
189
190   res = gnome_keyring_find_password_sync (&keyring_schema,
191     &password,
192     "account", account_name,
193     "param", key,
194     NULL);
195
196   if (res == GNOME_KEYRING_RESULT_OK)
197     {
198        empathy_account_settings_set_string (settings, key, password);
199        gnome_keyring_free_password (password);
200     }
201 }
202
203 static void
204 _handle_entry (EmpathyAccountSettings *settings, const gchar *account_name,
205     const gchar *key,
206     GConfEntry *entry)
207 {
208   const gchar *signature;
209
210   signature = empathy_account_settings_get_dbus_signature (settings, key);
211   if (signature == NULL)
212     {
213       DEBUG ("Parameter %s is unknown", signature);
214       return;
215     }
216
217   switch ((int)*signature)
218     {
219       case DBUS_TYPE_INT16:
220       case DBUS_TYPE_INT32:
221         {
222           gint v = gconf_value_get_int (gconf_entry_get_value (entry));
223           empathy_account_settings_set_int32 (settings, key, v);
224           break;
225         }
226       case DBUS_TYPE_UINT16:
227       case DBUS_TYPE_UINT32:
228         {
229           gint v = gconf_value_get_int (gconf_entry_get_value (entry));
230           empathy_account_settings_set_uint32 (settings, key, v);
231           break;
232         }
233       case DBUS_TYPE_STRING:
234         {
235           const gchar *v = gconf_value_get_string (
236               gconf_entry_get_value (entry));
237
238           /* MC 4 would put password in the keyring and leave the password in
239            * gconf keyring */
240
241           if (!tp_strdiff (key, "password") && !tp_strdiff (v, "keyring"))
242             _set_password_from_keyring (settings, account_name, key);
243           else
244               empathy_account_settings_set_string (settings, key, v);
245           break;
246         }
247       case DBUS_TYPE_BOOLEAN:
248         {
249           gboolean v = gconf_value_get_bool (
250               gconf_entry_get_value (entry));
251
252           empathy_account_settings_set_boolean (settings, key, v);
253           break;
254         }
255      default:
256        DEBUG ("Unsupported type in signature: %s", signature);
257     }
258 }
259
260 static void
261 _recurse_account (GSList *entries, EmpathyAccountSettings *settings,
262   const gchar *account_name)
263 {
264   GSList *tmp;
265
266   for (tmp = entries; tmp != NULL; tmp = tmp->next)
267     {
268
269       GConfEntry *entry;
270       gchar *param;
271
272       entry = (GConfEntry*) tmp->data;
273       param = _param_name_from_key (gconf_entry_get_key (entry));
274
275       if (g_str_has_prefix (param, "param-"))
276         {
277           _handle_entry (settings, account_name, param + strlen ("param-"),
278             entry);
279         }
280
281       g_free (param);
282       gconf_entry_unref (entry);
283     }
284 }
285
286 static gboolean
287 import_one_account (const char *path,
288   EmpathyConnectionManagers *managers,
289   GConfClient *client)
290 {
291   gchar *account_name = _account_name_from_key (path);
292   EmpathyAccountSettings *settings;
293   GError *error = NULL;
294   GSList *entries = NULL;
295   gchar *profile = NULL;
296   gchar *protocol = NULL;
297   const gchar *manager;
298   gchar *display_name;
299   gchar *key;
300   gboolean enabled = FALSE;
301   gboolean ret = FALSE;
302
303   DEBUG ("Starting import of %s (%s)", path, account_name);
304
305   key = g_strdup_printf ("%s/profile", path);
306   profile = gconf_client_get_string (client, key, NULL);
307   g_free (key);
308
309   if (profile == NULL)
310     {
311       DEBUG ("Account is missing a profile entry\n");
312       goto failed;
313     }
314
315   protocol = _get_protocol_from_profile (profile);
316   manager = _get_manager_for_protocol (managers, protocol);
317   if (manager == NULL)
318     {
319       DEBUG ("No manager available for this protocol %s", protocol);
320       goto failed;
321     }
322
323   key = g_strdup_printf ("%s/display_name", path);
324   display_name = gconf_client_get_string (client, key, NULL);
325   g_free (key);
326
327   if (display_name == NULL)
328     display_name = _create_default_display_name (protocol);
329
330   settings = empathy_account_settings_new (manager, protocol, display_name);
331   g_free (display_name);
332
333   /* Bit of a hack, as we know EmpathyConnectionManagers is ready the
334    * EmpathyAccountSettings should be ready right away as well */
335   g_assert (empathy_account_settings_is_ready (settings));
336
337   entries = gconf_client_all_entries (client, path, &error);
338
339   if (entries == NULL)
340     {
341
342       DEBUG ("Failed to get all entries: %s\n", error->message);
343       g_error_free (error);
344       goto failed;
345     }
346
347   _recurse_account (entries, settings, account_name);
348
349   key = g_strdup_printf ("%s/enabled", path);
350   enabled = gconf_client_get_bool (client, key, NULL);
351   g_free (key);
352   empathy_account_settings_apply_async (settings,
353           _create_account_cb, GINT_TO_POINTER (enabled));
354   ret = TRUE;
355
356 out:
357   g_free (protocol);
358   g_free (profile);
359   g_slist_free (entries);
360   g_free (account_name);
361
362   return ret;
363
364 failed:
365   DEBUG ("Failed to import %s", path);
366   if (settings != NULL)
367     g_object_unref (settings);
368   goto out;
369 }
370
371 gboolean
372 empathy_import_mc4_has_imported (void)
373 {
374   GConfClient *client;
375   gboolean ret;
376
377   client = gconf_client_get_default ();
378
379   ret = gconf_client_get_bool (client, IMPORTED_MC4_ACCOUNTS, NULL);
380   g_object_unref (client);
381
382   return ret;
383 }
384
385 gboolean
386 empathy_import_mc4_accounts (EmpathyConnectionManagers *managers)
387 {
388   GConfClient *client;
389   GError *error = NULL;
390   GSList *dir, *dirs = NULL;
391   gboolean imported_mc4_accounts;
392   gboolean imported = FALSE;
393
394   g_return_val_if_fail (empathy_connection_managers_is_ready (managers),
395     FALSE);
396
397   client = gconf_client_get_default ();
398
399   imported_mc4_accounts = gconf_client_get_bool (client,
400       IMPORTED_MC4_ACCOUNTS, &error);
401
402   if (error != NULL)
403     {
404       DEBUG ("Failed to get import_mc4_accounts key: %s\n", error->message);
405       g_clear_error (&error);
406       g_object_unref (client);
407       goto out;
408     }
409
410   if (imported_mc4_accounts)
411     {
412       DEBUG ("Mc4 accounts already imported");
413       goto out;
414     }
415
416   DEBUG ("MC 4 accounts are going to be imported\n");
417
418   dirs = gconf_client_all_dirs (client, MC_ACCOUNTS_GCONF_BASE, &error);
419
420   if (error != NULL)
421     {
422       DEBUG ("Failed to get mc_accounts_gconf_base dirs: %s\n",
423           error->message);
424       g_clear_error (&error);
425       g_object_unref (client);
426       goto out;
427     }
428
429   for (dir = dirs; NULL != dir; dir = dir->next)
430     {
431       if (import_one_account ((gchar *)dir->data, managers, client))
432         imported = TRUE;
433       g_free (dir->data);
434     }
435
436   gconf_client_set_bool (client,
437       IMPORTED_MC4_ACCOUNTS, TRUE, &error);
438
439   if (error != NULL)
440     {
441       DEBUG ("Failed to set import_mc4_accounts key: %s\n", error->message);
442       g_clear_error (&error);
443     }
444
445 out:
446   g_slist_free (dirs);
447   g_object_unref (client);
448   return imported;
449 }