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