]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-widget.c
fc95f66aafb69b14c6b628db2fe027b59ba80431
[empathy.git] / libempathy-gtk / empathy-account-widget.c
1 /*
2  * Copyright (C) 2006-2007 Imendio AB
3  * Copyright (C) 2007-2009 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program 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  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  *          Martyn Russell <martyn@imendio.com>
22  *          Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
23  *          Jonathan Tellier <jonathan.tellier@gmail.com>
24  *          Danielle Madeley <danielle.madeley@collabora.co.uk>
25  */
26
27 #include <config.h>
28
29 #include <string.h>
30
31 #include <gtk/gtk.h>
32 #include <glib/gi18n-lib.h>
33
34 #include <gio/gdesktopappinfo.h>
35
36 #include <libempathy/empathy-utils.h>
37
38 #include <telepathy-glib/account.h>
39 #include <telepathy-glib/account-manager.h>
40 #include <telepathy-glib/connection-manager.h>
41 #include <telepathy-glib/util.h>
42 #include <dbus/dbus-protocol.h>
43
44 #include "empathy-account-widget.h"
45 #include "empathy-account-widget-private.h"
46 #include "empathy-account-widget-sip.h"
47 #include "empathy-account-widget-irc.h"
48 #include "empathy-ui-utils.h"
49
50 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
51 #include <libempathy/empathy-debug.h>
52
53 G_DEFINE_TYPE (EmpathyAccountWidget, empathy_account_widget, G_TYPE_OBJECT)
54
55 typedef enum
56 {
57   NO_SERVICE = 0,
58   GTALK_SERVICE,
59   FACEBOOK_SERVICE,
60   N_SERVICES
61 } Service;
62
63 typedef struct
64 {
65   const gchar *label_username_example;
66   gboolean show_advanced;
67 } ServiceInfo;
68
69 static ServiceInfo services_infos[N_SERVICES] = {
70     { "label_username_example", TRUE },
71     { "label_username_g_example", FALSE },
72     { "label_username_f_example", FALSE },
73 };
74
75 struct _EmpathyAccountWidgetPriv {
76   EmpathyAccountSettings *settings;
77
78   GtkWidget *grid_common_settings;
79   GtkWidget *apply_button;
80   GtkWidget *cancel_button;
81   GtkWidget *entry_password;
82   GtkWidget *spinbutton_port;
83   GtkWidget *radiobutton_reuse;
84   GtkWidget *hbox_buttons;
85
86   gboolean simple;
87
88   gboolean contains_pending_changes;
89
90   /* An EmpathyAccountWidget can be used to either create an account or
91    * modify it. When we are creating an account, this member is set to TRUE */
92   gboolean creating_account;
93
94   /* whether there are any other real accounts. Necessary so we know whether
95    * it's safe to dismiss this widget in some cases (eg, whether the Cancel
96    * button should be sensitive) */
97   gboolean other_accounts_exist;
98
99   /* if TRUE, the GTK+ destroy signal has been fired and so the widgets
100    * embedded in this account widget can't be used any more
101    * workaround because some async callbacks can be called after the
102    * widget has been destroyed */
103   gboolean destroyed;
104
105   TpAccountManager *account_manager;
106
107   GtkWidget *param_account_widget;
108   GtkWidget *param_password_widget;
109
110   gboolean automatic_change;
111   GtkWidget *remember_password_widget;
112
113   /* Used only for IRC accounts */
114   EmpathyIrcNetworkChooser *irc_network_chooser;
115
116   /* Used for 'special' XMPP account having a service associated ensuring that
117    * JIDs have a specific suffix; such as Facebook for example */
118   gchar *jid_suffix;
119 };
120
121 enum {
122   PROP_PROTOCOL = 1,
123   PROP_SETTINGS,
124   PROP_SIMPLE,
125   PROP_CREATING_ACCOUNT,
126   PROP_OTHER_ACCOUNTS_EXIST,
127 };
128
129 enum {
130   HANDLE_APPLY,
131   ACCOUNT_CREATED,
132   CANCELLED,
133   CLOSE,
134   LAST_SIGNAL
135 };
136
137 static void account_widget_apply_and_log_in (EmpathyAccountWidget *);
138
139 enum {
140   RESPONSE_LAUNCH
141 };
142
143 static guint signals[LAST_SIGNAL] = { 0 };
144
145 #define CHANGED_TIMEOUT 300
146
147 #define DIGIT             "0-9"
148 #define DIGITS            "(["DIGIT"]+)"
149 #define ALPHA             "a-zA-Z"
150 #define ALPHAS            "(["ALPHA"]+)"
151 #define ALPHADIGIT        ALPHA DIGIT
152 #define ALPHADIGITS       "(["ALPHADIGIT"]+)"
153 #define ALPHADIGITDASH    ALPHA DIGIT "-"
154 #define ALPHADIGITDASHS   "(["ALPHADIGITDASH"]*)"
155
156 #define HOSTNUMBER        "("DIGITS"\\."DIGITS"\\."DIGITS"\\."DIGITS")"
157 #define TOPLABEL          "("ALPHAS \
158                             "| (["ALPHA"]"ALPHADIGITDASHS "["ALPHADIGIT"]))"
159 #define DOMAINLABEL       "("ALPHADIGITS"|(["ALPHADIGIT"]" ALPHADIGITDASHS \
160                                        "["ALPHADIGIT"]))"
161 #define HOSTNAME          "((" DOMAINLABEL "\\.)+" TOPLABEL ")"
162 /* Based on http://www.ietf.org/rfc/rfc1738.txt (section 5) */
163 #define HOST              "("HOSTNAME "|" HOSTNUMBER")"
164 /* Based on http://www.ietf.org/rfc/rfc0822.txt (appendix D) */
165 #define EMAIL_LOCALPART   "([^\\(\\)<>@,;:\\\\\"\\[\\]\\s]+)"
166
167 /* UIN is digital according to the unofficial specification:
168  * http://iserverd.khstu.ru/docum_ext/icqv5.html#CTS
169  * 5 digits minimum according to http://en.wikipedia.org/wiki/ICQ#UIN
170  * According to an user, we can also provide an email address instead of the
171  * ICQ UIN. */
172 #define ICQ_USER_NAME     "((["DIGIT"]{5,})|"EMAIL_LOCALPART"@"HOST")"
173
174 /* Based on http://www.ietf.org/rfc/rfc2812.txt (section 2.3.1) */
175 #define IRC_SPECIAL       "_\\[\\]{}\\\\|`^"
176 #define IRC_NICK_NAME     "(["ALPHA IRC_SPECIAL"]["ALPHADIGITDASH IRC_SPECIAL"]*)"
177 /*   user       =  1*( %x01-09 / %x0B-0C / %x0E-1F / %x21-3F / %x41-FF )
178  *                ; any octet except NUL, CR, LF, " " and "@"
179  *
180  * so technically, like so many other places in IRC, we should be using arrays
181  * of bytes here rather than UTF-8 strings. Life: too short. In practice this
182  * will always be ASCII.
183  */
184 #define IRC_USER_NAME     "([^\r\n@ ])+"
185
186 /* Based on http://www.ietf.org/rfc/rfc4622.txt (section 2.2)
187  * We just exclude invalid characters to avoid ucschars and other redundant
188  * complexity */
189 #define JABBER_USER_NAME  "([^@:'\"<>&\\s]+)"
190 /* ID is an email according to the unofficial specification:
191  * http://www.hypothetic.org/docs/msn/general/names.php */
192 #define MSN_USER_NAME     EMAIL_LOCALPART
193 /* Based on the official help:
194  * http://help.yahoo.com/l/us/yahoo/edit/registration/edit-01.html
195  * Looks like an email address can be used as well (bgo #655959)
196  * */
197 #define YAHOO_USER_NAME   "(["ALPHA"]["ALPHADIGIT"_\\.]{3,31})|("EMAIL_LOCALPART"@"HOST")"
198
199 #define ACCOUNT_REGEX_ICQ      "^"ICQ_USER_NAME"$"
200 #define ACCOUNT_REGEX_IRC      "^"IRC_NICK_NAME"$"
201 #define USERNAME_REGEX_IRC     "^"IRC_USER_NAME"$"
202 #define ACCOUNT_REGEX_JABBER   "^"JABBER_USER_NAME"@"HOST"$"
203 #define ACCOUNT_REGEX_MSN      "^"MSN_USER_NAME"@"HOST"$"
204 #define ACCOUNT_REGEX_YAHOO    "^"YAHOO_USER_NAME"$"
205
206 static void
207 account_widget_set_control_buttons_sensitivity (EmpathyAccountWidget *self,
208     gboolean sensitive)
209 {
210   /* we hit this case because of the 'other-accounts-exist' property handler
211    * being called during init (before constructed()) */
212   if (self->priv->apply_button == NULL || self->priv->cancel_button == NULL)
213     return;
214
215   gtk_widget_set_sensitive (self->priv->apply_button, sensitive);
216
217   if (sensitive)
218     {
219       /* We can't grab default if the widget hasn't be packed in a
220        * window */
221       GtkWidget *window;
222
223       window = gtk_widget_get_toplevel (self->priv->apply_button);
224       if (window != NULL &&
225           gtk_widget_is_toplevel (window))
226         {
227           gtk_widget_set_can_default (self->priv->apply_button, TRUE);
228           gtk_widget_grab_default (self->priv->apply_button);
229         }
230     }
231 }
232
233 static void
234 account_widget_set_entry_highlighting (GtkEntry *entry,
235     gboolean highlight)
236 {
237   g_return_if_fail (GTK_IS_ENTRY (entry));
238
239   if (highlight)
240     {
241       GtkStyleContext *style;
242       GdkRGBA color;
243
244       style = gtk_widget_get_style_context (GTK_WIDGET (entry));
245       gtk_style_context_get_background_color (style, GTK_STATE_FLAG_SELECTED,
246           &color);
247
248       /* Here we take the current theme colour and add it to
249        * the colour for white and average the two. This
250        * gives a colour which is inline with the theme but
251        * slightly whiter.
252        */
253       empathy_make_color_whiter (&color);
254
255       gtk_widget_override_background_color (GTK_WIDGET (entry), 0, &color);
256     }
257   else
258     {
259       gtk_widget_override_background_color (GTK_WIDGET (entry), 0, NULL);
260     }
261 }
262
263 static void
264 account_widget_handle_control_buttons_sensitivity (EmpathyAccountWidget *self)
265 {
266   gboolean is_valid;
267
268   is_valid = empathy_account_settings_is_valid (self->priv->settings);
269
270   account_widget_set_control_buttons_sensitivity (self, is_valid);
271
272   g_signal_emit (self, signals[HANDLE_APPLY], 0, is_valid);
273 }
274
275 static void
276 account_widget_entry_changed_common (EmpathyAccountWidget *self,
277     GtkEntry *entry, gboolean focus)
278 {
279   const gchar *str;
280   const gchar *param_name;
281   gboolean prev_status;
282   gboolean curr_status;
283
284   str = gtk_entry_get_text (entry);
285   param_name = g_object_get_data (G_OBJECT (entry), "param_name");
286   prev_status = empathy_account_settings_parameter_is_valid (
287       self->priv->settings, param_name);
288
289   if (EMP_STR_EMPTY (str))
290     {
291       const gchar *value = NULL;
292
293       empathy_account_settings_unset (self->priv->settings, param_name);
294
295       if (focus)
296         {
297           value = empathy_account_settings_get_string (self->priv->settings,
298               param_name);
299           DEBUG ("Unset %s and restore to %s", param_name, value);
300           gtk_entry_set_text (entry, value ? value : "");
301         }
302     }
303   else
304     {
305       DEBUG ("Setting %s to %s", param_name,
306           tp_strdiff (param_name, "password") ? str : "***");
307       empathy_account_settings_set_string (self->priv->settings, param_name,
308           str);
309     }
310
311   curr_status = empathy_account_settings_parameter_is_valid (
312       self->priv->settings, param_name);
313
314   if (curr_status != prev_status)
315     account_widget_set_entry_highlighting (entry, !curr_status);
316 }
317
318 static void
319 account_widget_entry_changed_cb (GtkEditable *entry,
320     EmpathyAccountWidget *self)
321 {
322   if (self->priv->automatic_change)
323     return;
324
325   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
326   empathy_account_widget_changed (self);
327 }
328
329 static void
330 account_widget_entry_map_cb (GtkEntry *entry,
331     EmpathyAccountWidget *self)
332 {
333   const gchar *param_name;
334   gboolean is_valid;
335
336   /* need to initialize input highlighting */
337   param_name = g_object_get_data (G_OBJECT (entry), "param_name");
338   is_valid = empathy_account_settings_parameter_is_valid (self->priv->settings,
339       param_name);
340   account_widget_set_entry_highlighting (entry, !is_valid);
341 }
342
343 static void
344 account_widget_int_changed_cb (GtkWidget *widget,
345     EmpathyAccountWidget *self)
346 {
347   const gchar *param_name;
348   gint value;
349   const gchar *signature;
350
351   value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
352   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
353
354   signature = empathy_account_settings_get_dbus_signature (self->priv->settings,
355     param_name);
356   g_return_if_fail (signature != NULL);
357
358   DEBUG ("Setting %s to %d", param_name, value);
359
360   switch ((int)*signature)
361     {
362     case DBUS_TYPE_INT16:
363     case DBUS_TYPE_INT32:
364       empathy_account_settings_set_int32 (self->priv->settings, param_name,
365           value);
366       break;
367     case DBUS_TYPE_INT64:
368       empathy_account_settings_set_int64 (self->priv->settings, param_name,
369           value);
370       break;
371     case DBUS_TYPE_UINT16:
372     case DBUS_TYPE_UINT32:
373       empathy_account_settings_set_uint32 (self->priv->settings, param_name,
374           value);
375       break;
376     case DBUS_TYPE_UINT64:
377       empathy_account_settings_set_uint64 (self->priv->settings, param_name,
378           value);
379       break;
380     default:
381       g_return_if_reached ();
382     }
383
384   empathy_account_widget_changed (self);
385 }
386
387 static void
388 account_widget_checkbutton_toggled_cb (GtkWidget *widget,
389     EmpathyAccountWidget *self)
390 {
391   gboolean     value;
392   gboolean     default_value;
393   const gchar *param_name;
394
395   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
396   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
397
398   /* FIXME: This is ugly! checkbox don't have a "not-set" value so we
399    * always unset the param and set the value if different from the
400    * default value. */
401   empathy_account_settings_unset (self->priv->settings, param_name);
402   default_value = empathy_account_settings_get_boolean (self->priv->settings,
403       param_name);
404
405   if (default_value == value)
406     {
407       DEBUG ("Unset %s and restore to %d", param_name, default_value);
408     }
409   else
410     {
411       DEBUG ("Setting %s to %d", param_name, value);
412       empathy_account_settings_set_boolean (self->priv->settings, param_name,
413           value);
414     }
415
416   empathy_account_widget_changed (self);
417 }
418
419 static void
420 account_widget_jabber_ssl_toggled_cb (GtkWidget *checkbutton_ssl,
421     EmpathyAccountWidget *self)
422 {
423   gboolean   value;
424   gint32       port = 0;
425
426   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton_ssl));
427   port = empathy_account_settings_get_uint32 (self->priv->settings, "port");
428
429   if (value)
430     {
431       if (port == 5222 || port == 0)
432         port = 5223;
433     }
434   else
435     {
436       if (port == 5223 || port == 0)
437         port = 5222;
438     }
439
440   gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->priv->spinbutton_port),
441       port);
442
443   self->priv->contains_pending_changes = TRUE;
444 }
445
446 static void
447 account_widget_combobox_changed_cb (GtkWidget *widget,
448     EmpathyAccountWidget *self)
449 {
450   GtkTreeIter iter;
451   GtkTreeModel *model;
452   const gchar *value;
453   const GValue *v;
454   const gchar *default_value = NULL;
455   const gchar *param_name;
456
457   if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
458     return;
459
460   model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
461   /* the param value is stored in the first column */
462   gtk_tree_model_get (model, &iter, 0, &value, -1);
463
464   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
465
466   v = empathy_account_settings_get_default (self->priv->settings, param_name);
467   if (v != NULL)
468     default_value = g_value_get_string (v);
469
470   if (!tp_strdiff (value, default_value))
471     {
472       DEBUG ("Unset %s and restore to %s", param_name, default_value);
473       empathy_account_settings_unset (self->priv->settings, param_name);
474     }
475   else
476     {
477       DEBUG ("Setting %s to %s", param_name, value);
478       empathy_account_settings_set_string (self->priv->settings, param_name,
479           value);
480     }
481
482   empathy_account_widget_changed (self);
483 }
484
485 static void
486 clear_icon_released_cb (GtkEntry *entry,
487     GtkEntryIconPosition icon_pos,
488     GdkEvent *event,
489     EmpathyAccountWidget *self)
490 {
491   const gchar *param_name;
492
493   param_name = g_object_get_data (G_OBJECT (entry), "param_name");
494
495   DEBUG ("Unset %s", param_name);
496   empathy_account_settings_unset (self->priv->settings, param_name);
497   gtk_entry_set_text (entry, "");
498
499   empathy_account_widget_changed (self);
500 }
501
502 static void
503 password_entry_changed_cb (GtkEditable *entry,
504     EmpathyAccountWidget *self)
505 {
506   const gchar *str;
507
508   str = gtk_entry_get_text (GTK_ENTRY (entry));
509
510   gtk_entry_set_icon_sensitive (GTK_ENTRY (entry),
511       GTK_ENTRY_ICON_SECONDARY, !EMP_STR_EMPTY (str));
512 }
513
514 static void
515 password_entry_activated_cb (GtkEntry *entry,
516     EmpathyAccountWidget *self)
517 {
518     if (gtk_widget_get_sensitive (self->priv->apply_button))
519         account_widget_apply_and_log_in (self);
520 }
521
522 static void
523 account_entry_activated_cb (GtkEntry *entry,
524     EmpathyAccountWidget *self)
525 {
526     if (gtk_widget_get_sensitive (self->priv->apply_button))
527         account_widget_apply_and_log_in (self);
528 }
529
530 void
531 empathy_account_widget_setup_widget (EmpathyAccountWidget *self,
532     GtkWidget *widget,
533     const gchar *param_name)
534 {
535   g_object_set_data_full (G_OBJECT (widget), "param_name",
536       g_strdup (param_name), g_free);
537
538   if (GTK_IS_SPIN_BUTTON (widget))
539     {
540       gint value = 0;
541       const gchar *signature;
542
543       signature = empathy_account_settings_get_dbus_signature (
544           self->priv->settings, param_name);
545       g_return_if_fail (signature != NULL);
546
547       switch ((int)*signature)
548         {
549           case DBUS_TYPE_INT16:
550           case DBUS_TYPE_INT32:
551             value = empathy_account_settings_get_int32 (self->priv->settings,
552               param_name);
553             break;
554           case DBUS_TYPE_INT64:
555             value = empathy_account_settings_get_int64 (self->priv->settings,
556               param_name);
557             break;
558           case DBUS_TYPE_UINT16:
559           case DBUS_TYPE_UINT32:
560             value = empathy_account_settings_get_uint32 (self->priv->settings,
561               param_name);
562             break;
563           case DBUS_TYPE_UINT64:
564             value = empathy_account_settings_get_uint64 (self->priv->settings,
565                 param_name);
566             break;
567           default:
568             g_return_if_reached ();
569         }
570
571       gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
572
573       g_signal_connect (widget, "value-changed",
574           G_CALLBACK (account_widget_int_changed_cb),
575           self);
576     }
577   else if (GTK_IS_ENTRY (widget))
578     {
579       const gchar *str = NULL;
580
581       str = empathy_account_settings_get_string (self->priv->settings,
582           param_name);
583       gtk_entry_set_text (GTK_ENTRY (widget), str ? str : "");
584
585       if (!tp_strdiff (param_name, "account"))
586         self->priv->param_account_widget = widget;
587       else if (!tp_strdiff (param_name, "password"))
588         self->priv->param_password_widget = widget;
589
590       if (strstr (param_name, "password"))
591         {
592           gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
593
594           /* Add 'clear' icon */
595           gtk_entry_set_icon_from_stock (GTK_ENTRY (widget),
596               GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
597
598           gtk_entry_set_icon_sensitive (GTK_ENTRY (widget),
599               GTK_ENTRY_ICON_SECONDARY, !EMP_STR_EMPTY (str));
600
601           g_signal_connect (widget, "icon-release",
602               G_CALLBACK (clear_icon_released_cb), self);
603           g_signal_connect (widget, "changed",
604               G_CALLBACK (password_entry_changed_cb), self);
605           g_signal_connect (widget, "activate",
606               G_CALLBACK (password_entry_activated_cb), self);
607         }
608       else if (strstr (param_name, "account"))
609         g_signal_connect (widget, "activate",
610             G_CALLBACK (account_entry_activated_cb), self);
611
612
613       g_signal_connect (widget, "changed",
614           G_CALLBACK (account_widget_entry_changed_cb), self);
615       g_signal_connect (widget, "map",
616           G_CALLBACK (account_widget_entry_map_cb), self);
617     }
618   else if (GTK_IS_TOGGLE_BUTTON (widget))
619     {
620       gboolean value = FALSE;
621
622       value = empathy_account_settings_get_boolean (self->priv->settings,
623           param_name);
624       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
625
626       g_signal_connect (widget, "toggled",
627           G_CALLBACK (account_widget_checkbutton_toggled_cb),
628           self);
629     }
630   else if (GTK_IS_COMBO_BOX (widget))
631     {
632       /* The combo box's model has to contain the param value in its first
633        * column (as a string) */
634       const gchar *str;
635       GtkTreeModel *model;
636       GtkTreeIter iter;
637       gboolean valid;
638
639       str = empathy_account_settings_get_string (self->priv->settings,
640           param_name);
641       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
642
643       valid = gtk_tree_model_get_iter_first (model, &iter);
644       while (valid)
645         {
646           gchar *name;
647
648           gtk_tree_model_get (model, &iter, 0, &name, -1);
649           if (!tp_strdiff (name, str))
650             {
651               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
652               valid = FALSE;
653             }
654           else
655             {
656               valid = gtk_tree_model_iter_next (model, &iter);
657             }
658
659           g_free (name);
660         }
661
662       g_signal_connect (widget, "changed",
663           G_CALLBACK (account_widget_combobox_changed_cb),
664           self);
665     }
666   else
667     {
668       DEBUG ("Unknown type of widget for param %s", param_name);
669     }
670
671   gtk_widget_set_sensitive (widget,
672       empathy_account_settings_param_is_supported (self->priv->settings,
673         param_name));
674 }
675
676 static GHashTable *
677 build_translated_params (void)
678 {
679   GHashTable *hash;
680
681   hash = g_hash_table_new (g_str_hash, g_str_equal);
682   g_hash_table_insert (hash, "account", _("Account"));
683   g_hash_table_insert (hash, "password", _("Password"));
684   g_hash_table_insert (hash, "server", _("Server"));
685   g_hash_table_insert (hash, "port", _("Port"));
686
687   return hash;
688 }
689
690 static gchar *
691 account_widget_generic_format_param_name (const gchar *param_name)
692 {
693   gchar *str;
694   gchar *p;
695   static GHashTable *translated_params = NULL;
696
697   if (G_UNLIKELY (translated_params == NULL))
698     translated_params = build_translated_params ();
699
700   /* Translate most common parameters */
701   str = g_hash_table_lookup (translated_params, param_name);
702   if (str != NULL)
703     return g_strdup (str);
704
705   str = g_strdup (param_name);
706
707   if (str && g_ascii_isalpha (str[0]))
708     str[0] = g_ascii_toupper (str[0]);
709
710   while ((p = strchr (str, '-')) != NULL)
711     {
712       if (p[1] != '\0' && g_ascii_isalpha (p[1]))
713         {
714           p[0] = ' ';
715           p[1] = g_ascii_toupper (p[1]);
716         }
717
718       p++;
719     }
720
721   return str;
722 }
723
724 static void
725 accounts_widget_generic_setup (EmpathyAccountWidget *self,
726     GtkWidget *grid_common_settings,
727     GtkWidget *grid_advanced_settings)
728 {
729   TpConnectionManagerParam *params, *param;
730   guint row_common = 0, row_advanced = 0;
731
732   params = empathy_account_settings_get_tp_params (self->priv->settings);
733
734   for (param = params; param != NULL && param->name != NULL; param++)
735     {
736       GtkWidget       *grid_settings;
737       guint           row;
738       GtkWidget       *widget = NULL;
739       gchar           *param_name_formatted;
740
741       if (param->flags & TP_CONN_MGR_PARAM_FLAG_REQUIRED)
742         {
743           grid_settings = grid_common_settings;
744           row = row_common++;
745         }
746       else if (self->priv->simple)
747         {
748           return;
749         }
750       else
751         {
752           grid_settings = grid_advanced_settings;
753           row = row_advanced++;
754         }
755
756       param_name_formatted = account_widget_generic_format_param_name
757         (param->name);
758
759       if (param->dbus_signature[0] == 's')
760         {
761           gchar *str;
762
763           str = g_strdup_printf (_("%s:"), param_name_formatted);
764           widget = gtk_label_new (str);
765           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
766           g_free (str);
767
768           gtk_grid_attach (GTK_GRID (grid_settings),
769               widget, 0, row, 1, 1);
770
771           gtk_widget_show (widget);
772
773           widget = gtk_entry_new ();
774           if (strcmp (param->name, "account") == 0)
775             {
776               g_signal_connect (widget, "realize",
777                   G_CALLBACK (gtk_widget_grab_focus),
778                   NULL);
779             }
780
781           gtk_grid_attach (GTK_GRID (grid_settings),
782               widget, 1, row, 1, 1);
783
784           gtk_widget_show (widget);
785         }
786       /* int types: ynqiuxt. double type is 'd' */
787       else if (param->dbus_signature[0] == 'y' ||
788           param->dbus_signature[0] == 'n' ||
789           param->dbus_signature[0] == 'q' ||
790           param->dbus_signature[0] == 'i' ||
791           param->dbus_signature[0] == 'u' ||
792           param->dbus_signature[0] == 'x' ||
793           param->dbus_signature[0] == 't' ||
794           param->dbus_signature[0] == 'd')
795         {
796           gchar   *str = NULL;
797           gdouble  minint = 0;
798           gdouble  maxint = 0;
799           gdouble  step = 1;
800
801           switch (param->dbus_signature[0])
802             {
803             case 'y': minint = G_MININT8;  maxint = G_MAXINT8;   break;
804             case 'n': minint = G_MININT16; maxint = G_MAXINT16;  break;
805             case 'q': minint = 0;          maxint = G_MAXUINT16; break;
806             case 'i': minint = G_MININT32; maxint = G_MAXINT32;  break;
807             case 'u': minint = 0;          maxint = G_MAXUINT32; break;
808             case 'x': minint = G_MININT64; maxint = G_MAXINT64;  break;
809             case 't': minint = 0;          maxint = G_MAXUINT64; break;
810             case 'd': minint = G_MININT32; maxint = G_MAXINT32;
811               step = 0.1; break;
812             default: g_assert_not_reached ();
813             }
814
815           str = g_strdup_printf (_("%s:"), param_name_formatted);
816           widget = gtk_label_new (str);
817           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
818           g_free (str);
819
820           gtk_grid_attach (GTK_GRID (grid_settings),
821               widget, 0, row, 1, 1);
822           gtk_widget_show (widget);
823
824           widget = gtk_spin_button_new_with_range (minint, maxint, step);
825           gtk_grid_attach (GTK_GRID (grid_settings),
826               widget, 1, row, 1, 1);
827           gtk_widget_show (widget);
828         }
829       else if (param->dbus_signature[0] == 'b')
830         {
831           widget = gtk_check_button_new_with_label (param_name_formatted);
832           gtk_grid_attach (GTK_GRID (grid_settings),
833               widget, 0, row, 2, 1);
834           gtk_widget_show (widget);
835         }
836       else
837         {
838           DEBUG ("Unknown signature for param %s: %s",
839               param_name_formatted, param->dbus_signature);
840         }
841
842       if (widget)
843         empathy_account_widget_setup_widget (self, widget, param->name);
844
845       g_free (param_name_formatted);
846     }
847 }
848
849 static void
850 account_widget_handle_params_valist (EmpathyAccountWidget *self,
851     const gchar *first_widget,
852     va_list args)
853 {
854   GObject *object;
855   const gchar *name;
856
857   for (name = first_widget; name; name = va_arg (args, const gchar *))
858     {
859       const gchar *param_name;
860
861       param_name = va_arg (args, const gchar *);
862       object = gtk_builder_get_object (self->ui_details->gui, name);
863
864       if (!object)
865         {
866           g_warning ("Builder is missing object '%s'.", name);
867           continue;
868         }
869
870       empathy_account_widget_setup_widget (self, GTK_WIDGET (object),
871           param_name);
872     }
873 }
874
875 static void
876 account_widget_cancel_clicked_cb (GtkWidget *button,
877     EmpathyAccountWidget *self)
878 {
879   g_signal_emit (self, signals[CANCELLED], 0);
880   g_signal_emit (self, signals[CLOSE], 0, GTK_RESPONSE_CANCEL);
881 }
882
883 static void
884 account_widget_account_enabled_cb (GObject *source_object,
885     GAsyncResult *res,
886     gpointer user_data)
887 {
888   GError *error = NULL;
889   TpAccount *account = TP_ACCOUNT (source_object);
890   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (user_data);
891
892   tp_account_set_enabled_finish (account, res, &error);
893
894   if (error != NULL)
895     {
896       DEBUG ("Could not enable the account: %s", error->message);
897       g_error_free (error);
898     }
899   else
900     {
901       empathy_connect_new_account (account, self->priv->account_manager);
902     }
903
904   /* unref self - part of the workaround */
905   g_object_unref (self);
906 }
907
908 static void
909 account_widget_applied_cb (GObject *source_object,
910     GAsyncResult *res,
911     gpointer user_data)
912 {
913   GError *error = NULL;
914   TpAccount *account;
915   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (source_object);
916   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (user_data);
917   gboolean reconnect_required;
918
919   empathy_account_settings_apply_finish (settings, res, &reconnect_required,
920       &error);
921
922   if (error != NULL)
923     {
924       DEBUG ("Could not apply changes to account: %s", error->message);
925       g_error_free (error);
926       return;
927     }
928
929   account = empathy_account_settings_get_account (self->priv->settings);
930
931   if (account != NULL)
932     {
933       if (self->priv->creating_account)
934         {
935           /* By default, when an account is created, we enable it. */
936
937           /* workaround to keep self alive during async call */
938           g_object_ref (self);
939
940           tp_account_set_enabled_async (account, TRUE,
941               account_widget_account_enabled_cb, self);
942           g_signal_emit (self, signals[ACCOUNT_CREATED], 0, account);
943         }
944       else
945         {
946           /* If the account was offline, we always want to try reconnecting,
947            * to give it a chance to connect if the previous params were wrong.
948            * tp_account_reconnect_async() won't do anything if the requested
949            * presence is offline anyway. */
950           if (tp_account_get_connection_status (account, NULL) ==
951               TP_CONNECTION_STATUS_DISCONNECTED)
952             reconnect_required = TRUE;
953
954           if (reconnect_required && tp_account_is_enabled (account)
955               && tp_account_is_enabled (account))
956             {
957               /* After having applied changes to a user account, we
958                * reconnect it if needed. This is done so the new
959                * information entered by the user is validated on the server. */
960               tp_account_reconnect_async (account, NULL, NULL);
961             }
962         }
963     }
964
965   if (!self->priv->destroyed)
966     account_widget_set_control_buttons_sensitivity (self, FALSE);
967
968   self->priv->contains_pending_changes = FALSE;
969
970   /* announce the widget can be closed */
971   g_signal_emit (self, signals[CLOSE], 0, GTK_RESPONSE_APPLY);
972
973   /* unref the widget - part of the workaround */
974   g_object_unref (self);
975 }
976
977 static void
978 account_widget_apply_and_log_in (EmpathyAccountWidget *self)
979 {
980   gboolean display_name_overridden;
981
982   if (self->priv->radiobutton_reuse != NULL)
983     {
984       gboolean reuse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
985             self->priv->radiobutton_reuse));
986
987       DEBUG ("Set register param: %d", !reuse);
988       empathy_account_settings_set_boolean (self->priv->settings, "register",
989           !reuse);
990     }
991
992   g_object_get (self->priv->settings,
993       "display-name-overridden", &display_name_overridden, NULL);
994
995   if (self->priv->creating_account || !display_name_overridden)
996     {
997       gchar *display_name;
998
999       /* set default display name for new accounts or update if user didn't
1000        * manually override it. */
1001       display_name = empathy_account_widget_get_default_display_name (self);
1002
1003       empathy_account_settings_set_display_name_async (self->priv->settings,
1004           display_name, NULL, NULL);
1005
1006       g_free (display_name);
1007     }
1008
1009   /* workaround to keep widget alive during async call */
1010   g_object_ref (self);
1011   empathy_account_settings_apply_async (self->priv->settings,
1012       account_widget_applied_cb, self);
1013 }
1014
1015 static void
1016 account_widget_apply_clicked_cb (GtkWidget *button,
1017     EmpathyAccountWidget *self)
1018 {
1019     account_widget_apply_and_log_in (self);
1020 }
1021
1022 static void
1023 account_widget_setup_generic (EmpathyAccountWidget *self)
1024 {
1025   GtkWidget *grid_common_settings;
1026   GtkWidget *grid_advanced_settings;
1027
1028   grid_common_settings = GTK_WIDGET (gtk_builder_get_object
1029       (self->ui_details->gui, "grid_common_settings"));
1030   grid_advanced_settings = GTK_WIDGET (gtk_builder_get_object
1031       (self->ui_details->gui, "grid_advanced_settings"));
1032
1033   accounts_widget_generic_setup (self, grid_common_settings,
1034       grid_advanced_settings);
1035
1036   g_object_unref (self->ui_details->gui);
1037 }
1038
1039 static void
1040 account_widget_settings_ready_cb (EmpathyAccountSettings *settings,
1041     GParamSpec *pspec,
1042     gpointer user_data)
1043 {
1044   EmpathyAccountWidget *self = user_data;
1045
1046   if (empathy_account_settings_is_ready (self->priv->settings))
1047     account_widget_setup_generic (self);
1048 }
1049
1050 static void
1051 account_widget_build_generic (EmpathyAccountWidget *self,
1052     const char *filename)
1053 {
1054   GtkWidget *expander_advanced;
1055
1056   self->ui_details->gui = empathy_builder_get_file (filename,
1057       "grid_common_settings", &self->priv->grid_common_settings,
1058       "vbox_generic_settings", &self->ui_details->widget,
1059       "expander_advanced_settings", &expander_advanced,
1060       NULL);
1061
1062   if (self->priv->simple)
1063     gtk_widget_hide (expander_advanced);
1064
1065   g_object_ref (self->ui_details->gui);
1066
1067   if (empathy_account_settings_is_ready (self->priv->settings))
1068     account_widget_setup_generic (self);
1069   else
1070     g_signal_connect (self->priv->settings, "notify::ready",
1071         G_CALLBACK (account_widget_settings_ready_cb), self);
1072 }
1073
1074 static void
1075 account_widget_build_salut (EmpathyAccountWidget *self,
1076     const char *filename)
1077 {
1078   GtkWidget *expander_advanced;
1079
1080   self->ui_details->gui = empathy_builder_get_file (filename,
1081       "grid_common_settings", &self->priv->grid_common_settings,
1082       "vbox_salut_settings", &self->ui_details->widget,
1083       "expander_advanced_settings", &expander_advanced,
1084       NULL);
1085
1086   empathy_account_widget_handle_params (self,
1087       "entry_published", "published-name",
1088       "entry_nickname", "nickname",
1089       "entry_first_name", "first-name",
1090       "entry_last_name", "last-name",
1091       "entry_email", "email",
1092       "entry_jid", "jid",
1093       NULL);
1094
1095   if (self->priv->simple)
1096     gtk_widget_hide (expander_advanced);
1097
1098   self->ui_details->default_focus = g_strdup ("entry_first_name");
1099 }
1100
1101 static void
1102 account_widget_build_irc (EmpathyAccountWidget *self,
1103   const char *filename)
1104 {
1105   empathy_account_settings_set_regex (self->priv->settings, "account",
1106       ACCOUNT_REGEX_IRC);
1107   empathy_account_settings_set_regex (self->priv->settings, "username",
1108       USERNAME_REGEX_IRC);
1109
1110   if (self->priv->simple)
1111     {
1112       self->priv->irc_network_chooser = empathy_account_widget_irc_build_simple
1113         (self, filename);
1114     }
1115   else
1116     {
1117       self->priv->irc_network_chooser = empathy_account_widget_irc_build (self,
1118           filename, &self->priv->grid_common_settings);
1119     }
1120 }
1121
1122 static void
1123 account_widget_build_sip (EmpathyAccountWidget *self,
1124   const char *filename)
1125 {
1126   empathy_account_widget_sip_build (self, filename,
1127     &self->priv->grid_common_settings);
1128
1129   if (self->priv->simple)
1130     {
1131       self->priv->remember_password_widget = GTK_WIDGET (
1132           gtk_builder_get_object (self->ui_details->gui,
1133             "remember_password_simple"));
1134     }
1135   else
1136     {
1137       self->priv->remember_password_widget = GTK_WIDGET (
1138           gtk_builder_get_object (self->ui_details->gui, "remember_password"));
1139     }
1140 }
1141
1142 static void
1143 account_widget_build_msn (EmpathyAccountWidget *self,
1144     const char *filename)
1145 {
1146   empathy_account_settings_set_regex (self->priv->settings, "account",
1147       ACCOUNT_REGEX_MSN);
1148
1149   if (self->priv->simple)
1150     {
1151       self->ui_details->gui = empathy_builder_get_file (filename,
1152           "vbox_msn_simple", &self->ui_details->widget,
1153           NULL);
1154
1155       empathy_account_widget_handle_params (self,
1156           "entry_id_simple", "account",
1157           "entry_password_simple", "password",
1158           NULL);
1159
1160       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1161
1162       self->priv->remember_password_widget = GTK_WIDGET (
1163           gtk_builder_get_object (self->ui_details->gui,
1164             "remember_password_simple"));
1165     }
1166   else
1167     {
1168       self->ui_details->gui = empathy_builder_get_file (filename,
1169           "grid_common_msn_settings", &self->priv->grid_common_settings,
1170           "vbox_msn_settings", &self->ui_details->widget,
1171           NULL);
1172
1173       empathy_account_widget_handle_params (self,
1174           "entry_id", "account",
1175           "entry_password", "password",
1176           "entry_server", "server",
1177           "spinbutton_port", "port",
1178           NULL);
1179
1180       self->ui_details->default_focus = g_strdup ("entry_id");
1181
1182       self->priv->remember_password_widget = GTK_WIDGET (
1183           gtk_builder_get_object (self->ui_details->gui, "remember_password"));
1184     }
1185 }
1186
1187 static void
1188 suffix_id_widget_changed_cb (GtkWidget *entry,
1189     EmpathyAccountWidget *self)
1190 {
1191   const gchar *account;
1192
1193   g_assert (self->priv->jid_suffix != NULL);
1194
1195   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
1196
1197   account = empathy_account_settings_get_string (self->priv->settings,
1198       "account");
1199   if (!EMP_STR_EMPTY (account) &&
1200       !g_str_has_suffix (account, self->priv->jid_suffix))
1201     {
1202       gchar *tmp;
1203
1204       tmp = g_strdup_printf ("%s%s", account, self->priv->jid_suffix);
1205
1206       DEBUG ("Change account from '%s' to '%s'", account, tmp);
1207
1208       empathy_account_settings_set_string (self->priv->settings, "account",
1209           tmp);
1210       g_free (tmp);
1211     }
1212
1213   empathy_account_widget_changed (self);
1214 }
1215
1216 static gchar *
1217 remove_jid_suffix (EmpathyAccountWidget *self,
1218     const gchar *str)
1219 {
1220   g_assert (self->priv->jid_suffix != NULL);
1221
1222   if (!g_str_has_suffix (str, self->priv->jid_suffix))
1223     return g_strdup (str);
1224
1225   return g_strndup (str, strlen (str) - strlen (self->priv->jid_suffix));
1226 }
1227
1228 static void
1229 setup_id_widget_with_suffix (EmpathyAccountWidget *self,
1230     GtkWidget *widget,
1231     const gchar *suffix)
1232 {
1233   const gchar *str = NULL;
1234
1235   g_object_set_data_full (G_OBJECT (widget), "param_name",
1236       g_strdup ("account"), g_free);
1237
1238   g_assert (self->priv->jid_suffix == NULL);
1239   self->priv->jid_suffix = g_strdup (suffix);
1240
1241   str = empathy_account_settings_get_string (self->priv->settings, "account");
1242   if (str != NULL)
1243     {
1244       gchar *tmp;
1245
1246       tmp = remove_jid_suffix (self, str);
1247       gtk_entry_set_text (GTK_ENTRY (widget), tmp);
1248       g_free (tmp);
1249     }
1250
1251   self->priv->param_account_widget = widget;
1252
1253   g_signal_connect (widget, "changed",
1254       G_CALLBACK (suffix_id_widget_changed_cb), self);
1255 }
1256
1257 static Service
1258 account_widget_get_service (EmpathyAccountWidget *self)
1259 {
1260   const gchar *icon_name, *service;
1261
1262   icon_name = empathy_account_settings_get_icon_name (self->priv->settings);
1263   service = empathy_account_settings_get_service (self->priv->settings);
1264
1265   /* Previous versions of Empathy didn't set the Service property on Facebook
1266    * and gtalk accounts, so we check using the icon name as well. */
1267   if (!tp_strdiff (icon_name, "im-google-talk") ||
1268       !tp_strdiff (service, "google-talk"))
1269     return GTALK_SERVICE;
1270
1271   if (!tp_strdiff (icon_name, "im-facebook") ||
1272       !tp_strdiff (service, "facebook"))
1273     return FACEBOOK_SERVICE;
1274
1275   return NO_SERVICE;
1276 }
1277
1278 static void
1279 account_widget_build_jabber (EmpathyAccountWidget *self,
1280     const char *filename)
1281 {
1282   GtkWidget *spinbutton_port;
1283   GtkWidget *checkbutton_ssl;
1284   GtkWidget *label_id, *label_password;
1285   GtkWidget *label_id_create, *label_password_create;
1286   GtkWidget *label_example_fb;
1287   GtkWidget *label_example;
1288   GtkWidget *expander_advanced;
1289   GtkWidget *entry_id;
1290   Service service;
1291
1292   service = account_widget_get_service (self);
1293
1294   empathy_account_settings_set_regex (self->priv->settings, "account",
1295       ACCOUNT_REGEX_JABBER);
1296
1297   if (self->priv->simple && service == NO_SERVICE)
1298     {
1299       /* Simple widget for XMPP */
1300       self->ui_details->gui = empathy_builder_get_file (filename,
1301           "vbox_jabber_simple", &self->ui_details->widget,
1302           "label_id_simple", &label_id,
1303           "label_id_create", &label_id_create,
1304           "label_password_simple", &label_password,
1305           "label_password_create", &label_password_create,
1306           NULL);
1307
1308       if (empathy_account_settings_get_boolean (self->priv->settings,
1309             "register"))
1310         {
1311           gtk_widget_hide (label_id);
1312           gtk_widget_hide (label_password);
1313           gtk_widget_show (label_id_create);
1314           gtk_widget_show (label_password_create);
1315         }
1316
1317       empathy_account_widget_handle_params (self,
1318           "entry_id_simple", "account",
1319           "entry_password_simple", "password",
1320           NULL);
1321
1322       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1323
1324       self->priv->remember_password_widget = GTK_WIDGET (
1325           gtk_builder_get_object (self->ui_details->gui,
1326             "remember_password_simple"));
1327     }
1328   else if (self->priv->simple && service == GTALK_SERVICE)
1329     {
1330       /* Simple widget for Google Talk */
1331       self->ui_details->gui = empathy_builder_get_file (filename,
1332           "vbox_gtalk_simple", &self->ui_details->widget,
1333           NULL);
1334
1335       empathy_account_widget_handle_params (self,
1336           "entry_id_g_simple", "account",
1337           "entry_password_g_simple", "password",
1338           NULL);
1339
1340       self->ui_details->default_focus = g_strdup ("entry_id_g_simple");
1341
1342       self->priv->remember_password_widget = GTK_WIDGET (
1343           gtk_builder_get_object (self->ui_details->gui,
1344             "remember_password_g_simple"));
1345     }
1346   else if (self->priv->simple && service == FACEBOOK_SERVICE)
1347     {
1348       /* Simple widget for Facebook */
1349       self->ui_details->gui = empathy_builder_get_file (filename,
1350           "vbox_fb_simple", &self->ui_details->widget,
1351           "entry_id_fb_simple", &entry_id,
1352           NULL);
1353
1354       empathy_account_widget_handle_params (self,
1355           "entry_password_fb_simple", "password",
1356           NULL);
1357
1358       setup_id_widget_with_suffix (self, entry_id, "@chat.facebook.com");
1359
1360       self->ui_details->default_focus = g_strdup ("entry_id_fb_simple");
1361
1362       self->priv->remember_password_widget = GTK_WIDGET (
1363           gtk_builder_get_object (self->ui_details->gui,
1364             "remember_password_fb_simple"));
1365     }
1366   else
1367     {
1368       ServiceInfo info = services_infos[service];
1369
1370       /* Full widget for XMPP, Google Talk and Facebook*/
1371       self->ui_details->gui = empathy_builder_get_file (filename,
1372           "grid_common_settings", &self->priv->grid_common_settings,
1373           "vbox_jabber_settings", &self->ui_details->widget,
1374           "spinbutton_port", &spinbutton_port,
1375           "checkbutton_ssl", &checkbutton_ssl,
1376           "label_username_f_example", &label_example_fb,
1377           info.label_username_example, &label_example,
1378           "expander_advanced", &expander_advanced,
1379           "entry_id", &entry_id,
1380           "label_id", &label_id,
1381           NULL);
1382
1383       empathy_account_widget_handle_params (self,
1384           "entry_password", "password",
1385           "entry_resource", "resource",
1386           "entry_server", "server",
1387           "spinbutton_port", "port",
1388           "spinbutton_priority", "priority",
1389           "checkbutton_ssl", "old-ssl",
1390           "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
1391           "checkbutton_encryption", "require-encryption",
1392           NULL);
1393
1394       if (service == FACEBOOK_SERVICE)
1395         {
1396           gtk_label_set_label (GTK_LABEL (label_id), _("Username:"));
1397
1398           /* Facebook special case the entry ID widget to hide the
1399            * "@chat.facebook.com" part */
1400           setup_id_widget_with_suffix (self, entry_id, "@chat.facebook.com");
1401         }
1402       else
1403         {
1404           empathy_account_widget_setup_widget (self, entry_id, "account");
1405         }
1406
1407       self->ui_details->default_focus = g_strdup ("entry_id");
1408       self->priv->spinbutton_port = spinbutton_port;
1409
1410       self->priv->remember_password_widget = GTK_WIDGET (
1411           gtk_builder_get_object (self->ui_details->gui, "remember_password"));
1412
1413       g_signal_connect (checkbutton_ssl, "toggled",
1414           G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
1415           self);
1416
1417       if (service == FACEBOOK_SERVICE)
1418         {
1419           GtkContainer *parent;
1420           GList *children;
1421
1422           /* Removing the label from list of focusable widgets */
1423           parent = GTK_CONTAINER (gtk_widget_get_parent (label_example_fb));
1424           children = gtk_container_get_children (parent);
1425           children = g_list_remove (children, label_example_fb);
1426           gtk_container_set_focus_chain (parent, children);
1427           g_list_free (children);
1428         }
1429
1430       gtk_widget_show (label_example);
1431
1432       if (!info.show_advanced)
1433         gtk_widget_hide (expander_advanced);
1434     }
1435 }
1436
1437 static void
1438 account_widget_build_icq (EmpathyAccountWidget *self,
1439     const char *filename)
1440 {
1441   GtkWidget *spinbutton_port;
1442
1443   empathy_account_settings_set_regex (self->priv->settings, "account",
1444       ACCOUNT_REGEX_ICQ);
1445
1446   if (self->priv->simple)
1447     {
1448       self->ui_details->gui = empathy_builder_get_file (filename,
1449           "vbox_icq_simple", &self->ui_details->widget,
1450           NULL);
1451
1452       empathy_account_widget_handle_params (self,
1453           "entry_uin_simple", "account",
1454           "entry_password_simple", "password",
1455           NULL);
1456
1457       self->ui_details->default_focus = g_strdup ("entry_uin_simple");
1458
1459       self->priv->remember_password_widget = GTK_WIDGET (
1460           gtk_builder_get_object (self->ui_details->gui,
1461             "remember_password_simple"));
1462     }
1463   else
1464     {
1465       self->ui_details->gui = empathy_builder_get_file (filename,
1466           "grid_common_settings", &self->priv->grid_common_settings,
1467           "vbox_icq_settings", &self->ui_details->widget,
1468           "spinbutton_port", &spinbutton_port,
1469           NULL);
1470
1471       empathy_account_widget_handle_params (self,
1472           "entry_uin", "account",
1473           "entry_password", "password",
1474           "entry_server", "server",
1475           "spinbutton_port", "port",
1476           "entry_charset", "charset",
1477           NULL);
1478
1479       self->ui_details->default_focus = g_strdup ("entry_uin");
1480
1481       self->priv->remember_password_widget = GTK_WIDGET (
1482           gtk_builder_get_object (self->ui_details->gui, "remember_password"));
1483     }
1484 }
1485
1486 static void
1487 account_widget_build_aim (EmpathyAccountWidget *self,
1488     const char *filename)
1489 {
1490   GtkWidget *spinbutton_port;
1491
1492   if (self->priv->simple)
1493     {
1494       self->ui_details->gui = empathy_builder_get_file (filename,
1495           "vbox_aim_simple", &self->ui_details->widget,
1496           NULL);
1497
1498       empathy_account_widget_handle_params (self,
1499           "entry_screenname_simple", "account",
1500           "entry_password_simple", "password",
1501           NULL);
1502
1503       self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
1504
1505       self->priv->remember_password_widget = GTK_WIDGET (
1506           gtk_builder_get_object (self->ui_details->gui,
1507             "remember_password_simple"));
1508     }
1509   else
1510     {
1511       self->ui_details->gui = empathy_builder_get_file (filename,
1512           "grid_common_settings", &self->priv->grid_common_settings,
1513           "vbox_aim_settings", &self->ui_details->widget,
1514           "spinbutton_port", &spinbutton_port,
1515           NULL);
1516
1517       empathy_account_widget_handle_params (self,
1518           "entry_screenname", "account",
1519           "entry_password", "password",
1520           "entry_server", "server",
1521           "spinbutton_port", "port",
1522           NULL);
1523
1524       self->ui_details->default_focus = g_strdup ("entry_screenname");
1525
1526       self->priv->remember_password_widget = GTK_WIDGET (
1527           gtk_builder_get_object (self->ui_details->gui, "remember_password"));
1528     }
1529 }
1530
1531 static void
1532 account_widget_build_yahoo (EmpathyAccountWidget *self,
1533     const char *filename)
1534 {
1535   empathy_account_settings_set_regex (self->priv->settings, "account",
1536       ACCOUNT_REGEX_YAHOO);
1537
1538   if (self->priv->simple)
1539     {
1540       self->ui_details->gui = empathy_builder_get_file (filename,
1541           "vbox_yahoo_simple", &self->ui_details->widget,
1542           NULL);
1543
1544       empathy_account_widget_handle_params (self,
1545           "entry_id_simple", "account",
1546           "entry_password_simple", "password",
1547           NULL);
1548
1549       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1550
1551       self->priv->remember_password_widget = GTK_WIDGET (
1552           gtk_builder_get_object (self->ui_details->gui,
1553             "remember_password_simple"));
1554     }
1555   else
1556     {
1557       self->ui_details->gui = empathy_builder_get_file (filename,
1558           "grid_common_settings", &self->priv->grid_common_settings,
1559           "vbox_yahoo_settings", &self->ui_details->widget,
1560           NULL);
1561
1562       empathy_account_widget_handle_params (self,
1563           "entry_id", "account",
1564           "entry_password", "password",
1565           "entry_locale", "room-list-locale",
1566           "entry_charset", "charset",
1567           "spinbutton_port", "port",
1568           "checkbutton_ignore_invites", "ignore-invites",
1569           NULL);
1570
1571       self->ui_details->default_focus = g_strdup ("entry_id");
1572
1573       self->priv->remember_password_widget = GTK_WIDGET (
1574           gtk_builder_get_object (self->ui_details->gui, "remember_password"));
1575     }
1576 }
1577
1578 static void
1579 account_widget_build_groupwise (EmpathyAccountWidget *self,
1580     const char *filename)
1581 {
1582   if (self->priv->simple)
1583     {
1584       self->ui_details->gui = empathy_builder_get_file (filename,
1585           "vbox_groupwise_simple", &self->ui_details->widget,
1586           NULL);
1587
1588       empathy_account_widget_handle_params (self,
1589           "entry_id_simple", "account",
1590           "entry_password_simple", "password",
1591           NULL);
1592
1593       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1594
1595       self->priv->remember_password_widget = GTK_WIDGET (
1596           gtk_builder_get_object (self->ui_details->gui,
1597             "remember_password_simple"));
1598     }
1599   else
1600     {
1601       self->ui_details->gui = empathy_builder_get_file (filename,
1602           "grid_common_groupwise_settings", &self->priv->grid_common_settings,
1603           "vbox_groupwise_settings", &self->ui_details->widget,
1604           NULL);
1605
1606       empathy_account_widget_handle_params (self,
1607           "entry_id", "account",
1608           "entry_password", "password",
1609           "entry_server", "server",
1610           "spinbutton_port", "port",
1611           NULL);
1612
1613       self->ui_details->default_focus = g_strdup ("entry_id");
1614
1615       self->priv->remember_password_widget = GTK_WIDGET (
1616           gtk_builder_get_object (self->ui_details->gui, "remember_password"));
1617     }
1618 }
1619
1620 static void
1621 account_widget_destroy_cb (GtkWidget *widget,
1622     EmpathyAccountWidget *self)
1623 {
1624   /* set the destroyed flag - workaround */
1625   self->priv->destroyed = TRUE;
1626
1627   g_object_unref (self);
1628 }
1629
1630 void
1631 empathy_account_widget_set_other_accounts_exist (EmpathyAccountWidget *self,
1632     gboolean others_exist)
1633 {
1634   self->priv->other_accounts_exist = others_exist;
1635
1636   if (self->priv->creating_account)
1637     account_widget_handle_control_buttons_sensitivity (self);
1638 }
1639
1640 static void
1641 do_set_property (GObject *object,
1642     guint prop_id,
1643     const GValue *value,
1644     GParamSpec *pspec)
1645 {
1646   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (object);
1647
1648   switch (prop_id)
1649     {
1650     case PROP_SETTINGS:
1651       self->priv->settings = g_value_dup_object (value);
1652       break;
1653     case PROP_SIMPLE:
1654       self->priv->simple = g_value_get_boolean (value);
1655       break;
1656     case PROP_CREATING_ACCOUNT:
1657       self->priv->creating_account = g_value_get_boolean (value);
1658       break;
1659     case PROP_OTHER_ACCOUNTS_EXIST:
1660       empathy_account_widget_set_other_accounts_exist (
1661           EMPATHY_ACCOUNT_WIDGET (object), g_value_get_boolean (value));
1662       break;
1663     default:
1664       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1665     }
1666 }
1667
1668 static void
1669 do_get_property (GObject *object,
1670     guint prop_id,
1671     GValue *value,
1672     GParamSpec *pspec)
1673 {
1674   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (object);
1675
1676   switch (prop_id)
1677     {
1678     case PROP_PROTOCOL:
1679       g_value_set_string (value,
1680         empathy_account_settings_get_protocol (self->priv->settings));
1681       break;
1682     case PROP_SETTINGS:
1683       g_value_set_object (value, self->priv->settings);
1684       break;
1685     case PROP_SIMPLE:
1686       g_value_set_boolean (value, self->priv->simple);
1687       break;
1688     case PROP_CREATING_ACCOUNT:
1689       g_value_set_boolean (value, self->priv->creating_account);
1690       break;
1691     case PROP_OTHER_ACCOUNTS_EXIST:
1692       g_value_set_boolean (value, self->priv->other_accounts_exist);
1693       break;
1694     default:
1695       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1696     }
1697 }
1698
1699 static void
1700 set_apply_button (EmpathyAccountWidget *self)
1701 {
1702   GtkWidget *image;
1703
1704   /* We can't use the stock button as its accelerator ('A') clashes with the
1705    * Add button. */
1706   gtk_button_set_use_stock (GTK_BUTTON (self->priv->apply_button), FALSE);
1707
1708   gtk_button_set_label (GTK_BUTTON (self->priv->apply_button), _("A_pply"));
1709   gtk_button_set_use_underline (GTK_BUTTON (self->priv->apply_button), TRUE);
1710
1711   image = gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON);
1712   gtk_button_set_image (GTK_BUTTON (self->priv->apply_button), image);
1713 }
1714
1715 static void
1716 presence_changed_cb (TpAccountManager *manager,
1717     TpConnectionPresenceType state,
1718     const gchar *status,
1719     const gchar *message,
1720     EmpathyAccountWidget *self)
1721 {
1722   if (self->priv->destroyed)
1723     return;
1724
1725   if (self->priv->apply_button == NULL)
1726     /* This button doesn't exist in 'simple' mode */
1727     return;
1728
1729   if (state > TP_CONNECTION_PRESENCE_TYPE_OFFLINE &&
1730       self->priv->creating_account)
1731     {
1732       /* We are online and creating a new account, display a Login button */
1733       GtkWidget *image;
1734
1735       gtk_button_set_use_stock (GTK_BUTTON (self->priv->apply_button), FALSE);
1736       gtk_button_set_label (GTK_BUTTON (self->priv->apply_button),
1737           _("L_og in"));
1738
1739       image = gtk_image_new_from_stock (GTK_STOCK_CONNECT,
1740           GTK_ICON_SIZE_BUTTON);
1741       gtk_button_set_image (GTK_BUTTON (self->priv->apply_button), image);
1742     }
1743   else
1744     {
1745       /* We are offline or modifying an existing account, display
1746        * a Save button */
1747       set_apply_button (self);
1748     }
1749 }
1750
1751 static void
1752 account_manager_ready_cb (GObject *source_object,
1753     GAsyncResult *result,
1754     gpointer user_data)
1755 {
1756   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (user_data);
1757   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
1758   GError *error = NULL;
1759   TpConnectionPresenceType state;
1760
1761   if (!tp_proxy_prepare_finish (account_manager, result, &error))
1762     {
1763       DEBUG ("Failed to prepare account manager: %s", error->message);
1764       g_error_free (error);
1765       goto out;
1766     }
1767
1768   state = tp_account_manager_get_most_available_presence (account_manager, NULL,
1769       NULL);
1770
1771   /* simulate a presence change so the apply button will be changed
1772    * if needed */
1773   presence_changed_cb (account_manager, state, NULL, NULL, self);
1774
1775 out:
1776   g_object_unref (self);
1777 }
1778
1779 #define WIDGET(cm, proto) \
1780   { #cm, #proto, "empathy-account-widget-"#proto".ui", \
1781     account_widget_build_##proto }
1782
1783 #ifndef HAVE_MEEGO
1784 /* Meego doesn't support registration */
1785 static void
1786 add_register_buttons (EmpathyAccountWidget *self,
1787     TpAccount *account)
1788 {
1789   const TpConnectionManagerProtocol *protocol;
1790   GtkWidget *radiobutton_register;
1791   GtkWidget *vbox = self->ui_details->widget;
1792
1793   if (!self->priv->creating_account)
1794     return;
1795
1796   protocol = empathy_account_settings_get_tp_protocol (self->priv->settings);
1797   if (protocol == NULL)
1798     return;
1799
1800   if (!tp_connection_manager_protocol_can_register (protocol))
1801     return;
1802
1803   if (account_widget_get_service (self) != NO_SERVICE)
1804     return;
1805
1806   if (self->priv->simple)
1807     return;
1808
1809   self->priv->radiobutton_reuse = gtk_radio_button_new_with_label (NULL,
1810       _("This account already exists on the server"));
1811   radiobutton_register = gtk_radio_button_new_with_label (
1812       gtk_radio_button_get_group (
1813         GTK_RADIO_BUTTON (self->priv->radiobutton_reuse)),
1814       _("Create a new account on the server"));
1815
1816   gtk_box_pack_start (GTK_BOX (vbox), self->priv->radiobutton_reuse, FALSE,
1817       FALSE, 0);
1818   gtk_box_pack_start (GTK_BOX (vbox), radiobutton_register, FALSE, FALSE, 0);
1819   gtk_box_reorder_child (GTK_BOX (vbox), self->priv->radiobutton_reuse, 0);
1820   gtk_box_reorder_child (GTK_BOX (vbox), radiobutton_register, 1);
1821   gtk_widget_show (self->priv->radiobutton_reuse);
1822   gtk_widget_show (radiobutton_register);
1823 }
1824 #endif /* HAVE_MEEGO */
1825
1826 static void
1827 remember_password_toggled_cb (GtkToggleButton *button,
1828     EmpathyAccountWidget *self)
1829 {
1830   if (gtk_toggle_button_get_active (button))
1831     {
1832       gtk_widget_set_sensitive (self->priv->param_password_widget, TRUE);
1833     }
1834   else
1835     {
1836       gtk_widget_set_sensitive (self->priv->param_password_widget, FALSE);
1837       gtk_entry_set_text (GTK_ENTRY (self->priv->param_password_widget), "");
1838       empathy_account_settings_unset (self->priv->settings, "password");
1839     }
1840 }
1841
1842 static void
1843 account_settings_password_retrieved_cb (GObject *object,
1844     gpointer user_data)
1845 {
1846   EmpathyAccountWidget *self = user_data;
1847   const gchar *password = empathy_account_settings_get_string (
1848       self->priv->settings, "password");
1849
1850   if (password != NULL)
1851     {
1852       /* We have to do this so that when we call gtk_entry_set_text,
1853        * the ::changed callback doesn't think the user made the
1854        * change. */
1855       self->priv->automatic_change = TRUE;
1856       gtk_entry_set_text (GTK_ENTRY (self->priv->param_password_widget),
1857           password);
1858       self->priv->automatic_change = FALSE;
1859     }
1860
1861   gtk_toggle_button_set_active (
1862       GTK_TOGGLE_BUTTON (self->priv->remember_password_widget),
1863       !EMP_STR_EMPTY (password));
1864 }
1865
1866 static void
1867 do_constructed (GObject *obj)
1868 {
1869   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1870   TpAccount *account;
1871   const gchar *display_name, *default_display_name;
1872   guint i = 0;
1873   struct {
1874     const gchar *cm_name;
1875     const gchar *protocol;
1876     const char *file;
1877     void (*func)(EmpathyAccountWidget *self, const gchar *filename);
1878   } widgets [] = {
1879     { "salut", "local-xmpp", "empathy-account-widget-local-xmpp.ui",
1880         account_widget_build_salut },
1881     WIDGET (gabble, jabber),
1882     WIDGET (butterfly, msn),
1883     WIDGET (haze, icq),
1884     WIDGET (haze, aim),
1885     WIDGET (haze, yahoo),
1886     WIDGET (haze, groupwise),
1887     WIDGET (idle, irc),
1888     WIDGET (sofiasip, sip),
1889   };
1890   const gchar *protocol, *cm_name;
1891
1892   account = empathy_account_settings_get_account (self->priv->settings);
1893
1894   cm_name = empathy_account_settings_get_cm (self->priv->settings);
1895   protocol = empathy_account_settings_get_protocol (self->priv->settings);
1896
1897   for (i = 0 ; i < G_N_ELEMENTS (widgets); i++)
1898     {
1899       if (!tp_strdiff (widgets[i].cm_name, cm_name) &&
1900           !tp_strdiff (widgets[i].protocol, protocol))
1901         {
1902           gchar *filename;
1903
1904           filename = empathy_file_lookup (widgets[i].file,
1905               "libempathy-gtk");
1906           widgets[i].func (self, filename);
1907           g_free (filename);
1908
1909           break;
1910         }
1911     }
1912
1913   if (i == G_N_ELEMENTS (widgets))
1914     {
1915       gchar *filename = empathy_file_lookup (
1916           "empathy-account-widget-generic.ui", "libempathy-gtk");
1917       account_widget_build_generic (self, filename);
1918       g_free (filename);
1919     }
1920
1921   /* handle default focus */
1922   if (self->ui_details->default_focus != NULL)
1923     {
1924       GObject *default_focus_entry;
1925
1926       default_focus_entry = gtk_builder_get_object
1927         (self->ui_details->gui, self->ui_details->default_focus);
1928       g_signal_connect (default_focus_entry, "realize",
1929           G_CALLBACK (gtk_widget_grab_focus),
1930           NULL);
1931     }
1932
1933   /* remember password */
1934   if (self->priv->param_password_widget != NULL
1935       && self->priv->remember_password_widget != NULL
1936       && empathy_account_settings_supports_sasl (self->priv->settings))
1937     {
1938       if (self->priv->simple)
1939         {
1940           gtk_toggle_button_set_active (
1941               GTK_TOGGLE_BUTTON (self->priv->remember_password_widget), TRUE);
1942         }
1943       else
1944         {
1945           gtk_toggle_button_set_active (
1946               GTK_TOGGLE_BUTTON (self->priv->remember_password_widget),
1947               !EMP_STR_EMPTY (empathy_account_settings_get_string (
1948                       self->priv->settings, "password")));
1949
1950           /* The password might not have been retrieved from the
1951            * keyring yet. We should update the remember password
1952            * toggle button and the password entry when/if it is. */
1953           tp_g_signal_connect_object (self->priv->settings,
1954               "password-retrieved",
1955               G_CALLBACK (account_settings_password_retrieved_cb), self, 0);
1956         }
1957
1958       g_signal_connect (self->priv->remember_password_widget, "toggled",
1959           G_CALLBACK (remember_password_toggled_cb), self);
1960
1961       remember_password_toggled_cb (
1962           GTK_TOGGLE_BUTTON (self->priv->remember_password_widget), self);
1963     }
1964   else if (self->priv->remember_password_widget != NULL
1965       && !empathy_account_settings_supports_sasl (self->priv->settings))
1966     {
1967       gtk_widget_set_visible (self->priv->remember_password_widget, FALSE);
1968     }
1969
1970   /* dup and init the account-manager */
1971   self->priv->account_manager = tp_account_manager_dup ();
1972
1973   g_object_ref (self);
1974   tp_proxy_prepare_async (self->priv->account_manager, NULL,
1975       account_manager_ready_cb, self);
1976
1977   /* handle apply and cancel button */
1978   self->priv->hbox_buttons = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
1979
1980   gtk_box_set_homogeneous (GTK_BOX (self->priv->hbox_buttons), TRUE);
1981
1982   self->priv->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
1983
1984   self->priv->apply_button = gtk_button_new ();
1985   set_apply_button (self);
1986
1987   /* We'll change this button to a "Log in" one if we are creating a new
1988    * account and are connected. */
1989   tp_g_signal_connect_object (self->priv->account_manager,
1990       "most-available-presence-changed",
1991       G_CALLBACK (presence_changed_cb), obj, 0);
1992
1993   gtk_box_pack_end (GTK_BOX (self->priv->hbox_buttons),
1994       self->priv->apply_button, TRUE, TRUE, 3);
1995   gtk_box_pack_end (GTK_BOX (self->priv->hbox_buttons),
1996       self->priv->cancel_button, TRUE, TRUE, 3);
1997
1998   gtk_box_pack_end (GTK_BOX (self->ui_details->widget), self->priv->hbox_buttons, FALSE,
1999       FALSE, 3);
2000
2001   g_signal_connect (self->priv->cancel_button, "clicked",
2002       G_CALLBACK (account_widget_cancel_clicked_cb),
2003       self);
2004   g_signal_connect (self->priv->apply_button, "clicked",
2005       G_CALLBACK (account_widget_apply_clicked_cb),
2006       self);
2007   gtk_widget_show_all (self->priv->hbox_buttons);
2008
2009   if (self->priv->creating_account)
2010     /* When creating an account, the user might have nothing to enter.
2011      * That means that no control interaction might occur,
2012      * so we update the control button sensitivity manually.
2013      */
2014     account_widget_handle_control_buttons_sensitivity (self);
2015   else
2016     account_widget_set_control_buttons_sensitivity (self, FALSE);
2017
2018 #ifndef HAVE_MEEGO
2019   add_register_buttons (self, account);
2020 #endif /* HAVE_MEEGO */
2021
2022   /* hook up to widget destruction to unref ourselves */
2023   g_signal_connect (self->ui_details->widget, "destroy",
2024       G_CALLBACK (account_widget_destroy_cb), self);
2025
2026   if (self->ui_details->gui != NULL)
2027     {
2028       empathy_builder_unref_and_keep_widget (self->ui_details->gui,
2029           self->ui_details->widget);
2030       self->ui_details->gui = NULL;
2031     }
2032
2033   display_name = empathy_account_settings_get_display_name (
2034       self->priv->settings);
2035   default_display_name = empathy_account_widget_get_default_display_name (self);
2036
2037   if (tp_strdiff (display_name, default_display_name) &&
2038       !self->priv->creating_account)
2039     {
2040       /* The display name of the account is not the one that we'd assign by
2041        * default; assume that the user changed it manually */
2042       g_object_set (self->priv->settings, "display-name-overridden", TRUE,
2043           NULL);
2044     }
2045 }
2046
2047 static void
2048 do_dispose (GObject *obj)
2049 {
2050   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
2051
2052   g_clear_object (&self->priv->settings);
2053   g_clear_object (&self->priv->account_manager);
2054
2055   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose != NULL)
2056     G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose (obj);
2057 }
2058
2059 static void
2060 do_finalize (GObject *obj)
2061 {
2062   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
2063
2064   g_free (self->ui_details->default_focus);
2065   g_slice_free (EmpathyAccountWidgetUIDetails, self->ui_details);
2066
2067   g_free (self->priv->jid_suffix);
2068
2069   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize != NULL)
2070     G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize (obj);
2071 }
2072
2073 static void
2074 empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
2075 {
2076   GObjectClass *oclass = G_OBJECT_CLASS (klass);
2077   GParamSpec *param_spec;
2078
2079   oclass->get_property = do_get_property;
2080   oclass->set_property = do_set_property;
2081   oclass->constructed = do_constructed;
2082   oclass->dispose = do_dispose;
2083   oclass->finalize = do_finalize;
2084
2085   param_spec = g_param_spec_string ("protocol",
2086       "protocol", "The protocol of the account",
2087       NULL,
2088       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
2089   g_object_class_install_property (oclass, PROP_PROTOCOL, param_spec);
2090
2091   param_spec = g_param_spec_object ("settings",
2092       "settings", "The settings of the account",
2093       EMPATHY_TYPE_ACCOUNT_SETTINGS,
2094       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
2095   g_object_class_install_property (oclass, PROP_SETTINGS, param_spec);
2096
2097   param_spec = g_param_spec_boolean ("simple",
2098       "simple", "Whether the account widget is a simple or an advanced one",
2099       FALSE,
2100       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
2101   g_object_class_install_property (oclass, PROP_SIMPLE, param_spec);
2102
2103   param_spec = g_param_spec_boolean ("creating-account",
2104       "creating-account",
2105       "TRUE if we're creating an account, FALSE if we're modifying it",
2106       FALSE,
2107       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
2108   g_object_class_install_property (oclass, PROP_CREATING_ACCOUNT, param_spec);
2109
2110   param_spec = g_param_spec_boolean ("other-accounts-exist",
2111       "other-accounts-exist",
2112       "TRUE if there are any other accounts (even if this isn't yet saved)",
2113       FALSE,
2114       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
2115   g_object_class_install_property (oclass, PROP_OTHER_ACCOUNTS_EXIST,
2116                   param_spec);
2117
2118   signals[HANDLE_APPLY] =
2119     g_signal_new ("handle-apply", G_TYPE_FROM_CLASS (klass),
2120         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
2121         g_cclosure_marshal_generic,
2122         G_TYPE_NONE,
2123         1, G_TYPE_BOOLEAN);
2124
2125   /* This signal is emitted when an account has been created and enabled. */
2126   signals[ACCOUNT_CREATED] =
2127       g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass),
2128           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
2129           g_cclosure_marshal_generic,
2130           G_TYPE_NONE,
2131           1, G_TYPE_OBJECT);
2132
2133   signals[CANCELLED] =
2134       g_signal_new ("cancelled", G_TYPE_FROM_CLASS (klass),
2135           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
2136           g_cclosure_marshal_generic,
2137           G_TYPE_NONE,
2138           0);
2139
2140   signals[CLOSE] =
2141     g_signal_new ("close", G_TYPE_FROM_CLASS (klass),
2142         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
2143         g_cclosure_marshal_VOID__INT,
2144         G_TYPE_NONE,
2145         1, G_TYPE_INT);
2146
2147   g_type_class_add_private (klass, sizeof (EmpathyAccountWidgetPriv));
2148 }
2149
2150 static void
2151 empathy_account_widget_init (EmpathyAccountWidget *self)
2152 {
2153   self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_ACCOUNT_WIDGET,
2154         EmpathyAccountWidgetPriv);
2155
2156   self->ui_details = g_slice_new0 (EmpathyAccountWidgetUIDetails);
2157 }
2158
2159 /* public methods */
2160
2161 void
2162 empathy_account_widget_discard_pending_changes (EmpathyAccountWidget *self)
2163 {
2164   empathy_account_settings_discard_changes (self->priv->settings);
2165   self->priv->contains_pending_changes = FALSE;
2166 }
2167
2168 gboolean
2169 empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *self)
2170 {
2171   return self->priv->contains_pending_changes;
2172 }
2173
2174 void
2175 empathy_account_widget_handle_params (EmpathyAccountWidget *self,
2176     const gchar *first_widget,
2177     ...)
2178 {
2179   va_list args;
2180
2181   va_start (args, first_widget);
2182   account_widget_handle_params_valist (self, first_widget, args);
2183   va_end (args);
2184 }
2185
2186 GtkWidget *
2187 empathy_account_widget_get_widget (EmpathyAccountWidget *widget)
2188 {
2189   return widget->ui_details->widget;
2190 }
2191
2192 EmpathyAccountWidget *
2193 empathy_account_widget_new_for_protocol (EmpathyAccountSettings *settings,
2194     gboolean simple)
2195 {
2196   EmpathyAccountWidget *self;
2197
2198   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), NULL);
2199
2200   self = g_object_new
2201     (EMPATHY_TYPE_ACCOUNT_WIDGET,
2202         "settings", settings, "simple", simple,
2203         "creating-account",
2204         empathy_account_settings_get_account (settings) == NULL,
2205         NULL);
2206
2207   return self;
2208 }
2209
2210 gchar *
2211 empathy_account_widget_get_default_display_name (EmpathyAccountWidget *self)
2212 {
2213   const gchar *login_id;
2214   const gchar *protocol, *p;
2215   gchar *default_display_name;
2216   Service service;
2217
2218   login_id = empathy_account_settings_get_string (self->priv->settings,
2219       "account");
2220   protocol = empathy_account_settings_get_protocol (self->priv->settings);
2221   service = account_widget_get_service (self);
2222
2223   if (login_id != NULL)
2224     {
2225       /* TODO: this should be done in empathy-account-widget-irc */
2226       if (!tp_strdiff (protocol, "irc"))
2227         {
2228           EmpathyIrcNetwork *network;
2229
2230           network = empathy_irc_network_chooser_get_network (
2231               self->priv->irc_network_chooser);
2232           g_assert (network != NULL);
2233
2234           /* To translators: The first parameter is the login id and the
2235            * second one is the network. The resulting string will be something
2236            * like: "MyUserName on freenode".
2237            * You should reverse the order of these arguments if the
2238            * server should come before the login id in your locale.*/
2239           default_display_name = g_strdup_printf (_("%1$s on %2$s"),
2240               login_id, empathy_irc_network_get_name (network));
2241         }
2242       else if (service == FACEBOOK_SERVICE && self->priv->jid_suffix != NULL)
2243         {
2244           gchar *tmp;
2245
2246           tmp = remove_jid_suffix (self, login_id);
2247           default_display_name = g_strdup_printf ("Facebook (%s)", tmp);
2248           g_free (tmp);
2249         }
2250       else
2251         {
2252           default_display_name = g_strdup (login_id);
2253         }
2254
2255       return default_display_name;
2256     }
2257
2258   if ((p = empathy_protocol_name_to_display_name (protocol)) != NULL)
2259     protocol = p;
2260
2261   if (protocol != NULL)
2262     {
2263       /* To translators: The parameter is the protocol name. The resulting
2264        * string will be something like: "Jabber Account" */
2265       default_display_name = g_strdup_printf (_("%s Account"), protocol);
2266     }
2267   else
2268     {
2269       default_display_name = g_strdup (_("New account"));
2270     }
2271
2272   return default_display_name;
2273 }
2274
2275 /* Used by subclass to indicate that widget contains pending changes */
2276 void
2277 empathy_account_widget_changed (EmpathyAccountWidget *self)
2278 {
2279   account_widget_handle_control_buttons_sensitivity (self);
2280   self->priv->contains_pending_changes = TRUE;
2281 }
2282
2283 void
2284 empathy_account_widget_set_account_param (EmpathyAccountWidget *self,
2285     const gchar *account)
2286 {
2287   if (self->priv->param_account_widget == NULL)
2288     return;
2289
2290   gtk_entry_set_text (GTK_ENTRY (self->priv->param_account_widget), account);
2291 }
2292
2293 void
2294 empathy_account_widget_set_password_param (EmpathyAccountWidget *self,
2295     const gchar *account)
2296 {
2297   if (self->priv->param_password_widget == NULL)
2298     return;
2299
2300   gtk_entry_set_text (GTK_ENTRY (self->priv->param_password_widget), account);
2301 }
2302
2303 EmpathyAccountSettings *
2304 empathy_account_widget_get_settings (EmpathyAccountWidget *self)
2305 {
2306   return self->priv->settings;
2307 }
2308
2309 void
2310 empathy_account_widget_hide_buttons (EmpathyAccountWidget *self)
2311 {
2312   gtk_widget_hide (self->priv->hbox_buttons);
2313 }