https://projects.maemo.org
[modest] / src / maemo / easysetup / modest-easysetup-wizard.c
1 /* Copyright (c) 2007, Nokia Corporation
2  * All rights reserved.
3  *
4  */
5
6
7 #include "modest-easysetup-wizard.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/gtkseparator.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 "widgets/modest-serversecurity-combo-box.h"
23 #include "widgets/modest-secureauth-combo-box.h"
24 #include "widgets/modest-validating-entry.h"
25 #include "modest-text-utils.h"
26 #include "modest-account-mgr.h"
27 #include "modest-account-mgr-helpers.h"
28 #include "modest-runtime.h" /* For modest_runtime_get_account_mgr(). */
29 #include "maemo/modest-connection-specific-smtp-window.h"
30 #include "maemo/modest-maemo-ui-constants.h"
31 #include "maemo/modest-account-settings-dialog.h"
32 #include <gconf/gconf-client.h>
33 #include <string.h> /* For strlen(). */
34
35 /* Include config.h so that _() works: */
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #define EXAMPLE_EMAIL_ADDRESS "first.last@provider.com"
41
42 G_DEFINE_TYPE (ModestEasysetupWizardDialog, modest_easysetup_wizard_dialog, MODEST_TYPE_WIZARD_DIALOG);
43
44 #define WIZARD_DIALOG_GET_PRIVATE(o) \
45         (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_EASYSETUP_WIZARD_DIALOG, ModestEasysetupWizardDialogPrivate))
46
47 typedef struct _ModestEasysetupWizardDialogPrivate ModestEasysetupWizardDialogPrivate;
48
49 struct _ModestEasysetupWizardDialogPrivate
50 {
51         ModestPresets *presets;
52 };
53
54 static void
55 modest_easysetup_wizard_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_easysetup_wizard_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_easysetup_wizard_dialog_dispose (GObject *object)
76 {
77         if (G_OBJECT_CLASS (modest_easysetup_wizard_dialog_parent_class)->dispose)
78                 G_OBJECT_CLASS (modest_easysetup_wizard_dialog_parent_class)->dispose (object);
79 }
80
81 static void
82 modest_easysetup_wizard_dialog_finalize (GObject *object)
83 {
84         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (object);
85         ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
86         
87         if (self->account_manager)
88                 g_object_unref (G_OBJECT (self->account_manager));
89                 
90         if (priv->presets)
91                 modest_presets_destroy (priv->presets);
92                 
93         if (self->specific_window)
94                 gtk_widget_destroy (self->specific_window);
95                 
96         g_free (self->saved_account_name);
97         
98         G_OBJECT_CLASS (modest_easysetup_wizard_dialog_parent_class)->finalize (object);
99 }
100
101 static void
102 show_error (GtkWindow *parent_window, const gchar* text);
103
104 static gboolean
105 create_account (ModestEasysetupWizardDialog *self);
106
107 static void
108 create_subsequent_easysetup_pages (ModestEasysetupWizardDialog *self);
109
110 static void
111 set_default_custom_servernames(ModestEasysetupWizardDialog *dialog);
112
113 static void on_combo_servertype_changed(GtkComboBox *combobox, gpointer user_data);
114
115 static void
116 invoke_enable_buttons_vfunc (ModestEasysetupWizardDialog *wizard_dialog)
117 {
118         ModestWizardDialogClass *klass = MODEST_WIZARD_DIALOG_GET_CLASS (wizard_dialog);
119         
120         /* Call the vfunc, which may be overridden by derived classes: */
121         if (klass->enable_buttons) {
122                 GtkNotebook *notebook = NULL;
123                 g_object_get (wizard_dialog, "wizard-notebook", &notebook, NULL);
124                 
125                 const gint current_page_num = gtk_notebook_get_current_page (notebook);
126                 if (current_page_num == -1)
127                         return;
128                         
129                 GtkWidget* current_page_widget = gtk_notebook_get_nth_page (notebook, current_page_num);
130                 (*(klass->enable_buttons))(MODEST_WIZARD_DIALOG (wizard_dialog), current_page_widget);
131         }
132 }
133
134 static void
135 on_caption_entry_changed (GtkEditable *editable, gpointer user_data)
136 {
137         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
138         g_assert(self);
139         invoke_enable_buttons_vfunc(self);
140 }
141
142 static void
143 on_caption_combobox_changed (GtkComboBox *widget, gpointer user_data)
144 {
145         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
146         g_assert(self);
147         invoke_enable_buttons_vfunc(self);
148 }
149
150 /** This is a convenience function to create a caption containing a mandatory widget.
151  * When the widget is edited, the enable_buttons() vfunc will be called.
152  */
153 static GtkWidget* create_caption_new_with_asterix(ModestEasysetupWizardDialog *self,
154         GtkSizeGroup *group,
155         const gchar *value,
156         GtkWidget *control,
157         GtkWidget *icon,
158         HildonCaptionStatus flag)
159 {
160   GtkWidget *caption = hildon_caption_new (group, value, control, icon, flag);
161   
162 /* The translated strings seem to already contain the *,
163  * but this code can be used if that is not true in future.
164  */
165 #if 0
166         /* Add a * character to indicate mandatory fields,
167          * as specified in our "Email UI Specification": */
168         if (flag == HILDON_CAPTION_MANDATORY) {
169                 gchar* title = g_strdup_printf("%s*", value);
170                 caption = hildon_caption_new (group, title, control, icon, flag);       
171                 g_free(title);
172         }       
173         else
174                 caption = hildon_caption_new (group, value, control, icon, flag);
175 #endif
176
177         /* Connect to the appropriate changed signal for the widget, 
178          * so we can ask for the prev/next buttons to be enabled/disabled appropriately:
179          */
180         if (GTK_IS_ENTRY (control)) {
181                 g_signal_connect (G_OBJECT (control), "changed",
182                 G_CALLBACK (on_caption_entry_changed), self);
183                 
184         }
185         else if (GTK_IS_COMBO_BOX (control)) {
186                 g_signal_connect (G_OBJECT (control), "changed",
187                 G_CALLBACK (on_caption_combobox_changed), self);
188         }
189          
190         return caption;
191 }
192            
193 static GtkWidget*
194 create_page_welcome (ModestEasysetupWizardDialog *self)
195 {
196         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
197         GtkWidget *label = gtk_label_new(_("mcen_ia_emailsetup_intro"));
198         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
199         gtk_widget_show (label);
200         gtk_widget_show (GTK_WIDGET (box));
201         return GTK_WIDGET (box);
202 }
203
204 static void
205 on_combo_account_country (GtkComboBox *widget, gpointer user_data)
206 {
207         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
208         g_assert(self);
209         ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
210         
211         /* Fill the providers combo, based on the selected country: */
212         gint mcc_id = easysetup_country_combo_box_get_active_country_id (
213                 EASYSETUP_COUNTRY_COMBO_BOX (self->combo_account_country));
214         easysetup_provider_combo_box_fill (
215                 EASYSETUP_PROVIDER_COMBO_BOX (self->combo_account_serviceprovider), priv->presets, mcc_id);
216 }
217
218 static void
219 on_combo_account_serviceprovider (GtkComboBox *widget, gpointer user_data)
220 {
221         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
222         g_assert(self);
223         ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
224         
225         /* Fill the providers combo, based on the selected country: */
226         gchar* provider_id = easysetup_provider_combo_box_get_active_provider_id (
227                 EASYSETUP_PROVIDER_COMBO_BOX (self->combo_account_serviceprovider));
228         
229         gchar* domain_name = NULL;
230         if(provider_id)
231           domain_name = modest_presets_get_domain (priv->presets, provider_id);
232         
233         if(!domain_name)
234                 domain_name = g_strdup (EXAMPLE_EMAIL_ADDRESS);
235                 
236         if (self->entry_user_email)
237                 gtk_entry_set_text (GTK_ENTRY (self->entry_user_email), domain_name);
238                 
239     g_free (domain_name);
240         
241         g_free (provider_id);
242 }
243
244 static void
245 on_entry_max (ModestValidatingEntry *self, gpointer user_data)
246 {
247         ModestEasysetupWizardDialog *dialog = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
248         show_error (GTK_WINDOW (dialog), _("ckdg_ib_maximum_characters_reached"));
249 }
250
251 static GtkWidget*
252 create_page_account_details (ModestEasysetupWizardDialog *self)
253 {
254         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
255         GtkWidget *label = gtk_label_new(_("mcen_ia_accountdetails"));
256         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, MODEST_MARGIN_HALF);
257         gtk_widget_show (label);
258         
259         /* Create a size group to be used by all captions.
260          * Note that HildonCaption does not create a default size group if we do not specify one.
261          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
262         GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
263
264         /* The country widgets: */
265         self->combo_account_country = GTK_WIDGET (easysetup_country_combo_box_new ());
266         GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, _("mcen_fi_country"), 
267                 self->combo_account_country, NULL, HILDON_CAPTION_OPTIONAL);
268         gtk_widget_show (self->combo_account_country);
269         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
270         gtk_widget_show (caption);
271         
272         /* connect to country combo's changed signal, so we can fill the provider combo: */
273     g_signal_connect (G_OBJECT (self->combo_account_country), "changed",
274             G_CALLBACK (on_combo_account_country), self);
275             
276         GtkWidget *separator = gtk_hseparator_new ();
277         gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, MODEST_MARGIN_HALF);
278         gtk_widget_show (separator);
279             
280         /* The service provider widgets: */     
281         self->combo_account_serviceprovider = GTK_WIDGET (easysetup_provider_combo_box_new ());
282         
283         caption = create_caption_new_with_asterix (self, sizegroup, _("mcen_fi_serviceprovider"), 
284                 self->combo_account_serviceprovider, NULL, HILDON_CAPTION_OPTIONAL);
285         gtk_widget_show (self->combo_account_serviceprovider);
286         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
287         gtk_widget_show (caption);
288         
289         /* connect to providers combo's changed signal, so we can fill the email address: */
290     g_signal_connect (G_OBJECT (self->combo_account_serviceprovider), "changed",
291             G_CALLBACK (on_combo_account_serviceprovider), self);
292         
293         /* TODO: Default to the current country somehow.
294          * But I don't know how to get the information that is specified in the 
295          * "Language and region" control panel. It does not seem be anywhere in gconf. murrayc.
296          *
297          * This is probably not the best choice of gconf key:
298          * This is the  "mcc used in the last pairing", ie. the last connection you made.
299      * set by the osso-operator-wizard package, suggested by Dirk-Jan Binnema.
300      *
301          */
302         GConfClient *client = gconf_client_get_default ();
303         GError *error = NULL;
304         const gchar* key = "/apps/osso/operator-wizard/last_mcc";
305         gint mcc_id = gconf_client_get_int(client, key, &error);
306         
307         if(mcc_id < 0)
308         mcc_id = 0;
309      
310     if (error) {
311         g_warning ("Error getting gconf key %s:\n%s", key, error->message);
312         g_error_free (error);
313         error = NULL;
314         
315         mcc_id = 0;
316     }
317     
318     /* Note that gconf_client_get_int() seems to return 0 without an error if the key is not there
319      * This might just be a Maemo bug.
320      */
321     if (mcc_id == 0) 
322     {
323         /* For now, we default to Finland when there is nothing better: */
324         mcc_id = 244;
325     }
326    
327         easysetup_country_combo_box_set_active_country_id (
328                 EASYSETUP_COUNTRY_COMBO_BOX (self->combo_account_country), mcc_id);
329                 
330         
331         /* The description widgets: */  
332         self->entry_account_title = GTK_WIDGET (modest_validating_entry_new ());
333         /* Do use auto-capitalization: */
334         hildon_gtk_entry_set_input_mode (GTK_ENTRY (self->entry_account_title), 
335                 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
336         
337         /* Set a default account title, choosing one that does not already exist: */
338         /* Note that this is irrelevant to the non-user visible name, which we will create later. */
339         gchar* default_account_name_start = g_strdup (_("mcen_ia_emailsetup_defaultname"));
340         gchar* default_account_name = modest_account_mgr_get_unused_account_display_name (
341                 self->account_manager, default_account_name_start);
342         g_free (default_account_name_start);
343         default_account_name_start = NULL;
344         
345         gtk_entry_set_text( GTK_ENTRY (self->entry_account_title), default_account_name);
346         g_free (default_account_name);
347         default_account_name = NULL;
348
349         caption = create_caption_new_with_asterix (self, sizegroup, _("mcen_fi_account_title"), 
350                 self->entry_account_title, NULL, HILDON_CAPTION_MANDATORY);
351         gtk_widget_show (self->entry_account_title);
352         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
353         gtk_widget_show (caption);
354         
355         /* Prevent the use of some characters in the account title, 
356          * as required by our UI specification: */
357         GList *list_prevent = NULL;
358         list_prevent = g_list_append (list_prevent, "\\");
359         list_prevent = g_list_append (list_prevent, "/");
360         list_prevent = g_list_append (list_prevent, ":");
361         list_prevent = g_list_append (list_prevent, "*");
362         list_prevent = g_list_append (list_prevent, "?");
363         list_prevent = g_list_append (list_prevent, "\""); /* The UI spec mentions â€œ, but maybe means ", maybe both. */
364         list_prevent = g_list_append (list_prevent, "“");
365         list_prevent = g_list_append (list_prevent, "<"); 
366         list_prevent = g_list_append (list_prevent, ">"); 
367         list_prevent = g_list_append (list_prevent, "|");
368         list_prevent = g_list_append (list_prevent, "^");       
369         modest_validating_entry_set_unallowed_characters (
370                 MODEST_VALIDATING_ENTRY (self->entry_account_title), list_prevent);
371         g_list_free (list_prevent);
372         
373         /* Set max length as in the UI spec:
374          * The UI spec seems to want us to show a dialog if we hit the maximum. */
375         gtk_entry_set_max_length (GTK_ENTRY (self->entry_account_title), 64);
376         modest_validating_entry_set_max_func (MODEST_VALIDATING_ENTRY (self->entry_account_title), 
377                 on_entry_max, self);
378         
379         gtk_widget_show (GTK_WIDGET (box));
380         
381         return GTK_WIDGET (box);
382 }
383
384 static GtkWidget*
385 create_page_user_details (ModestEasysetupWizardDialog *self)
386 {
387         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
388         
389         /* Create a size group to be used by all captions.
390          * Note that HildonCaption does not create a default size group if we do not specify one.
391          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
392         GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
393          
394         /* The name widgets: */
395         self->entry_user_name = GTK_WIDGET (modest_validating_entry_new ());
396         /* Auto-capitalization is the default, so let's turn it off: */
397         hildon_gtk_entry_set_input_mode (GTK_ENTRY (self->entry_user_name), HILDON_GTK_INPUT_MODE_FULL);
398         /* Set max length as in the UI spec:
399          * The UI spec seems to want us to show a dialog if we hit the maximum. */
400         gtk_entry_set_max_length (GTK_ENTRY (self->entry_user_name), 64);
401         modest_validating_entry_set_max_func (MODEST_VALIDATING_ENTRY (self->entry_user_name), 
402                 on_entry_max, self);
403         GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, 
404                 _("mcen_li_emailsetup_name"), self->entry_user_name, NULL, HILDON_CAPTION_OPTIONAL);
405         gtk_widget_show (self->entry_user_name);
406         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
407         gtk_widget_show (caption);
408         
409         /* Prevent the use of some characters in the name, 
410          * as required by our UI specification: */
411         GList *list_prevent = NULL;
412         list_prevent = g_list_append (list_prevent, "<");
413         list_prevent = g_list_append (list_prevent, ">");
414         modest_validating_entry_set_unallowed_characters (
415                 MODEST_VALIDATING_ENTRY (self->entry_user_name), list_prevent);
416         g_list_free (list_prevent);
417         
418         /* The username widgets: */     
419         self->entry_user_username = GTK_WIDGET (modest_validating_entry_new ());
420         /* Auto-capitalization is the default, so let's turn it off: */
421         hildon_gtk_entry_set_input_mode (GTK_ENTRY (self->entry_user_username), HILDON_GTK_INPUT_MODE_FULL);
422         caption = create_caption_new_with_asterix (self, sizegroup, _("mail_fi_username"), 
423                 self->entry_user_username, NULL, HILDON_CAPTION_MANDATORY);
424         gtk_widget_show (self->entry_user_username);
425         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
426         gtk_widget_show (caption);
427         
428         /* Prevent the use of some characters in the username, 
429          * as required by our UI specification: */
430         modest_validating_entry_set_unallowed_characters_whitespace (
431                 MODEST_VALIDATING_ENTRY (self->entry_user_username));
432         
433         /* Set max length as in the UI spec:
434          * The UI spec seems to want us to show a dialog if we hit the maximum. */
435         gtk_entry_set_max_length (GTK_ENTRY (self->entry_user_username), 64);
436         modest_validating_entry_set_max_func (MODEST_VALIDATING_ENTRY (self->entry_user_username), 
437                 on_entry_max, self);
438         
439         /* The password widgets: */     
440         self->entry_user_password = gtk_entry_new ();
441         /* Auto-capitalization is the default, so let's turn it off: */
442         hildon_gtk_entry_set_input_mode (GTK_ENTRY (self->entry_user_password), HILDON_GTK_INPUT_MODE_FULL);
443         gtk_entry_set_visibility (GTK_ENTRY (self->entry_user_password), FALSE);
444         /* gtk_entry_set_invisible_char (GTK_ENTRY (self->entry_user_password), '*'); */
445         caption = create_caption_new_with_asterix (self, sizegroup, 
446                 _("mail_fi_password"), self->entry_user_password, NULL, HILDON_CAPTION_OPTIONAL);
447         gtk_widget_show (self->entry_user_password);
448         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
449         gtk_widget_show (caption);
450         
451         /* The email address widgets: */        
452         self->entry_user_email = GTK_WIDGET (modest_validating_entry_new ());
453         /* Auto-capitalization is the default, so let's turn it off: */
454         hildon_gtk_entry_set_input_mode (GTK_ENTRY (self->entry_user_email), HILDON_GTK_INPUT_MODE_FULL);
455         caption = create_caption_new_with_asterix (self, sizegroup, 
456                 _("mcen_li_emailsetup_email_address"), self->entry_user_email, NULL, HILDON_CAPTION_MANDATORY);
457         gtk_entry_set_text (GTK_ENTRY (self->entry_user_email), EXAMPLE_EMAIL_ADDRESS); /* Default text. */
458         gtk_widget_show (self->entry_user_email);
459         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
460         gtk_widget_show (caption);
461         
462         /* Set max length as in the UI spec:
463          * The UI spec seems to want us to show a dialog if we hit the maximum. */
464         gtk_entry_set_max_length (GTK_ENTRY (self->entry_user_email), 64);
465         modest_validating_entry_set_max_func (MODEST_VALIDATING_ENTRY (self->entry_user_email), 
466                 on_entry_max, self);
467         
468         
469         gtk_widget_show (GTK_WIDGET (box));
470         
471         return GTK_WIDGET (box);
472 }
473
474 static GtkWidget* create_page_complete_easysetup (ModestEasysetupWizardDialog *self)
475 {
476         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
477         GtkWidget *label = gtk_label_new(_("mcen_ia_emailsetup_setup_complete"));
478         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
479         gtk_widget_show (label);
480         gtk_widget_show (GTK_WIDGET (box));
481         return GTK_WIDGET (box);
482 }
483
484 /** Change the caption title for the incoming server, 
485  * as specified in the UI spec:
486  */
487 static void update_incoming_server_title (ModestEasysetupWizardDialog *self)
488 {
489         ModestProtocol protocol = easysetup_servertype_combo_box_get_active_servertype (
490                 EASYSETUP_SERVERTYPE_COMBO_BOX (self->combo_incoming_servertype));
491         const gchar* type = 
492                 (protocol == MODEST_PROTOCOL_STORE_POP ? 
493                         _("mail_fi_emailtype_pop3") : 
494                         _("mail_fi_emailtype_imap") );
495                         
496                 
497         /* Note that this produces a compiler warning, 
498          * because the compiler does not know that the translated string will have a %s in it.
499          * I do not see a way to avoid the warning while still using these Logical IDs. murrayc. */
500         gchar* incomingserver_title = g_strdup_printf(_("mcen_li_emailsetup_servertype"), type);
501         g_object_set (G_OBJECT (self->caption_incoming), "label", incomingserver_title, NULL);
502         g_free(incomingserver_title);
503 }
504
505 /** Change the caption title for the incoming server, 
506  * as specified in the UI spec:
507  */
508 static void update_incoming_server_security_choices (ModestEasysetupWizardDialog *self)
509 {
510         ModestProtocol protocol = easysetup_servertype_combo_box_get_active_servertype (
511                 EASYSETUP_SERVERTYPE_COMBO_BOX (self->combo_incoming_servertype));
512         
513         /* Fill the combo with appropriately titled choices for POP or IMAP. */
514         /* The choices are the same, but the titles are different, as in the UI spec. */
515         modest_serversecurity_combo_box_fill (
516                 MODEST_SERVERSECURITY_COMBO_BOX (self->combo_incoming_security), protocol);
517 }
518
519 static void on_combo_servertype_changed(GtkComboBox *combobox, gpointer user_data)
520 {
521         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
522         update_incoming_server_title (self);
523         update_incoming_server_security_choices (self);
524 }
525            
526 static GtkWidget* create_page_custom_incoming (ModestEasysetupWizardDialog *self)
527 {
528         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
529         
530         /* Create a size group to be used by all captions.
531          * Note that HildonCaption does not create a default size group if we do not specify one.
532          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
533         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
534          
535         /* The incoming server widgets: */
536         if (!self->combo_incoming_servertype)
537                 self->combo_incoming_servertype = GTK_WIDGET (easysetup_servertype_combo_box_new ());
538         easysetup_servertype_combo_box_set_active_servertype (
539                 EASYSETUP_SERVERTYPE_COMBO_BOX (self->combo_incoming_servertype), MODEST_PROTOCOL_STORE_POP);
540         GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, 
541                 _("mcen_li_emailsetup_type"), self->combo_incoming_servertype, NULL, HILDON_CAPTION_MANDATORY);
542         gtk_widget_show (self->combo_incoming_servertype);
543         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
544         gtk_widget_show (caption);
545         
546         if(!self->entry_incomingserver)
547                 self->entry_incomingserver = gtk_entry_new ();
548         /* Auto-capitalization is the default, so let's turn it off: */
549         hildon_gtk_entry_set_input_mode (GTK_ENTRY (self->entry_incomingserver), HILDON_GTK_INPUT_MODE_FULL);
550         set_default_custom_servernames (self);
551
552         if (self->caption_incoming)
553           gtk_widget_destroy (self->caption_incoming);
554            
555         /* The caption title will be updated in update_incoming_server_title().
556          * so this default text will never be seen: */
557         /* (Note: Changing the title seems pointless. murrayc) */
558         self->caption_incoming = create_caption_new_with_asterix (self, sizegroup, 
559                 "Incoming Server", self->entry_incomingserver, NULL, HILDON_CAPTION_MANDATORY);
560         update_incoming_server_title (self);
561         gtk_widget_show (self->entry_incomingserver);
562         gtk_box_pack_start (GTK_BOX (box), self->caption_incoming, FALSE, FALSE, MODEST_MARGIN_HALF);
563         gtk_widget_show (self->caption_incoming);
564         
565         /* Change the caption title when the servertype changes, 
566          * as in the UI spec: */
567          g_signal_connect (G_OBJECT (self->combo_incoming_servertype), "changed",
568                 G_CALLBACK (on_combo_servertype_changed), self);
569         
570         /* The secure connection widgets: */    
571         if (!self->combo_incoming_security)
572                 self->combo_incoming_security = GTK_WIDGET (modest_serversecurity_combo_box_new ());
573         update_incoming_server_security_choices (self);
574         modest_serversecurity_combo_box_set_active_serversecurity (
575                 MODEST_SERVERSECURITY_COMBO_BOX (self->combo_incoming_security), MODEST_PROTOCOL_SECURITY_NONE);
576         caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_connection"), 
577                 self->combo_incoming_security, NULL, HILDON_CAPTION_OPTIONAL);
578         gtk_widget_show (self->combo_incoming_security);
579         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
580         gtk_widget_show (caption);
581         
582         if(!self->checkbox_incoming_auth)
583                 self->checkbox_incoming_auth = gtk_check_button_new ();
584         caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_authentication"), 
585                 self->checkbox_incoming_auth, NULL, HILDON_CAPTION_OPTIONAL);
586         gtk_widget_show (self->checkbox_incoming_auth);
587         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
588         gtk_widget_show (caption);
589         
590         gtk_widget_show (GTK_WIDGET (box));
591         
592         return GTK_WIDGET (box);
593 }
594
595 static void
596 on_toggle_button_changed (GtkToggleButton *togglebutton, gpointer user_data)
597 {
598         GtkWidget *widget = GTK_WIDGET (user_data);
599         
600         /* Enable the widget only if the toggle button is active: */
601         const gboolean enable = gtk_toggle_button_get_active (togglebutton);
602         gtk_widget_set_sensitive (widget, enable);
603 }
604
605 /* Make the sensitivity of a widget depend on a toggle button.
606  */
607 static void
608 enable_widget_for_togglebutton (GtkWidget *widget, GtkToggleButton* button)
609 {
610         g_signal_connect (G_OBJECT (button), "toggled",
611                 G_CALLBACK (on_toggle_button_changed), widget);
612         
613         /* Set the starting sensitivity: */
614         on_toggle_button_changed (button, widget);
615 }
616
617 static void
618 on_button_outgoing_smtp_servers (GtkButton *button, gpointer user_data)
619 {
620         ModestEasysetupWizardDialog * self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
621         
622         /* Create the window, if necessary: */
623         if (!(self->specific_window)) {
624                 self->specific_window = GTK_WIDGET (modest_connection_specific_smtp_window_new ());
625                 modest_connection_specific_smtp_window_fill_with_connections (
626                         MODEST_CONNECTION_SPECIFIC_SMTP_WINDOW (self->specific_window), self->account_manager, 
627                         NULL /* account_name, not known yet. */);
628         }
629
630         /* Show the window: */
631         gtk_window_set_transient_for (GTK_WINDOW (self->specific_window), GTK_WINDOW (self));
632         gtk_widget_show (self->specific_window);
633 }
634
635 static GtkWidget* create_page_custom_outgoing (ModestEasysetupWizardDialog *self)
636 {
637         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
638         
639         /* Create a size group to be used by all captions.
640          * Note that HildonCaption does not create a default size group if we do not specify one.
641          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
642         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
643          
644         /* The outgoing server widgets: */
645         if (!self->entry_outgoingserver)
646                 self->entry_outgoingserver = gtk_entry_new ();
647         /* Auto-capitalization is the default, so let's turn it off: */
648         hildon_gtk_entry_set_input_mode (GTK_ENTRY (self->entry_outgoingserver), HILDON_GTK_INPUT_MODE_FULL);
649         GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, 
650                 _("mcen_li_emailsetup_smtp"), self->entry_outgoingserver, NULL, HILDON_CAPTION_OPTIONAL);
651         gtk_widget_show (self->entry_outgoingserver);
652         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
653         gtk_widget_show (caption);
654         set_default_custom_servernames (self);
655         
656         /* The secure connection widgets: */    
657         if (!self->combo_outgoing_security)
658                 self->combo_outgoing_security = GTK_WIDGET (modest_serversecurity_combo_box_new ());
659         modest_serversecurity_combo_box_fill (
660                 MODEST_SERVERSECURITY_COMBO_BOX (self->combo_outgoing_security), MODEST_PROTOCOL_TRANSPORT_SMTP);
661         modest_serversecurity_combo_box_set_active_serversecurity (
662                 MODEST_SERVERSECURITY_COMBO_BOX (self->combo_outgoing_security), MODEST_PROTOCOL_SECURITY_NONE);
663         caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_connection"), 
664                 self->combo_outgoing_security, NULL, HILDON_CAPTION_OPTIONAL);
665         gtk_widget_show (self->combo_outgoing_security);
666         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
667         gtk_widget_show (caption);
668         
669         /* The secure authentication widgets: */
670         if (!self->combo_outgoing_auth)
671                 self->combo_outgoing_auth = GTK_WIDGET (modest_secureauth_combo_box_new ());
672         caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_authentication"), 
673                 self->combo_outgoing_auth, NULL, HILDON_CAPTION_OPTIONAL);
674         gtk_widget_show (self->combo_outgoing_auth);
675         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
676         gtk_widget_show (caption);
677         
678         GtkWidget *separator = gtk_hseparator_new ();
679         gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, MODEST_MARGIN_HALF);
680         gtk_widget_show (separator);
681         
682         /* connection-specific checkbox: */
683         if (!self->checkbox_outgoing_smtp_specific) {
684                 self->checkbox_outgoing_smtp_specific = gtk_check_button_new ();
685                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->checkbox_outgoing_smtp_specific), 
686                         FALSE);
687         }
688         caption = hildon_caption_new (sizegroup, _("mcen_fi_advsetup_connection_smtp"), 
689                 self->checkbox_outgoing_smtp_specific, NULL, HILDON_CAPTION_OPTIONAL);
690         gtk_widget_show (self->checkbox_outgoing_smtp_specific);
691         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
692         gtk_widget_show (caption);
693         
694         /* Connection-specific SMTP-Severs Edit button: */
695         if (!self->button_outgoing_smtp_servers)
696                 self->button_outgoing_smtp_servers = gtk_button_new_with_label (_("mcen_bd_edit"));
697         caption = hildon_caption_new (sizegroup, _("mcen_fi_advsetup_optional_smtp"), 
698                 self->button_outgoing_smtp_servers, NULL, HILDON_CAPTION_OPTIONAL);
699         hildon_caption_set_child_expand (HILDON_CAPTION (caption), FALSE);
700         gtk_widget_show (self->button_outgoing_smtp_servers);
701         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
702         gtk_widget_show (caption);
703         
704         /* Only enable the button when the checkbox is checked: */
705         enable_widget_for_togglebutton (self->button_outgoing_smtp_servers, 
706                 GTK_TOGGLE_BUTTON (self->checkbox_outgoing_smtp_specific));
707                 
708         g_signal_connect (G_OBJECT (self->button_outgoing_smtp_servers), "clicked",
709                 G_CALLBACK (on_button_outgoing_smtp_servers), self);
710         
711         
712         gtk_widget_show (GTK_WIDGET (box));
713         
714         return GTK_WIDGET (box);
715 }
716
717
718 static void
719 on_button_edit_advanced_settings (GtkButton *button, gpointer user_data)
720 {
721         ModestEasysetupWizardDialog * self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
722         
723         /* Save the new account, so we can edit it with ModestAccountSettingsDialog, 
724          * without recoding it to use non-gconf information.
725          * This account will be deleted if Finish is never actually clicked. */
726
727         const gboolean saved = create_account (self);
728         if (!saved)
729                 return;
730                 
731         if (!(self->saved_account_name))
732                 return;
733         
734         /* Show the Account Settings window: */
735         ModestAccountSettingsDialog *dialog = modest_account_settings_dialog_new ();
736         modest_account_settings_dialog_set_account_name (dialog, self->saved_account_name);
737         
738         gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (self));
739         printf ("debug: before run\n");
740         gtk_dialog_run (GTK_DIALOG (dialog));
741         printf ("debug: after run\n");
742         gtk_widget_destroy (GTK_WIDGET (dialog));
743 }
744 static GtkWidget* create_page_complete_custom (ModestEasysetupWizardDialog *self)
745 {
746         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
747         GtkWidget *label = gtk_label_new(_("mcen_ia_emailsetup_setup_complete"));
748         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
749         gtk_widget_show (label);
750         
751         if (!self->button_edit)
752                 self->button_edit = gtk_button_new_with_label (_("mcen_bd_edit"));
753         GtkWidget *caption = hildon_caption_new (NULL, _("mcen_fi_advanced_settings"), 
754                 self->button_edit, NULL, HILDON_CAPTION_OPTIONAL);
755         hildon_caption_set_child_expand (HILDON_CAPTION (caption), FALSE);
756         gtk_widget_show (self->button_edit);
757         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
758         gtk_widget_show (caption);
759         
760         g_signal_connect (G_OBJECT (self->button_edit), "clicked", 
761                 G_CALLBACK (on_button_edit_advanced_settings), self);
762         
763         gtk_widget_show (GTK_WIDGET (box));
764         return GTK_WIDGET (box);
765 }
766
767
768 /*
769  */
770 static void 
771 on_response (ModestWizardDialog *wizard_dialog,
772         gint response_id,
773         gpointer user_data)
774 {
775         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (wizard_dialog);
776         
777         if (response_id == GTK_RESPONSE_CANCEL) {
778                 /* Remove any temporarily-saved account that will not actually be needed: */
779                 if (self->saved_account_name) {
780                         modest_account_mgr_remove_account (self->account_manager,
781                                                                      self->saved_account_name, FALSE);
782                 }       
783         }
784         
785         invoke_enable_buttons_vfunc (self);
786 }
787
788 static void
789 modest_easysetup_wizard_dialog_init (ModestEasysetupWizardDialog *self)
790 {
791         gtk_container_set_border_width (GTK_CONTAINER (self), MODEST_MARGIN_HALF);
792         
793         /* Create the notebook to be used by the ModestWizardDialog base class:
794          * Each page of the notebook will be a page of the wizard: */
795         GtkNotebook *notebook = GTK_NOTEBOOK (gtk_notebook_new());
796         
797     /* Set the notebook used by the ModestWizardDialog base class: */
798     g_object_set (G_OBJECT(self), "wizard-notebook", notebook, NULL);
799     
800     /* Set the wizard title:
801      * The actual window title will be a combination of this and the page's tab label title. */
802     g_object_set (G_OBJECT(self), "wizard-name", _("mcen_ti_emailsetup"), NULL);
803
804         /* Read in the information about known service providers: */
805         ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
806         
807         const gchar* filepath = MODEST_PROVIDERS_DATA_PATH; /* Defined in config.h */
808         priv->presets = modest_presets_new (filepath);
809         if (!(priv->presets)) {
810                 g_warning ("Could not locate the official provider data keyfile from %s", filepath);
811         }
812         
813         g_assert(priv->presets);
814         
815         
816         /* Get the account manager object, 
817          * so we can check for existing accounts,
818          * and create new accounts: */
819         self->account_manager = modest_runtime_get_account_mgr ();
820         g_assert (self->account_manager);
821         g_object_ref (self->account_manager);
822         
823     /* Create the common pages, 
824      */
825     self->page_welcome = create_page_welcome (self);
826         self->page_account_details = create_page_account_details (self);
827         self->page_user_details = create_page_user_details (self);
828         
829         /* Add the common pages: */
830         gtk_notebook_append_page (notebook, self->page_welcome, 
831                 gtk_label_new (_("mcen_ti_emailsetup_welcome")));
832         gtk_notebook_append_page (notebook, self->page_account_details, 
833                 gtk_label_new (_("mcen_ti_accountdetails")));
834         gtk_notebook_append_page (notebook, self->page_user_details, 
835                 gtk_label_new (_("mcen_ti_emailsetup_userdetails")));
836                 
837         /* Create and add the easysetup-specific pages,
838          * because we need _some_ final page to enable the Next and Finish buttons: */
839         create_subsequent_easysetup_pages (self);
840
841             
842     /* Connect to the dialog's response signal so we can enable/disable buttons 
843      * for the newly-selected page, because the prev/next buttons cause response to be emitted.
844      * Note that we use g_signal_connect_after() instead of g_signal_connect()
845      * so that we can be enable/disable after ModestWizardDialog has done its own 
846      * enabling/disabling of buttons.
847      * 
848      * HOWEVER, this doesn't work because ModestWizardDialog's response signal handler 
849      * does g_signal_stop_emission_by_name(), stopping our signal handler from running.
850      * 
851      * It's not enough to connect to the notebook's switch-page signal, because 
852      * ModestWizardDialog's "response" signal handler enables the buttons itself, 
853      * _after_ switching the page (understandably).
854      * (Note that if we had, if we used g_signal_connect() instead of g_signal_connect_after()
855      * then gtk_notebook_get_current_page() would return an incorrect value.)
856      */
857     g_signal_connect_after (G_OBJECT (self), "response",
858             G_CALLBACK (on_response), self);       
859 }
860
861 ModestEasysetupWizardDialog*
862 modest_easysetup_wizard_dialog_new (void)
863 {
864         return g_object_new (MODEST_TYPE_EASYSETUP_WIZARD_DIALOG, NULL);
865 }
866
867 static void create_subsequent_customsetup_pages (ModestEasysetupWizardDialog *self)
868 {
869         GtkNotebook *notebook = NULL;
870         g_object_get (self, "wizard-notebook", &notebook, NULL);
871         g_assert(notebook);
872         
873         /* Create the custom pages: */
874         if(!(self->page_custom_incoming)) {
875                 self->page_custom_incoming = create_page_custom_incoming (self);
876         }
877                 
878         if(!(self->page_custom_outgoing)) {
879                 self->page_custom_outgoing = create_page_custom_outgoing (self);
880         }
881         
882         if(!(self->page_complete_customsetup)) {
883                 self->page_complete_customsetup = create_page_complete_custom (self);
884         }
885         
886         if (!gtk_widget_get_parent (GTK_WIDGET (self->page_custom_incoming)))
887                 gtk_notebook_append_page (notebook, self->page_custom_incoming,
888                         gtk_label_new (_("mcen_ti_emailsetup_incomingdetails")));
889         
890         if (!gtk_widget_get_parent (GTK_WIDGET (self->page_custom_outgoing)))           
891                 gtk_notebook_append_page (notebook, self->page_custom_outgoing,
892                         gtk_label_new (_("mcen_ti_emailsetup_outgoingdetails")));
893                 
894         if (!gtk_widget_get_parent (GTK_WIDGET (self->page_complete_customsetup)))
895                 gtk_notebook_append_page (notebook, self->page_complete_customsetup,
896                         gtk_label_new (_("mcen_ti_emailsetup_complete")));
897 }
898         
899 static void create_subsequent_easysetup_pages (ModestEasysetupWizardDialog *self)
900 {
901         GtkNotebook *notebook = NULL;
902         g_object_get (self, "wizard-notebook", &notebook, NULL);
903         g_assert(notebook);
904         
905         /* Create the easysetup-specific pages: */
906         if(!self->page_complete_easysetup)
907                 self->page_complete_easysetup = create_page_complete_easysetup (self);
908
909         if (!gtk_widget_get_parent (GTK_WIDGET (self->page_complete_easysetup)))
910                 gtk_notebook_append_page (notebook, self->page_complete_easysetup, 
911                         gtk_label_new (_("mcen_ti_emailsetup_complete")));
912                         
913 }
914 /* After the user details page,
915  * the following pages depend on whether "Other" was chosen 
916  * in the provider combobox on the account page
917  */
918 static void create_subsequent_pages (ModestEasysetupWizardDialog *self)
919 {
920         if (easysetup_provider_combo_box_get_active_provider_id (
921                 EASYSETUP_PROVIDER_COMBO_BOX (self->combo_account_serviceprovider)) == 0) {
922                 /* "Other..." was selected: */
923                 
924                 /* Make sure that the easysetup pages do not exist: */
925                 if(self->page_complete_easysetup) {
926                         gtk_widget_destroy (self->page_complete_easysetup);
927                         self->page_complete_easysetup = NULL;
928                 }
929                 
930                 create_subsequent_customsetup_pages (self);
931         }       
932         else {
933                 /* A specific provider was selected: */
934                 {
935                         /* Make sure that the custom pages do not exist:
936                          * Because they will be used if they exist, when creating the account. */
937                         if(self->page_custom_incoming) {
938                                 gtk_widget_destroy (self->page_custom_incoming);
939                                 self->page_custom_incoming = NULL;
940                         }
941                         
942                         if(self->page_custom_outgoing) {
943                                 gtk_widget_destroy (self->page_custom_outgoing);
944                                 self->page_custom_outgoing = NULL;
945                         }
946                         
947                         if(self->page_complete_customsetup) {
948                                 gtk_widget_destroy (self->page_complete_customsetup);
949                                 self->page_complete_customsetup = NULL;
950                         }
951                 }
952                 
953                 /* Create the easysetup pages: */
954                 create_subsequent_easysetup_pages (self);
955         }
956 }
957
958
959 static gchar*
960 util_get_default_servername_from_email_address (const gchar* email_address, ModestProtocol servertype)
961 {
962         if (!email_address)
963                 return NULL;
964         
965         gchar* at = g_utf8_strchr (email_address, -1, '@');
966         if (!at || (g_utf8_strlen (at, -1) < 2))
967                 return NULL;
968                 
969         gchar* domain = g_utf8_next_char (at);
970         if(!domain)
971                 return NULL;
972                 
973         const gchar* hostname = NULL;
974         if (servertype == MODEST_PROTOCOL_STORE_POP)
975                 hostname = "pop";
976         else if (servertype == MODEST_PROTOCOL_STORE_IMAP)
977                 hostname = "imap";
978         else if (servertype == MODEST_PROTOCOL_TRANSPORT_SMTP)
979                 hostname = "smtp";
980         
981         if (!hostname)
982                 return NULL;
983                 
984         return g_strdup_printf ("%s.%s", hostname, domain);
985 }
986
987 static void set_default_custom_servernames (ModestEasysetupWizardDialog *account_wizard)
988 {
989         if (!account_wizard->entry_incomingserver)
990                 return;
991                 
992         /* Set a default domain for the server, based on the email address,
993          * if no server name was already specified.
994          */
995         const gchar* incoming_existing = gtk_entry_get_text (GTK_ENTRY (account_wizard->entry_incomingserver));
996         if ((!incoming_existing || (strlen(incoming_existing) == 0)) 
997                 && account_wizard->entry_user_email) {
998                 const ModestProtocol protocol = easysetup_servertype_combo_box_get_active_servertype (
999                         EASYSETUP_SERVERTYPE_COMBO_BOX (account_wizard->combo_incoming_servertype));
1000                 const gchar* email_address = gtk_entry_get_text (GTK_ENTRY(account_wizard->entry_user_email));
1001                 
1002                 gchar* servername = util_get_default_servername_from_email_address (email_address, protocol);
1003                 gtk_entry_set_text (GTK_ENTRY (account_wizard->entry_incomingserver), servername);
1004                 g_free (servername);
1005         }
1006         
1007         /* Set a default domain for the server, based on the email address,
1008          * if no server name was already specified.
1009          */
1010         if (!account_wizard->entry_outgoingserver)
1011                 return;
1012                 
1013         const gchar* outgoing_existing = gtk_entry_get_text (GTK_ENTRY (account_wizard->entry_outgoingserver));
1014         if ((!outgoing_existing || (strlen(outgoing_existing) == 0)) 
1015                 && account_wizard->entry_user_email) {
1016                 const gchar* email_address = gtk_entry_get_text (GTK_ENTRY(account_wizard->entry_user_email));
1017                 
1018                 gchar* servername = util_get_default_servername_from_email_address (email_address, MODEST_PROTOCOL_TRANSPORT_SMTP);
1019                 gtk_entry_set_text (GTK_ENTRY (account_wizard->entry_outgoingserver), servername);
1020                 g_free (servername);
1021         }
1022 }
1023
1024 static gboolean
1025 on_before_next (ModestWizardDialog *dialog, GtkWidget *current_page, GtkWidget *next_page)
1026 {
1027         ModestEasysetupWizardDialog *account_wizard = MODEST_EASYSETUP_WIZARD_DIALOG (dialog);
1028         
1029         /* Do extra validation that couldn't be done for every key press,
1030          * either because it was too slow,
1031          * or because it requires interaction:
1032          */
1033         if (current_page == account_wizard->page_account_details) {     
1034                 /* Check that the title is not already in use: */
1035                 const gchar* account_title = gtk_entry_get_text (GTK_ENTRY (account_wizard->entry_account_title));
1036                 if ((!account_title) || (strlen(account_title) == 0))
1037                         return FALSE;
1038                         
1039                 /* Aavoid a clash with an existing display name: */
1040                 const gboolean name_in_use = modest_account_mgr_account_with_display_name_exists (
1041                         account_wizard->account_manager, account_title);
1042
1043                 if (name_in_use) {
1044                         /* Warn the user via a dialog: */
1045                         show_error (GTK_WINDOW (account_wizard), _("mail_ib_account_name_already_existing"));
1046             
1047                         return FALSE;
1048                 }
1049         }
1050         else if (current_page == account_wizard->page_user_details) {
1051                 /* Check that the email address is valud: */
1052                 const gchar* email_address = gtk_entry_get_text (GTK_ENTRY (account_wizard->entry_user_email));
1053                 if ((!email_address) || (strlen(email_address) == 0))
1054                         return FALSE;
1055                         
1056                 if (!modest_text_utils_validate_email_address (email_address)) {
1057                         /* Warn the user via a dialog: */
1058                         show_error (GTK_WINDOW (account_wizard), _("mcen_ib_invalid_email"));
1059                                              
1060             /* Return focus to the email address entry: */
1061             gtk_widget_grab_focus (account_wizard->entry_user_email);
1062             
1063                         return FALSE;
1064                 }
1065                 
1066                 /* Make sure that the subsequent pages are appropriate for the provider choice. */
1067                 create_subsequent_pages (account_wizard);
1068         }
1069         
1070         /* TODO: The UI Spec wants us to check that the servernames are valid, 
1071          * but does not specify how.
1072          */
1073           
1074         if(next_page == account_wizard->page_custom_incoming) {
1075                 set_default_custom_servernames (account_wizard);
1076         }
1077         else if (next_page == account_wizard->page_custom_outgoing) {
1078                 set_default_custom_servernames (account_wizard);
1079         }
1080         
1081         /* If this is the last page, and this is a click on Finish, 
1082          * then attempt to create the dialog.
1083          */
1084         if(!next_page) /* This is NULL when this is a click on Finish. */
1085         {
1086                 create_account (account_wizard);
1087         }
1088         
1089         
1090         return TRUE;
1091 }
1092
1093 static gboolean entry_is_empty (GtkWidget *entry)
1094 {
1095         if (!entry)
1096                 return FALSE;
1097                 
1098         const gchar* text = gtk_entry_get_text (GTK_ENTRY (entry));
1099         if ((!text) || (strlen(text) == 0))
1100                 return TRUE;
1101         else
1102                 return FALSE;
1103 }
1104
1105 static void
1106 on_enable_buttons (ModestWizardDialog *dialog, GtkWidget *current_page)
1107 {
1108         ModestEasysetupWizardDialog *account_wizard = MODEST_EASYSETUP_WIZARD_DIALOG (dialog);
1109         
1110         gboolean enable_next = TRUE;
1111         if (current_page == account_wizard->page_welcome) {
1112                 enable_next = TRUE;
1113         }
1114         else if (current_page == account_wizard->page_account_details) {
1115                 /* The account details title is mandatory: */
1116                 if (entry_is_empty(account_wizard->entry_account_title))
1117                         enable_next = FALSE;
1118         }
1119         else if (current_page == account_wizard->page_user_details) {   
1120                 /* The user details username is mandatory: */
1121                 if (entry_is_empty(account_wizard->entry_user_username))
1122                         enable_next = FALSE;
1123                         
1124                 /* The user details email address is mandatory: */
1125                 if (enable_next && entry_is_empty (account_wizard->entry_user_email))
1126                         enable_next = FALSE;
1127         }
1128         else if (current_page == account_wizard->page_custom_incoming) {
1129                 /* The custom incoming server is mandatory: */
1130                 if (entry_is_empty(account_wizard->entry_incomingserver))
1131                         enable_next = FALSE;
1132         }
1133                         
1134         /* Enable the buttons, 
1135          * identifying them via their associated response codes:
1136          */
1137         GtkDialog *dialog_base = GTK_DIALOG (dialog);
1138     gtk_dialog_set_response_sensitive (dialog_base,
1139                                        MODEST_WIZARD_DIALOG_NEXT,
1140                                        enable_next);
1141                                        
1142     /* Disable the Finish button until we are on the last page,
1143      * because HildonWizardDialog enables this for all but the first page: */
1144     GtkNotebook *notebook = NULL;
1145         g_object_get (dialog_base, "wizard-notebook", &notebook, NULL);
1146         
1147     gint current = gtk_notebook_get_current_page (notebook);
1148     gint last = gtk_notebook_get_n_pages (notebook) - 1;
1149     gboolean is_last = (current == last);
1150     
1151     if(!is_last) {
1152         gtk_dialog_set_response_sensitive (dialog_base,
1153                                        MODEST_WIZARD_DIALOG_FINISH,
1154                                        FALSE);
1155     }
1156 }
1157
1158 static void
1159 modest_easysetup_wizard_dialog_class_init (ModestEasysetupWizardDialogClass *klass)
1160 {
1161         GObjectClass *object_class = G_OBJECT_CLASS (klass);
1162         g_type_class_add_private (klass, sizeof (ModestEasysetupWizardDialogPrivate));
1163
1164
1165         object_class->get_property = modest_easysetup_wizard_dialog_get_property;
1166         object_class->set_property = modest_easysetup_wizard_dialog_set_property;
1167         object_class->dispose = modest_easysetup_wizard_dialog_dispose;
1168         object_class->finalize = modest_easysetup_wizard_dialog_finalize;
1169         
1170         /* Provide a vfunc implementation so we can decide 
1171          * when to enable/disable the prev/next buttons.
1172          */
1173         ModestWizardDialogClass *base_klass = (ModestWizardDialogClass*)(klass);
1174         base_klass->before_next = on_before_next;
1175         base_klass->enable_buttons = on_enable_buttons;
1176 }
1177  
1178 static void
1179 show_error (GtkWindow *parent_window, const gchar* text)
1180 {
1181         GtkDialog *dialog = GTK_DIALOG (gtk_message_dialog_new (parent_window,
1182                 (GtkDialogFlags)0,
1183                  GTK_MESSAGE_ERROR,
1184                  GTK_BUTTONS_OK,
1185                  text ));
1186                  
1187                  gtk_dialog_run (dialog);
1188                  gtk_widget_destroy (GTK_WIDGET (dialog));
1189 }
1190
1191 /** Attempt to create the account from the information that the user has entered.
1192  * @result: TRUE if the account was successfully created.
1193  */
1194 gboolean
1195 create_account (ModestEasysetupWizardDialog *self)
1196 {
1197         ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
1198         
1199         const gchar* display_name = gtk_entry_get_text (GTK_ENTRY (self->entry_account_title));
1200
1201         /* Some checks: */
1202         if (!display_name)
1203                 return FALSE;
1204                 
1205         /* We should have checked for this already, 
1206          * and changed that name accordingly, 
1207          * but let's check again just in case:
1208          */
1209         if (modest_account_mgr_account_with_display_name_exists (self->account_manager, display_name)) 
1210                 return FALSE;
1211
1212         /* Increment the non-user visible name if necessary, 
1213          * based on the display name: */
1214         gchar *account_name_start = g_strdup_printf ("%sID", display_name);
1215         gchar* account_name = modest_account_mgr_get_unused_account_name (self->account_manager,
1216                 account_name_start, FALSE /* not a server account */);
1217         g_free (account_name_start);
1218                 
1219         /* username and password (for both incoming and outgoing): */
1220         const gchar* username = gtk_entry_get_text (GTK_ENTRY (self->entry_user_username));
1221         const gchar* password = gtk_entry_get_text (GTK_ENTRY (self->entry_user_password));
1222         
1223         /* Incoming server: */
1224         /* Note: We need something as default for the ModestProtocol values, 
1225          * or modest_account_mgr_add_server_account will fail. */
1226         gchar* servername_incoming = NULL;
1227         ModestProtocol protocol_incoming = MODEST_PROTOCOL_STORE_POP;
1228         ModestProtocol protocol_security_incoming = MODEST_PROTOCOL_SECURITY_NONE;
1229         ModestProtocol protocol_authentication_incoming = MODEST_PROTOCOL_AUTH_NONE;
1230         
1231         /* Get details from the specified presets: */
1232         gchar* provider_id = easysetup_provider_combo_box_get_active_provider_id (
1233                 EASYSETUP_PROVIDER_COMBO_BOX (self->combo_account_serviceprovider));
1234         if(provider_id) {
1235                 /* Use presets: */
1236                 
1237                 servername_incoming = modest_presets_get_server (priv->presets, provider_id, 
1238                         TRUE /* incoming */);
1239                 
1240                 ModestPresetsServerType servertype_incoming = modest_presets_get_info_server_type (priv->presets, provider_id, 
1241                         TRUE /* incoming */);
1242                 
1243         
1244                 /* We don't check for SMTP here as that is impossible for an incoming server. */
1245                 if (servertype_incoming == MODEST_PRESETS_SERVER_TYPE_IMAP)
1246                         protocol_incoming = MODEST_PROTOCOL_STORE_IMAP;
1247                 else if (servertype_incoming == MODEST_PRESETS_SERVER_TYPE_POP)
1248                         protocol_incoming = MODEST_PROTOCOL_STORE_POP;
1249                                 
1250                 ModestPresetsSecurity security_incoming = modest_presets_get_info_server_security (priv->presets, provider_id, 
1251                         TRUE /* incoming */);
1252                         
1253                 
1254                 if (security_incoming & MODEST_PRESETS_SECURITY_SECURE_INCOMING)
1255                         protocol_security_incoming = MODEST_PROTOCOL_SECURITY_SSL; /* TODO: Is this what we want? */
1256                 
1257                 if (security_incoming & MODEST_PRESETS_SECURITY_APOP)
1258                         protocol_authentication_incoming = MODEST_PROTOCOL_AUTH_PASSWORD; /* TODO: Is this what we want? */
1259         }
1260         else {
1261                 /* Use custom pages because no preset was specified: */
1262                 servername_incoming = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry_incomingserver) ));
1263                 
1264                 protocol_incoming = easysetup_servertype_combo_box_get_active_servertype (
1265                 EASYSETUP_SERVERTYPE_COMBO_BOX (self->combo_incoming_servertype));
1266                 
1267                 protocol_security_incoming = modest_serversecurity_combo_box_get_active_serversecurity (
1268                 MODEST_SERVERSECURITY_COMBO_BOX (self->combo_incoming_security));
1269                 
1270                 protocol_authentication_incoming = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->checkbox_incoming_auth)) 
1271                         ? MODEST_PROTOCOL_AUTH_PASSWORD
1272                         : MODEST_PROTOCOL_AUTH_NONE;
1273                 
1274         }
1275         
1276         /* First we add the 2 server accounts, and then we add the account that uses them.
1277          * If we don't do it in this order then we will experience a crash. */
1278          
1279         /* Add a (incoming) server account, to be used by the account: */
1280         gchar *store_name_start = g_strconcat (account_name, "_store", NULL);
1281         gchar *store_name = modest_account_mgr_get_unused_account_name (self->account_manager, 
1282                 store_name_start, TRUE /* server account */);
1283         g_free (store_name_start);
1284         gboolean created = modest_account_mgr_add_server_account (self->account_manager,
1285                 store_name,
1286                 servername_incoming,
1287                 username, password,
1288                 protocol_incoming,
1289                 protocol_security_incoming,
1290                 protocol_authentication_incoming);              
1291                 
1292         g_free (servername_incoming);
1293         
1294         if (!created) {
1295                 /* TODO: Provide a Logical ID for the text: */
1296                 show_error (GTK_WINDOW (self), _("An error occurred while creating the incoming account."));
1297                 return FALSE;   
1298         }
1299         
1300         /* Sanity check: */
1301         /* There must be at least one account now: */
1302         GSList *account_names = modest_account_mgr_account_names (self->account_manager);
1303         if(!account_names)
1304         {
1305                 g_warning ("modest_account_mgr_account_names() returned NULL after adding an account.");
1306         }
1307         g_slist_free (account_names);
1308         
1309         
1310         /* Outgoing server: */
1311         gchar* servername_outgoing = NULL;
1312         ModestProtocol protocol_outgoing = MODEST_PROTOCOL_STORE_POP;
1313         ModestProtocol protocol_security_outgoing = MODEST_PROTOCOL_SECURITY_NONE;
1314         ModestProtocol protocol_authentication_outgoing = MODEST_PROTOCOL_AUTH_NONE;
1315         
1316         if(provider_id) {
1317                 /* Use presets: */
1318                 servername_outgoing = modest_presets_get_server (priv->presets, provider_id, 
1319                         FALSE /* incoming */);
1320                         
1321                 ModestPresetsServerType servertype_outgoing = modest_presets_get_info_server_type (priv->presets, provider_id, 
1322                         FALSE /* incoming */);
1323                 
1324                 /* Note: We need something as default, or modest_account_mgr_add_server_account will fail. */
1325                 protocol_outgoing = MODEST_PROTOCOL_TRANSPORT_SENDMAIL; 
1326                 if (servertype_outgoing == MODEST_PRESETS_SERVER_TYPE_SMTP)
1327                         protocol_outgoing = MODEST_PROTOCOL_TRANSPORT_SMTP;
1328                 
1329                 ModestPresetsSecurity security_outgoing = 
1330                         modest_presets_get_info_server_security (priv->presets, provider_id, 
1331                                 FALSE /* incoming */);
1332                         
1333                 protocol_security_outgoing = MODEST_PROTOCOL_SECURITY_NONE;
1334                 if (security_outgoing & MODEST_PRESETS_SECURITY_SECURE_SMTP)
1335                         protocol_security_outgoing = MODEST_PROTOCOL_SECURITY_SSL; /* TODO: Is this what we want? */
1336                 
1337                 protocol_authentication_outgoing = MODEST_PROTOCOL_AUTH_NONE;
1338                 /* TODO: There is no SMTP authentication enum for presets. */
1339         }
1340         else {
1341                 /* Use custom pages because no preset was specified: */
1342                 servername_outgoing = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry_outgoingserver) ));
1343                 
1344                 protocol_outgoing = MODEST_PROTOCOL_TRANSPORT_SMTP; /* It's always SMTP for outgoing. */
1345
1346                 protocol_security_outgoing = modest_serversecurity_combo_box_get_active_serversecurity (
1347                         MODEST_SERVERSECURITY_COMBO_BOX (self->combo_outgoing_security));
1348                 
1349                 protocol_authentication_outgoing = modest_secureauth_combo_box_get_active_secureauth (
1350                         MODEST_SECUREAUTH_COMBO_BOX (self->combo_outgoing_auth));
1351         }
1352             
1353         /* Add a (outgoing) server account to be used by the account: */
1354         gchar *transport_name_start = g_strconcat (account_name, "_transport", NULL);
1355         gchar *transport_name = modest_account_mgr_get_unused_account_name (self->account_manager, 
1356                 transport_name_start, TRUE /* server account */);
1357         g_free (transport_name_start);
1358         created = modest_account_mgr_add_server_account (self->account_manager,
1359                 transport_name,
1360                 servername_outgoing,
1361                 username, password,
1362                 protocol_outgoing,
1363                 protocol_security_outgoing,
1364                 protocol_authentication_outgoing);
1365                 
1366         g_free (servername_outgoing);
1367                 
1368         if (!created) {
1369                 /* TODO: Provide a Logical ID for the text: */
1370                 show_error (GTK_WINDOW (self), _("An error occurred while creating the outgoing account."));
1371                 return FALSE;   
1372         }
1373         
1374         
1375         /* Create the account, which will contain the two "server accounts": */
1376         created = modest_account_mgr_add_account (self->account_manager, account_name, 
1377                 store_name, /* The name of our POP/IMAP server account. */
1378                 transport_name /* The name of our SMTP server account. */);
1379         g_free (store_name);
1380         g_free (transport_name);
1381         
1382         if (!created) {
1383                 /* TODO: Provide a Logical ID for the text: */
1384                 show_error (GTK_WINDOW (self), _("An error occurred while creating the account."));
1385                 return FALSE;   
1386         }
1387         
1388         /* The user name and email address must be set additionally: */
1389         const gchar* user_name = gtk_entry_get_text (GTK_ENTRY (self->entry_user_name));
1390         modest_account_mgr_set_string (self->account_manager, account_name,
1391                 MODEST_ACCOUNT_FULLNAME, user_name, FALSE /* not server account */);
1392
1393         const gchar* emailaddress = gtk_entry_get_text (GTK_ENTRY (self->entry_user_email));
1394         modest_account_mgr_set_string (self->account_manager, account_name,
1395                 MODEST_ACCOUNT_EMAIL, emailaddress, FALSE /* not server account */);
1396
1397         /* Set the display name: */
1398         modest_account_mgr_set_string (self->account_manager, account_name,
1399                 MODEST_ACCOUNT_DISPLAY_NAME, display_name, FALSE /* not server account */);
1400
1401         /* Save the connection-specific SMTP server accounts. */
1402         gboolean result = TRUE;
1403         if (self->specific_window)
1404                 result = modest_connection_specific_smtp_window_save_server_accounts (
1405                         MODEST_CONNECTION_SPECIFIC_SMTP_WINDOW (self->specific_window), account_name);
1406                         
1407         g_free (self->saved_account_name);
1408         self->saved_account_name = g_strdup (account_name);
1409         
1410         g_free (account_name);
1411
1412         return result;
1413 }
1414
1415