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