2 * Copyright (C) 2008 Collabora Ltd.
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.
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.
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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Authors: Jonny Lamb <jonny.lamb@collabora.co.uk>
28 #include <glade/glade.h>
29 #include <glib/gi18n.h>
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
34 #include <libmissioncontrol/mc-account.h>
35 #include <telepathy-glib/util.h>
37 #include "empathy-import-dialog.h"
39 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
40 #include <libempathy/empathy-debug.h>
41 #include <libempathy/empathy-utils.h>
43 #include <libempathy-gtk/empathy-ui-utils.h>
45 /* Pidgin to MC map */
53 static PidginMcMapItem pidgin_mc_map[] =
55 { "msn", "server", "server" },
56 { "msn", "port", "port" },
58 { "jabber", "connect_server", "server" },
59 { "jabber", "port", "port" },
60 { "jabber", "require_tls", "require-encryption" },
61 { "jabber", "old_ssl", "old-ssl" },
63 { "aim", "server", "server" },
64 { "aim", "port", "port" },
66 { "salut", "first", "first-name" },
67 { "salut", "last", "last-name" },
68 { "salut", "jid", "jid" },
69 { "salut", "email", "email" },
71 { "groupwise", "server", "server" },
72 { "groupwise", "port", "port" },
74 { "icq", "server", "server" },
75 { "icq", "port", "port" },
77 { "irc", "realname", "fullname" },
78 { "irc", "ssl", "use-ssl" },
79 { "irc", "port", "port" },
81 { "yahoo", "server", "server" },
82 { "yahoo", "port", "port" },
83 { "yahoo", "xfer_port", "xfer-port" },
84 { "yahoo", "ignore_invites", "ignore-invites" },
85 { "yahoo", "yahoojp", "yahoojp" },
86 { "yahoo", "xferjp_host", "xferjp-host" },
87 { "yahoo", "serverjp", "serverjp" },
88 { "yahoo", "xfer_host", "xfer-host" },
101 GtkWidget *button_ok;
102 GtkWidget *button_cancel;
103 } EmpathyImportDialog;
105 #define PIDGIN_ACCOUNT_TAG_NAME "name"
106 #define PIDGIN_ACCOUNT_TAG_ACCOUNT "account"
107 #define PIDGIN_ACCOUNT_TAG_PROTOCOL "protocol"
108 #define PIDGIN_ACCOUNT_TAG_PASSWORD "password"
109 #define PIDGIN_ACCOUNT_TAG_SETTINGS "settings"
110 #define PIDGIN_SETTING_PROP_TYPE "type"
111 #define PIDGIN_PROTOCOL_BONJOUR "bonjour"
112 #define PIDGIN_PROTOCOL_NOVELL "novell"
125 static void import_dialog_add_setting (GHashTable *settings,
126 gchar *key, gpointer value, EmpathyImportSettingType type);
127 static gboolean import_dialog_add_account (gchar *protocol_name,
128 GHashTable *settings);
129 static void import_dialog_pidgin_parse_setting (gchar *protocol,
130 xmlNodePtr setting, GHashTable *settings);
131 static void import_dialog_pidgin_import_accounts ();
132 static void import_dialog_button_ok_clicked_cb (GtkButton *button,
133 EmpathyImportDialog *dialog);
134 static void import_dialog_button_cancel_clicked_cb (GtkButton *button,
135 EmpathyImportDialog *dialog);
138 import_dialog_account_data_free (AccountData *data)
140 g_free (data->protocol);
141 g_hash_table_destroy (data->settings);
145 import_dialog_add_account (AccountData *data)
154 DEBUG ("Looking up profile with protocol '%s'", data->protocol);
155 profile = mc_profile_lookup (data->protocol);
160 account = mc_account_create (profile);
162 g_hash_table_iter_init (&iter, data->settings);
163 while (g_hash_table_iter_next (&iter, &key, &value))
165 const gchar *param = key;
166 GValue *gvalue = value;
168 switch (G_VALUE_TYPE (gvalue))
171 DEBUG ("Set param '%s' to '%s' (string)",
172 param, g_value_get_string (gvalue));
173 mc_account_set_param_string (account,
174 param, g_value_get_string (gvalue));
178 DEBUG ("Set param '%s' to %s (boolean)",
179 param, g_value_get_boolean (gvalue) ? "TRUE" : "FALSE");
180 mc_account_set_param_boolean (account,
181 param, g_value_get_boolean (gvalue));
185 DEBUG ("Set param '%s' to '%i' (integer)",
186 param, g_value_get_int (gvalue));
187 mc_account_set_param_int (account,
188 param, g_value_get_int (gvalue));
193 /* Set the display name of the account */
194 mc_account_get_param_string (account, "account", &username);
195 display_name = g_strdup_printf ("%s (%s)",
196 mc_profile_get_display_name (profile), username);
197 mc_account_set_display_name (account, display_name);
200 g_free (display_name);
201 g_object_unref (account);
202 g_object_unref (profile);
208 import_dialog_pidgin_parse_setting (AccountData *data,
211 PidginMcMapItem *item = NULL;
216 GValue *value = NULL;
218 /* We can't do anything if we didn't discovered the protocol yet */
222 /* We can't do anything if the setting don't have a name */
223 tag_name = (gchar *) xmlGetProp (setting, PIDGIN_ACCOUNT_TAG_NAME);
227 /* Search for the map corresponding to setting we are parsing */
228 for (i = 0; i < G_N_ELEMENTS (pidgin_mc_map); i++)
230 if (strcmp (data->protocol, pidgin_mc_map[i].protocol) == 0 &&
231 strcmp (tag_name, pidgin_mc_map[i].pidgin_name) == 0)
233 item = pidgin_mc_map + i;
239 /* If we didn't find the item, there is nothing we can do */
243 type = (gchar *) xmlGetProp (setting, PIDGIN_SETTING_PROP_TYPE);
244 content = (gchar *) xmlNodeGetContent (setting);
246 if (strcmp (type, "bool") == 0)
248 sscanf (content, "%i", &i);
249 value = tp_g_value_slice_new (G_TYPE_BOOLEAN);
250 g_value_set_boolean (value, i != 0);
252 else if (strcmp (type, "int") == 0)
254 sscanf (content, "%i", &i);
255 value = tp_g_value_slice_new (G_TYPE_INT);
256 g_value_set_int (value, i);
258 else if (strcmp (type, "string") == 0)
260 value = tp_g_value_slice_new (G_TYPE_STRING);
261 g_value_set_string (value, content);
265 g_hash_table_insert (data->settings, item->mc_name, value);
272 import_dialog_pidgin_load (void)
274 xmlNodePtr rootnode, node, child, setting;
275 xmlParserCtxtPtr ctxt;
278 GList *accounts = NULL;
280 /* Load pidgin accounts xml */
281 ctxt = xmlNewParserCtxt ();
282 filename = g_build_filename (g_get_home_dir (), ".purple", "accounts.xml",
284 doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
287 rootnode = xmlDocGetRootElement (doc);
288 if (rootnode == NULL)
291 for (node = rootnode->children; node; node = node->next)
295 /* If it is not an account node, skip */
296 if (strcmp ((gchar *) node->name, PIDGIN_ACCOUNT_TAG_ACCOUNT) != 0)
299 /* Create account data struct */
300 data = g_slice_new0 (AccountData);
301 data->settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
302 (GDestroyNotify) tp_g_value_slice_free);
304 /* Parse account's child nodes to fill the account data struct */
305 for (child = node->children; child; child = child->next)
310 if (strcmp ((gchar *) child->name,
311 PIDGIN_ACCOUNT_TAG_PROTOCOL) == 0)
313 const gchar *protocol;
316 protocol = content = (gchar *) xmlNodeGetContent (child);
318 if (g_str_has_prefix (protocol, "prpl-"))
321 if (strcmp (protocol, PIDGIN_PROTOCOL_BONJOUR) == 0)
323 else if (strcmp (protocol, PIDGIN_PROTOCOL_NOVELL) == 0)
324 protocol = "groupwise";
326 data->protocol = g_strdup (protocol);
330 /* Username and IRC server. */
331 else if (strcmp ((gchar *) child->name,
332 PIDGIN_ACCOUNT_TAG_NAME) == 0)
335 GStrv name_resource = NULL;
336 GStrv nick_server = NULL;
337 const gchar *username;
339 name = (gchar *) xmlNodeGetContent (child);
341 /* Split "username/resource" */
342 if (g_strrstr (name, "/") != NULL)
344 name_resource = g_strsplit (name, "/", 2);
345 username = name_resource[0];
350 /* Split "username@server" if it is an IRC account */
351 if (data->protocol && strstr (name, "@") &&
352 strcmp (data->protocol, "irc") == 0)
354 nick_server = g_strsplit (name, "@", 2);
355 username = nick_server[0];
357 /* Add the server setting */
358 value = tp_g_value_slice_new (G_TYPE_STRING);
359 g_value_set_string (value, nick_server[1]);
360 g_hash_table_insert (data->settings, "server", value);
363 /* Add the account setting */
364 value = tp_g_value_slice_new (G_TYPE_STRING);
365 g_value_set_string (value, username);
366 g_hash_table_insert (data->settings, "account", value);
368 g_strfreev (name_resource);
369 g_strfreev (nick_server);
374 else if (strcmp ((gchar *) child->name,
375 PIDGIN_ACCOUNT_TAG_PASSWORD) == 0)
379 password = (gchar *) xmlNodeGetContent (child);
381 /* Add the password setting */
382 value = tp_g_value_slice_new (G_TYPE_STRING);
383 g_value_set_string (value, password);
384 g_hash_table_insert (data->settings, "password", value);
390 else if (strcmp ((gchar *) child->name,
391 PIDGIN_ACCOUNT_TAG_SETTINGS) == 0)
392 for (setting = child->children; setting; setting = setting->next)
393 import_dialog_pidgin_parse_setting (data, setting);
396 /* If we have the needed settings, add the account data to the list,
397 * otherwise free the data */
398 if (data->protocol && g_hash_table_size (data->settings) > 0)
399 accounts = g_list_prepend (accounts, data);
401 import_dialog_account_data_free (data);
406 xmlFreeParserCtxt (ctxt);
412 import_dialog_button_ok_clicked_cb (GtkButton *button,
413 EmpathyImportDialog *dialog)
416 import_dialog_pidgin_import_accounts ();
418 DEBUG ("ok clicked");
420 gtk_widget_hide (GTK_WIDGET (dialog->window));
424 import_dialog_button_cancel_clicked_cb (GtkButton *button,
425 EmpathyImportDialog *dialog)
427 gtk_widget_hide (GTK_WIDGET (dialog->window));
431 import_dialog_add_accounts_to_model (EmpathyImportDialog *dialog)
435 GList *accounts, *account;
437 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
439 accounts = import_dialog_pidgin_load ();
441 for (account = accounts; account; account = account->next)
443 GValue *value, *account_data;
444 AccountData *data = (AccountData *) account->data;
446 account_data = tp_g_value_slice_new (G_TYPE_POINTER);
447 g_value_set_pointer (account_data, data);
449 value = g_hash_table_lookup (data->settings, "account");
451 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
453 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
455 COL_PROTOCOL, data->protocol,
456 COL_NAME, g_value_get_string (value),
457 COL_SOURCE, "Pidgin",
458 COL_ACCOUNT_DATA, account_data,
462 g_list_free (accounts);
466 import_dialog_cell_toggled_cb (GtkCellRendererToggle *cell_renderer,
467 const gchar *path_str,
468 EmpathyImportDialog *dialog)
474 path = gtk_tree_path_new_from_string (path_str);
475 model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
477 gtk_tree_model_get_iter (model, &iter, path);
479 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
480 COL_IMPORT, !gtk_cell_renderer_toggle_get_active (cell_renderer),
483 gtk_tree_path_free (path);
487 import_dialog_set_up_account_list (EmpathyImportDialog *dialog)
491 GtkTreeViewColumn *column;
492 GtkCellRenderer *cell;
494 store = gtk_list_store_new (COL_COUNT, G_TYPE_BOOLEAN, G_TYPE_STRING,
495 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_VALUE);
497 gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview),
498 GTK_TREE_MODEL (store));
500 g_object_unref (store);
502 view = GTK_TREE_VIEW (dialog->treeview);
503 gtk_tree_view_set_headers_visible (view, TRUE);
506 cell = gtk_cell_renderer_toggle_new ();
507 gtk_tree_view_insert_column_with_attributes (view, -1,
509 "active", COL_IMPORT,
512 g_signal_connect (cell, "toggled",
513 G_CALLBACK (import_dialog_cell_toggled_cb), dialog);
515 /* Protocol column */
516 column = gtk_tree_view_column_new ();
517 gtk_tree_view_column_set_title (column, _("Protocol"));
518 gtk_tree_view_column_set_expand (column, TRUE);
519 gtk_tree_view_append_column (view, column);
521 cell = gtk_cell_renderer_text_new ();
525 gtk_tree_view_column_pack_start (column, cell, TRUE);
526 gtk_tree_view_column_add_attribute (column, cell, "text", COL_PROTOCOL);
529 column = gtk_tree_view_column_new ();
530 gtk_tree_view_column_set_title (column, _("Account"));
531 gtk_tree_view_column_set_expand (column, TRUE);
532 gtk_tree_view_append_column (view, column);
534 cell = gtk_cell_renderer_text_new ();
538 gtk_tree_view_column_pack_start (column, cell, TRUE);
539 gtk_tree_view_column_add_attribute (column, cell, "text", COL_NAME);
542 column = gtk_tree_view_column_new ();
543 gtk_tree_view_column_set_title (column, _("Source"));
544 gtk_tree_view_column_set_expand (column, TRUE);
545 gtk_tree_view_append_column (view, column);
547 cell = gtk_cell_renderer_text_new ();
551 gtk_tree_view_column_pack_start (column, cell, TRUE);
552 gtk_tree_view_column_add_attribute (column, cell, "text", COL_SOURCE);
554 import_dialog_add_accounts_to_model (dialog);
558 empathy_import_dialog_show (GtkWindow *parent)
560 static EmpathyImportDialog *dialog = NULL;
566 gtk_window_present (GTK_WINDOW (dialog->window));
570 dialog = g_slice_new0 (EmpathyImportDialog);
572 filename = empathy_file_lookup ("empathy-import-dialog.glade", "src");
573 glade = empathy_glade_get_file (filename,
576 "import_dialog", &dialog->window,
577 "treeview", &dialog->treeview,
580 empathy_glade_connect (glade,
582 "button_ok", "clicked", import_dialog_button_ok_clicked_cb,
583 "button_cancel", "clicked", import_dialog_button_cancel_clicked_cb,
586 import_dialog_set_up_account_list (dialog);
588 g_object_add_weak_pointer (G_OBJECT (dialog->window), (gpointer) &dialog);
591 g_object_unref (glade);
594 gtk_window_set_transient_for (GTK_WINDOW (dialog->window), parent);
596 gtk_widget_show (dialog->window);