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