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