Added files from osso-modest-easysetup
authorMurray Cumming <murrayc@murrayc.com>
Tue, 3 Apr 2007 13:36:38 +0000 (13:36 +0000)
committerMurray Cumming <murrayc@murrayc.com>
Tue, 3 Apr 2007 13:36:38 +0000 (13:36 +0000)
pmo-trunk-r1487

28 files changed:
src/maemo/easysetup/Makefile.am [new file with mode: 0644]
src/maemo/easysetup/localisation.h [new file with mode: 0644]
src/maemo/easysetup/main.c [new file with mode: 0644]
src/maemo/easysetup/mcc_mapping [new file with mode: 0644]
src/maemo/easysetup/mcc_mapping.en_GB [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-country-combo-box.c [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-country-combo-box.h [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-provider-combo-box.c [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-provider-combo-box.h [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-secureauth-combo-box.c [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-secureauth-combo-box.h [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-serversecurity-combo-box.c [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-serversecurity-combo-box.h [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-servertype-combo-box.c [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-servertype-combo-box.h [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-wizard.c [new file with mode: 0644]
src/maemo/easysetup/modest-easysetup-wizard.h [new file with mode: 0644]
src/maemo/easysetup/modest-presets.c [new file with mode: 0644]
src/maemo/easysetup/modest-presets.h [new file with mode: 0644]
src/maemo/easysetup/modest-text-utils.c [new file with mode: 0644]
src/maemo/easysetup/modest-text-utils.h [new file with mode: 0644]
src/maemo/easysetup/modest-validating-entry.c [new file with mode: 0644]
src/maemo/easysetup/modest-validating-entry.h [new file with mode: 0644]
src/maemo/easysetup/modest-wizard-dialog.c [new file with mode: 0644]
src/maemo/easysetup/modest-wizard-dialog.h [new file with mode: 0644]
src/maemo/easysetup/osso_countries_1.0.mo [new file with mode: 0644]
src/maemo/easysetup/osso_countries_1.0.po [new file with mode: 0644]
src/maemo/easysetup/provider-data-test.keyfile [new file with mode: 0644]

diff --git a/src/maemo/easysetup/Makefile.am b/src/maemo/easysetup/Makefile.am
new file mode 100644 (file)
index 0000000..a79c6a1
--- /dev/null
@@ -0,0 +1,30 @@
+SUBDIRS=modest-account-mgr
+DIST_SUBDIRS=
+
+INCLUDES=\
+       $(MODEST_GSTUFF_CFLAGS)\
+       -DPREFIX=\"@prefix@\" \
+       -DOSSO_MODEST_EASYSETUP_LOCALEDIR=\"$(OSSO_MODEST_EASYSETUP_LOCALEDIR)\" \
+       -I$(srcdir)/modest-account-mgr
+
+
+bin_PROGRAMS=\
+       osso-modest-easysetup
+
+osso_modest_easysetup_SOURCES=\
+       main.c \
+       modest-wizard-dialog.h modest-wizard-dialog.c \
+       modest-presets.h modest-presets.c \
+       modest-easysetup-wizard.h modest-easysetup-wizard.c \
+       modest-easysetup-country-combo-box.h modest-easysetup-country-combo-box.c \
+       modest-easysetup-provider-combo-box.h modest-easysetup-provider-combo-box.c \
+       modest-easysetup-servertype-combo-box.h modest-easysetup-servertype-combo-box.c \
+       modest-easysetup-serversecurity-combo-box.h modest-easysetup-serversecurity-combo-box.c \
+       modest-easysetup-secureauth-combo-box.h modest-easysetup-secureauth-combo-box.c \
+       modest-validating-entry.h modest-validating-entry.c \
+       modest-text-utils.h modest-text-utils.c
+
+osso_modest_easysetup_LDADD =                                          \
+       $(MODEST_GSTUFF_LIBS) \
+       modest-account-mgr/libmodestaccountmgr.a
+
diff --git a/src/maemo/easysetup/localisation.h b/src/maemo/easysetup/localisation.h
new file mode 100644 (file)
index 0000000..efdf636
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef LOCALISATION_H
+#define LOCALISATION_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif                          /* HAVE_CONFIG_H */
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(String) gettext(String)
+#ifdef gettext_noop
+#define N_(String) gettext_noop(String)
+#else
+#define N_(String) (String)
+#endif
+#define locale_init() setlocale(LC_ALL, "");\
+    bindtextdomain(GETTEXT_PACKAGE, localedir);\
+    textdomain(GETTEXT_PACKAGE);
+#else                           /* NLS is disabled */
+#define locale_init() 
+#define _(String) (String)
+#define N_(String) (String)
+#define textdomain(String) (String)
+#define gettext(String) (String)
+#define dgettext(Domain,String) (String)
+#define dcgettext(Domain,String,Type) (String)
+#define bindtextdomain(Domain,Directory) (Domain)
+#define bind_textdomain_codeset(Domain,Codeset) (Codeset)
+#endif                          /* ENABLE_NLS */
+
+#endif /* LOCALISATION_H */
+#ifndef LOCALISATION_H
+#define LOCALISATION_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif                          /* HAVE_CONFIG_H */
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(String) gettext(String)
+#ifdef gettext_noop
+#define N_(String) gettext_noop(String)
+#else
+#define N_(String) (String)
+#endif
+#define locale_init() setlocale(LC_ALL, "");\
+    bindtextdomain(GETTEXT_PACKAGE, localedir);\
+    textdomain(GETTEXT_PACKAGE);
+#else                           /* NLS is disabled */
+#define locale_init() 
+#define _(String) (String)
+#define N_(String) (String)
+#define textdomain(String) (String)
+#define gettext(String) (String)
+#define dgettext(Domain,String) (String)
+#define dcgettext(Domain,String,Type) (String)
+#define bindtextdomain(Domain,Directory) (Domain)
+#define bind_textdomain_codeset(Domain,Codeset) (Codeset)
+#endif                          /* ENABLE_NLS */
+
+#endif /* LOCALISATION_H */
+
diff --git a/src/maemo/easysetup/main.c b/src/maemo/easysetup/main.c
new file mode 100644 (file)
index 0000000..3cd0d74
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#include <config.h> /* For GETTEXT_PACKAGE, etc */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkmain.h>
+#include "modest-easysetup-wizard.h"
+
+/* Copied from modest-main.c: */
+typedef enum {
+       MODEST_ERR_NONE    = 0,   /* no error */
+       MODEST_ERR_OPTIONS = 1,   /* error in the options */
+       MODEST_ERR_CONF    = 2,   /* error getting confuration db */
+       MODEST_ERR_UI      = 3,   /* error in the UI */
+       MODEST_ERR_HILDON  = 4,   /* error with Hildon (maemo-only) */
+       MODEST_ERR_RUN     = 5,   /* error running */
+       MODEST_ERR_PARAM   = 7,   /* error in one or more of the parameters */
+       MODEST_ERR_INIT    = 8    /* error in initialization */
+} ModestErrorCode;
+
+static gboolean modest_easysetup_init(int argc, char *argv[])
+{
+        /* Setup gettext, to use our .po files: */
+        /* GETTEXT_PACKAGE is defined in config.h */
+        /* OSSO_MODEST_EASYSETUP_LOCALEDIR is defined in the Makefile.am */
+       bindtextdomain (GETTEXT_PACKAGE, OSSO_MODEST_EASYSETUP_LOCALEDIR);
+       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+       textdomain (GETTEXT_PACKAGE);
+
+       if (!gtk_init_check(&argc, &argv)) {
+               g_printerr ("osso-modest-easysetup: failed to initialize GTK+\n");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean modest_easysetup_uninit()
+{
+       return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{      
+       if (!modest_easysetup_init (argc, argv)) {
+               g_printerr ("osso-modest-easysetup: cannot init runtime\n");
+               return MODEST_ERR_INIT;
+       }
+
+       ModestEasysetupWizardDialog *wizard = modest_easysetup_wizard_dialog_new ();
+       gtk_dialog_run (GTK_DIALOG (wizard));
+
+       if (!modest_easysetup_uninit ()) 
+               g_printerr ("osso-modest-easysetup: shutdown failed\n");
+
+       return MODEST_ERR_NONE;
+}
+
diff --git a/src/maemo/easysetup/mcc_mapping b/src/maemo/easysetup/mcc_mapping
new file mode 100644 (file)
index 0000000..6b984d1
--- /dev/null
@@ -0,0 +1,230 @@
+412    osso_db_country_afghanistan\r
+276    osso_db_country_albania\r
+603    osso_db_country_algeria\r
+544    osso_db_country_american_samoa\r
+213    osso_db_country_andorra\r
+631    osso_db_country_angola\r
+365    osso_db_country_anguilla\r
+344    osso_db_country_antigua_and_barbuda\r
+722    osso_db_country_argentina\r
+283    osso_db_country_armenia\r
+363    osso_db_country_aruba\r
+505    osso_db_country_australia\r
+232    osso_db_country_austria\r
+400    osso_db_country_azerbaijani_republic\r
+364    osso_db_country_bahamas\r
+426    osso_db_country_bahrain\r
+470    osso_db_country_bangladesh\r
+342    osso_db_country_barbados\r
+257    osso_db_country_belarus\r
+206    osso_db_country_belgium\r
+702    osso_db_country_belize\r
+616    osso_db_country_benin\r
+350    osso_db_country_bermuda\r
+402    osso_db_country_bhutan\r
+736    osso_db_country_bolivia\r
+218    osso_db_country_bosnia_and_herzegovina\r
+652    osso_db_country_botswana\r
+724    osso_db_country_brazil\r
+348    osso_db_country_british_virgin_islands\r
+528    osso_db_country_brunei_darussalam\r
+284    osso_db_country_bulgaria\r
+613    osso_db_country_burkina_faso\r
+642    osso_db_country_burundi\r
+456    osso_db_country_cambodia\r
+624    osso_db_country_cameroon\r
+302    osso_db_country_canada\r
+625    osso_db_country_cape_verde\r
+346    osso_db_country_cayman_islands\r
+623    osso_db_country_central_african_republic\r
+622    osso_db_country_chad\r
+730    osso_db_country_chile\r
+461    osso_db_country_china\r
+460    osso_db_country_china\r
+732    osso_db_country_colombia\r
+654    osso_db_country_comoros\r
+629    osso_db_country_republic_of_the_congo\r
+548    osso_db_country_cook_islands\r
+712    osso_db_country_costa_rica\r
+612    osso_db_country_cote_dlvoire\r
+219    osso_db_country_croatia\r
+368    osso_db_country_cuba\r
+280    osso_db_country_cyprus\r
+230    osso_db_country_czech_republic\r
+630    osso_db_country_democratic_republic_of_the_congo\r
+238    osso_db_country_denmark\r
+638    osso_db_country_djibouti\r
+366    osso_db_country_dominica\r
+370    osso_db_country_dominican_republic\r
+514    osso_db_country_east_timor\r
+740    osso_db_country_ecuador\r
+602    osso_db_country_egypt\r
+706    osso_db_country_el_salvador\r
+627    osso_db_country_equatorial_guinea\r
+657    osso_db_country_eritrea\r
+248    osso_db_country_estonia\r
+636    osso_db_country_ethiopia\r
+288    osso_db_country_faroe_islands\r
+542    osso_db_country_fiji\r
+244    osso_db_country_finland\r
+208    osso_db_country_france\r
+742    osso_db_country_french_guiana\r
+547    osso_db_country_french_polynesia\r
+628    osso_db_country_gobonese_republic\r
+607    osso_db_country_gambia\r
+282    osso_db_country_georgia\r
+262    osso_db_country_germany\r
+620    osso_db_country_ghana\r
+266    osso_db_country_gibraltar\r
+202    osso_db_country_greece\r
+290    osso_db_country_greenland\r
+352    osso_db_country_grenada\r
+340    osso_db_country_guadeloupe\r
+535    osso_db_country_guam\r
+704    osso_db_country_guatemala\r
+611    osso_db_country_guinea\r
+632    osso_db_country_guinea_bissaus\r
+738    osso_db_country_guyana\r
+372    osso_db_country_haiti\r
+708    osso_db_country_honduras\r
+454    osso_db_country_hong_kong\r
+216    osso_db_country_hungary\r
+274    osso_db_country_iceland\r
+404    osso_db_country_india\r
+510    osso_db_country_indonesia\r
+432    osso_db_country_iran\r
+418    osso_db_country_iraq\r
+272    osso_db_country_republic_of_ireland\r
+425    osso_db_country_israel\r
+222    osso_db_country_italy\r
+338    osso_db_country_jamaica\r
+441    osso_db_country_japan\r
+440    osso_db_country_japan\r
+416    osso_db_country_jordan\r
+401    osso_db_country_kazakhstan\r
+639    osso_db_country_kenya\r
+545    osso_db_country_kiribati\r
+467    osso_db_country_korea_north\r
+450    osso_db_country_country_south_korea\r
+419    osso_db_country_kuwait\r
+437    osso_db_country_kyrgyz_republic\r
+457    osso_db_country_laos\r
+247    osso_db_country_latvia\r
+415    osso_db_country_lebanon\r
+651    osso_db_country_lesotho\r
+618    osso_db_country_liberia\r
+606    osso_db_country_libya\r
+295    osso_db_country_liechtenstein\r
+246    osso_db_country_lithuania\r
+270    osso_db_country_luxembourg\r
+455    osso_db_country_macao\r
+294    osso_db_country_the_former_yugoslav_republic_of_macedonia\r
+646    osso_db_country_madagascar\r
+650    osso_db_country_malawi\r
+502    osso_db_country_malaysia\r
+472    osso_db_country_maldives\r
+610    osso_db_country_mali\r
+278    osso_db_country_malta\r
+551    osso_db_country_marshall_islands\r
+340    osso_db_country_martinique\r
+609    osso_db_country_mauritania\r
+617    osso_db_country_mauritius\r
+334    osso_db_country_mexico\r
+550    osso_db_country_micronesia\r
+259    osso_db_country_republic_of_moldova\r
+212    osso_db_country_monaco\r
+428    osso_db_country_mongolia\r
+354    osso_db_country_montserrat\r
+604    osso_db_country_morocco\r
+643    osso_db_country_mozambique\r
+414    osso_db_country_myanmar\r
+649    osso_db_country_namibia\r
+536    osso_db_country_nauru\r
+429    osso_db_country_nepal\r
+204    osso_db_country_netherlands\r
+362    osso_db_country_netherlands_antilles\r
+546    osso_db_country_new_caledonia\r
+530    osso_db_country_new_zealand\r
+710    osso_db_country_nicaraqua\r
+614    osso_db_country_niger\r
+621    osso_db_country_nigeria\r
+534    osso_db_country_northern_mariana_islands\r
+242    osso_db_country_norway\r
+422    osso_db_country_oman\r
+410    osso_db_country_pakistan\r
+552    osso_db_country_palau\r
+714    osso_db_country_panama\r
+537    osso_db_country_papua_new_guinea\r
+744    osso_db_country_paraquay\r
+716    osso_db_country_peru\r
+515    osso_db_country_philippines\r
+260    osso_db_country_poland\r
+268    osso_db_country_portugal\r
+330    osso_db_country_puerto_rico\r
+427    osso_db_country_qatar\r
+647    osso_db_country_reunion\r
+226    osso_db_country_romania\r
+250    osso_db_country_russian_federation\r
+635    osso_db_country_rwandese_republic\r
+356    osso_db_country_saint_kitts_and_nevis\r
+358    osso_db_country_saint_lucia\r
+308    osso_db_country_saint_pierre_and_miquelon\r
+360    osso_db_country_saint_vincent_and_grenadines\r
+549    osso_db_country_samoa\r
+292    osso_db_country_san_marino\r
+626    osso_db_country_sao_tome_and_principe\r
+420    osso_db_country_saudi_arabia\r
+608    osso_db_country_senegal\r
+220    osso_db_country_serbia_and_montenegro\r
+633    osso_db_country_seychelles\r
+619    osso_db_country_sierra_leone\r
+525    osso_db_country_singapore\r
+231    osso_db_country_slovakia\r
+293    osso_db_country_slovenia\r
+540    osso_db_country_solomon_islands\r
+637    osso_db_country_somalia\r
+655    osso_db_country_south_africa\r
+214    osso_db_country_spain\r
+413    osso_db_country_sri_lanka\r
+634    osso_db_country_sudan\r
+746    osso_db_country_suriname\r
+653    osso_db_country_swaziland\r
+240    osso_db_country_sweden\r
+228    osso_db_country_switzerland\r
+417    osso_db_country_syrian_arab_republic\r
+466    osso_db_country_taiwan\r
+436    osso_db_country_tajikistan\r
+640    osso_db_country_united_republic_of_tanzania\r
+520    osso_db_country_thailand\r
+615    osso_db_country_togolese_republic\r
+539    osso_db_country_tonga\r
+374    osso_db_country_trinidad_and_tobago\r
+605    osso_db_country_tunisia\r
+286    osso_db_country_turkey\r
+438    osso_db_country_turkmenistan\r
+376    osso_db_country_turks_and_caicos_islands\r
+641    osso_db_country_uganda\r
+255    osso_db_country_ukraine\r
+424    osso_db_country_united_arab_emirates\r
+430    osso_db_country_united_arab_emirates_abu_dhabi\r
+431    osso_db_country_united_arab_emirates_dubai\r
+235    osso_db_country_united_kingdom_of_great_britain_and_northern_ireland\r
+234    osso_db_country_united_kingdom_of_great_britain_and_northern_ireland\r
+310    osso_db_country_united_states_of_america\r
+316    osso_db_country_united_states_of_america\r
+311    osso_db_country_united_states_of_america\r
+312    osso_db_country_united_states_of_america\r
+313    osso_db_country_united_states_of_america\r
+314    osso_db_country_united_states_of_america\r
+315    osso_db_country_united_states_of_america\r
+332    osso_db_country_unites_states_virgin_islands\r
+748    osso_db_country_uruguay\r
+434    osso_db_country_uzbekistan\r
+541    osso_db_country_vanuatu\r
+225    osso_db_country_the_vatican\r
+734    osso_db_country_venezuela\r
+452    osso_db_country_viet_nam\r
+543    osso_db_country_wallis_and_futuna\r
+421    osso_db_country_yemen\r
+645    osso_db_country_zambia\r
+648    osso_db_country_zimbabwe\r
diff --git a/src/maemo/easysetup/mcc_mapping.en_GB b/src/maemo/easysetup/mcc_mapping.en_GB
new file mode 100644 (file)
index 0000000..491e504
--- /dev/null
@@ -0,0 +1,107 @@
+276    Albania\r
+213    Andorra\r
+722    Argentina\r
+363    Aruba\r
+505    Australia\r
+232    Austria\r
+400    Azerbaijan\r
+426    Bahrain\r
+470    Bangladesh\r
+257    Belarus\r
+206    Belgium\r
+736    Bolivia\r
+218    Bosnia and Herzegovina\r
+652    Botswana\r
+724    Brazil\r
+528    Brunei Darussalam\r
+284    Bulgaria\r
+456    Cambodia\r
+302    Canada\r
+730    Chile\r
+460    China\r
+732    Colombia\r
+219    Croatia\r
+280    Cyprus\r
+230    Czech Republic\r
+238    Denmark\r
+370    Dominican Republic\r
+740    Ecuador\r
+602    Egypt\r
+706    El Salvador\r
+248    Estonia\r
+244    Finland\r
+208    France\r
+282    Georgia\r
+262    Germany\r
+620    Ghana\r
+266    Gibraltar\r
+202    Greece\r
+340    Guadeloupe\r
+704    Guatemala\r
+708    Honduras\r
+454    Hong Kong, China\r
+216    Hungary\r
+274    Iceland\r
+404    India\r
+510    Indonesia\r
+272    Ireland\r
+425    Israel\r
+222    Italy\r
+338    Jamaica\r
+440    Japan\r
+416    Jordan\r
+401    Kazakhstan\r
+639    Kenya\r
+419    Kuwait\r
+247    Latvia\r
+415    Lebanon\r
+295    Liechtenstein\r
+246    Lithuania\r
+270    Luxembourg\r
+455    Macao, China\r
+294    Macedonia\r
+502    Malaysia\r
+472    Maldives\r
+278    Malta\r
+340    Martinique\r
+334    Mexico\r
+259    Moldova\r
+212    Monaco\r
+428    Mongolia\r
+220    Montenegro\r
+604    Morocco\r
+204    Netherlands\r
+530    New Zealand\r
+621    Nigeria\r
+242    Norway\r
+422    Oman\r
+410    Pakistan\r
+714    Panama\r
+744    Paraguay\r
+716    Peru\r
+515    Philippines\r
+260    Poland\r
+268    Portugal\r
+427    Qatar\r
+226    Romania\r
+250    Russian Federation\r
+420    Saudi Arabia\r
+220    Serbia\r
+525    Singapore\r
+231    Slovakia\r
+293    Slovenia\r
+655    South Africa\r
+214    Spain\r
+413    Sri Lanka\r
+240    Sweden\r
+228    Switzerland\r
+417    Syria\r
+466    Taiwan\r
+520    Thailand\r
+374    Trinidad and Tobago\r
+286    Turkey\r
+255    Ukraine\r
+234    United Kingdom\r
+748    Uruguay\r
+310    USA\r
+734    Venezuela\r
diff --git a/src/maemo/easysetup/modest-easysetup-country-combo-box.c b/src/maemo/easysetup/modest-easysetup-country-combo-box.c
new file mode 100644 (file)
index 0000000..7eed707
--- /dev/null
@@ -0,0 +1,304 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#define _GNU_SOURCE /* So we can use the getline() function, which is a convenient GNU extension. */
+#include <stdio.h>
+
+#include "modest-easysetup-country-combo-box.h"
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkcelllayout.h>
+#include <gtk/gtkcellrenderertext.h>
+
+#include <stdlib.h>
+#include <string.h> /* For memcpy() */
+
+#include <libintl.h> /* For dgettext(). */
+
+G_DEFINE_TYPE (EasysetupCountryComboBox, easysetup_country_combo_box, GTK_TYPE_COMBO_BOX);
+
+#define COUNTRY_COMBO_BOX_GET_PRIVATE(o) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((o), EASYSETUP_TYPE_COUNTRY_COMBO_BOX, EasysetupCountryComboBoxPrivate))
+
+typedef struct _EasysetupCountryComboBoxPrivate EasysetupCountryComboBoxPrivate;
+
+struct _EasysetupCountryComboBoxPrivate
+{
+       GtkTreeModel *model;
+};
+
+static void
+easysetup_country_combo_box_get_property (GObject *object, guint property_id,
+                                                                                                                       GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_country_combo_box_set_property (GObject *object, guint property_id,
+                                                                                                                       const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_country_combo_box_dispose (GObject *object)
+{
+       if (G_OBJECT_CLASS (easysetup_country_combo_box_parent_class)->dispose)
+               G_OBJECT_CLASS (easysetup_country_combo_box_parent_class)->dispose (object);
+}
+
+static void
+easysetup_country_combo_box_finalize (GObject *object)
+{
+       EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (object);
+
+       g_object_unref (G_OBJECT (priv->model));
+
+       G_OBJECT_CLASS (easysetup_country_combo_box_parent_class)->finalize (object);
+}
+
+static void
+easysetup_country_combo_box_class_init (EasysetupCountryComboBoxClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (EasysetupCountryComboBoxPrivate));
+
+       object_class->get_property = easysetup_country_combo_box_get_property;
+       object_class->set_property = easysetup_country_combo_box_set_property;
+       object_class->dispose = easysetup_country_combo_box_dispose;
+       object_class->finalize = easysetup_country_combo_box_finalize;
+}
+
+enum MODEL_COLS {
+       MODEL_COL_NAME = 0,
+       MODEL_COL_ID = 1
+};
+
+/** id and country must be freed.
+ */
+static void parse_mcc_mapping_line (const char* line, char** id, char** country)
+{
+       /* Initialize output parameters: */
+       *id = NULL;
+       *country = NULL;
+       
+       g_assert(line);
+       
+       const gboolean is_valid_utf8 = g_utf8_validate (line, -1, NULL);
+       if(!is_valid_utf8) {
+               g_warning("UTF8 validation failed.");
+               return;
+       }
+       
+       /* Look at each character, to find the whitespace between the ID and name: */
+       char* result_id = NULL;
+       char* result_country = NULL;
+       
+       const char* p = line;
+       const char* p_start_of_country = NULL;
+       while (p && *p)
+       {
+               p = g_utf8_next_char(p);
+               gunichar ch = g_utf8_get_char(p);
+               if (g_unichar_isspace(ch)) { /* Note: This checks for any whitespace, not just space. */
+                       if(!result_id) {
+                               /* The text before this must be the ID: */
+                               const int length = p - line;
+                               result_id = g_malloc (length + 1); /* 1 for null-termination. */
+                               memcpy(result_id, line, length);
+                               result_id[length] = 0; /* Null-termination. */
+                       }
+                       else if(p_start_of_country)
+                       {
+                               /* This whitespace is probably the newline after the country. */
+                               
+                               /* The text after the whitespace, after the ID, must be the country: */
+                               int length = p - p_start_of_country;
+                               result_country = g_malloc(length + 1);
+                               memcpy(result_country, p_start_of_country, length);
+                               result_country[length] = 0; /* Null-termination. */
+                               break;
+                       }
+               }
+               else if(result_id && !p_start_of_country) {
+                       p_start_of_country = p;
+               }
+       }
+       
+       *id = result_id;
+       *country = result_country;
+}
+
+/** Note that the mcc_mapping file is installed 
+ * by the operator-wizard-settings package.
+ */
+static void load_from_file (EasysetupCountryComboBox *self)
+{
+       EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (self);
+       
+       /* Load the file one line at a time: */
+       FILE *file = fopen("mcc_mapping", "r");
+       if (!file)
+       {
+               g_warning("Could not open mcc_mapping file.\n");
+               return;
+       }
+
+       GtkListStore *liststore = GTK_LIST_STORE (priv->model);
+                       
+       /* We use the getline() GNU extension,
+        * because it reads per line, which simplifies our code,
+        * and it doesn't require us to hard-code a buffer length.
+        */
+       int len = 0;
+       char *line = NULL;
+       while (getline (&line, &len, file) > 0) /* getline will realloc line if necessary. */
+       {
+               /* printf ("DBEUG: len=%d, line: %s\n", len, line); */
+               
+               char *id_str = NULL;
+               char *country = NULL;
+               parse_mcc_mapping_line (line, &id_str, &country);
+               /* printf("DEBUG: parsed: id=%s, country=%s\n", id_str, country); */
+               
+               if(id_str && country) {
+                       guint id = (guint)g_ascii_strtod(id_str, NULL); /* Note that this parses locale-independent text. */
+                       
+                       /* Get the translation for the country name:
+                        * Note that the osso_countries_1.0 translation domain files are installed 
+                        * by the operator-wizard-settings package. */
+                       const gchar *name_translated = dgettext ("osso_countries_1.0", country);
+                       if(!name_translated)
+                         name_translated = country;
+                       
+                       /* Add the row to the model: */
+                       GtkTreeIter iter;
+                       gtk_list_store_append (liststore, &iter);
+                       gtk_list_store_set(liststore, &iter, MODEL_COL_ID, id, MODEL_COL_NAME, name_translated, -1);
+               }
+               
+               g_free (id_str);
+               g_free (country);
+       }
+
+       if (line)
+               free (line);
+               
+       fclose (file);
+}
+
+static void
+easysetup_country_combo_box_init (EasysetupCountryComboBox *self)
+{
+       EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (self);
+
+       /* Create a tree model for the combo box,
+        * with a string for the name, and an int for the MCC ID.
+        * This must match our MODEL_COLS enum constants.
+        */
+       priv->model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_UINT));
+
+       /* Setup the combo box: */
+       GtkComboBox *combobox = GTK_COMBO_BOX (self);
+       gtk_combo_box_set_model (combobox, priv->model);
+
+       /* Country column:
+        * The ID model column in not shown in the view. */
+       GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combobox), renderer, TRUE);
+       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, 
+       "text", MODEL_COL_NAME, NULL);
+       
+       /* Fill the model with rows: */
+       load_from_file (self);
+}
+
+EasysetupCountryComboBox*
+easysetup_country_combo_box_new (void)
+{
+       return g_object_new (EASYSETUP_TYPE_COUNTRY_COMBO_BOX, NULL);
+}
+
+/**
+ * Returns the MCC number of the selected country, or 0 if no country was selected. 
+ */
+guint
+easysetup_country_combo_box_get_active_country_id (EasysetupCountryComboBox *self)
+{
+       GtkTreeIter active;
+       const gboolean found = gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self), &active);
+       if (found) {
+               EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (self);
+
+               guint id = 0;
+               gtk_tree_model_get (priv->model, &active, MODEL_COL_ID, &id, -1); 
+               return id;      
+       }
+
+       return 0; /* Failed. */
+}
+
+
+/* This allows us to pass more than one piece of data to the signal handler,
+ * and get a result: */
+typedef struct 
+{
+               EasysetupCountryComboBox* self;
+               guint mcc_id;
+               gboolean found;
+} ForEachData;
+
+static gboolean
+on_model_foreach_select_id(GtkTreeModel *model, 
+       GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
+{
+       ForEachData *state = (ForEachData*)(user_data);
+       
+       /* Select the item if it has the matching ID: */
+       guint id = 0;
+       gtk_tree_model_get (model, iter, MODEL_COL_ID, &id, -1); 
+       if(id == state->mcc_id) {
+               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->self), iter);
+               
+               state->found = TRUE;
+               return TRUE; /* Stop walking the tree. */
+       }
+       
+       return FALSE; /* Keep walking the tree. */
+}
+
+/**
+ * Selects the MCC number of the selected country.
+ * Specify 0 to select no country. 
+ */
+gboolean
+easysetup_country_combo_box_set_active_country_id (EasysetupCountryComboBox *self, guint mcc_id)
+{
+       EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (self);
+       
+       /* Create a state instance so we can send two items of data to the signal handler: */
+       ForEachData *state = g_new0 (ForEachData, 1);
+       state->self = self;
+       state->mcc_id = mcc_id;
+       state->found = FALSE;
+       
+       /* Look at each item, and select the one with the correct ID: */
+       gtk_tree_model_foreach (priv->model, &on_model_foreach_select_id, state);
+
+       const gboolean result = state->found;
+       
+       /* Free the state instance: */
+       g_free(state);
+       
+       return result;
+}
+
diff --git a/src/maemo/easysetup/modest-easysetup-country-combo-box.h b/src/maemo/easysetup/modest-easysetup-country-combo-box.h
new file mode 100644 (file)
index 0000000..410e638
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#ifndef _EASYSETUP_COUNTRY_COMBO_BOX
+#define _EASYSETUP_COUNTRY_COMBO_BOX
+
+#include <gtk/gtkcombobox.h>
+
+G_BEGIN_DECLS
+
+#define EASYSETUP_TYPE_COUNTRY_COMBO_BOX easysetup_country_combo_box_get_type()
+
+#define EASYSETUP_COUNTRY_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       EASYSETUP_TYPE_COUNTRY_COMBO_BOX, EasysetupCountryComboBox))
+
+#define EASYSETUP_COUNTRY_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_CAST ((klass), \
+       EASYSETUP_TYPE_COUNTRY_COMBO_BOX, EasysetupCountryComboBoxClass))
+
+#define EASYSETUP_IS_COUNTRY_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       EASYSETUP_TYPE_COUNTRY_COMBO_BOX))
+
+#define EASYSETUP_IS_COUNTRY_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       EASYSETUP_TYPE_COUNTRY_COMBO_BOX))
+
+#define EASYSETUP_COUNTRY_COMBO_BOX_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       EASYSETUP_TYPE_COUNTRY_COMBO_BOX, EasysetupCountryComboBoxClass))
+
+typedef struct {
+       GtkComboBox parent;
+} EasysetupCountryComboBox;
+
+typedef struct {
+       GtkComboBoxClass parent_class;
+} EasysetupCountryComboBoxClass;
+
+GType easysetup_country_combo_box_get_type (void);
+
+EasysetupCountryComboBox* easysetup_country_combo_box_new (void);
+
+guint easysetup_country_combo_box_get_active_country_id (EasysetupCountryComboBox *self);
+gboolean easysetup_country_combo_box_set_active_country_id (EasysetupCountryComboBox *self, guint mcc_id);
+
+G_END_DECLS
+
+#endif /* _EASYSETUP_COUNTRY_COMBO_BOX */
diff --git a/src/maemo/easysetup/modest-easysetup-provider-combo-box.c b/src/maemo/easysetup/modest-easysetup-provider-combo-box.c
new file mode 100644 (file)
index 0000000..c68b662
--- /dev/null
@@ -0,0 +1,189 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#define _GNU_SOURCE /* So we can use the getline() function, which is a convenient GNU extension. */
+#include <stdio.h>
+
+#include "modest-easysetup-provider-combo-box.h"
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkcelllayout.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <glib/gi18n.h>
+
+#include <stdlib.h>
+#include <string.h> /* For memcpy() */
+
+G_DEFINE_TYPE (EasysetupProviderComboBox, easysetup_provider_combo_box, GTK_TYPE_COMBO_BOX);
+
+#define PROVIDER_COMBO_BOX_GET_PRIVATE(o) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((o), EASYSETUP_TYPE_PROVIDER_COMBO_BOX, EasysetupProviderComboBoxPrivate))
+
+typedef struct _EasysetupProviderComboBoxPrivate EasysetupProviderComboBoxPrivate;
+
+struct _EasysetupProviderComboBoxPrivate
+{
+       GtkTreeModel *model;
+};
+
+static void
+easysetup_provider_combo_box_get_property (GObject *object, guint property_id,
+                                                                                                                       GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_provider_combo_box_set_property (GObject *object, guint property_id,
+                                                                                                                       const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_provider_combo_box_dispose (GObject *object)
+{
+       if (G_OBJECT_CLASS (easysetup_provider_combo_box_parent_class)->dispose)
+               G_OBJECT_CLASS (easysetup_provider_combo_box_parent_class)->dispose (object);
+}
+
+static void
+easysetup_provider_combo_box_finalize (GObject *object)
+{
+       EasysetupProviderComboBoxPrivate *priv = PROVIDER_COMBO_BOX_GET_PRIVATE (object);
+
+       g_object_unref (G_OBJECT (priv->model));
+
+       G_OBJECT_CLASS (easysetup_provider_combo_box_parent_class)->finalize (object);
+}
+
+static void
+easysetup_provider_combo_box_class_init (EasysetupProviderComboBoxClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (EasysetupProviderComboBoxPrivate));
+
+       object_class->get_property = easysetup_provider_combo_box_get_property;
+       object_class->set_property = easysetup_provider_combo_box_set_property;
+       object_class->dispose = easysetup_provider_combo_box_dispose;
+       object_class->finalize = easysetup_provider_combo_box_finalize;
+}
+
+enum MODEL_COLS {
+       MODEL_COL_NAME = 0,
+       MODEL_COL_ID = 1 /* a string, not an int. */
+};
+
+
+
+static void
+easysetup_provider_combo_box_init (EasysetupProviderComboBox *self)
+{
+       EasysetupProviderComboBoxPrivate *priv = PROVIDER_COMBO_BOX_GET_PRIVATE (self);
+
+       /* Create a tree model for the combo box,
+        * with a string for the name, and a string for the ID (e.g. "vodafone.it").
+        * This must match our MODEL_COLS enum constants.
+        */
+       priv->model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING));
+
+       /* Setup the combo box: */
+       GtkComboBox *combobox = GTK_COMBO_BOX (self);
+       gtk_combo_box_set_model (combobox, priv->model);
+
+       /* Provider column:
+        * The ID model column in not shown in the view. */
+       GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combobox), renderer, TRUE);
+       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, 
+       "text", MODEL_COL_NAME, NULL);
+       
+       /* The application should call easysetup_provider_combo_box_fill()
+        * to actually add some rows. */
+}
+
+EasysetupProviderComboBox*
+easysetup_provider_combo_box_new (void)
+{
+       return g_object_new (EASYSETUP_TYPE_PROVIDER_COMBO_BOX, NULL);
+}
+
+void easysetup_provider_combo_box_fill (EasysetupProviderComboBox *combobox, ModestPresets *presets, gint country_id)
+{      
+       EasysetupProviderComboBoxPrivate *priv = PROVIDER_COMBO_BOX_GET_PRIVATE (combobox);
+       
+       /* Remove any existing rows: */
+       GtkListStore *liststore = GTK_LIST_STORE (priv->model);
+       gtk_list_store_clear (liststore);
+       
+       /* Add the appropriate rows for this country, from the presets file: */
+       gchar ** provider_ids = NULL;
+       gchar ** provider_names = modest_presets_get_providers (presets, country_id, 
+               TRUE /* include_globals */, &provider_ids);
+       
+       gchar ** iter_provider_names = provider_names;
+       gchar ** iter_provider_ids = provider_ids;
+       while(iter_provider_names && *iter_provider_names && iter_provider_ids && *iter_provider_ids)
+       {
+               const gchar* provider_name = *iter_provider_names;
+               if(!provider_name)
+                       continue;
+                       
+               const gchar* provider_id = *iter_provider_ids;
+               if(!provider_id)
+                       continue;
+               
+               /* printf("debug: provider_name=%s\n", provider_name); */
+       
+               /* Add the row: */
+               GtkTreeIter iter;
+               gtk_list_store_append (liststore, &iter);
+               gtk_list_store_set(liststore, &iter, MODEL_COL_ID, provider_id, MODEL_COL_NAME, provider_name, -1);
+               
+               ++iter_provider_names;
+               ++iter_provider_ids;    
+       }
+       
+       /* Free the result of modest_presets_get_providers()
+        * as specified by its documentation: */
+       g_strfreev (provider_names);
+       g_strfreev (provider_ids);
+       
+       /* Add the "Other" item: */
+       /* Note that ID 0 means "Other" for us: */
+       /* TODO: We need a Logical ID for this text. */
+       GtkTreeIter iter;
+       gtk_list_store_append (liststore, &iter);
+       gtk_list_store_set (liststore, &iter, MODEL_COL_ID, 0, MODEL_COL_NAME, _("Other..."), -1);
+       
+       /* Select the "Other" item: */
+       gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combobox), &iter);
+}
+
+/**
+ * Returns the MCC number of the selected provider, 
+ * or NULL if no provider was selected, or "Other" was selected. 
+ */
+gchar*
+easysetup_provider_combo_box_get_active_provider_id (EasysetupProviderComboBox *combobox)
+{
+       GtkTreeIter active;
+       const gboolean found = gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combobox), &active);
+       if (found) {
+               EasysetupProviderComboBoxPrivate *priv = PROVIDER_COMBO_BOX_GET_PRIVATE (combobox);
+
+               gchar *id = NULL;
+               gtk_tree_model_get (priv->model, &active, MODEL_COL_ID, &id, -1);
+               return g_strdup(id);    
+       }
+
+       return NULL; /* Failed. */
+}
diff --git a/src/maemo/easysetup/modest-easysetup-provider-combo-box.h b/src/maemo/easysetup/modest-easysetup-provider-combo-box.h
new file mode 100644 (file)
index 0000000..d6d07c2
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#ifndef _EASYSETUP_PROVIDER_COMBO_BOX
+#define _EASYSETUP_PROVIDER_COMBO_BOX
+
+#include <gtk/gtkcombobox.h>
+#include "modest-presets.h"
+
+G_BEGIN_DECLS
+
+#define EASYSETUP_TYPE_PROVIDER_COMBO_BOX easysetup_provider_combo_box_get_type()
+
+#define EASYSETUP_PROVIDER_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       EASYSETUP_TYPE_PROVIDER_COMBO_BOX, EasysetupProviderComboBox))
+
+#define EASYSETUP_PROVIDER_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_CAST ((klass), \
+       EASYSETUP_TYPE_PROVIDER_COMBO_BOX, EasysetupProviderComboBoxClass))
+
+#define EASYSETUP_IS_PROVIDER_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       EASYSETUP_TYPE_PROVIDER_COMBO_BOX))
+
+#define EASYSETUP_IS_PROVIDER_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       EASYSETUP_TYPE_PROVIDER_COMBO_BOX))
+
+#define EASYSETUP_PROVIDER_COMBO_BOX_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       EASYSETUP_TYPE_PROVIDER_COMBO_BOX, EasysetupProviderComboBoxClass))
+
+typedef struct {
+       GtkComboBox parent;
+} EasysetupProviderComboBox;
+
+typedef struct {
+       GtkComboBoxClass parent_class;
+} EasysetupProviderComboBoxClass;
+
+GType easysetup_provider_combo_box_get_type (void);
+
+EasysetupProviderComboBox* easysetup_provider_combo_box_new (void);
+
+void easysetup_provider_combo_box_fill (EasysetupProviderComboBox *combobox, ModestPresets *presets, gint country_id);
+
+gchar* easysetup_provider_combo_box_get_active_provider_id (EasysetupProviderComboBox *combobox);
+
+G_END_DECLS
+
+#endif /* _EASYSETUP_PROVIDER_COMBO_BOX */
diff --git a/src/maemo/easysetup/modest-easysetup-secureauth-combo-box.c b/src/maemo/easysetup/modest-easysetup-secureauth-combo-box.c
new file mode 100644 (file)
index 0000000..01c8453
--- /dev/null
@@ -0,0 +1,218 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#define _GNU_SOURCE /* So we can use the getline() function, which is a convenient GNU extension. */
+#include <stdio.h>
+
+#include "modest-easysetup-secureauth-combo-box.h"
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkcelllayout.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <glib/gi18n.h>
+
+#include <stdlib.h>
+#include <string.h> /* For memcpy() */
+
+G_DEFINE_TYPE (EasysetupSecureauthComboBox, easysetup_secureauth_combo_box, GTK_TYPE_COMBO_BOX);
+
+#define SECUREAUTH_COMBO_BOX_GET_PRIVATE(o) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((o), EASYSETUP_TYPE_SECUREAUTH_COMBO_BOX, EasysetupSecureauthComboBoxPrivate))
+
+typedef struct _EasysetupSecureauthComboBoxPrivate EasysetupSecureauthComboBoxPrivate;
+
+struct _EasysetupSecureauthComboBoxPrivate
+{
+       GtkTreeModel *model;
+};
+
+static void
+easysetup_secureauth_combo_box_get_property (GObject *object, guint property_id,
+                                                                                                                       GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_secureauth_combo_box_set_property (GObject *object, guint property_id,
+                                                                                                                       const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_secureauth_combo_box_dispose (GObject *object)
+{
+       if (G_OBJECT_CLASS (easysetup_secureauth_combo_box_parent_class)->dispose)
+               G_OBJECT_CLASS (easysetup_secureauth_combo_box_parent_class)->dispose (object);
+}
+
+static void
+easysetup_secureauth_combo_box_finalize (GObject *object)
+{
+       EasysetupSecureauthComboBoxPrivate *priv = SECUREAUTH_COMBO_BOX_GET_PRIVATE (object);
+
+       g_object_unref (G_OBJECT (priv->model));
+
+       G_OBJECT_CLASS (easysetup_secureauth_combo_box_parent_class)->finalize (object);
+}
+
+static void
+easysetup_secureauth_combo_box_class_init (EasysetupSecureauthComboBoxClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (EasysetupSecureauthComboBoxPrivate));
+
+       object_class->get_property = easysetup_secureauth_combo_box_get_property;
+       object_class->set_property = easysetup_secureauth_combo_box_set_property;
+       object_class->dispose = easysetup_secureauth_combo_box_dispose;
+       object_class->finalize = easysetup_secureauth_combo_box_finalize;
+}
+
+enum MODEL_COLS {
+       MODEL_COL_NAME = 0, /* a string */
+       MODEL_COL_ID = 1 /* an int. */
+};
+
+void easysetup_secureauth_combo_box_fill (EasysetupSecureauthComboBox *combobox);
+
+static void
+easysetup_secureauth_combo_box_init (EasysetupSecureauthComboBox *self)
+{
+       EasysetupSecureauthComboBoxPrivate *priv = SECUREAUTH_COMBO_BOX_GET_PRIVATE (self);
+
+       /* Create a tree model for the combo box,
+        * with a string for the name, and an ID for the secureauth.
+        * This must match our MODEL_COLS enum constants.
+        */
+       priv->model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
+
+       /* Setup the combo box: */
+       GtkComboBox *combobox = GTK_COMBO_BOX (self);
+       gtk_combo_box_set_model (combobox, priv->model);
+
+       /* Secureauth column:
+        * The ID model column in not shown in the view. */
+       GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combobox), renderer, TRUE);
+       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, 
+       "text", MODEL_COL_NAME, NULL);
+       
+       easysetup_secureauth_combo_box_fill (self);
+}
+
+EasysetupSecureauthComboBox*
+easysetup_secureauth_combo_box_new (void)
+{
+       return g_object_new (EASYSETUP_TYPE_SECUREAUTH_COMBO_BOX, NULL);
+}
+
+/* Fill the combo box with appropriate choices.
+ * #combobox: The combo box.
+ * @protocol: IMAP or POP.
+ */
+void easysetup_secureauth_combo_box_fill (EasysetupSecureauthComboBox *combobox)
+{      
+       EasysetupSecureauthComboBoxPrivate *priv = SECUREAUTH_COMBO_BOX_GET_PRIVATE (combobox);
+       
+       /* Remove any existing rows: */
+       GtkListStore *liststore = GTK_LIST_STORE (priv->model);
+       gtk_list_store_clear (liststore);
+       
+       GtkTreeIter iter;
+       gtk_list_store_append (liststore, &iter);
+       gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)MODEST_PROTOCOL_AUTH_NONE, MODEL_COL_NAME, _("mcen_fi_advsetup_smtp_none"), -1);
+       
+       /* Select the None item: */
+       gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combobox), &iter);
+       
+       gtk_list_store_append (liststore, &iter);
+       gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)MODEST_PROTOCOL_AUTH_PASSWORD, MODEL_COL_NAME, _("mcen_fi_advsetup_smtp_login"), -1);
+       
+       /* TODO: I can't find a ModestProtocol enum flag for this: */
+       gtk_list_store_append (liststore, &iter);
+       gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)0, MODEL_COL_NAME, _("mcen_fi_advsetup_smtp_cram_md5"), -1);
+}
+
+/**
+ * Returns the selected secureauth, 
+ * or MODEST_PROTOCOL_UNKNOWN if no secureauth was selected.
+ */
+ModestProtocol
+easysetup_secureauth_combo_box_get_active_secureauth (EasysetupSecureauthComboBox *combobox)
+{
+       GtkTreeIter active;
+       const gboolean found = gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combobox), &active);
+       if (found) {
+               EasysetupSecureauthComboBoxPrivate *priv = SECUREAUTH_COMBO_BOX_GET_PRIVATE (combobox);
+
+               ModestProtocol secureauth = MODEST_PROTOCOL_UNKNOWN;
+               gtk_tree_model_get (priv->model, &active, MODEL_COL_ID, &secureauth, -1);
+               return secureauth;      
+       }
+
+       return MODEST_PROTOCOL_UNKNOWN; /* Failed. */
+}
+
+/* This allows us to pass more than one piece of data to the signal handler,
+ * and get a result: */
+typedef struct 
+{
+               EasysetupSecureauthComboBox* self;
+               gint id;
+               gboolean found;
+} ForEachData;
+
+static gboolean
+on_model_foreach_select_id(GtkTreeModel *model, 
+       GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
+{
+       ForEachData *state = (ForEachData*)(user_data);
+       
+       /* Select the item if it has the matching ID: */
+       guint id = 0;
+       gtk_tree_model_get (model, iter, MODEL_COL_ID, &id, -1); 
+       if(id == state->id) {
+               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->self), iter);
+               
+               state->found = TRUE;
+               return TRUE; /* Stop walking the tree. */
+       }
+       
+       return FALSE; /* Keep walking the tree. */
+}
+
+/**
+ * Selects the specified secureauth, 
+ * or MODEST_PROTOCOL_UNKNOWN if no secureauth was selected.
+ */
+gboolean
+easysetup_secureauth_combo_box_set_active_secureauth (EasysetupSecureauthComboBox *combobox, ModestProtocol secureauth)
+{
+       EasysetupSecureauthComboBoxPrivate *priv = SECUREAUTH_COMBO_BOX_GET_PRIVATE (combobox);
+       
+       /* Create a state instance so we can send two items of data to the signal handler: */
+       ForEachData *state = g_new0 (ForEachData, 1);
+       state->self = combobox;
+       state->id = secureauth;
+       state->found = FALSE;
+       
+       /* Look at each item, and select the one with the correct ID: */
+       gtk_tree_model_foreach (priv->model, &on_model_foreach_select_id, state);
+
+       const gboolean result = state->found;
+       
+       /* Free the state instance: */
+       g_free(state);
+       
+       return result;
+}
+
diff --git a/src/maemo/easysetup/modest-easysetup-secureauth-combo-box.h b/src/maemo/easysetup/modest-easysetup-secureauth-combo-box.h
new file mode 100644 (file)
index 0000000..bb1fd8e
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#ifndef _EASYSETUP_SECUREAUTH_COMBO_BOX
+#define _EASYSETUP_SECUREAUTH_COMBO_BOX
+
+#include <gtk/gtkcombobox.h>
+#include "modest-account-mgr/modest-protocol-info.h"
+
+G_BEGIN_DECLS
+
+#define EASYSETUP_TYPE_SECUREAUTH_COMBO_BOX easysetup_secureauth_combo_box_get_type()
+
+#define EASYSETUP_SECUREAUTH_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       EASYSETUP_TYPE_SECUREAUTH_COMBO_BOX, EasysetupSecureauthComboBox))
+
+#define EASYSETUP_SECUREAUTH_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_CAST ((klass), \
+       EASYSETUP_TYPE_SECUREAUTH_COMBO_BOX, EasysetupSecureauthComboBoxClass))
+
+#define EASYSETUP_IS_SECUREAUTH_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       EASYSETUP_TYPE_SECUREAUTH_COMBO_BOX))
+
+#define EASYSETUP_IS_SECUREAUTH_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       EASYSETUP_TYPE_SECUREAUTH_COMBO_BOX))
+
+#define EASYSETUP_SECUREAUTH_COMBO_BOX_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       EASYSETUP_TYPE_SECUREAUTH_COMBO_BOX, EasysetupSecureauthComboBoxClass))
+
+typedef struct {
+       GtkComboBox parent;
+} EasysetupSecureauthComboBox;
+
+typedef struct {
+       GtkComboBoxClass parent_class;
+} EasysetupSecureauthComboBoxClass;
+
+GType easysetup_secureauth_combo_box_get_type (void);
+
+EasysetupSecureauthComboBox* easysetup_secureauth_combo_box_new (void);
+
+ModestProtocol easysetup_secureauth_combo_box_get_active_secureauth (EasysetupSecureauthComboBox *combobox);
+
+gboolean easysetup_secureauth_combo_box_set_active_secureauth (EasysetupSecureauthComboBox *combobox, ModestProtocol secureauth);
+
+
+G_END_DECLS
+
+#endif /* _EASYSETUP_PROVIDER_COMBO_BOX */
diff --git a/src/maemo/easysetup/modest-easysetup-serversecurity-combo-box.c b/src/maemo/easysetup/modest-easysetup-serversecurity-combo-box.c
new file mode 100644 (file)
index 0000000..5486e12
--- /dev/null
@@ -0,0 +1,226 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#define _GNU_SOURCE /* So we can use the getline() function, which is a convenient GNU extension. */
+#include <stdio.h>
+
+#include "modest-easysetup-serversecurity-combo-box.h"
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkcelllayout.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <glib/gi18n.h>
+
+#include <stdlib.h>
+#include <string.h> /* For memcpy() */
+
+G_DEFINE_TYPE (EasysetupServersecurityComboBox, easysetup_serversecurity_combo_box, GTK_TYPE_COMBO_BOX);
+
+#define SERVERSECURITY_COMBO_BOX_GET_PRIVATE(o) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((o), EASYSETUP_TYPE_SERVERSECURITY_COMBO_BOX, EasysetupServersecurityComboBoxPrivate))
+
+typedef struct _EasysetupServersecurityComboBoxPrivate EasysetupServersecurityComboBoxPrivate;
+
+struct _EasysetupServersecurityComboBoxPrivate
+{
+       GtkTreeModel *model;
+};
+
+static void
+easysetup_serversecurity_combo_box_get_property (GObject *object, guint property_id,
+                                                                                                                       GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_serversecurity_combo_box_set_property (GObject *object, guint property_id,
+                                                                                                                       const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_serversecurity_combo_box_dispose (GObject *object)
+{
+       if (G_OBJECT_CLASS (easysetup_serversecurity_combo_box_parent_class)->dispose)
+               G_OBJECT_CLASS (easysetup_serversecurity_combo_box_parent_class)->dispose (object);
+}
+
+static void
+easysetup_serversecurity_combo_box_finalize (GObject *object)
+{
+       EasysetupServersecurityComboBoxPrivate *priv = SERVERSECURITY_COMBO_BOX_GET_PRIVATE (object);
+
+       g_object_unref (G_OBJECT (priv->model));
+
+       G_OBJECT_CLASS (easysetup_serversecurity_combo_box_parent_class)->finalize (object);
+}
+
+static void
+easysetup_serversecurity_combo_box_class_init (EasysetupServersecurityComboBoxClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (EasysetupServersecurityComboBoxPrivate));
+
+       object_class->get_property = easysetup_serversecurity_combo_box_get_property;
+       object_class->set_property = easysetup_serversecurity_combo_box_set_property;
+       object_class->dispose = easysetup_serversecurity_combo_box_dispose;
+       object_class->finalize = easysetup_serversecurity_combo_box_finalize;
+}
+
+enum MODEL_COLS {
+       MODEL_COL_NAME = 0, /* a string */
+       MODEL_COL_ID = 1 /* an int. */
+};
+
+static void
+easysetup_serversecurity_combo_box_init (EasysetupServersecurityComboBox *self)
+{
+       EasysetupServersecurityComboBoxPrivate *priv = SERVERSECURITY_COMBO_BOX_GET_PRIVATE (self);
+
+       /* Create a tree model for the combo box,
+        * with a string for the name, and an ID for the serversecurity.
+        * This must match our MODEL_COLS enum constants.
+        */
+       priv->model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
+
+       /* Setup the combo box: */
+       GtkComboBox *combobox = GTK_COMBO_BOX (self);
+       gtk_combo_box_set_model (combobox, priv->model);
+
+       /* Serversecurity column:
+        * The ID model column in not shown in the view. */
+       GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combobox), renderer, TRUE);
+       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, 
+       "text", MODEL_COL_NAME, NULL);
+       
+       /* The application must call easysetup_serversecurity_combo_box_fill().
+        */
+}
+
+EasysetupServersecurityComboBox*
+easysetup_serversecurity_combo_box_new (void)
+{
+       return g_object_new (EASYSETUP_TYPE_SERVERSECURITY_COMBO_BOX, NULL);
+}
+
+/* Fill the combo box with appropriate choices.
+ * #combobox: The combo box.
+ * @protocol: IMAP or POP.
+ */
+void easysetup_serversecurity_combo_box_fill (EasysetupServersecurityComboBox *combobox, ModestProtocol protocol)
+{      
+       EasysetupServersecurityComboBoxPrivate *priv = SERVERSECURITY_COMBO_BOX_GET_PRIVATE (combobox);
+       
+       /* Remove any existing rows: */
+       GtkListStore *liststore = GTK_LIST_STORE (priv->model);
+       gtk_list_store_clear (liststore);
+       
+       GtkTreeIter iter;
+       gtk_list_store_append (liststore, &iter);
+       gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)MODEST_PROTOCOL_SECURITY_NONE, MODEL_COL_NAME, _("mcen_fi_advsetup_other_security_none"), -1);
+       
+       /* Select the None item: */
+       gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combobox), &iter);
+       
+       gtk_list_store_append (liststore, &iter);
+       gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)MODEST_PROTOCOL_SECURITY_TLS, MODEL_COL_NAME, _("mcen_fi_advsetup_other_security_normal"), -1);
+       
+       /* Add security choices with protocol-specific names, as in the UI spec:
+        * (Note: Changing the title seems pointless. murrayc) */
+       if(protocol == MODEST_PROTOCOL_STORE_POP) {
+               gtk_list_store_append (liststore, &iter);
+               gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)MODEST_PROTOCOL_SECURITY_SSL, MODEL_COL_NAME, _("mcen_fi_advsetup_other_security_securepop3s"), -1);
+       } else if(protocol == MODEST_PROTOCOL_STORE_IMAP) {
+               gtk_list_store_append (liststore, &iter);
+               gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)MODEST_PROTOCOL_SECURITY_SSL, MODEL_COL_NAME, _("mcen_fi_advsetup_other_security_secureimap4"), -1);
+       } else if(protocol == MODEST_PROTOCOL_TRANSPORT_SMTP) {
+               gtk_list_store_append (liststore, &iter);
+               gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)MODEST_PROTOCOL_SECURITY_SSL, MODEL_COL_NAME, _("mcen_fi_advsetup_other_security_ssl"), -1);
+       }
+}
+
+/**
+ * Returns the selected serversecurity, 
+ * or MODEST_PROTOCOL_UNKNOWN if no serversecurity was selected.
+ */
+ModestProtocol
+easysetup_serversecurity_combo_box_get_active_serversecurity (EasysetupServersecurityComboBox *combobox)
+{
+       GtkTreeIter active;
+       const gboolean found = gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combobox), &active);
+       if (found) {
+               EasysetupServersecurityComboBoxPrivate *priv = SERVERSECURITY_COMBO_BOX_GET_PRIVATE (combobox);
+
+               ModestProtocol serversecurity = MODEST_PROTOCOL_UNKNOWN;
+               gtk_tree_model_get (priv->model, &active, MODEL_COL_ID, &serversecurity, -1);
+               return serversecurity;  
+       }
+
+       return MODEST_PROTOCOL_UNKNOWN; /* Failed. */
+}
+
+/* This allows us to pass more than one piece of data to the signal handler,
+ * and get a result: */
+typedef struct 
+{
+               EasysetupServersecurityComboBox* self;
+               gint id;
+               gboolean found;
+} ForEachData;
+
+static gboolean
+on_model_foreach_select_id(GtkTreeModel *model, 
+       GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
+{
+       ForEachData *state = (ForEachData*)(user_data);
+       
+       /* Select the item if it has the matching ID: */
+       guint id = 0;
+       gtk_tree_model_get (model, iter, MODEL_COL_ID, &id, -1); 
+       if(id == state->id) {
+               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->self), iter);
+               
+               state->found = TRUE;
+               return TRUE; /* Stop walking the tree. */
+       }
+       
+       return FALSE; /* Keep walking the tree. */
+}
+
+/**
+ * Selects the specified serversecurity, 
+ * or MODEST_PROTOCOL_UNKNOWN if no serversecurity was selected.
+ */
+gboolean
+easysetup_serversecurity_combo_box_set_active_serversecurity (EasysetupServersecurityComboBox *combobox, ModestProtocol serversecurity)
+{
+       EasysetupServersecurityComboBoxPrivate *priv = SERVERSECURITY_COMBO_BOX_GET_PRIVATE (combobox);
+       
+       /* Create a state instance so we can send two items of data to the signal handler: */
+       ForEachData *state = g_new0 (ForEachData, 1);
+       state->self = combobox;
+       state->id = serversecurity;
+       state->found = FALSE;
+       
+       /* Look at each item, and select the one with the correct ID: */
+       gtk_tree_model_foreach (priv->model, &on_model_foreach_select_id, state);
+
+       const gboolean result = state->found;
+       
+       /* Free the state instance: */
+       g_free(state);
+       
+       return result;
+}
+
diff --git a/src/maemo/easysetup/modest-easysetup-serversecurity-combo-box.h b/src/maemo/easysetup/modest-easysetup-serversecurity-combo-box.h
new file mode 100644 (file)
index 0000000..fb08ec7
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#ifndef _EASYSETUP_SERVERSECURITY_COMBO_BOX
+#define _EASYSETUP_SERVERSECURITY_COMBO_BOX
+
+#include <gtk/gtkcombobox.h>
+#include "modest-account-mgr/modest-protocol-info.h"
+
+G_BEGIN_DECLS
+
+#define EASYSETUP_TYPE_SERVERSECURITY_COMBO_BOX easysetup_serversecurity_combo_box_get_type()
+
+#define EASYSETUP_SERVERSECURITY_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       EASYSETUP_TYPE_SERVERSECURITY_COMBO_BOX, EasysetupServersecurityComboBox))
+
+#define EASYSETUP_SERVERSECURITY_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_CAST ((klass), \
+       EASYSETUP_TYPE_SERVERSECURITY_COMBO_BOX, EasysetupServersecurityComboBoxClass))
+
+#define EASYSETUP_IS_SERVERSECURITY_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       EASYSETUP_TYPE_SERVERSECURITY_COMBO_BOX))
+
+#define EASYSETUP_IS_SERVERSECURITY_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       EASYSETUP_TYPE_SERVERSECURITY_COMBO_BOX))
+
+#define EASYSETUP_SERVERSECURITY_COMBO_BOX_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       EASYSETUP_TYPE_SERVERSECURITY_COMBO_BOX, EasysetupServersecurityComboBoxClass))
+
+typedef struct {
+       GtkComboBox parent;
+} EasysetupServersecurityComboBox;
+
+typedef struct {
+       GtkComboBoxClass parent_class;
+} EasysetupServersecurityComboBoxClass;
+
+GType easysetup_serversecurity_combo_box_get_type (void);
+
+EasysetupServersecurityComboBox* easysetup_serversecurity_combo_box_new (void);
+
+void easysetup_serversecurity_combo_box_fill (EasysetupServersecurityComboBox *combobox, ModestProtocol protocol);
+
+ModestProtocol easysetup_serversecurity_combo_box_get_active_serversecurity (EasysetupServersecurityComboBox *combobox);
+
+gboolean easysetup_serversecurity_combo_box_set_active_serversecurity (EasysetupServersecurityComboBox *combobox, ModestProtocol serversecurity);
+
+
+G_END_DECLS
+
+#endif /* _EASYSETUP_PROVIDER_COMBO_BOX */
diff --git a/src/maemo/easysetup/modest-easysetup-servertype-combo-box.c b/src/maemo/easysetup/modest-easysetup-servertype-combo-box.c
new file mode 100644 (file)
index 0000000..7e87ecb
--- /dev/null
@@ -0,0 +1,211 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#define _GNU_SOURCE /* So we can use the getline() function, which is a convenient GNU extension. */
+#include <stdio.h>
+
+#include "modest-easysetup-servertype-combo-box.h"
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkcelllayout.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <glib/gi18n.h>
+
+#include <stdlib.h>
+#include <string.h> /* For memcpy() */
+
+G_DEFINE_TYPE (EasysetupServertypeComboBox, easysetup_servertype_combo_box, GTK_TYPE_COMBO_BOX);
+
+#define SERVERTYPE_COMBO_BOX_GET_PRIVATE(o) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((o), EASYSETUP_TYPE_SERVERTYPE_COMBO_BOX, EasysetupServertypeComboBoxPrivate))
+
+typedef struct _EasysetupServertypeComboBoxPrivate EasysetupServertypeComboBoxPrivate;
+
+struct _EasysetupServertypeComboBoxPrivate
+{
+       GtkTreeModel *model;
+};
+
+static void
+easysetup_servertype_combo_box_get_property (GObject *object, guint property_id,
+                                                                                                                       GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_servertype_combo_box_set_property (GObject *object, guint property_id,
+                                                                                                                       const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_servertype_combo_box_dispose (GObject *object)
+{
+       if (G_OBJECT_CLASS (easysetup_servertype_combo_box_parent_class)->dispose)
+               G_OBJECT_CLASS (easysetup_servertype_combo_box_parent_class)->dispose (object);
+}
+
+static void
+easysetup_servertype_combo_box_finalize (GObject *object)
+{
+       EasysetupServertypeComboBoxPrivate *priv = SERVERTYPE_COMBO_BOX_GET_PRIVATE (object);
+
+       g_object_unref (G_OBJECT (priv->model));
+
+       G_OBJECT_CLASS (easysetup_servertype_combo_box_parent_class)->finalize (object);
+}
+
+static void
+easysetup_servertype_combo_box_class_init (EasysetupServertypeComboBoxClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (EasysetupServertypeComboBoxPrivate));
+
+       object_class->get_property = easysetup_servertype_combo_box_get_property;
+       object_class->set_property = easysetup_servertype_combo_box_set_property;
+       object_class->dispose = easysetup_servertype_combo_box_dispose;
+       object_class->finalize = easysetup_servertype_combo_box_finalize;
+}
+
+enum MODEL_COLS {
+       MODEL_COL_NAME = 0, /* a string */
+       MODEL_COL_ID = 1 /* an int. */
+};
+
+static void
+easysetup_servertype_combo_box_fill (EasysetupServertypeComboBox *combobox);
+
+static void
+easysetup_servertype_combo_box_init (EasysetupServertypeComboBox *self)
+{
+       EasysetupServertypeComboBoxPrivate *priv = SERVERTYPE_COMBO_BOX_GET_PRIVATE (self);
+
+       /* Create a tree model for the combo box,
+        * with a string for the name, and an ID for the servertype.
+        * This must match our MODEL_COLS enum constants.
+        */
+       priv->model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
+
+       /* Setup the combo box: */
+       GtkComboBox *combobox = GTK_COMBO_BOX (self);
+       gtk_combo_box_set_model (combobox, priv->model);
+
+       /* Servertype column:
+        * The ID model column in not shown in the view. */
+       GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combobox), renderer, TRUE);
+       gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, 
+       "text", MODEL_COL_NAME, NULL);
+       
+       easysetup_servertype_combo_box_fill (self);
+}
+
+EasysetupServertypeComboBox*
+easysetup_servertype_combo_box_new (void)
+{
+       return g_object_new (EASYSETUP_TYPE_SERVERTYPE_COMBO_BOX, NULL);
+}
+
+void easysetup_servertype_combo_box_fill (EasysetupServertypeComboBox *combobox)
+{      
+       EasysetupServertypeComboBoxPrivate *priv = SERVERTYPE_COMBO_BOX_GET_PRIVATE (combobox);
+       
+       /* Remove any existing rows: */
+       GtkListStore *liststore = GTK_LIST_STORE (priv->model);
+       gtk_list_store_clear (liststore);
+       
+       GtkTreeIter iter;
+       gtk_list_store_append (liststore, &iter);
+       gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)MODEST_PROTOCOL_STORE_POP, MODEL_COL_NAME, _("mail_fi_emailtype_pop3"), -1);
+       
+       /* Select the POP item: */
+       gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combobox), &iter);
+       
+       gtk_list_store_append (liststore, &iter);
+       gtk_list_store_set (liststore, &iter, MODEL_COL_ID, (gint)MODEST_PROTOCOL_STORE_IMAP, MODEL_COL_NAME, _("mail_fi_emailtype_imap"), -1);
+}
+
+/**
+ * Returns the selected servertype, 
+ * or MODEST_PROTOCOL_UNKNOWN if no servertype was selected.
+ */
+ModestProtocol
+easysetup_servertype_combo_box_get_active_servertype (EasysetupServertypeComboBox *combobox)
+{
+       GtkTreeIter active;
+       const gboolean found = gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combobox), &active);
+       if (found) {
+               EasysetupServertypeComboBoxPrivate *priv = SERVERTYPE_COMBO_BOX_GET_PRIVATE (combobox);
+
+               ModestProtocol servertype = MODEST_PROTOCOL_UNKNOWN;
+               gtk_tree_model_get (priv->model, &active, MODEL_COL_ID, &servertype, -1);
+               return servertype;      
+       }
+
+       return MODEST_PROTOCOL_UNKNOWN; /* Failed. */
+}
+
+/* This allows us to pass more than one piece of data to the signal handler,
+ * and get a result: */
+typedef struct 
+{
+               EasysetupServertypeComboBox* self;
+               gint id;
+               gboolean found;
+} ForEachData;
+
+static gboolean
+on_model_foreach_select_id(GtkTreeModel *model, 
+       GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
+{
+       ForEachData *state = (ForEachData*)(user_data);
+       
+       /* Select the item if it has the matching ID: */
+       guint id = 0;
+       gtk_tree_model_get (model, iter, MODEL_COL_ID, &id, -1); 
+       if(id == state->id) {
+               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->self), iter);
+               
+               state->found = TRUE;
+               return TRUE; /* Stop walking the tree. */
+       }
+       
+       return FALSE; /* Keep walking the tree. */
+}
+
+/**
+ * Selects the specified servertype, 
+ * or MODEST_PROTOCOL_UNKNOWN if no servertype was selected.
+ */
+gboolean
+easysetup_servertype_combo_box_set_active_servertype (EasysetupServertypeComboBox *combobox, ModestProtocol servertype)
+{
+       EasysetupServertypeComboBoxPrivate *priv = SERVERTYPE_COMBO_BOX_GET_PRIVATE (combobox);
+       
+       /* Create a state instance so we can send two items of data to the signal handler: */
+       ForEachData *state = g_new0 (ForEachData, 1);
+       state->self = combobox;
+       state->id = servertype;
+       state->found = FALSE;
+       
+       /* Look at each item, and select the one with the correct ID: */
+       gtk_tree_model_foreach (priv->model, &on_model_foreach_select_id, state);
+
+       const gboolean result = state->found;
+       
+       /* Free the state instance: */
+       g_free(state);
+       
+       return result;
+}
+
diff --git a/src/maemo/easysetup/modest-easysetup-servertype-combo-box.h b/src/maemo/easysetup/modest-easysetup-servertype-combo-box.h
new file mode 100644 (file)
index 0000000..76c4aee
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#ifndef _EASYSETUP_SERVERTYPE_COMBO_BOX
+#define _EASYSETUP_SERVERTYPE_COMBO_BOX
+
+#include <gtk/gtkcombobox.h>
+#include "modest-account-mgr/modest-protocol-info.h"
+
+G_BEGIN_DECLS
+
+#define EASYSETUP_TYPE_SERVERTYPE_COMBO_BOX easysetup_servertype_combo_box_get_type()
+
+#define EASYSETUP_SERVERTYPE_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       EASYSETUP_TYPE_SERVERTYPE_COMBO_BOX, EasysetupServertypeComboBox))
+
+#define EASYSETUP_SERVERTYPE_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_CAST ((klass), \
+       EASYSETUP_TYPE_SERVERTYPE_COMBO_BOX, EasysetupServertypeComboBoxClass))
+
+#define EASYSETUP_IS_SERVERTYPE_COMBO_BOX(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       EASYSETUP_TYPE_SERVERTYPE_COMBO_BOX))
+
+#define EASYSETUP_IS_SERVERTYPE_COMBO_BOX_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       EASYSETUP_TYPE_SERVERTYPE_COMBO_BOX))
+
+#define EASYSETUP_SERVERTYPE_COMBO_BOX_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       EASYSETUP_TYPE_SERVERTYPE_COMBO_BOX, EasysetupServertypeComboBoxClass))
+
+typedef struct {
+       GtkComboBox parent;
+} EasysetupServertypeComboBox;
+
+typedef struct {
+       GtkComboBoxClass parent_class;
+} EasysetupServertypeComboBoxClass;
+
+GType easysetup_servertype_combo_box_get_type (void);
+
+EasysetupServertypeComboBox* easysetup_servertype_combo_box_new (void);
+
+ModestProtocol easysetup_servertype_combo_box_get_active_servertype (EasysetupServertypeComboBox *combobox);
+
+gboolean easysetup_servertype_combo_box_set_active_servertype (EasysetupServertypeComboBox *combobox, ModestProtocol servertype);
+
+
+G_END_DECLS
+
+#endif /* _EASYSETUP_PROVIDER_COMBO_BOX */
diff --git a/src/maemo/easysetup/modest-easysetup-wizard.c b/src/maemo/easysetup/modest-easysetup-wizard.c
new file mode 100644 (file)
index 0000000..a9eaed6
--- /dev/null
@@ -0,0 +1,1201 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+
+#include "modest-easysetup-wizard.h"
+#include <glib/gi18n.h>
+#include <gtk/gtknotebook.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkcombobox.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkmessagedialog.h>
+#include <hildon-widgets/hildon-caption.h>
+#include "modest-easysetup-country-combo-box.h"
+#include "modest-easysetup-provider-combo-box.h"
+#include "modest-easysetup-servertype-combo-box.h"
+#include "modest-easysetup-serversecurity-combo-box.h"
+#include "modest-easysetup-secureauth-combo-box.h"
+#include "modest-validating-entry.h"
+#include "modest-text-utils.h"
+#include "modest-account-mgr/modest-account-mgr.h"
+#include <gconf/gconf-client.h>
+#include <string.h> /* For strlen(). */
+
+#define EXAMPLE_EMAIL_ADDRESS "first.last@provider.com"
+
+G_DEFINE_TYPE (ModestEasysetupWizardDialog, modest_easysetup_wizard_dialog, MODEST_TYPE_WIZARD_DIALOG);
+
+#define WIZARD_DIALOG_GET_PRIVATE(o) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_EASYSETUP_WIZARD_DIALOG, ModestEasysetupWizardDialogPrivate))
+
+typedef struct _ModestEasysetupWizardDialogPrivate ModestEasysetupWizardDialogPrivate;
+
+struct _ModestEasysetupWizardDialogPrivate
+{
+       ModestPresets *presets;
+};
+
+static void
+modest_easysetup_wizard_dialog_get_property (GObject *object, guint property_id,
+                                                                                                                       GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+modest_easysetup_wizard_dialog_set_property (GObject *object, guint property_id,
+                                                                                                                       const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+modest_easysetup_wizard_dialog_dispose (GObject *object)
+{
+       if (G_OBJECT_CLASS (modest_easysetup_wizard_dialog_parent_class)->dispose)
+               G_OBJECT_CLASS (modest_easysetup_wizard_dialog_parent_class)->dispose (object);
+}
+
+static void
+modest_easysetup_wizard_dialog_finalize (GObject *object)
+{
+       ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (object);
+       ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
+       
+       if (self->account_manager)
+               g_object_unref (G_OBJECT (self->account_manager));
+               
+       if (priv->presets)
+               modest_presets_destroy (priv->presets);
+       
+       G_OBJECT_CLASS (modest_easysetup_wizard_dialog_parent_class)->finalize (object);
+}
+
+static void
+show_error (GtkWindow *parent_window, const gchar* text);
+
+static gboolean
+create_account (ModestEasysetupWizardDialog *self);
+
+static void
+create_subsequent_easysetup_pages (ModestEasysetupWizardDialog *self);
+
+static void
+set_default_custom_servernames(ModestEasysetupWizardDialog *dialog);
+
+static void
+invoke_enable_buttons_vfunc (ModestEasysetupWizardDialog *wizard_dialog)
+{
+       ModestWizardDialogClass *klass = MODEST_WIZARD_DIALOG_GET_CLASS (wizard_dialog);
+       
+       /* Call the vfunc, which may be overridden by derived classes: */
+       if (klass->enable_buttons) {
+               GtkNotebook *notebook = NULL;
+               g_object_get (wizard_dialog, "wizard-notebook", &notebook, NULL);
+               
+               const gint current_page_num = gtk_notebook_get_current_page (notebook);
+               if (current_page_num == -1)
+                       return;
+                       
+               GtkWidget* current_page_widget = gtk_notebook_get_nth_page (notebook, current_page_num);
+               (*(klass->enable_buttons))(MODEST_WIZARD_DIALOG (wizard_dialog), current_page_widget);
+       }
+}
+
+static void
+on_caption_entry_changed (GtkEditable *editable, gpointer user_data)
+{
+       ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
+       g_assert(self);
+       invoke_enable_buttons_vfunc(self);
+}
+
+static void
+on_caption_combobox_changed (GtkComboBox *widget, gpointer user_data)
+{
+       ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
+       g_assert(self);
+       invoke_enable_buttons_vfunc(self);
+}
+
+/** This is a convenience function to create a caption containing a mandatory widget.
+ * When the widget is edited, the enable_buttons() vfunc will be called.
+ */
+static GtkWidget* create_caption_new_with_asterix(ModestEasysetupWizardDialog *self,
+       GtkSizeGroup *group,
+       const gchar *value,
+       GtkWidget *control,
+       GtkWidget *icon,
+       HildonCaptionStatus flag)
+{
+  GtkWidget *caption = hildon_caption_new (group, value, control, icon, flag);
+  
+/* The translated strings seem to already contain the *,
+ * but this code can be used if that is not true in future.
+ */
+#if 0
+       /* Add a * character to indicate mandatory fields,
+        * as specified in our "Email UI Specification": */
+       if (flag == HILDON_CAPTION_MANDATORY) {
+               gchar* title = g_strdup_printf("%s*", value);
+               caption = hildon_caption_new (group, title, control, icon, flag);       
+               g_free(title);
+       }       
+       else
+               caption = hildon_caption_new (group, value, control, icon, flag);
+#endif
+
+       /* Connect to the appropriate changed signal for the widget, 
+        * so we can ask for the prev/next buttons to be enabled/disabled appropriately:
+        */
+       if (GTK_IS_ENTRY (control)) {
+               g_signal_connect (G_OBJECT (control), "changed",
+               G_CALLBACK (on_caption_entry_changed), self);
+               
+       }
+       else if (GTK_IS_COMBO_BOX (control)) {
+               g_signal_connect (G_OBJECT (control), "changed",
+               G_CALLBACK (on_caption_combobox_changed), self);
+       }
+        
+       return caption;
+}
+           
+static GtkWidget*
+create_page_welcome (ModestEasysetupWizardDialog *self)
+{
+       GtkWidget *box = gtk_vbox_new (FALSE, 2);
+       GtkWidget *label = gtk_label_new(_("mcen_ia_emailsetup_intro"));
+       gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+       gtk_widget_show (label);
+       gtk_widget_show (GTK_WIDGET (box));
+       return GTK_WIDGET (box);
+}
+
+static void
+on_combo_account_country (GtkComboBox *widget, gpointer user_data)
+{
+       ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
+       g_assert(self);
+       ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
+       
+       /* Fill the providers combo, based on the selected country: */
+       gint mcc_id = easysetup_country_combo_box_get_active_country_id (
+               EASYSETUP_COUNTRY_COMBO_BOX (self->combo_account_country));
+       easysetup_provider_combo_box_fill (
+               EASYSETUP_PROVIDER_COMBO_BOX (self->combo_account_serviceprovider), priv->presets, mcc_id);
+}
+
+static void
+on_combo_account_serviceprovider (GtkComboBox *widget, gpointer user_data)
+{
+       ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
+       g_assert(self);
+       ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
+       
+       /* Fill the providers combo, based on the selected country: */
+       gchar* provider_id = easysetup_provider_combo_box_get_active_provider_id (
+               EASYSETUP_PROVIDER_COMBO_BOX (self->combo_account_serviceprovider));
+       
+       gchar* domain_name = NULL;
+       if(provider_id)
+         domain_name = modest_presets_get_domain (priv->presets, provider_id);
+       
+       if(!domain_name)
+               domain_name = g_strdup (EXAMPLE_EMAIL_ADDRESS);
+               
+       if (self->entry_user_email)
+               gtk_entry_set_text (GTK_ENTRY (self->entry_user_email), domain_name);
+               
+    g_free (domain_name);
+       
+       g_free (provider_id);
+}
+
+
+static GtkWidget*
+create_page_account_details (ModestEasysetupWizardDialog *self)
+{
+       GtkWidget *box = gtk_vbox_new (FALSE, 2);
+       GtkWidget *label = gtk_label_new(_("mcen_ia_accountdetails"));
+       gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 2);
+       gtk_widget_show (label);
+       
+       /* Create a size group to be used by all captions.
+        * Note that HildonCaption does not create a default size group if we do not specify one.
+        * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
+       GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+       /* The country widgets: */
+       self->combo_account_country = GTK_WIDGET (easysetup_country_combo_box_new ());
+       GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, _("mcen_fi_country"), 
+               self->combo_account_country, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->combo_account_country);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* connect to country combo's changed signal, so we can fill the provider combo: */
+    g_signal_connect (G_OBJECT (self->combo_account_country), "changed",
+            G_CALLBACK (on_combo_account_country), self);
+            
+       
+       /* The service provider widgets: */     
+       self->combo_account_serviceprovider = GTK_WIDGET (easysetup_provider_combo_box_new ());
+       
+       caption = create_caption_new_with_asterix (self, sizegroup, _("mcen_fi_serviceprovider"), 
+               self->combo_account_serviceprovider, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->combo_account_serviceprovider);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* connect to providers combo's changed signal, so we can fill the email address: */
+    g_signal_connect (G_OBJECT (self->combo_account_serviceprovider), "changed",
+            G_CALLBACK (on_combo_account_serviceprovider), self);
+       
+       /* TODO: Default to the current country somehow.
+        * But I don't know how to get the information that is specified in the 
+        * "Language and region" control panel. It does not seem be anywhere in gconf. murrayc.
+        *
+        * This is probably not the best choice of gconf key:
+        * This is the  "mcc used in the last pairing", ie. the last connection you made.
+     * set by the osso-operator-wizard package, suggested by Dirk-Jan Binnema.
+     *
+        */
+       GConfClient *client = gconf_client_get_default ();
+       GError *error = NULL;
+       const gchar* key = "/apps/osso/operator-wizard/last_mcc";
+       gint mcc_id = gconf_client_get_int(client, key, &error);
+       
+       if(mcc_id < 0)
+       mcc_id = 0;
+     
+    if (error) {
+       g_warning ("Error getting gconf key %s:\n%s", key, error->message);
+       g_error_free (error);
+       error = NULL;
+       
+       mcc_id = 0;
+    }
+    
+    /* Note that gconf_client_get_int() seems to return 0 without an error if the key is not there
+     * This might just be a Maemo bug.
+     */
+    if (mcc_id == 0) 
+    {
+       /* For now, we default to Finland when there is nothing better: */
+       mcc_id = 244;
+    }
+   
+       easysetup_country_combo_box_set_active_country_id (
+               EASYSETUP_COUNTRY_COMBO_BOX (self->combo_account_country), mcc_id);
+               
+       
+       /* The description widgets: */  
+       self->entry_account_title = GTK_WIDGET (easysetup_validating_entry_new ());
+       gtk_entry_set_text( GTK_ENTRY (self->entry_account_title), 
+               _("mcen_ia_emailsetup_defaultname")); /* default description. */
+       /* TODO: Check if an account with this default name exists, and increment if necessary. */
+               
+       caption = create_caption_new_with_asterix (self, sizegroup, _("mcen_fi_account_title"), 
+               self->entry_account_title, NULL, HILDON_CAPTION_MANDATORY);
+       gtk_widget_show (self->entry_account_title);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* Prevent the use of some characters in the account title, 
+        * as required by our UI specification: */
+       GList *list_prevent = NULL;
+       list_prevent = g_list_append (list_prevent, "\\");
+       list_prevent = g_list_append (list_prevent, "/");
+       list_prevent = g_list_append (list_prevent, ":");
+       list_prevent = g_list_append (list_prevent, "*");
+       list_prevent = g_list_append (list_prevent, "?");
+       list_prevent = g_list_append (list_prevent, "\""); /* The UI spec mentions â€œ, but maybe means ", maybe both. */
+       list_prevent = g_list_append (list_prevent, "“");
+       list_prevent = g_list_append (list_prevent, "<"); 
+       list_prevent = g_list_append (list_prevent, ">"); 
+       list_prevent = g_list_append (list_prevent, "|");
+       list_prevent = g_list_append (list_prevent, "^");       
+       easysetup_validating_entry_set_unallowed_characters (
+               EASYSETUP_VALIDATING_ENTRY (self->entry_account_title), list_prevent);
+       g_list_free (list_prevent);
+       
+       /* Set max length as in the UI spec:
+        * TODO: The UI spec seems to want us to show a dialog if we hit the maximum. */
+       gtk_entry_set_max_length (GTK_ENTRY (self->entry_account_title), 64);
+       
+       gtk_widget_show (GTK_WIDGET (box));
+       
+       return GTK_WIDGET (box);
+}
+
+static GtkWidget*
+create_page_user_details (ModestEasysetupWizardDialog *self)
+{
+       GtkWidget *box = gtk_vbox_new (FALSE, 2);
+       
+       /* Create a size group to be used by all captions.
+        * Note that HildonCaption does not create a default size group if we do not specify one.
+        * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
+       GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+        
+       /* The name widgets: */
+       self->entry_user_name = GTK_WIDGET (easysetup_validating_entry_new ());
+       /* Set max length as in the UI spec:
+        * TODO: The UI spec seems to want us to show a dialog if we hit the maximum. */
+       gtk_entry_set_max_length (GTK_ENTRY (self->entry_user_name), 64);
+       GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, 
+               _("mcen_li_emailsetup_name"), self->entry_user_name, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->entry_user_name);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* Prevent the use of some characters in the name, 
+        * as required by our UI specification: */
+       GList *list_prevent = NULL;
+       list_prevent = g_list_append (list_prevent, "<");
+       list_prevent = g_list_append (list_prevent, ">");
+       easysetup_validating_entry_set_unallowed_characters (
+               EASYSETUP_VALIDATING_ENTRY (self->entry_user_name), list_prevent);
+       g_list_free (list_prevent);
+       
+       /* The username widgets: */     
+       self->entry_user_username = GTK_WIDGET (easysetup_validating_entry_new ());
+       caption = create_caption_new_with_asterix (self, sizegroup, _("mail_fi_username"), 
+               self->entry_user_username, NULL, HILDON_CAPTION_MANDATORY);
+       gtk_widget_show (self->entry_user_username);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* Prevent the use of some characters in the username, 
+        * as required by our UI specification: */
+       easysetup_validating_entry_set_unallowed_characters_whitespace (
+               EASYSETUP_VALIDATING_ENTRY (self->entry_user_username));
+       
+       /* Set max length as in the UI spec:
+        * TODO: The UI spec seems to want us to show a dialog if we hit the maximum. */
+       gtk_entry_set_max_length (GTK_ENTRY (self->entry_user_username), 64);
+       
+       /* The password widgets: */     
+       self->entry_user_password = gtk_entry_new ();
+       gtk_entry_set_visibility (GTK_ENTRY (self->entry_user_password), FALSE);
+       /* gtk_entry_set_invisible_char (GTK_ENTRY (self->entry_user_password), '*'); */
+       caption = create_caption_new_with_asterix (self, sizegroup, 
+               _("mail_fi_password"), self->entry_user_password, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->entry_user_password);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* The email address widgets: */        
+       self->entry_user_email = GTK_WIDGET (easysetup_validating_entry_new ());
+       caption = create_caption_new_with_asterix (self, sizegroup, 
+               _("mcen_li_emailsetup_email_address"), self->entry_user_email, NULL, HILDON_CAPTION_MANDATORY);
+       gtk_entry_set_text (GTK_ENTRY (self->entry_user_email), EXAMPLE_EMAIL_ADDRESS); /* Default text. */
+       gtk_widget_show (self->entry_user_email);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* Set max length as in the UI spec:
+        * TODO: The UI spec seems to want us to show a dialog if we hit the maximum. */
+       gtk_entry_set_max_length (GTK_ENTRY (self->entry_user_email), 64);
+       
+       
+       gtk_widget_show (GTK_WIDGET (box));
+       
+       return GTK_WIDGET (box);
+}
+
+static GtkWidget* create_page_complete_easysetup (ModestEasysetupWizardDialog *self)
+{
+       GtkWidget *box = gtk_vbox_new (FALSE, 2);
+       GtkWidget *label = gtk_label_new(_("mcen_ia_emailsetup_setup_complete"));
+       gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+       gtk_widget_show (label);
+       gtk_widget_show (GTK_WIDGET (box));
+       return GTK_WIDGET (box);
+}
+
+/** Change the caption title for the incoming server, 
+ * as specified in the UI spec:
+ */
+static void update_incoming_server_title (ModestEasysetupWizardDialog *self)
+{
+       ModestProtocol protocol = easysetup_servertype_combo_box_get_active_servertype (
+               EASYSETUP_SERVERTYPE_COMBO_BOX (self->combo_incoming_servertype));
+       const gchar* type = 
+               (protocol == MODEST_PROTOCOL_STORE_POP ? 
+                       _("mail_fi_emailtype_pop3") : 
+                       _("mail_fi_emailtype_imap") );
+                       
+               
+       /* Note that this produces a compiler warning, 
+        * because the compiler does not know that the translated string will have a %s in it.
+        * I do not see a way to avoid the warning while still using these Logical IDs. murrayc. */
+       gchar* incomingserver_title = g_strdup_printf(_("mcen_li_emailsetup_servertype"), type);
+       g_object_set (G_OBJECT (self->caption_incoming), "label", incomingserver_title, NULL);
+       g_free(incomingserver_title);
+}
+
+/** Change the caption title for the incoming server, 
+ * as specified in the UI spec:
+ */
+static void update_incoming_server_security_choices (ModestEasysetupWizardDialog *self)
+{
+       ModestProtocol protocol = easysetup_servertype_combo_box_get_active_servertype (
+               EASYSETUP_SERVERTYPE_COMBO_BOX (self->combo_incoming_servertype));
+       
+       /* Fill the combo with appropriately titled choices for POP or IMAP. */
+       /* The choices are the same, but the titles are different, as in the UI spec. */
+       easysetup_serversecurity_combo_box_fill (
+               EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_incoming_security), protocol);
+}
+
+void on_combo_servertype_changed(GtkComboBox *combobox, gpointer user_data)
+{
+       ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (user_data);
+       update_incoming_server_title (self);
+       update_incoming_server_security_choices (self);
+}
+           
+static GtkWidget* create_page_custom_incoming (ModestEasysetupWizardDialog *self)
+{
+       GtkWidget *box = gtk_vbox_new (FALSE, 2);
+       
+       /* Create a size group to be used by all captions.
+        * Note that HildonCaption does not create a default size group if we do not specify one.
+        * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
+       GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+        
+       /* The incoming server widgets: */
+       if (!self->combo_incoming_servertype)
+               self->combo_incoming_servertype = GTK_WIDGET (easysetup_servertype_combo_box_new ());
+       easysetup_servertype_combo_box_set_active_servertype (
+               EASYSETUP_SERVERTYPE_COMBO_BOX (self->combo_incoming_servertype), MODEST_PROTOCOL_STORE_POP);
+       GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, 
+               _("mcen_li_emailsetup_type"), self->combo_incoming_servertype, NULL, HILDON_CAPTION_MANDATORY);
+       gtk_widget_show (self->combo_incoming_servertype);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       if(!self->entry_incomingserver)
+               self->entry_incomingserver = gtk_entry_new ();
+       set_default_custom_servernames (self);
+
+       if (self->caption_incoming)
+         gtk_widget_destroy (self->caption_incoming);
+          
+       /* The caption title will be updated in update_incoming_server_title().
+        * so this default text will never be seen: */
+       /* (Note: Changing the title seems pointless. murrayc) */
+       self->caption_incoming = create_caption_new_with_asterix (self, sizegroup, 
+               "Incoming Server", self->entry_incomingserver, NULL, HILDON_CAPTION_MANDATORY);
+       update_incoming_server_title (self);
+       gtk_widget_show (self->entry_incomingserver);
+       gtk_box_pack_start (GTK_BOX (box), self->caption_incoming, FALSE, FALSE, 2);
+       gtk_widget_show (self->caption_incoming);
+       
+       /* Change the caption title when the servertype changes, 
+        * as in the UI spec: */
+        g_signal_connect (G_OBJECT (self->combo_incoming_servertype), "changed",
+               G_CALLBACK (on_combo_servertype_changed), self);
+       
+       /* The secure connection widgets: */    
+       if (!self->combo_incoming_security)
+               self->combo_incoming_security = GTK_WIDGET (easysetup_serversecurity_combo_box_new ());
+       update_incoming_server_security_choices (self);
+       easysetup_serversecurity_combo_box_set_active_serversecurity (
+               EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_incoming_security), MODEST_PROTOCOL_SECURITY_NONE);
+       caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_connection"), 
+               self->combo_incoming_security, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->combo_incoming_security);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       if(!self->checkbox_incoming_auth)
+               self->checkbox_incoming_auth = 
+                       gtk_check_button_new_with_label (_("mcen_li_emailsetup_secure_authentication"));
+       gtk_box_pack_start (GTK_BOX (box), self->checkbox_incoming_auth, FALSE, FALSE, 2);
+       gtk_widget_show (self->checkbox_incoming_auth);
+       
+       gtk_widget_show (GTK_WIDGET (box));
+       
+       return GTK_WIDGET (box);
+}
+
+static void
+on_toggle_button_changed (GtkToggleButton *togglebutton, gpointer user_data)
+{
+       GtkWidget *widget = GTK_WIDGET (user_data);
+       
+       /* Enable the widget only if the toggle button is active: */
+       const gboolean enable = gtk_toggle_button_get_active (togglebutton);
+       gtk_widget_set_sensitive (widget, enable);
+}
+
+/* Make the sensitivity of a widget depend on a toggle button.
+ */
+static void
+enable_widget_for_togglebutton (GtkWidget *widget, GtkToggleButton* button)
+{
+       g_signal_connect (G_OBJECT (button), "toggled",
+               G_CALLBACK (on_toggle_button_changed), widget);
+       
+       /* Set the starting sensitivity: */
+       on_toggle_button_changed (button, widget);
+}
+       
+static GtkWidget* create_page_custom_outgoing (ModestEasysetupWizardDialog *self)
+{
+       GtkWidget *box = gtk_vbox_new (FALSE, 2);
+       
+       /* Create a size group to be used by all captions.
+        * Note that HildonCaption does not create a default size group if we do not specify one.
+        * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
+       GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+        
+       /* The outgoing server widgets: */
+       if (!self->entry_outgoingserver)
+               self->entry_outgoingserver = gtk_entry_new ();
+       GtkWidget *caption = create_caption_new_with_asterix (self, sizegroup, 
+               _("mcen_li_emailsetup_smtp"), self->entry_outgoingserver, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->entry_outgoingserver);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       set_default_custom_servernames (self);
+       
+       /* The secure connection widgets: */    
+       if (!self->combo_outgoing_security)
+               self->combo_outgoing_security = GTK_WIDGET (easysetup_serversecurity_combo_box_new ());
+       easysetup_serversecurity_combo_box_fill (
+               EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_outgoing_security), MODEST_PROTOCOL_TRANSPORT_SMTP);
+       easysetup_serversecurity_combo_box_set_active_serversecurity (
+               EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_outgoing_security), MODEST_PROTOCOL_SECURITY_NONE);
+       caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_connection"), 
+               self->combo_outgoing_security, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->combo_outgoing_security);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* The secure authentication widgets: */
+       if (!self->combo_outgoing_auth)
+               self->combo_outgoing_auth = GTK_WIDGET (easysetup_secureauth_combo_box_new ());
+       caption = hildon_caption_new (sizegroup, _("mcen_li_emailsetup_secure_authentication"), 
+               self->combo_outgoing_auth, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->combo_outgoing_auth);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* connection-specific checkbox: */
+       if (!self->checkbox_outgoing_smtp_specific) {
+               self->checkbox_outgoing_smtp_specific = gtk_check_button_new_with_label (_("mcen_fi_advsetup_connection_smtp"));
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->checkbox_outgoing_smtp_specific), 
+                       FALSE);
+       }
+       gtk_box_pack_start (GTK_BOX (box), self->checkbox_outgoing_smtp_specific, FALSE, FALSE, 2);
+       gtk_widget_show (self->checkbox_outgoing_smtp_specific);
+       
+       /* Connection-specific SMTP-Severs Edit button: */
+       if (!self->button_outgoing_smtp_servers)
+               self->button_outgoing_smtp_servers = gtk_button_new_with_label (_("mcen_bd_emailsetup_edit"));
+       caption = hildon_caption_new (sizegroup, _("mcen_fi_advsetup_optional_smtp"), 
+               self->button_outgoing_smtp_servers, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->button_outgoing_smtp_servers);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       /* Only enable the button when the checkbox is checked: */
+       enable_widget_for_togglebutton (self->button_outgoing_smtp_servers, 
+               GTK_TOGGLE_BUTTON (self->checkbox_outgoing_smtp_specific));
+       
+       
+       gtk_widget_show (GTK_WIDGET (box));
+       
+       return GTK_WIDGET (box);
+}
+
+static GtkWidget* create_page_complete_custom (ModestEasysetupWizardDialog *self)
+{
+       GtkWidget *box = gtk_vbox_new (FALSE, 2);
+       GtkWidget *label = gtk_label_new(_("mcen_ia_emailsetup_setup_complete"));
+       gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+       gtk_widget_show (label);
+       
+       if (!self->button_edit)
+               self->button_edit = gtk_button_new_with_label (_("mcen_bd_emailsetup_edit"));
+       GtkWidget *caption = hildon_caption_new (NULL, _("mcen_fi_advanced_settings"), 
+               self->button_edit, NULL, HILDON_CAPTION_OPTIONAL);
+       gtk_widget_show (self->button_edit);
+       gtk_box_pack_start (GTK_BOX (box), caption, FALSE, FALSE, 2);
+       gtk_widget_show (caption);
+       
+       gtk_widget_show (GTK_WIDGET (box));
+       return GTK_WIDGET (box);
+}
+
+
+/*
+ */
+static void 
+on_response (ModestWizardDialog *wizard_dialog,
+       gint response_id,
+       gpointer user_data)
+{
+       ModestEasysetupWizardDialog *self = MODEST_EASYSETUP_WIZARD_DIALOG (wizard_dialog);
+       invoke_enable_buttons_vfunc (self);
+}
+
+static void
+modest_easysetup_wizard_dialog_init (ModestEasysetupWizardDialog *self)
+{
+       /* Create the notebook to be used by the ModestWizardDialog base class:
+        * Each page of the notebook will be a page of the wizard: */
+       GtkNotebook *notebook = GTK_NOTEBOOK (gtk_notebook_new());
+       
+    /* Set the notebook used by the ModestWizardDialog base class: */
+    g_object_set (G_OBJECT(self), "wizard-notebook", notebook, NULL);
+    
+    /* Set the wizard title:
+     * The actual window title will be a combination of this and the page's tab label title. */
+    g_object_set (G_OBJECT(self), "wizard-name", _("mcen_ti_emailsetup"), NULL);
+
+       /* Read in the information about known service providers: */
+       ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
+       priv->presets = modest_presets_new ("provider-data-test.keyfile"); /* TODO: the actual filepath. */
+
+       /* Create the account manager object, 
+        * so we can check for existing accounts,
+        * and create new accounts: */
+       ModestConf *conf = modest_conf_new (); /* Just a thin wrapper around GConfClient. */
+       self->account_manager = modest_account_mgr_new (conf);
+       g_object_unref (conf);
+       
+    /* Create the common pages, 
+     */
+    self->page_welcome = create_page_welcome (self);
+       self->page_account_details = create_page_account_details (self);
+       self->page_user_details = create_page_user_details (self);
+       
+       /* Add the common pages: */
+       gtk_notebook_append_page (notebook, self->page_welcome, 
+               gtk_label_new (_("mcen_ti_emailsetup_welcome")));
+       gtk_notebook_append_page (notebook, self->page_account_details, 
+               gtk_label_new (_("mcen_ti_accountdetails")));
+       gtk_notebook_append_page (notebook, self->page_user_details, 
+               gtk_label_new (_("mcen_ti_emailsetup_userdetails")));
+               
+       /* Create and add the easysetup-specific pages,
+        * because we need _some_ final page to enable the Next and Finish buttons: */
+       create_subsequent_easysetup_pages (self);
+
+            
+    /* Connect to the dialog's response signal so we can enable/disable buttons 
+     * for the newly-selected page, because the prev/next buttons cause response to be emitted.
+     * Note that we use g_signal_connect_after() instead of g_signal_connect()
+     * so that we can be enable/disable after ModestWizardDialog has done its own 
+     * enabling/disabling of buttons.
+     * 
+     * HOWEVER, this doesn't work because ModestWizardDialog's response signal handler 
+     * does g_signal_stop_emission_by_name(), stopping our signal handler from running.
+     * 
+     * It's not enough to connect to the notebook's switch-page signal, because 
+     * ModestWizardDialog's "response" signal handler enables the buttons itself, 
+     * _after_ switching the page (understandably).
+     * (Note that if we had, if we used g_signal_connect() instead of g_signal_connect_after()
+     * then gtk_notebook_get_current_page() would return an incorrect value.)
+     */
+    g_signal_connect_after (G_OBJECT (self), "response",
+            G_CALLBACK (on_response), self);       
+}
+
+ModestEasysetupWizardDialog*
+modest_easysetup_wizard_dialog_new (void)
+{
+       return g_object_new (MODEST_TYPE_EASYSETUP_WIZARD_DIALOG, NULL);
+}
+
+static void create_subsequent_customsetup_pages (ModestEasysetupWizardDialog *self)
+{
+       GtkNotebook *notebook = NULL;
+       g_object_get (self, "wizard-notebook", &notebook, NULL);
+       g_assert(notebook);
+       
+       /* Create the custom pages: */
+       if(!(self->page_custom_incoming)) {
+               self->page_custom_incoming = create_page_custom_incoming (self);
+       }
+               
+       if(!(self->page_custom_outgoing)) {
+               self->page_custom_outgoing = create_page_custom_outgoing (self);
+       }
+       
+       if(!(self->page_complete_customsetup)) {
+               self->page_complete_customsetup = create_page_complete_custom (self);
+       }
+       
+       if (!gtk_widget_get_parent (GTK_WIDGET (self->page_custom_incoming)))
+               gtk_notebook_append_page (notebook, self->page_custom_incoming,
+                       gtk_label_new (_("mcen_ti_emailsetup_incomingdetails")));
+       
+       if (!gtk_widget_get_parent (GTK_WIDGET (self->page_custom_outgoing)))           
+               gtk_notebook_append_page (notebook, self->page_custom_outgoing,
+                       gtk_label_new (_("mcen_ti_emailsetup_outgoingdetails")));
+               
+       if (!gtk_widget_get_parent (GTK_WIDGET (self->page_complete_customsetup)))
+               gtk_notebook_append_page (notebook, self->page_complete_customsetup,
+                       gtk_label_new (_("mcen_ti_emailsetup_complete")));
+}
+       
+static void create_subsequent_easysetup_pages (ModestEasysetupWizardDialog *self)
+{
+       GtkNotebook *notebook = NULL;
+       g_object_get (self, "wizard-notebook", &notebook, NULL);
+       g_assert(notebook);
+       
+       /* Create the easysetup-specific pages: */
+       if(!self->page_complete_easysetup)
+               self->page_complete_easysetup = create_page_complete_easysetup (self);
+
+       if (!gtk_widget_get_parent (GTK_WIDGET (self->page_complete_easysetup)))
+               gtk_notebook_append_page (notebook, self->page_complete_easysetup, 
+                       gtk_label_new (_("mcen_ti_emailsetup_complete")));
+                       
+}
+/* After the user details page,
+ * the following pages depend on whether "Other" was chosen 
+ * in the provider combobox on the account page
+ */
+static void create_subsequent_pages (ModestEasysetupWizardDialog *self)
+{
+       if (easysetup_provider_combo_box_get_active_provider_id (
+               EASYSETUP_PROVIDER_COMBO_BOX (self->combo_account_serviceprovider)) == 0) {
+               /* "Other..." was selected: */
+               
+               /* Make sure that the easysetup pages do not exist: */
+               if(self->page_complete_easysetup) {
+                       gtk_widget_destroy (self->page_complete_easysetup);
+                       self->page_complete_easysetup = NULL;
+               }
+               
+               create_subsequent_customsetup_pages (self);
+       }       
+       else {
+               /* A specific provider was selected: */
+               {
+                       /* Make sure that the custom pages do not exist:
+                        * Because they will be used if they exist, when creating the account. */
+                       if(self->page_custom_incoming) {
+                               gtk_widget_destroy (self->page_custom_incoming);
+                               self->page_custom_incoming = NULL;
+                       }
+                       
+                       if(self->page_custom_outgoing) {
+                               gtk_widget_destroy (self->page_custom_outgoing);
+                               self->page_custom_outgoing = NULL;
+                       }
+                       
+                       if(self->page_complete_customsetup) {
+                               gtk_widget_destroy (self->page_complete_customsetup);
+                               self->page_complete_customsetup = NULL;
+                       }
+               }
+               
+               /* Create the easysetup pages: */
+               create_subsequent_easysetup_pages (self);
+       }
+}
+
+gchar*
+util_get_default_servername_from_email_address (const gchar* email_address, ModestProtocol servertype)
+{
+       if (!email_address)
+               return NULL;
+       
+       gchar* at = g_utf8_strchr (email_address, -1, '@');
+       if (!at || (g_utf8_strlen (at, -1) < 2))
+               return NULL;
+               
+       gchar* domain = g_utf8_next_char (at);
+       if(!domain)
+               return NULL;
+               
+       const gchar* hostname = NULL;
+       if (servertype == MODEST_PROTOCOL_STORE_POP)
+               hostname = "pop";
+       else if (servertype == MODEST_PROTOCOL_STORE_IMAP)
+               hostname = "imap";
+       else if (servertype == MODEST_PROTOCOL_TRANSPORT_SMTP)
+               hostname = "smtp";
+       
+       if (!hostname)
+               return NULL;
+               
+       return g_strdup_printf ("%s.%s", hostname, domain);
+}
+
+static void set_default_custom_servernames (ModestEasysetupWizardDialog *account_wizard)
+{
+       /* Set a default domain for the server, based on the email address,
+        * if no server name was already specified.
+        */
+       const gchar* incoming_existing = gtk_entry_get_text (GTK_ENTRY (account_wizard->entry_incomingserver));
+       if ((!incoming_existing || (strlen(incoming_existing) == 0)) 
+               && account_wizard->entry_user_email) {
+               const ModestProtocol protocol = easysetup_servertype_combo_box_get_active_servertype (
+                       EASYSETUP_SERVERTYPE_COMBO_BOX (account_wizard->combo_incoming_servertype));
+               const gchar* email_address = gtk_entry_get_text (GTK_ENTRY(account_wizard->entry_user_email));
+               gtk_entry_set_text (GTK_ENTRY (account_wizard->entry_incomingserver), util_get_default_servername_from_email_address (email_address, protocol));
+       }
+       
+       /* Set a default domain for the server, based on the email address,
+        * if no server name was already specified.
+        */
+       const gchar* outgoing_existing = gtk_entry_get_text (GTK_ENTRY (account_wizard->entry_outgoingserver));
+       if ((!outgoing_existing || (strlen(outgoing_existing) == 0)) 
+               && account_wizard->entry_user_email) {
+               const gchar* email_address = gtk_entry_get_text (GTK_ENTRY(account_wizard->entry_user_email));
+               gtk_entry_set_text (GTK_ENTRY (account_wizard->entry_outgoingserver), util_get_default_servername_from_email_address (email_address, MODEST_PROTOCOL_TRANSPORT_SMTP));
+       }
+}
+
+static gboolean
+on_before_next (ModestWizardDialog *dialog, GtkWidget *current_page, GtkWidget *next_page)
+{
+       ModestEasysetupWizardDialog *account_wizard = MODEST_EASYSETUP_WIZARD_DIALOG (dialog);
+       
+       /* Do extra validation that couldn't be done for every key press,
+        * either because it was too slow,
+        * or because it requires interaction:
+        */
+       if (current_page == account_wizard->page_account_details) {     
+               /* Check that the title is not already in use: */
+               const gchar* account_name = gtk_entry_get_text (GTK_ENTRY (account_wizard->entry_account_title));
+               if ((!account_name) || (strlen(account_name) == 0))
+                       return FALSE;
+                       
+               gboolean name_in_use = FALSE;
+               name_in_use = modest_account_mgr_account_exists (account_wizard->account_manager,
+                       account_name, TRUE /*  server_account */);
+               
+               if (name_in_use) {
+                       /* Warn the user via a dialog: */
+                       /* TODO: The UI spec says we should increment the title,
+                        * as well as warning. This seems contradictory.
+                        */
+                       show_error (GTK_WINDOW (account_wizard), _("mail_ib_account_name_already_existing."));
+            
+                       return FALSE;
+               }
+       }
+       else if (current_page == account_wizard->page_user_details) {
+               /* Check that the email address is valud: */
+               const gchar* email_address = gtk_entry_get_text (GTK_ENTRY (account_wizard->entry_user_email));
+               if ((!email_address) || (strlen(email_address) == 0))
+                       return FALSE;
+                       
+               if (!modest_text_utils_validate_email_address (email_address)) {
+                       /* Warn the user via a dialog: */
+                       show_error (GTK_WINDOW (account_wizard), _("mcen_ib_invalid_email"));
+                                             
+            /* Return focus to the email address entry: */
+            gtk_widget_grab_focus (account_wizard->entry_user_email);
+            
+                       return FALSE;
+               }
+               
+               /* Make sure that the subsequent pages are appropriate for the provider choice. */
+               create_subsequent_pages (account_wizard);
+       }
+       
+       /* TODO: The UI Spec wants us to check that the servernames are valid, 
+        * but does not specify how.
+        */
+         
+       if(next_page == account_wizard->page_custom_incoming) {
+               set_default_custom_servernames (account_wizard);
+       }
+       else if (next_page == account_wizard->page_custom_outgoing) {
+               set_default_custom_servernames (account_wizard);
+       }
+       
+       /* If this is the last page, and this is a click on Finish, 
+        * then attempt to create the dialog.
+        */
+       if(!next_page) /* This is NULL when this is a click on Finish. */
+       {
+               create_account (account_wizard);
+       }
+       
+       
+       return TRUE;
+}
+
+static gboolean entry_is_empty (GtkWidget *entry)
+{
+       if (!entry)
+               return FALSE;
+               
+       const gchar* text = gtk_entry_get_text (GTK_ENTRY (entry));
+       if ((!text) || (strlen(text) == 0))
+               return TRUE;
+       else
+               return FALSE;
+}
+
+static void
+on_enable_buttons (ModestWizardDialog *dialog, GtkWidget *current_page)
+{
+       ModestEasysetupWizardDialog *account_wizard = MODEST_EASYSETUP_WIZARD_DIALOG (dialog);
+       
+       gboolean enable_next = TRUE;
+       if (current_page == account_wizard->page_welcome) {
+               enable_next = TRUE;
+       }
+       else if (current_page == account_wizard->page_account_details) {
+               /* The account details title is mandatory: */
+               if (entry_is_empty(account_wizard->entry_account_title))
+                       enable_next = FALSE;
+       }
+       else if (current_page == account_wizard->page_user_details) {   
+               /* The user details username is mandatory: */
+               if (entry_is_empty(account_wizard->entry_user_username))
+                       enable_next = FALSE;
+                       
+               /* The user details email address is mandatory: */
+               if (enable_next && entry_is_empty (account_wizard->entry_user_email))
+                       enable_next = FALSE;
+       }
+       else if (current_page == account_wizard->page_custom_incoming) {
+               /* The custom incoming server is mandatory: */
+               if (entry_is_empty(account_wizard->entry_incomingserver))
+                       enable_next = FALSE;
+       }
+                       
+       /* Enable the buttons, 
+        * identifying them via their associated response codes:
+        */
+       GtkDialog *dialog_base = GTK_DIALOG (dialog);
+    gtk_dialog_set_response_sensitive (dialog_base,
+                                       MODEST_WIZARD_DIALOG_NEXT,
+                                       enable_next);
+                                       
+    /* Disable the Finish button until we are on the last page,
+     * because HildonWizardDialog enables this for all but the first page: */
+    GtkNotebook *notebook = NULL;
+       g_object_get (dialog_base, "wizard-notebook", &notebook, NULL);
+       
+    gint current = gtk_notebook_get_current_page (notebook);
+    gint last = gtk_notebook_get_n_pages (notebook) - 1;
+    gboolean is_last = (current == last);
+    
+    if(!is_last) {
+       gtk_dialog_set_response_sensitive (dialog_base,
+                                       MODEST_WIZARD_DIALOG_FINISH,
+                                       FALSE);
+    }
+}
+
+static void
+modest_easysetup_wizard_dialog_class_init (ModestEasysetupWizardDialogClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       g_type_class_add_private (klass, sizeof (ModestEasysetupWizardDialogPrivate));
+
+
+       object_class->get_property = modest_easysetup_wizard_dialog_get_property;
+       object_class->set_property = modest_easysetup_wizard_dialog_set_property;
+       object_class->dispose = modest_easysetup_wizard_dialog_dispose;
+       object_class->finalize = modest_easysetup_wizard_dialog_finalize;
+       
+       /* Provide a vfunc implementation so we can decide 
+        * when to enable/disable the prev/next buttons.
+        */
+       ModestWizardDialogClass *base_klass = (ModestWizardDialogClass*)(klass);
+       base_klass->before_next = on_before_next;
+       base_klass->enable_buttons = on_enable_buttons;
+}
+static void
+show_error (GtkWindow *parent_window, const gchar* text)
+{
+       GtkDialog *dialog = GTK_DIALOG (gtk_message_dialog_new (parent_window,
+               (GtkDialogFlags)0,
+                GTK_MESSAGE_ERROR,
+                GTK_BUTTONS_OK,
+                text ));
+                
+                gtk_dialog_run (dialog);
+                gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+/** Attempt to create the account from the information that the user has entered.
+ * @result: TRUE if the account was successfully created.
+ */
+gboolean
+create_account (ModestEasysetupWizardDialog *self)
+{
+       ModestEasysetupWizardDialogPrivate *priv = WIZARD_DIALOG_GET_PRIVATE (self);
+       
+       const gchar* account_name = gtk_entry_get_text (GTK_ENTRY (self->entry_account_title));
+
+       /* Some checks: */
+       if (!account_name)
+               return FALSE;
+               
+       /* We should have checked for this already, 
+        * and changed that name accordingly, 
+        * but let's check again just in case:
+        */
+       if (modest_account_mgr_account_exists (self->account_manager, account_name, FALSE)) 
+               return FALSE;
+               
+       /* username and password (for both incoming and outgoing): */
+       const gchar* username = gtk_entry_get_text (GTK_ENTRY (self->entry_user_username));
+       const gchar* password = gtk_entry_get_text (GTK_ENTRY (self->entry_user_password));
+       
+       /* Incoming server: */
+       /* Note: We need something as default for the ModestProtocol values, 
+        * or modest_account_mgr_add_server_account will fail. */
+       gchar* servername_incoming = NULL;
+       ModestProtocol protocol_incoming = MODEST_PROTOCOL_STORE_POP;
+       ModestProtocol protocol_security_incoming = MODEST_PROTOCOL_SECURITY_NONE;
+       ModestProtocol protocol_authentication_incoming = MODEST_PROTOCOL_AUTH_NONE;
+       
+       /* Get details from the specified presets: */
+       gchar* provider_id = easysetup_provider_combo_box_get_active_provider_id (
+               EASYSETUP_PROVIDER_COMBO_BOX (self->combo_account_serviceprovider));
+       if(provider_id) {
+               /* Use presets: */
+               
+               servername_incoming = modest_presets_get_server (priv->presets, provider_id, 
+                       TRUE /* incoming */);
+               
+               ModestPresetsServerType servertype_incoming = modest_presets_get_info_server_type (priv->presets, provider_id, 
+                       TRUE /* incoming */);
+               
+       
+               /* We don't check for SMTP here as that is impossible for an incoming server. */
+               if (servertype_incoming == MODEST_PRESETS_SERVER_TYPE_IMAP)
+                       protocol_incoming = MODEST_PROTOCOL_STORE_IMAP;
+               else if (servertype_incoming == MODEST_PRESETS_SERVER_TYPE_POP)
+                       protocol_incoming = MODEST_PROTOCOL_STORE_POP;
+                               
+               ModestPresetsSecurity security_incoming = modest_presets_get_info_server_security (priv->presets, provider_id, 
+                       TRUE /* incoming */);
+                       
+               
+               if (security_incoming & MODEST_PRESETS_SECURITY_SECURE_INCOMING)
+                       protocol_security_incoming = MODEST_PROTOCOL_SECURITY_SSL; /* TODO: Is this what we want? */
+               
+               if (security_incoming & MODEST_PRESETS_SECURITY_APOP)
+                       protocol_authentication_incoming = MODEST_PROTOCOL_AUTH_PASSWORD; /* TODO: Is this what we want? */
+       }
+       else {
+               /* Use custom pages because no preset was specified: */
+               servername_incoming = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry_incomingserver) ));
+               
+               protocol_incoming = easysetup_servertype_combo_box_get_active_servertype (
+               EASYSETUP_SERVERTYPE_COMBO_BOX (self->combo_incoming_servertype));
+               
+               protocol_security_incoming = easysetup_serversecurity_combo_box_get_active_serversecurity (
+               EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_incoming_security));
+               
+               protocol_authentication_incoming = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->checkbox_incoming_auth)) 
+                       ? MODEST_PROTOCOL_AUTH_PASSWORD
+                       : MODEST_PROTOCOL_AUTH_NONE;
+               
+       }
+       
+       gboolean created = modest_account_mgr_add_server_account (self->account_manager,
+               account_name,
+               servername_incoming,
+               username, password,
+               protocol_incoming,
+               protocol_security_incoming,
+               protocol_authentication_incoming);              
+               
+       g_free (servername_incoming);
+       
+       if (!created) {
+               /* TODO: Provide a Logical ID for the text: */
+               show_error (GTK_WINDOW (self), _("An error occurred while creating the incoming account."));
+               return FALSE;   
+       }
+       
+       /* Outgoing server: */
+       gchar* servername_outgoing = NULL;
+       ModestProtocol protocol_outgoing = MODEST_PROTOCOL_STORE_POP;
+       ModestProtocol protocol_security_outgoing = MODEST_PROTOCOL_SECURITY_NONE;
+       ModestProtocol protocol_authentication_outgoing = MODEST_PROTOCOL_AUTH_NONE;
+       
+       if(provider_id) {
+               /* Use presets: */
+               servername_outgoing = modest_presets_get_server (priv->presets, provider_id, 
+                       FALSE /* incoming */);
+                       
+               ModestPresetsServerType servertype_outgoing = modest_presets_get_info_server_type (priv->presets, provider_id, 
+                       FALSE /* incoming */);
+               
+               /* Note: We need something as default, or modest_account_mgr_add_server_account will fail. */
+               protocol_outgoing = MODEST_PROTOCOL_TRANSPORT_SENDMAIL; 
+               if (servertype_outgoing == MODEST_PRESETS_SERVER_TYPE_SMTP)
+                       protocol_outgoing = MODEST_PROTOCOL_TRANSPORT_SMTP; /* TODO: Is this what we want? */
+               
+               ModestPresetsSecurity security_outgoing = 
+                       modest_presets_get_info_server_security (priv->presets, provider_id, 
+                               FALSE /* incoming */);
+                       
+               protocol_security_outgoing = MODEST_PROTOCOL_SECURITY_NONE;
+               if (security_outgoing & MODEST_PRESETS_SECURITY_SECURE_SMTP)
+                       protocol_security_outgoing = MODEST_PROTOCOL_SECURITY_SSL; /* TODO: Is this what we want? */
+               
+               protocol_authentication_outgoing = MODEST_PROTOCOL_AUTH_NONE;
+               /* TODO: There is no SMTP authentication enum for presets. */
+       }
+       else {
+               /* Use custom pages because no preset was specified: */
+               servername_outgoing = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry_outgoingserver) ));
+               
+               protocol_outgoing = MODEST_PROTOCOL_TRANSPORT_SMTP; /* It's always SMTP for outgoing. */
+
+               protocol_security_outgoing = easysetup_serversecurity_combo_box_get_active_serversecurity (
+                       EASYSETUP_SERVERSECURITY_COMBO_BOX (self->combo_outgoing_security));
+               
+               protocol_authentication_outgoing = easysetup_secureauth_combo_box_get_active_secureauth (
+                       EASYSETUP_SECUREAUTH_COMBO_BOX (self->combo_outgoing_auth));
+               
+               gboolean specific = gtk_toggle_button_get_active (
+                       GTK_TOGGLE_BUTTON (self->checkbox_outgoing_smtp_specific));
+               
+       }
+           
+       created = modest_account_mgr_add_server_account (self->account_manager,
+               account_name,
+               servername_outgoing,
+               username, password,
+               protocol_outgoing,
+               protocol_security_outgoing,
+               protocol_authentication_outgoing);
+               
+       g_free (servername_outgoing);
+               
+       if (!created) {
+               /* TODO: Provide a Logical ID for the text: */
+               show_error (GTK_WINDOW (self), _("An error occurred while creating the outgoing account."));
+               return FALSE;   
+       }            
+       
+       return FALSE;
+}
+
+
diff --git a/src/maemo/easysetup/modest-easysetup-wizard.h b/src/maemo/easysetup/modest-easysetup-wizard.h
new file mode 100644 (file)
index 0000000..8958873
--- /dev/null
@@ -0,0 +1,92 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#ifndef _MODEST_EAYSETUP_WIZARD_DIALOG
+#define _MODEST_EAYSETUP_WIZARD_DIALOG
+
+/* #include <hildon-widgets/hildon-wizard-dialog.h> */
+#include "modest-wizard-dialog.h" /* We use a copied-and-improved HildonWizardDialog. */
+#include "modest-account-mgr/modest-account-mgr.h"
+#include <hildon-widgets/hildon-caption.h>
+
+G_BEGIN_DECLS
+
+#define MODEST_TYPE_EASYSETUP_WIZARD_DIALOG modest_easysetup_wizard_dialog_get_type()
+
+#define MODEST_EASYSETUP_WIZARD_DIALOG(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       MODEST_TYPE_EASYSETUP_WIZARD_DIALOG, ModestEasysetupWizardDialog))
+
+#define MODEST_EASYSETUP_WIZARD_DIALOG_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_CAST ((klass), \
+       MODEST_TYPE_EASYSETUP_WIZARD_DIALOG, ModestEasysetupWizardDialogClass))
+
+#define ACCOUNT_IS_WIZARD_DIALOG(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       MODEST_TYPE_EASYSETUP_WIZARD_DIALOG))
+
+#define MODEST_EASYSETUP_IS_WIZARD_DIALOG_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       MODEST_TYPE_EASYSETUP_WIZARD_DIALOG))
+
+#define MODEST_EASYSETUP_WIZARD_DIALOG_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       MODEST_TYPE_EASYSETUP_WIZARD_DIALOG, ModestEasysetupWizardDialogClass))
+
+typedef struct {
+       ModestWizardDialog parent;
+       
+       /* Used by derived widgets to query existing accounts,
+        * and to create new accounts: */
+       ModestAccountMgr *account_manager;
+               
+       /* These widgets are only for use by derived widgets: */
+       /* Pages that are common to all account wizards: */
+       GtkWidget *page_welcome;
+       
+       GtkWidget *page_account_details;
+       GtkWidget *combo_account_country;
+       GtkWidget *combo_account_serviceprovider;
+       GtkWidget *entry_account_title;
+       
+       GtkWidget *page_user_details;
+       GtkWidget *entry_user_name;
+       GtkWidget *entry_user_username;
+       GtkWidget *entry_user_password;
+       GtkWidget *entry_user_email;
+       
+       GtkWidget *page_complete_easysetup;
+       
+       GtkWidget *page_custom_incoming;
+       GtkWidget *combo_incoming_servertype;
+       GtkWidget *caption_incoming;
+       GtkWidget *entry_incomingserver;
+       GtkWidget *combo_incoming_security;
+       GtkWidget *checkbox_incoming_auth;
+
+       GtkWidget *page_custom_outgoing;
+       GtkWidget *entry_outgoingserver;
+       GtkWidget *combo_outgoing_security;
+       GtkWidget *combo_outgoing_auth;
+       GtkWidget *checkbox_outgoing_smtp_specific;
+       GtkWidget *button_outgoing_smtp_servers;
+       
+       GtkWidget *page_complete_customsetup;
+       GtkWidget *button_edit;
+       
+} ModestEasysetupWizardDialog;
+
+typedef struct {
+       ModestWizardDialogClass parent_class;
+       
+} ModestEasysetupWizardDialogClass;
+
+GType modest_easysetup_wizard_dialog_get_type (void);
+
+ModestEasysetupWizardDialog* modest_easysetup_wizard_dialog_new (void);
+
+G_END_DECLS
+
+#endif /* _MODEST_EAYSETUP_WIZARD_DIALOG */
diff --git a/src/maemo/easysetup/modest-presets.c b/src/maemo/easysetup/modest-presets.c
new file mode 100644 (file)
index 0000000..8d4e001
--- /dev/null
@@ -0,0 +1,319 @@
+/* Copyright (c) 2006, Nokia Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Nokia Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h> /* for strcmp */
+#include "modest-presets.h"
+
+#define MODEST_PRESETS_KEY_NAME              "Name"
+#define MODEST_PRESETS_KEY_DOMAIN            "Domain"
+#define MODEST_PRESETS_KEY_MCC               "MCC"
+#define MODEST_PRESETS_KEY_INCOMING          "IncomingMailServer"
+#define MODEST_PRESETS_KEY_OUTGOING          "OutgoingMailServer"
+#define MODEST_PRESETS_KEY_MAILBOX_TYPE      "MailboxType"
+#define MODEST_PRESETS_KEY_MAILBOX_TYPE_POP  "pop"
+#define MODEST_PRESETS_KEY_MAILBOX_TYPE_IMAP "imap"
+#define MODEST_PRESETS_KEY_APOP              "APOPSecureLogin"
+#define MODEST_PRESETS_KEY_SECURE_SMTP       "SecureSMTP"
+#define MODEST_PRESETS_KEY_TRUE                     "true"
+
+/** An efficient way to store the info for each provider.
+ */
+typedef enum _ModestPresetsInfo {
+       /* two bits for the server type */
+       MODEST_PRESETS_INFO_NONE             = 0x0000,
+       MODEST_PRESETS_INFO_IMAP             = 0x0001,
+       MODEST_PRESETS_INFO_POP              = 0x0002,
+       MODEST_PRESETS_INFO_SMTP             = 0x0003,
+
+       /* one bit for each of these */
+       MODEST_PRESETS_INFO_APOP             = 0x0004,
+       MODEST_PRESETS_INFO_SECURE_SMTP      = 0x0008,
+       MODEST_PRESETS_INFO_SECURE_INCOMING  = 0x000f   
+} ModestPresetsInfo;
+
+/**
+ * modest_presets_get_info:
+ * @self: a valid ModestPresets instance
+ * @provider_id: ID of the provider 
+ * @incoming_server: get the incoming mailserver if TRUE, get the
+ * outgoing server otherwise
+ *
+ * get information about some incoming or outgoing mailserver
+ *
+ * Returns: a ModestPresetsInfo with the required information
+ */
+static ModestPresetsInfo
+modest_presets_get_info (ModestPresets *self, const gchar *provider_id, gboolean incoming_server);
+                                                   
+
+ModestPresets*
+modest_presets_new (const gchar *presetfile)
+{
+       ModestPresets *presets = NULL;
+       GError        *err     = NULL;
+       
+       g_return_val_if_fail (presetfile, NULL);
+       
+       presets = g_new (ModestPresets, 1);
+       presets->keyfile = g_key_file_new ();
+
+       if (!presets->keyfile) {
+               g_printerr ("modest: cannot instantiate GKeyFile\n");
+               g_free (presets);
+               return NULL;
+       }
+
+       if (!g_key_file_load_from_file (presets->keyfile, presetfile,
+                                       G_KEY_FILE_NONE, &err)) {
+               g_printerr ("modest: cannot open keyfile: %s\n",
+                           err ? err->message : "unknown reason");
+               g_error_free (err);
+               g_free (presets);
+               return NULL;
+       }
+
+       return presets;
+}
+
+gchar**
+modest_presets_get_providers  (ModestPresets *self, guint mcc,
+                              gboolean include_globals, gchar ***provider_ids)
+{
+       gchar **all_providers = NULL;
+       gchar **all_provider_ids = NULL;
+       gchar **filtered  = NULL;
+       gchar **filtered_ids = NULL;
+       GError *err       = NULL;
+       guint i, j, len;
+       
+       g_return_val_if_fail (self && self->keyfile, NULL);
+
+       /* Get all the provider IDs: */
+       all_provider_ids = g_key_file_get_groups (self->keyfile, NULL);
+       len = g_strv_length(all_provider_ids);
+
+       /* Get the names for all these providers: */
+       all_providers = g_new0(gchar*, len + 1); /* Provider names. */
+       for (i=0; i != len; ++i) {
+               const gchar * provider_id = all_provider_ids[i];
+               if(provider_id) {
+                       gchar* name = g_key_file_get_string(self->keyfile, provider_id, 
+                               MODEST_PRESETS_KEY_NAME, NULL);
+                               
+                       /* Be forgiving of missing names.
+                        * If we use NULL then we will null-terminate the array.
+                        */
+                       if(!name)
+                               name = g_strdup("");
+                               
+                       all_providers[i] = name;        
+               }
+               else
+                       all_providers[i] = NULL;
+       };
+               
+       /* return *all* providers? */
+       if (mcc == 0 && include_globals) {
+               *provider_ids = all_provider_ids;
+               return all_providers;
+       }
+       
+       /* nope: filter them */
+
+       filtered = g_new0(gchar*, len + 1); /* Provider names. */
+       filtered_ids = g_new0(gchar*, len + 1); /* Provider IDs */
+
+       for (i=0, j=0; i != len; ++i) {
+
+               int this_mcc;
+               this_mcc = g_key_file_get_integer (self->keyfile, all_provider_ids[i],
+                                                  MODEST_PRESETS_KEY_MCC, &err);
+               if (err) {
+                       g_strfreev (all_providers);
+                       g_strfreev (all_provider_ids);
+                       g_strfreev (filtered);
+                       g_strfreev (filtered_ids);
+                       
+                       g_printerr ("modest: error parsing keyfile: %s\n", err->message);
+                       g_error_free (err);
+                       
+                       return NULL;
+               }
+               
+               if (this_mcc == mcc || (this_mcc == 0 && include_globals)) {
+                       filtered[j]   = all_providers[i];
+                       filtered_ids[j]   = all_provider_ids[i];
+                       ++j;
+                       filtered[j] = NULL; /* the array must be NULL-terminated */
+                       filtered_ids[j] = NULL; /* the array must be NULL-terminated */
+                       
+                       all_providers[i]  = NULL; /*  g_strfreev: leave it alone */
+                       all_provider_ids[i]  = NULL; /*  g_strfreev: leave it alone */
+               }
+       }
+       
+       g_strfreev (all_providers);
+       g_strfreev (all_provider_ids);
+       
+       *provider_ids = filtered_ids;
+       return filtered;
+}
+
+
+gchar*
+modest_presets_get_server (ModestPresets *self, const gchar *provider_id,
+                          gboolean incoming_server)
+{      
+       g_return_val_if_fail (self && self->keyfile, NULL);
+       g_return_val_if_fail (provider_id, NULL);
+
+       return g_key_file_get_string (self->keyfile, provider_id, 
+                                     incoming_server ?
+                                     MODEST_PRESETS_KEY_INCOMING :
+                                     MODEST_PRESETS_KEY_OUTGOING,
+                                     NULL);
+}
+
+gchar *                   modest_presets_get_domain      (ModestPresets *self,
+                                                         const gchar *provider_id)
+{      
+       g_return_val_if_fail (self && self->keyfile, NULL);
+       g_return_val_if_fail (provider_id, NULL);
+
+       return g_key_file_get_string (self->keyfile, provider_id, 
+                                     MODEST_PRESETS_KEY_DOMAIN,
+                                     NULL);
+}              
+
+
+ModestPresetsInfo
+modest_presets_get_info (ModestPresets *self, const gchar *provider_id, gboolean incoming_server)
+{
+       ModestPresetsInfo info = 0;
+       gchar *val = NULL;
+       
+       g_return_val_if_fail (self && self->keyfile, 0);
+
+       if(incoming_server) {
+               val = g_key_file_get_string (self->keyfile, provider_id,
+                                               MODEST_PRESETS_KEY_INCOMING, NULL);
+               if (val) {
+                       g_free (val);
+                       val = g_key_file_get_string (self->keyfile, provider_id,
+                                                    MODEST_PRESETS_KEY_MAILBOX_TYPE, NULL);
+                       if (strcmp (val, MODEST_PRESETS_KEY_MAILBOX_TYPE_POP) == 0)
+                               info |= MODEST_PRESETS_INFO_POP;
+                       if (strcmp (val, MODEST_PRESETS_KEY_MAILBOX_TYPE_IMAP) == 0)
+                               info |= MODEST_PRESETS_INFO_IMAP;
+                       g_free (val);
+       
+                       val = g_key_file_get_string (self->keyfile, provider_id,
+                                                    MODEST_PRESETS_KEY_APOP, NULL);
+                       if (val && strcmp(val, MODEST_PRESETS_KEY_TRUE) == 0)
+                               info |= MODEST_PRESETS_INFO_APOP;
+                       g_free(val);
+               }
+       }
+       else /* outgoing: */ {
+               val = g_key_file_get_string (self->keyfile, provider_id,
+                                            MODEST_PRESETS_KEY_OUTGOING, NULL);
+               if (val) {
+                       g_free (val);
+                       info |= MODEST_PRESETS_INFO_SMTP;
+                       
+                       val = g_key_file_get_string (self->keyfile, provider_id,
+                                                    MODEST_PRESETS_KEY_SECURE_SMTP, NULL);
+                       if (val && strcmp(val,MODEST_PRESETS_KEY_TRUE) == 0)
+                               info |= MODEST_PRESETS_INFO_SECURE_SMTP;
+                       g_free(val);
+               }
+       }
+
+       return info;
+}
+
+ModestPresetsServerType
+modest_presets_get_info_server_type (ModestPresets *self,
+                                                   const gchar *provider_id,
+                                                   gboolean incoming_server)
+{
+       ModestPresetsInfo info = modest_presets_get_info (self, provider_id, incoming_server);
+
+       /* The server type is stored in the first 2 bits: */
+       info = info & 0x03;
+       
+       /* Convert from the internal enum to the public enum: */
+       if(info == MODEST_PRESETS_INFO_IMAP)
+               return MODEST_PRESETS_SERVER_TYPE_IMAP;
+       else if(info == MODEST_PRESETS_INFO_POP)
+               return MODEST_PRESETS_SERVER_TYPE_POP;
+       else if(info == MODEST_PRESETS_INFO_SMTP)
+               return MODEST_PRESETS_SERVER_TYPE_SMTP;
+       else
+               return MODEST_PRESETS_SERVER_TYPE_NONE;
+}
+
+ModestPresetsSecurity
+modest_presets_get_info_server_security (ModestPresets *self,
+                                                   const gchar *provider_id,
+                                                   gboolean incoming_server)
+{
+       ModestPresetsInfo info = modest_presets_get_info (self, provider_id, incoming_server);
+
+       /* The security flags are stored in all except the first 4 bits: */
+       info = info && !0x04;
+       
+       /* Convert from the internal flags to the public flags: */
+       ModestPresetsSecurity security = MODEST_PRESETS_SECURITY_NONE;
+       if(info && MODEST_PRESETS_INFO_APOP)
+               security = security | MODEST_PRESETS_SECURITY_APOP;
+               
+       if(info && MODEST_PRESETS_INFO_SECURE_SMTP)
+               security = security | MODEST_PRESETS_SECURITY_SECURE_SMTP;
+               
+       if(info && MODEST_PRESETS_INFO_SECURE_INCOMING)
+               security = security | MODEST_PRESETS_SECURITY_SECURE_INCOMING;
+
+       return security;
+}
+
+                                                       
+       
+       
+void
+modest_presets_destroy (ModestPresets *self)
+{
+       if (!self)
+               return;
+
+       g_key_file_free (self->keyfile);
+       self->keyfile = NULL;
+       
+       g_free (self);
+}
diff --git a/src/maemo/easysetup/modest-presets.h b/src/maemo/easysetup/modest-presets.h
new file mode 100644 (file)
index 0000000..7e602e0
--- /dev/null
@@ -0,0 +1,159 @@
+/* Copyright (c) 2006, Nokia Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Nokia Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MODEST_PRESETS_H__
+#define __MODEST_PRESETS_H__
+
+#include <glib.h>
+
+struct _ModestPresets {
+/* private data: don't touch */
+       GKeyFile *keyfile;
+};
+typedef struct _ModestPresets ModestPresets;
+
+typedef enum _ModestPresetsServerType {
+       MODEST_PRESETS_SERVER_TYPE_NONE,
+       MODEST_PRESETS_SERVER_TYPE_IMAP,
+       MODEST_PRESETS_SERVER_TYPE_POP,
+       MODEST_PRESETS_SERVER_TYPE_SMTP
+} ModestPresetsServerType;
+
+/** These are flags, which should be ORed.
+ */
+typedef enum _ModestPresetsSecurity {
+       MODEST_PRESETS_SECURITY_NONE = 0,
+       MODEST_PRESETS_SECURITY_APOP = 1 << 0,
+       MODEST_PRESETS_SECURITY_SECURE_SMTP = 1 << 1,
+       MODEST_PRESETS_SECURITY_SECURE_INCOMING = 1 << 2
+} ModestPresetsSecurity;
+
+/* typedef enum _ModestPresetsInfo ModestPresetsInfo; */
+
+
+/**
+ * modest_presets_new:
+ * @presetfile: the full path to the file with presets (in GKeyFile format)
+ * 
+ * make a new ModestPresets instance
+ *
+ * Returns: a new ModestPresets instance, or NULL in case of error.
+ */
+ModestPresets*            modest_presets_new             (const gchar *presetfile);
+
+
+/**
+ * modest_presets_get_providers:
+ * @self: a valid ModestPresets instance
+ * @mcc: limit the search to providers with this mcc (Mobile Country Code),
+ *       or 0  to get all
+ * @include_globals: include (global) providers without MCC (such as GMail, Yahoo)
+ * @provider_ids: Output parameter, which will be set to a newly allocated array of strings, or NULL in case of error.
+ * 
+ * get a list of providers matching certian criteria
+ *
+ * Returns: The provider names, as a newly allocated array of strings, or NULL in case of error
+ * should be freed with g_strfreev
+ * 
+ **/
+gchar **         modest_presets_get_providers   (ModestPresets *self, guint mcc, 
+                                                gboolean include_globals, gchar ***provider_ids);
+
+/**
+ * modest_presets_get_server:
+ * @self: a valid ModestPresets instance
+ * @provider_id: ID of the provider 
+ * @incoming_server: get the incoming mailserver if TRUE, get the
+ * outgoing server otherwise
+ *
+ * get the name of a incoming or outgoing mailserver
+ * 
+ * Returns: a newly allocated string with the servername, or NULL in case
+ * of error, or server not found. (FIXME). Note that if the (incoming) server uses a
+ * non-standard port, the port number is appended to the name, eg. pop.foo.fi:995
+ */
+gchar *                   modest_presets_get_server      (ModestPresets *self,
+                                                         const gchar *provider_id,
+                                                         gboolean incoming_server);
+                                                         
+/**
+ * modest_presets_get_domain:
+ * @self: a valid ModestPresets instance
+ * @provider_id: ID of the provider 
+ *
+ * Get the name of the most-used domain for theis provider. For instance. hotmail.com
+ * 
+ * Returns: a newly allocated string with the domain name, or NULL in case
+ * of error.
+ */
+gchar *                   modest_presets_get_domain      (ModestPresets *self,
+                                                         const gchar *provider_id);
+                                                         
+/**
+ * modest_presets_get_info_server_type:
+ * @self: a valid ModestPresets instance
+ * @provider_id: ID of the provider 
+ * @incoming_server: get the incoming mailserver if TRUE, get the
+ * outgoing server otherwise
+ *
+ * get information about some incoming or outgoing mailserver
+ *
+ * Returns: a ModestPresetsServerType with the required information
+ */
+ModestPresetsServerType          modest_presets_get_info_server_type (ModestPresets *self,
+                                                   const gchar *provider_id,
+                                                   gboolean incoming_server);
+
+/**
+ * modest_presets_get_info_server_security:
+ * @self: a valid ModestPresets instance
+ * @provider_id: ID of the provider 
+ * @incoming_server: get the incoming mailserver if TRUE, get the
+ * outgoing server otherwise
+ *
+ * get information about some incoming or outgoing mailserver
+ *
+ * Returns: ModestPresetsSecurity ORable flags with the required information
+ */                                        
+ModestPresetsSecurity          modest_presets_get_info_server_security (ModestPresets *self,
+                                                   const gchar *provider_id,
+                                                   gboolean incoming_server);
+
+/**
+ * modest_presets_destroy:
+ * @self: a valid ModestPresets instance (ie. must not be NULL)
+ *
+ * destroy ModestPresets instance; this is required after you're done with it.
+ */
+void                      modest_presets_destroy         (ModestPresets *self);
+
+
+#endif /*__MODEST_PRESETS__*/
+
+
diff --git a/src/maemo/easysetup/modest-text-utils.c b/src/maemo/easysetup/modest-text-utils.c
new file mode 100644 (file)
index 0000000..875c20d
--- /dev/null
@@ -0,0 +1,923 @@
+/* Copyright (c) 2006, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib/gi18n.h>
+#include <regex.h>
+#include <modest-text-utils.h>
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /*HAVE_CONFIG_H */
+
+/* defines */
+#define FORWARD_STRING _("-----Forwarded Message-----")
+#define FROM_STRING _("From:")
+#define SENT_STRING _("Sent:")
+#define TO_STRING _("To:")
+#define        SUBJECT_STRING _("Subject:")
+#define EMPTY_STRING ""
+
+/*
+ * we need these regexps to find URLs in plain text e-mails
+ */
+typedef struct _url_match_pattern_t url_match_pattern_t;
+struct _url_match_pattern_t {
+       gchar   *regex;
+       regex_t *preg;
+       gchar   *prefix;
+};
+
+typedef struct _url_match_t url_match_t;
+struct _url_match_t {
+       guint offset;
+       guint len;
+       const gchar* prefix;
+};
+
+#define MAIL_VIEWER_URL_MATCH_PATTERNS  {                              \
+       { "(file|rtsp|http|ftp|https)://[-A-Za-z0-9_$.+!*(),;:@%&=?/~#]+[-A-Za-z0-9_$%&=?/~#]",\
+         NULL, NULL },\
+       { "www\\.[-a-z0-9.]+[-a-z0-9](:[0-9]*)?(/[-A-Za-z0-9_$.+!*(),;:@%&=?/~#]*[^]}\\),?!;:\"]?)?",\
+         NULL, "http://" },\
+       { "ftp\\.[-a-z0-9.]+[-a-z0-9](:[0-9]*)?(/[-A-Za-z0-9_$.+!*(),;:@%&=?/~#]*[^]}\\),?!;:\"]?)?",\
+         NULL, "ftp://" },\
+       { "(voipto|callto|chatto|jabberto|xmpp):[-_a-z@0-9.\\+]+", \
+          NULL, NULL},                                             \
+       { "mailto:[-_a-z0-9.\\+]+@[-_a-z0-9.]+",                    \
+         NULL, NULL},\
+       { "[-_a-z0-9.\\+]+@[-_a-z0-9.]+",\
+         NULL, "mailto:"}\
+       }
+
+/* private */
+static gchar*   cite                    (const time_t sent_date, const gchar *from);
+static void     hyperlinkify_plain_text (GString *txt);
+static gint     cmp_offsets_reverse     (const url_match_t *match1, const url_match_t *match2);
+static void     chk_partial_match       (const url_match_t *match, guint* offset);
+static GSList*  get_url_matches         (GString *txt);
+
+static GString* get_next_line           (const char *b, const gsize blen, const gchar * iter);
+static int      get_indent_level        (const char *l);
+static void     unquote_line            (GString * l);
+static void     append_quoted           (GString * buf, const int indent, const GString * str, 
+                                        const int cutpoint);
+static int      get_breakpoint_utf8     (const gchar * s, const gint indent, const gint limit);
+static int      get_breakpoint_ascii    (const gchar * s, const gint indent, const gint limit);
+static int      get_breakpoint          (const gchar * s, const gint indent, const gint limit);
+
+static gchar*   modest_text_utils_quote_plain_text (const gchar *text, 
+                                                   const gchar *cite, 
+                                                   int limit);
+
+static gchar*   modest_text_utils_quote_html       (const gchar *text, 
+                                                   const gchar *cite, 
+                                                   int limit);
+
+
+/* ******************************************************************* */
+/* ************************* PUBLIC FUNCTIONS ************************ */
+/* ******************************************************************* */
+
+gchar *
+modest_text_utils_quote (const gchar *text, 
+                        const gchar *content_type,
+                        const gchar *from,
+                        const time_t sent_date, 
+                        int limit)
+{
+       gchar *retval, *cited;
+
+       g_return_val_if_fail (text, NULL);
+       g_return_val_if_fail (content_type, NULL);
+
+       cited = cite (sent_date, from);
+       
+       if (content_type && strcmp (content_type, "text/html") == 0)
+               /* TODO: extract the <body> of the HTML and pass it to
+                  the function */
+               retval = modest_text_utils_quote_html (text, cited, limit);
+       else
+               retval = modest_text_utils_quote_plain_text (text, cited, limit);
+       
+       g_free (cited);
+
+       return retval;
+}
+
+
+gchar *
+modest_text_utils_cite (const gchar *text,
+                       const gchar *content_type,
+                       const gchar *from,
+                       time_t sent_date)
+{
+       gchar *tmp, *retval;
+
+       g_return_val_if_fail (text, NULL);
+       g_return_val_if_fail (content_type, NULL);
+
+       tmp = cite (sent_date, from);
+       retval = g_strdup_printf ("%s%s\n", tmp, text);
+       g_free (tmp);
+
+       return retval;
+}
+
+gchar * 
+modest_text_utils_inline (const gchar *text,
+                         const gchar *content_type,
+                         const gchar *from,
+                         time_t sent_date,
+                         const gchar *to,
+                         const gchar *subject)
+{
+       gchar sent_str[101];
+       const gchar *plain_format = "%s\n%s %s\n%s %s\n%s %s\n%s %s\n\n%s";
+       const gchar *html_format = \
+               "%s<br>\n<table width=\"100%\" border=\"0\" cellspacing=\"2\" cellpadding=\"2\">\n" \
+               "<tr><td>%s</td><td>%s</td></tr>\n" \
+               "<tr><td>%s</td><td>%s</td></tr>\n" \
+               "<tr><td>%s</td><td>%s</td></tr>\n" \
+               "<tr><td>%s</td><td>%s</td></tr>\n" \
+               "<br><br>%s";
+       const gchar *format;
+
+       g_return_val_if_fail (text, NULL);
+       g_return_val_if_fail (content_type, NULL);
+       g_return_val_if_fail (text, NULL);
+       
+       modest_text_utils_strftime (sent_str, 100, "%c", sent_date);
+
+       if (!strcmp (content_type, "text/html"))
+               /* TODO: extract the <body> of the HTML and pass it to
+                  the function */
+               format = html_format;
+       else
+               format = plain_format;
+
+       return g_strdup_printf (format, 
+                               FORWARD_STRING,
+                               FROM_STRING, (from) ? from : EMPTY_STRING,
+                               SENT_STRING, sent_str,
+                               TO_STRING, (to) ? to : EMPTY_STRING,
+                               SUBJECT_STRING, (subject) ? subject : EMPTY_STRING,
+                               text);
+}
+
+/* just to prevent warnings:
+ * warning: `%x' yields only last 2 digits of year in some locales
+ */
+gsize
+modest_text_utils_strftime(char *s, gsize max, const char *fmt, time_t timet)
+{
+       static GDate date;
+
+       /* does not work on old maemo glib: 
+        *   g_date_set_time_t (&date, timet);
+        */
+       g_date_set_time (&date, (GTime) timet); 
+
+       return g_date_strftime (s, max, fmt, (const GDate*) &date);
+}
+
+gchar *
+modest_text_utils_derived_subject (const gchar *subject, const gchar *prefix)
+{
+       gchar *tmp;
+
+       g_return_val_if_fail (prefix, NULL);
+       
+       if (!subject)
+               return g_strdup (prefix);
+
+       tmp = g_strchug (g_strdup (subject));
+
+       if (!strncmp (tmp, prefix, strlen (prefix))) {
+               return tmp;
+       } else {
+               g_free (tmp);
+               return g_strdup_printf ("%s %s", prefix, subject);
+       }
+}
+
+gchar*
+modest_text_utils_remove_address (const gchar *address_list, const gchar *address)
+{
+       gchar *dup, *token, *ptr, *result;
+       GString *filtered_emails;
+
+       g_return_val_if_fail (address_list, NULL);
+
+       if (!address)
+               return g_strdup (address_list);
+       
+       /* search for substring */
+       if (!strstr ((const char *) address_list, (const char *) address))
+               return g_strdup (address_list);
+
+       dup = g_strdup (address_list);
+       filtered_emails = g_string_new (NULL);
+       
+       token = strtok_r (dup, ",", &ptr);
+
+       while (token != NULL) {
+               /* Add to list if not found */
+               if (!strstr ((const char *) token, (const char *) address)) {
+                       if (filtered_emails->len == 0)
+                               g_string_append_printf (filtered_emails, "%s", g_strstrip (token));
+                       else
+                               g_string_append_printf (filtered_emails, ",%s", g_strstrip (token));
+               }
+               token = strtok_r (NULL, ",", &ptr);
+       }
+       result = filtered_emails->str;
+
+       /* Clean */
+       g_free (dup);
+       g_string_free (filtered_emails, FALSE);
+
+       return result;
+}
+
+gchar*
+modest_text_utils_convert_to_html (const gchar *data)
+{
+       guint            i;
+       gboolean         first_space = TRUE;
+       GString         *html;      
+       gsize           len;
+
+       if (!data)
+               return NULL;
+
+       len = strlen (data);
+       html = g_string_sized_new (len + 100);  /* just a  guess... */
+       
+       g_string_append_printf (html,
+                               "<html>"
+                               "<head>"
+                               "<meta http-equiv=\"content-type\""
+                               " content=\"text/html; charset=utf8\">"
+                               "</head>"
+                               "<body><tt>");
+       
+       /* replace with special html chars where needed*/
+       for (i = 0; i != len; ++i)  {
+               char    kar = data[i]; 
+               switch (kar) {
+                       
+               case 0:  break; /* ignore embedded \0s */       
+               case '<' : g_string_append   (html, "&lt;"); break;
+               case '>' : g_string_append   (html, "&gt;"); break;
+               case '&' : g_string_append   (html, "&quot;"); break;
+               case '\n': g_string_append   (html, "<br>\n"); break;
+               default:
+                       if (kar == ' ') {
+                               g_string_append (html, first_space ? " " : "&nbsp;");
+                               first_space = FALSE;
+                       } else  if (kar == '\t')
+                               g_string_append (html, "&nbsp; &nbsp;&nbsp;");
+                       else {
+                               int charnum = 0;
+                               first_space = TRUE;
+                               /* optimization trick: accumulate 'normal' chars, then copy */
+                               do {
+                                       kar = data [++charnum + i];
+                                       
+                               } while ((i + charnum < len) &&
+                                        (kar > '>' || (kar != '<' && kar != '>'
+                                                       && kar != '&' && kar !=  ' '
+                                                       && kar != '\n' && kar != '\t')));
+                               g_string_append_len (html, &data[i], charnum);
+                               i += (charnum  - 1);
+                       }
+               }
+       }
+       
+       g_string_append (html, "</tt></body></html>");
+       hyperlinkify_plain_text (html);
+
+       return g_string_free (html, FALSE);
+}
+
+GSList *
+modest_text_utils_split_addresses_list (const gchar *addresses)
+{
+       gchar *current, *start, *last_blank;
+       GSList *result = NULL;
+
+       start = (gchar *) addresses;
+       current = start;
+       last_blank = start;
+
+       while (*current != '\0') {
+               if ((start == current)&&((*current == ' ')||(*current == ','))) {
+                       start++;
+                       last_blank = current;
+               } else if (*current == ',') {
+                       gchar *new_address = NULL;
+                       new_address = g_strndup (start, current - last_blank);
+                       result = g_slist_prepend (result, new_address);
+                       start = current + 1;
+                       last_blank = start;
+               } else if (*current == '\"') {
+                       if (current == start) {
+                               current++;
+                               start++;
+                       }
+                       while ((*current != '\"')&&(*current != '\0'))
+                               current++;
+               }
+                               
+               current++;
+       }
+
+       if (start != current) {
+               gchar *new_address = NULL;
+               new_address = g_strndup (start, current - last_blank);
+               result = g_slist_prepend (result, new_address);
+       }
+
+       result = g_slist_reverse (result);
+       return result;
+
+}
+
+void
+modest_text_utils_address_range_at_position (const gchar *recipients_list,
+                                            gint position,
+                                            gint *start,
+                                            gint *end)
+{
+       gchar *current = NULL;
+       gint range_start = 0;
+       gint range_end = 0;
+       gint index;
+       gboolean is_quoted = FALSE;
+
+       index = 0;
+       for (current = (gchar *) recipients_list; *current != '\0'; current = g_utf8_find_next_char (current, NULL)) {
+               gunichar c = g_utf8_get_char (current);
+
+               if ((c == ',') && (!is_quoted)) {
+                       if (index < position) {
+                               range_start = index + 1;
+                       } else {
+                               break;
+                       }
+               } else if (c == '\"') {
+                       is_quoted = !is_quoted;
+               } else if ((c == ' ') &&(range_start == index)) {
+                       range_start ++;
+               }
+               index ++;
+               range_end = index;
+       }
+
+       if (start)
+               *start = range_start;
+       if (end)
+               *end = range_end;
+}
+
+
+/* ******************************************************************* */
+/* ************************* UTILIY FUNCTIONS ************************ */
+/* ******************************************************************* */
+
+static GString *
+get_next_line (const gchar * b, const gsize blen, const gchar * iter)
+{
+       GString *gs;
+       const gchar *i0;
+       
+       if (iter > b + blen)
+               return g_string_new("");
+       
+       i0 = iter;
+       while (iter[0]) {
+               if (iter[0] == '\n')
+                       break;
+               iter++;
+       }
+       gs = g_string_new_len (i0, iter - i0);
+       return gs;
+}
+static int
+get_indent_level (const char *l)
+{
+       int indent = 0;
+
+       while (l[0]) {
+               if (l[0] == '>') {
+                       indent++;
+                       if (l[1] == ' ') {
+                               l++;
+                       }
+               } else {
+                       break;
+               }
+               l++;
+
+       }
+
+       /*      if we hit the signature marker "-- ", we return -(indent + 1). This
+        *      stops reformatting.
+        */
+       if (strcmp (l, "-- ") == 0) {
+               return -1 - indent;
+       } else {
+               return indent;
+       }
+}
+
+static void
+unquote_line (GString * l)
+{
+       gchar *p;
+
+       p = l->str;
+       while (p[0]) {
+               if (p[0] == '>') {
+                       if (p[1] == ' ') {
+                               p++;
+                       }
+               } else {
+                       break;
+               }
+               p++;
+       }
+       g_string_erase (l, 0, p - l->str);
+}
+
+static void
+append_quoted (GString * buf, int indent, const GString * str,
+              const int cutpoint)
+{
+       int i;
+
+       indent = indent < 0 ? abs (indent) - 1 : indent;
+       for (i = 0; i <= indent; i++) {
+               g_string_append (buf, "> ");
+       }
+       if (cutpoint > 0) {
+               g_string_append_len (buf, str->str, cutpoint);
+       } else {
+               g_string_append (buf, str->str);
+       }
+       g_string_append (buf, "\n");
+}
+
+static int
+get_breakpoint_utf8 (const gchar * s, gint indent, const gint limit)
+{
+       gint index = 0;
+       const gchar *pos, *last;
+       gunichar *uni;
+
+       indent = indent < 0 ? abs (indent) - 1 : indent;
+
+       last = NULL;
+       pos = s;
+       uni = g_utf8_to_ucs4_fast (s, -1, NULL);
+       while (pos[0]) {
+               if ((index + 2 * indent > limit) && last) {
+                       g_free (uni);
+                       return last - s;
+               }
+               if (g_unichar_isspace (uni[index])) {
+                       last = pos;
+               }
+               pos = g_utf8_next_char (pos);
+               index++;
+       }
+       g_free (uni);
+       return strlen (s);
+}
+
+static int
+get_breakpoint_ascii (const gchar * s, const gint indent, const gint limit)
+{
+       gint i, last;
+
+       last = strlen (s);
+       if (last + 2 * indent < limit)
+               return last;
+
+       for (i = strlen (s); i > 0; i--) {
+               if (s[i] == ' ') {
+                       if (i + 2 * indent <= limit) {
+                               return i;
+                       } else {
+                               last = i;
+                       }
+               }
+       }
+       return last;
+}
+
+static int
+get_breakpoint (const gchar * s, const gint indent, const gint limit)
+{
+
+       if (g_utf8_validate (s, -1, NULL)) {
+               return get_breakpoint_utf8 (s, indent, limit);
+       } else {                /* assume ASCII */
+               //g_warning("invalid UTF-8 in msg");
+               return get_breakpoint_ascii (s, indent, limit);
+       }
+}
+
+static gchar *
+cite (const time_t sent_date, const gchar *from)
+{
+       gchar sent_str[101];
+
+       /* format sent_date */
+       modest_text_utils_strftime (sent_str, 100, "%c", sent_date);
+       return g_strdup_printf (N_("On %s, %s wrote:\n"), 
+                               sent_str, 
+                               (from) ? from : EMPTY_STRING);
+}
+
+
+static gchar *
+modest_text_utils_quote_plain_text (const gchar *text, 
+                                   const gchar *cite, 
+                                   int limit)
+{
+       const gchar *iter;
+       gint indent, breakpoint, rem_indent = 0;
+       GString *q, *l, *remaining;
+       gsize len;
+
+       /* remaining will store the rest of the line if we have to break it */
+       q = g_string_new (cite);
+       remaining = g_string_new ("");
+
+       iter = text;
+       len = strlen(text);
+       do {
+               l = get_next_line (text, len, iter);
+               iter = iter + l->len + 1;
+               indent = get_indent_level (l->str);
+               unquote_line (l);
+
+               if (remaining->len) {
+                       if (l->len && indent == rem_indent) {
+                               g_string_prepend (l, " ");
+                               g_string_prepend (l, remaining->str);
+                       } else {
+                               do {
+                                       breakpoint =
+                                               get_breakpoint (remaining->str,
+                                                               rem_indent,
+                                                               limit);
+                                       append_quoted (q, rem_indent,
+                                                      remaining, breakpoint);
+                                       g_string_erase (remaining, 0,
+                                                       breakpoint);
+                                       if (remaining->str[0] == ' ') {
+                                               g_string_erase (remaining, 0,
+                                                               1);
+                                       }
+                               } while (remaining->len);
+                       }
+               }
+               g_string_free (remaining, TRUE);
+               breakpoint = get_breakpoint (l->str, indent, limit);
+               remaining = g_string_new (l->str + breakpoint);
+               if (remaining->str[0] == ' ') {
+                       g_string_erase (remaining, 0, 1);
+               }
+               rem_indent = indent;
+               append_quoted (q, indent, l, breakpoint);
+               g_string_free (l, TRUE);
+       } while ((iter < text + len) || (remaining->str[0]));
+
+       return g_string_free (q, FALSE);
+}
+
+static gchar*
+modest_text_utils_quote_html (const gchar *text, 
+                             const gchar *cite, 
+                             int limit)
+{
+       const gchar *format = \
+               "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" \
+               "<html>\n" \
+               "<body>\n" \
+               "%s" \
+               "<blockquote type=\"cite\">\n%s\n</blockquote>\n" \
+               "</body>\n" \
+               "</html>\n";
+
+       return g_strdup_printf (format, cite, text);
+}
+
+static gint 
+cmp_offsets_reverse (const url_match_t *match1, const url_match_t *match2)
+{
+       return match2->offset - match1->offset;
+}
+
+
+
+/*
+ * check if the match is inside an existing match... */
+static void
+chk_partial_match (const url_match_t *match, guint* offset)
+{
+       if (*offset >= match->offset && *offset < match->offset + match->len)
+               *offset = -1;
+}
+
+static GSList*
+get_url_matches (GString *txt)
+{
+       regmatch_t rm;
+        guint rv, i, offset = 0;
+        GSList *match_list = NULL;
+
+       static url_match_pattern_t patterns[] = MAIL_VIEWER_URL_MATCH_PATTERNS;
+       const size_t pattern_num = sizeof(patterns)/sizeof(url_match_pattern_t);
+
+       /* initalize the regexps */
+       for (i = 0; i != pattern_num; ++i) {
+               patterns[i].preg = g_slice_new0 (regex_t);
+
+               /* this should not happen */
+               g_return_val_if_fail (regcomp (patterns[i].preg, patterns[i].regex,
+                                              REG_ICASE|REG_EXTENDED|REG_NEWLINE) == 0, NULL);
+       }
+        /* find all the matches */
+       for (i = 0; i != pattern_num; ++i) {
+               offset     = 0; 
+               while (1) {
+                       int test_offset;
+                       if ((rv = regexec (patterns[i].preg, txt->str + offset, 1, &rm, 0)) != 0) {
+                               g_return_val_if_fail (rv == REG_NOMATCH, NULL); /* this should not happen */
+                               break; /* try next regexp */ 
+                       }
+                       if (rm.rm_so == -1)
+                               break;
+
+                       /* FIXME: optimize this */
+                       /* to avoid partial matches on something that was already found... */
+                       /* check_partial_match will put -1 in the data ptr if that is the case */
+                       test_offset = offset + rm.rm_so;
+                       g_slist_foreach (match_list, (GFunc)chk_partial_match, &test_offset);
+                       
+                       /* make a list of our matches (<offset, len, prefix> tupels)*/
+                       if (test_offset != -1) {
+                               url_match_t *match = g_slice_new (url_match_t);
+                               match->offset = offset + rm.rm_so;
+                               match->len    = rm.rm_eo - rm.rm_so;
+                               match->prefix = patterns[i].prefix;
+                               match_list = g_slist_prepend (match_list, match);
+                       }
+                       offset += rm.rm_eo;
+               }
+       }
+
+       for (i = 0; i != pattern_num; ++i) {
+               regfree (patterns[i].preg);
+               g_slice_free  (regex_t, patterns[i].preg);
+       } /* don't free patterns itself -- it's static */
+       
+       /* now sort the list, so the matches are in reverse order of occurence.
+        * that way, we can do the replacements starting from the end, so we don't need
+        * to recalculate the offsets
+        */
+       match_list = g_slist_sort (match_list,
+                                  (GCompareFunc)cmp_offsets_reverse); 
+       return match_list;      
+}
+
+
+
+static void
+hyperlinkify_plain_text (GString *txt)
+{
+       GSList *cursor;
+       GSList *match_list = get_url_matches (txt);
+
+       /* we will work backwards, so the offsets stay valid */
+       for (cursor = match_list; cursor; cursor = cursor->next) {
+
+               url_match_t *match = (url_match_t*) cursor->data;
+               gchar *url  = g_strndup (txt->str + match->offset, match->len);
+               gchar *repl = NULL; /* replacement  */
+
+               /* the prefix is NULL: use the one that is already there */
+               repl = g_strdup_printf ("<a href=\"%s%s\">%s</a>",
+                                       match->prefix ? match->prefix : EMPTY_STRING, 
+                                       url, url);
+
+               /* replace the old thing with our hyperlink
+                * replacement thing */
+               g_string_erase  (txt, match->offset, match->len);
+               g_string_insert (txt, match->offset, repl);
+               
+               g_free (url);
+               g_free (repl);
+
+               g_slice_free (url_match_t, match);      
+       }
+       
+       g_slist_free (match_list);
+}
+
+
+
+gchar*
+modest_text_utils_get_display_address (gchar *address)
+{
+       gchar *cursor;
+       
+       if (!address)
+               return NULL;
+
+       g_return_val_if_fail (g_utf8_validate (address, -1, NULL), NULL);
+
+       g_strchug (address); /* remove leading whitespace */
+
+       /*  <email@address> from display name */
+       cursor = g_strstr_len (address, strlen(address), "<");
+       if (cursor == address) /* there's nothing else? leave it */
+               return address;
+       if (cursor) 
+               cursor[0]='\0';
+
+       /* remove (bla bla) from display name */
+       cursor = g_strstr_len (address, strlen(address), "(");
+       if (cursor == address) /* there's nothing else? leave it */
+               return address;
+       if (cursor) 
+               cursor[0]='\0';
+
+       g_strchomp (address); /* remove trailing whitespace */
+
+       return address;
+}
+
+
+
+gint 
+modest_text_utils_get_subject_prefix_len (const gchar *sub)
+{
+       gint i;
+       static const gchar* prefix[] = {
+               "Re:", "RE:", "Fwd:", "FWD:", "FW:", NULL
+       };
+               
+       if (!sub || (sub[0] != 'R' && sub[0] != 'F')) /* optimization */
+               return 0;
+
+       i = 0;
+       
+       while (prefix[i]) {
+               if (g_str_has_prefix(sub, prefix[i])) {
+                       int prefix_len = strlen(prefix[i]); 
+                       if (sub[prefix_len] == ' ')
+                               ++prefix_len; /* ignore space after prefix as well */
+                       return prefix_len; 
+               }
+               ++i;
+       }
+       return 0;
+}
+
+
+gint
+modest_text_utils_utf8_strcmp (const gchar* s1, const gchar *s2, gboolean insensitive)
+{
+       gint result = 0;
+       gchar *n1, *n2;
+
+       /* work even when s1 and/or s2 == NULL */
+       if (G_UNLIKELY(s1 == s2))
+               return 0;
+
+       /* if it's not case sensitive */
+       if (!insensitive)
+               return strcmp (s1 ? s1 : "", s2 ? s2 : "");
+       
+       n1 = g_utf8_collate_key (s1 ? s1 : "", -1);
+       n2 = g_utf8_collate_key (s2 ? s2 : "", -1);
+       
+       result = strcmp (n1, n2);
+
+       g_free (n1);
+       g_free (n2);
+       
+       return result;
+}
+
+
+gchar*
+modest_text_utils_get_display_date (time_t date)
+{
+       time_t now;
+       const guint BUF_SIZE = 64; 
+       gchar date_buf[BUF_SIZE];  
+       gchar now_buf [BUF_SIZE];  
+       
+       now = time (NULL);
+
+       modest_text_utils_strftime (date_buf, BUF_SIZE, "%x", date);
+       modest_text_utils_strftime (now_buf,  BUF_SIZE, "%x",  now); /* today */
+       
+       /* if this is today, get the time instead of the date */
+       if (strcmp (date_buf, now_buf) == 0)
+               modest_text_utils_strftime (date_buf, BUF_SIZE, _("%X"), date);
+       
+       return g_strdup(date_buf);
+}
+
+gboolean 
+modest_text_utils_validate_email_address (const gchar *email_address)
+{
+       int count = 0;
+       const gchar *c = NULL, *domain = NULL;
+       static gchar *rfc822_specials = "()<>@,;:\\\"[]";
+
+       /* first we validate the name portion (name@domain) */
+       for (c = email_address;  *c;  c++) {
+               if (*c == '\"' && 
+                   (c == email_address || 
+                    *(c - 1) == '.' || 
+                    *(c - 1) == '\"')) {
+                       while (*++c) {
+                               if (*c == '\"') 
+                                       break;
+                               if (*c == '\\' && (*++c == ' ')) 
+                                       continue;
+                               if (*c <= ' ' || *c >= 127) 
+                                       return FALSE;
+                       }
+                       if (!*c++) 
+                               return FALSE;
+                       if (*c == '@') 
+                               break;
+                       if (*c != '.') 
+                               return FALSE;
+                       continue;
+               }
+               if (*c == '@') 
+                       break;
+               if (*c <= ' ' || *c >= 127) 
+                       return FALSE;
+               if (strchr(rfc822_specials, *c)) 
+                       return FALSE;
+       }
+       if (c == email_address || *(c - 1) == '.') 
+               return FALSE;
+
+       /* next we validate the domain portion (name@domain) */
+       if (!*(domain = ++c)) 
+               return FALSE;
+       do {
+               if (*c == '.') {
+                       if (c == domain || *(c - 1) == '.') 
+                               return FALSE;
+                       count++;
+               }
+               if (*c <= ' ' || *c >= 127) 
+                       return FALSE;
+               if (strchr(rfc822_specials, *c)) 
+                       return FALSE;
+       } while (*++c);
+
+       return (count >= 1) ? TRUE : FALSE;
+}
+
+
+
+
+gchar *
+modest_text_utils_get_display_size (guint size)
+{
+       const guint KB=1024;
+       const guint MB=1024 * KB;
+       const guint GB=1024 * MB;
+       const guint TB=1024 * GB;
+
+       if (size < KB)
+               return g_strdup_printf (_("%0.1f Kb"), (double)size / KB);
+       else if (size < MB)
+               return g_strdup_printf (_("%d Kb"), size / KB);
+       else if (size < GB)
+               return g_strdup_printf (_("%d Mb"), size / MB);
+       else if (size < TB)
+               return g_strdup_printf (_("%d Gb"), size/ GB);
+       else
+               return g_strdup_printf (_("Very big"));
+}
diff --git a/src/maemo/easysetup/modest-text-utils.h b/src/maemo/easysetup/modest-text-utils.h
new file mode 100644 (file)
index 0000000..18dea34
--- /dev/null
@@ -0,0 +1,253 @@
+/* Copyright (c) 2006, Nokia Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Nokia Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/* modest-text-utils.h */
+
+#ifndef __MODEST_TEXT_UTILS_H__
+#define __MODEST_TEXT_UTILS_H__
+
+#include <time.h>
+#include <glib.h>
+
+/**
+ * modest_text_utils_derived_subject:
+ * @subject: a string which contains the original subject
+ * @prefix: the prefix for the new subject (such as 'Re:' or 'Fwd:'),
+ *           must not be NULL
+ *
+ * create a 'derived' subject line for eg. replies and forwards 
+ * 
+ * Returns: a newly allocated string containing the resulting subject
+ * subject == NULL, then @prefix " " will be returned
+ */
+gchar* modest_text_utils_derived_subject (const gchar *subject, 
+                                         const gchar* prefix);
+
+
+/**
+ * modest_text_utils_quote:
+ * @text: a non-NULL string which contains the message to quote
+ * @from: a non-NULL  sender of the original message
+ * @content_type: the non-NULL content type for the quoting, e.g. "text/html"
+ * @sent_date: sent date/time of the original message
+ * @limit: specifies the maximum characters per line in the quoted text
+ * 
+ * quote an existing message
+ * 
+ * Returns: a newly allocated string containing the quoted message
+ */
+gchar* modest_text_utils_quote (const gchar *text, 
+                               const gchar *content_type,
+                               const gchar *from,
+                               const time_t sent_date, 
+                               int limit);
+
+
+/**
+ * modest_text_utils_cited_text:
+ * @from: sender of the message
+ * @sent_date: the sent date of the original message
+ * @text: the text of the original message
+ *
+ * cite the text in a message
+ * 
+ * Returns: a newly allocated string containing the cited text
+ */
+gchar* modest_text_utils_cite (const gchar *text,
+                              const gchar *content_type,
+                              const gchar *from,
+                              time_t sent_date);
+
+/**
+ * modest_text_utils_inlined_text
+ * @from: the non-NULL sender of the original message
+ * @sent_date: sent date/time of the original message
+ * @to: 
+ * @subject: 
+ * @text: 
+ *
+ * creates a new string with the "Original message" text prepended to
+ * the text passed as argument and some data of the header
+ * 
+ * Returns: a newly allocated string containing the quoted message
+ */
+gchar*   modest_text_utils_inline (const gchar *text,
+                                  const gchar *content_type,
+                                  const gchar *from,
+                                  time_t sent_date,
+                                  const gchar *to,
+                                  const gchar *subject);
+
+/**
+ * modest_text_utils_remove_address
+ * @address_list: none-NULL string with a comma-separated list of email addresses
+ * @address: an specific e-mail address 
+ *
+ * remove a specific address from a list of email addresses; if @address
+ * is NULL, returns an unchanged @address_list
+ * 
+ * Returns: a newly allocated string containing the new list, or NULL
+ * in case of error or the original @address_list was NULL
+ */
+gchar*   modest_text_utils_remove_address (const gchar *address_list, 
+                                          const gchar *address);
+
+/**
+ * modest_text_utils_address_range_at_position:
+ * @address_list: utf8 string containing a list of addresses
+ * @position: a gint
+ * @start: a gint pointer
+ * @end: a gint pointer
+ *
+ * Finds the start and end positions of the address at @position,
+ * in @recipients_list, a list of addresses in the format of a 
+ * recipient list in email. It stores the results in @start and
+ * @end
+ */
+void     modest_text_utils_address_range_at_position (const gchar *recipients_list,
+                                                     gint position,
+                                                     gint *start,
+                                                     gint *end);
+                                                     
+
+/**
+ * modest_text_utils_convert_to_html:
+ * @txt: a string which contains the message to quote
+ *
+ * convert plain text (utf8) into html
+ * 
+ * Returns: a newly allocated string containing the html
+ */
+gchar*  modest_text_utils_convert_to_html (const gchar *txt);
+
+
+/**
+ * modest_text_utils_strftime:
+ * @s:
+ * @max:
+ * @fmt:
+ * @timet:
+ *
+ * this is just an alias for strftime(3), so we can use that without
+ * getting warning from gcc
+ * 
+ * Returns: a formatted string of max length @max in @s
+ */
+size_t modest_text_utils_strftime(char *s, size_t max, const char  *fmt, time_t timet);
+
+
+
+/**
+ * modest_text_utils_get_display_addres:
+ * @address: original address (UTF8 string)
+ *
+ * make a 'display address' from an address:
+ * "Foo Bar <foo@bar.cx> (Bla)" --> "Foo Bar"
+ * ie. removes "<...>" and "(...)" parts
+ * the change is in-place; removes leading/trailing whitespace
+ * 
+ * Returns: the new address. The string is *not* newly allocated.
+ * NULL in case of error
+ */
+gchar* modest_text_utils_get_display_address (gchar *address);
+
+
+/**
+ * modest_text_utils_get_subject_prefix_len:
+ * @subject: original subject (UTF8 string)
+ *
+ * determine the length of the "Re:/RE:/Fwd:" prefix in an e-mail address
+ * 
+ * Returns: the length of the  prefix, or 0 if there is none
+ */
+gint modest_text_utils_get_subject_prefix_len (const gchar *subject);
+
+
+/**
+ * modest_text_utils_utf8_strcmp:
+ * @s1: the first string
+ * @s2: the second string
+ * @insensitive: should the comparison be case-insensitive?
+ *
+ * a strcmp that is NULL-safe, can deal with UTF8 and case-insensitive comparison 
+ *
+ * Returns: an integer less than, equal to, or greater than zero if s1 is found,
+ * respectively, to be less than, to match, or be greater than s2.
+ */
+gint modest_text_utils_utf8_strcmp (const gchar* s1, const gchar *s2, gboolean insensitive);
+
+
+
+/**
+ * modest_text_utils_get_display_date:
+ * @date: the date to display
+ *
+ * get a string representation for a date.
+ * 
+ * Returns: the new display date, as a newly allocated string;
+ * free with g_free
+ */
+gchar* modest_text_utils_get_display_date (time_t date);
+
+
+/**
+ * modest_text_utils_get_display_size:
+ * @size: size in bytes
+ *
+ * get a string representation for a size in bytes.
+ * 
+ * Returns: the newly allocated display string for the
+ * size in bytes. must be freed.
+ */
+gchar * modest_text_utils_get_display_size (guint size);
+
+
+/**
+ * modest_text_utils_validate_email_address:
+ * @email_address: a string
+ * 
+ * validates the email address passed as argument
+ * 
+ * Returns: TRUE if the address is valid, FALSE otherwise
+ **/
+gboolean     modest_text_utils_validate_email_address (const gchar *email_address);
+
+/**
+ * modest_text_utils_split_addresses_list:
+ * @addresses: a string
+ *
+ * obtains a GSList of addresses from a string of addresses
+ * in the format understood by email protocols
+ *
+ * Returns: a GSList of strings
+ **/
+GSList      *modest_text_utils_split_addresses_list (const gchar *addresses);
+
+#endif /* __MODEST_TEXT_UTILS_H__ */
diff --git a/src/maemo/easysetup/modest-validating-entry.c b/src/maemo/easysetup/modest-validating-entry.c
new file mode 100644 (file)
index 0000000..79f2ea3
--- /dev/null
@@ -0,0 +1,205 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#include "modest-validating-entry.h"
+#include <gtk/gtksignal.h> /* For the gtk_signal_stop_emit_by_name() convenience function. */
+#include <string.h> /* For strlen(). */
+
+G_DEFINE_TYPE (EasysetupValidatingEntry, easysetup_validating_entry, GTK_TYPE_ENTRY);
+
+#define VALIDATING_ENTRY_GET_PRIVATE(o) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((o), EASYSETUP_TYPE_VALIDATING_ENTRY, EasysetupValidatingEntryPrivate))
+
+typedef struct _EasysetupValidatingEntryPrivate EasysetupValidatingEntryPrivate;
+
+struct _EasysetupValidatingEntryPrivate
+{
+       /* A list of gunichar, rather than char*,
+        * because gunichar is easier to deal with internally,
+        * but gchar* is easier to supply from the external interface.
+        */
+       GList *list_prevent;
+       
+       gboolean prevent_whitespace;
+};
+
+static void
+easysetup_validating_entry_get_property (GObject *object, guint property_id,
+                                                                                                                       GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_validating_entry_set_property (GObject *object, guint property_id,
+                                                                                                                       const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+easysetup_validating_entry_dispose (GObject *object)
+{
+       if (G_OBJECT_CLASS (easysetup_validating_entry_parent_class)->dispose)
+               G_OBJECT_CLASS (easysetup_validating_entry_parent_class)->dispose (object);
+}
+
+static void
+easysetup_validating_entry_finalize (GObject *object)
+{
+       EasysetupValidatingEntryPrivate *priv = VALIDATING_ENTRY_GET_PRIVATE (object);
+       
+       /* Free the list and its items: */
+       if (priv->list_prevent) {
+               g_list_foreach (priv->list_prevent, (GFunc)&g_free, NULL);
+               g_list_free (priv->list_prevent);
+       }
+       
+       G_OBJECT_CLASS (easysetup_validating_entry_parent_class)->finalize (object);
+}
+
+static void
+easysetup_validating_entry_class_init (EasysetupValidatingEntryClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (EasysetupValidatingEntryPrivate));
+
+       object_class->get_property = easysetup_validating_entry_get_property;
+       object_class->set_property = easysetup_validating_entry_set_property;
+       object_class->dispose = easysetup_validating_entry_dispose;
+       object_class->finalize = easysetup_validating_entry_finalize;
+}
+
+static gint
+on_list_compare(gconstpointer a, gconstpointer b)
+{
+       gunichar* unichar_a = (gunichar*)(a);
+       gunichar* unichar_b = (gunichar*)(b);
+       if(*unichar_a == *unichar_b)
+               return 0;
+       else
+               return -1; /* Really, we should return > and <, but we don't use this for sorting. */
+}
+                                             
+static void 
+on_insert_text(GtkEditable *editable,
+       gchar *new_text, gint new_text_length, 
+       gint *position,
+    gpointer user_data)
+{
+       EasysetupValidatingEntry *self = EASYSETUP_VALIDATING_ENTRY (user_data);
+       EasysetupValidatingEntryPrivate *priv = VALIDATING_ENTRY_GET_PRIVATE (self);
+       
+       if(!new_text_length)
+               return;
+               
+       /* Note: new_text_length is documented as the number of bytes, not characters. */
+       if(!g_utf8_validate (new_text, new_text_length, NULL))
+               return;
+       
+       /* Look at each UTF-8 character in the text (it could be several via a drop or a paste),
+        * and check them */
+       gboolean allow = TRUE;
+       gchar *iter = new_text; /* new_text seems to be NULL-terminated, though that is not documented. */
+       while (iter)
+       {
+               if(priv->list_prevent) {
+                       /* If the character is in our prevent list, 
+                        * then do not allow this text to be entered.
+                        * 
+                        * This prevents entry of all text, without removing the unwanted characters.
+                        * It is debatable whether that is the best thing to do.
+                        */
+                       gunichar one_char = g_utf8_get_char (iter);
+                       GList *found = g_list_find_custom(priv->list_prevent, &one_char, &on_list_compare);
+                       if(found) {
+                               allow = FALSE;
+                               break;
+                       }       
+               }
+               
+               if(priv->prevent_whitespace) {
+                       /* Check for whitespace characters: */
+                       gunichar one_char = g_utf8_get_char (iter);
+                       if (g_unichar_isspace (one_char)) {
+                               allow = FALSE;
+                               break;
+                       }
+               }
+
+               /* Crashes. Don't know why: iter = g_utf8_next_char (iter); 
+                * Maybe it doesn't check for null-termination. */      
+               iter = g_utf8_find_next_char (iter, new_text + new_text_length);
+       }
+       
+       if(!allow) {
+               /* The signal documentation says 
+                * "by connecting to this signal and then stopping the signal with 
+                * gtk_signal_emit_stop(), it is possible to modify the inserted text, 
+                * or prevent it from being inserted entirely."
+                */
+                gtk_signal_emit_stop_by_name (GTK_OBJECT (self), "insert-text");
+       }
+} 
+                                            
+static void
+easysetup_validating_entry_init (EasysetupValidatingEntry *self)
+{
+       /* Connect to the GtkEditable::insert-text signal 
+        * so we can filter out some characters:
+        * We connect _before_ so we can stop the default signal handler from running.
+        */
+       g_signal_connect (G_OBJECT (self), "insert-text", (GCallback)&on_insert_text, self);
+}
+
+EasysetupValidatingEntry*
+easysetup_validating_entry_new (void)
+{
+       return g_object_new (EASYSETUP_TYPE_VALIDATING_ENTRY, NULL);
+}
+
+/** Specify characters that may not be entered into this GtkEntry.
+ *  
+ * list: A list of gchar* strings. Each one identifies a UTF-8 character.
+ */
+void easysetup_validating_entry_set_unallowed_characters (EasysetupValidatingEntry *self, GList *list)
+{
+       EasysetupValidatingEntryPrivate *priv = VALIDATING_ENTRY_GET_PRIVATE (self);
+           
+       /* Free the list and its items: */      
+       if (priv->list_prevent) {
+               g_list_foreach (priv->list_prevent, (GFunc)&g_free, NULL);
+               g_list_free (priv->list_prevent);
+       }
+     
+    /* Do a deep copy of the list, converting gchar* to gunichar: */
+    priv->list_prevent = NULL;
+    GList *iter = NULL;               
+    for (iter = list; iter != NULL; iter = iter->next) {
+       gunichar *one_char = g_new0 (gunichar, 1);
+       if(iter->data)
+               *one_char = g_utf8_get_char ((gchar*)iter->data);
+       else
+               *one_char = 0;
+               
+       priv->list_prevent = g_list_append (priv->list_prevent, one_char);      
+    }
+}
+
+/** Specify that no whitespace characters may be entered into this GtkEntry.
+ *  
+ */
+void easysetup_validating_entry_set_unallowed_characters_whitespace (EasysetupValidatingEntry *self)
+{
+       EasysetupValidatingEntryPrivate *priv = VALIDATING_ENTRY_GET_PRIVATE (self);
+       priv->prevent_whitespace = TRUE;
+}
diff --git a/src/maemo/easysetup/modest-validating-entry.h b/src/maemo/easysetup/modest-validating-entry.h
new file mode 100644 (file)
index 0000000..e442841
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (c) 2007, Nokia Corporation
+ * All rights reserved.
+ *
+ */
+
+#ifndef _EASYSETUP_VALIDATING_ENTRY
+#define _EASYSETUP_VALIDATING_ENTRY
+
+#include <gtk/gtkentry.h>
+
+G_BEGIN_DECLS
+
+#define EASYSETUP_TYPE_VALIDATING_ENTRY easysetup_validating_entry_get_type()
+
+#define EASYSETUP_VALIDATING_ENTRY(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       EASYSETUP_TYPE_VALIDATING_ENTRY, EasysetupValidatingEntry))
+
+#define EASYSETUP_VALIDATING_ENTRY_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_CAST ((klass), \
+       EASYSETUP_TYPE_VALIDATING_ENTRY, EasysetupValidatingEntryClass))
+
+#define EASYSETUP_IS_VALIDATING_ENTRY(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       EASYSETUP_TYPE_VALIDATING_ENTRY))
+
+#define EASYSETUP_IS_VALIDATING_ENTRY_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       EASYSETUP_TYPE_VALIDATING_ENTRY))
+
+#define EASYSETUP_VALIDATING_ENTRY_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       EASYSETUP_TYPE_VALIDATING_ENTRY, EasysetupValidatingEntryClass))
+
+typedef struct {
+       GtkEntry parent;
+} EasysetupValidatingEntry;
+
+typedef struct {
+       GtkEntryClass parent_class;
+} EasysetupValidatingEntryClass;
+
+GType easysetup_validating_entry_get_type (void);
+
+EasysetupValidatingEntry* easysetup_validating_entry_new (void);
+
+void easysetup_validating_entry_set_unallowed_characters (EasysetupValidatingEntry *self, GList *list);
+void easysetup_validating_entry_set_unallowed_characters_whitespace (EasysetupValidatingEntry *self);
+
+G_END_DECLS
+
+#endif /* _EASYSETUP_VALIDATING_ENTRY */
diff --git a/src/maemo/easysetup/modest-wizard-dialog.c b/src/maemo/easysetup/modest-wizard-dialog.c
new file mode 100644 (file)
index 0000000..5283e61
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * This is a copy of modest-wizard-dialog.h with a rename and some API additions,
+ * for osso-modest-easysetup.
+ * 
+ * This file was part of modest-libs
+ *
+ * Copyright (C) 2005, 2006, 2007 Nokia Corporation, all rights reserved.
+ *
+ */
+/**
+ * SECTION:modest-wizard-dialog
+ * @short_description: A widget to create a guided installation
+ * process wizard
+ *
+ * #ModestWizardDialog is a widget to create a guided installation
+ * process. The dialog has four standard buttons, previous, next,
+ * finish, cancel, and contains several pages with optional icons.
+ * Response buttons are dimmed/undimmed automatically and the standard
+ * icon is shown/hidden in response to page navigation. The notebook
+ * widget provided by users contains the actual wizard pages.
+ */
+
+#include <gtk/gtkdialog.h>
+#include <gtk/gtknotebook.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkbox.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkbutton.h>
+#include <hildon-widgets/hildon-defines.h>
+
+#include "modest-wizard-dialog.h"
+
+#include <libintl.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* Specify the hildon-libs translation domain,
+ * so we can reuse its translations 
+ * instead of repeating them in our own translations.
+ */
+/* #define _(String) dgettext(PACKAGE, String) */
+
+#define _(String) dgettext("hildon-libs", String)
+
+static GtkDialogClass *parent_class;
+
+static void class_init              (ModestWizardDialogClass   *wizard_dialog_class);
+
+static void init                    (ModestWizardDialog        *wizard_dialog);
+
+static void create_title            (ModestWizardDialog        *wizard_dialog);
+
+static void set_property            (GObject                   *object,
+                                     guint                     property_id,
+                                     const GValue              *value,
+                                     GParamSpec                *pspec);
+
+static void get_property            (GObject                   *object,
+                                     guint                     property_id,
+                                     GValue                    *value,
+                                     GParamSpec                *pspec);
+
+static void finalize                (GObject                   *object);
+
+static void response                (ModestWizardDialog        *wizard, 
+                                     gint                      response_id,
+                                     gpointer                  unused);
+
+static void make_buttons_sensitive  (ModestWizardDialog *wizard_dialog,
+                                     gboolean           previous,
+                                     gboolean           finish,
+                                     gboolean next);
+                                     
+static gboolean invoke_before_next_vfunc (ModestWizardDialog *wizard_dialog);
+static void invoke_enable_buttons_vfunc (ModestWizardDialog *wizard_dialog);
+
+enum {
+    PROP_ZERO,
+    PROP_WIZARD_NAME,
+    PROP_WIZARD_NOTEBOOK,
+    PROP_WIZARD_AUTOTITLE
+};
+
+struct _ModestWizardDialogPrivate {
+    gchar       *wizard_name;
+    GtkNotebook *notebook;
+    GtkBox      *box;
+    GtkWidget   *image;
+    gboolean    autotitle;
+};
+
+
+GType
+modest_wizard_dialog_get_type (void)
+{
+    static GType wizard_dialog_type = 0;
+
+    if (!wizard_dialog_type) {
+
+        static const GTypeInfo wizard_dialog_info = {
+            sizeof (ModestWizardDialogClass),
+            NULL,       /* base_init      */
+            NULL,       /* base_finalize  */
+            (GClassInitFunc) class_init,
+            NULL,       /* class_finalize */
+            NULL,       /* class_data     */
+            sizeof (ModestWizardDialog),
+            0,          /* n_preallocs    */
+            (GInstanceInitFunc) init,
+        };
+
+        wizard_dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
+                                                     "ModestWizardDialog",
+                                                     &wizard_dialog_info,
+                                                     0);
+    }
+
+    return wizard_dialog_type;
+}
+
+static void
+class_init (ModestWizardDialogClass *wizard_dialog_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (wizard_dialog_class);
+
+    parent_class = g_type_class_peek_parent (wizard_dialog_class);
+
+    g_type_class_add_private (wizard_dialog_class,
+                              sizeof(ModestWizardDialogPrivate));
+
+    /* Override virtual methods */
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+    object_class->finalize     = finalize;
+
+    /**
+     * ModestWizardDialog:wizard-name:
+     *
+     * The name of the wizard.
+     */
+    g_object_class_install_property (object_class, PROP_WIZARD_NAME,
+            g_param_spec_string 
+            ("wizard-name",
+             "Wizard Name",
+             "The name of the ModestWizardDialog",
+             NULL,
+             G_PARAM_READWRITE));
+
+    /**
+     * ModestWizardDialog:wizard-notebook:
+     *
+     * The notebook object, which is used by the ModestWizardDialog.
+     */
+    g_object_class_install_property(object_class, PROP_WIZARD_NOTEBOOK,
+            g_param_spec_object 
+            ("wizard-notebook",
+             "Wizard Notebook",
+             "GtkNotebook object to be used in the "
+             "ModestWizardDialog",
+             GTK_TYPE_NOTEBOOK, G_PARAM_READWRITE));
+
+    /**
+     * ModestWizardDialog:autotitle
+     *
+     * If the wizard should automatically try to change the window title when changing steps. 
+     * Set to FALSE if you'd like to override the default behaviour. 
+     *
+     * Since: 0.14.5 
+     */
+    g_object_class_install_property(object_class, PROP_WIZARD_AUTOTITLE,
+            g_param_spec_boolean 
+            ("autotitle",
+             "AutoTitle",
+             "If the wizard should autotitle itself",
+             TRUE, 
+             G_PARAM_READWRITE));
+}
+
+static void 
+finalize (GObject *object)
+{
+    ModestWizardDialog *dialog = MODEST_WIZARD_DIALOG (object);
+    g_return_if_fail (dialog != NULL);
+
+    if (dialog->priv->wizard_name != NULL)
+        g_free (MODEST_WIZARD_DIALOG (object)->priv->wizard_name);
+    
+    if (G_OBJECT_CLASS (parent_class)->finalize)
+        G_OBJECT_CLASS (parent_class)->finalize(object);
+}
+
+/* Disable or enable the Previous, Next and Finish buttons */
+static void
+make_buttons_sensitive (ModestWizardDialog *wizard_dialog,
+                        gboolean previous,
+                        gboolean finish,
+                        gboolean next)
+{
+    gtk_dialog_set_response_sensitive (GTK_DIALOG (wizard_dialog),
+                                       MODEST_WIZARD_DIALOG_PREVIOUS,
+                                       previous);
+
+    gtk_dialog_set_response_sensitive (GTK_DIALOG (wizard_dialog),
+                                       MODEST_WIZARD_DIALOG_FINISH,
+                                       finish);
+
+    gtk_dialog_set_response_sensitive (GTK_DIALOG (wizard_dialog),
+                                       MODEST_WIZARD_DIALOG_NEXT,
+                                       next);
+}
+
+static void 
+init (ModestWizardDialog *wizard_dialog)
+{
+    /* Initialize private structure for faster member access */
+    ModestWizardDialogPrivate *priv =
+        G_TYPE_INSTANCE_GET_PRIVATE (wizard_dialog,
+                MODEST_TYPE_WIZARD_DIALOG,
+                ModestWizardDialogPrivate);
+
+    GtkDialog *dialog = GTK_DIALOG (wizard_dialog);
+
+    /* Init internal widgets */
+    GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
+    gtk_dialog_set_has_separator (dialog, FALSE);
+    wizard_dialog->priv = priv;
+    priv->box = GTK_BOX (gtk_hbox_new (FALSE, 0));
+    priv->image = gtk_image_new_from_icon_name ("qgn_widg_wizard",
+            HILDON_ICON_SIZE_WIDG_WIZARD);
+
+    /* Default values for user provided properties */
+    priv->notebook = NULL;
+    priv->wizard_name = NULL;
+    priv->autotitle = TRUE;
+
+    /* Build wizard layout */
+    gtk_box_pack_start_defaults (GTK_BOX (dialog->vbox), GTK_WIDGET (priv->box));
+    gtk_box_pack_start_defaults (GTK_BOX (priv->box), GTK_WIDGET (vbox));
+    gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (priv->image), FALSE, FALSE, 0);
+
+    /* Add response buttons: finish, previous, next, cancel */
+    gtk_dialog_add_button (dialog, _("ecdg_bd_wizard_finish"), MODEST_WIZARD_DIALOG_FINISH);
+    gtk_dialog_add_button (dialog, _("ecdg_bd_wizard_previous"), MODEST_WIZARD_DIALOG_PREVIOUS);
+    gtk_dialog_add_button (dialog, _("ecdg_bd_wizard_next"), MODEST_WIZARD_DIALOG_NEXT);
+    gtk_dialog_add_button (dialog, _("ecdg_bd_wizard_cancel"), MODEST_WIZARD_DIALOG_CANCEL);
+
+    /* Set initial button states: previous and finish buttons are disabled */
+    make_buttons_sensitive (wizard_dialog, FALSE, FALSE, TRUE);
+
+    /* Show all the internal widgets */
+    gtk_widget_show_all (GTK_WIDGET (dialog->vbox));
+
+    /* connect to dialog's response signal */
+    g_signal_connect (G_OBJECT (dialog), "response",
+            G_CALLBACK (response), NULL);
+}
+
+static void
+set_property (GObject      *object, 
+              guint        property_id,
+              const GValue *value, 
+              GParamSpec   *pspec)
+{
+    ModestWizardDialogPrivate *priv = MODEST_WIZARD_DIALOG(object)->priv;
+
+    switch (property_id) {
+
+        case PROP_WIZARD_AUTOTITLE:
+
+            priv->autotitle = g_value_get_boolean (value);
+
+            if (priv->autotitle && 
+                priv->wizard_name && 
+                priv->notebook)
+                create_title (MODEST_WIZARD_DIALOG (object));
+            else if (priv->wizard_name)
+                gtk_window_set_title (GTK_WINDOW (object), priv->wizard_name);
+            
+            break;
+
+        case PROP_WIZARD_NAME: 
+
+            /* Set new wizard name. This name will appear in titlebar */
+            if (priv->wizard_name)
+                g_free (priv->wizard_name);
+
+            gchar *str = (gchar *) g_value_get_string (value);
+            g_return_if_fail (str != NULL);
+
+            priv->wizard_name = g_strdup (str);
+
+            /* We need notebook in order to create title, since page information
+               is used in title generation */
+            
+            if (priv->notebook && priv->autotitle)
+                create_title (MODEST_WIZARD_DIALOG (object));
+    
+            break;
+
+        case PROP_WIZARD_NOTEBOOK: {
+
+            GtkNotebook *book = GTK_NOTEBOOK (g_value_get_object (value));
+            g_return_if_fail (book != NULL);
+
+            priv->notebook = book;
+
+            /* Set the default properties for the notebook (disable tabs,
+             * and remove borders) to make it look like a nice wizard widget */
+            gtk_notebook_set_show_tabs (priv->notebook, FALSE);
+            gtk_notebook_set_show_border (priv->notebook, FALSE);
+            gtk_box_pack_start_defaults (GTK_BOX( priv->box), GTK_WIDGET (priv->notebook));
+
+            /* Show the notebook so that a gtk_widget_show on the dialog is
+             * all that is required to display the dialog correctly */
+            gtk_widget_show ( GTK_WIDGET (priv->notebook));
+
+            /* Update dialog title to reflect current page stats etc */        
+            if (priv->wizard_name && priv->autotitle)
+                create_title (MODEST_WIZARD_DIALOG (object));
+            
+            } break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+            break;
+    }
+}
+
+static void
+get_property (GObject      *object,
+              guint        property_id,
+              GValue       *value,
+              GParamSpec   *pspec)
+{
+    ModestWizardDialogPrivate *priv = MODEST_WIZARD_DIALOG (object)->priv;
+
+    switch (property_id) {
+
+        case PROP_WIZARD_NAME:
+            g_value_set_string (value, priv->wizard_name);
+            break;
+
+        case PROP_WIZARD_NOTEBOOK:
+            g_value_set_object (value, priv->notebook);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+            break;
+    }
+}
+
+/*
+ * Creates the title of the dialog taking into account the current 
+ * page of the notebook.
+ */
+static void
+create_title (ModestWizardDialog *wizard_dialog)
+{
+    gint pages, current;
+    gchar *str = NULL;
+    ModestWizardDialogPrivate *priv = wizard_dialog->priv;
+    GtkNotebook *notebook = priv->notebook;
+
+    if (!notebook)
+        return;
+
+    /* Get page information, we'll need that when creating title */
+    pages = gtk_notebook_get_n_pages (notebook);
+    current = gtk_notebook_get_current_page (priv->notebook);
+    if (current < 0)
+        current = 0;
+
+    /* the welcome title on the initial page */
+    if (current == 0) {
+        str = g_strdup_printf (_("ecdg_ti_wizard_welcome"), 
+                priv->wizard_name, pages);
+    } else {
+        const gchar *steps = gtk_notebook_get_tab_label_text (notebook,
+                gtk_notebook_get_nth_page (notebook, current));
+
+        str = g_strdup_printf (_("ecdg_ti_wizard_step"), 
+                priv->wizard_name, current + 1, pages, steps);
+    }
+
+    /* Update the dialog to display the generated title */
+    gtk_window_set_title (GTK_WINDOW (wizard_dialog), str);
+    g_free (str);
+}
+
+/*
+ * Response signal handler. This function is needed because GtkDialog's 
+ * handler for this signal closes the dialog and we don't want that, we 
+ * want to change pages and, dimm certain response buttons. Overriding the 
+ * virtual function would not work because that would be called after the 
+ * signal handler implemented by GtkDialog.
+ * FIXME: There is a much saner way to do that [MDK]
+ */
+static void 
+response (ModestWizardDialog   *wizard_dialog,
+          gint                 response_id,
+          gpointer             unused)
+{
+    ModestWizardDialogPrivate *priv = wizard_dialog->priv;
+    GtkNotebook *notebook = priv->notebook;
+    gint current = 0;
+    gboolean is_first, is_last;
+    
+    switch (response_id) {
+        
+        case MODEST_WIZARD_DIALOG_PREVIOUS:
+            gtk_notebook_prev_page (notebook); /* go to previous page */
+            break;
+
+        case MODEST_WIZARD_DIALOG_NEXT:
+               if (invoke_before_next_vfunc (wizard_dialog))
+               gtk_notebook_next_page (notebook); /* go to next page */
+               
+            break;
+
+        case MODEST_WIZARD_DIALOG_CANCEL:
+               return;
+               break;      
+        case MODEST_WIZARD_DIALOG_FINISH:
+               if (invoke_before_next_vfunc (wizard_dialog))
+               return;
+            
+            break;
+
+    }
+
+    current = gtk_notebook_get_current_page (notebook);
+    gint last = gtk_notebook_get_n_pages (notebook) - 1;
+    is_last = current == last;
+    is_first = current == 0;
+    
+    /* If first page, previous and finish are disabled, 
+       if last page, next is disabled */
+    make_buttons_sensitive (wizard_dialog,
+            !is_first /* previous */, !is_first /* finish */, !is_last /* next*/);
+            
+    /* Allow derived classes to disable buttons to prevent navigation,
+     * according to their own validation logic: */
+    invoke_enable_buttons_vfunc (wizard_dialog);
+    
+    /* Don't let the dialog close */
+    g_signal_stop_emission_by_name (wizard_dialog, "response");
+
+    /* We show the default image on first and last pages */
+    last = gtk_notebook_get_n_pages (notebook) - 1;
+    if (current == last || current == 0)
+        gtk_widget_show (GTK_WIDGET(priv->image));
+    else
+        gtk_widget_hide (GTK_WIDGET(priv->image));
+
+    /* New page number may appear in the title, update it */
+    if (priv->autotitle) 
+        create_title (wizard_dialog);
+}
+
+/**
+ * modest_wizard_dialog_new:
+ * @parent: a #GtkWindow
+ * @wizard_name: the name of dialog
+ * @notebook: the notebook to be shown on the dialog
+ *
+ * Creates a new #ModestWizardDialog.
+ *
+ * Returns: a new #ModestWizardDialog
+ */
+GtkWidget*
+modest_wizard_dialog_new (GtkWindow   *parent,
+                          const char  *wizard_name,
+                          GtkNotebook *notebook)
+{
+    GtkWidget *widget;
+
+    g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
+
+    widget = GTK_WIDGET (g_object_new
+            (MODEST_TYPE_WIZARD_DIALOG,
+             "wizard-name", wizard_name,
+             "wizard-notebook", notebook, NULL));
+
+    if (parent)
+        gtk_window_set_transient_for (GTK_WINDOW (widget), parent);
+
+    return widget;
+}
+
+static gboolean
+invoke_before_next_vfunc (ModestWizardDialog *wizard_dialog)
+{
+       ModestWizardDialogClass *klass = MODEST_WIZARD_DIALOG_GET_CLASS (wizard_dialog);
+       
+       /* Call the vfunc, which may be overridden by derived classes: */
+       if (klass->before_next) {
+               ModestWizardDialogPrivate *priv = MODEST_WIZARD_DIALOG(wizard_dialog)->priv;
+       
+               gint current_page_num = gtk_notebook_get_current_page (priv->notebook);
+               
+               /* Get widgets for the two pages: */
+               GtkWidget* current_page_widget = gtk_notebook_get_nth_page (priv->notebook, current_page_num);
+               
+               GtkWidget* next_page_widget = NULL;
+               if ((current_page_num + 1) < gtk_notebook_get_n_pages (priv->notebook))
+                       next_page_widget = gtk_notebook_get_nth_page (priv->notebook, current_page_num + 1);
+               
+               /* Ask the vfunc implementation whether navigation should be allowed: */
+               return (*(klass->before_next))(wizard_dialog, current_page_widget, next_page_widget);
+       }
+       
+       /* Allow navigation by default if there is no vfunc implementation: */
+       return TRUE;
+}
+
+static void
+invoke_enable_buttons_vfunc (ModestWizardDialog *wizard_dialog)
+{
+       ModestWizardDialogClass *klass = MODEST_WIZARD_DIALOG_GET_CLASS (wizard_dialog);
+       
+       /* Call the vfunc, which may be overridden by derived classes: */
+       if (klass->enable_buttons) {
+               ModestWizardDialogPrivate *priv = MODEST_WIZARD_DIALOG(wizard_dialog)->priv;
+       
+               gint current_page_num = gtk_notebook_get_current_page (priv->notebook);
+               
+               GtkWidget* current_page_widget = gtk_notebook_get_nth_page (priv->notebook, current_page_num);
+                       
+               (*(klass->enable_buttons))(wizard_dialog, current_page_widget);
+       }
+}
diff --git a/src/maemo/easysetup/modest-wizard-dialog.h b/src/maemo/easysetup/modest-wizard-dialog.h
new file mode 100644 (file)
index 0000000..772e97e
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * This is a copy of modest-wizard-dialog.h with a rename and some API additions,
+ * for osso-modest-easysetup.
+ * 
+ * This file was part of modest-libs
+ *
+ * Copyright (C) 2005, 2006, 2007 Nokia Corporation, all rights reserved.
+ *
+ */
+#ifndef __MODEST_WIZARD_DIALOG_H__
+#define __MODEST_WIZARD_DIALOG_H__
+
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtknotebook.h>
+#include <gtk/gtkdialog.h>
+
+G_BEGIN_DECLS
+
+#define MODEST_TYPE_WIZARD_DIALOG (modest_wizard_dialog_get_type())
+
+#define MODEST_WIZARD_DIALOG(obj) (GTK_CHECK_CAST ((obj), \
+            MODEST_TYPE_WIZARD_DIALOG, ModestWizardDialog))
+
+#define MODEST_WIZARD_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), \
+            MODEST_TYPE_WIZARD_DIALOG, ModestWizardDialogClass))
+
+#define MODEST_IS_WIZARD_DIALOG(obj) (GTK_CHECK_TYPE ((obj), \
+            MODEST_TYPE_WIZARD_DIALOG))
+
+#define MODEST_IS_WIZARD_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), \
+            MODEST_TYPE_WIZARD_DIALOG))
+            
+#define MODEST_WIZARD_DIALOG_GET_CLASS(obj) \
+            (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+            MODEST_TYPE_WIZARD_DIALOG, ModestWizardDialogClass))
+
+typedef struct _ModestWizardDialog ModestWizardDialog;
+
+typedef struct _ModestWizardDialogClass ModestWizardDialogClass;
+
+typedef struct _ModestWizardDialogPrivate ModestWizardDialogPrivate;
+
+/* button response IDs */
+enum {
+    MODEST_WIZARD_DIALOG_CANCEL = GTK_RESPONSE_CANCEL,
+    MODEST_WIZARD_DIALOG_PREVIOUS = 0,
+    MODEST_WIZARD_DIALOG_NEXT,
+    MODEST_WIZARD_DIALOG_FINISH
+};
+
+struct _ModestWizardDialog {
+    GtkDialog                   parent;
+    ModestWizardDialogPrivate   *priv;
+};
+
+struct _ModestWizardDialogClass {
+    GtkDialogClass          parent_class;
+    
+       /** Implementations of this vfunc should prepare the next page if necessary, 
+        * and only return TRUE if the navigation should be allowed.
+        * You may even change the next page, via the GtkNotebook API, in the signal handler. */
+       gboolean (* before_next) (ModestWizardDialog *dialog, GtkWidget *current_page, GtkWidget *next_page);
+
+       /** Implementations of this vfunc should enable or disable 
+        * the next/forward buttons appropriately, based on the entered data. */
+       void (* enable_buttons) (ModestWizardDialog *dialog, GtkWidget *current_page);
+
+
+    void (*_gtk_reserved2)  (void);
+    void (*_gtk_reserved3)  (void);
+    void (*_gtk_reserved4)  (void);
+};
+
+
+GType modest_wizard_dialog_get_type   (void) G_GNUC_CONST;
+
+GtkWidget* modest_wizard_dialog_new   (GtkWindow        *parent,
+                                       const char       *wizard_name,
+                                       GtkNotebook      *notebook);
+
+G_END_DECLS
+
+#endif /* __MODEST_WIZARD_DIALOG_H__ */
diff --git a/src/maemo/easysetup/osso_countries_1.0.mo b/src/maemo/easysetup/osso_countries_1.0.mo
new file mode 100644 (file)
index 0000000..a0a427b
Binary files /dev/null and b/src/maemo/easysetup/osso_countries_1.0.mo differ
diff --git a/src/maemo/easysetup/osso_countries_1.0.po b/src/maemo/easysetup/osso_countries_1.0.po
new file mode 100644 (file)
index 0000000..e0965c2
--- /dev/null
@@ -0,0 +1,906 @@
+# Copyright (C) 2006 Nokia Corporation.
+# This file is distributed under the same license as the modest package
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: osso_countries-0.1\n"
+"Report-Msgid-Bugs-To: dirk-jan.binnema@nokia.com\n"
+"POT-Creation-Date: 2007.01.02 11:34+0200\n"
+"PO-Revision-Date: 2007.01.02 11:34+0200\n"
+"Last-Translator:\n"
+"Language-Team: en_GB\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"\r\r\r
+msgid "osso_db_country_afghanistan"
+msgstr "Afghanistan"
+
+# \r
+msgid "osso_db_country_albania"
+msgstr "Albania"
+
+# \r
+msgid "osso_db_country_algeria"
+msgstr "Algeria"
+
+# \r
+msgid "osso_db_country_american_samoa"
+msgstr "American Samoa"
+
+# \r
+msgid "osso_db_country_andorra"
+msgstr "Andorra"
+
+# \r
+msgid "osso_db_country_angola"
+msgstr "Angola"
+
+# \r
+msgid "osso_db_country_anguilla"
+msgstr "Anguilla"
+
+# \r
+msgid "osso_db_country_antigua_and_barbuda"
+msgstr "Antigua and Barbuda"
+
+# \r
+msgid "osso_db_country_argentina"
+msgstr "Argentine Republic"
+
+# \r
+msgid "osso_db_country_armenia"
+msgstr "Armenia"
+
+# \r
+msgid "osso_db_country_aruba"
+msgstr "Aruba"
+
+# \r
+msgid "osso_db_country_australia"
+msgstr "Australia"
+
+# \r
+msgid "osso_db_country_austria"
+msgstr "Austria"
+
+# \r
+msgid "osso_db_country_azerbaijani_republic"
+msgstr "Azerbaijani Republic"
+
+# \r
+msgid "osso_db_country_bahamas"
+msgstr "Bahamas"
+
+# \r
+msgid "osso_db_country_bahrain"
+msgstr "Bahrain"
+
+# \r
+msgid "osso_db_country_bangladesh"
+msgstr "Bangladesh"
+
+# \r
+msgid "osso_db_country_barbados"
+msgstr "Barbados"
+
+# \r
+msgid "osso_db_country_belarus"
+msgstr "Belarus"
+
+# \r
+msgid "osso_db_country_belgium"
+msgstr "Belgium"
+
+# \r
+msgid "osso_db_country_belize"
+msgstr "Belize"
+
+# \r
+msgid "osso_db_country_benin"
+msgstr "Benin"
+
+# \r
+msgid "osso_db_country_bermuda"
+msgstr "Bermuda"
+
+# \r
+msgid "osso_db_country_bhutan"
+msgstr "Bhutan"
+
+# \r
+msgid "osso_db_country_bolivia"
+msgstr "Bolivia"
+
+# \r
+msgid "osso_db_country_bosnia_and_herzegovina"
+msgstr "Bosnia and Herzegovina"
+
+# \r
+msgid "osso_db_country_botswana"
+msgstr "Botswana"
+
+# \r
+msgid "osso_db_country_brazil"
+msgstr "Brazil"
+
+# \r
+msgid "osso_db_country_british_virgin_islands"
+msgstr "British Virgin Islands"
+
+# \r
+msgid "osso_db_country_brunei_darussalam"
+msgstr "Brunei Darussalam"
+
+# \r
+msgid "osso_db_country_bulgaria"
+msgstr "Bulgaria"
+
+# \r
+msgid "osso_db_country_burkina_faso"
+msgstr "Burkina Faso"
+
+# \r
+msgid "osso_db_country_burundi"
+msgstr "Burundi"
+
+# \r
+msgid "osso_db_country_cambodia"
+msgstr "Cambodia"
+
+# \r
+msgid "osso_db_country_cameroon"
+msgstr "Cameroon"
+
+# \r
+msgid "osso_db_country_canada"
+msgstr "Canada"
+
+# \r
+msgid "osso_db_country_canary_islands_spain"
+msgstr "Canary Islands (Spain)"
+
+# \r
+msgid "osso_db_country_cape_verde"
+msgstr "Cape Verde"
+
+# \r
+msgid "osso_db_country_cayman_islands"
+msgstr "Cayman Islands"
+
+# \r
+msgid "osso_db_country_central_african_republic"
+msgstr "Central African Republic"
+
+# \r
+msgid "osso_db_country_chad"
+msgstr "Chad"
+
+# \r
+msgid "osso_db_country_chile"
+msgstr "Chile"
+
+# \r
+msgid "osso_db_country_china"
+msgstr "China"
+
+# \r
+msgid "osso_db_country_colombia"
+msgstr "Colombia"
+
+# \r
+msgid "osso_db_country_comoros"
+msgstr "Comoros"
+
+# \r
+msgid "osso_db_country_republic_of_the_congo"
+msgstr "Republic of the Congo"
+
+# \r
+msgid "osso_db_country_cook_islands"
+msgstr "Cook Islands"
+
+# \r
+msgid "osso_db_country_costa_rica"
+msgstr "Costa Rica"
+
+# \r
+msgid "osso_db_country_cote_dlvoire"
+msgstr "Cote d'Ivoire"
+
+# \r
+msgid "osso_db_country_croatia"
+msgstr "Croatia"
+
+# \r
+msgid "osso_db_country_cuba"
+msgstr "Cuba"
+
+# \r
+msgid "osso_db_country_cyprus"
+msgstr "Cyprus"
+
+# \r
+msgid "osso_db_country_czech_republic"
+msgstr "Czech Republic"
+
+# \r
+msgid "osso_db_country_democratic_republic_of_the_congo"
+msgstr "Democratic Republic of the Congo"
+
+# \r
+msgid "osso_db_country_denmark"
+msgstr "Denmark"
+
+# \r
+msgid "osso_db_country_djibouti"
+msgstr "Djibouti"
+
+# \r
+msgid "osso_db_country_dominica"
+msgstr "Dominica"
+
+# \r
+msgid "osso_db_country_dominican_republic"
+msgstr "Dominican Republic"
+
+# \r
+msgid "osso_db_country_east_timor"
+msgstr "East Timor"
+
+# \r
+msgid "osso_db_country_ecuador"
+msgstr "Ecuador"
+
+# \r
+msgid "osso_db_country_egypt"
+msgstr "Egypt"
+
+# \r
+msgid "osso_db_country_el_salvador"
+msgstr "El Salvador"
+
+# \r
+msgid "osso_db_country_equatorial_guinea"
+msgstr "Equatorial Guinea"
+
+# \r
+msgid "osso_db_country_eritrea"
+msgstr "Eritrea"
+
+# \r
+msgid "osso_db_country_estonia"
+msgstr "Estonia"
+
+# \r
+msgid "osso_db_country_ethiopia"
+msgstr "Ethiopia"
+
+# \r
+msgid "osso_db_country_faroe_islands"
+msgstr "Faroe Islands"
+
+# \r
+msgid "osso_db_country_fiji"
+msgstr "Fiji"
+
+# \r
+msgid "osso_db_country_finland"
+msgstr "Finland"
+
+# \r
+msgid "osso_db_country_france"
+msgstr "France"
+
+# \r
+msgid "osso_db_country_french_guiana"
+msgstr "French Guiana"
+
+# \r
+msgid "osso_db_country_french_polynesia"
+msgstr "French Polynesia"
+
+# \r
+msgid "osso_db_country_gobonese_republic"
+msgstr "Gabonese Republic"
+
+# \r
+msgid "osso_db_country_gambia"
+msgstr "Gambia"
+
+# \r
+msgid "osso_db_country_georgia"
+msgstr "Georgia"
+
+# \r
+msgid "osso_db_country_germany"
+msgstr "Germany"
+
+# \r
+msgid "osso_db_country_ghana"
+msgstr "Ghana"
+
+# \r
+msgid "osso_db_country_gibraltar"
+msgstr "Gibraltar"
+
+# \r
+msgid "osso_db_country_greece"
+msgstr "Greece"
+
+# \r
+msgid "osso_db_country_greenland"
+msgstr "Greenland"
+
+# \r
+msgid "osso_db_country_hong_kong"
+msgstr "Hong Kong, China"
+
+# \r
+msgid "osso_db_country_grenada"
+msgstr "Grenada"
+
+# \r
+msgid "osso_db_country_guadeloupe"
+msgstr "Guadeloupe"
+
+# \r
+msgid "osso_db_country_guam"
+msgstr "Guam"
+
+# \r
+msgid "osso_db_country_guatemala"
+msgstr "Guatemala"
+
+# \r
+msgid "osso_db_country_guinea"
+msgstr "Guinea"
+
+# \r
+msgid "osso_db_country_guinea_bissaus"
+msgstr "Guinea-Bissau"
+
+# \r
+msgid "osso_db_country_guyana"
+msgstr "Guyana"
+
+# \r
+msgid "osso_db_country_haiti"
+msgstr "Haiti"
+
+# \r
+msgid "osso_db_country_honduras"
+msgstr "Honduras"
+
+# \r
+msgid "osso_db_country_hungary"
+msgstr "Hungary"
+
+# \r
+msgid "osso_db_country_iceland"
+msgstr "Iceland"
+
+# \r
+msgid "osso_db_country_india"
+msgstr "India"
+
+# \r
+msgid "osso_db_country_indonesia"
+msgstr "Indonesia"
+
+# \r
+msgid "osso_db_country_iran"
+msgstr "Iran"
+
+# \r
+msgid "osso_db_country_iraq"
+msgstr "Iraq"
+
+# \r
+msgid "osso_db_country_republic_of_ireland"
+msgstr "Ireland"
+
+# \r
+msgid "osso_db_country_israel"
+msgstr "Israel"
+
+# \r
+msgid "osso_db_country_italy"
+msgstr "Italy"
+
+# \r
+msgid "osso_db_country_jamaica"
+msgstr "Jamaica"
+
+# \r
+msgid "osso_db_country_japan"
+msgstr "Japan"
+
+# \r
+msgid "osso_db_country_jordan"
+msgstr "Jordan"
+
+# \r
+msgid "osso_db_country_kazakhstan"
+msgstr "Kazakhstan"
+
+# \r
+msgid "osso_db_country_kenya"
+msgstr "Kenya"
+
+# \r
+msgid "osso_db_country_kiribati"
+msgstr "Kiribati"
+
+# \r
+msgid "osso_db_country_korea_north"
+msgstr "Korea, North"
+
+# \r
+msgid "osso_db_country_country_south_korea"
+msgstr "Korea, South"
+
+# \r
+msgid "osso_db_country_kuwait"
+msgstr "Kuwait"
+
+# \r
+msgid "osso_db_country_kyrgyz_republic"
+msgstr "Kyrgyz Republic"
+
+# \r
+msgid "osso_db_country_laos"
+msgstr "Laos"
+
+# \r
+msgid "osso_db_country_latvia"
+msgstr "Latvia"
+
+# \r
+msgid "osso_db_country_lebanon"
+msgstr "Lebanon"
+
+# \r
+msgid "osso_db_country_lesotho"
+msgstr "Lesotho"
+
+# \r
+msgid "osso_db_country_liberia"
+msgstr "Liberia"
+
+# \r
+msgid "osso_db_country_libya"
+msgstr "Libya"
+
+# \r
+msgid "osso_db_country_liechtenstein"
+msgstr "Liechtenstein"
+
+# \r
+msgid "osso_db_country_lithuania"
+msgstr "Lithuania"
+
+# \r
+msgid "osso_db_country_luxembourg"
+msgstr "Luxembourg"
+
+# \r
+msgid "osso_db_country_macao"
+msgstr "Macao, China"
+
+# \r
+msgid "osso_db_country_the_former_yugoslav_republic_of_macedonia"
+msgstr "Macedonia"
+
+# \r
+msgid "osso_db_country_madagascar"
+msgstr "Madagascar"
+
+# \r
+msgid "osso_db_country_malawi"
+msgstr "Malawi"
+
+# \r
+msgid "osso_db_country_malaysia"
+msgstr "Malaysia"
+
+# \r
+msgid "osso_db_country_maldives"
+msgstr "Maldives"
+
+# \r
+msgid "osso_db_country_mali"
+msgstr "Mali"
+
+# \r
+msgid "osso_db_country_malta"
+msgstr "Malta"
+
+# \r
+msgid "osso_db_country_marshall_islands"
+msgstr "Marshall Islands"
+
+# \r
+msgid "osso_db_country_martinique"
+msgstr "Martinique"
+
+# \r
+msgid "osso_db_country_mauritania"
+msgstr "Mauritania"
+
+# \r
+msgid "osso_db_country_mauritius"
+msgstr "Mauritius"
+
+# \r
+msgid "osso_db_country_mexico"
+msgstr "Mexico"
+
+# \r
+msgid "osso_db_country_micronesia"
+msgstr "Micronesia"
+
+# \r
+msgid "osso_db_country_republic_of_moldova"
+msgstr "Moldova"
+
+# \r
+msgid "osso_db_country_monaco"
+msgstr "Monaco"
+
+# \r
+msgid "osso_db_country_mongolia"
+msgstr "Mongolia"
+
+# \r
+msgid "osso_db_country_montserrat"
+msgstr "Montserrat"
+
+# \r
+msgid "osso_db_country_morocco"
+msgstr "Morocco"
+
+# \r
+msgid "osso_db_country_mozambique"
+msgstr "Mozambique"
+
+# \r
+msgid "osso_db_country_myanmar"
+msgstr "Myanmar"
+
+# \r
+msgid "osso_db_country_namibia"
+msgstr "Namibia"
+
+# \r
+msgid "osso_db_country_nauru"
+msgstr "Nauru"
+
+# \r
+msgid "osso_db_country_nepal"
+msgstr "Nepal"
+
+# \r
+msgid "osso_db_country_netherlands"
+msgstr "Netherlands"
+
+# \r
+msgid "osso_db_country_netherlands_antilles"
+msgstr "Netherlands Antilles"
+
+# \r
+msgid "osso_db_country_new_caledonia"
+msgstr "New Caledonia"
+
+# \r
+msgid "osso_db_country_new_zealand"
+msgstr "New Zealand"
+
+# \r
+msgid "osso_db_country_nicaraqua"
+msgstr "Nicaragua"
+
+# \r
+msgid "osso_db_country_niger"
+msgstr "Niger"
+
+# \r
+msgid "osso_db_country_nigeria"
+msgstr "Nigeria"
+
+# \r
+msgid "osso_db_country_northern_mariana_islands"
+msgstr "Northern Mariana Islands"
+
+# \r
+msgid "osso_db_country_norway"
+msgstr "Norway"
+
+# \r
+msgid "osso_db_country_oman"
+msgstr "Oman"
+
+# \r
+msgid "osso_db_country_pakistan"
+msgstr "Pakistan"
+
+# \r
+msgid "osso_db_country_palau"
+msgstr "Palau"
+
+# \r
+msgid "osso_db_country_panama"
+msgstr "Panama"
+
+# \r
+msgid "osso_db_country_papua_new_guinea"
+msgstr "Papua New Guinea"
+
+# \r
+msgid "osso_db_country_paraquay"
+msgstr "Paraguay"
+
+# \r
+msgid "osso_db_country_peru"
+msgstr "Peru"
+
+# \r
+msgid "osso_db_country_philippines"
+msgstr "Philippines"
+
+# \r
+msgid "osso_db_country_poland"
+msgstr "Poland"
+
+# \r
+msgid "osso_db_country_portugal"
+msgstr "Portugal"
+
+# \r
+msgid "osso_db_country_puerto_rico"
+msgstr "Puerto Rico"
+
+# \r
+msgid "osso_db_country_qatar"
+msgstr "Qatar"
+
+# \r
+msgid "osso_db_country_reunion"
+msgstr "Reunion"
+
+# \r
+msgid "osso_db_country_romania"
+msgstr "Romania"
+
+# \r
+msgid "osso_db_country_russian_federation"
+msgstr "Russian Federation"
+
+# \r
+msgid "osso_db_country_rwandese_republic"
+msgstr "Rwandese Republic"
+
+# \r
+msgid "osso_db_country_saint_kitts_and_nevis"
+msgstr "Saint Kitts and Nevis"
+
+# \r
+msgid "osso_db_country_saint_lucia"
+msgstr "Saint Lucia"
+
+# \r
+msgid "osso_db_country_saint_pierre_and_miquelon"
+msgstr "Saint Pierre and Miquelon"
+
+# \r
+msgid "osso_db_country_saint_vincent_and_grenadines"
+msgstr "Saint Vincent and the Grenadines"
+
+# \r
+msgid "osso_db_country_samoa"
+msgstr "Samoa"
+
+# \r
+msgid "osso_db_country_san_marino"
+msgstr "San Marino"
+
+# \r
+msgid "osso_db_country_sao_tome_and_principe"
+msgstr "Sao Tome and Principe"
+
+# \r
+msgid "osso_db_country_saudi_arabia"
+msgstr "Saudi Arabia"
+
+# \r
+msgid "osso_db_country_senegal"
+msgstr "Senegal"
+
+# \r
+msgid "osso_db_country_serbia_and_montenegro"
+msgstr "Serbia and Montenegro"
+
+# \r
+msgid "osso_db_country_seychelles"
+msgstr "Seychelles"
+
+# \r
+msgid "osso_db_country_sierra_leone"
+msgstr "Sierra Leone"
+
+# \r
+msgid "osso_db_country_singapore"
+msgstr "Singapore"
+
+# \r
+msgid "osso_db_country_slovakia"
+msgstr "Slovakia"
+
+# \r
+msgid "osso_db_country_slovenia"
+msgstr "Slovenia"
+
+# \r
+msgid "osso_db_country_solomon_islands"
+msgstr "Solomon Islands"
+
+# \r
+msgid "osso_db_country_somalia"
+msgstr "Somalia"
+
+# \r
+msgid "osso_db_country_south_africa"
+msgstr "South Africa"
+
+# \r
+msgid "osso_db_country_spain"
+msgstr "Spain"
+
+# \r
+msgid "osso_db_country_sri_lanka"
+msgstr "Sri Lanka"
+
+# \r
+msgid "osso_db_country_sudan"
+msgstr "Sudan"
+
+# \r
+msgid "osso_db_country_suriname"
+msgstr "Suriname"
+
+# \r
+msgid "osso_db_country_swaziland"
+msgstr "Swaziland"
+
+# \r
+msgid "osso_db_country_sweden"
+msgstr "Sweden"
+
+# \r
+msgid "osso_db_country_switzerland"
+msgstr "Switzerland"
+
+# \r
+msgid "osso_db_country_syrian_arab_republic"
+msgstr "Syria"
+
+# \r
+msgid "osso_db_country_taiwan"
+msgstr "Taiwan"
+
+# \r
+msgid "osso_db_country_tajikistan"
+msgstr "Tajikistan"
+
+# \r
+msgid "osso_db_country_united_republic_of_tanzania"
+msgstr "Tanzania"
+
+# \r
+msgid "osso_db_country_thailand"
+msgstr "Thailand"
+
+# \r
+msgid "osso_db_country_the_vatican"
+msgstr "Vatican City State"
+
+# \r
+msgid "osso_db_country_tibet"
+msgstr "Tibet"
+
+# \r
+msgid "osso_db_country_tunisia"
+msgstr "Tunisia"
+
+# \r
+msgid "osso_db_country_turkey"
+msgstr "Turkey"
+
+# \r
+msgid "osso_db_country_ukraine"
+msgstr "Ukraine"
+
+# \r
+msgid "osso_db_country_united_arab_emirates"
+msgstr "United Arab Emirates"
+
+# \r
+msgid "osso_db_country_united_arab_emirates_abu_dhabi"
+msgstr "United Arab Emirates (Abu Dhabi)"
+
+# \r
+msgid "osso_db_country_united_arab_emirates_dubai"
+msgstr "United Arab Emirates (Dubai)"
+
+# \r
+msgid "osso_db_country_togolese_republic"
+msgstr "Togolese Republic"
+
+# \r
+msgid "osso_db_country_tonga"
+msgstr "Tonga"
+
+# \r
+msgid "osso_db_country_trinidad_and_tobago"
+msgstr "Trinidad and Tobago"
+
+# \r
+msgid "osso_db_country_turkmenistan"
+msgstr "Turkmenistan"
+
+# \r
+msgid "osso_db_country_turks_and_caicos_islands"
+msgstr "Turks and Caicos Islands"
+
+# \r
+msgid "osso_db_country_uganda"
+msgstr "Uganda"
+
+# \r
+msgid "osso_db_country_united_kingdom_of_great_britain_and_northern_ireland"
+msgstr "United Kingdom"
+
+# \r
+msgid "osso_db_country_united_states_of_america"
+msgstr "United States of America"
+
+# \r
+msgid "osso_db_country_unites_states_virgin_islands"
+msgstr "United States Virgin Islands"
+
+# \r
+msgid "osso_db_country_uruguay"
+msgstr "Uruguay"
+
+# \r
+msgid "osso_db_country_uzbekistan"
+msgstr "Uzbekistan"
+
+# \r
+msgid "osso_db_country_vanuatu"
+msgstr "Vanuatu"
+
+# \r
+msgid "osso_db_country_venezuela"
+msgstr "Venezuela"
+
+# \r
+msgid "osso_db_country_viet_nam"
+msgstr "Viet Nam"
+
+# \r
+msgid "osso_db_country_wallis_and_futuna"
+msgstr "Wallis and Futuna"
+
+# \r
+msgid "osso_db_country_yemen"
+msgstr "Yemen"
+
+# \r
+msgid "osso_db_country_zambia"
+msgstr "Zambia"
+
+# \r
+msgid "osso_db_country_zimbabwe"
+msgstr "Zimbabwe"
+
diff --git a/src/maemo/easysetup/provider-data-test.keyfile b/src/maemo/easysetup/provider-data-test.keyfile
new file mode 100644 (file)
index 0000000..899f6b0
--- /dev/null
@@ -0,0 +1,41 @@
+[bla.com]
+Name = Bla
+Domain=bla.com
+MCC=0
+OutgoingMailServer=smtp.bla.com
+SecureSmtp=true
+IncomingMailServer=pop.bla.com:995
+IncomingSecurity=2
+MailboxType=pop
+[foo.com]
+Name=Foo
+Domain=foo.com
+MCC=0
+OutgoingMailServer=mail.foo.com
+IncomingMailServer=smtp.foo.com
+IncomingSecurity=0
+MailboxType=pop
+[xxx.fi]
+Name=XXX
+Domain=xxx.fi
+MCC=244
+OutgoingMailServer=smtp.xxx.fi
+IncomingMailServer=mail.xxx.fi
+IncomingSecurity=0
+MailboxType=imap
+[zzz.fi]
+Name=ZZZ
+Domain=zzz.fi
+MCC=244
+OutgoingMailServer=smtp.zzz.fi
+IncomingMailServer=mail.zzz.fi
+IncomingSecurity=0
+MailboxType=pop
+[rrr.af]
+Name=RRR
+Domain=rrr.af
+MCC=412
+OutgoingMailServer=smtp.rrr.af
+IncomingMailServer=mail.rrr.af
+IncomingSecurity=0
+MailboxType=imap