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