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