2007-04-06 Murray Cumming <murrayc@murrayc.com>
[modest] / src / maemo / modest-account-settings-dialog.c
1 /* Copyright (c) 2007, Nokia Corporation
2  * All rights reserved.
3  *
4  */
5
6
7 #include "modest-account-settings-dialog.h"
8 #include <glib/gi18n.h>
9 #include <gtk/gtknotebook.h>
10 #include <gtk/gtkvbox.h>
11 #include <gtk/gtklabel.h>
12 #include <gtk/gtkcombobox.h>
13 #include <gtk/gtkentry.h>
14 #include <gtk/gtkbutton.h>
15 #include <gtk/gtkcheckbutton.h>
16 #include <gtk/gtkmessagedialog.h>
17 #include <gtk/gtkstock.h>
18 #include <hildon-widgets/hildon-caption.h>
19 #include "maemo/easysetup/modest-easysetup-country-combo-box.h"
20 #include "maemo/easysetup/modest-easysetup-provider-combo-box.h"
21 #include "maemo/easysetup/modest-easysetup-servertype-combo-box.h"
22 #include "maemo/easysetup/modest-easysetup-serversecurity-combo-box.h"
23 #include "maemo/easysetup/modest-easysetup-secureauth-combo-box.h"
24 #include "maemo/easysetup/modest-validating-entry.h"
25 #include "modest-text-utils.h"
26 #include "modest-account-mgr.h"
27 #include "modest-account-mgr-helpers.h" /* For modest_account_mgr_get_account_data(). */
28 #include "modest-runtime.h" /* For modest_runtime_get_account_mgr(). */
29 #include "maemo/modest-connection-specific-smtp-window.h"
30 #include <gconf/gconf-client.h>
31 #include <string.h> /* For strlen(). */
32
33 /* Include config.h so that _() works: */
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #define EXAMPLE_EMAIL_ADDRESS "first.last@provider.com"
39
40 G_DEFINE_TYPE (ModestAccountSettingsDialog, modest_account_settings_dialog, GTK_TYPE_DIALOG);
41
42 #define ACCOUNT_SETTINGS_DIALOG_GET_PRIVATE(o) \
43         (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_ACCOUNT_SETTINGS_DIALOG, ModestAccountSettingsDialogPrivate))
44
45 typedef struct _ModestAccountSettingsDialogPrivate ModestAccountSettingsDialogPrivate;
46
47 struct _ModestAccountSettingsDialogPrivate
48 {
49 };
50
51 static void
52 enable_buttons (ModestAccountSettingsDialog *self);
53
54 static void
55 modest_account_settings_dialog_get_property (GObject *object, guint property_id,
56                                                                                                                         GValue *value, GParamSpec *pspec)
57 {
58         switch (property_id) {
59         default:
60                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
61         }
62 }
63
64 static void
65 modest_account_settings_dialog_set_property (GObject *object, guint property_id,
66                                                                                                                         const GValue *value, GParamSpec *pspec)
67 {
68         switch (property_id) {
69         default:
70                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
71         }
72 }
73
74 static void
75 modest_account_settings_dialog_dispose (GObject *object)
76 {
77         if (G_OBJECT_CLASS (modest_account_settings_dialog_parent_class)->dispose)
78                 G_OBJECT_CLASS (modest_account_settings_dialog_parent_class)->dispose (object);
79 }
80
81 static void
82 modest_account_settings_dialog_finalize (GObject *object)
83 {
84         ModestAccountSettingsDialog *self = MODEST_ACCOUNT_SETTINGS_DIALOG (object);
85         
86         if (self->account_manager)
87                 g_object_unref (G_OBJECT (self->account_manager));
88         
89         G_OBJECT_CLASS (modest_account_settings_dialog_parent_class)->finalize (object);
90 }
91
92 #if 0
93 static void
94 show_error (GtkWindow *parent_window, const gchar* text);
95 #endif
96
97
98 static void
99 on_caption_entry_changed (GtkEditable *editable, gpointer user_data)
100 {
101         ModestAccountSettingsDialog *self = MODEST_ACCOUNT_SETTINGS_DIALOG (user_data);
102         g_assert(self);
103         enable_buttons(self);
104 }
105
106 static void
107 on_caption_combobox_changed (GtkComboBox *widget, gpointer user_data)
108 {
109         ModestAccountSettingsDialog *self = MODEST_ACCOUNT_SETTINGS_DIALOG (user_data);
110         g_assert(self);
111         enable_buttons(self);
112 }
113
114 /** This is a convenience function to create a caption containing a mandatory widget.
115  * When the widget is edited, the enable_buttons() vfunc will be called.
116  */
117 static GtkWidget* create_caption_new_with_asterix(ModestAccountSettingsDialog *self,
118         GtkSizeGroup *group,
119         const gchar *value,
120         GtkWidget *control,
121         GtkWidget *icon,
122         HildonCaptionStatus flag)
123 {
124   GtkWidget *caption = hildon_caption_new (group, value, control, icon, flag);
125   
126 /* The translated strings seem to already contain the *,
127  * but this code can be used if that is not true in future.
128  */
129 #if 0
130         /* Add a * character to indicate mandatory fields,
131          * as specified in our "Email UI Specification": */
132         if (flag == HILDON_CAPTION_MANDATORY) {
133                 gchar* title = g_strdup_printf("%s*", value);
134                 caption = hildon_caption_new (group, title, control, icon, flag);       
135                 g_free(title);
136         }       
137         else
138                 caption = hildon_caption_new (group, value, control, icon, flag);
139 #endif
140
141         /* Connect to the appropriate changed signal for the widget, 
142          * so we can ask for the prev/next buttons to be enabled/disabled appropriately:
143          */
144         if (GTK_IS_ENTRY (control)) {
145                 g_signal_connect (G_OBJECT (control), "changed",
146                 G_CALLBACK (on_caption_entry_changed), self);
147                 
148         }
149         else if (GTK_IS_COMBO_BOX (control)) {
150                 g_signal_connect (G_OBJECT (control), "changed",
151                 G_CALLBACK (on_caption_combobox_changed), self);
152         }
153          
154         return caption;
155 }
156
157 static GtkWidget*
158 create_page_account_details (ModestAccountSettingsDialog *self)
159 {
160         GtkWidget *box = gtk_vbox_new (FALSE, 2);
161         GtkWidget *label = gtk_label_new(_("mcen_ia_accountdetails"));
162         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 2);
163         gtk_widget_show (label);
164         
165         /* Create a size group to be used by all captions.
166          * Note that HildonCaption does not create a default size group if we do not specify one.
167          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
168         GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
169            
170         /* The description widgets: */  
171         self->entry_account_title = GTK_WIDGET (easysetup_validating_entry_new ());
172         GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, _("mcen_fi_account_title"), 
173                 self->entry_account_title, NULL, HILDON_CAPTION_MANDATORY);
174         gtk_widget_show (self->entry_account_title);
175         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
176         gtk_widget_show (caption);
177         
178         /* Prevent the use of some characters in the account title, 
179          * as required by our UI specification: */
180         GList *list_prevent = NULL;
181         list_prevent = g_list_append (list_prevent, "\\");
182         list_prevent = g_list_append (list_prevent, "/");
183         list_prevent = g_list_append (list_prevent, ":");
184         list_prevent = g_list_append (list_prevent, "*");
185         list_prevent = g_list_append (list_prevent, "?");
186         list_prevent = g_list_append (list_prevent, "\""); /* The UI spec mentions “, but maybe means ", maybe both. */
187         list_prevent = g_list_append (list_prevent, "“");
188         list_prevent = g_list_append (list_prevent, "<"); 
189         list_prevent = g_list_append (list_prevent, ">"); 
190         list_prevent = g_list_append (list_prevent, "|");
191         list_prevent = g_list_append (list_prevent, "^");       
192         easysetup_validating_entry_set_unallowed_characters (
193                 EASYSETUP_VALIDATING_ENTRY (self->entry_account_title), list_prevent);
194         g_list_free (list_prevent);
195         
196         /* Set max length as in the UI spec:
197          * TODO: The UI spec seems to want us to show a dialog if we hit the maximum. */
198         gtk_entry_set_max_length (GTK_ENTRY (self->entry_account_title), 64);
199         
200         /* TODO: The Retrieve and Limit Retrieve combo boxes. */
201         
202         /* The leave-messages widgets: */
203         if(!self->checkbox_leave_messages)
204                 self->checkbox_leave_messages = 
205                         gtk_check_button_new_with_label (_("mcen_fi_advsetup_leave_on_server"));
206         gtk_box_pack_start (GTK_BOX (box), self->checkbox_leave_messages, FALSE, FALSE, 2);
207         gtk_widget_show (self->checkbox_leave_messages);
208         
209         
210         gtk_widget_show (GTK_WIDGET (box));
211         
212         return GTK_WIDGET (box);
213 }
214
215 static void
216 on_button_signature (GtkButton *button, gpointer user_data)
217 {
218         
219 }
220
221 static GtkWidget*
222 create_page_user_details (ModestAccountSettingsDialog *self)
223 {
224         GtkWidget *box = gtk_vbox_new (FALSE, 2);
225         
226         /* Create a size group to be used by all captions.
227          * Note that HildonCaption does not create a default size group if we do not specify one.
228          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
229         GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
230          
231         /* The name widgets: */
232         self->entry_user_name = GTK_WIDGET (easysetup_validating_entry_new ());
233         /* Set max length as in the UI spec:
234          * TODO: The UI spec seems to want us to show a dialog if we hit the maximum. */
235         gtk_entry_set_max_length (GTK_ENTRY (self->entry_user_name), 64);
236         GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, 
237                 _("mcen_li_emailsetup_name"), self->entry_user_name, NULL, HILDON_CAPTION_OPTIONAL);
238         gtk_widget_show (self->entry_user_name);
239         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
240         gtk_widget_show (caption);
241         
242         /* Prevent the use of some characters in the name, 
243          * as required by our UI specification: */
244         GList *list_prevent = NULL;
245         list_prevent = g_list_append (list_prevent, "<");
246         list_prevent = g_list_append (list_prevent, ">");
247         easysetup_validating_entry_set_unallowed_characters (
248                 EASYSETUP_VALIDATING_ENTRY (self->entry_user_name), list_prevent);
249         g_list_free (list_prevent);
250         
251         /* The username widgets: */     
252         self->entry_user_username = GTK_WIDGET (easysetup_validating_entry_new ());
253         caption = create_caption_new_with_asterix (self, sizegroup, _("mail_fi_username"), 
254                 self->entry_user_username, NULL, HILDON_CAPTION_MANDATORY);
255         gtk_widget_show (self->entry_user_username);
256         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
257         gtk_widget_show (caption);
258         
259         /* Prevent the use of some characters in the username, 
260          * as required by our UI specification: */
261         easysetup_validating_entry_set_unallowed_characters_whitespace (
262                 EASYSETUP_VALIDATING_ENTRY (self->entry_user_username));
263         
264         /* Set max length as in the UI spec:
265          * TODO: The UI spec seems to want us to show a dialog if we hit the maximum. */
266         gtk_entry_set_max_length (GTK_ENTRY (self->entry_user_username), 64);
267         
268         /* The password widgets: */     
269         self->entry_user_password = gtk_entry_new ();
270         gtk_entry_set_visibility (GTK_ENTRY (self->entry_user_password), FALSE);
271         /* gtk_entry_set_invisible_char (GTK_ENTRY (self->entry_user_password), '*'); */
272         caption = create_caption_new_with_asterix (self, sizegroup, 
273                 _("mail_fi_password"), self->entry_user_password, NULL, HILDON_CAPTION_OPTIONAL);
274         gtk_widget_show (self->entry_user_password);
275         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
276         gtk_widget_show (caption);
277         
278         /* The email address widgets: */        
279         self->entry_user_email = GTK_WIDGET (easysetup_validating_entry_new ());
280         caption = create_caption_new_with_asterix (self, sizegroup, 
281                 _("mcen_li_emailsetup_email_address"), self->entry_user_email, NULL, HILDON_CAPTION_MANDATORY);
282         gtk_entry_set_text (GTK_ENTRY (self->entry_user_email), EXAMPLE_EMAIL_ADDRESS); /* Default text. */
283         gtk_widget_show (self->entry_user_email);
284         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
285         gtk_widget_show (caption);
286         
287         /* Set max length as in the UI spec:
288          * TODO: The UI spec seems to want us to show a dialog if we hit the maximum. */
289         gtk_entry_set_max_length (GTK_ENTRY (self->entry_user_email), 64);
290         
291         
292         /* Signature button: */
293         if (!self->button_signature)
294                 self->button_signature = gtk_button_new_with_label (_("mcen_bd_emailsetup_edit"));
295         caption = hildon_caption_new (sizegroup, _("mcen_fi_email_signature"), 
296                 self->button_signature, NULL, HILDON_CAPTION_OPTIONAL);
297         gtk_widget_show (self->button_signature);
298         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
299         gtk_widget_show (caption);
300                 
301         g_signal_connect (G_OBJECT (self->button_signature), "clicked",
302                 G_CALLBACK (on_button_signature), self);
303                 
304         gtk_widget_show (GTK_WIDGET (box));
305         
306         return GTK_WIDGET (box);
307 }
308
309 /** Change the caption title for the incoming server, 
310  * as specified in the UI spec:
311  */
312 static void update_incoming_server_title (ModestAccountSettingsDialog *self, ModestProtocol protocol)
313 {
314         const gchar* type = 
315                 (protocol == MODEST_PROTOCOL_STORE_POP ? 
316                         _("mail_fi_emailtype_pop3") : 
317                         _("mail_fi_emailtype_imap") );
318                         
319                 
320         /* Note that this produces a compiler warning, 
321          * because the compiler does not know that the translated string will have a %s in it.
322          * I do not see a way to avoid the warning while still using these Logical IDs. murrayc. */
323         gchar* incomingserver_title = g_strdup_printf(_("mcen_li_emailsetup_servertype"), type);
324         g_object_set (G_OBJECT (self->caption_incoming), "label", incomingserver_title, NULL);
325         g_free(incomingserver_title);
326 }
327
328 /** Change the caption title for the incoming server, 
329  * as specified in the UI spec:
330  */
331 static void update_incoming_server_security_choices (ModestAccountSettingsDialog *self, ModestProtocol protocol)
332 {
333         /* Fill the combo with appropriately titled choices for POP or IMAP. */
334         /* The choices are the same, but the titles are different, as in the UI spec. */
335         easysetup_serversecurity_combo_box_fill (
336                 EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_incoming_security), protocol);
337 }
338            
339 static GtkWidget* create_page_incoming (ModestAccountSettingsDialog *self)
340 {
341         GtkWidget *box = gtk_vbox_new (FALSE, 2);
342         
343         /* Create a size group to be used by all captions.
344          * Note that HildonCaption does not create a default size group if we do not specify one.
345          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
346         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
347          
348         /* The incoming server widgets: */
349         if(!self->entry_incomingserver)
350                 self->entry_incomingserver = gtk_entry_new ();
351
352         if (self->caption_incoming)
353           gtk_widget_destroy (self->caption_incoming);
354            
355         /* The caption title will be updated in update_incoming_server_title().
356          * so this default text will never be seen: */
357         /* (Note: Changing the title seems pointless. murrayc) */
358         self->caption_incoming = create_caption_new_with_asterix (self, sizegroup, 
359                 "Incoming Server", self->entry_incomingserver, NULL, HILDON_CAPTION_MANDATORY);
360         gtk_widget_show (self->entry_incomingserver);
361         gtk_box_pack_start (GTK_BOX (box), self->caption_incoming, FALSE, FALSE, 2);
362         gtk_widget_show (self->caption_incoming);
363         
364         /* The secure connection widgets: */
365         /* This will be filled by update_incoming_server_security_choices(). */
366         if (!self->combo_incoming_security)
367                 self->combo_incoming_security = GTK_WIDGET (easysetup_serversecurity_combo_box_new ());
368         easysetup_serversecurity_combo_box_set_active_serversecurity (
369                 EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_incoming_security), MODEST_PROTOCOL_SECURITY_NONE);
370         GtkWidget *caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_connection"), 
371                 self->combo_incoming_security, NULL, HILDON_CAPTION_OPTIONAL);
372         gtk_widget_show (self->combo_incoming_security);
373         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
374         gtk_widget_show (caption);
375         
376         /* The port widgets: */
377         if (!self->entry_incoming_port)
378                 self->entry_incoming_port = GTK_WIDGET (gtk_entry_new ());
379         caption = hildon_caption_new (sizegroup, _("mcen_fi_emailsetup_port"), 
380                 self->entry_incoming_port, NULL, HILDON_CAPTION_OPTIONAL);
381         gtk_widget_show (self->entry_incoming_port);
382         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
383         gtk_widget_show (caption);
384         
385         /* The secure authentication widgets: */
386         if(!self->checkbox_incoming_auth)
387                 self->checkbox_incoming_auth = 
388                         gtk_check_button_new_with_label (_("mcen_li_emailsetup_secure_authentication"));
389         gtk_box_pack_start (GTK_BOX (box), self->checkbox_incoming_auth, FALSE, FALSE, 2);
390         gtk_widget_show (self->checkbox_incoming_auth);
391         
392         gtk_widget_show (GTK_WIDGET (box));
393         
394         return GTK_WIDGET (box);
395 }
396
397 static void
398 on_toggle_button_changed (GtkToggleButton *togglebutton, gpointer user_data)
399 {
400         GtkWidget *widget = GTK_WIDGET (user_data);
401         
402         /* Enable the widget only if the toggle button is active: */
403         const gboolean enable = gtk_toggle_button_get_active (togglebutton);
404         gtk_widget_set_sensitive (widget, enable);
405 }
406
407 /* Make the sensitivity of a widget depend on a toggle button.
408  */
409 static void
410 enable_widget_for_togglebutton (GtkWidget *widget, GtkToggleButton* button)
411 {
412         g_signal_connect (G_OBJECT (button), "toggled",
413                 G_CALLBACK (on_toggle_button_changed), widget);
414         
415         /* Set the starting sensitivity: */
416         on_toggle_button_changed (button, widget);
417 }
418         
419 static void
420 on_smtp_servers_window_hide (GtkWindow *window, gpointer user_data)
421 {
422         /* Destroy the window when it is closed: */
423         gtk_widget_destroy (GTK_WIDGET (window));
424 }
425
426 static void
427 on_button_outgoing_smtp_servers (GtkButton *button, gpointer user_data)
428 {
429
430         ModestAccountSettingsDialog * self = MODEST_ACCOUNT_SETTINGS_DIALOG (user_data);
431         
432         /* Show the window: */
433         /* TODO: Retrieve the chosen settings,
434          * so we can supply them when creating the connection somehow.
435          */
436         GtkWidget *window = GTK_WIDGET (modest_connection_specific_smtp_window_new ());
437         gtk_window_set_transient_for (GTK_WINDOW (self), GTK_WINDOW (window));
438         g_signal_connect (G_OBJECT (window), "hide",
439                 G_CALLBACK (on_smtp_servers_window_hide), self);
440     gtk_widget_show (window);
441 }
442
443 static void
444 on_combo_outgoing_auth_changed (GtkComboBox *widget, gpointer user_data)
445 {
446         ModestAccountSettingsDialog *self = MODEST_ACCOUNT_SETTINGS_DIALOG (user_data);
447         
448         ModestProtocol protocol_security = 
449                 easysetup_secureauth_combo_box_get_active_secureauth (
450                         EASYSETUP_SECUREAUTH_COMBO_BOX (self->combo_outgoing_auth));
451         const gboolean secureauth_used = protocol_security != MODEST_PROTOCOL_AUTH_NONE;
452         
453         gtk_widget_set_sensitive (self->caption_outgoing_username, secureauth_used);
454         gtk_widget_set_sensitive (self->caption_outgoing_password, secureauth_used);
455 }
456
457 static GtkWidget* create_page_outgoing (ModestAccountSettingsDialog *self)
458 {
459         GtkWidget *box = gtk_vbox_new (FALSE, 2);
460         
461         /* Create a size group to be used by all captions.
462          * Note that HildonCaption does not create a default size group if we do not specify one.
463          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
464         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
465          
466         /* The outgoing server widgets: */
467         if (!self->entry_outgoingserver)
468                 self->entry_outgoingserver = gtk_entry_new ();
469         GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, 
470                 _("mcen_li_emailsetup_smtp"), self->entry_outgoingserver, NULL, HILDON_CAPTION_OPTIONAL);
471         gtk_widget_show (self->entry_outgoingserver);
472         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
473         gtk_widget_show (caption);
474         
475         /* The secure authentication widgets: */
476         if (!self->combo_outgoing_auth)
477                 self->combo_outgoing_auth = GTK_WIDGET (easysetup_secureauth_combo_box_new ());
478         caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_authentication"), 
479                 self->combo_outgoing_auth, NULL, HILDON_CAPTION_OPTIONAL);
480         gtk_widget_show (self->combo_outgoing_auth);
481         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
482         gtk_widget_show (caption);
483         
484         /* Dim the outgoing username and password when no secure authentication is used, as per the UI spec: */
485         g_signal_connect (G_OBJECT (self->combo_outgoing_auth), "changed", (GCallback)on_combo_outgoing_auth_changed, self);
486         
487         /* The username widgets: */     
488         self->entry_outgoing_username = GTK_WIDGET (easysetup_validating_entry_new ());
489         self->caption_outgoing_username = create_caption_new_with_asterix (self, sizegroup, _("mail_fi_username"), 
490                 self->entry_outgoing_username, NULL, HILDON_CAPTION_MANDATORY);
491         gtk_widget_show (self->entry_outgoing_username);
492         gtk_box_pack_start (GTK_BOX (box), self->caption_outgoing_username, FALSE, FALSE, 2);
493         gtk_widget_show (self->caption_outgoing_username);
494         
495         /* Prevent the use of some characters in the username, 
496          * as required by our UI specification: */
497         easysetup_validating_entry_set_unallowed_characters_whitespace (
498                 EASYSETUP_VALIDATING_ENTRY (self->entry_outgoing_username));
499         
500         /* Set max length as in the UI spec:
501          * TODO: The UI spec seems to want us to show a dialog if we hit the maximum. */
502         gtk_entry_set_max_length (GTK_ENTRY (self->entry_outgoing_username), 64);
503         
504         /* The password widgets: */     
505         self->entry_outgoing_password = gtk_entry_new ();
506         gtk_entry_set_visibility (GTK_ENTRY (self->entry_outgoing_password), FALSE);
507         /* gtk_entry_set_invisible_char (GTK_ENTRY (self->entry_outgoing_password), '*'); */
508         self->caption_outgoing_password = create_caption_new_with_asterix (self, sizegroup, 
509                 _("mail_fi_password"), self->entry_outgoing_password, NULL, HILDON_CAPTION_OPTIONAL);
510         gtk_widget_show (self->entry_outgoing_password);
511         gtk_box_pack_start (GTK_BOX (box), self->caption_outgoing_password, FALSE, FALSE, 2);
512         gtk_widget_show (self->caption_outgoing_password);
513         
514         /* The secure connection widgets: */
515         /* This will be filled and set with easysetup_serversecurity_combo_box_fill() 
516          * and easysetup_serversecurity_combo_box_set_active_serversecurity().
517          */
518         if (!self->combo_outgoing_security)
519                 self->combo_outgoing_security = GTK_WIDGET (easysetup_serversecurity_combo_box_new ());
520         caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_connection"), 
521                 self->combo_outgoing_security, NULL, HILDON_CAPTION_OPTIONAL);
522         gtk_widget_show (self->combo_outgoing_security);
523         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
524         gtk_widget_show (caption);      
525         
526         /* The port widgets: */
527         if (!self->entry_outgoing_port)
528                 self->entry_outgoing_port = GTK_WIDGET (gtk_entry_new ());
529         caption = hildon_caption_new (sizegroup, _("mcen_fi_emailsetup_port"), 
530                 self->entry_outgoing_port, NULL, HILDON_CAPTION_OPTIONAL);
531         gtk_widget_show (self->entry_outgoing_port);
532         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
533         gtk_widget_show (caption);
534         
535         /* connection-specific checkbox: */
536         if (!self->checkbox_outgoing_smtp_specific) {
537                 self->checkbox_outgoing_smtp_specific = gtk_check_button_new_with_label (_("mcen_fi_advsetup_connection_smtp"));
538                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->checkbox_outgoing_smtp_specific), 
539                         FALSE);
540         }
541         gtk_box_pack_start (GTK_BOX (box), self->checkbox_outgoing_smtp_specific, FALSE, FALSE, 2);
542         gtk_widget_show (self->checkbox_outgoing_smtp_specific);
543         
544         /* Connection-specific SMTP-Severs Edit button: */
545         if (!self->button_outgoing_smtp_servers)
546                 self->button_outgoing_smtp_servers = gtk_button_new_with_label (_("mcen_bd_emailsetup_edit"));
547         caption = hildon_caption_new (sizegroup, _("mcen_fi_advsetup_optional_smtp"), 
548                 self->button_outgoing_smtp_servers, NULL, HILDON_CAPTION_OPTIONAL);
549         gtk_widget_show (self->button_outgoing_smtp_servers);
550         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
551         gtk_widget_show (caption);
552         
553         /* Only enable the button when the checkbox is checked: */
554         enable_widget_for_togglebutton (self->button_outgoing_smtp_servers, 
555                 GTK_TOGGLE_BUTTON (self->checkbox_outgoing_smtp_specific));
556                 
557         g_signal_connect (G_OBJECT (self->button_outgoing_smtp_servers), "clicked",
558                 G_CALLBACK (on_button_outgoing_smtp_servers), self);
559         
560         
561         gtk_widget_show (GTK_WIDGET (box));
562         
563         return GTK_WIDGET (box);
564 }
565
566 /*
567  */
568 static void 
569 on_response (GtkDialog *wizard_dialog,
570         gint response_id,
571         gpointer user_data)
572 {
573         ModestAccountSettingsDialog *self = MODEST_ACCOUNT_SETTINGS_DIALOG (wizard_dialog);
574         enable_buttons (self);
575 }
576
577 static void
578 modest_account_settings_dialog_init (ModestAccountSettingsDialog *self)
579 {
580         /* Create the notebook to be used by the GtkDialog base class:
581          * Each page of the notebook will be a page of the wizard: */
582         GtkNotebook *notebook = GTK_NOTEBOOK (gtk_notebook_new());
583
584     
585     gtk_window_set_title (GTK_WINDOW (self), _("mcen_ti_emailsetup"));
586         
587         /* Get the account manager object, 
588          * so we can check for existing accounts,
589          * and create new accounts: */
590         self->account_manager = modest_runtime_get_account_mgr ();
591         g_assert (self->account_manager);
592         g_object_ref (self->account_manager);
593         
594     /* Create the common pages, 
595      */
596         self->page_account_details = create_page_account_details (self);
597         self->page_user_details = create_page_user_details (self);
598         self->page_incoming = create_page_incoming (self);
599         self->page_outgoing = create_page_outgoing (self);
600         
601         /* Add the notebook pages: */
602         gtk_notebook_append_page (notebook, self->page_account_details, 
603                 gtk_label_new (_("mcen_ti_account_settings_account")));
604         gtk_notebook_append_page (notebook, self->page_user_details, 
605                 gtk_label_new (_("mcen_ti_account_settings_userinfo")));
606         gtk_notebook_append_page (notebook, self->page_incoming,
607                 gtk_label_new (_("mcen_ti_advsetup_retrieval")));
608         gtk_notebook_append_page (notebook, self->page_outgoing,
609                 gtk_label_new (_("mcen_ti_advsetup_sending")));
610                 
611         GtkDialog *dialog = GTK_DIALOG (self);
612         gtk_container_add (GTK_CONTAINER (dialog->vbox), GTK_WIDGET (notebook));
613         gtk_widget_show (GTK_WIDGET (notebook));
614         
615     /* Add the buttons: */
616     gtk_dialog_add_button (GTK_DIALOG(self), GTK_STOCK_OK, GTK_RESPONSE_OK);
617     gtk_dialog_add_button (GTK_DIALOG(self), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
618     
619     /* Connect to the dialog's response signal: */
620     g_signal_connect_after (G_OBJECT (self), "response",
621             G_CALLBACK (on_response), self);       
622 }
623
624 ModestAccountSettingsDialog*
625 modest_account_settings_dialog_new (void)
626 {
627         return g_object_new (MODEST_TYPE_ACCOUNT_SETTINGS_DIALOG, NULL);
628 }
629
630 /** Update the UI with the stored account details, so they can be edited.
631  * @account_name: Name of the account, which should contain incoming and outgoing server accounts.
632  */
633 void modest_account_settings_dialog_set_account_name (ModestAccountSettingsDialog *dialog, const gchar* account_name)
634 {
635         ModestAccountData *account_data = modest_account_mgr_get_account_data (dialog->account_manager, 
636                 account_name);
637         if (!account_data) {
638                 g_printerr ("modest: failed to get account data for %s\n", account_name);
639                 return;
640         }
641
642         if (!(account_data->store_account)) {
643                 g_printerr ("modest: account has no stores: %s\n", account_name);
644                 return;
645         }
646                 
647         gtk_entry_set_text( GTK_ENTRY (dialog->entry_account_title),
648                 account_name ? account_name : "");
649         gtk_entry_set_text( GTK_ENTRY (dialog->entry_user_name), 
650                 account_data->fullname ? account_data->fullname : ""); /* TODO: Not working. */
651         gtk_entry_set_text( GTK_ENTRY (dialog->entry_user_email),  /* TODO: Not working. */
652                 account_data->email ? account_data->email : "");
653                 
654         ModestServerAccountData *incoming_account = account_data->store_account;
655         if (incoming_account) {
656                 gtk_entry_set_text( GTK_ENTRY (dialog->entry_user_username),
657                         incoming_account->username ? incoming_account->username : "");
658                 gtk_entry_set_text( GTK_ENTRY (dialog->entry_user_password), 
659                         incoming_account->password ? incoming_account->password : "");
660                         
661                 gtk_entry_set_text( GTK_ENTRY (dialog->entry_incomingserver), 
662                         incoming_account->hostname ? incoming_account->hostname : "");
663                         
664                 update_incoming_server_title (dialog, incoming_account->proto);
665                 update_incoming_server_security_choices (dialog, incoming_account->proto);
666                 
667                 /* TODO:
668         gchar            *uri;
669         ModestProtocol    proto;
670         gchar            *password;
671         time_t            last_updated;
672         GSList           *options;
673         */
674         
675         }
676         
677         ModestServerAccountData *outgoing_account = account_data->transport_account;
678         if (outgoing_account) {
679                 gtk_entry_set_text( GTK_ENTRY (dialog->entry_outgoingserver), 
680                         outgoing_account->hostname ? outgoing_account->hostname : "");
681                 
682                 /* TODO: Dim these if secure authentication is None, as per the UI spec: */
683                 gtk_entry_set_text( GTK_ENTRY (dialog->entry_outgoing_username), 
684                         outgoing_account->username ? outgoing_account->username : "");
685                 gtk_entry_set_text( GTK_ENTRY (dialog->entry_outgoing_password), 
686                         outgoing_account->password ? outgoing_account->password : "");
687                 
688                 /* How do we get the auth setting from the server account struct?: */
689                 easysetup_secureauth_combo_box_set_active_secureauth (
690                         EASYSETUP_SECUREAUTH_COMBO_BOX (dialog->combo_outgoing_auth), MODEST_PROTOCOL_AUTH_NONE);
691                 on_combo_outgoing_auth_changed (GTK_COMBO_BOX (dialog->combo_outgoing_auth), dialog);
692                 
693                 easysetup_serversecurity_combo_box_fill (
694                 EASYSETUP_SERVERSECURITY_COMBO_BOX (dialog->combo_outgoing_security), outgoing_account->proto);
695                 
696                 
697                 
698                 /* TODO: set port. */
699         }
700         
701         /* TODO: account_data->display_name */
702         /* account_data->is_enabled,  */
703         /*account_data->is_default,  */
704
705         /* account_data->store_account->proto */
706
707         modest_account_mgr_free_account_data (dialog->account_manager, account_data);
708 }
709         
710 #if 0
711 static gboolean
712 on_before_next (GtkDialog *dialog, GtkWidget *current_page, GtkWidget *next_page)
713 {
714         ModestAccountSettingsDialog *self = MODEST_ACCOUNT_SETTINGS_DIALOG (dialog);
715         
716         /* Do extra validation that couldn't be done for every key press,
717          * either because it was too slow,
718          * or because it requires interaction:
719          */
720         if (current_page == self->page_account_details) {       
721                 /* Check that the title is not already in use: */
722                 const gchar* account_name = gtk_entry_get_text (GTK_ENTRY (self->entry_account_title));
723                 if ((!account_name) || (strlen(account_name) == 0))
724                         return FALSE;
725                         
726                 gboolean name_in_use = FALSE;
727                 name_in_use = modest_account_mgr_account_exists (self->account_manager,
728                         account_name, FALSE /*  server_account */);
729                 
730                 if (name_in_use) {
731                         /* Warn the user via a dialog: */
732                         show_error (GTK_WINDOW (self), _("mail_ib_account_name_already_existing."));
733             
734                         return FALSE;
735                 }
736         }
737         else if (current_page == self->page_user_details) {
738                 /* Check that the email address is valud: */
739                 const gchar* email_address = gtk_entry_get_text (GTK_ENTRY (self->entry_user_email));
740                 if ((!email_address) || (strlen(email_address) == 0))
741                         return FALSE;
742                         
743                 if (!modest_text_utils_validate_email_address (email_address)) {
744                         /* Warn the user via a dialog: */
745                         show_error (GTK_WINDOW (self), _("mcen_ib_invalid_email"));
746                                              
747             /* Return focus to the email address entry: */
748             gtk_widget_grab_focus (self->entry_user_email);
749             
750                         return FALSE;
751                 }
752                 
753                 /* Make sure that the subsequent pages are appropriate for the provider choice. */
754                 create_subsequent_pages (self);
755         }
756         
757         /* TODO: The UI Spec wants us to check that the servernames are valid, 
758          * but does not specify how.
759          */
760           
761         if(next_page == self->page_incoming) {
762                 set_default_custom_servernames (self);
763         }
764         else if (next_page == self->page_outgoing) {
765                 set_default_custom_servernames (self);
766         }
767         
768         /* If this is the last page, and this is a click on Finish, 
769          * then attempt to create the dialog.
770          */
771         if(!next_page) /* This is NULL when this is a click on Finish. */
772         {
773                 create_account (self);
774         }
775         
776         
777         return TRUE;
778 }
779 #endif
780
781 static gboolean entry_is_empty (GtkWidget *entry)
782 {
783         if (!entry)
784                 return FALSE;
785                 
786         const gchar* text = gtk_entry_get_text (GTK_ENTRY (entry));
787         if ((!text) || (strlen(text) == 0))
788                 return TRUE;
789         else
790                 return FALSE;
791 }
792
793 static void
794 enable_buttons (ModestAccountSettingsDialog *self)
795 {
796         gboolean enable_ok = TRUE;
797         
798         /* The account details title is mandatory: */
799         if (entry_is_empty(self->entry_account_title))
800                         enable_ok = FALSE;
801
802         /* The user details username is mandatory: */
803         if (entry_is_empty(self->entry_user_username))
804                 enable_ok = FALSE;
805                 
806         /* The user details email address is mandatory: */
807         if (enable_ok && entry_is_empty (self->entry_user_email))
808                 enable_ok = FALSE;
809
810         /* The custom incoming server is mandatory: */
811         if (entry_is_empty(self->entry_incomingserver))
812                 enable_ok = FALSE;
813                         
814         /* Enable the buttons, 
815          * identifying them via their associated response codes:
816          */
817         GtkDialog *dialog_base = GTK_DIALOG (self);
818     gtk_dialog_set_response_sensitive (dialog_base,
819                                        GTK_RESPONSE_OK,
820                                        enable_ok);
821 }
822
823 static void
824 modest_account_settings_dialog_class_init (ModestAccountSettingsDialogClass *klass)
825 {
826         GObjectClass *object_class = G_OBJECT_CLASS (klass);
827         g_type_class_add_private (klass, sizeof (ModestAccountSettingsDialogPrivate));
828
829
830         object_class->get_property = modest_account_settings_dialog_get_property;
831         object_class->set_property = modest_account_settings_dialog_set_property;
832         object_class->dispose = modest_account_settings_dialog_dispose;
833         object_class->finalize = modest_account_settings_dialog_finalize;
834 }
835  
836 #if 0
837 static void
838 show_error (GtkWindow *parent_window, const gchar* text)
839 {
840         GtkDialog *dialog = GTK_DIALOG (gtk_message_dialog_new (parent_window,
841                 (GtkDialogFlags)0,
842                  GTK_MESSAGE_ERROR,
843                  GTK_BUTTONS_OK,
844                  text ));
845                  
846                  gtk_dialog_run (dialog);
847                  gtk_widget_destroy (GTK_WIDGET (dialog));
848 }
849 #endif
850
851 #if 0
852 /** Attempt to create the account from the information that the user has entered.
853  * @result: TRUE if the account was successfully created.
854  */
855 gboolean
856 create_account (ModestAccountSettingsDialog *self)
857 {
858         ModestAccountSettingsDialogPrivate *priv = ACCOUNT_SETTINGS_DIALOG_GET_PRIVATE (self);
859         
860         const gchar* account_name = gtk_entry_get_text (GTK_ENTRY (self->entry_account_title));
861
862         /* Some checks: */
863         if (!account_name)
864                 return FALSE;
865                 
866         /* We should have checked for this already, 
867          * and changed that name accordingly, 
868          * but let's check again just in case:
869          */
870         if (modest_account_mgr_account_exists (self->account_manager, account_name, FALSE)) 
871                 return FALSE;   
872                 
873         /* username and password (for both incoming and outgoing): */
874         const gchar* username = gtk_entry_get_text (GTK_ENTRY (self->entry_user_username));
875         const gchar* password = gtk_entry_get_text (GTK_ENTRY (self->entry_user_password));
876         
877         /* Incoming server: */
878         /* Note: We need something as default for the ModestProtocol values, 
879          * or modest_account_mgr_add_server_account will fail. */
880         gchar* servername_incoming = NULL;
881         ModestProtocol protocol_incoming = MODEST_PROTOCOL_STORE_POP;
882         ModestProtocol protocol_security_incoming = MODEST_PROTOCOL_SECURITY_NONE;
883         ModestProtocol protocol_authentication_incoming = MODEST_PROTOCOL_AUTH_NONE;
884         
885         
886         /* Use custom pages because no preset was specified: */
887         servername_incoming = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry_incomingserver) ));
888         
889         protocol_incoming = easysetup_servertype_combo_box_get_active_servertype (
890         EASYSETUP_SERVERTYPE_COMBO_BOX (self->combo_incoming_servertype));
891         
892         protocol_security_incoming = easysetup_serversecurity_combo_box_get_active_serversecurity (
893         EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_incoming_security));
894         
895         protocol_authentication_incoming = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->checkbox_incoming_auth)) 
896                 ? MODEST_PROTOCOL_AUTH_PASSWORD
897                 : MODEST_PROTOCOL_AUTH_NONE;
898                 
899
900         
901         /* First we add the 2 server accounts, and then we add the account that uses them.
902          * If we don't do it in this order then we will experience a crash. */
903          
904         /* Add a (incoming) server account, to be used by the account: */
905         gchar *store_name = g_strconcat (account_name, "_store", NULL);
906         gboolean created = modest_account_mgr_add_server_account (self->account_manager,
907                 store_name,
908                 servername_incoming,
909                 username, password,
910                 protocol_incoming,
911                 protocol_security_incoming,
912                 protocol_authentication_incoming);              
913                 
914         g_free (servername_incoming);
915         
916         if (!created) {
917                 /* TODO: Provide a Logical ID for the text: */
918                 show_error (GTK_WINDOW (self), _("An error occurred while creating the incoming account."));
919                 return FALSE;   
920         }
921         
922         /* Sanity check: */
923         /* There must be at least one account now: */
924         GSList *account_names = modest_account_mgr_account_names (self->account_manager);
925         if(account_names != NULL)
926         {
927                 g_warning ("modest_account_mgr_account_names() returned NULL after adding an account.");
928         }
929         g_slist_free (account_names);
930         
931         
932         /* Outgoing server: */
933         gchar* servername_outgoing = NULL;
934         ModestProtocol protocol_outgoing = MODEST_PROTOCOL_STORE_POP;
935         ModestProtocol protocol_security_outgoing = MODEST_PROTOCOL_SECURITY_NONE;
936         ModestProtocol protocol_authentication_outgoing = MODEST_PROTOCOL_AUTH_NONE;
937         
938         
939         /* Use custom pages because no preset was specified: */
940         servername_outgoing = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry_outgoingserver) ));
941         
942         protocol_outgoing = MODEST_PROTOCOL_TRANSPORT_SMTP; /* It's always SMTP for outgoing. */
943
944         protocol_security_outgoing = easysetup_serversecurity_combo_box_get_active_serversecurity (
945                 EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_outgoing_security));
946         
947         protocol_authentication_outgoing = easysetup_secureauth_combo_box_get_active_secureauth (
948                 EASYSETUP_SECUREAUTH_COMBO_BOX (self->combo_outgoing_auth));
949         
950         /* TODO: 
951         gboolean specific = gtk_toggle_button_get_active (
952                 GTK_TOGGLE_BUTTON (self->checkbox_outgoing_smtp_specific));
953         */
954                 
955             
956         /* Add a (outgoing) server account to be used by the account: */
957         gchar *transport_name = g_strconcat (account_name, "_transport", NULL); /* What is this good for? */
958         created = modest_account_mgr_add_server_account (self->account_manager,
959                 transport_name,
960                 servername_outgoing,
961                 username, password,
962                 protocol_outgoing,
963                 protocol_security_outgoing,
964                 protocol_authentication_outgoing);
965                 
966         g_free (servername_outgoing);
967                 
968         if (!created) {
969                 /* TODO: Provide a Logical ID for the text: */
970                 show_error (GTK_WINDOW (self), _("An error occurred while creating the outgoing account."));
971                 return FALSE;   
972         }
973         
974         
975         /* Create the account, which will contain the two "server accounts": */
976         created = modest_account_mgr_add_account (self->account_manager, account_name, 
977                 store_name, /* The name of our POP/IMAP server account. */
978                 transport_name /* The name of our SMTP server account. */);
979         g_free (store_name);
980         g_free (transport_name);
981         
982         if (!created) {
983                 /* TODO: Provide a Logical ID for the text: */
984                 show_error (GTK_WINDOW (self), _("An error occurred while creating the account."));
985                 return FALSE;   
986         }
987         
988         return FALSE;
989 }
990 #endif
991
992