aa57fdc11c7c24db0879cb77debee8d9fd89d7d4
[empathy.git] / libempathy-gtk / empathy-account-widget-irc.c
1 /*
2  * Copyright (C) 2007-2008 Guillaume Desmottes
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors: Guillaume Desmottes <gdesmott@gnome.org>
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26
27 #include <glib/gi18n-lib.h>
28 #include <gtk/gtk.h>
29
30 #include <libmissioncontrol/mc-account.h>
31 #include <libmissioncontrol/mc-protocol.h>
32
33 #include <libempathy/empathy-utils.h>
34 #include <libempathy/empathy-irc-network-manager.h>
35
36 #include "empathy-irc-network-dialog.h"
37 #include "empathy-account-widget.h"
38 #include "empathy-account-widget-irc.h"
39 #include "empathy-ui-utils.h"
40
41 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT | EMPATHY_DEBUG_IRC
42 #include <libempathy/empathy-debug.h>
43
44 #define IRC_NETWORKS_FILENAME "irc-networks.xml"
45
46 typedef struct {
47   McAccount *account;
48   EmpathyIrcNetworkManager *network_manager;
49
50   GtkWidget *vbox_settings;
51
52   GtkWidget *combobox_network;
53   GtkWidget *button_add_network;
54   GtkWidget *button_network;
55   GtkWidget *button_remove_network;
56 } EmpathyAccountWidgetIrc;
57
58 enum {
59   COL_NETWORK_OBJ,
60   COL_NETWORK_NAME,
61 };
62
63 static void
64 account_widget_irc_destroy_cb (GtkWidget *widget,
65                                EmpathyAccountWidgetIrc *settings)
66 {
67   g_object_unref (settings->network_manager);
68   g_object_unref (settings->account);
69   g_slice_free (EmpathyAccountWidgetIrc, settings);
70 }
71
72 static void
73 unset_server_params (EmpathyAccountWidgetIrc *settings)
74 {
75   DEBUG ("Unset server, port and use-ssl");
76   mc_account_unset_param (settings->account, "server");
77   mc_account_unset_param (settings->account, "port");
78   mc_account_unset_param (settings->account, "use-ssl");
79 }
80
81 static void
82 update_server_params (EmpathyAccountWidgetIrc *settings)
83 {
84   GtkTreeIter iter;
85   GtkTreeModel *model;
86   EmpathyIrcNetwork *network;
87   GSList *servers;
88   gchar *charset;
89
90   if (!gtk_combo_box_get_active_iter (
91         GTK_COMBO_BOX (settings->combobox_network), &iter))
92     {
93       unset_server_params (settings);
94       return;
95     }
96
97   model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
98   gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1);
99
100   g_assert (network != NULL);
101
102   g_object_get (network, "charset", &charset, NULL);
103   DEBUG ("Setting charset to %s", charset);
104   mc_account_set_param_string (settings->account, "charset", charset);
105   g_free (charset);
106
107   servers = empathy_irc_network_get_servers (network);
108   if (g_slist_length (servers) > 0)
109     {
110       /* set the first server as CM server */
111       EmpathyIrcServer *server = servers->data;
112       gchar *address;
113       guint port;
114       gboolean ssl;
115
116       g_object_get (server,
117           "address", &address,
118           "port", &port,
119           "ssl", &ssl,
120           NULL);
121
122       DEBUG ("Setting server to %s", address);
123       mc_account_set_param_string (settings->account, "server", address);
124       DEBUG ("Setting port to %u", port);
125       mc_account_set_param_int (settings->account, "port", port);
126       DEBUG ("Setting use-ssl to %s", ssl ? "TRUE": "FALSE" );
127       mc_account_set_param_boolean (settings->account, "use-ssl", ssl);
128
129       g_free (address);
130     }
131   else
132     {
133       /* No server. Unset values */
134       unset_server_params (settings);
135     }
136
137   g_slist_foreach (servers, (GFunc) g_object_unref, NULL);
138   g_slist_free (servers);
139   g_object_unref (network);
140 }
141
142 static void
143 irc_network_dialog_destroy_cb (GtkWidget *widget,
144                                EmpathyAccountWidgetIrc *settings)
145 {
146   GtkTreeIter iter;
147   GtkTreeModel *model;
148   EmpathyIrcNetwork *network;
149   gchar *name;
150
151   /* name could be changed */
152   gtk_combo_box_get_active_iter (GTK_COMBO_BOX (settings->combobox_network),
153       &iter);
154   model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
155   gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1);
156
157   g_object_get (network, "name", &name, NULL);
158   gtk_list_store_set (GTK_LIST_STORE (model), &iter,
159       COL_NETWORK_NAME, name, -1);
160
161   update_server_params (settings);
162
163   g_object_unref (network);
164   g_free (name);
165 }
166
167 static void
168 display_irc_network_dialog (EmpathyAccountWidgetIrc *settings,
169                             EmpathyIrcNetwork *network)
170 {
171   GtkWindow *window;
172   GtkWidget *dialog;
173
174   window = empathy_get_toplevel_window (settings->vbox_settings);
175   dialog = empathy_irc_network_dialog_show (network, GTK_WIDGET (window));
176   g_signal_connect (dialog, "destroy",
177       G_CALLBACK (irc_network_dialog_destroy_cb), settings);
178 }
179
180 static void
181 account_widget_irc_button_edit_network_clicked_cb (
182     GtkWidget *button,
183     EmpathyAccountWidgetIrc *settings)
184 {
185   GtkTreeIter iter;
186   GtkTreeModel *model;
187   EmpathyIrcNetwork *network;
188
189   gtk_combo_box_get_active_iter (GTK_COMBO_BOX (settings->combobox_network),
190       &iter);
191   model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
192   gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1);
193
194   g_assert (network != NULL);
195
196   display_irc_network_dialog (settings, network);
197
198   g_object_unref (network);
199 }
200
201 static void
202 account_widget_irc_button_remove_clicked_cb (GtkWidget *button,
203                                              EmpathyAccountWidgetIrc *settings)
204 {
205   EmpathyIrcNetwork *network;
206   GtkTreeIter iter;
207   GtkTreeModel *model;
208   gchar *name;
209
210   gtk_combo_box_get_active_iter (GTK_COMBO_BOX (settings->combobox_network),
211       &iter);
212   model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
213   gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1);
214
215   g_assert (network != NULL);
216
217   g_object_get (network, "name", &name, NULL);
218   DEBUG ("Remove network %s", name);
219
220   gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
221   empathy_irc_network_manager_remove (settings->network_manager, network);
222
223   /* Select the first network */
224   if (gtk_tree_model_get_iter_first (model, &iter))
225     {
226       gtk_combo_box_set_active_iter (
227           GTK_COMBO_BOX (settings->combobox_network), &iter);
228     }
229
230   g_free (name);
231   g_object_unref (network);
232 }
233
234 static void
235 account_widget_irc_button_add_network_clicked_cb (GtkWidget *button,
236                                                   EmpathyAccountWidgetIrc *settings)
237 {
238   EmpathyIrcNetwork *network;
239   GtkTreeModel *model;
240   GtkListStore *store;
241   gchar *name;
242   GtkTreeIter iter;
243
244   network = empathy_irc_network_new (_("New Network"));
245   empathy_irc_network_manager_add (settings->network_manager, network);
246
247   model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
248   store = GTK_LIST_STORE (model);
249
250   g_object_get (network, "name", &name, NULL);
251
252   gtk_list_store_insert_with_values (store, &iter, -1,
253       COL_NETWORK_OBJ, network,
254       COL_NETWORK_NAME, name,
255       -1);
256
257   gtk_combo_box_set_active_iter (GTK_COMBO_BOX (settings->combobox_network),
258       &iter);
259
260   display_irc_network_dialog (settings, network);
261
262   g_free (name);
263   g_object_unref (network);
264 }
265
266 static void
267 account_widget_irc_combobox_network_changed_cb (GtkWidget *combobox,
268                                                 EmpathyAccountWidgetIrc *settings)
269 {
270   update_server_params (settings);
271 }
272
273 static void
274 fill_networks_model (EmpathyAccountWidgetIrc *settings,
275                      EmpathyIrcNetwork *network_to_select)
276 {
277   GSList *networks, *l;
278   GtkTreeModel *model;
279   GtkListStore *store;
280
281   networks = empathy_irc_network_manager_get_networks (
282       settings->network_manager);
283
284   model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network));
285   store = GTK_LIST_STORE (model);
286
287   for (l = networks; l != NULL; l = g_slist_next (l))
288     {
289       gchar *name;
290       EmpathyIrcNetwork *network = l->data;
291       GtkTreeIter iter;
292
293       g_object_get (network, "name", &name, NULL);
294
295       gtk_list_store_insert_with_values (store, &iter, -1,
296           COL_NETWORK_OBJ, network,
297           COL_NETWORK_NAME, name,
298           -1);
299
300        if (network == network_to_select)
301          {
302            gtk_combo_box_set_active_iter (
303                GTK_COMBO_BOX (settings->combobox_network), &iter);
304          }
305
306       g_free (name);
307       g_object_unref (network);
308     }
309
310   if (network_to_select == NULL)
311     {
312       /* Select the first network */
313       GtkTreeIter iter;
314
315       if (gtk_tree_model_get_iter_first (model, &iter))
316         {
317           gtk_combo_box_set_active_iter (
318               GTK_COMBO_BOX (settings->combobox_network), &iter);
319
320           update_server_params (settings);
321         }
322     }
323
324   g_slist_free (networks);
325 }
326
327 static void
328 account_widget_irc_setup (EmpathyAccountWidgetIrc *settings)
329 {
330   gchar *nick = NULL;
331   gchar *fullname = NULL;
332   gchar *server = NULL;
333   gint port = 6667;
334   gchar *charset;
335   gboolean ssl = FALSE;
336   EmpathyIrcNetwork *network = NULL;
337
338   mc_account_get_param_string (settings->account, "account", &nick);
339   mc_account_get_param_string (settings->account, "fullname", &fullname);
340   mc_account_get_param_string (settings->account, "server", &server);
341   mc_account_get_param_string (settings->account, "charset", &charset);
342   mc_account_get_param_int (settings->account, "port", &port);
343   mc_account_get_param_boolean (settings->account, "use-ssl", &ssl);
344
345   if (!nick)
346     {
347       nick = g_strdup (g_get_user_name ());
348       mc_account_set_param_string (settings->account, "account", nick);
349     }
350
351   if (!fullname)
352     {
353       fullname = g_strdup (g_get_real_name ());
354       if (!fullname)
355         {
356           fullname = g_strdup (nick);
357         }
358       mc_account_set_param_string (settings->account, "fullname", fullname);
359     }
360
361   if (server != NULL)
362     {
363       GtkListStore *store;
364
365       network = empathy_irc_network_manager_find_network_by_address (
366           settings->network_manager, server);
367
368
369       store = GTK_LIST_STORE (gtk_combo_box_get_model (
370             GTK_COMBO_BOX (settings->combobox_network)));
371
372       if (network != NULL)
373         {
374           gchar *name;
375
376           g_object_set (network, "charset", charset, NULL);
377
378           g_object_get (network, "name", &name, NULL);
379           DEBUG ("Account use network %s", name);
380
381           g_free (name);
382         }
383       else
384         {
385           /* We don't have this network. Let's create it */
386           EmpathyIrcServer *srv;
387           GtkTreeIter iter;
388
389           DEBUG ("Create a network %s", server);
390           network = empathy_irc_network_new (server);
391           srv = empathy_irc_server_new (server, port, ssl);
392
393           empathy_irc_network_append_server (network, srv);
394           empathy_irc_network_manager_add (settings->network_manager, network);
395
396           gtk_list_store_insert_with_values (store, &iter, -1,
397               COL_NETWORK_OBJ, network,
398               COL_NETWORK_NAME, server,
399               -1);
400
401           gtk_combo_box_set_active_iter (
402               GTK_COMBO_BOX (settings->combobox_network), &iter);
403
404           g_object_unref (srv);
405           g_object_unref (network);
406         }
407     }
408
409
410   fill_networks_model (settings, network);
411
412   g_free (nick);
413   g_free (fullname);
414   g_free (server);
415   g_free (charset);
416 }
417
418 /**
419  * empathy_account_widget_irc_new:
420  * @account: the #McAccount to configure
421  *
422  * Creates a new IRC account widget to configure a given #McAccount
423  *
424  * Returns: The toplevel container of the configuration widget
425  */
426 GtkWidget *
427 empathy_account_widget_irc_new (McAccount *account)
428 {
429   EmpathyAccountWidgetIrc *settings;
430   gchar *dir, *user_file_with_path, *global_file_with_path;
431   GtkBuilder *gui;
432   GtkListStore *store;
433   GtkCellRenderer *renderer;
434   gchar *filename;
435
436   settings = g_slice_new0 (EmpathyAccountWidgetIrc);
437   settings->account = g_object_ref (account);
438
439   dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL);
440   g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR);
441   user_file_with_path = g_build_filename (dir, IRC_NETWORKS_FILENAME, NULL);
442   g_free (dir);
443
444   global_file_with_path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"),
445       "libempathy-gtk", IRC_NETWORKS_FILENAME, NULL);
446   if (!g_file_test (global_file_with_path, G_FILE_TEST_EXISTS))
447     {
448       g_free (global_file_with_path);
449       global_file_with_path = g_build_filename (DATADIR, "empathy",
450           IRC_NETWORKS_FILENAME, NULL);
451     }
452
453   settings->network_manager = empathy_irc_network_manager_new (
454       global_file_with_path,
455       user_file_with_path);
456
457   g_free (global_file_with_path);
458   g_free (user_file_with_path);
459
460   filename = empathy_file_lookup ("empathy-account-widget-irc.ui",
461       "libempathy-gtk");
462   gui = empathy_builder_get_file (filename,
463       "vbox_irc_settings", &settings->vbox_settings,
464       "combobox_network", &settings->combobox_network,
465       "button_network", &settings->button_network,
466       "button_add_network", &settings->button_add_network,
467       "button_remove_network", &settings->button_remove_network,
468       NULL);
469   g_free (filename);
470
471   /* Fill the networks combobox */
472   store = gtk_list_store_new (2, G_TYPE_OBJECT, G_TYPE_STRING);
473
474   gtk_cell_layout_clear (GTK_CELL_LAYOUT (settings->combobox_network)); 
475   renderer = gtk_cell_renderer_text_new ();
476   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (settings->combobox_network),
477       renderer, TRUE);
478   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (settings->combobox_network),
479       renderer,
480       "text", COL_NETWORK_NAME,
481       NULL);
482
483   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
484       COL_NETWORK_NAME,
485       GTK_SORT_ASCENDING);
486
487   gtk_combo_box_set_model (GTK_COMBO_BOX (settings->combobox_network),
488       GTK_TREE_MODEL (store));
489   g_object_unref (store);
490
491   account_widget_irc_setup (settings);
492
493   empathy_account_widget_handle_params (account, gui,
494       "entry_nick", "account",
495       "entry_fullname", "fullname",
496       "entry_password", "password",
497       "entry_quit_message", "quit-message",
498       NULL);
499
500   empathy_builder_connect (gui, settings,
501       "vbox_irc_settings", "destroy", account_widget_irc_destroy_cb,
502       "button_network", "clicked", account_widget_irc_button_edit_network_clicked_cb,
503       "button_add_network", "clicked", account_widget_irc_button_add_network_clicked_cb,
504       "button_remove_network", "clicked", account_widget_irc_button_remove_clicked_cb,
505       "combobox_network", "changed", account_widget_irc_combobox_network_changed_cb,
506       NULL);
507
508   return empathy_builder_unref_and_keep_widget (gui, settings->vbox_settings);
509 }