]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-irc-network-chooser.c
ac814e614059e03b25d93c78aa1ed1bea216e108
[empathy.git] / libempathy-gtk / empathy-irc-network-chooser.c
1 /*
2  * Copyright (C) 2007-2008 Guillaume Desmottes
3  * Copyright (C) 2010 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Authors: Guillaume Desmottes <gdesmott@gnome.org>
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27
28 #include <glib/gi18n-lib.h>
29 #include <gtk/gtk.h>
30
31 #include <libempathy/empathy-utils.h>
32 #include <libempathy/empathy-irc-network-manager.h>
33
34 #include "empathy-irc-network-dialog.h"
35 #include "empathy-ui-utils.h"
36 #include "empathy-irc-network-chooser-dialog.h"
37
38 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT | EMPATHY_DEBUG_IRC
39 #include <libempathy/empathy-debug.h>
40
41 #include "empathy-irc-network-chooser.h"
42
43 #define DEFAULT_IRC_NETWORK "irc.gimp.org"
44 #define DEFAULT_IRC_PORT 6667
45 #define DEFAULT_IRC_SSL FALSE
46
47 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIrcNetworkChooser)
48
49 enum {
50     PROP_SETTINGS = 1
51 };
52
53 enum {
54     SIG_CHANGED,
55     LAST_SIGNAL
56 };
57
58 static guint signals[LAST_SIGNAL] = { 0 };
59
60 typedef struct {
61     EmpathyAccountSettings *settings;
62
63     EmpathyIrcNetworkManager *network_manager;
64     GtkWidget *dialog;
65     /* Displayed network */
66     EmpathyIrcNetwork *network;
67 } EmpathyIrcNetworkChooserPriv;
68
69 G_DEFINE_TYPE (EmpathyIrcNetworkChooser, empathy_irc_network_chooser,
70     GTK_TYPE_BUTTON);
71
72 static void
73 empathy_irc_network_chooser_set_property (GObject *object,
74     guint prop_id,
75     const GValue *value,
76     GParamSpec *pspec)
77 {
78   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (object);
79
80   switch (prop_id)
81     {
82       case PROP_SETTINGS:
83         priv->settings = g_value_dup_object (value);
84         break;
85       default:
86         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
87         break;
88     }
89 }
90
91 static void
92 empathy_irc_network_chooser_get_property (GObject *object,
93     guint prop_id,
94     GValue *value,
95     GParamSpec *pspec)
96 {
97   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (object);
98
99   switch (prop_id)
100     {
101       case PROP_SETTINGS:
102         g_value_set_object (value, priv->settings);
103         break;
104       default:
105         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
106         break;
107     }
108 }
109
110 static void
111 unset_server_params (EmpathyIrcNetworkChooser *self)
112 {
113   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);
114
115   DEBUG ("Unset server, port and use-ssl");
116   empathy_account_settings_unset (priv->settings, "server");
117   empathy_account_settings_unset (priv->settings, "port");
118   empathy_account_settings_unset (priv->settings, "use-ssl");
119 }
120
121 static gchar *
122 dup_network_service (EmpathyIrcNetwork *network)
123 {
124   /* Account.Service has to be a lower case alphanumeric string which may
125    * also contain '-' but not start with it. */
126 #define VALID G_CSET_a_2_z G_CSET_DIGITS "-"
127   gchar *service, *tmp;
128
129   service = g_strdup (empathy_irc_network_get_name (network));
130   service = g_strstrip (service);
131
132   if (tp_str_empty (service))
133     {
134       g_free (service);
135       return NULL;
136     }
137
138   tmp = service;
139   service = g_ascii_strdown (service, -1);
140   g_free (tmp);
141
142   service = g_strcanon (service, VALID, '-');
143
144   if (service[0] == '-')
145     {
146       tmp = service;
147       service = g_strdup (service + 1);
148
149       g_free (tmp);
150     }
151
152   return service;
153 }
154
155 static void
156 update_server_params (EmpathyIrcNetworkChooser *self)
157 {
158   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);
159   GSList *servers;
160   const gchar *charset;
161
162   g_assert (priv->network != NULL);
163
164   charset = empathy_irc_network_get_charset (priv->network);
165   DEBUG ("Setting charset to %s", charset);
166   empathy_account_settings_set (priv->settings, "charset",
167       g_variant_new_string (charset));
168
169   servers = empathy_irc_network_get_servers (priv->network);
170   if (g_slist_length (servers) > 0)
171     {
172       /* set the first server as CM server */
173       EmpathyIrcServer *server = servers->data;
174       gchar *address;
175       guint port;
176       gboolean ssl;
177       gchar *service;
178
179       g_object_get (server,
180           "address", &address,
181           "port", &port,
182           "ssl", &ssl,
183           NULL);
184
185       DEBUG ("Setting server to %s", address);
186       empathy_account_settings_set (priv->settings, "server",
187           g_variant_new_string (address));
188       DEBUG ("Setting port to %u", port);
189       empathy_account_settings_set (priv->settings, "port",
190           g_variant_new_uint32 (port));
191       DEBUG ("Setting use-ssl to %s", ssl ? "TRUE": "FALSE" );
192       empathy_account_settings_set (priv->settings, "use-ssl",
193           g_variant_new_boolean (ssl));
194
195       /* Set Account.Service */
196       service = dup_network_service (priv->network);
197       DEBUG ("Setting Service to %s", service);
198       empathy_account_settings_set_service (priv->settings, service);
199
200       g_free (address);
201       g_free (service);
202     }
203   else
204     {
205       /* No server. Unset values */
206       unset_server_params (self);
207     }
208
209   g_slist_foreach (servers, (GFunc) g_object_unref, NULL);
210   g_slist_free (servers);
211 }
212
213 static void
214 set_label (EmpathyIrcNetworkChooser *self)
215 {
216   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);
217
218   g_assert (priv->network != NULL);
219
220   gtk_button_set_label (GTK_BUTTON (self),
221       empathy_irc_network_get_name (priv->network));
222 }
223
224 static void
225 set_label_from_settings (EmpathyIrcNetworkChooser *self)
226 {
227   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);
228   const gchar *server;
229
230   tp_clear_object (&priv->network);
231
232   server = empathy_account_settings_get_string (priv->settings, "server");
233
234   if (server != NULL)
235     {
236       EmpathyIrcServer *srv;
237       gint port;
238       gboolean ssl;
239
240       priv->network = empathy_irc_network_manager_find_network_by_address (
241           priv->network_manager, server);
242
243       if (priv->network != NULL)
244         {
245           /* The network is known */
246           g_object_ref (priv->network);
247           set_label (self);
248           return;
249         }
250
251       /* We don't have this network. Let's create it */
252       port = empathy_account_settings_get_uint32 (priv->settings, "port");
253       ssl = empathy_account_settings_get_boolean (priv->settings,
254           "use-ssl");
255
256       DEBUG ("Create a network %s", server);
257       priv->network = empathy_irc_network_new (server);
258       srv = empathy_irc_server_new (server, port, ssl);
259
260       empathy_irc_network_append_server (priv->network, srv);
261       empathy_irc_network_manager_add (priv->network_manager, priv->network);
262
263       set_label (self);
264
265       g_object_unref (srv);
266       return;
267     }
268
269   /* Set default network */
270   priv->network = empathy_irc_network_manager_find_network_by_address (
271           priv->network_manager, DEFAULT_IRC_NETWORK);
272
273   if (priv->network == NULL)
274     {
275       /* Default network is not known, recreate it */
276       EmpathyIrcServer *srv;
277
278       priv->network = empathy_irc_network_new (DEFAULT_IRC_NETWORK);
279
280       srv = empathy_irc_server_new (DEFAULT_IRC_NETWORK, DEFAULT_IRC_PORT,
281           DEFAULT_IRC_SSL);
282
283       empathy_irc_network_append_server (priv->network, srv);
284       empathy_irc_network_manager_add (priv->network_manager, priv->network);
285
286       g_object_unref (srv);
287     }
288
289   set_label (self);
290   update_server_params (self);
291   g_object_ref (priv->network);
292 }
293
294 static void
295 dialog_response_cb (GtkDialog *dialog,
296     gint response,
297     EmpathyIrcNetworkChooser *self)
298 {
299   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);
300   EmpathyIrcNetworkChooserDialog *chooser =
301     EMPATHY_IRC_NETWORK_CHOOSER_DIALOG (priv->dialog);
302
303   if (response != GTK_RESPONSE_CLOSE &&
304       response != GTK_RESPONSE_DELETE_EVENT)
305     return;
306
307   if (empathy_irc_network_chooser_dialog_get_changed (chooser))
308     {
309       tp_clear_object (&priv->network);
310
311       priv->network = g_object_ref (
312           empathy_irc_network_chooser_dialog_get_network (chooser));
313
314       update_server_params (self);
315       set_label (self);
316
317       g_signal_emit (self, signals[SIG_CHANGED], 0);
318     }
319
320   gtk_widget_destroy (priv->dialog);
321   priv->dialog = NULL;
322 }
323
324 static void
325 clicked_cb (GtkButton *button,
326     gpointer user_data)
327 {
328   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (button);
329   GtkWindow *window;
330
331   if (priv->dialog != NULL)
332     goto out;
333
334   window = empathy_get_toplevel_window (GTK_WIDGET (button));
335
336   priv->dialog = empathy_irc_network_chooser_dialog_new (priv->settings,
337       priv->network, window);
338   gtk_widget_show_all (priv->dialog);
339
340   tp_g_signal_connect_object (priv->dialog, "response",
341       G_CALLBACK (dialog_response_cb), button, 0);
342
343 out:
344   empathy_window_present (GTK_WINDOW (priv->dialog));
345 }
346
347 static void
348 empathy_irc_network_chooser_constructed (GObject *object)
349 {
350   EmpathyIrcNetworkChooser *self = (EmpathyIrcNetworkChooser *) object;
351   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);
352
353   g_assert (priv->settings != NULL);
354
355   set_label_from_settings (self);
356
357   g_signal_connect (self, "clicked", G_CALLBACK (clicked_cb), self);
358 }
359
360 static void
361 empathy_irc_network_chooser_dispose (GObject *object)
362 {
363   EmpathyIrcNetworkManager *self = (EmpathyIrcNetworkManager *) object;
364   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);
365
366   tp_clear_object (&priv->settings);
367   tp_clear_object (&priv->network_manager);
368   tp_clear_object (&priv->network);
369
370   if (G_OBJECT_CLASS (empathy_irc_network_chooser_parent_class)->dispose)
371     G_OBJECT_CLASS (empathy_irc_network_chooser_parent_class)->dispose (object);
372 }
373
374 static void
375 empathy_irc_network_chooser_class_init (EmpathyIrcNetworkChooserClass *klass)
376 {
377   GObjectClass *object_class = G_OBJECT_CLASS (klass);
378
379   object_class->get_property = empathy_irc_network_chooser_get_property;
380   object_class->set_property = empathy_irc_network_chooser_set_property;
381   object_class->constructed = empathy_irc_network_chooser_constructed;
382   object_class->dispose = empathy_irc_network_chooser_dispose;
383
384   g_object_class_install_property (object_class, PROP_SETTINGS,
385     g_param_spec_object ("settings",
386       "Settings",
387       "The EmpathyAccountSettings to show and edit",
388       EMPATHY_TYPE_ACCOUNT_SETTINGS,
389       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
390
391   signals[SIG_CHANGED] = g_signal_new ("changed",
392       G_OBJECT_CLASS_TYPE (object_class),
393       G_SIGNAL_RUN_LAST,
394       0,
395       NULL, NULL,
396       g_cclosure_marshal_generic,
397       G_TYPE_NONE,
398       0);
399
400   g_type_class_add_private (object_class,
401       sizeof (EmpathyIrcNetworkChooserPriv));
402 }
403
404 static void
405 empathy_irc_network_chooser_init (EmpathyIrcNetworkChooser *self)
406 {
407   EmpathyIrcNetworkChooserPriv *priv;
408
409   priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
410       EMPATHY_TYPE_IRC_NETWORK_CHOOSER, EmpathyIrcNetworkChooserPriv);
411   self->priv = priv;
412
413   priv->network_manager = empathy_irc_network_manager_dup_default ();
414 }
415
416 GtkWidget *
417 empathy_irc_network_chooser_new (EmpathyAccountSettings *settings)
418 {
419   return g_object_new (EMPATHY_TYPE_IRC_NETWORK_CHOOSER,
420       "settings", settings,
421       NULL);
422 }
423
424 EmpathyIrcNetwork *
425 empathy_irc_network_chooser_get_network (EmpathyIrcNetworkChooser *self)
426 {
427   EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);
428
429   return priv->network;
430 }