]> git.0d.be Git - empathy.git/blob - src/empathy-import-pidgin.c
UOA: Do not segfault when "Done" or "Cancel" button clicked but widget is not ready yet
[empathy.git] / src / empathy-import-pidgin.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: Jonny Lamb <jonny.lamb@collabora.co.uk>
20  * */
21
22 #include "config.h"
23
24 #include <glib/gstdio.h>
25 #include <dbus/dbus-protocol.h>
26
27 #include "empathy-import-utils.h"
28 #include "empathy-import-pidgin.h"
29
30 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
31 #include <libempathy/empathy-debug.h>
32 #include <libempathy/empathy-utils.h>
33
34 /* Pidgin to CM map */
35 typedef struct
36 {
37   const gchar *protocol;
38   const gchar *pidgin_name;
39   const gchar *cm_name;
40 } PidginCmMapItem;
41
42 static PidginCmMapItem pidgin_cm_map[] =
43 {
44   { "msn", "server", "server" },
45   { "msn", "port", "port" },
46
47   { "jabber", "connect_server", "server" },
48   { "jabber", "port", "port" },
49   { "jabber", "require_tls", "require-encryption" },
50   { "jabber", "old_ssl", "old-ssl" },
51
52   { "aim", "server", "server" },
53   { "aim", "port", "port" },
54
55   { "salut", "first", "first-name" },
56   { "salut", "last", "last-name" },
57   { "salut", "jid", "jid" },
58   { "salut", "email", "email" },
59
60   { "groupwise", "server", "server" },
61   { "groupwise", "port", "port" },
62
63   { "icq", "server", "server" },
64   { "icq", "port", "port" },
65
66   { "irc", "realname", "fullname" },
67   { "irc", "ssl", "use-ssl" },
68   { "irc", "port", "port" },
69
70   { "yahoo", "server", "server" },
71   { "yahoo", "port", "port" },
72   { "yahoo", "xfer_port", "xfer-port" },
73   { "yahoo", "ignore_invites", "ignore-invites" },
74   { "yahoo", "yahoojp", "yahoojp" },
75   { "yahoo", "xferjp_host", "xferjp-host" },
76   { "yahoo", "serverjp", "serverjp" },
77   { "yahoo", "xfer_host", "xfer-host" },
78 };
79
80 #define PIDGIN_ACCOUNT_TAG_NAME "name"
81 #define PIDGIN_ACCOUNT_TAG_ACCOUNT "account"
82 #define PIDGIN_ACCOUNT_TAG_PROTOCOL "protocol"
83 #define PIDGIN_ACCOUNT_TAG_PASSWORD "password"
84 #define PIDGIN_ACCOUNT_TAG_SETTINGS "settings"
85 #define PIDGIN_SETTING_PROP_UI "ui"
86 #define PIDGIN_SETTING_PROP_NAME "name"
87 #define PIDGIN_SETTING_PROP_TYPE "type"
88 #define PIDGIN_PROTOCOL_BONJOUR "bonjour"
89 #define PIDGIN_PROTOCOL_NOVELL "novell"
90
91 static void
92 import_dialog_pidgin_parse_setting (EmpathyImportAccountData *data,
93                                     xmlNodePtr setting)
94 {
95   PidginCmMapItem *item = NULL;
96   gchar *tag_name;
97   gchar *type = NULL;
98   gchar *content;
99   guint i;
100   GValue *value = NULL;
101
102   /* We can't do anything if the setting don't have a name */
103   tag_name = (gchar *) xmlGetProp (setting,
104       (xmlChar *) PIDGIN_SETTING_PROP_NAME);
105   if (!tag_name)
106     return;
107
108   /* Search for the map corresponding to setting we are parsing */
109   for (i = 0; i < G_N_ELEMENTS (pidgin_cm_map); i++)
110     {
111       if (!tp_strdiff (data->protocol, pidgin_cm_map[i].protocol) &&
112           !tp_strdiff (tag_name, pidgin_cm_map[i].pidgin_name))
113         {
114           item = pidgin_cm_map + i;
115           break;
116         }
117     }
118   g_free (tag_name);
119
120   /* If we didn't find the item, there is nothing we can do */
121   if (!item)
122     return;
123
124   type = (gchar *) xmlGetProp (setting, (xmlChar *) PIDGIN_SETTING_PROP_TYPE);
125   content = (gchar *) xmlNodeGetContent (setting);
126
127   if (!tp_strdiff (type, "bool"))
128     {
129       i = (gint) g_ascii_strtod (content, NULL);
130       value = tp_g_value_slice_new (G_TYPE_BOOLEAN);
131       g_value_set_boolean (value, i != 0);
132     }
133   else if (!tp_strdiff (type, "int"))
134     {
135       TpConnectionManager *cm = NULL;
136       TpProtocol *proto;
137       const TpConnectionManagerParam *param;
138       const gchar *signature;
139       int signature_i;
140
141       if (!empathy_import_protocol_is_supported (data->protocol, &cm))
142         return;
143
144       proto = tp_connection_manager_get_protocol_object (cm, data->protocol);
145       param = tp_protocol_get_param (proto, item->cm_name);
146       signature = tp_connection_manager_param_get_dbus_signature (param);
147       signature_i = (int) (*signature);
148
149       i = (gint) g_ascii_strtod (content, NULL);
150
151       if (signature_i == DBUS_TYPE_INT16 ||
152           signature_i == DBUS_TYPE_INT32)
153         {
154           value = tp_g_value_slice_new (G_TYPE_INT);
155           g_value_set_int (value, i);
156         }
157       else if (signature_i == DBUS_TYPE_UINT16 ||
158           signature_i == DBUS_TYPE_UINT32)
159         {
160           value = tp_g_value_slice_new (G_TYPE_UINT);
161           g_value_set_uint (value, (guint) i);
162         }
163     }
164   else if (!tp_strdiff (type, "string"))
165     {
166       value = tp_g_value_slice_new (G_TYPE_STRING);
167       g_value_set_string (value, content);
168     }
169
170   if (value)
171     g_hash_table_insert (data->settings, (gpointer) item->cm_name, value);
172
173   g_free (type);
174   g_free (content);
175 }
176
177 static void
178 import_dialog_pidgin_handle_settings (EmpathyImportAccountData *data,
179                                       xmlNodePtr settings)
180 {
181   xmlNodePtr setting;
182   gchar *tag_ui, *name, *type, *content;
183
184   tag_ui = (gchar *) xmlGetProp (settings, (xmlChar *) PIDGIN_SETTING_PROP_UI);
185
186   /* UI settings - fetch the Enabled parameter.
187    * The expected value of the ui property is 'gtk-gaim', which looks obsolete,
188    * but still valid for 2.7.3.
189    */
190   if (tag_ui && !tp_strdiff (tag_ui, "gtk-gaim"))
191     {
192       for (setting = settings->children; setting; setting = setting->next)
193         {
194           name = (gchar *) xmlGetProp (setting,
195               (xmlChar *) PIDGIN_SETTING_PROP_NAME);
196           type = (gchar *) xmlGetProp (setting,
197               (xmlChar *) PIDGIN_SETTING_PROP_TYPE);
198           /* The Enabled parameter is supposed to be boolean.
199            * Pidgin name of the setting is 'auto-login'.
200            */
201           if (!tp_strdiff (name, "auto-login") && !tp_strdiff (type, "bool"))
202             {
203               content = (gchar *) xmlNodeGetContent (setting);
204               data->enabled = (0 != (gint) g_ascii_strtod (content, NULL));
205               g_free (content);
206             }
207           g_free (type);
208           g_free (name);
209         }
210     }
211   /* General settings. */
212   else
213     {
214       for (setting = settings->children; setting; setting = setting->next)
215         import_dialog_pidgin_parse_setting (data, setting);
216     }
217
218   g_free (tag_ui);
219 }
220
221 GList *
222 empathy_import_pidgin_load (void)
223 {
224   xmlNodePtr rootnode, node, child;
225   xmlParserCtxtPtr ctxt;
226   xmlDocPtr doc;
227   gchar *filename;
228   GList *accounts = NULL;
229
230   /* Load pidgin accounts xml */
231   ctxt = xmlNewParserCtxt ();
232   filename = g_build_filename (g_get_home_dir (), ".purple", "accounts.xml",
233       NULL);
234
235   if (g_access (filename, R_OK) != 0)
236     goto FILENAME;
237
238   doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
239
240   rootnode = xmlDocGetRootElement (doc);
241   if (rootnode == NULL)
242     goto OUT;
243
244   for (node = rootnode->children; node; node = node->next)
245     {
246       EmpathyImportAccountData *data;
247
248       /* If it is not an account node, skip. */
249       if (tp_strdiff ((gchar *) node->name, PIDGIN_ACCOUNT_TAG_ACCOUNT))
250         continue;
251
252       /* Create account data struct */
253       data = empathy_import_account_data_new ("Pidgin");
254
255       /* Parse account's child nodes to fill the account data struct */
256       for (child = node->children; child; child = child->next)
257         {
258           GValue *value;
259
260           /* Protocol */
261           if (!tp_strdiff ((gchar *) child->name,
262               PIDGIN_ACCOUNT_TAG_PROTOCOL))
263             {
264               xmlChar *content;
265               const gchar *protocol;
266
267               content = xmlNodeGetContent (child);
268
269               protocol = (const gchar *) content;
270
271               if (g_str_has_prefix (protocol, "prpl-"))
272                 protocol += 5;
273
274               if (!tp_strdiff (protocol, PIDGIN_PROTOCOL_BONJOUR))
275                 data->protocol = g_strdup ("salut");
276               else if (!tp_strdiff (protocol, PIDGIN_PROTOCOL_NOVELL))
277                 data->protocol = g_strdup ("groupwise");
278               else
279                 data->protocol = g_strdup (protocol);
280
281               xmlFree (content);
282
283               if (data->protocol == NULL)
284                 break;
285             }
286
287           /* Username and IRC server. */
288           else if (!tp_strdiff ((gchar *) child->name,
289               PIDGIN_ACCOUNT_TAG_NAME))
290             {
291               gchar *name;
292               GStrv name_resource = NULL;
293               GStrv nick_server = NULL;
294               const gchar *username;
295
296               name = (gchar *) xmlNodeGetContent (child);
297
298               /* Split "username/resource" */
299               if (g_strrstr (name, "/") != NULL)
300                 {
301                   name_resource = g_strsplit (name, "/", 2);
302                   username = name_resource[0];
303                 }
304               else
305                 username = name;
306
307              /* Split "username@server" if it is an IRC account */
308              if (strstr (name, "@") && !tp_strdiff (data->protocol, "irc"))
309               {
310                 nick_server = g_strsplit (name, "@", 2);
311                 username = nick_server[0];
312
313                 /* Add the server setting */
314                 value = tp_g_value_slice_new (G_TYPE_STRING);
315                 g_value_set_string (value, nick_server[1]);
316                 g_hash_table_insert (data->settings, (gpointer) "server", value);
317               }
318
319               /* Add the account setting */
320               value = tp_g_value_slice_new (G_TYPE_STRING);
321               g_value_set_string (value, username);
322               g_hash_table_insert (data->settings, (gpointer) "account", value);
323
324               g_strfreev (name_resource);
325               g_strfreev (nick_server);
326               g_free (name);
327             }
328
329           /* Password */
330           else if (!tp_strdiff ((gchar *) child->name,
331               PIDGIN_ACCOUNT_TAG_PASSWORD))
332             {
333               gchar *password;
334
335               password = (gchar *) xmlNodeGetContent (child);
336
337               /* Add the password setting */
338               value = tp_g_value_slice_new (G_TYPE_STRING);
339               g_value_set_string (value, password);
340               g_hash_table_insert (data->settings, (gpointer) "password", value);
341
342               g_free (password);
343             }
344
345           /* Other settings */
346           else if (!tp_strdiff ((gchar *) child->name,
347               PIDGIN_ACCOUNT_TAG_SETTINGS))
348             import_dialog_pidgin_handle_settings (data, child);
349         }
350
351       /* If we have the needed settings, add the account data to the list,
352        * otherwise free the data */
353       if (data->protocol != NULL && g_hash_table_size (data->settings) > 0)
354         {
355           /* Special-case XMPP:
356            * http://bugzilla.gnome.org/show_bug.cgi?id=579992 */
357           if (!tp_strdiff (data->protocol, "jabber"))
358             {
359               if (EMP_STR_EMPTY (tp_asv_get_string (data->settings, "server")))
360                 {
361                   g_hash_table_remove (data->settings, "port");
362                   g_hash_table_remove (data->settings, "server");
363                 }
364             }
365
366           /* If there is no password then MC treats the account as not
367            * ready and doesn't display it. */
368           if (!g_hash_table_lookup (data->settings, "password"))
369             {
370               GValue *value;
371               value = tp_g_value_slice_new (G_TYPE_STRING);
372               g_value_set_string (value, "");
373               g_hash_table_insert (data->settings, (gpointer) "password", value);
374             }
375
376           accounts = g_list_prepend (accounts, data);
377         }
378       else
379         empathy_import_account_data_free (data);
380     }
381
382 OUT:
383   xmlFreeDoc (doc);
384   xmlFreeParserCtxt (ctxt);
385
386 FILENAME:
387   g_free (filename);
388
389   return accounts;
390 }
391
392 gboolean
393 empathy_import_pidgin_accounts_to_import (void)
394 {
395   gchar *filename;
396   gboolean out;
397   GFile *file;
398
399   filename = g_build_filename (g_get_home_dir (), ".purple", "accounts.xml",
400       NULL);
401   file = g_file_new_for_path (filename);
402   out = g_file_query_exists (file, NULL);
403
404   g_free (filename);
405   g_object_unref (file);
406
407   return out;
408 }