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