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