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