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