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