6c6ab474524aa1a2c16722884fa2cb07da540c73
[modest] / src / hildon2 / modest-easysetup-wizard-dialog.c
1
2 /* Copyright (c) 2006, Nokia Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  * * Neither the name of the Nokia Corporation nor the names of its
15  *   contributors may be used to endorse or promote products derived from
16  *   this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30  
31 #include <config.h>
32 #include "modest-easysetup-wizard-dialog.h"
33 #include <glib/gi18n.h>
34 #include <gtk/gtknotebook.h>
35 #include <gtk/gtkvbox.h>
36 #include <gtk/gtklabel.h>
37 #include <gtk/gtkentry.h>
38 #include <gtk/gtkbutton.h>
39 #include <gtk/gtkcheckbutton.h>
40 #include <gtk/gtkmessagedialog.h>
41 #include <gtk/gtkseparator.h>
42 #include "modest-country-picker.h"
43 #include "modest-provider-picker.h"
44 #include "modest-servertype-picker.h"
45 #include "widgets/modest-validating-entry.h"
46 #include "modest-text-utils.h"
47 #include "modest-conf.h"
48 #include "modest-defs.h"
49 #include "modest-account-mgr.h"
50 #include "modest-signal-mgr.h"
51 #include "modest-account-mgr-helpers.h"
52 #include "modest-runtime.h" /* For modest_runtime_get_account_mgr(). */
53 #include "modest-connection-specific-smtp-window.h"
54 #include "widgets/modest-ui-constants.h"
55 #include "widgets/modest-default-account-settings-dialog.h"
56 #include "widgets/modest-easysetup-wizard-page.h"
57 #include "modest-maemo-utils.h"
58 #include "modest-utils.h"
59 #include "modest-hildon-includes.h"
60 #include "modest-maemo-security-options-view.h"
61 #include <modest-account-protocol.h>
62
63 /* Include config.h so that _() works: */
64 #ifdef HAVE_CONFIG_H
65 #include <config.h>
66 #endif
67
68 G_DEFINE_TYPE (ModestEasysetupWizardDialog, modest_easysetup_wizard_dialog, MODEST_TYPE_WIZARD_DIALOG);
69
70 #define MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
71                                                     MODEST_TYPE_EASYSETUP_WIZARD_DIALOG, \
72                                                     ModestEasysetupWizardDialogPrivate))
73
74 typedef struct _ModestEasysetupWizardDialogPrivate ModestEasysetupWizardDialogPrivate;
75
76
77 typedef enum {
78         MODEST_EASYSETUP_WIZARD_DIALOG_INCOMING_CHANGED = 0x01,
79         MODEST_EASYSETUP_WIZARD_DIALOG_OUTGOING_CHANGED = 0x02
80 } ModestEasysetupWizardDialogServerChanges;
81
82 struct _ModestEasysetupWizardDialogPrivate
83 {
84         ModestPresets *presets;
85
86         /* Remember what fields the user edited manually to not prefill them
87          * again. */
88         ModestEasysetupWizardDialogServerChanges server_changes;
89         
90         /* Check if the user changes a field to show a confirmation dialog */
91         gboolean dirty;
92
93         /* If we have a pending load of settings or not. */
94         gboolean pending_load_settings;
95         
96         /* Used by derived widgets to query existing accounts,
97          * and to create new accounts: */
98         ModestAccountMgr *account_manager;
99         ModestAccountSettings *settings;
100         
101         /* notebook pages: */
102         GtkWidget *page_welcome;
103         
104         GtkWidget *page_account_details;
105         GtkWidget *account_country_picker;
106         GtkWidget *account_serviceprovider_picker;
107         GtkWidget *entry_account_title;
108         
109         GtkWidget *page_user_details;
110         GtkWidget *entry_user_name;
111         GtkWidget *entry_user_username;
112         GtkWidget *entry_user_password;
113         GtkWidget *entry_user_email;
114         
115         GtkWidget *page_complete_easysetup;
116         
117         GtkWidget *page_custom_incoming;
118         GtkWidget *incoming_servertype_picker;
119         GtkWidget *caption_incoming;
120         GtkWidget *entry_incomingserver;
121
122         /* Security widgets */
123         GtkWidget *incoming_security;
124         GtkWidget *outgoing_security;
125
126         GtkWidget *page_custom_outgoing;
127         GtkWidget *entry_outgoingserver;
128         GtkWidget *checkbox_outgoing_smtp_specific;
129         GtkWidget *button_outgoing_smtp_servers;
130         
131         GtkWidget *page_complete_customsetup;
132
133         ModestProtocolType last_plugin_protocol_selected;
134         GSList *missing_data_signals;
135 };
136
137 static void save_to_settings (ModestEasysetupWizardDialog *self);
138 static void real_enable_buttons (ModestWizardDialog *dialog, gboolean enable_next);
139
140 static gboolean
141 on_delete_event (GtkWidget *widget,
142                  GdkEvent *event,
143                  ModestEasysetupWizardDialog *wizard)
144 {
145         gtk_dialog_response (GTK_DIALOG (wizard), GTK_RESPONSE_CANCEL);
146         return TRUE;
147 }
148
149 static void
150 on_easysetup_changed(GtkWidget* widget, ModestEasysetupWizardDialog* wizard)
151 {
152         ModestEasysetupWizardDialogPrivate* priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(wizard);
153         g_return_if_fail (priv != NULL);
154         priv->dirty = TRUE;
155 }
156
157 static void
158 modest_easysetup_wizard_dialog_dispose (GObject *object)
159 {
160         if (G_OBJECT_CLASS (modest_easysetup_wizard_dialog_parent_class)->dispose)
161                 G_OBJECT_CLASS (modest_easysetup_wizard_dialog_parent_class)->dispose (object);
162 }
163
164 static void
165 modest_easysetup_wizard_dialog_finalize (GObject *object)
166 {
167         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (object);
168         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
169         
170         if (priv->account_manager)
171                 g_object_unref (G_OBJECT (priv->account_manager));
172                 
173         if (priv->presets)
174                 modest_presets_destroy (priv->presets);
175
176         if (priv->settings)
177                 g_object_unref (priv->settings);
178
179         if (priv->missing_data_signals) {
180                 modest_signal_mgr_disconnect_all_and_destroy (priv->missing_data_signals);
181                 priv->missing_data_signals = NULL;
182         }
183                 
184         G_OBJECT_CLASS (modest_easysetup_wizard_dialog_parent_class)->finalize (object);
185 }
186
187 static void
188 create_subsequent_easysetup_pages (ModestEasysetupWizardDialog *self);
189
190 static void
191 set_default_custom_servernames(ModestEasysetupWizardDialog *dialog);
192
193 static void on_servertype_selector_changed(HildonTouchSelector *selector, gint column, gpointer user_data);
194
195 static gint 
196 get_port_from_protocol (ModestProtocolType server_type,
197                         gboolean alternate_port)
198 {
199         int server_port = 0;
200         ModestProtocol *protocol;
201         ModestProtocolRegistry *protocol_registry;
202
203         protocol_registry = modest_runtime_get_protocol_registry ();
204         protocol = modest_protocol_registry_get_protocol_by_type (protocol_registry, server_type);
205
206         if (alternate_port) {
207                 server_port = modest_account_protocol_get_alternate_port (MODEST_ACCOUNT_PROTOCOL (protocol));
208         } else {
209                 server_port = modest_account_protocol_get_port (MODEST_ACCOUNT_PROTOCOL (protocol));
210         }
211         return server_port;
212 }
213
214 static void
215 invoke_enable_buttons_vfunc (ModestEasysetupWizardDialog *wizard_dialog)
216 {
217         ModestWizardDialogClass *klass = MODEST_WIZARD_DIALOG_GET_CLASS (wizard_dialog);
218         
219         /* Call the vfunc, which may be overridden by derived classes: */
220         if (klass->enable_buttons) {
221                 GtkNotebook *notebook = NULL;
222                 g_object_get (wizard_dialog, "wizard-notebook", &notebook, NULL);
223                 
224                 const gint current_page_num = gtk_notebook_get_current_page (notebook);
225                 if (current_page_num == -1)
226                         return;
227                         
228                 GtkWidget* current_page_widget = gtk_notebook_get_nth_page (notebook, current_page_num);
229                 (*(klass->enable_buttons))(MODEST_WIZARD_DIALOG (wizard_dialog), current_page_widget);
230         }
231 }
232
233 static void
234 on_caption_entry_changed (GtkEditable *editable, gpointer user_data)
235 {
236         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
237         g_assert(self);
238         invoke_enable_buttons_vfunc(self);
239 }
240
241 static void
242 on_caption_combobox_changed (GtkComboBox *widget, gpointer user_data)
243 {
244         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
245         g_assert(self);
246         invoke_enable_buttons_vfunc(self);
247 }
248
249 static void
250 on_picker_button_value_changed (HildonPickerButton *widget, gpointer user_data)
251 {
252         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
253         g_assert(self);
254         invoke_enable_buttons_vfunc(self);
255 }
256
257 /** This is a convenience function to create a caption containing a mandatory widget.
258  * When the widget is edited, the enable_buttons() vfunc will be called.
259  */
260 static GtkWidget* 
261 create_captioned (ModestEasysetupWizardDialog *self,
262                   GtkSizeGroup *group,
263                   const gchar *value,
264                   GtkWidget *control)
265 {
266
267         GtkWidget *result;
268         result = modest_maemo_utils_create_captioned (group, value, control);
269
270         /* Connect to the appropriate changed signal for the widget, 
271          * so we can ask for the prev/next buttons to be enabled/disabled appropriately:
272          */
273         if (GTK_IS_ENTRY (control)) {
274                 g_signal_connect (G_OBJECT (control), "changed",
275                                   G_CALLBACK (on_caption_entry_changed), self);
276                 
277         }
278         else if (GTK_IS_COMBO_BOX (control)) {
279                 g_signal_connect (G_OBJECT (control), "changed",
280                                   G_CALLBACK (on_caption_combobox_changed), self);
281         }
282          
283         return result;
284 }
285            
286 static GtkWidget*
287 create_page_welcome (ModestEasysetupWizardDialog *self)
288 {
289         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_NONE);
290         GtkWidget *label = gtk_label_new(_("mcen_ia_emailsetup_intro"));
291         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
292         /* So that it is not truncated: */
293         gtk_widget_set_size_request (label, 600, -1);
294         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
295         gtk_widget_show (label);
296         gtk_widget_show (GTK_WIDGET (box));
297         return GTK_WIDGET (box);
298 }
299
300 static void
301 on_account_country_selector_changed (HildonTouchSelector *widget, gint column, gpointer user_data)
302 {
303         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
304         g_assert(self);
305         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
306         
307         priv->dirty = TRUE;
308         
309         /* Fill the providers picker, based on the selected country: */
310         if (priv->presets != NULL) {
311                 gint mcc = modest_country_picker_get_active_country_mcc (
312                         MODEST_COUNTRY_PICKER (priv->account_country_picker));
313                 modest_provider_picker_fill (
314                         MODEST_PROVIDER_PICKER (priv->account_serviceprovider_picker), priv->presets, mcc);
315         }
316 }
317
318 static void
319 on_account_serviceprovider_selector_changed (HildonTouchSelector *widget, gint column, gpointer user_data)
320 {
321         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
322         g_assert(self);
323         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
324         
325         priv->dirty = TRUE;
326         
327         /* Fill the providers combo, based on the selected country: */
328         gchar* provider_id = modest_provider_picker_get_active_provider_id (
329                 MODEST_PROVIDER_PICKER (priv->account_serviceprovider_picker));
330         
331         gchar* domain_name = NULL;
332         if(provider_id)
333                 domain_name = modest_presets_get_domain (priv->presets, provider_id);
334         
335         if(!domain_name)
336                 domain_name = g_strdup (MODEST_EXAMPLE_EMAIL_ADDRESS);
337                 
338         if (priv->entry_user_email)
339                 gtk_entry_set_text (GTK_ENTRY (priv->entry_user_email), domain_name);
340                 
341         g_free (domain_name);
342         
343         g_free (provider_id);
344 }
345
346 static void
347 on_entry_max (ModestValidatingEntry *self, gpointer user_data)
348 {
349         modest_platform_information_banner (GTK_WIDGET (self), NULL,
350                                             _CS("ckdg_ib_maximum_characters_reached"));
351 }
352
353 static GtkWidget*
354 create_page_account_details (ModestEasysetupWizardDialog *self)
355 {
356         GtkWidget *caption;
357         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_NONE);
358         GtkWidget *label = gtk_label_new(_("mcen_ia_accountdetails"));
359         ModestEasysetupWizardDialogPrivate* priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(self);
360
361         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
362         gtk_widget_set_size_request (label, 600, -1);
363         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, MODEST_MARGIN_HALF);
364         gtk_widget_show (label);
365
366         /* Create a size group to be used by all captions.
367          * Note that HildonCaption does not create a default size group if we do not specify one.
368          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
369         GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
370
371         /* The country widgets: */
372         priv->account_country_picker = GTK_WIDGET (modest_country_picker_new (MODEST_EDITABLE_SIZE,
373                                                                               MODEST_EDITABLE_ARRANGEMENT));
374         hildon_button_set_title (HILDON_BUTTON (priv->account_country_picker), _("mcen_fi_country"));
375         g_signal_connect (G_OBJECT (priv->account_country_picker), "value-changed",
376                           G_CALLBACK (on_picker_button_value_changed), self);
377         gtk_box_pack_start (GTK_BOX (box), priv->account_country_picker, FALSE, FALSE, MODEST_MARGIN_HALF);
378         gtk_widget_show (priv->account_country_picker);
379         
380         GtkWidget *separator = gtk_hseparator_new ();
381         gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, MODEST_MARGIN_HALF);
382         gtk_widget_show (separator);
383             
384         /* The service provider widgets: */     
385         priv->account_serviceprovider_picker = GTK_WIDGET (modest_provider_picker_new (MODEST_EDITABLE_SIZE,
386                                                                                        MODEST_EDITABLE_ARRANGEMENT));
387         hildon_button_set_title (HILDON_BUTTON (priv->account_serviceprovider_picker), _("mcen_fi_serviceprovider"));
388         g_signal_connect (G_OBJECT (priv->account_serviceprovider_picker), "value-changed",
389                           G_CALLBACK (on_picker_button_value_changed), self);
390         gtk_box_pack_start (GTK_BOX (box), priv->account_serviceprovider_picker, FALSE, FALSE, MODEST_MARGIN_HALF);
391         gtk_widget_show (priv->account_serviceprovider_picker);
392         
393         /* The description widgets: */  
394         priv->entry_account_title = GTK_WIDGET (modest_validating_entry_new ());
395         g_signal_connect(G_OBJECT(priv->entry_account_title), "changed",
396                          G_CALLBACK(on_easysetup_changed), self);
397         /* Do use auto-capitalization: */
398         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->entry_account_title), 
399                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
400         
401         /* Set a default account title, choosing one that does not already exist: */
402         /* Note that this is irrelevant to the non-user visible name, which we will create later. */
403         gchar* default_account_name_start = g_strdup (_("mcen_ia_emailsetup_defaultname"));
404         gchar* default_account_name = modest_account_mgr_get_unused_account_display_name (
405                 priv->account_manager, default_account_name_start);
406         g_free (default_account_name_start);
407         default_account_name_start = NULL;
408         
409         gtk_entry_set_text( GTK_ENTRY (priv->entry_account_title), default_account_name);
410         g_free (default_account_name);
411         default_account_name = NULL;
412
413         caption = create_captioned (self, sizegroup, _("mcen_fi_account_title"), 
414                                     priv->entry_account_title);
415         gtk_widget_show (priv->entry_account_title);
416         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
417         gtk_widget_show (caption);
418         
419         /* Prevent the use of some characters in the account title, 
420          * as required by our UI specification: */
421         GList *list_prevent = NULL;
422         list_prevent = g_list_append (list_prevent, "\\");
423         list_prevent = g_list_append (list_prevent, "/");
424         list_prevent = g_list_append (list_prevent, ":");
425         list_prevent = g_list_append (list_prevent, "*");
426         list_prevent = g_list_append (list_prevent, "?");
427         list_prevent = g_list_append (list_prevent, "\""); /* The UI spec mentions â€œ, but maybe means ", maybe both. */
428         list_prevent = g_list_append (list_prevent, "“");
429         list_prevent = g_list_append (list_prevent, "<"); 
430         list_prevent = g_list_append (list_prevent, ">"); 
431         list_prevent = g_list_append (list_prevent, "|");
432         list_prevent = g_list_append (list_prevent, "^");       
433         modest_validating_entry_set_unallowed_characters (
434                 MODEST_VALIDATING_ENTRY (priv->entry_account_title), list_prevent);
435         g_list_free (list_prevent);
436         list_prevent = NULL;
437         modest_validating_entry_set_func(MODEST_VALIDATING_ENTRY(priv->entry_account_title),
438                                                                                                                                          modest_utils_on_entry_invalid_character, self);
439         
440         /* Set max length as in the UI spec:
441          * The UI spec seems to want us to show a dialog if we hit the maximum. */
442         gtk_entry_set_max_length (GTK_ENTRY (priv->entry_account_title), 64);
443         modest_validating_entry_set_max_func (MODEST_VALIDATING_ENTRY (priv->entry_account_title), 
444                                               on_entry_max, self);
445         
446         gtk_widget_show (GTK_WIDGET (box));
447         
448         return GTK_WIDGET (box);
449 }
450
451 static GtkWidget*
452 create_page_user_details (ModestEasysetupWizardDialog *self)
453 {
454         GtkSizeGroup* sizegroup;
455         GtkWidget *box;
456         ModestEasysetupWizardDialogPrivate *priv;
457
458         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(self);
459         
460         /* Create a size group to be used by all captions.
461          * Note that HildonCaption does not create a default size group if we do not specify one.
462          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
463         box = gtk_vbox_new (FALSE, MODEST_MARGIN_NONE);
464         sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
465          
466         /* The name widgets: (use auto cap) */
467         priv->entry_user_name = GTK_WIDGET (modest_validating_entry_new ());
468         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->entry_user_name), 
469                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
470         
471         /* Set max length as in the UI spec:
472          * The UI spec seems to want us to show a dialog if we hit the maximum. */
473         gtk_entry_set_max_length (GTK_ENTRY (priv->entry_user_name), 64);
474         modest_validating_entry_set_max_func (MODEST_VALIDATING_ENTRY (priv->entry_user_name), 
475                                               on_entry_max, self);
476         GtkWidget *caption = create_captioned (self, sizegroup, 
477                                                _("mcen_li_emailsetup_name"), priv->entry_user_name);
478         g_signal_connect(G_OBJECT(priv->entry_user_name), "changed", 
479                          G_CALLBACK(on_easysetup_changed), self);
480         gtk_widget_show (priv->entry_user_name);
481         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
482         gtk_widget_show (caption);
483         
484         /* Prevent the use of some characters in the name, 
485          * as required by our UI specification: */
486         GList *list_prevent = NULL;
487         list_prevent = g_list_append (list_prevent, "<");
488         list_prevent = g_list_append (list_prevent, ">");
489         modest_validating_entry_set_unallowed_characters (
490                 MODEST_VALIDATING_ENTRY (priv->entry_user_name), list_prevent);
491         modest_validating_entry_set_func(MODEST_VALIDATING_ENTRY(priv->entry_user_name),
492                 modest_utils_on_entry_invalid_character, self);
493         g_list_free (list_prevent);
494         
495         /* The username widgets: */     
496         priv->entry_user_username = GTK_WIDGET (modest_validating_entry_new ());
497         /* Auto-capitalization is the default, so let's turn it off: */
498         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->entry_user_username), 
499                                          HILDON_GTK_INPUT_MODE_FULL);
500         caption = create_captioned (self, sizegroup, _("mail_fi_username"), 
501                                     priv->entry_user_username);
502         gtk_widget_show (priv->entry_user_username);
503         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
504         g_signal_connect(G_OBJECT(priv->entry_user_username), "changed", 
505                          G_CALLBACK(on_easysetup_changed), self);
506         gtk_widget_show (caption);
507         
508         /* Prevent the use of some characters in the username, 
509          * as required by our UI specification: */
510         modest_validating_entry_set_unallowed_characters_whitespace (
511                 MODEST_VALIDATING_ENTRY (priv->entry_user_username));
512         modest_validating_entry_set_func(MODEST_VALIDATING_ENTRY(priv->entry_user_username),
513                 modest_utils_on_entry_invalid_character, self);
514         
515         /* Set max length as in the UI spec:
516          * The UI spec seems to want us to show a dialog if we hit the maximum. */
517         gtk_entry_set_max_length (GTK_ENTRY (priv->entry_user_username), 64);
518         modest_validating_entry_set_max_func (MODEST_VALIDATING_ENTRY (priv->entry_user_username), 
519                                               on_entry_max, self);
520         
521         /* The password widgets: */     
522         priv->entry_user_password = gtk_entry_new ();
523         /* Auto-capitalization is the default, so let's turn it off: */
524         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->entry_user_password), 
525                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_INVISIBLE);
526         gtk_entry_set_visibility (GTK_ENTRY (priv->entry_user_password), FALSE);
527         /* gtk_entry_set_invisible_char (GTK_ENTRY (priv->entry_user_password), '*'); */
528         caption = create_captioned (self, sizegroup, 
529                                     _("mail_fi_password"), priv->entry_user_password);
530         g_signal_connect(G_OBJECT(priv->entry_user_password), "changed", 
531                          G_CALLBACK(on_easysetup_changed), self);
532         gtk_widget_show (priv->entry_user_password);
533         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
534         gtk_widget_show (caption);
535         
536         /* The email address widgets: */        
537         priv->entry_user_email = GTK_WIDGET (modest_validating_entry_new ());
538         /* Auto-capitalization is the default, so let's turn it off: */
539         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->entry_user_email), HILDON_GTK_INPUT_MODE_FULL);
540         caption = create_captioned (self, sizegroup, 
541                                     _("mcen_li_emailsetup_email_address"), priv->entry_user_email);
542         gtk_entry_set_text (GTK_ENTRY (priv->entry_user_email), MODEST_EXAMPLE_EMAIL_ADDRESS); /* Default text. */
543         gtk_widget_show (priv->entry_user_email);
544         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
545         g_signal_connect(G_OBJECT(priv->entry_user_email), "changed", 
546                          G_CALLBACK(on_easysetup_changed), self);
547         gtk_widget_show (caption);
548         
549         /* Set max length as in the UI spec:
550          * The UI spec seems to want us to show a dialog if we hit the maximum. */
551         gtk_entry_set_max_length (GTK_ENTRY (priv->entry_user_email), 64);
552         modest_validating_entry_set_max_func (MODEST_VALIDATING_ENTRY (priv->entry_user_email), 
553                                               on_entry_max, self);
554         
555         
556         gtk_widget_show (GTK_WIDGET (box));
557         
558         return GTK_WIDGET (box);
559 }
560
561 static GtkWidget* 
562 create_page_complete_easysetup (ModestEasysetupWizardDialog *self)
563 {
564         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_NONE);
565         
566         GtkWidget *label = gtk_label_new(_("mcen_ia_emailsetup_setup_complete"));
567         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
568         gtk_widget_set_size_request (label, 600, -1);
569         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
570         /* The documentation for gtk_label_set_line_wrap() says that we must 
571          * call gtk_widget_set_size_request() with a hard-coded width, 
572          * though I wonder why gtk_label_set_max_width_chars() isn't enough. */
573         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
574         gtk_widget_show (label);
575         
576         label = gtk_label_new (_("mcen_ia_easysetup_complete"));
577         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
578         gtk_widget_set_size_request (label, 600, -1);
579         
580         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
581         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
582         gtk_widget_show (label);
583         
584         gtk_widget_show (GTK_WIDGET (box));
585         return GTK_WIDGET (box);
586 }
587
588 /** Change the caption title for the incoming server, 
589  * as specified in the UI spec:
590  */
591 static void 
592 update_incoming_server_title (ModestEasysetupWizardDialog *self)
593 {
594         ModestEasysetupWizardDialogPrivate* priv; 
595         ModestProtocolType protocol_type; 
596         ModestProtocolRegistry *protocol_registry;
597
598         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(self);
599         protocol_registry = modest_runtime_get_protocol_registry ();
600         
601         protocol_type = modest_servertype_picker_get_active_servertype (
602                 MODEST_SERVERTYPE_PICKER (priv->incoming_servertype_picker));
603
604         /* This could happen when the combo box has still no active iter */
605         if (protocol_type != MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
606                 gchar* incomingserver_title;
607                 const gchar *protocol_display_name; 
608
609                 protocol_display_name = modest_protocol_get_display_name (modest_protocol_registry_get_protocol_by_type (protocol_registry, protocol_type));
610                 
611                 incomingserver_title = g_strdup_printf(_("mcen_li_emailsetup_servertype"), protocol_display_name);
612                 g_object_set (G_OBJECT (priv->caption_incoming), "label", incomingserver_title, NULL);
613                 g_free(incomingserver_title);
614         }
615 }
616
617 /** Change the caption title for the incoming server, 
618  * as specified in the UI spec:
619  */
620 static void 
621 update_incoming_server_security_choices (ModestEasysetupWizardDialog *self)
622 {
623         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(self);
624         ModestServertypePicker *server_type_picker;
625         ModestProtocolType protocol_type;
626         ModestSecurityOptionsView *view;
627
628         server_type_picker = 
629                 MODEST_SERVERTYPE_PICKER (priv->incoming_servertype_picker);
630         protocol_type = 
631                 modest_servertype_picker_get_active_servertype (server_type_picker);
632         
633         /* Fill the combo with appropriately titled choices for all
634            those protocols */
635         view = MODEST_SECURITY_OPTIONS_VIEW (priv->incoming_security);
636         modest_security_options_view_set_server_type (view, protocol_type);
637 }
638
639 static void 
640 on_servertype_selector_changed(HildonTouchSelector *selector, gint column, gpointer user_data)
641 {
642         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
643         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(self);
644         ModestServertypePicker *picker;
645         ModestProtocolType protocol_type;
646
647         priv->dirty = TRUE;
648         
649         /* Update title */
650         update_incoming_server_title (self);
651
652         /* Update security options if needed */
653         picker = MODEST_SERVERTYPE_PICKER (priv->incoming_servertype_picker);
654         protocol_type = modest_servertype_picker_get_active_servertype (picker);
655         update_incoming_server_security_choices (self);
656         gtk_widget_show (priv->incoming_security);
657
658         set_default_custom_servernames (self);
659 }
660
661 static void 
662 on_entry_incoming_servername_changed(GtkEntry *entry, gpointer user_data)
663 {
664         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
665         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
666         priv->dirty = TRUE;
667         priv->server_changes |= MODEST_EASYSETUP_WIZARD_DIALOG_INCOMING_CHANGED;
668 }
669
670 static GtkWidget* 
671 create_page_custom_incoming (ModestEasysetupWizardDialog *self)
672 {
673         ModestProtocolRegistry *protocol_registry;
674         ModestEasysetupWizardDialogPrivate* priv; 
675         GtkWidget *box; 
676         GtkWidget *scrolled_window;
677         GtkWidget *label;
678         GtkSizeGroup *sizegroup;
679
680         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(self);
681         protocol_registry = modest_runtime_get_protocol_registry ();
682
683         box = gtk_vbox_new (FALSE, MODEST_MARGIN_NONE);
684         scrolled_window = gtk_scrolled_window_new (NULL, NULL);
685
686         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
687                                         GTK_POLICY_NEVER,
688                                         GTK_POLICY_AUTOMATIC);
689
690         /* Show note that account type cannot be changed in future: */
691         label = gtk_label_new (_("mcen_ia_emailsetup_account_type"));
692         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
693         gtk_widget_set_size_request (label, 600, -1);
694         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
695         gtk_widget_show (label);
696         
697         /* Create a size group to be used by all captions.
698          * Note that HildonCaption does not create a default size group if we do not specify one.
699          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
700         sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
701          
702         /* The incoming server widgets: */
703         priv->incoming_servertype_picker = GTK_WIDGET (modest_servertype_picker_new (MODEST_EDITABLE_SIZE,
704                                                                                      MODEST_EDITABLE_ARRANGEMENT,
705                                                                                      TRUE));
706         hildon_button_set_title (HILDON_BUTTON (priv->incoming_servertype_picker), _("mcen_li_emailsetup_type"));
707         g_signal_connect (G_OBJECT (priv->incoming_servertype_picker), "value-changed",
708                           G_CALLBACK (on_picker_button_value_changed), self);
709         gtk_box_pack_start (GTK_BOX (box), priv->incoming_servertype_picker, FALSE, FALSE, MODEST_MARGIN_HALF);
710         gtk_widget_show (priv->incoming_servertype_picker);
711         
712         priv->entry_incomingserver = gtk_entry_new ();
713         g_signal_connect(G_OBJECT(priv->entry_incomingserver), "changed", G_CALLBACK(on_easysetup_changed), self);
714         /* Auto-capitalization is the default, so let's turn it off: */
715         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->entry_incomingserver), HILDON_GTK_INPUT_MODE_FULL);
716         set_default_custom_servernames (self);
717
718         /* The caption title will be updated in update_incoming_server_title().
719          * so this default text will never be seen: */
720         /* (Note: Changing the title seems pointless. murrayc) */
721         priv->caption_incoming = create_captioned (self, sizegroup, 
722                                                    "Incoming Server", 
723                                                    priv->entry_incomingserver);
724         update_incoming_server_title (self);
725         gtk_widget_show (priv->entry_incomingserver);
726         gtk_box_pack_start (GTK_BOX (box), priv->caption_incoming, FALSE, FALSE, MODEST_MARGIN_HALF);
727         gtk_widget_show (priv->caption_incoming);
728         
729         /* Change the caption title when the servertype changes, 
730          * as in the UI spec: */
731         g_signal_connect (G_OBJECT (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->incoming_servertype_picker))), 
732                           "changed",
733                           G_CALLBACK (on_servertype_selector_changed), self);
734
735         /* Remember when the servername was changed manually: */
736         g_signal_connect (G_OBJECT (priv->entry_incomingserver), "changed",
737                           G_CALLBACK (on_entry_incoming_servername_changed), self);
738
739         /* The secure connection widgets. These are only valid for
740            protocols with security */   
741         priv->incoming_security = 
742                 modest_maemo_security_options_view_new (MODEST_SECURITY_OPTIONS_INCOMING,
743                                                         FALSE, sizegroup);
744         gtk_box_pack_start (GTK_BOX (box), priv->incoming_security, 
745                             FALSE, FALSE, MODEST_MARGIN_HALF);
746
747         /* Set default selection */
748         modest_servertype_picker_set_active_servertype (
749                 MODEST_SERVERTYPE_PICKER (priv->incoming_servertype_picker), 
750                 MODEST_PROTOCOLS_STORE_POP);
751
752         gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), box);
753         gtk_container_set_focus_vadjustment (GTK_CONTAINER (box),
754                                              gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
755         gtk_widget_show (GTK_WIDGET (box));
756         gtk_widget_show (scrolled_window);
757
758         return GTK_WIDGET (scrolled_window);
759 }
760
761 static void
762 on_toggle_button_changed (GtkToggleButton *togglebutton, gpointer user_data)
763 {
764         GtkWidget *widget = GTK_WIDGET (user_data);
765         
766         /* Enable the widget only if the toggle button is active: */
767         const gboolean enable = gtk_toggle_button_get_active (togglebutton);
768         gtk_widget_set_sensitive (widget, enable);
769 }
770
771 /* Make the sensitivity of a widget depend on a toggle button.
772  */
773 static void
774 enable_widget_for_togglebutton (GtkWidget *widget, GtkToggleButton* button)
775 {
776         g_signal_connect (G_OBJECT (button), "toggled",
777                           G_CALLBACK (on_toggle_button_changed), widget);
778         
779         /* Set the starting sensitivity: */
780         on_toggle_button_changed (button, widget);
781 }
782
783 static void
784 on_button_outgoing_smtp_servers (GtkButton *button, gpointer user_data)
785 {
786         ModestEasysetupWizardDialog * self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
787         ModestEasysetupWizardDialogPrivate* priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(self);
788         GtkWidget *specific_window;
789         
790         /* We set dirty here because setting it depending on the connection specific dialog
791         seems overkill */
792         priv->dirty = TRUE;
793         
794         /* Create the window, if necessary: */
795         specific_window = (GtkWidget *) modest_connection_specific_smtp_window_new ();
796         modest_connection_specific_smtp_window_fill_with_connections (MODEST_CONNECTION_SPECIFIC_SMTP_WINDOW (specific_window), priv->account_manager);
797
798         /* Show the window */
799         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (specific_window));
800         gtk_widget_show (specific_window);
801 }
802
803 static void 
804 on_entry_outgoing_servername_changed (GtkEntry *entry, gpointer user_data)
805 {
806         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
807         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
808         priv->server_changes |= MODEST_EASYSETUP_WIZARD_DIALOG_OUTGOING_CHANGED;
809 }
810
811 static GtkWidget* 
812 create_page_custom_outgoing (ModestEasysetupWizardDialog *self)
813 {
814         ModestEasysetupWizardDialogPrivate *priv;
815         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_NONE);
816         
817         /* Create a size group to be used by all captions.
818          * Note that HildonCaption does not create a default size group if we do not specify one.
819          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
820         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
821          
822         /* The outgoing server widgets: */
823         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
824         priv->entry_outgoingserver = gtk_entry_new ();
825         g_signal_connect (G_OBJECT (priv->entry_outgoingserver), "changed",
826                   G_CALLBACK (on_easysetup_changed), self);
827         /* Auto-capitalization is the default, so let's turn it off: */
828         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->entry_outgoingserver), HILDON_GTK_INPUT_MODE_FULL);
829         GtkWidget *caption = create_captioned (self, sizegroup, 
830                                                _("mcen_li_emailsetup_smtp"), priv->entry_outgoingserver);
831         gtk_widget_show (priv->entry_outgoingserver);
832         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
833         gtk_widget_show (caption);
834         set_default_custom_servernames (self);
835
836         /* The secure connection widgets. These are only valid for
837            protocols with security */   
838         priv->outgoing_security = 
839                 modest_maemo_security_options_view_new (MODEST_SECURITY_OPTIONS_OUTGOING,
840                                                         FALSE, sizegroup);
841         gtk_box_pack_start (GTK_BOX (box), priv->outgoing_security, 
842                             FALSE, FALSE, MODEST_MARGIN_HALF);
843         gtk_widget_show (priv->outgoing_security);
844         
845         GtkWidget *separator = gtk_hseparator_new ();
846         gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, MODEST_MARGIN_HALF);
847         gtk_widget_show (separator);
848         
849         /* connection-specific checkbox: */
850         priv->checkbox_outgoing_smtp_specific = gtk_check_button_new ();
851         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->checkbox_outgoing_smtp_specific), 
852                                       FALSE);
853         g_signal_connect (G_OBJECT (priv->checkbox_outgoing_smtp_specific), "toggled",
854                   G_CALLBACK (on_easysetup_changed), self);
855
856         caption = modest_maemo_utils_create_captioned (sizegroup, _("mcen_fi_advsetup_connection_smtp"), 
857                                                        priv->checkbox_outgoing_smtp_specific);
858         gtk_widget_show (priv->checkbox_outgoing_smtp_specific);
859         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
860         gtk_widget_show (caption);
861         
862         /* Connection-specific SMTP-Severs Edit button: */
863         priv->button_outgoing_smtp_servers = gtk_button_new_with_label (_("mcen_bd_edit"));
864         caption = modest_maemo_utils_create_captioned (sizegroup, _("mcen_fi_advsetup_optional_smtp"), 
865                                                        priv->button_outgoing_smtp_servers);
866         hildon_caption_set_child_expand (HILDON_CAPTION (caption), FALSE);
867         gtk_widget_show (priv->button_outgoing_smtp_servers);
868         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
869         gtk_widget_show (caption);
870         
871         /* Only enable the button when the checkbox is checked: */
872         enable_widget_for_togglebutton (priv->button_outgoing_smtp_servers, 
873                                         GTK_TOGGLE_BUTTON (priv->checkbox_outgoing_smtp_specific));
874                 
875         g_signal_connect (G_OBJECT (priv->button_outgoing_smtp_servers), "clicked",
876                           G_CALLBACK (on_button_outgoing_smtp_servers), self);
877
878         g_signal_connect (G_OBJECT (priv->entry_outgoingserver), "changed",
879                           G_CALLBACK (on_entry_outgoing_servername_changed), self);
880         
881         
882         gtk_widget_show (GTK_WIDGET (box));
883         
884         return GTK_WIDGET (box);
885 }
886
887 static gboolean
888 show_advanced_edit(gpointer user_data)
889 {
890         ModestEasysetupWizardDialog * self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
891         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
892         gint response;
893         
894         /* Show the Account Settings window: */
895         ModestAccountSettingsDialog *dialog = modest_default_account_settings_dialog_new ();
896         if (priv->pending_load_settings) {
897                 save_to_settings (self);
898                 priv->pending_load_settings = FALSE;
899         }
900         modest_account_settings_dialog_load_settings (dialog, priv->settings);
901         
902         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
903         
904         response = gtk_dialog_run (GTK_DIALOG (dialog));
905
906         gtk_widget_destroy (GTK_WIDGET (dialog));
907         
908         return FALSE; /* Do not call this timeout callback again. */
909 }
910
911 static void
912 on_button_edit_advanced_settings (GtkButton *button, gpointer user_data)
913 {
914         ModestEasysetupWizardDialog * self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
915         
916         /* Show the Account Settings window: */
917         show_advanced_edit(self);
918 }
919 static GtkWidget* 
920 create_page_complete_custom (ModestEasysetupWizardDialog *self)
921 {
922         GtkWidget *box = gtk_vbox_new (FALSE, MODEST_MARGIN_NONE);
923         GtkWidget *label = gtk_label_new(_("mcen_ia_emailsetup_setup_complete"));
924         GtkWidget *button_edit = gtk_button_new_with_label (_("mcen_bd_edit"));
925         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
926         gtk_widget_set_size_request (label, 600, -1);
927         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
928         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
929         gtk_widget_show (label);
930         
931         label = gtk_label_new (_("mcen_ia_customsetup_complete"));
932         gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
933         gtk_widget_set_size_request (label, 600, -1);
934         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
935         gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
936         gtk_widget_show (label);
937         
938         GtkWidget *caption = modest_maemo_utils_create_captioned (NULL, _("mcen_fi_advanced_settings"), 
939                                                                   button_edit);
940         hildon_caption_set_child_expand (HILDON_CAPTION (caption), FALSE);
941         gtk_widget_show (button_edit);
942         gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, MODEST_MARGIN_HALF);
943         gtk_widget_show (caption);
944         
945         g_signal_connect (G_OBJECT (button_edit), "clicked", 
946                           G_CALLBACK (on_button_edit_advanced_settings), self);
947         
948         gtk_widget_show (GTK_WIDGET (box));
949         return GTK_WIDGET (box);
950 }
951
952
953 /*
954  */
955 static void 
956 on_response (ModestWizardDialog *wizard_dialog,
957              gint response_id,
958              gpointer user_data)
959 {
960         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (wizard_dialog);
961
962         invoke_enable_buttons_vfunc (self);
963 }
964
965 static void 
966 on_response_before (ModestWizardDialog *wizard_dialog,
967                     gint response_id,
968                     gpointer user_data)
969 {
970         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (wizard_dialog);
971         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(wizard_dialog);
972         if (response_id == GTK_RESPONSE_CANCEL) {
973                 /* This is mostly copied from
974                  * src/maemo/modest-account-settings-dialog.c */
975                 if (priv->dirty) {
976                         GtkDialog *dialog = GTK_DIALOG (hildon_note_new_confirmation (GTK_WINDOW (self), 
977                                 _("imum_nc_wizard_confirm_lose_changes")));
978                         /* TODO: These button names will be ambiguous, and not
979                          * specified in the UI specification. */
980
981                         const gint dialog_response = gtk_dialog_run (dialog);
982                         gtk_widget_destroy (GTK_WIDGET (dialog));
983
984                         if (dialog_response != GTK_RESPONSE_OK) {
985                                 /* Don't let the dialog close */
986                                 g_signal_stop_emission_by_name (wizard_dialog, "response");
987                         }
988                 }
989         }
990 }
991
992 typedef struct IdleData {
993         ModestEasysetupWizardDialog *dialog;
994         ModestPresets *presets;
995 } IdleData;
996
997 static gboolean
998 presets_idle (gpointer userdata)
999 {
1000         IdleData *idle_data = (IdleData *) userdata;
1001         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (idle_data->dialog);
1002         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
1003
1004         g_assert (idle_data->presets);
1005
1006         gdk_threads_enter ();
1007
1008         priv->presets = idle_data->presets;
1009
1010         if (MODEST_IS_COUNTRY_PICKER (priv->account_country_picker)) {
1011 /*              gint mcc = get_default_country_code(); */
1012                 gint mcc;
1013                 /* Fill the combo in an idle call, as it takes a lot of time */
1014                 modest_country_picker_load_data(
1015                         MODEST_COUNTRY_PICKER (priv->account_country_picker));
1016                 /* connect to country picker's changed signal, so we can fill the provider picker: */
1017                 g_signal_connect (G_OBJECT (hildon_picker_button_get_selector 
1018                                             (HILDON_PICKER_BUTTON (priv->account_country_picker))),
1019                                   "changed",
1020                                   G_CALLBACK (on_account_country_selector_changed), self);
1021             
1022                 modest_country_picker_set_active_country_locale (
1023                         MODEST_COUNTRY_PICKER (priv->account_country_picker));
1024                 mcc = modest_country_picker_get_active_country_mcc (
1025                         MODEST_COUNTRY_PICKER (priv->account_country_picker));
1026                 modest_provider_picker_fill (
1027                         MODEST_PROVIDER_PICKER (priv->account_serviceprovider_picker),
1028                         priv->presets, mcc);
1029                 /* connect to providers picker's changed signal, so we can fill the email address: */
1030                 g_signal_connect (G_OBJECT (hildon_picker_button_get_selector 
1031                                             (HILDON_PICKER_BUTTON (priv->account_serviceprovider_picker))),
1032                                   "changed",
1033                                   G_CALLBACK (on_account_serviceprovider_selector_changed), self);
1034                 
1035                 modest_provider_picker_set_others_provider (MODEST_PROVIDER_PICKER (priv->account_serviceprovider_picker));
1036         }
1037
1038         priv->dirty = FALSE;
1039
1040         g_object_unref (idle_data->dialog);
1041         g_free (idle_data);
1042
1043         gdk_threads_leave ();
1044
1045         return FALSE;
1046 }
1047
1048 static gpointer
1049 presets_loader (gpointer userdata)
1050 {
1051         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (userdata);
1052         ModestPresets *presets = NULL;
1053         IdleData *idle_data;
1054
1055         const gchar* path  = NULL;
1056         const gchar* path1 = MODEST_PROVIDER_DATA_FILE;
1057         const gchar* path2 = MODEST_MAEMO_PROVIDER_DATA_FILE;
1058         
1059         if (access(path1, R_OK) == 0) 
1060                 path = path1;
1061         else if (access(path2, R_OK) == 0)
1062                 path = path2;
1063         else {
1064                 g_warning ("%s: neither '%s' nor '%s' is a readable provider data file",
1065                            __FUNCTION__, path1, path2);
1066                 return NULL;
1067         }
1068
1069         presets = modest_presets_new (path);
1070         if (!presets) {
1071                 g_warning ("%s: failed to parse '%s'", __FUNCTION__, path);
1072                 return NULL;
1073         }
1074         
1075         idle_data = g_new0 (IdleData, 1);
1076         idle_data->dialog = self;
1077         idle_data->presets = presets;
1078         
1079         g_idle_add (presets_idle, idle_data);   
1080
1081         return NULL;
1082 }
1083
1084 static void
1085 modest_easysetup_wizard_dialog_append_page (GtkNotebook *notebook,
1086                                             GtkWidget *page,
1087                                             const gchar *label)
1088 {
1089         gint index;
1090         /* Append page and set attributes */
1091         index = gtk_notebook_append_page (notebook, page, gtk_label_new (label));
1092         gtk_container_child_set (GTK_CONTAINER (notebook), page,
1093                                  "tab-expand", TRUE, "tab-fill", TRUE,
1094                                  NULL);
1095         gtk_widget_show (page);
1096 }
1097
1098 static void
1099 init_user_page (ModestEasysetupWizardDialogPrivate *priv)
1100 {
1101         priv->page_user_details = NULL;
1102         priv->entry_user_name = NULL;
1103         priv->entry_user_username = NULL;
1104         priv->entry_user_password = NULL;
1105         priv->entry_user_email = NULL;
1106 }
1107
1108 static void
1109 init_incoming_page (ModestEasysetupWizardDialogPrivate *priv)
1110 {
1111         priv->page_custom_incoming = NULL;
1112         priv->incoming_servertype_picker = NULL;
1113         priv->caption_incoming = NULL;
1114         priv->entry_incomingserver = NULL;
1115         priv->entry_user_email = NULL;
1116         priv->incoming_security = NULL;
1117 }
1118
1119 static void
1120 init_outgoing_page (ModestEasysetupWizardDialogPrivate *priv)
1121 {
1122         priv->page_custom_outgoing = NULL;
1123         priv->entry_outgoingserver = NULL;
1124         priv->checkbox_outgoing_smtp_specific = NULL;
1125         priv->button_outgoing_smtp_servers = NULL;
1126         priv->outgoing_security = NULL;
1127 }
1128
1129 static void
1130 modest_easysetup_wizard_dialog_init (ModestEasysetupWizardDialog *self)
1131 {
1132         gtk_container_set_border_width (GTK_CONTAINER (self), MODEST_MARGIN_HALF);
1133         
1134         /* Create the notebook to be used by the ModestWizardDialog base class:
1135          * Each page of the notebook will be a page of the wizard: */
1136         GtkNotebook *notebook = GTK_NOTEBOOK (gtk_notebook_new());
1137         
1138         /* Set the notebook used by the ModestWizardDialog base class: */
1139         g_object_set (G_OBJECT(self), "wizard-notebook", notebook, NULL);
1140     
1141         /* Set the wizard title:
1142          * The actual window title will be a combination of this and the page's tab label title. */
1143         g_object_set (G_OBJECT(self), "wizard-name", _("mcen_ti_emailsetup"), NULL);
1144
1145         /* Read in the information about known service providers: */
1146         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
1147         
1148         /* The server fields did not have been manually changed yet */
1149         priv->server_changes = 0;
1150         priv->pending_load_settings = TRUE;
1151
1152         /* Get the account manager object, 
1153          * so we can check for existing accounts,
1154          * and create new accounts: */
1155         priv->account_manager = modest_runtime_get_account_mgr ();
1156         g_object_ref (priv->account_manager);
1157         
1158         /* Initialize fields */
1159         priv->page_welcome = create_page_welcome (self);
1160         priv->page_account_details = create_page_account_details (self);
1161
1162         init_user_page (priv);
1163         init_incoming_page (priv);
1164         init_outgoing_page (priv);
1165
1166         priv->page_complete_easysetup = NULL;       
1167         priv->page_complete_customsetup = NULL;
1168         priv->last_plugin_protocol_selected = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1169         priv->missing_data_signals = NULL;
1170
1171         /* Add the common pages */
1172         modest_easysetup_wizard_dialog_append_page (notebook, priv->page_welcome, 
1173                                                     _("mcen_ti_emailsetup_welcome"));
1174         modest_easysetup_wizard_dialog_append_page (notebook, priv->page_account_details, 
1175                                                     _("mcen_ti_accountdetails"));
1176                 
1177         /* Connect to the dialog's response signal so we can enable/disable buttons 
1178          * for the newly-selected page, because the prev/next buttons cause response to be emitted.
1179          * Note that we use g_signal_connect_after() instead of g_signal_connect()
1180          * so that we can be enable/disable after ModestWizardDialog has done its own 
1181          * enabling/disabling of buttons.
1182          * 
1183          * HOWEVER, this doesn't work because ModestWizardDialog's response signal handler 
1184          * does g_signal_stop_emission_by_name(), stopping our signal handler from running.
1185          * 
1186          * It's not enough to connect to the notebook's switch-page signal, because 
1187          * ModestWizardDialog's "response" signal handler enables the buttons itself, 
1188          * _after_ switching the page (understandably).
1189          * (Note that if we had, if we used g_signal_connect() instead of g_signal_connect_after()
1190          * then gtk_notebook_get_current_page() would return an incorrect value.)
1191          */
1192         g_signal_connect_after (G_OBJECT (self), "response",
1193                                 G_CALLBACK (on_response), self);
1194
1195         /* This is to show a confirmation dialog when the user hits cancel */
1196         g_signal_connect (G_OBJECT (self), "response",
1197                           G_CALLBACK (on_response_before), self);
1198
1199         g_signal_connect (G_OBJECT (self), "delete-event",
1200                           G_CALLBACK (on_delete_event), self);
1201
1202         /* Reset dirty, because there was no user input until now */
1203         priv->dirty = FALSE;
1204         
1205         /* When this window is shown, hibernation should not be possible, 
1206          * because there is no sensible way to save the state: */
1207         modest_window_mgr_prevent_hibernation_while_window_is_shown (
1208                 modest_runtime_get_window_mgr (), GTK_WINDOW (self)); 
1209
1210         /* Load provider presets */
1211         g_object_ref (self);
1212         g_thread_create (presets_loader, self, FALSE, NULL);
1213
1214         hildon_help_dialog_help_enable (GTK_DIALOG(self), "applications_email_wizardwelcome",
1215                                         modest_maemo_utils_get_osso_context()); 
1216
1217         priv->settings = modest_account_settings_new ();
1218 }
1219
1220 ModestEasysetupWizardDialog*
1221 modest_easysetup_wizard_dialog_new (void)
1222 {       
1223         
1224         return g_object_new (MODEST_TYPE_EASYSETUP_WIZARD_DIALOG, NULL);
1225 }
1226
1227 static void 
1228 create_subsequent_customsetup_pages (ModestEasysetupWizardDialog *self)
1229 {
1230         ModestEasysetupWizardDialogPrivate *priv;
1231         GtkNotebook *notebook = NULL;
1232
1233         g_object_get (self, "wizard-notebook", &notebook, NULL);
1234         g_assert(notebook);
1235
1236         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
1237
1238         if (!priv->page_user_details) {
1239                 priv->page_user_details = create_page_user_details (self);
1240         }                       
1241
1242         /* Create the custom pages: */
1243         if(!(priv->page_custom_incoming)) {
1244                 priv->page_custom_incoming = create_page_custom_incoming (self);
1245         }
1246                 
1247         /* TODO: only if needed */
1248         if(!(priv->page_custom_outgoing)) {
1249                 priv->page_custom_outgoing = create_page_custom_outgoing (self);
1250         }
1251         
1252         if(!(priv->page_complete_customsetup)) {
1253                 priv->page_complete_customsetup = create_page_complete_custom (self);
1254         }
1255
1256         if (!gtk_widget_get_parent (GTK_WIDGET (priv->page_user_details)))
1257                 modest_easysetup_wizard_dialog_append_page (notebook, priv->page_user_details,
1258                                                             _("mcen_ti_emailsetup_userdetails"));
1259
1260         if (!gtk_widget_get_parent (GTK_WIDGET (priv->page_custom_incoming)))
1261                 modest_easysetup_wizard_dialog_append_page (notebook, priv->page_custom_incoming, 
1262                                                             _("mcen_ti_emailsetup_incomingdetails"));
1263         
1264         if (!gtk_widget_get_parent (GTK_WIDGET (priv->page_custom_outgoing)))           
1265                 modest_easysetup_wizard_dialog_append_page (notebook, priv->page_custom_outgoing, 
1266                                                             _("mcen_ti_emailsetup_outgoingdetails"));
1267                 
1268         if (!gtk_widget_get_parent (GTK_WIDGET (priv->page_complete_customsetup)))
1269                 modest_easysetup_wizard_dialog_append_page (notebook, priv->page_complete_customsetup, 
1270                                                             _("mcen_ti_emailsetup_complete"));
1271                         
1272         /* This is unnecessary with GTK+ 2.10: */
1273         modest_wizard_dialog_force_title_update (MODEST_WIZARD_DIALOG(self));
1274 }
1275         
1276 static void 
1277 create_subsequent_easysetup_pages (ModestEasysetupWizardDialog *self)
1278 {
1279         ModestEasysetupWizardDialogPrivate *priv;
1280         GtkNotebook *notebook = NULL;
1281
1282         g_object_get (self, "wizard-notebook", &notebook, NULL);
1283         g_assert(notebook);
1284         
1285         /* Create the easysetup-specific pages: */
1286         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
1287         if(!priv->page_complete_easysetup)
1288                 priv->page_complete_easysetup = create_page_complete_easysetup (self);
1289
1290         if (!gtk_widget_get_parent (GTK_WIDGET (priv->page_complete_easysetup)))
1291                 modest_easysetup_wizard_dialog_append_page (notebook, priv->page_complete_easysetup, 
1292                                                             _("mcen_ti_emailsetup_complete"));
1293                         
1294         /* This is unnecessary with GTK+ 2.10: */
1295         modest_wizard_dialog_force_title_update (MODEST_WIZARD_DIALOG(self));
1296 }
1297
1298 /* */
1299 static void
1300 remove_non_common_tabs (GtkNotebook *notebook, 
1301                         gboolean remove_user_details) 
1302 {
1303         gint starting_tab;
1304         /* The first 2 tabs are the common ones (welcome tab and the
1305            providers tab), so we always remove starting from the
1306            end */
1307
1308         starting_tab = (remove_user_details) ? 2 : 3;
1309         while (gtk_notebook_get_n_pages (notebook) > starting_tab) 
1310                 gtk_notebook_remove_page (notebook, -1); 
1311 }
1312
1313 static void
1314 on_missing_mandatory_data (ModestAccountProtocol *protocol,
1315                            gboolean missing,
1316                            gpointer user_data)
1317 {
1318         real_enable_buttons (MODEST_WIZARD_DIALOG (user_data), !missing);
1319 }
1320
1321 /* After the user details page,
1322  * the following pages depend on whether "Other" was chosen 
1323  * in the provider combobox on the account page
1324  */
1325 static void 
1326 create_subsequent_pages (ModestEasysetupWizardDialog *self)
1327 {
1328         ModestEasysetupWizardDialogPrivate *priv;
1329         ModestProviderPicker *picker;
1330         ModestProviderPickerIdType id_type;
1331         GtkNotebook *notebook;
1332
1333         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
1334         picker = MODEST_PROVIDER_PICKER (priv->account_serviceprovider_picker);
1335         id_type = modest_provider_picker_get_active_id_type (picker);
1336         g_object_get (self, "wizard-notebook", &notebook, NULL);
1337
1338         if (id_type == MODEST_PROVIDER_PICKER_ID_OTHER) {
1339                 /* "Other..." was selected: */
1340
1341                 /* If we come from a rollbacked easysetup */
1342                 if (priv->page_complete_easysetup) {
1343                         remove_non_common_tabs (notebook, FALSE);
1344                         priv->page_complete_easysetup = NULL;
1345                 } 
1346                 
1347                 /* If we come from a rollbacked plugin protocol setup */
1348                 if (priv->last_plugin_protocol_selected != MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
1349                         remove_non_common_tabs (notebook, TRUE);
1350                         priv->last_plugin_protocol_selected = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1351                         modest_signal_mgr_disconnect_all_and_destroy (priv->missing_data_signals);
1352                         priv->missing_data_signals = NULL;
1353                 }
1354
1355                 create_subsequent_customsetup_pages (self);
1356         } else {
1357                 /* If we come from a rollbacked custom setup */
1358                 if (priv->page_custom_incoming) {
1359                         remove_non_common_tabs (notebook, TRUE);
1360                         init_user_page (priv);
1361                         init_incoming_page (priv);
1362                         init_outgoing_page (priv);
1363                         init_user_page (priv);
1364                         priv->page_complete_customsetup = NULL;
1365                 }
1366
1367                 /* It's a pluggable protocol and not a provider with presets */
1368                 if (id_type == MODEST_PROVIDER_PICKER_ID_PLUGIN_PROTOCOL) {
1369                         ModestProtocol *protocol;
1370                         gchar *proto_name;
1371                         ModestProtocolType proto_type;
1372
1373                         
1374                         /* If we come from a rollbacked easy setup */
1375                         if (priv->last_plugin_protocol_selected == 
1376                             MODEST_PROTOCOL_REGISTRY_TYPE_INVALID &&
1377                             priv->page_complete_easysetup) {
1378                                 remove_non_common_tabs (notebook, TRUE);
1379                                 init_user_page (priv);
1380                                 priv->page_complete_easysetup = NULL;
1381                         }
1382                         
1383                         proto_name = modest_provider_picker_get_active_provider_id (picker);
1384                         protocol = modest_protocol_registry_get_protocol_by_name (modest_runtime_get_protocol_registry (),
1385                                                                                   MODEST_PROTOCOL_REGISTRY_PROVIDER_PROTOCOLS,
1386                                                                                   proto_name);
1387                         proto_type = modest_protocol_get_type_id (protocol);
1388
1389                         if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol) &&
1390                             proto_type != priv->last_plugin_protocol_selected) {
1391                                 ModestPairList *tabs;
1392                                 GSList *tmp;
1393
1394                                 /* Remember the last selected plugin protocol */
1395                                 priv->last_plugin_protocol_selected = proto_type;
1396
1397                                 /* Get tabs */
1398                                 tabs = modest_account_protocol_get_easysetupwizard_tabs (MODEST_ACCOUNT_PROTOCOL (protocol));
1399                                 tmp = (GSList *) tabs;
1400                                 while (tmp) {
1401                                         ModestPair *pair = (ModestPair *) tmp->data;
1402                                         modest_easysetup_wizard_dialog_append_page (notebook,
1403                                                                                     GTK_WIDGET (pair->second),
1404                                                                                     (const gchar *) pair->first);
1405
1406                                         /* Connect signals */
1407                                         priv->missing_data_signals = 
1408                                                 modest_signal_mgr_connect (priv->missing_data_signals, 
1409                                                                            G_OBJECT (pair->second), 
1410                                                                            "missing-mandatory-data",
1411                                                                            G_CALLBACK (on_missing_mandatory_data), 
1412                                                                            self);
1413
1414                                         g_free (pair->first);
1415                                         tmp = g_slist_next (tmp);
1416                                         /* Critical: if you don't show the page then the dialog will ignore it */
1417 /*                                      gtk_widget_show (GTK_WIDGET (pair->second)); */
1418                                 }
1419                                 modest_pair_list_free (tabs);
1420                         }
1421                         g_free (proto_name);
1422                 } else {
1423                         if (priv->last_plugin_protocol_selected != 
1424                             MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
1425                                 remove_non_common_tabs (notebook, TRUE);
1426                                 init_user_page (priv);
1427                                 priv->page_complete_easysetup = NULL;
1428                                 priv->last_plugin_protocol_selected = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1429                                 modest_signal_mgr_disconnect_all_and_destroy (priv->missing_data_signals);
1430                                 priv->missing_data_signals = NULL;
1431                         }
1432                         if (!priv->page_user_details) {
1433                                 priv->page_user_details = create_page_user_details (self);
1434                                 modest_easysetup_wizard_dialog_append_page (notebook, 
1435                                                                             priv->page_user_details,
1436                                                                             _("mcen_ti_emailsetup_userdetails"));
1437                         }
1438                 }
1439                 
1440                 /* Create the easysetup pages: */
1441                 create_subsequent_easysetup_pages (self);
1442         }
1443 }
1444
1445
1446 static gchar*
1447 util_get_default_servername_from_email_address (const gchar* email_address, ModestProtocolType protocol_type)
1448 {
1449         const gchar* hostname = NULL;
1450         gchar* at;
1451         gchar* domain;
1452         ModestProtocolRegistry *protocol_registry;
1453         ModestProtocol *protocol;
1454
1455         if (!email_address)
1456                 return NULL;
1457         
1458         at = g_utf8_strchr (email_address, -1, '@');
1459         if (!at || (g_utf8_strlen (at, -1) < 2))
1460                 return NULL;
1461                 
1462         domain = g_utf8_next_char (at);
1463         if(!domain)
1464                 return NULL;
1465
1466         protocol_registry = modest_runtime_get_protocol_registry ();
1467         protocol = modest_protocol_registry_get_protocol_by_type (protocol_registry, protocol_type);
1468                 
1469         if (modest_protocol_registry_protocol_type_has_tag (protocol_registry, protocol_type, MODEST_PROTOCOL_REGISTRY_REMOTE_STORE_PROTOCOLS) ||
1470             modest_protocol_registry_protocol_type_has_tag (protocol_registry, protocol_type, MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS)) {
1471                 hostname = modest_protocol_get_name (protocol);
1472         }
1473         
1474         if (!hostname)
1475                 return NULL;
1476                 
1477         return g_strdup_printf ("%s.%s", hostname, domain);
1478 }
1479
1480 static void 
1481 set_default_custom_servernames (ModestEasysetupWizardDialog *self)
1482 {
1483         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(self);
1484
1485         if (!priv->entry_incomingserver)
1486                 return;
1487                 
1488         /* Set a default domain for the server, based on the email address,
1489          * if no server name was already specified.
1490          */
1491         if (priv->entry_user_email
1492             && ((priv->server_changes & MODEST_EASYSETUP_WIZARD_DIALOG_INCOMING_CHANGED) == 0)) {
1493                 const ModestProtocolType protocol_type = modest_servertype_picker_get_active_servertype (
1494                         MODEST_SERVERTYPE_PICKER (priv->incoming_servertype_picker));
1495
1496                 /* This could happen when the combo box has still no active iter */
1497                 if (protocol_type != MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
1498                         const gchar* email_address = gtk_entry_get_text (GTK_ENTRY(priv->entry_user_email));    
1499                         gchar* servername = util_get_default_servername_from_email_address (email_address, 
1500                                                                                             protocol_type);
1501
1502                         /* Do not set the INCOMING_CHANGED flag because of this edit */
1503                         g_signal_handlers_block_by_func (G_OBJECT (priv->entry_incomingserver), G_CALLBACK (on_entry_incoming_servername_changed), self);
1504                         gtk_entry_set_text (GTK_ENTRY (priv->entry_incomingserver), servername);
1505                         g_signal_handlers_unblock_by_func (G_OBJECT (priv->entry_incomingserver), G_CALLBACK (on_entry_incoming_servername_changed), self);
1506                         
1507                         g_free (servername);
1508                 }
1509         }
1510         
1511         /* Set a default domain for the server, based on the email address,
1512          * if no server name was already specified.
1513          */
1514         if (!priv->entry_outgoingserver)
1515                 return;
1516                 
1517         if (priv->entry_user_email
1518             && ((priv->server_changes & MODEST_EASYSETUP_WIZARD_DIALOG_OUTGOING_CHANGED) == 0)) {
1519                 const gchar* email_address = gtk_entry_get_text (GTK_ENTRY(priv->entry_user_email));
1520                 
1521                 gchar* servername = util_get_default_servername_from_email_address (email_address, MODEST_PROTOCOLS_TRANSPORT_SMTP);
1522
1523                 /* Do not set the OUTGOING_CHANGED flag because of this edit */
1524                 g_signal_handlers_block_by_func (G_OBJECT (priv->entry_outgoingserver), G_CALLBACK (on_entry_outgoing_servername_changed), self);
1525                 gtk_entry_set_text (GTK_ENTRY (priv->entry_outgoingserver), servername);
1526                 g_signal_handlers_unblock_by_func (G_OBJECT (priv->entry_outgoingserver), G_CALLBACK (on_entry_outgoing_servername_changed), self);
1527
1528                 g_free (servername);
1529         }
1530 }
1531
1532 static gchar*
1533 get_entered_account_title (ModestEasysetupWizardDialog *self)
1534 {
1535         ModestEasysetupWizardDialogPrivate *priv;
1536         const gchar* account_title;
1537
1538         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE(self);
1539         account_title = gtk_entry_get_text (GTK_ENTRY (priv->entry_account_title));
1540
1541         if (!account_title || (g_utf8_strlen (account_title, -1) == 0)) {
1542                 return NULL;
1543         } else {
1544                 /* Strip it of whitespace at the start and end: */
1545                 gchar *result = g_strdup (account_title);
1546                 result = g_strstrip (result);
1547                 
1548                 if (!result)
1549                         return NULL;
1550                         
1551                 if (g_utf8_strlen (result, -1) == 0) {
1552                         g_free (result);
1553                         return NULL;    
1554                 }
1555                 
1556                 return result;
1557         }
1558 }
1559
1560 static gboolean
1561 on_before_next (ModestWizardDialog *dialog, GtkWidget *current_page, GtkWidget *next_page)
1562 {
1563         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (dialog);
1564         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
1565         ModestProtocolRegistry *protocol_registry;
1566
1567         protocol_registry = modest_runtime_get_protocol_registry ();
1568
1569         /* if are browsing pages previous to the last one, then we have pending settings in
1570          * this wizard */
1571         if (next_page != NULL)
1572                 priv->pending_load_settings = TRUE;
1573         
1574         /* Do extra validation that couldn't be done for every key press,
1575          * either because it was too slow,
1576          * or because it requires interaction:
1577          */
1578         if (current_page == priv->page_account_details) {       
1579                 /* Check that the title is not already in use: */
1580                 gchar* account_title = get_entered_account_title (self);
1581                 if (!account_title)
1582                         return FALSE;
1583                         
1584                 /* Aavoid a clash with an existing display name: */
1585                 const gboolean name_in_use = modest_account_mgr_account_with_display_name_exists (
1586                         priv->account_manager, account_title);
1587
1588                 if (name_in_use) {
1589                         /* Warn the user via a dialog: */
1590                         hildon_banner_show_information(NULL, NULL, _("mail_ib_account_name_already_existing"));
1591             
1592                         return FALSE;
1593                 }
1594
1595                 /* Make sure that the subsequent pages are appropriate for the provider choice. */
1596                 create_subsequent_pages (self);
1597
1598         } else if (current_page == priv->page_user_details) {
1599                 /* Check that the email address is valud: */
1600                 const gchar* email_address = gtk_entry_get_text (GTK_ENTRY (priv->entry_user_email));
1601                 if ((!email_address) || (g_utf8_strlen (email_address, -1) == 0))
1602                         return FALSE;
1603                         
1604                 if (!modest_text_utils_validate_email_address (email_address, NULL)) {
1605                         /* Warn the user via a dialog: */
1606                         hildon_banner_show_information (NULL, NULL, _("mcen_ib_invalid_email"));
1607                                              
1608                         /* Return focus to the email address entry: */
1609                         gtk_widget_grab_focus (priv->entry_user_email);
1610                         gtk_editable_select_region (GTK_EDITABLE (priv->entry_user_email), 0, -1);
1611
1612                         return FALSE;
1613                 }
1614         }
1615           
1616         if (next_page == priv->page_custom_incoming) {
1617                 set_default_custom_servernames (self);
1618         } else if (next_page == priv->page_custom_outgoing) {
1619                 set_default_custom_servernames (self);
1620
1621                 /* Check if the server supports secure authentication */
1622 /*              if (modest_security_options_view_auth_check (security_options)) */
1623 /*                      if (!check_has_supported_auth_methods (self)) */
1624 /*                              return FALSE; */
1625                 gtk_widget_show (priv->outgoing_security);
1626         }
1627         
1628         /* If this is the last page, and this is a click on Finish, 
1629          * then attempt to create the dialog.
1630          */
1631         if(!next_page && 
1632            current_page != priv->page_account_details) /* This is NULL when this is a click on Finish. */
1633         {
1634                 if (priv->pending_load_settings) {
1635                         save_to_settings (self);
1636                 }
1637
1638                 /* We check if there's already another account with the same configuration */
1639                 if (modest_account_mgr_check_already_configured_account (priv->account_manager, priv->settings)) {
1640                         modest_platform_information_banner (NULL, NULL, _("mail_ib_setting_failed"));
1641                         return FALSE;
1642                 }
1643
1644                 modest_account_mgr_add_account_from_settings (priv->account_manager, priv->settings);
1645         }
1646         
1647         
1648         return TRUE;
1649 }
1650
1651 static gboolean entry_is_empty (GtkWidget *entry)
1652 {
1653         if (!entry)
1654                 return FALSE;
1655                 
1656         const gchar* text = gtk_entry_get_text (GTK_ENTRY (entry));
1657         if ((!text) || (g_utf8_strlen (text, -1) == 0))
1658                 return TRUE;
1659         else {
1660                 /* Strip it of whitespace at the start and end: */
1661                 gchar *stripped = g_strdup (text);
1662                 stripped = g_strstrip (stripped);
1663                 
1664                 if (!stripped)
1665                         return TRUE;
1666                         
1667                 const gboolean result = (g_utf8_strlen (stripped, -1) == 0);
1668                 
1669                 g_free (stripped);
1670                 return result;
1671         }
1672 }
1673
1674 static void
1675 real_enable_buttons (ModestWizardDialog *dialog, gboolean enable_next)
1676 {               
1677         GtkNotebook *notebook = NULL;
1678         gboolean is_finish_tab;
1679         GtkWidget *current;
1680         ModestEasysetupWizardDialogPrivate *priv;
1681
1682         /* Get data */
1683         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (dialog);
1684         g_object_get (dialog, "wizard-notebook", &notebook, NULL);
1685         
1686         /* Disable the Finish button until we are on the last page,
1687          * because HildonWizardDialog enables this for all but the
1688          * first page */
1689         current = gtk_notebook_get_nth_page (notebook, gtk_notebook_get_current_page (notebook));
1690         is_finish_tab = ((current == priv->page_complete_easysetup) ||
1691                          (current == priv->page_complete_customsetup));
1692
1693         if (is_finish_tab) {
1694                 /* Disable Next on the last page no matter what the
1695                    argument say */
1696                 enable_next = FALSE;
1697         } else {
1698                 /* Not the last one */
1699                 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
1700                                                    MODEST_WIZARD_DIALOG_FINISH,
1701                                                    FALSE);
1702         }
1703         
1704         gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
1705                                            MODEST_WIZARD_DIALOG_NEXT,
1706                                            enable_next);
1707 }
1708
1709 static void
1710 on_enable_buttons (ModestWizardDialog *dialog, GtkWidget *current_page)
1711 {
1712         ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (dialog);
1713         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
1714         
1715         gboolean enable_next = TRUE;
1716         if (current_page == priv->page_welcome) {
1717                 enable_next = TRUE;
1718         } else if (current_page == priv->page_account_details) {
1719                 /* The account details title is mandatory: */
1720                 if (entry_is_empty(priv->entry_account_title))
1721                         enable_next = FALSE;
1722         } else if (current_page == priv->page_user_details) {   
1723                 /* The user details username is mandatory: */
1724                 if (entry_is_empty(priv->entry_user_username))
1725                         enable_next = FALSE;
1726                         
1727                 /* The user details email address is mandatory: */
1728                 if (enable_next && entry_is_empty (priv->entry_user_email))
1729                         enable_next = FALSE;
1730         } else if (current_page == priv->page_custom_incoming) {
1731                 /* The custom incoming server is mandatory: */
1732                 if (entry_is_empty(priv->entry_incomingserver))
1733                         enable_next = FALSE;
1734         } else if (MODEST_IS_EASYSETUP_WIZARD_PAGE (current_page)) {
1735                 enable_next = !modest_easysetup_wizard_page_validate (
1736                        MODEST_EASYSETUP_WIZARD_PAGE (current_page));
1737         }
1738                         
1739         /* Enable/disable buttons */ 
1740         real_enable_buttons (dialog, enable_next);
1741 }
1742
1743 static void
1744 modest_easysetup_wizard_dialog_class_init (ModestEasysetupWizardDialogClass *klass)
1745 {
1746         GObjectClass *object_class = G_OBJECT_CLASS (klass);
1747         g_type_class_add_private (klass, sizeof (ModestEasysetupWizardDialogPrivate));
1748
1749
1750         object_class->dispose = modest_easysetup_wizard_dialog_dispose;
1751         object_class->finalize = modest_easysetup_wizard_dialog_finalize;
1752         
1753         /* Provide a vfunc implementation so we can decide 
1754          * when to enable/disable the prev/next buttons.
1755          */
1756         ModestWizardDialogClass *base_klass = (ModestWizardDialogClass*)(klass);
1757         base_klass->before_next = on_before_next;
1758         base_klass->enable_buttons = on_enable_buttons;
1759 }
1760
1761 /**
1762  * save_to_settings:
1763  * @self: a #ModestEasysetupWizardDialog
1764  *
1765  * takes information from all the wizard and stores it in settings
1766  */
1767 static void
1768 save_to_settings (ModestEasysetupWizardDialog *self)
1769 {
1770         ModestEasysetupWizardDialogPrivate *priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
1771         guint special_port;
1772         gchar *provider_id;
1773         gchar* display_name;
1774         const gchar *username, *password;
1775         gchar *store_hostname, *transport_hostname;
1776         guint store_port, transport_port;
1777         ModestProtocolRegistry *protocol_registry;
1778         ModestProtocolType store_protocol, transport_protocol;
1779         ModestProtocolType store_security, transport_security;
1780         ModestProtocolType store_auth_protocol, transport_auth_protocol;
1781         ModestServerAccountSettings *store_settings, *transport_settings;
1782         const gchar *fullname, *email_address;
1783         ModestProviderPicker *picker;
1784         ModestProviderPickerIdType id_type;
1785
1786         priv = MODEST_EASYSETUP_WIZARD_DIALOG_GET_PRIVATE (self);
1787         picker = MODEST_PROVIDER_PICKER (priv->account_serviceprovider_picker);
1788         protocol_registry = modest_runtime_get_protocol_registry ();
1789
1790         /* Get details from the specified presets: */
1791         id_type = modest_provider_picker_get_active_id_type (picker);
1792         provider_id = modest_provider_picker_get_active_provider_id (picker);
1793                 
1794         /* Let the plugin save the settings. We do a return in order
1795            to save an indentation level */
1796         if (id_type == MODEST_PROVIDER_PICKER_ID_PLUGIN_PROTOCOL) {
1797                 ModestProtocol *protocol;
1798
1799                 protocol = modest_protocol_registry_get_protocol_by_name (
1800                        modest_runtime_get_protocol_registry (),
1801                        MODEST_PROTOCOL_REGISTRY_PROVIDER_PROTOCOLS,
1802                        provider_id);
1803
1804                 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
1805                         gint n_pages, i = 0;
1806                         GtkNotebook *notebook;
1807                         GList *wizard_pages = NULL;
1808
1809                         g_object_get (self, "wizard-notebook", &notebook, NULL);
1810                         n_pages = gtk_notebook_get_n_pages (notebook);
1811                         for (i = 0; i < n_pages; i++) {
1812                                 GtkWidget *page = gtk_notebook_get_nth_page (notebook, i);
1813                                 if (MODEST_IS_EASYSETUP_WIZARD_PAGE (page))
1814                                         wizard_pages  = g_list_append (wizard_pages, page);
1815                         }
1816                         modest_account_protocol_save_wizard_settings (MODEST_ACCOUNT_PROTOCOL (protocol),
1817                                                                       wizard_pages,
1818                                                                       priv->settings);
1819                         g_list_free (wizard_pages);
1820                 } else {
1821                         g_warning ("The selected protocol is a plugin protocol "//
1822                                    "but it's not a ModestAccountProtocol");
1823                 }
1824
1825                 return;
1826         }
1827
1828         /* username and password (for both incoming and outgoing): */
1829         username = gtk_entry_get_text (GTK_ENTRY (priv->entry_user_username));
1830         password = gtk_entry_get_text (GTK_ENTRY (priv->entry_user_password));
1831
1832         store_settings = modest_account_settings_get_store_settings (priv->settings);
1833         transport_settings = modest_account_settings_get_transport_settings (priv->settings);
1834
1835         /* Incoming server: */
1836         /* Note: We need something as default for the transport store protocol values, 
1837          * or modest_account_mgr_add_server_account will fail. */
1838         store_port = 0;
1839         store_protocol = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1840         store_security = MODEST_PROTOCOLS_CONNECTION_NONE;
1841         store_auth_protocol = MODEST_PROTOCOLS_AUTH_NONE;
1842
1843         if (provider_id) {
1844                 ModestProtocolType store_provider_server_type;
1845                 gboolean store_provider_use_alternate_port;
1846                 /* Use presets: */
1847                 store_hostname = modest_presets_get_server (priv->presets, provider_id, 
1848                                                             TRUE /* store */);
1849                 
1850                 store_provider_server_type = modest_presets_get_info_server_type (priv->presets,
1851                                                                          provider_id, 
1852                                                                          TRUE /* store */);
1853                 store_security  = modest_presets_get_info_server_security (priv->presets,
1854                                                                                     provider_id, 
1855                                                                                     TRUE /* store */);
1856                 store_auth_protocol  = modest_presets_get_info_server_auth (priv->presets,
1857                                                                                      provider_id, 
1858                                                                                      TRUE /* store */);
1859                 store_provider_use_alternate_port  = modest_presets_get_info_server_use_alternate_port (priv->presets,
1860                                                                                                         provider_id, 
1861                                                                                                         TRUE /* store */);
1862
1863                 /* We don't check for SMTP here as that is impossible for an incoming server. */
1864                 if (store_provider_server_type == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID)
1865                         store_protocol = MODEST_PROTOCOLS_STORE_POP;
1866                 else
1867                         store_protocol = store_provider_server_type;
1868
1869                 /* we check if there is a *special* port */
1870                 special_port = modest_presets_get_port (priv->presets, provider_id, TRUE /* incoming */);
1871                 if (special_port != 0)
1872                         store_port = special_port;
1873                 else 
1874                         store_port = get_port_from_protocol(store_provider_server_type, store_security);
1875
1876                 modest_server_account_settings_set_security_protocol (store_settings, 
1877                                                                       store_security);
1878                 modest_server_account_settings_set_auth_protocol (store_settings, 
1879                                                                   store_auth_protocol);
1880                 if (store_port != 0)
1881                         modest_server_account_settings_set_port (store_settings, store_port);
1882         } else {
1883                 /* Use custom pages because no preset was specified: */
1884                 store_hostname = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->entry_incomingserver) ));               
1885                 store_protocol = modest_servertype_picker_get_active_servertype (
1886                         MODEST_SERVERTYPE_PICKER (priv->incoming_servertype_picker));           
1887
1888                 modest_security_options_view_save_settings (
1889                                     MODEST_SECURITY_OPTIONS_VIEW (priv->incoming_security),
1890                                     priv->settings);
1891         }
1892
1893         /* now we store the common store account settings */
1894         modest_server_account_settings_set_hostname (store_settings, store_hostname);
1895         modest_server_account_settings_set_username (store_settings, username);
1896         modest_server_account_settings_set_password (store_settings, password);
1897         modest_server_account_settings_set_protocol (store_settings, store_protocol);
1898
1899         g_object_unref (store_settings);
1900         g_free (store_hostname);
1901         
1902         /* Outgoing server: */
1903         transport_hostname = NULL;
1904         transport_protocol = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1905         transport_security = MODEST_PROTOCOLS_CONNECTION_NONE;
1906         transport_auth_protocol = MODEST_PROTOCOLS_AUTH_NONE;
1907         transport_port = 0;
1908         
1909         if (provider_id) {
1910                 ModestProtocolType transport_provider_server_type;
1911                 ModestProtocolType transport_provider_security;
1912
1913                 /* Use presets */
1914                 transport_hostname = modest_presets_get_server (priv->presets, provider_id, 
1915                                                                 FALSE /* transport */);
1916                         
1917                 transport_provider_server_type = modest_presets_get_info_server_type (priv->presets,
1918                                                                                       provider_id, 
1919                                                                                       FALSE /* transport */);           
1920                 transport_provider_security = modest_presets_get_info_server_security (priv->presets, 
1921                                                                                        provider_id, 
1922                                                                                        FALSE /* transport */);
1923
1924                 /* Note: We need something as default, or modest_account_mgr_add_server_account will fail. */
1925                 transport_protocol = transport_provider_server_type;
1926                 transport_security = transport_provider_security;
1927                 if (transport_security == MODEST_PROTOCOLS_CONNECTION_SSL) {
1928                         /* printf("DEBUG: %s: using secure SMTP\n", __FUNCTION__); */
1929                         /* we check if there is a *special* port */
1930                         special_port = modest_presets_get_port (priv->presets, provider_id,
1931                                                                 FALSE /* transport */);
1932                         if (special_port != 0)
1933                                 transport_port = special_port;
1934                         else 
1935                                 transport_port = 465;
1936                         transport_auth_protocol = MODEST_PROTOCOLS_AUTH_PASSWORD;
1937                 } else {
1938                         /* printf("DEBUG: %s: using non-secure SMTP\n", __FUNCTION__); */
1939                         transport_auth_protocol = MODEST_PROTOCOLS_AUTH_NONE;
1940                 }
1941
1942                 modest_server_account_settings_set_security_protocol (transport_settings, 
1943                                                                       transport_security);
1944                 modest_server_account_settings_set_auth_protocol (transport_settings, 
1945                                                                   transport_auth_protocol);
1946                 if (transport_port != 0)
1947                         modest_server_account_settings_set_port (transport_settings, 
1948                                                                  transport_port);
1949         } else {
1950                 ModestProtocolRegistry *registry;
1951                 ModestProtocol *store_proto;
1952
1953                 registry = modest_runtime_get_protocol_registry ();
1954                 /* Use custom pages because no preset was specified: */
1955                 transport_hostname = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->entry_outgoingserver) ));
1956
1957                 store_proto = modest_protocol_registry_get_protocol_by_type (registry, 
1958                                                                              store_protocol);
1959
1960                 if (transport_protocol == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
1961                         /* fallback to SMTP if none was specified */
1962                         g_warning ("No transport protocol was specified for store %d (%s)",
1963                                    modest_protocol_get_type_id (store_proto),
1964                                    modest_protocol_get_display_name (store_proto));
1965                         transport_protocol = MODEST_PROTOCOLS_TRANSPORT_SMTP;
1966                 }
1967
1968                 modest_security_options_view_save_settings (
1969                                     MODEST_SECURITY_OPTIONS_VIEW (priv->outgoing_security),
1970                                     priv->settings);
1971         }
1972
1973         /* now we store the common transport account settings */
1974         modest_server_account_settings_set_hostname (transport_settings, transport_hostname);
1975         modest_server_account_settings_set_username (transport_settings, username);
1976         modest_server_account_settings_set_password (transport_settings, password);
1977         modest_server_account_settings_set_protocol (transport_settings, transport_protocol);
1978
1979         g_object_unref (transport_settings);
1980         g_free (transport_hostname);
1981         
1982         fullname = gtk_entry_get_text (GTK_ENTRY (priv->entry_user_name));
1983         email_address = gtk_entry_get_text (GTK_ENTRY (priv->entry_user_email));
1984         modest_account_settings_set_fullname (priv->settings, fullname);
1985         modest_account_settings_set_email_address (priv->settings, email_address);
1986         /* we don't set retrieve type to preserve advanced settings if
1987            any. By default account settings are set to headers only */
1988         
1989         /* Save the connection-specific SMTP server accounts. */
1990         modest_account_settings_set_use_connection_specific_smtp 
1991                 (priv->settings, 
1992                  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->checkbox_outgoing_smtp_specific)));
1993
1994         display_name = get_entered_account_title (self);
1995         modest_account_settings_set_display_name (priv->settings, display_name);
1996         g_free (display_name);
1997 }
1998