* Fixes NB#80791 place the buttons in their proper place in the unknown certificate...
[modest] / src / maemo / modest-platform.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31 #include <glib/gi18n.h>
32 #include <modest-platform.h>
33 #include <modest-runtime.h>
34 #include <modest-main-window.h>
35 #include <modest-header-view.h>
36 #include "maemo/modest-maemo-global-settings-dialog.h"
37 #include "modest-widget-memory.h"
38 #include <modest-hildon-includes.h>
39 #include <modest-maemo-utils.h>
40 #include <dbus_api/modest-dbus-callbacks.h>
41 #include <maemo/modest-osso-autosave-callbacks.h>
42 #include <libosso.h>
43 #include <tny-maemo-conic-device.h>
44 #include <tny-simple-list.h>
45 #include <tny-folder.h>
46 #include <tny-camel-imap-store-account.h>
47 #include <tny-camel-pop-store-account.h>
48 #include <gtk/gtkicontheme.h>
49 #include <gtk/gtkmenuitem.h>
50 #include <gtk/gtkmain.h>
51 #include <modest-text-utils.h>
52 #include "modest-tny-folder.h"
53 #include "modest-tny-account.h"
54 #include <string.h>
55 #include <libgnomevfs/gnome-vfs-mime-utils.h>
56 #include <modest-account-settings-dialog.h>
57 #include <maemo/easysetup/modest-easysetup-wizard.h>
58 #include <hildon/hildon-sound.h>
59
60 #ifdef MODEST_HAVE_MCE
61 #include <mce/dbus-names.h>
62 #endif /*MODEST_HAVE_MCE*/
63
64 #ifdef MODEST_HAVE_ABOOK
65 #include <libosso-abook/osso-abook.h>
66 #endif /*MODEST_HAVE_ABOOK*/
67
68 #ifdef MODEST_HAVE_LIBALARM
69 #include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
70 #endif /*MODEST_HAVE_LIBALARM*/
71
72
73 #define HILDON_OSSO_URI_ACTION "uri-action"
74 #define URI_ACTION_COPY "copy:"
75 #define MODEST_NEW_MAIL_SOUND_FILE "/usr/share/sounds/ui-new_email.wav"
76 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
77
78 static void     
79 on_modest_conf_update_interval_changed (ModestConf* self, 
80                                         const gchar *key, 
81                                         ModestConfEvent event,
82                                         ModestConfNotificationId id, 
83                                         gpointer user_data)
84 {
85         g_return_if_fail (key);
86         
87         if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
88                 const guint update_interval_minutes = 
89                         modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
90                 modest_platform_set_update_interval (update_interval_minutes);
91         }
92 }
93
94
95
96 static gboolean
97 check_required_files (void)
98 {
99         FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
100         if (!mcc_file) {
101                 g_printerr ("modest: check for mcc file failed\n");
102                 return FALSE;
103         } else 
104                 fclose (mcc_file);
105         
106         if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
107             access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
108                 g_printerr ("modest: cannot find providers data\n");
109                 return FALSE;
110         }
111         
112         return TRUE;
113 }
114
115
116 /* the gpointer here is the osso_context. */
117 gboolean
118 modest_platform_init (int argc, char *argv[])
119 {
120         osso_context_t *osso_context;
121         
122         osso_hw_state_t hw_state = { 0 };
123         DBusConnection *con;    
124         GSList *acc_names;
125         
126         if (!check_required_files ()) {
127                 g_printerr ("modest: missing required files\n");
128                 return FALSE;
129         }
130         
131         osso_context =  osso_initialize(PACKAGE,PACKAGE_VERSION,
132                                         FALSE, NULL);   
133         if (!osso_context) {
134                 g_printerr ("modest: failed to acquire osso context\n");
135                 return FALSE;
136         }
137         modest_maemo_utils_set_osso_context (osso_context);
138
139         if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
140                 g_printerr ("modest: could not get dbus connection\n");
141                 return FALSE;
142         }
143
144         /* Add a D-Bus handler to be used when the main osso-rpc 
145          * D-Bus handler has not handled something.
146          * We use this for D-Bus methods that need to use more complex types 
147          * than osso-rpc supports. 
148          */
149         if (!dbus_connection_add_filter (con,
150                                          modest_dbus_req_filter,
151                                          NULL,
152                                          NULL)) {
153
154                 g_printerr ("modest: Could not add D-Bus filter\n");
155                 return FALSE;
156         }
157
158         /* Register our simple D-Bus callbacks, via the osso API: */
159         osso_return_t result = osso_rpc_set_cb_f(osso_context, 
160                                MODEST_DBUS_SERVICE, 
161                                MODEST_DBUS_OBJECT, 
162                                MODEST_DBUS_IFACE,
163                                modest_dbus_req_handler, NULL /* user_data */);
164         if (result != OSSO_OK) {
165                 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
166                 return FALSE;
167         }
168
169         /* Register hardware event dbus callback: */
170         hw_state.shutdown_ind = TRUE;
171         osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
172
173         /* Register osso auto-save callbacks: */
174         result = osso_application_set_autosave_cb (osso_context, 
175                 modest_on_osso_application_autosave, NULL /* user_data */);
176         if (result != OSSO_OK) {
177                 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
178                 return FALSE;
179         }
180         
181
182         /* Make sure that the update interval is changed whenever its gconf key 
183          * is changed */
184         /* CAUTION: we're not using here the
185            modest_conf_listen_to_namespace because we know that there
186            are other parts of Modest listening for this namespace, so
187            we'll receive the notifications anyway. We basically do not
188            use it because there is no easy way to do the
189            modest_conf_forget_namespace */
190         ModestConf *conf = modest_runtime_get_conf ();
191         g_signal_connect (G_OBJECT(conf),
192                           "key_changed",
193                           G_CALLBACK (on_modest_conf_update_interval_changed), 
194                           NULL);
195
196         /* only force the setting of the default interval, if there are actually
197          * any accounts */
198         acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
199         if (acc_names) {
200                 /* Get the initial update interval from gconf: */
201                 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
202                                                        MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
203                 modest_account_mgr_free_account_names (acc_names);
204         }
205
206         
207 #ifdef MODEST_HAVE_ABOOK
208         /* initialize the addressbook */
209         if (!osso_abook_init (&argc, &argv, osso_context)) {
210                 g_printerr ("modest: failed to initialized addressbook\n");
211                 return FALSE;
212         }
213 #endif /*MODEST_HAVE_ABOOK*/
214
215         return TRUE;
216 }
217
218 gboolean
219 modest_platform_uninit (void)
220 {
221         osso_context_t *osso_context =
222                 modest_maemo_utils_get_osso_context ();
223         if (osso_context)
224                 osso_deinitialize (osso_context);
225
226         return TRUE;
227 }
228
229
230
231
232 TnyDevice*
233 modest_platform_get_new_device (void)
234 {
235         return TNY_DEVICE (tny_maemo_conic_device_new ());
236 }
237
238 gchar*
239 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
240                                     gchar **effective_mime_type)
241 {
242         GString *mime_str = NULL;
243         gchar *icon_name  = NULL;
244         gchar **icons, **cursor;
245         
246         if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) 
247                 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
248         else {
249                 mime_str = g_string_new (mime_type);
250                 g_string_ascii_down (mime_str);
251         }
252         
253         icons = hildon_mime_get_icon_names (mime_str->str, NULL);
254         
255         for (cursor = icons; cursor; ++cursor) {
256                 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
257                     !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
258                         icon_name = g_strdup ("qgn_list_messagin");
259                         break;
260                 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
261                         icon_name = g_strdup (*cursor);
262                         break;
263                 }
264         }
265         g_strfreev (icons);
266
267         if (effective_mime_type)
268                 *effective_mime_type = g_string_free (mime_str, FALSE);
269         else
270                 g_string_free (mime_str, TRUE);
271         
272         return icon_name;
273 }
274
275
276 static gboolean
277 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
278 {
279         GError *err = NULL;
280         gboolean result;
281
282         g_return_val_if_fail (uri, FALSE);
283         
284         result = hildon_uri_open (uri, action, &err);
285         if (!result) {
286                 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
287                             uri, action,  err && err->message ? err->message : "unknown error");
288                 if (err)
289                         g_error_free (err);
290         }
291         return result;
292 }
293
294
295
296 gboolean 
297 modest_platform_activate_uri (const gchar *uri)
298 {
299         HildonURIAction *action;
300         gboolean result = FALSE;
301         GSList *actions, *iter = NULL;
302         
303         g_return_val_if_fail (uri, FALSE);
304         if (!uri)
305                 return FALSE;
306
307         /* don't try to activate file: uri's -- they might confuse the user,
308          * and/or might have security implications */
309         if (!g_str_has_prefix (uri, "file:")) {
310                 
311                 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
312                 
313                 for (iter = actions; iter; iter = g_slist_next (iter)) {
314                         action = (HildonURIAction*) iter->data;
315                         if (action && strcmp (hildon_uri_action_get_service (action),
316                                               "com.nokia.modest") == 0) {
317                                 result = checked_hildon_uri_open (uri, action);
318                                 break;
319                         }
320                 }
321                 
322                 /* if we could not open it with email, try something else */
323                 if (!result)
324                         result = checked_hildon_uri_open (uri, NULL);   
325         } 
326         
327         if (!result) {
328                 ModestWindow *parent =
329                         modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
330                 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
331                                                 _("mcen_ib_unsupported_link"));
332                 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
333         } 
334         
335         return result;
336 }
337
338 gboolean 
339 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
340 {
341         gint result = 0;
342         DBusConnection *con;
343         gchar *uri_path = NULL;
344         
345         uri_path = gnome_vfs_get_uri_from_local_path (path);    
346         con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
347         
348         if (mime_type)
349                 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
350         if (result != 1)
351                 result = hildon_mime_open_file (con, uri_path);
352         if (result != 1)
353                 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
354         
355         return result != 1;
356 }
357
358 typedef struct  {
359         GSList *actions;
360         gchar  *uri;
361 } ModestPlatformPopupInfo;
362
363 static gboolean
364 delete_uri_popup (GtkWidget *menu,
365                   GdkEvent *event,
366                   gpointer userdata)
367 {
368         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
369
370         g_free (popup_info->uri);
371         hildon_uri_free_actions (popup_info->actions);
372
373         return FALSE;
374 }
375
376 static void
377 activate_uri_popup_item (GtkMenuItem *menu_item,
378                          gpointer userdata)
379 {
380         GSList *node;
381         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
382         const gchar* action_name;
383
384         action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
385         if (!action_name) {
386                 g_printerr ("modest: no action name defined\n");
387                 return;
388         }
389
390         /* special handling for the copy menu item -- copy the uri to the clipboard */
391         /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
392         if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
393                 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
394                 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
395
396                 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
397                         action_name += strlen ("mailto:");
398                 
399                 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
400                 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
401                 return; /* we're done */
402         }
403         
404         /* now, the real uri-actions... */
405         for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
406                 HildonURIAction *action = (HildonURIAction *) node->data;
407                 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
408                         if (!checked_hildon_uri_open (popup_info->uri, action)) {
409                                 ModestWindow *parent =
410                                         modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
411                                 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
412                                                                 _("mcen_ib_unsupported_link"));
413                         }
414                         break;
415                 }
416         }
417 }
418
419 gboolean 
420 modest_platform_show_uri_popup (const gchar *uri)
421 {
422         GSList *actions_list;
423
424         if (uri == NULL)
425                 return FALSE;
426         
427         actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
428         if (actions_list) {
429
430                 GtkWidget *menu = gtk_menu_new ();
431                 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
432
433                 /* don't add actions for file: uri's -- they might confuse the user,
434                  * and/or might have security implications
435                  * we still allow to copy the url though
436                  */
437                 if (!g_str_has_prefix (uri, "file:")) {                 
438                 
439                         GSList *node;                   
440                         popup_info->actions = actions_list;
441                         popup_info->uri = g_strdup (uri);
442                         
443                         for (node = actions_list; node != NULL; node = g_slist_next (node)) {
444                                 GtkWidget *menu_item;
445                                 const gchar *action_name;
446                                 const gchar *translation_domain;
447                                 HildonURIAction *action = (HildonURIAction *) node->data;
448                                 action_name = hildon_uri_action_get_name (action);
449                                 translation_domain = hildon_uri_action_get_translation_domain (action);
450                                 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
451                                 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);  /* hack */
452                                 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
453                                                   popup_info);
454                                 
455                                 if (hildon_uri_is_default_action (action, NULL)) {
456                                         gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
457                                 } else {
458                                         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
459                                 }
460                                 gtk_widget_show (menu_item);
461                         }
462                 }
463
464                 /* always add the copy item */
465                 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
466                                                                               "uri_link_copy_link_location"));
467                 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
468                                         g_strconcat (URI_ACTION_COPY, uri, NULL),
469                                         g_free);
470                 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
471                 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
472                 gtk_widget_show (menu_item);
473
474                 
475                 /* and what to do when the link is deleted */
476                 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
477                 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
478                                                   
479         } else {
480                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
481         }
482         
483         return TRUE;
484 }
485
486
487 GdkPixbuf*
488 modest_platform_get_icon (const gchar *name, guint icon_size)
489 {
490         GError *err = NULL;
491         GdkPixbuf* pixbuf = NULL;
492         GtkIconTheme *current_theme = NULL;
493
494         g_return_val_if_fail (name, NULL);
495
496         /* strlen == 0 is not really an error; it just
497          * means the icon is not available
498          */
499         if (!name || strlen(name) == 0)
500                 return NULL;
501         
502         current_theme = gtk_icon_theme_get_default ();
503         pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
504                                            GTK_ICON_LOOKUP_NO_SVG,
505                                            &err);
506         if (!pixbuf) {
507                 g_printerr ("modest: error loading theme icon '%s': %s\n",
508                             name, err->message);
509                 g_error_free (err);
510         } 
511         return pixbuf;
512 }
513
514 const gchar*
515 modest_platform_get_app_name (void)
516 {
517         return _("mcen_ap_name");
518 }
519
520 static void 
521 entry_insert_text (GtkEditable *editable,
522                    const gchar *text,
523                    gint         length,
524                    gint        *position,
525                    gpointer     data)
526 {
527         gchar *chars;
528         gint chars_length;
529
530         chars = gtk_editable_get_chars (editable, 0, -1);
531         chars_length = g_utf8_strlen (chars, -1);
532
533         /* Show WID-INF036 */
534         if (chars_length >= 20) {
535                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
536                                                  _CS("ckdg_ib_maximum_characters_reached"));
537         } else {
538                 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
539                         /* Show an error */
540                         gchar *tmp, *msg;
541                         
542                         tmp = g_strndup (folder_name_forbidden_chars, 
543                                          FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
544                         msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
545                         hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), 
546                                                          NULL, msg);
547                         g_free (msg);
548                         g_free (tmp);
549                 } else {        
550                         /* Write the text in the entry if it's valid */
551                         g_signal_handlers_block_by_func (editable,
552                                                          (gpointer) entry_insert_text, data);
553                         gtk_editable_insert_text (editable, text, length, position);
554                         g_signal_handlers_unblock_by_func (editable,
555                                                            (gpointer) entry_insert_text, data);
556                 }
557         }
558         /* Do not allow further processing */
559         g_signal_stop_emission_by_name (editable, "insert_text");
560 }
561
562 static void
563 entry_changed (GtkEditable *editable,
564                gpointer     user_data)
565 {
566         gchar *chars;
567         GtkWidget *ok_button;
568         GList *buttons;
569
570         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
571         ok_button = GTK_WIDGET (buttons->next->data);
572         
573         chars = gtk_editable_get_chars (editable, 0, -1);
574         g_return_if_fail (chars != NULL);
575
576         
577         if (g_utf8_strlen (chars,-1) >= 21)
578                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
579                                                  _CS("ckdg_ib_maximum_characters_reached"));
580         else
581                 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
582                 
583         /* Free */
584         g_list_free (buttons);
585         g_free (chars);
586 }
587
588 static guint
589 checked_hildon_sort_dialog_add_sort_key (HildonSortDialog *dialog, const gchar* key, guint max)
590 {
591         gint sort_key;
592         
593         g_return_val_if_fail (dialog && HILDON_IS_SORT_DIALOG(dialog), 0);
594         g_return_val_if_fail (key, 0);
595         
596         sort_key = hildon_sort_dialog_add_sort_key (dialog, key);
597         if (sort_key < 0 || sort_key >= max) {
598                 g_warning ("%s: out of range (%d) for %s", __FUNCTION__, sort_key, key);
599                 return 0;
600         } else
601                 return (guint)sort_key; 
602 }
603
604
605 static void
606 launch_sort_headers_dialog (GtkWindow *parent_window,
607                             HildonSortDialog *dialog)
608 {
609         ModestHeaderView *header_view = NULL;
610         GList *cols = NULL;
611         GtkSortType sort_type;
612         gint sort_key;
613         gint default_key = 0;
614         gint result;
615         gboolean outgoing = FALSE;
616         gint current_sort_colid = -1;
617         GtkSortType current_sort_type;
618         gint attachments_sort_id;
619         gint priority_sort_id;
620         GtkTreeSortable *sortable;
621         
622         /* Get header window */
623         if (MODEST_IS_MAIN_WINDOW (parent_window)) {
624                 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
625                                                                                       MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
626         }
627         if (!header_view)
628                 return;
629         
630         /* Add sorting keys */
631         cols = modest_header_view_get_columns (header_view);
632         if (cols == NULL) 
633                 return;
634 #define SORT_ID_NUM 6
635         int sort_model_ids[SORT_ID_NUM];
636         int sort_ids[SORT_ID_NUM];
637
638         outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
639                     MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
640
641         sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"),
642                                                             SORT_ID_NUM);
643         if (outgoing) {
644                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
645                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
646         } else {
647                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
648                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
649         }
650
651         sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"),
652                                                             SORT_ID_NUM);
653         if (outgoing) {
654                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
655                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
656         } else {
657                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
658                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
659         }
660         default_key = sort_key;
661
662         sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"),
663                                                             SORT_ID_NUM);
664         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
665         if (outgoing)
666                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
667         else
668                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
669
670         sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"),
671                                                             SORT_ID_NUM);
672         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
673         sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
674         attachments_sort_id = sort_key;
675
676         sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"),
677                                                             SORT_ID_NUM);
678         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
679         sort_ids[sort_key] = 0;
680
681         sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"),
682                                                             SORT_ID_NUM);
683         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
684         sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY_MASK;
685         priority_sort_id = sort_key;
686         
687         sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model
688                                       (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
689         /* Launch dialogs */
690         if (!gtk_tree_sortable_get_sort_column_id (sortable,
691                                                    &current_sort_colid, &current_sort_type)) {
692                 hildon_sort_dialog_set_sort_key (dialog, default_key);
693                 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
694         } else {
695                 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
696                 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
697                         gpointer flags_sort_type_pointer;
698                         flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
699                         if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY_MASK)
700                                 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
701                         else
702                                 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
703                 } else {
704                         gint current_sort_keyid = 0;
705                         while (current_sort_keyid < 6) {
706                                 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
707                                         break;
708                                 else 
709                                         current_sort_keyid++;
710                         }
711                         hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
712                 }
713         }
714
715         result = gtk_dialog_run (GTK_DIALOG (dialog));
716         if (result == GTK_RESPONSE_OK) {
717                 sort_key = hildon_sort_dialog_get_sort_key (dialog);
718                 if (sort_key < 0 || sort_key > SORT_ID_NUM -1) {
719                         g_warning ("%s: out of range (%d)", __FUNCTION__, sort_key);
720                         sort_key = 0;
721                 }
722
723                 sort_type = hildon_sort_dialog_get_sort_order (dialog);
724                 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
725                         g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
726                                            GINT_TO_POINTER (sort_ids[sort_key]));
727                         /* This is a hack to make it resort rows always when flag fields are
728                          * selected. If we do not do this, changing sort field from priority to
729                          * attachments does not work */
730                         modest_header_view_sort_by_column_id (header_view, 0, sort_type);
731                 } else {
732                         gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data), 
733                                                                  sort_model_ids[sort_key]);
734                 }
735
736                 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
737                 gtk_tree_sortable_sort_column_changed (sortable);
738         }
739
740         modest_widget_memory_save (modest_runtime_get_conf (),
741                                    G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
742         
743         /* free */
744         g_list_free(cols);      
745 }
746
747
748
749 static void
750 on_response (GtkDialog *dialog,
751              gint response,
752              gpointer user_data)
753 {
754         GList *child_vbox, *child_hbox;
755         GtkWidget *hbox, *entry;
756         TnyFolderStore *parent;
757         const gchar *new_name;
758         gboolean exists;
759
760         if (response != GTK_RESPONSE_ACCEPT)
761                 return;
762         
763         /* Get entry */
764         child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
765         hbox = child_vbox->data;
766         child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
767         entry = child_hbox->next->data;
768         
769         parent = TNY_FOLDER_STORE (user_data);
770         new_name = gtk_entry_get_text (GTK_ENTRY (entry));
771         exists = FALSE;
772         
773         /* Look for another folder with the same name */
774         if (modest_tny_folder_has_subfolder_with_name (parent, 
775                                                        new_name,
776                                                        TRUE)) {
777                 exists = TRUE;
778         }
779         
780         if (!exists) {
781                 if (TNY_IS_ACCOUNT (parent) &&
782                     modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
783                     modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
784                                                                          new_name)) {
785                         exists = TRUE;
786                 }
787         }
788         
789         if (exists) {
790                 
791                 /* Show an error */
792                 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)), 
793                                                 NULL, _CS("ckdg_ib_folder_already_exists"));
794                 /* Select the text */
795                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
796                 gtk_widget_grab_focus (entry);
797                 /* Do not close the dialog */
798                 g_signal_stop_emission_by_name (dialog, "response");
799         }
800 }
801
802
803
804 static gint
805 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
806                                         TnyFolderStore *parent,
807                                         const gchar *dialog_title,
808                                         const gchar *label_text,
809                                         const gchar *suggested_name,
810                                         gchar **folder_name)
811 {
812         GtkWidget *accept_btn = NULL; 
813         GtkWidget *dialog, *entry, *label, *hbox;
814         GList *buttons = NULL;
815         gint result;
816
817         /* Ask the user for the folder name */
818         dialog = gtk_dialog_new_with_buttons (dialog_title,
819                                               parent_window,
820                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
821                                               _("mcen_bd_dialog_ok"),
822                                               GTK_RESPONSE_ACCEPT,
823                                               _("mcen_bd_dialog_cancel"),
824                                               GTK_RESPONSE_REJECT,
825                                               NULL);
826
827         /* Add accept button (with unsensitive handler) */
828         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
829         accept_btn = GTK_WIDGET (buttons->next->data);
830         /* Create label and entry */
831         label = gtk_label_new (label_text);
832         /* TODO: check that the suggested name does not exist */
833         /* We set 21 as maximum because we want to show WID-INF036
834            when the user inputs more that 20 */
835         entry = gtk_entry_new_with_max_length (21);
836         if (suggested_name)
837                 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
838         else
839                 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
840         gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
841
842         /* Connect to the response method to avoid closing the dialog
843            when an invalid name is selected*/
844         g_signal_connect (dialog,
845                           "response",
846                           G_CALLBACK (on_response),
847                           parent);
848
849         /* Track entry changes */
850         g_signal_connect (entry,
851                           "insert-text",
852                           G_CALLBACK (entry_insert_text),
853                           dialog);
854         g_signal_connect (entry,
855                           "changed",
856                           G_CALLBACK (entry_changed),
857                           dialog);
858
859         /* Create the hbox */
860         hbox = gtk_hbox_new (FALSE, 12);
861         gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
862         gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
863
864         /* Add hbox to dialog */
865         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
866                             hbox, FALSE, FALSE, 0);
867         
868         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
869         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
870         
871         result = gtk_dialog_run (GTK_DIALOG(dialog));
872         if (result == GTK_RESPONSE_ACCEPT)
873                 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
874
875         gtk_widget_destroy (dialog);
876
877         while (gtk_events_pending ())
878                 gtk_main_iteration ();
879
880         return result;
881 }
882
883 gint
884 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
885                                        TnyFolderStore *parent_folder,
886                                        gchar *suggested_name,
887                                        gchar **folder_name)
888 {
889         gchar *real_suggested_name = NULL;
890         gint result;
891
892         if(suggested_name == NULL)
893         {
894                 const gchar *default_name = _("mcen_ia_default_folder_name");
895                 unsigned int i;
896                 gchar num_str[3];
897
898                 for(i = 0; i < 100; ++ i) {
899                         gboolean exists = FALSE;
900
901                         sprintf(num_str, "%.2u", i);
902
903                         if (i == 0)
904                                 real_suggested_name = g_strdup (default_name);
905                         else
906                                 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
907                                                                        num_str);
908                         exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
909                                                                             real_suggested_name,
910                                                                             TRUE);
911
912                         if (!exists)
913                                 break;
914
915                         g_free (real_suggested_name);
916                 }
917
918                 /* Didn't find a free number */
919                 if (i == 100)
920                         real_suggested_name = g_strdup (default_name);
921         } else {
922                 real_suggested_name = suggested_name;
923         }
924
925         result = modest_platform_run_folder_name_dialog (parent_window, 
926                                                          parent_folder,
927                                                          _("mcen_ti_new_folder"),
928                                                          _("mcen_fi_new_folder_name"),
929                                                          real_suggested_name,
930                                                          folder_name);
931         if (suggested_name == NULL)
932                 g_free(real_suggested_name);
933
934         return result;
935 }
936
937 gint
938 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
939                                           TnyFolderStore *parent_folder,
940                                           const gchar *suggested_name,
941                                           gchar **folder_name)
942 {
943         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
944
945         return modest_platform_run_folder_name_dialog (parent_window, 
946                                                        parent_folder,
947                                                        _HL("ckdg_ti_rename_folder"),
948                                                        _HL("ckdg_fi_rename_name"),
949                                                        suggested_name,
950                                                        folder_name);
951 }
952
953
954
955 static void
956 on_destroy_dialog (GtkDialog *dialog)
957 {
958         gtk_widget_destroy (GTK_WIDGET(dialog));
959         if (gtk_events_pending ())
960                 gtk_main_iteration ();
961 }
962
963 gint
964 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
965                                          const gchar *message)
966 {
967         GtkWidget *dialog;
968         gint response;
969         
970         dialog = hildon_note_new_confirmation (parent_window, message);
971         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
972                                      GTK_WINDOW (dialog));
973
974         response = gtk_dialog_run (GTK_DIALOG (dialog));
975
976         on_destroy_dialog (GTK_DIALOG(dialog));
977         
978         while (gtk_events_pending ())
979                 gtk_main_iteration ();
980
981         return response;
982 }
983
984 gint
985 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
986                                                       const gchar *message,
987                                                       const gchar *button_accept,
988                                                       const gchar *button_cancel)
989 {
990         GtkWidget *dialog;
991         gint response;
992         
993         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
994                                                            button_accept, GTK_RESPONSE_ACCEPT,
995                                                            button_cancel, GTK_RESPONSE_CANCEL,
996                                                            NULL);
997         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
998                                      GTK_WINDOW (dialog));
999
1000         response = gtk_dialog_run (GTK_DIALOG (dialog));
1001
1002         on_destroy_dialog (GTK_DIALOG(dialog));
1003         
1004         while (gtk_events_pending ())
1005                 gtk_main_iteration ();
1006
1007         return response;
1008 }
1009         
1010 gint
1011 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
1012                                    const gchar *message)
1013 {
1014         GtkWidget *dialog;
1015         gint response;
1016         
1017         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1018                                                            _("mcen_bd_yes"), GTK_RESPONSE_YES,
1019                                                            _("mcen_bd_no"), GTK_RESPONSE_NO,
1020                                                            NULL);
1021         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
1022         response = gtk_dialog_run (GTK_DIALOG (dialog));
1023         
1024         on_destroy_dialog (GTK_DIALOG(dialog));
1025
1026         while (gtk_events_pending ())
1027                 gtk_main_iteration ();
1028
1029         return response;
1030 }
1031
1032
1033
1034 void
1035 modest_platform_run_information_dialog (GtkWindow *parent_window,
1036                                         const gchar *message)
1037 {
1038         GtkWidget *note;
1039         
1040         note = hildon_note_new_information (parent_window, message);
1041         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1042                                      GTK_WINDOW (note));
1043         
1044         g_signal_connect_swapped (note,
1045                                   "response", 
1046                                   G_CALLBACK (on_destroy_dialog),
1047                                   note);
1048
1049         gtk_widget_show_all (note);
1050 }
1051
1052
1053
1054 typedef struct _ConnectAndWaitData {
1055         GMutex *mutex;
1056         GMainLoop *wait_loop;
1057         gboolean has_callback;
1058         gulong handler;
1059 } ConnectAndWaitData;
1060
1061
1062 static void
1063 quit_wait_loop (TnyAccount *account,
1064                 ConnectAndWaitData *data) 
1065 {
1066         /* Set the has_callback to TRUE (means that the callback was
1067            executed and wake up every code waiting for cond to be
1068            TRUE */
1069         g_mutex_lock (data->mutex);
1070         data->has_callback = TRUE;
1071         if (data->wait_loop)
1072                 g_main_loop_quit (data->wait_loop);
1073         g_mutex_unlock (data->mutex);
1074 }
1075
1076 static void
1077 on_connection_status_changed (TnyAccount *account, 
1078                               TnyConnectionStatus status,
1079                               gpointer user_data)
1080 {
1081         TnyConnectionStatus conn_status;
1082         ConnectAndWaitData *data;
1083                         
1084         /* Ignore if reconnecting or disconnected */
1085         conn_status = tny_account_get_connection_status (account);
1086         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1087             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1088                 return;
1089
1090         /* Remove the handler */
1091         data = (ConnectAndWaitData *) user_data;
1092         g_signal_handler_disconnect (account, data->handler);
1093
1094         /* Quit from wait loop */
1095         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1096 }
1097
1098 static void
1099 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
1100                                     gboolean canceled, 
1101                                     GError *err, 
1102                                     gpointer user_data)
1103 {
1104         /* Quit from wait loop */
1105         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1106 }
1107
1108 gboolean 
1109 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1110                                   TnyAccount *account)
1111 {
1112         ConnectAndWaitData *data = NULL;
1113         gboolean device_online;
1114         TnyDevice *device;
1115         TnyConnectionStatus conn_status;
1116         gboolean user_requested;
1117         
1118         device = modest_runtime_get_device();
1119         device_online = tny_device_is_online (device);
1120
1121         /* Whether the connection is user requested or automatically
1122            requested, for example via D-Bus */
1123         user_requested = (parent_window) ? TRUE : FALSE;
1124
1125         /* If there is no account check only the device status */
1126         if (!account) {
1127                 if (device_online)
1128                         return TRUE;
1129                 else
1130                         return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1131                                                                NULL, user_requested);
1132         }
1133
1134         /* Return if the account is already connected */
1135         conn_status = tny_account_get_connection_status (account);
1136         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1137                 return TRUE;
1138
1139         /* Create the helper */
1140         data = g_slice_new0 (ConnectAndWaitData);
1141         data->mutex = g_mutex_new ();
1142         data->has_callback = FALSE;
1143
1144         /* Connect the device */
1145         if (!device_online) {
1146                 /* Track account connection status changes */
1147                 data->handler = g_signal_connect (account, "connection-status-changed",                                     
1148                                                   G_CALLBACK (on_connection_status_changed),
1149                                                   data);
1150                 /* Try to connect the device */
1151                 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1152                                                                 NULL, user_requested);
1153
1154                 /* If the device connection failed then exit */
1155                 if (!device_online && data->handler)
1156                         goto frees;
1157         } else {
1158                 /* Force a reconnection of the account */
1159                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1160                                               on_tny_camel_account_set_online_cb, data);
1161         }
1162
1163         /* Wait until the callback is executed */
1164         g_mutex_lock (data->mutex);
1165         if (!data->has_callback) {
1166                 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1167                 gdk_threads_leave ();
1168                 g_mutex_unlock (data->mutex);
1169                 g_main_loop_run (data->wait_loop);
1170                 g_mutex_lock (data->mutex);
1171                 gdk_threads_enter ();
1172         }
1173         g_mutex_unlock (data->mutex);
1174
1175  frees:
1176         if (data) {
1177                 if (g_signal_handler_is_connected (account, data->handler))
1178                         g_signal_handler_disconnect (account, data->handler);
1179                 g_mutex_free (data->mutex);
1180                 g_main_loop_unref (data->wait_loop);
1181                 g_slice_free (ConnectAndWaitData, data);
1182         }
1183
1184         conn_status = tny_account_get_connection_status (account);
1185         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1186 }
1187
1188 gboolean 
1189 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1190 {
1191         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1192                 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1193                     !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1194                         /* This must be a maildir account, which does not require a connection: */
1195                         return TRUE;
1196                 }
1197         }
1198
1199         return modest_platform_connect_and_wait (parent_window, account);
1200 }
1201
1202 gboolean 
1203 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1204 {
1205         if (!folder_store)
1206                 return TRUE; /* Maybe it is something local. */
1207                 
1208         gboolean result = TRUE;
1209         if (TNY_IS_FOLDER (folder_store)) {
1210                 /* Get the folder's parent account: */
1211                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1212                 if (account != NULL) {
1213                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1214                         g_object_unref (account);
1215                 }
1216         } else if (TNY_IS_ACCOUNT (folder_store)) {
1217                 /* Use the folder store as an account: */
1218                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1219         }
1220
1221         return result;
1222 }
1223
1224 void
1225 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1226                                  ModestSortDialogType type)
1227 {
1228         GtkWidget *dialog = NULL;
1229
1230         /* Build dialog */
1231         dialog = hildon_sort_dialog_new (parent_window);
1232         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1233                                      GTK_WINDOW (dialog));
1234
1235         hildon_help_dialog_help_enable (GTK_DIALOG(dialog),
1236                                         "applications_email_sort",
1237                                         modest_maemo_utils_get_osso_context());
1238
1239         /* Fill sort keys */
1240         switch (type) {
1241         case MODEST_SORT_HEADERS:
1242                 launch_sort_headers_dialog (parent_window, 
1243                                             HILDON_SORT_DIALOG(dialog));
1244                 break;
1245         }
1246         
1247         /* Free */
1248         on_destroy_dialog (GTK_DIALOG(dialog));
1249 }
1250
1251
1252 gboolean 
1253 modest_platform_set_update_interval (guint minutes)
1254 {
1255 #ifdef MODEST_HAVE_LIBALARM
1256         
1257         ModestConf *conf = modest_runtime_get_conf ();
1258         if (!conf)
1259                 return FALSE;
1260                 
1261         cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1262
1263         /* Delete any existing alarm,
1264          * because we will replace it: */
1265         if (alarm_cookie) {
1266                 if (alarm_event_del(alarm_cookie) != 1)
1267                         g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1268                 alarm_cookie = 0;
1269                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1270         }
1271         
1272         /* 0 means no updates: */
1273         if (minutes == 0)
1274                 return TRUE;
1275         
1276      
1277         /* Register alarm: */
1278         
1279         /* Set the interval in alarm_event_t structure: */
1280         alarm_event_t *event = g_new0(alarm_event_t, 1);
1281         event->alarm_time = minutes * 60; /* seconds */
1282         
1283         /* Set recurrence every few minutes: */
1284         event->recurrence = minutes;
1285         event->recurrence_count = -1; /* Means infinite */
1286
1287         /* Specify what should happen when the alarm happens:
1288          * It should call this D-Bus method: */
1289          
1290         event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1291         event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1292         event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1293         event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1294
1295         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1296          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1297          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1298          * This is why we want to use the Alarm API instead of just g_timeout_add().
1299          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1300          * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1301          */
1302         event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION | ALARM_EVENT_CONNECTED;
1303         
1304         alarm_cookie = alarm_event_add (event);
1305
1306         /* now, free it */
1307         alarm_event_free (event);
1308         
1309         /* Store the alarm ID in GConf, so we can remove it later:
1310          * This is apparently valid between application instances. */
1311         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1312         
1313         if (!alarm_cookie) {
1314             /* Error */
1315             const alarm_error_t alarm_error = alarmd_get_error ();
1316             g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1317             
1318             /* Give people some clue: */
1319             /* The alarm API should have a function for this: */
1320             if (alarm_error == ALARMD_ERROR_DBUS) {
1321                 g_debug ("  ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1322             } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1323                 g_debug ("  ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1324             } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1325                 g_debug ("  ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1326             } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1327                 g_debug ("  ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1328             } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1329                 g_debug ("  ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1330             } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1331                 g_debug ("  ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1332             }
1333             
1334             return FALSE;
1335         }
1336 #endif /* MODEST_HAVE_LIBALARM */       
1337         return TRUE;
1338 }
1339
1340 void
1341 modest_platform_push_email_notification(void)
1342 {
1343         gboolean play_sound;
1344         ModestWindow *main_window;
1345         gboolean screen_on = TRUE, app_in_foreground;
1346
1347         /* Check whether or not we should play a sound */
1348         play_sound = modest_conf_get_bool (modest_runtime_get_conf (),
1349                                            MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1350                                            NULL);
1351
1352         /* Get the screen status */
1353         main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1354         if (main_window)
1355                 screen_on = modest_main_window_screen_is_on (MODEST_MAIN_WINDOW (main_window));
1356
1357         /* Get the window status */
1358         app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1359
1360         /* If the screen is on and the app is in the
1361            foreground we don't show anything */
1362         if (!(screen_on && app_in_foreground)) {
1363                 /* Play a sound */
1364                 if (play_sound)
1365                         hildon_play_system_sound (MODEST_NEW_MAIL_SOUND_FILE);
1366
1367                 /* Activate LED. This must be deactivated by
1368                    modest_platform_remove_new_mail_notifications */
1369 #ifdef MODEST_HAVE_MCE
1370                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1371                                      MCE_SERVICE,
1372                                      MCE_REQUEST_PATH,
1373                                      MCE_REQUEST_IF,
1374                                      MCE_ACTIVATE_LED_PATTERN,
1375                                      NULL,
1376                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1377                                      DBUS_TYPE_INVALID);
1378 #endif
1379         }
1380 }
1381
1382 void 
1383 modest_platform_on_new_headers_received (TnyList *header_list,
1384                                          gboolean show_visual)
1385 {
1386         g_return_if_fail (TNY_IS_LIST(header_list));
1387
1388         if (tny_list_get_length(header_list) == 0) {
1389                 g_warning ("%s: header list is empty", __FUNCTION__);
1390                 return;
1391         }
1392         
1393         if (!show_visual) {
1394                 modest_platform_push_email_notification ();
1395                 /* We do a return here to avoid indentation with an else */
1396                 return;
1397         }
1398
1399 #ifdef MODEST_HAVE_HILDON_NOTIFY
1400         gboolean play_sound;
1401
1402         /* Check whether or not we should play a sound */
1403         play_sound = modest_conf_get_bool (modest_runtime_get_conf (),
1404                                            MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1405                                            NULL);
1406
1407         HildonNotification *notification;
1408         TnyIterator *iter;
1409         GSList *notifications_list = NULL;
1410
1411         /* Get previous notifications ids */
1412         notifications_list = modest_conf_get_list (modest_runtime_get_conf (), 
1413                                                    MODEST_CONF_NOTIFICATION_IDS, 
1414                                                    MODEST_CONF_VALUE_INT, NULL);
1415
1416         iter = tny_list_create_iterator (header_list);
1417         while (!tny_iterator_is_done (iter)) {
1418                 gchar *url = NULL, *display_address = NULL,  *summary = NULL;
1419                 const gchar *display_date;
1420                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1421                 TnyFolder *folder = tny_header_get_folder (header);
1422                 gboolean first_notification = TRUE;
1423                 gint notif_id;
1424
1425                 /* constant string, don't free */
1426                 display_date = modest_text_utils_get_display_date (tny_header_get_date_received (header));
1427
1428                 display_address = g_strdup(tny_header_get_from (header));
1429                 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1430                 
1431                 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1432                 notification = hildon_notification_new (summary,
1433                                                         tny_header_get_subject (header),
1434                                                         "qgn_list_messagin",
1435                                                         "email.arrive");
1436                 /* Create the message URL */
1437                 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder), 
1438                                        tny_header_get_uid (header));
1439
1440                 hildon_notification_add_dbus_action(notification,
1441                                                     "default",
1442                                                     "Cancel",
1443                                                     MODEST_DBUS_SERVICE,
1444                                                     MODEST_DBUS_OBJECT,
1445                                                     MODEST_DBUS_IFACE,
1446                                                     MODEST_DBUS_METHOD_OPEN_MESSAGE,
1447                                                     G_TYPE_STRING, url,
1448                                                     -1);
1449
1450                 /* Play sound if the user wants. Show the LED
1451                    pattern. Show and play just one */
1452                 if (G_UNLIKELY (first_notification)) {
1453                         first_notification = FALSE;
1454                         if (play_sound)  {
1455                                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1456                                                                     "sound-file", MODEST_NEW_MAIL_SOUND_FILE);
1457                         }
1458
1459                         /* Set the led pattern */
1460                         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1461                                                             "dialog-type", 4);
1462                         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1463                                                             "led-pattern",
1464                                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);                  
1465                 }
1466
1467                 /* Notify. We need to do this in an idle because this function
1468                    could be called from a thread */
1469                 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1470
1471                 /* Save id in the list */
1472                 g_object_get(G_OBJECT(notification), "id", &notif_id, NULL);
1473                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1474                 /* We don't listen for the "closed" signal, because we
1475                    don't care about if the notification was removed or
1476                    not to store the list in gconf */
1477         
1478                 /* Free & carry on */
1479                 g_free (display_address);
1480                 g_free (summary);
1481                 g_free (url);
1482                 g_object_unref (folder);
1483                 g_object_unref (header);
1484                 tny_iterator_next (iter);
1485         }
1486         g_object_unref (iter);
1487
1488         /* Save the ids */
1489         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1490                               notifications_list, MODEST_CONF_VALUE_INT, NULL);
1491
1492         g_slist_free (notifications_list);
1493         
1494 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1495 }
1496
1497 void
1498 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1499 {
1500         if (only_visuals) {
1501 #ifdef MODEST_HAVE_MCE
1502                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1503                                      MCE_SERVICE,
1504                                      MCE_REQUEST_PATH,
1505                                      MCE_REQUEST_IF,
1506                                      MCE_DEACTIVATE_LED_PATTERN,
1507                                      NULL,
1508                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1509                                      DBUS_TYPE_INVALID);
1510 #endif
1511                 return;
1512         }
1513
1514 #ifdef MODEST_HAVE_HILDON_NOTIFY
1515         GSList *notif_list = NULL;
1516
1517         /* Get previous notifications ids */
1518         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1519                                            MODEST_CONF_NOTIFICATION_IDS, 
1520                                            MODEST_CONF_VALUE_INT, NULL);
1521
1522         while (notif_list) {
1523                 gint notif_id;
1524                 NotifyNotification *notif;
1525
1526                 /* Nasty HACK to remove the notifications, set the id
1527                    of the existing ones and then close them */
1528                 notif_id = GPOINTER_TO_INT(notif_list->data);
1529                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1530                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1531
1532                 /* Close the notification, note that some ids could be
1533                    already invalid, but we don't care because it does
1534                    not fail */
1535                 notify_notification_close(notif, NULL);
1536                 g_object_unref(notif);
1537
1538                 /* Delete the link, it's like going to the next */
1539                 notif_list = g_slist_delete_link (notif_list, notif_list);
1540         }
1541
1542         /* Save the ids */
1543         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1544                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1545
1546         g_slist_free (notif_list);
1547
1548 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1549 }
1550
1551
1552
1553 GtkWidget * 
1554 modest_platform_get_global_settings_dialog ()
1555 {
1556         return modest_maemo_global_settings_dialog_new ();
1557 }
1558
1559 void
1560 modest_platform_show_help (GtkWindow *parent_window, 
1561                            const gchar *help_id)
1562 {
1563         osso_return_t result;
1564         g_return_if_fail (help_id);
1565
1566         result = hildon_help_show (modest_maemo_utils_get_osso_context(),
1567                                    help_id, HILDON_HELP_SHOW_DIALOG);
1568         
1569         if (result != OSSO_OK) {
1570                 gchar *error_msg;
1571                 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id); 
1572                 hildon_banner_show_information (GTK_WIDGET (parent_window),
1573                                                 NULL,
1574                                                 error_msg);
1575                 g_free (error_msg);
1576         }
1577 }
1578
1579 void 
1580 modest_platform_show_search_messages (GtkWindow *parent_window)
1581 {
1582         osso_return_t result = OSSO_ERROR;
1583         
1584         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1585                                              "osso_global_search",
1586                                              "search_email", NULL, DBUS_TYPE_INVALID);
1587
1588         if (result != OSSO_OK) {
1589                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1590         }
1591 }
1592
1593 void 
1594 modest_platform_show_addressbook (GtkWindow *parent_window)
1595 {
1596         osso_return_t result = OSSO_ERROR;
1597         
1598         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1599                                              "osso_addressbook",
1600                                              "top_application", NULL, DBUS_TYPE_INVALID);
1601
1602         if (result != OSSO_OK) {
1603                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1604         }
1605 }
1606
1607 GtkWidget *
1608 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1609 {
1610         GtkWidget *widget = modest_folder_view_new (query);
1611
1612         /* Show one account by default */
1613         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1614                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1615
1616         /* Restore settings */
1617         modest_widget_memory_restore (modest_runtime_get_conf(), 
1618                                       G_OBJECT (widget),
1619                                       MODEST_CONF_FOLDER_VIEW_KEY);
1620
1621         return widget;
1622 }
1623
1624 void
1625 banner_finish (gpointer data, GObject *object)
1626 {
1627         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1628         modest_window_mgr_unregister_banner (mgr);
1629         g_object_unref (mgr);
1630 }
1631
1632 void 
1633 modest_platform_information_banner (GtkWidget *parent,
1634                                     const gchar *icon_name,
1635                                     const gchar *text)
1636 {
1637         GtkWidget *banner;
1638         ModestWindowMgr *mgr;
1639
1640         mgr = modest_runtime_get_window_mgr ();
1641         banner = hildon_banner_show_information (parent, icon_name, text);
1642
1643         modest_window_mgr_register_banner (mgr);
1644         g_object_ref (mgr);
1645         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1646 }
1647
1648 void
1649 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1650                                                  const gchar *icon_name,
1651                                                  const gchar *text,
1652                                                  gint timeout)
1653 {
1654         GtkWidget *banner;
1655         banner = hildon_banner_show_information (parent, icon_name, text);
1656         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1657 }
1658
1659 GtkWidget *
1660 modest_platform_animation_banner (GtkWidget *parent,
1661                                   const gchar *animation_name,
1662                                   const gchar *text)
1663 {
1664         GtkWidget *inf_note = NULL;
1665
1666         g_return_val_if_fail (text != NULL, NULL);
1667
1668         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1669
1670         return inf_note;
1671 }
1672
1673 typedef struct
1674 {
1675         GMainLoop* loop;
1676         TnyAccount *account;
1677         gboolean is_online;
1678         gint count_tries;
1679 } CheckAccountIdleData;
1680
1681 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1682
1683 static gboolean 
1684 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1685 {
1686         gboolean stop_trying = FALSE;
1687         g_return_val_if_fail (data && data->account, FALSE);
1688         
1689         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1690                 tny_account_get_connection_status (data->account));     
1691         
1692         if (data && data->account && 
1693                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1694                  * after which the account is likely to be usable, or never likely to be usable soon: */
1695                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1696         {
1697                 data->is_online = TRUE;
1698                 
1699                 stop_trying = TRUE;
1700         } else {
1701                 /* Give up if we have tried too many times: */
1702                 if (data->count_tries >= NUMBER_OF_TRIES) {
1703                         stop_trying = TRUE;
1704                 } else {
1705                         /* Wait for another timeout: */
1706                         ++(data->count_tries);
1707                 }
1708         }
1709         
1710         if (stop_trying) {
1711                 /* Allow the function that requested this idle callback to continue: */
1712                 if (data->loop)
1713                         g_main_loop_quit (data->loop);
1714                         
1715                 if (data->account)
1716                         g_object_unref (data->account);
1717                 
1718                 return FALSE; /* Don't call this again. */
1719         } else {
1720                 return TRUE; /* Call this timeout callback again. */
1721         }
1722 }
1723
1724 /* Return TRUE immediately if the account is already online,
1725  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1726  * soon as the account is online, or FALSE if the account does 
1727  * not become online in the NUMBER_OF_TRIES seconds.
1728  * This is useful when the D-Bus method was run immediately after 
1729  * the application was started (when using D-Bus activation), 
1730  * because the account usually takes a short time to go online.
1731  * The return value is maybe not very useful.
1732  */
1733 gboolean
1734 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1735 {
1736         g_return_val_if_fail (account, FALSE);
1737         
1738         printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1739         
1740         if (!tny_device_is_online (modest_runtime_get_device())) {
1741                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1742                 return FALSE;
1743         }
1744         
1745         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1746          * so we avoid wait unnecessarily: */
1747         if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) && 
1748                 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1749                 return TRUE;            
1750         }
1751                 
1752         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1753                 __FUNCTION__, tny_account_get_connection_status (account));
1754         
1755         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1756          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1757          * we want to avoid. */
1758         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1759                 return TRUE;
1760                 
1761         /* This blocks on the result: */
1762         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1763         data->is_online = FALSE;
1764         data->account = account;
1765         g_object_ref (data->account);
1766         data->count_tries = 0;
1767                 
1768         GMainContext *context = NULL; /* g_main_context_new (); */
1769         data->loop = g_main_loop_new (context, FALSE /* not running */);
1770
1771         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1772
1773         /* This main loop will run until the idle handler has stopped it: */
1774         g_main_loop_run (data->loop);
1775
1776         g_main_loop_unref (data->loop);
1777         /* g_main_context_unref (context); */
1778
1779         g_slice_free (CheckAccountIdleData, data);
1780         
1781         return data->is_online; 
1782 }
1783
1784
1785
1786 static void
1787 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1788 {
1789         /* GTK_RESPONSE_HELP means we need to show the certificate */
1790         if (response_id == GTK_RESPONSE_APPLY) {
1791                 GtkWidget *note;
1792                 gchar *msg;
1793                 
1794                 /* Do not close the dialog */
1795                 g_signal_stop_emission_by_name (dialog, "response");
1796
1797                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1798                 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1799                 gtk_dialog_run (GTK_DIALOG(note));
1800                 gtk_widget_destroy (note);
1801         }
1802 }
1803
1804
1805 gboolean
1806 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1807                                                      const gchar *certificate)
1808 {
1809         GtkWidget *note;
1810         gint response;
1811         ModestWindow *main_win;
1812         
1813         if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1814                 g_warning ("%s: don't show dialogs if there's no main window; assuming 'Cancel'",
1815                            __FUNCTION__);
1816                 return FALSE;
1817         }
1818
1819         /* don't create it */
1820         main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
1821         g_return_val_if_fail (main_win, FALSE); /* should not happen */
1822         
1823         
1824         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1825                                            server_name);
1826         
1827         note = hildon_note_new_confirmation_add_buttons  (
1828                 GTK_WINDOW(main_win),
1829                 question,
1830                 _("mcen_bd_dialog_ok"),     GTK_RESPONSE_OK,
1831                 _("mcen_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
1832                 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1833                 NULL, NULL);
1834         
1835         g_signal_connect (G_OBJECT(note), "response", 
1836                           G_CALLBACK(on_cert_dialog_response),
1837                           (gpointer) certificate);
1838         
1839         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1840                                      GTK_WINDOW (note));
1841         response = gtk_dialog_run(GTK_DIALOG(note));
1842
1843         on_destroy_dialog (GTK_DIALOG(note));
1844         g_free (question);
1845         
1846         return response == GTK_RESPONSE_OK;
1847 }
1848
1849 gboolean
1850 modest_platform_run_alert_dialog (const gchar* prompt, 
1851                                   gboolean is_question)
1852 {       
1853         ModestWindow *main_win; 
1854
1855         if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1856                 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1857                            " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1858                 return is_question ? FALSE : TRUE;
1859         }
1860
1861         main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1862         g_return_val_if_fail (main_win, FALSE); /* should not happen */
1863         
1864         gboolean retval = TRUE;
1865         if (is_question) {
1866                 /* The Tinymail documentation says that we should show Yes and No buttons, 
1867                  * when it is a question.
1868                  * Obviously, we need tinymail to use more specific error codes instead,
1869                  * so we know what buttons to show. */
1870                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win), 
1871                                                                               prompt));
1872                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1873                                              GTK_WINDOW (dialog));
1874                 
1875                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1876                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1877                 
1878                 on_destroy_dialog (GTK_DIALOG(dialog));         
1879         } else {
1880                 /* Just show the error text and use the default response: */
1881                 modest_platform_run_information_dialog (GTK_WINDOW (main_win), 
1882                                                         prompt);
1883         }
1884         return retval;
1885 }
1886
1887 /***************/
1888 typedef struct {
1889         GtkWindow *parent_window;
1890         ModestConnectedPerformer callback;
1891         TnyAccount *account;
1892         gpointer user_data;
1893         gchar *iap;
1894         TnyDevice *device;
1895 } OnWentOnlineInfo;
1896  
1897 static void 
1898 on_went_online_info_free (OnWentOnlineInfo *info)
1899 {
1900         /* And if we cleanup, we DO cleanup  :-)  */
1901         
1902         if (info->device)
1903                 g_object_unref (info->device);
1904         if (info->iap)
1905                 g_free (info->iap);
1906         if (info->parent_window)
1907                 g_object_unref (info->parent_window);
1908         if (info->account)
1909                 g_object_unref (info->account);
1910         
1911         g_slice_free (OnWentOnlineInfo, info);
1912         
1913         /* We're done ... */
1914         
1915         return;
1916 }
1917  
1918 static void
1919 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1920 {
1921         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1922  
1923         /* Now it's really time to callback to the caller. If going online didn't succeed,
1924          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1925          * canceled will be set. Etcetera etcetera. */
1926         
1927         if (info->callback) {
1928                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1929         }
1930         
1931         /* This is our last call, we must cleanup here if we didn't yet do that */
1932         on_went_online_info_free (info);
1933         
1934         return;
1935 }
1936  
1937  
1938 static void
1939 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1940 {
1941         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1942         info->iap = g_strdup (iap_id);
1943         
1944         if (canceled || err || !info->account) {
1945         
1946                 /* If there's a problem or if there's no account (then that's it for us, we callback
1947                  * the caller's callback now. He'll have to handle err or canceled, of course.
1948                  * We are not really online, as the account is not really online here ... */    
1949                 
1950                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1951                  * this info. We don't cleanup err, Tinymail does that! */
1952                 
1953                 if (info->callback) {
1954                         
1955                         /* info->account can be NULL here, this means that the user did not
1956                          * provide a nice account instance. We'll assume that the user knows
1957                          * what he's doing and is happy with just the device going online. 
1958                          * 
1959                          * We can't do magic, we don't know what account the user wants to
1960                          * see going online. So just the device goes online, end of story */
1961                         
1962                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1963                 }
1964                 
1965         } else if (info->account) {
1966                 
1967                 /* If there's no problem and if we have an account, we'll put the account
1968                  * online too. When done, the callback of bringing the account online
1969                  * will callback the caller's callback. This is the most normal case. */
1970  
1971                 info->device = TNY_DEVICE (g_object_ref (device));
1972                 
1973                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1974                                               on_account_went_online, info);
1975                 
1976                 /* The on_account_went_online cb frees up the info, go look if you
1977                  * don't believe me! (so we return here) */
1978                 
1979                 return;
1980         }
1981         
1982         /* We cleanup if we are not bringing the account online too */
1983         on_went_online_info_free (info);
1984  
1985         return; 
1986 }
1987         
1988 void 
1989 modest_platform_connect_and_perform (GtkWindow *parent_window, 
1990                                      gboolean force,
1991                                      TnyAccount *account, 
1992                                      ModestConnectedPerformer callback, 
1993                                      gpointer user_data)
1994 {
1995         gboolean device_online;
1996         TnyDevice *device;
1997         TnyConnectionStatus conn_status;
1998         OnWentOnlineInfo *info;
1999         
2000         device = modest_runtime_get_device();
2001         device_online = tny_device_is_online (device);
2002
2003         /* If there is no account check only the device status */
2004         if (!account) {
2005                 
2006                 if (device_online) {
2007  
2008                         /* We promise to instantly perform the callback, so ... */
2009                         if (callback) {
2010                                 callback (FALSE, NULL, parent_window, account, user_data);
2011                         }
2012                         
2013                 } else {
2014                         
2015                         info = g_slice_new0 (OnWentOnlineInfo);
2016                         
2017                         info->iap = NULL;
2018                         info->device = NULL;
2019                         info->account = NULL;
2020                 
2021                         if (parent_window)
2022                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2023                         else
2024                                 info->parent_window = NULL;
2025                         info->user_data = user_data;
2026                         info->callback = callback;
2027                 
2028                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2029                                                               force, on_conic_device_went_online, 
2030                                                               info);
2031  
2032                         /* We'll cleanup in on_conic_device_went_online */
2033                 }
2034  
2035                 /* The other code has no more reason to run. This is all that we can do for the
2036                  * caller (he should have given us a nice and clean account instance!). We
2037                  * can't do magic, we don't know what account he intends to bring online. So
2038                  * we'll just bring the device online (and await his false bug report). */
2039                 
2040                 return;
2041         }
2042  
2043         
2044         /* Return if the account is already connected */
2045         
2046         conn_status = tny_account_get_connection_status (account);
2047         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2048  
2049                 /* We promise to instantly perform the callback, so ... */
2050                 if (callback) {
2051                         callback (FALSE, NULL, parent_window, account, user_data);
2052                 }
2053                 
2054                 return;
2055         }
2056         
2057         /* Else, we are in a state that requires that we go online before we
2058          * call the caller's callback. */
2059         
2060         info = g_slice_new0 (OnWentOnlineInfo);
2061         
2062         info->device = NULL;
2063         info->iap = NULL;
2064         info->account = TNY_ACCOUNT (g_object_ref (account));
2065         
2066         if (parent_window)
2067                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2068         else
2069                 info->parent_window = NULL;
2070         
2071         /* So we'll put the callback away for later ... */
2072         
2073         info->user_data = user_data;
2074         info->callback = callback;
2075         
2076         if (!device_online) {
2077  
2078                 /* If also the device is offline, then we connect both the device 
2079                  * and the account */
2080                 
2081                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2082                                                       force, on_conic_device_went_online, 
2083                                                       info);
2084                 
2085         } else {
2086                 
2087                 /* If the device is online, we'll just connect the account */
2088                 
2089                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2090                                               on_account_went_online, info);
2091         }
2092  
2093         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2094          * in both situations, go look if you don't believe me! */
2095         
2096         return;
2097 }
2098
2099 void
2100 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2101                                                gboolean force,
2102                                                TnyFolderStore *folder_store, 
2103                                                ModestConnectedPerformer callback, 
2104                                                gpointer user_data)
2105 {
2106         TnyAccount *account = NULL;
2107         
2108         if (!folder_store) {
2109                 /* We promise to instantly perform the callback, so ... */
2110                 if (callback) {
2111                         callback (FALSE, NULL, parent_window, NULL, user_data);
2112                 }
2113                 return; 
2114                 
2115                 /* Original comment: Maybe it is something local. */
2116                 /* PVH's comment: maybe we should KNOW this in stead of assuming? */
2117                 
2118         } else if (TNY_IS_FOLDER (folder_store)) {
2119                 /* Get the folder's parent account: */
2120                 account = tny_folder_get_account(TNY_FOLDER (folder_store));
2121         } else if (TNY_IS_ACCOUNT (folder_store)) {
2122                 /* Use the folder store as an account: */
2123                 account = TNY_ACCOUNT (folder_store);
2124         }
2125  
2126         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2127                 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
2128                     !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
2129                         
2130                         /* This IS a local account like a maildir account, which does not require 
2131                          * a connection. (original comment had a vague assumption in its language
2132                          * usage. There's no assuming needed, this IS what it IS: a local account), */
2133  
2134                         /* We promise to instantly perform the callback, so ... */
2135                         if (callback) {
2136                                 callback (FALSE, NULL, parent_window, account, user_data);
2137                         }
2138                         
2139                         return;
2140                 }
2141         }
2142  
2143         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2144  
2145         return;
2146 }
2147
2148 static void
2149 src_account_connect_performer (gboolean canceled, 
2150                                GError *err,
2151                                GtkWindow *parent_window, 
2152                                TnyAccount *src_account, 
2153                                gpointer user_data)
2154 {
2155         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2156
2157         if (canceled || err) {
2158                 /* If there was any error call the user callback */
2159                 info->callback (canceled, err, parent_window, src_account, info->data);
2160         } else {
2161                 /* Connect the destination account */
2162                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2163                                                                TNY_FOLDER_STORE (info->dst_account),
2164                                                                info->callback, info->data);
2165         }
2166
2167         /* Free the info object */
2168         g_object_unref (info->dst_account);
2169         g_slice_free (DoubleConnectionInfo, info);
2170 }
2171
2172
2173 void 
2174 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2175                                             gboolean force,
2176                                             TnyFolderStore *folder_store,
2177                                             DoubleConnectionInfo *connect_info)
2178 {
2179         modest_platform_connect_if_remote_and_perform(parent_window, 
2180                                                       force,
2181                                                       folder_store, 
2182                                                       src_account_connect_performer, 
2183                                                       connect_info);
2184 }
2185
2186 GtkWidget *
2187 modest_platform_get_account_settings_dialog (ModestAccountSettings *settings)
2188 {
2189         ModestAccountSettingsDialog *dialog = modest_account_settings_dialog_new ();
2190
2191         modest_account_settings_dialog_set_account (dialog, settings);
2192         return GTK_WIDGET (dialog);
2193 }
2194
2195 GtkWidget *
2196 modest_platform_get_account_settings_wizard ()
2197 {
2198         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2199
2200         return GTK_WIDGET (dialog);
2201 }