0167cac8c921b470705b8946fa30be869bf6a388
[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                         gint insert_length;
568
569                         insert_length = g_utf8_strlen (text, -1);
570
571                         if (insert_length + chars_length >= 20) {
572                                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
573                                                                  _CS("ckdg_ib_maximum_characters_reached"));
574                         }
575                         /* Write the text in the entry if it's valid */
576                         g_signal_handlers_block_by_func (editable,
577                                                          (gpointer) entry_insert_text, data);
578                         gtk_editable_insert_text (editable, text, MIN (chars_length + insert_length, 20), position);
579                         g_signal_handlers_unblock_by_func (editable,
580                                                            (gpointer) entry_insert_text, data);
581                 }
582         }
583         /* Do not allow further processing */
584         g_signal_stop_emission_by_name (editable, "insert_text");
585 }
586
587 static void
588 entry_changed (GtkEditable *editable,
589                gpointer     user_data)
590 {
591         gchar *chars;
592         GtkWidget *ok_button;
593         GList *buttons;
594
595         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
596         ok_button = GTK_WIDGET (buttons->data);
597
598         chars = gtk_editable_get_chars (editable, 0, -1);
599         g_return_if_fail (chars != NULL);
600
601
602         if (g_utf8_strlen (chars,-1) >= 20) {
603                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
604                                                  _CS("ckdg_ib_maximum_characters_reached"));
605         }
606         gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
607
608         /* Free */
609         g_list_free (buttons);
610         g_free (chars);
611 }
612
613
614
615 static void
616 on_response (GtkDialog *dialog,
617              gint response,
618              gpointer user_data)
619 {
620         GtkWidget *entry, *picker;
621         TnyFolderStore *parent;
622         const gchar *new_name;
623         gboolean exists;
624
625         if (response != GTK_RESPONSE_ACCEPT)
626                 return;
627         
628         /* Get entry */
629         entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
630         picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
631         
632         parent = TNY_FOLDER_STORE (user_data);
633         new_name = gtk_entry_get_text (GTK_ENTRY (entry));
634         exists = FALSE;
635         
636         if (picker != NULL) {
637
638                 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
639         }
640
641         /* Look for another folder with the same name */
642         if (modest_tny_folder_has_subfolder_with_name (parent, 
643                                                        new_name,
644                                                        TRUE)) {
645                 exists = TRUE;
646         }
647         
648         if (!exists) {
649                 if (TNY_IS_ACCOUNT (parent) &&
650                     modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
651                     modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
652                                                                          new_name)) {
653                         exists = TRUE;
654                 }
655         }
656         
657         if (exists) {
658                 
659                 /* Show an error */
660                 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)), 
661                                                 NULL, _CS("ckdg_ib_folder_already_exists"));
662                 /* Select the text */
663                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
664                 gtk_widget_grab_focus (entry);
665                 /* Do not close the dialog */
666                 g_signal_stop_emission_by_name (dialog, "response");
667         }
668
669 }
670
671 typedef struct _FolderChooserData {
672         TnyFolderStore *store;
673         GtkWidget *dialog;
674 } FolderChooserData;
675
676 static void
677 folder_chooser_activated (ModestFolderView *folder_view,
678                           TnyFolderStore *folder,
679                           FolderChooserData *userdata)
680 {
681         userdata->store = folder;
682         gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
683 }
684
685 static TnyFolderStore *
686 folder_chooser_dialog_run (ModestFolderView *original)
687 {
688         GtkWidget *folder_view;
689         FolderChooserData userdata = {NULL, NULL};
690         GtkWidget *pannable;
691         const gchar *visible_id = NULL;
692
693         userdata.dialog = hildon_dialog_new ();
694         pannable = hildon_pannable_area_new ();
695         folder_view = modest_platform_create_folder_view (NULL);
696         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
697                                        MODEST_FOLDER_VIEW_FILTER_CAN_HAVE_FOLDERS);
698
699         modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original), 
700                                        MODEST_FOLDER_VIEW (folder_view));
701
702         visible_id = 
703                 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
704         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
705                                                                      visible_id);
706
707         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
708         gtk_container_add (GTK_CONTAINER (pannable), folder_view);
709         gtk_widget_set_size_request (pannable, -1, 320);
710
711         gtk_widget_show (folder_view);
712         gtk_widget_show (pannable);
713         gtk_widget_show (userdata.dialog);
714         g_signal_connect (G_OBJECT (folder_view), "folder-activated", 
715                           G_CALLBACK (folder_chooser_activated), 
716                           (gpointer) &userdata);
717
718         gtk_dialog_run (GTK_DIALOG (userdata.dialog));
719         gtk_widget_destroy (userdata.dialog);
720
721         return userdata.store;
722 }
723
724 static gchar *
725 folder_store_get_display_name (TnyFolderStore *store)
726 {
727         if (TNY_IS_ACCOUNT (store)) {
728                 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
729         } else {
730                 gchar *fname;
731                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
732
733                 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
734                 type = tny_folder_get_folder_type (TNY_FOLDER (store));
735                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
736                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
737                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
738                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
739                                 g_free (fname);
740                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
741                         }
742                 } else {
743                         /* Sometimes an special folder is reported by the server as
744                            NORMAL, like some versions of Dovecot */
745                         if (type == TNY_FOLDER_TYPE_NORMAL ||
746                             type == TNY_FOLDER_TYPE_UNKNOWN) {
747                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
748                         }
749                 }
750
751                 if (type == TNY_FOLDER_TYPE_INBOX) {
752                         g_free (fname);
753                         fname = g_strdup (_("mcen_me_folder_inbox"));
754                 }
755                 return fname;
756         }
757 }
758
759 static void
760 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
761 {
762         gchar *name;
763
764         if (store == NULL) {
765                 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
766         } else {
767                 GdkPixbuf *pixbuf;
768                 const gchar *icon_name = NULL;
769
770                 g_object_ref (store);
771                 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, 
772                                         store, (GDestroyNotify) g_object_unref);
773                 name = folder_store_get_display_name (store);
774                 hildon_button_set_value (HILDON_BUTTON (button), name);
775                 g_free (name);
776
777                 /* Select icon */
778                 if (TNY_IS_ACCOUNT (store)) {
779                         if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
780                             icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
781                         else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
782                                 icon_name = MODEST_FOLDER_ICON_MMC;
783                         else
784                                 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
785                 } else {
786                         if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
787                                 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
788                                 switch (type) {
789                                 case TNY_FOLDER_TYPE_INBOX:
790                                         icon_name = MODEST_FOLDER_ICON_INBOX;
791                                         break;
792                                 default:
793                                         icon_name = MODEST_FOLDER_ICON_ACCOUNT;
794                                 }
795                         } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)))
796                                 icon_name = MODEST_FOLDER_ICON_NORMAL;
797                         else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store)))
798                                 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
799                 }
800
801                 /* Set icon */
802                 pixbuf = modest_platform_get_icon (icon_name, MODEST_ICON_SIZE_SMALL);
803
804                 if (pixbuf) {
805                         hildon_button_set_image (HILDON_BUTTON (button),
806                                                  gtk_image_new_from_pixbuf (pixbuf));
807                         g_object_unref (pixbuf);
808                 }
809         }
810 }
811
812 static void
813 folder_picker_clicked (GtkButton *button,
814                        ModestFolderView *folder_view)
815 {
816         TnyFolderStore *store;
817
818         store = folder_chooser_dialog_run (folder_view);
819         if (store) {
820                 folder_picker_set_store (GTK_BUTTON (button), store);
821         }
822 }
823
824 static GtkWidget *
825 folder_picker_new (ModestFolderView *folder_view, TnyFolderStore *suggested)
826 {
827         GtkWidget *button;
828
829         button = hildon_button_new (MODEST_EDITABLE_SIZE,
830                                     HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
831
832         hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
833
834         if (suggested) {
835                 folder_picker_set_store (GTK_BUTTON (button), suggested);
836         }
837
838         g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (folder_picker_clicked), folder_view);
839
840         return button;
841 }
842
843
844 static gint
845 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
846                                           TnyFolderStore *suggested_parent,
847                                           const gchar *dialog_title,
848                                           const gchar *label_text,
849                                           const gchar *suggested_name,
850                                           gboolean show_name,
851                                           gboolean show_parent,
852                                           gchar **folder_name,
853                                           TnyFolderStore **parent)
854 {
855         GtkWidget *accept_btn = NULL; 
856         GtkWidget *dialog, *entry = NULL, *label_entry = NULL,  *label_location = NULL, *hbox;
857         GtkWidget *account_picker = NULL;
858         GList *buttons = NULL;
859         gint result;
860         GtkSizeGroup *sizegroup;
861         ModestFolderView *folder_view;
862         ModestWindow *folder_window;
863         ModestHildon2WindowMgr *window_mgr;
864
865         window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
866         folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
867         g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
868
869         folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
870
871         /* Ask the user for the folder name */
872         dialog = gtk_dialog_new_with_buttons (dialog_title,
873                                               parent_window,
874                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
875                                               _FM("ckdg_bd_new_folder_dialog_ok"),
876                                               GTK_RESPONSE_ACCEPT,
877                                               NULL);
878
879         /* Add accept button (with unsensitive handler) */
880         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
881         accept_btn = GTK_WIDGET (buttons->data);
882
883         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
884
885         if (show_name) {
886                 label_entry = gtk_label_new (label_text);
887                 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
888                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
889
890                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
891                 gtk_size_group_add_widget (sizegroup, label_entry);
892
893                 if (suggested_name)
894                         gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
895                 else
896                         gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
897                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
898                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
899                                                 g_utf8_strlen (_("mcen_ia_default_folder_name"), -1)));
900                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
901         }
902
903         if (show_parent) {
904
905                 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
906
907                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
908                 gtk_size_group_add_widget (sizegroup, label_location);
909
910                 account_picker = folder_picker_new (folder_view, suggested_parent);
911         }
912
913         g_object_unref (sizegroup);
914
915         /* Connect to the response method to avoid closing the dialog
916            when an invalid name is selected*/
917         g_signal_connect (dialog,
918                           "response",
919                           G_CALLBACK (on_response),
920                           suggested_parent);
921
922         if (show_name) {
923                 /* Track entry changes */
924                 g_signal_connect (entry,
925                                   "insert-text",
926                                   G_CALLBACK (entry_insert_text),
927                                   dialog);
928                 g_signal_connect (entry,
929                                   "changed",
930                                   G_CALLBACK (entry_changed),
931                                   dialog);
932         }
933
934
935         /* Some locales like pt_BR need this to get the full window
936            title shown */
937         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
938
939         /* Create the hbox */
940         if (show_name) {
941                 hbox = gtk_hbox_new (FALSE, 12);
942                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
943                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
944
945                 /* Add hbox to dialog */
946                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
947                                     hbox, FALSE, FALSE, 0);
948                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
949         }
950
951         if (show_parent) {
952                 hbox = gtk_hbox_new (FALSE, 12);
953                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
954                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
955
956                 /* Add hbox to dialog */
957                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
958                                     hbox, FALSE, FALSE, 0);
959                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
960         }
961         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
962                                      GTK_WINDOW (dialog), parent_window);
963         gtk_widget_show_all (GTK_WIDGET(dialog));
964
965         result = gtk_dialog_run (GTK_DIALOG(dialog));
966         if (result == GTK_RESPONSE_ACCEPT) {
967                 if (show_name)
968                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
969                 if (show_parent) {
970                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
971                         if (*parent)
972                                 g_object_ref (*parent);
973                 }
974         }
975
976         gtk_widget_destroy (dialog);
977
978         while (gtk_events_pending ())
979                 gtk_main_iteration ();
980
981         return result;
982 }
983
984 gint
985 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
986                                        TnyFolderStore *suggested_folder,
987                                        gchar *suggested_name,
988                                        gchar **folder_name,
989                                        TnyFolderStore **parent_folder)
990 {
991         gchar *real_suggested_name = NULL, *tmp = NULL;
992         gint result;
993         ModestTnyAccountStore *acc_store;
994         TnyAccount *account;
995
996         if(suggested_name == NULL)
997         {
998                 const gchar *default_name = _("mcen_ia_default_folder_name");
999                 unsigned int i;
1000                 gchar num_str[3];
1001
1002                 for(i = 0; i < 100; ++ i) {
1003                         gboolean exists = FALSE;
1004
1005                         sprintf(num_str, "%.2u", i);
1006
1007                         if (i == 0)
1008                                 real_suggested_name = g_strdup (default_name);
1009                         else
1010                                 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
1011                                                                        num_str);
1012                         exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
1013                                                                             real_suggested_name,
1014                                                                             TRUE);
1015
1016                         if (!exists)
1017                                 break;
1018
1019                         g_free (real_suggested_name);
1020                 }
1021
1022                 /* Didn't find a free number */
1023                 if (i == 100)
1024                         real_suggested_name = g_strdup (default_name);
1025         } else {
1026                 real_suggested_name = suggested_name;
1027         }
1028
1029         /* In hildon 2.2 we always suggest the archive folder as parent */
1030         acc_store = modest_runtime_get_account_store ();
1031         account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1032         if (account) {
1033                 suggested_folder = (TnyFolderStore *)
1034                         modest_tny_account_get_special_folder (account, 
1035                                                                TNY_FOLDER_TYPE_ARCHIVE);
1036                 g_object_unref (account);
1037                 account = NULL;
1038         }
1039
1040         /* If there is not archive folder then fallback to local folders account */ 
1041         if (!suggested_folder)
1042                 suggested_folder = (TnyFolderStore *)
1043                         modest_tny_account_store_get_local_folders_account (acc_store);
1044
1045         tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
1046         result = modest_platform_run_folder_common_dialog (parent_window, 
1047                                                            suggested_folder,
1048                                                            _("mcen_ti_new_folder"),
1049                                                            tmp,
1050                                                            real_suggested_name,
1051                                                            TRUE,
1052                                                            TRUE,
1053                                                            folder_name,
1054                                                            parent_folder);
1055         g_free (tmp);
1056
1057         if (suggested_name == NULL)
1058                 g_free(real_suggested_name);
1059
1060         return result;
1061 }
1062
1063 gint
1064 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1065                                           TnyFolderStore *parent_folder,
1066                                           const gchar *suggested_name,
1067                                           gchar **folder_name)
1068 {
1069         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1070
1071         return modest_platform_run_folder_common_dialog (parent_window, 
1072                                                          parent_folder,
1073                                                          _HL("ckdg_ti_rename_folder"),
1074                                                          _HL("ckdg_fi_rename_name"),
1075                                                          suggested_name,
1076                                                          TRUE,
1077                                                          FALSE,
1078                                                          folder_name,
1079                                                          NULL);
1080 }
1081
1082
1083
1084 static void
1085 on_destroy_dialog (GtkWidget *dialog)
1086 {
1087         /* This could happen when the dialogs get programatically
1088            hidden or destroyed (for example when closing the
1089            application while a dialog is being shown) */
1090         if (!GTK_IS_WIDGET (dialog))
1091                 return;
1092
1093         gtk_widget_destroy (dialog);
1094
1095         if (gtk_events_pending ())
1096                 gtk_main_iteration ();
1097 }
1098
1099 gint
1100 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1101                                          const gchar *message)
1102 {
1103         GtkWidget *dialog;
1104         gint response;
1105         
1106         dialog = hildon_note_new_confirmation (parent_window, message);
1107         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1108                                      GTK_WINDOW (dialog), parent_window);
1109
1110         response = gtk_dialog_run (GTK_DIALOG (dialog));
1111
1112         on_destroy_dialog (dialog);
1113
1114         return response;
1115 }
1116
1117 gint
1118 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1119                                                       const gchar *message,
1120                                                       const gchar *button_accept,
1121                                                       const gchar *button_cancel)
1122 {
1123         GtkWidget *dialog;
1124         gint response;
1125         
1126         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1127                                                            button_accept, GTK_RESPONSE_ACCEPT,
1128                                                            button_cancel, GTK_RESPONSE_CANCEL,
1129                                                            NULL);
1130
1131         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1132                                      GTK_WINDOW (dialog), parent_window);
1133
1134         response = gtk_dialog_run (GTK_DIALOG (dialog));
1135
1136         on_destroy_dialog (dialog);
1137
1138         return response;
1139 }
1140         
1141 void
1142 modest_platform_run_information_dialog (GtkWindow *parent_window,
1143                                         const gchar *message,
1144                                         gboolean block)
1145 {
1146         GtkWidget *note;
1147         
1148         note = hildon_note_new_information (parent_window, message);
1149         if (block)
1150                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1151                                              GTK_WINDOW (note), parent_window);
1152         
1153         if (block) {
1154                 gtk_dialog_run (GTK_DIALOG (note));
1155         
1156                 on_destroy_dialog (note);
1157         } else {
1158                 g_signal_connect_swapped (note,
1159                                           "response", 
1160                                           G_CALLBACK (on_destroy_dialog),
1161                                           note);
1162
1163                 gtk_widget_show_all (note);
1164         }
1165 }
1166
1167 typedef struct _ConnectAndWaitData {
1168         GMutex *mutex;
1169         GMainLoop *wait_loop;
1170         gboolean has_callback;
1171         gulong handler;
1172 } ConnectAndWaitData;
1173
1174
1175 static void
1176 quit_wait_loop (TnyAccount *account,
1177                 ConnectAndWaitData *data) 
1178 {
1179         /* Set the has_callback to TRUE (means that the callback was
1180            executed and wake up every code waiting for cond to be
1181            TRUE */
1182         g_mutex_lock (data->mutex);
1183         data->has_callback = TRUE;
1184         if (data->wait_loop)
1185                 g_main_loop_quit (data->wait_loop);
1186         g_mutex_unlock (data->mutex);
1187 }
1188
1189 static void
1190 on_connection_status_changed (TnyAccount *account, 
1191                               TnyConnectionStatus status,
1192                               gpointer user_data)
1193 {
1194         TnyConnectionStatus conn_status;
1195         ConnectAndWaitData *data;
1196                         
1197         /* Ignore if reconnecting or disconnected */
1198         conn_status = tny_account_get_connection_status (account);
1199         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1200             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1201                 return;
1202
1203         /* Remove the handler */
1204         data = (ConnectAndWaitData *) user_data;
1205         g_signal_handler_disconnect (account, data->handler);
1206
1207         /* Quit from wait loop */
1208         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1209 }
1210
1211 static void
1212 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
1213                                     gboolean canceled, 
1214                                     GError *err, 
1215                                     gpointer user_data)
1216 {
1217         /* Quit from wait loop */
1218         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1219 }
1220
1221 gboolean 
1222 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1223                                   TnyAccount *account)
1224 {
1225         ConnectAndWaitData *data = NULL;
1226         gboolean device_online;
1227         TnyDevice *device;
1228         TnyConnectionStatus conn_status;
1229         gboolean user_requested;
1230         
1231         device = modest_runtime_get_device();
1232         device_online = tny_device_is_online (device);
1233
1234         /* Whether the connection is user requested or automatically
1235            requested, for example via D-Bus */
1236         user_requested = (parent_window) ? TRUE : FALSE;
1237
1238         /* If there is no account check only the device status */
1239         if (!account) {
1240                 if (device_online)
1241                         return TRUE;
1242                 else
1243                         return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1244                                                                NULL, user_requested);
1245         }
1246
1247         /* Return if the account is already connected */
1248         conn_status = tny_account_get_connection_status (account);
1249         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1250                 return TRUE;
1251
1252         /* Create the helper */
1253         data = g_slice_new0 (ConnectAndWaitData);
1254         data->mutex = g_mutex_new ();
1255         data->has_callback = FALSE;
1256
1257         /* Connect the device */
1258         if (!device_online) {
1259                 /* Track account connection status changes */
1260                 data->handler = g_signal_connect (account, "connection-status-changed",
1261                                                   G_CALLBACK (on_connection_status_changed),
1262                                                   data);
1263                 /* Try to connect the device */
1264                 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1265                                                                 NULL, user_requested);
1266
1267                 /* If the device connection failed then exit */
1268                 if (!device_online && data->handler)
1269                         goto frees;
1270         } else {
1271                 /* Force a reconnection of the account */
1272                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1273                                               on_tny_camel_account_set_online_cb, data);
1274         }
1275
1276         /* Wait until the callback is executed */
1277         g_mutex_lock (data->mutex);
1278         if (!data->has_callback) {
1279                 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1280                 gdk_threads_leave ();
1281                 g_mutex_unlock (data->mutex);
1282                 g_main_loop_run (data->wait_loop);
1283                 g_mutex_lock (data->mutex);
1284                 gdk_threads_enter ();
1285         }
1286         g_mutex_unlock (data->mutex);
1287
1288  frees:
1289         if (data) {
1290                 if (g_signal_handler_is_connected (account, data->handler))
1291                         g_signal_handler_disconnect (account, data->handler);
1292                 g_mutex_free (data->mutex);
1293                 g_main_loop_unref (data->wait_loop);
1294                 g_slice_free (ConnectAndWaitData, data);
1295         }
1296
1297         conn_status = tny_account_get_connection_status (account);
1298         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1299 }
1300
1301 gboolean 
1302 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1303 {
1304         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1305                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1306                         /* This must be a maildir account, which does not require a connection: */
1307                         return TRUE;
1308                 }
1309         }
1310
1311         return modest_platform_connect_and_wait (parent_window, account);
1312 }
1313
1314 gboolean 
1315 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1316 {
1317         if (!folder_store)
1318                 return TRUE; /* Maybe it is something local. */
1319                 
1320         gboolean result = TRUE;
1321         if (TNY_IS_FOLDER (folder_store)) {
1322                 /* Get the folder's parent account: */
1323                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1324                 if (account != NULL) {
1325                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1326                         g_object_unref (account);
1327                 }
1328         } else if (TNY_IS_ACCOUNT (folder_store)) {
1329                 /* Use the folder store as an account: */
1330                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1331         }
1332
1333         return result;
1334 }
1335
1336 GtkWidget *
1337 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1338 {
1339         GtkWidget *dialog;
1340
1341         dialog = modest_hildon2_sort_dialog_new (parent_window);
1342
1343         return dialog;
1344 }
1345
1346
1347 gboolean 
1348 modest_platform_set_update_interval (guint minutes)
1349 {
1350 #ifdef MODEST_HAVE_LIBALARM
1351         
1352         ModestConf *conf = modest_runtime_get_conf ();
1353         if (!conf)
1354                 return FALSE;
1355                 
1356         cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1357
1358         /* Delete any existing alarm,
1359          * because we will replace it: */
1360         if (alarm_cookie) {
1361                 if (alarmd_event_del(alarm_cookie) != 0)
1362                         g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1363                 alarm_cookie = 0;
1364                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1365         }
1366         
1367         /* 0 means no updates: */
1368         if (minutes == 0)
1369                 return TRUE;
1370         
1371      
1372         /* Register alarm: */
1373         
1374         /* Set the interval in alarm_event_t structure: */
1375         alarm_event_t *event = alarm_event_create ();
1376         alarm_event_add_actions (event, 1);
1377         alarm_action_t *action = alarm_event_get_action (event, 0);
1378         alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1379         event->alarm_time = minutes * 60; /* seconds */
1380         
1381         /* Set recurrence every few minutes: */
1382         event->recur_secs = minutes*60;
1383         event->recur_count = -1; /* Means infinite */
1384
1385         /* Specify what should happen when the alarm happens:
1386          * It should call this D-Bus method: */
1387          
1388         action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1389         action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1390         action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1391         action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1392         action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1393
1394         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1395          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1396          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1397          * This is why we want to use the Alarm API instead of just g_timeout_add().
1398          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1399          * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1400          */
1401         event->flags = ALARM_EVENT_CONNECTED;
1402         
1403         alarm_cookie = alarmd_event_add (event);
1404
1405         /* now, free it */
1406         alarm_event_delete (event);
1407         
1408         /* Store the alarm ID in GConf, so we can remove it later:
1409          * This is apparently valid between application instances. */
1410         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1411         
1412         if (!alarm_cookie) {
1413             /* Error */
1414             g_debug ("Error setting alarm event. \n");
1415             
1416             return FALSE;
1417         }
1418 #endif /* MODEST_HAVE_LIBALARM */       
1419         return TRUE;
1420 }
1421
1422 void
1423 modest_platform_push_email_notification(void)
1424 {
1425         gboolean screen_on, app_in_foreground;
1426
1427         /* Get the window status */
1428         app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1429
1430         screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1431
1432         /* If the screen is on and the app is in the
1433            foreground we don't show anything */
1434         if (!(screen_on && app_in_foreground)) {
1435
1436                 _modest_platform_play_email_tone ();
1437
1438                 /* Activate LED. This must be deactivated by
1439                    modest_platform_remove_new_mail_notifications */
1440 #ifdef MODEST_HAVE_MCE
1441                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1442                                      MCE_SERVICE,
1443                                      MCE_REQUEST_PATH,
1444                                      MCE_REQUEST_IF,
1445                                      MCE_ACTIVATE_LED_PATTERN,
1446                                      NULL,
1447                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1448                                      DBUS_TYPE_INVALID);
1449 #endif
1450         }
1451 }
1452
1453 void 
1454 modest_platform_on_new_headers_received (TnyList *header_list,
1455                                          gboolean show_visual)
1456 {
1457         g_return_if_fail (TNY_IS_LIST(header_list));
1458
1459         if (tny_list_get_length(header_list) == 0) {
1460                 g_warning ("%s: header list is empty", __FUNCTION__);
1461                 return;
1462         }
1463         
1464         if (!show_visual) {
1465                 modest_platform_push_email_notification ();
1466                 /* We do a return here to avoid indentation with an else */
1467                 return;
1468         }
1469
1470 #ifdef MODEST_HAVE_HILDON_NOTIFY
1471         HildonNotification *notification;
1472         TnyIterator *iter;
1473         GSList *notifications_list = NULL;
1474
1475         /* Get previous notifications ids */
1476         notifications_list = modest_conf_get_list (modest_runtime_get_conf (), 
1477                                                    MODEST_CONF_NOTIFICATION_IDS, 
1478                                                    MODEST_CONF_VALUE_INT, NULL);
1479
1480         iter = tny_list_create_iterator (header_list);
1481         while (!tny_iterator_is_done (iter)) {
1482                 gchar *url = NULL, *display_address = NULL,  *summary = NULL;
1483                 const gchar *display_date;
1484                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1485                 TnyFolder *folder = tny_header_get_folder (header);
1486                 gboolean first_notification = TRUE;
1487                 gint notif_id;
1488                 gchar *str;
1489                 ModestDatetimeFormatter *datetime_formatter;
1490
1491                 /* constant string, don't free */
1492                 datetime_formatter = modest_datetime_formatter_new ();
1493                 display_date = modest_datetime_formatter_display_datetime (datetime_formatter,
1494                                                                            tny_header_get_date_received (header));
1495                 g_object_unref (datetime_formatter);
1496
1497                 display_address = tny_header_dup_from (header);
1498                 /* string is changed in-place */
1499                 modest_text_utils_get_display_address (display_address);
1500
1501                 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1502                 str = tny_header_dup_subject (header);
1503                 notification = hildon_notification_new (summary,
1504                                                         str,
1505                                                         "qgn_list_messagin",
1506                                                         "email-message");
1507                 g_free (str);
1508                 /* Create the message URL */
1509                 str = tny_header_dup_uid (header);
1510                 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder), 
1511                                        str);
1512                 g_free (str);
1513
1514                 hildon_notification_add_dbus_action(notification,
1515                                                     "default",
1516                                                     "Cancel",
1517                                                     MODEST_DBUS_SERVICE,
1518                                                     MODEST_DBUS_OBJECT,
1519                                                     MODEST_DBUS_IFACE,
1520                                                     MODEST_DBUS_METHOD_OPEN_MESSAGE,
1521                                                     G_TYPE_STRING, url,
1522                                                     -1);
1523
1524                 /* Play sound if the user wants. Show the LED
1525                    pattern. Show and play just one */
1526                 if (G_UNLIKELY (first_notification)) {
1527                         gchar *active_profile;
1528                         gchar *mail_tone;
1529                         gchar *mail_volume;
1530                         gint mail_volume_int;
1531
1532                         first_notification = FALSE;
1533
1534                         active_profile = profile_get_profile ();
1535                         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1536                         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1537                         mail_volume_int = profile_parse_int (mail_volume);
1538
1539                         if (mail_volume_int > 0)
1540                                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1541                                                                     "sound-file", mail_tone);
1542
1543                         g_free (mail_volume);
1544                         g_free (mail_tone);
1545                         g_free (active_profile);
1546
1547                         /* Set the led pattern */
1548                         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1549                                                             "dialog-type", 4);
1550                         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1551                                                             "led-pattern",
1552                                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);                  
1553                 }
1554
1555                 /* Notify. We need to do this in an idle because this function
1556                    could be called from a thread */
1557                 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1558
1559                 /* Save id in the list */
1560                 g_object_get(G_OBJECT(notification), "id", &notif_id, NULL);
1561                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1562                 /* We don't listen for the "closed" signal, because we
1563                    don't care about if the notification was removed or
1564                    not to store the list in gconf */
1565         
1566                 /* Free & carry on */
1567                 g_free (display_address);
1568                 g_free (summary);
1569                 g_free (url);
1570                 g_object_unref (folder);
1571                 g_object_unref (header);
1572                 tny_iterator_next (iter);
1573         }
1574         g_object_unref (iter);
1575
1576         /* Save the ids */
1577         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1578                               notifications_list, MODEST_CONF_VALUE_INT, NULL);
1579
1580         g_slist_free (notifications_list);
1581         
1582 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1583 }
1584
1585 void
1586 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1587 {
1588         if (only_visuals) {
1589 #ifdef MODEST_HAVE_MCE
1590                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1591                                      MCE_SERVICE,
1592                                      MCE_REQUEST_PATH,
1593                                      MCE_REQUEST_IF,
1594                                      MCE_DEACTIVATE_LED_PATTERN,
1595                                      NULL,
1596                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1597                                      DBUS_TYPE_INVALID);
1598 #endif
1599                 return;
1600         }
1601
1602 #ifdef MODEST_HAVE_HILDON_NOTIFY
1603         GSList *notif_list = NULL;
1604
1605         /* Get previous notifications ids */
1606         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1607                                            MODEST_CONF_NOTIFICATION_IDS, 
1608                                            MODEST_CONF_VALUE_INT, NULL);
1609
1610         while (notif_list) {
1611                 gint notif_id;
1612                 NotifyNotification *notif;
1613
1614                 /* Nasty HACK to remove the notifications, set the id
1615                    of the existing ones and then close them */
1616                 notif_id = GPOINTER_TO_INT(notif_list->data);
1617                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1618                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1619
1620                 /* Close the notification, note that some ids could be
1621                    already invalid, but we don't care because it does
1622                    not fail */
1623                 notify_notification_close(notif, NULL);
1624                 g_object_unref(notif);
1625
1626                 /* Delete the link, it's like going to the next */
1627                 notif_list = g_slist_delete_link (notif_list, notif_list);
1628         }
1629
1630         /* Save the ids */
1631         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1632                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1633
1634         g_slist_free (notif_list);
1635
1636 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1637 }
1638
1639
1640
1641 GtkWidget * 
1642 modest_platform_get_global_settings_dialog ()
1643 {
1644         return modest_hildon2_global_settings_dialog_new ();
1645 }
1646
1647 void
1648 modest_platform_show_help (GtkWindow *parent_window, 
1649                            const gchar *help_id)
1650 {
1651         return;
1652 }
1653
1654 void 
1655 modest_platform_show_search_messages (GtkWindow *parent_window)
1656 {
1657         osso_return_t result = OSSO_ERROR;
1658         
1659         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1660                                              "osso_global_search",
1661                                              "search_email", NULL, DBUS_TYPE_INVALID);
1662
1663         if (result != OSSO_OK) {
1664                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1665         }
1666 }
1667
1668 void 
1669 modest_platform_show_addressbook (GtkWindow *parent_window)
1670 {
1671         osso_return_t result = OSSO_ERROR;
1672
1673         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1674                                              "osso_addressbook",
1675                                              "top_application", NULL, DBUS_TYPE_INVALID);
1676
1677         if (result != OSSO_OK) {
1678                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1679         }
1680 }
1681
1682 GtkWidget *
1683 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1684 {
1685         GtkWidget *widget = modest_folder_view_new (query);
1686
1687         /* Show one account by default */
1688         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1689                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1690
1691         /* Restore settings */
1692         modest_widget_memory_restore (modest_runtime_get_conf(), 
1693                                       G_OBJECT (widget),
1694                                       MODEST_CONF_FOLDER_VIEW_KEY);
1695
1696         return widget;
1697 }
1698
1699 void
1700 banner_finish (gpointer data, GObject *object)
1701 {
1702         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1703         modest_window_mgr_unregister_banner (mgr);
1704         g_object_unref (mgr);
1705 }
1706
1707 void 
1708 modest_platform_information_banner (GtkWidget *parent,
1709                                     const gchar *icon_name,
1710                                     const gchar *text)
1711 {
1712         GtkWidget *banner, *banner_parent = NULL;
1713         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1714
1715         if (modest_window_mgr_get_num_windows (mgr) == 0)
1716                 return;
1717
1718         if (parent && GTK_IS_WINDOW (parent)) {
1719                 /* If the window is the active one then show the
1720                    banner on top of this window */
1721                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1722                         banner_parent = parent;
1723                 /* If the window is not the topmost but it's visible
1724                    (it's minimized for example) then show the banner
1725                    with no parent */ 
1726                 else if (GTK_WIDGET_VISIBLE (parent))
1727                         banner_parent = NULL;
1728                 /* If the window is hidden (like the main window when
1729                    running in the background) then do not show
1730                    anything */
1731                 else 
1732                         return;
1733         }
1734
1735
1736         banner = hildon_banner_show_information (banner_parent, icon_name, text);
1737
1738         modest_window_mgr_register_banner (mgr);
1739         g_object_ref (mgr);
1740         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1741 }
1742
1743 void
1744 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1745                                                  const gchar *icon_name,
1746                                                  const gchar *text,
1747                                                  gint timeout)
1748 {
1749         GtkWidget *banner;
1750
1751         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1752                 return;
1753
1754         banner = hildon_banner_show_information (parent, icon_name, text);
1755         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1756 }
1757
1758 GtkWidget *
1759 modest_platform_animation_banner (GtkWidget *parent,
1760                                   const gchar *animation_name,
1761                                   const gchar *text)
1762 {
1763         GtkWidget *inf_note = NULL;
1764
1765         g_return_val_if_fail (text != NULL, NULL);
1766
1767         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1768                 return NULL;
1769
1770         /* If the parent is not visible then do not show */
1771         if (parent && !GTK_WIDGET_VISIBLE (parent))
1772                 return NULL;
1773
1774         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1775
1776         return inf_note;
1777 }
1778
1779 typedef struct
1780 {
1781         GMainLoop* loop;
1782         TnyAccount *account;
1783         gboolean is_online;
1784         gint count_tries;
1785 } CheckAccountIdleData;
1786
1787 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1788
1789 static gboolean 
1790 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1791 {
1792         gboolean stop_trying = FALSE;
1793         g_return_val_if_fail (data && data->account, FALSE);
1794         
1795         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1796                 tny_account_get_connection_status (data->account));     
1797         
1798         if (data && data->account && 
1799                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1800                  * after which the account is likely to be usable, or never likely to be usable soon: */
1801                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1802         {
1803                 data->is_online = TRUE;
1804                 
1805                 stop_trying = TRUE;
1806         } else {
1807                 /* Give up if we have tried too many times: */
1808                 if (data->count_tries >= NUMBER_OF_TRIES) {
1809                         stop_trying = TRUE;
1810                 } else {
1811                         /* Wait for another timeout: */
1812                         ++(data->count_tries);
1813                 }
1814         }
1815         
1816         if (stop_trying) {
1817                 /* Allow the function that requested this idle callback to continue: */
1818                 if (data->loop)
1819                         g_main_loop_quit (data->loop);
1820                         
1821                 if (data->account)
1822                         g_object_unref (data->account);
1823                 
1824                 return FALSE; /* Don't call this again. */
1825         } else {
1826                 return TRUE; /* Call this timeout callback again. */
1827         }
1828 }
1829
1830 /* Return TRUE immediately if the account is already online,
1831  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1832  * soon as the account is online, or FALSE if the account does 
1833  * not become online in the NUMBER_OF_TRIES seconds.
1834  * This is useful when the D-Bus method was run immediately after 
1835  * the application was started (when using D-Bus activation), 
1836  * because the account usually takes a short time to go online.
1837  * The return value is maybe not very useful.
1838  */
1839 gboolean
1840 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1841 {
1842         gboolean is_online;
1843
1844         g_return_val_if_fail (account, FALSE);
1845
1846         if (!tny_device_is_online (modest_runtime_get_device())) {
1847                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1848                 return FALSE;
1849         }
1850
1851         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1852          * so we avoid wait unnecessarily: */
1853         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1854                 return TRUE;
1855
1856         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1857          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1858          * we want to avoid. */
1859         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1860                 return TRUE;
1861                 
1862         /* This blocks on the result: */
1863         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1864         data->is_online = FALSE;
1865         data->account = account;
1866         g_object_ref (data->account);
1867         data->count_tries = 0;
1868                 
1869         GMainContext *context = NULL; /* g_main_context_new (); */
1870         data->loop = g_main_loop_new (context, FALSE /* not running */);
1871
1872         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1873
1874         /* This main loop will run until the idle handler has stopped it: */
1875         g_main_loop_run (data->loop);
1876
1877         g_main_loop_unref (data->loop);
1878         /* g_main_context_unref (context); */
1879
1880         is_online = data->is_online;
1881         g_slice_free (CheckAccountIdleData, data);
1882         
1883         return is_online;       
1884 }
1885
1886
1887
1888 static void
1889 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1890 {
1891         /* GTK_RESPONSE_HELP means we need to show the certificate */
1892         if (response_id == GTK_RESPONSE_APPLY) {
1893                 GtkWidget *note;
1894                 gchar *msg;
1895                 
1896                 /* Do not close the dialog */
1897                 g_signal_stop_emission_by_name (dialog, "response");
1898
1899                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1900                 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1901                 gtk_dialog_run (GTK_DIALOG(note));
1902                 gtk_widget_destroy (note);
1903         }
1904 }
1905
1906
1907 gboolean
1908 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1909                                                      const gchar *certificate)
1910 {
1911         GtkWidget *note;
1912         gint response;
1913         ModestWindow *win;
1914         HildonWindowStack *stack;
1915
1916         stack = hildon_window_stack_get_default ();
1917         win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1918
1919         if (!win) {
1920           g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1921                            __FUNCTION__);
1922                 return FALSE;
1923         }
1924
1925         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1926                                            server_name);
1927
1928         /* We use GTK_RESPONSE_APPLY because we want the button in the
1929            middle of OK and CANCEL the same as the browser does for
1930            example. With GTK_RESPONSE_HELP the view button is aligned
1931            to the left while the other two to the right */
1932         note = hildon_note_new_confirmation_add_buttons  (
1933                 NULL,
1934                 question,
1935                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
1936                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
1937                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1938                 NULL, NULL);
1939
1940         g_signal_connect (G_OBJECT(note), "response", 
1941                           G_CALLBACK(on_cert_dialog_response),
1942                           (gpointer) certificate);
1943
1944         response = gtk_dialog_run(GTK_DIALOG(note));
1945
1946         on_destroy_dialog (note);
1947         g_free (question);
1948
1949         return response == GTK_RESPONSE_OK;
1950 }
1951
1952 gboolean
1953 modest_platform_run_alert_dialog (const gchar* prompt,
1954                                   gboolean is_question)
1955 {
1956         ModestWindow *top_win;
1957         HildonWindowStack *stack;
1958
1959         stack = hildon_window_stack_get_default ();
1960         top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1961
1962         if (!top_win) {
1963                 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1964                            __FUNCTION__);
1965                 return FALSE;
1966         }
1967
1968         gboolean retval = TRUE;
1969         if (is_question) {
1970                 /* The Tinymail documentation says that we should show Yes and No buttons,
1971                  * when it is a question.
1972                  * Obviously, we need tinymail to use more specific error codes instead,
1973                  * so we know what buttons to show. */
1974                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win), 
1975                                                                               prompt));
1976                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1977                                              GTK_WINDOW (dialog), GTK_WINDOW (top_win));
1978
1979                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1980                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1981
1982                 on_destroy_dialog (dialog);
1983         } else {
1984                 /* Just show the error text and use the default response: */
1985                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
1986                                                         prompt, FALSE);
1987         }
1988         return retval;
1989 }
1990
1991 /***************/
1992 typedef struct {
1993         GtkWindow *parent_window;
1994         ModestConnectedPerformer callback;
1995         TnyAccount *account;
1996         gpointer user_data;
1997         gchar *iap;
1998         TnyDevice *device;
1999 } OnWentOnlineInfo;
2000  
2001 static void 
2002 on_went_online_info_free (OnWentOnlineInfo *info)
2003 {
2004         /* And if we cleanup, we DO cleanup  :-)  */
2005         
2006         if (info->device)
2007                 g_object_unref (info->device);
2008         if (info->iap)
2009                 g_free (info->iap);
2010         if (info->parent_window)
2011                 g_object_unref (info->parent_window);
2012         if (info->account)
2013                 g_object_unref (info->account);
2014         
2015         g_slice_free (OnWentOnlineInfo, info);
2016         
2017         /* We're done ... */
2018         
2019         return;
2020 }
2021  
2022 static void
2023 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2024 {
2025         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2026  
2027         /* Now it's really time to callback to the caller. If going online didn't succeed,
2028          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2029          * canceled will be set. Etcetera etcetera. */
2030         
2031         if (info->callback) {
2032                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2033         }
2034         
2035         /* This is our last call, we must cleanup here if we didn't yet do that */
2036         on_went_online_info_free (info);
2037         
2038         return;
2039 }
2040  
2041  
2042 static void
2043 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2044 {
2045         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2046         info->iap = g_strdup (iap_id);
2047         
2048         if (canceled || err || !info->account) {
2049         
2050                 /* If there's a problem or if there's no account (then that's it for us, we callback
2051                  * the caller's callback now. He'll have to handle err or canceled, of course.
2052                  * We are not really online, as the account is not really online here ... */    
2053                 
2054                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2055                  * this info. We don't cleanup err, Tinymail does that! */
2056                 
2057                 if (info->callback) {
2058                         
2059                         /* info->account can be NULL here, this means that the user did not
2060                          * provide a nice account instance. We'll assume that the user knows
2061                          * what he's doing and is happy with just the device going online. 
2062                          * 
2063                          * We can't do magic, we don't know what account the user wants to
2064                          * see going online. So just the device goes online, end of story */
2065                         
2066                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2067                 }
2068                 
2069         } else if (info->account) {
2070                 
2071                 /* If there's no problem and if we have an account, we'll put the account
2072                  * online too. When done, the callback of bringing the account online
2073                  * will callback the caller's callback. This is the most normal case. */
2074  
2075                 info->device = TNY_DEVICE (g_object_ref (device));
2076                 
2077                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2078                                               on_account_went_online, info);
2079                 
2080                 /* The on_account_went_online cb frees up the info, go look if you
2081                  * don't believe me! (so we return here) */
2082                 
2083                 return;
2084         }
2085         
2086         /* We cleanup if we are not bringing the account online too */
2087         on_went_online_info_free (info);
2088  
2089         return; 
2090 }
2091         
2092 void 
2093 modest_platform_connect_and_perform (GtkWindow *parent_window, 
2094                                      gboolean force,
2095                                      TnyAccount *account, 
2096                                      ModestConnectedPerformer callback, 
2097                                      gpointer user_data)
2098 {
2099         gboolean device_online;
2100         TnyDevice *device;
2101         TnyConnectionStatus conn_status;
2102         OnWentOnlineInfo *info;
2103         
2104         device = modest_runtime_get_device();
2105         device_online = tny_device_is_online (device);
2106
2107         /* If there is no account check only the device status */
2108         if (!account) {
2109                 
2110                 if (device_online) {
2111  
2112                         /* We promise to instantly perform the callback, so ... */
2113                         if (callback) {
2114                                 callback (FALSE, NULL, parent_window, account, user_data);
2115                         }
2116                         
2117                 } else {
2118                         
2119                         info = g_slice_new0 (OnWentOnlineInfo);
2120                         
2121                         info->iap = NULL;
2122                         info->device = NULL;
2123                         info->account = NULL;
2124                 
2125                         if (parent_window)
2126                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2127                         else
2128                                 info->parent_window = NULL;
2129                         info->user_data = user_data;
2130                         info->callback = callback;
2131                 
2132                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2133                                                               force, on_conic_device_went_online, 
2134                                                               info);
2135  
2136                         /* We'll cleanup in on_conic_device_went_online */
2137                 }
2138  
2139                 /* The other code has no more reason to run. This is all that we can do for the
2140                  * caller (he should have given us a nice and clean account instance!). We
2141                  * can't do magic, we don't know what account he intends to bring online. So
2142                  * we'll just bring the device online (and await his false bug report). */
2143                 
2144                 return;
2145         }
2146  
2147         
2148         /* Return if the account is already connected */
2149         
2150         conn_status = tny_account_get_connection_status (account);
2151         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2152  
2153                 /* We promise to instantly perform the callback, so ... */
2154                 if (callback) {
2155                         callback (FALSE, NULL, parent_window, account, user_data);
2156                 }
2157                 
2158                 return;
2159         }
2160         
2161         /* Else, we are in a state that requires that we go online before we
2162          * call the caller's callback. */
2163         
2164         info = g_slice_new0 (OnWentOnlineInfo);
2165         
2166         info->device = NULL;
2167         info->iap = NULL;
2168         info->account = TNY_ACCOUNT (g_object_ref (account));
2169         
2170         if (parent_window)
2171                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2172         else
2173                 info->parent_window = NULL;
2174         
2175         /* So we'll put the callback away for later ... */
2176         
2177         info->user_data = user_data;
2178         info->callback = callback;
2179         
2180         if (!device_online) {
2181  
2182                 /* If also the device is offline, then we connect both the device 
2183                  * and the account */
2184                 
2185                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2186                                                       force, on_conic_device_went_online, 
2187                                                       info);
2188                 
2189         } else {
2190                 
2191                 /* If the device is online, we'll just connect the account */
2192                 
2193                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2194                                               on_account_went_online, info);
2195         }
2196  
2197         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2198          * in both situations, go look if you don't believe me! */
2199         
2200         return;
2201 }
2202
2203 void
2204 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2205                                                gboolean force,
2206                                                TnyFolderStore *folder_store, 
2207                                                ModestConnectedPerformer callback, 
2208                                                gpointer user_data)
2209 {
2210         TnyAccount *account = NULL;
2211
2212         if (!folder_store ||
2213             (TNY_IS_MERGE_FOLDER (folder_store) &&
2214              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2215
2216                 /* We promise to instantly perform the callback, so ... */
2217                 if (callback) {
2218                         GError *error = NULL;
2219                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2220                                      "Unable to move or not found folder");
2221                         callback (FALSE, error, parent_window, NULL, user_data);
2222                         g_error_free (error);
2223                 }
2224                 return;
2225
2226         } else if (TNY_IS_FOLDER (folder_store)) {
2227                 /* Get the folder's parent account: */
2228                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2229         } else if (TNY_IS_ACCOUNT (folder_store)) {
2230                 /* Use the folder store as an account: */
2231                 account = TNY_ACCOUNT (g_object_ref (folder_store));
2232         }
2233
2234         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2235                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2236                         /* No need to connect a local account */
2237                         if (callback)
2238                                 callback (FALSE, NULL, parent_window, account, user_data);
2239
2240                         goto clean;
2241                 }
2242         }
2243         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2244
2245  clean:
2246         if (account)
2247                 g_object_unref (account);
2248 }
2249
2250 static void
2251 src_account_connect_performer (gboolean canceled,
2252                                GError *err,
2253                                GtkWindow *parent_window,
2254                                TnyAccount *src_account,
2255                                gpointer user_data)
2256 {
2257         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2258
2259         if (canceled || err) {
2260                 /* If there was any error call the user callback */
2261                 info->callback (canceled, err, parent_window, src_account, info->data);
2262         } else {
2263                 /* Connect the destination account */
2264                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2265                                                                TNY_FOLDER_STORE (info->dst_account),
2266                                                                info->callback, info->data);
2267         }
2268
2269         /* Free the info object */
2270         g_object_unref (info->dst_account);
2271         g_slice_free (DoubleConnectionInfo, info);
2272 }
2273
2274
2275 void 
2276 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2277                                             gboolean force,
2278                                             TnyFolderStore *folder_store,
2279                                             DoubleConnectionInfo *connect_info)
2280 {
2281         modest_platform_connect_if_remote_and_perform(parent_window, 
2282                                                       force,
2283                                                       folder_store, 
2284                                                       src_account_connect_performer, 
2285                                                       connect_info);
2286 }
2287
2288 GtkWidget *
2289 modest_platform_get_account_settings_wizard (void)
2290 {
2291         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2292
2293         return GTK_WIDGET (dialog);
2294 }
2295
2296 ModestConnectedVia
2297 modest_platform_get_current_connection (void)
2298 {
2299         TnyDevice *device = NULL;
2300         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2301         
2302         device = modest_runtime_get_device ();
2303
2304         if (!tny_device_is_online (device))
2305                 return MODEST_CONNECTED_VIA_ANY;
2306
2307 #ifdef MODEST_HAVE_CONIC
2308         /* Get iap id */
2309         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2310         if (iap_id) {
2311                 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2312                         TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2313                 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2314                 if (bearer_type) {
2315                         if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2316                             !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2317                             !strcmp (bearer_type, "WIMAX")) {
2318                                 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2319                         } else {
2320                                 retval = MODEST_CONNECTED_VIA_ANY;
2321                         }
2322                 }       
2323                 g_object_unref (iap);
2324         }
2325 #else
2326         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
2327 #endif /* MODEST_HAVE_CONIC */
2328         return retval;
2329 }
2330
2331
2332
2333 gboolean
2334 modest_platform_check_memory_low (ModestWindow *win,
2335                                   gboolean visuals)
2336 {
2337         gboolean lowmem;
2338         
2339         /* are we in low memory state? */
2340         lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2341         
2342         if (win && lowmem && visuals)
2343                 modest_platform_run_information_dialog (
2344                         GTK_WINDOW(win),
2345                         dgettext("ke-recv","memr_ib_operation_disabled"),
2346                         TRUE);
2347
2348         if (lowmem)
2349                 g_debug ("%s: low memory reached. disallowing some operations",
2350                          __FUNCTION__);
2351
2352         return lowmem;
2353 }
2354
2355 void 
2356 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2357                                            TnyFolder *folder)
2358 {
2359         GtkWidget *dialog;
2360         
2361         /* Create dialog */
2362         dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2363
2364         /* Run dialog */
2365         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2366                                      GTK_WINDOW (dialog), 
2367                                      parent_window);
2368         gtk_widget_show_all (dialog);
2369
2370         g_signal_connect_swapped (dialog, "response", 
2371                                   G_CALLBACK (gtk_widget_destroy),
2372                                   dialog);
2373 }
2374
2375 void
2376 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2377                                            TnyHeader *header)
2378 {
2379         GtkWidget *dialog;
2380
2381         /* Create dialog */
2382         dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2383
2384         /* Run dialog */
2385         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2386                                      GTK_WINDOW (dialog),
2387                                      parent_window);
2388         gtk_widget_show_all (dialog);
2389
2390         g_signal_connect_swapped (dialog, "response", 
2391                                   G_CALLBACK (gtk_widget_destroy),
2392                                   dialog);
2393 }
2394
2395 osso_context_t *
2396 modest_platform_get_osso_context (void)
2397 {
2398         return modest_maemo_utils_get_osso_context ();
2399 }
2400
2401 static void
2402 _modest_platform_play_email_tone (void)
2403 {
2404         gchar *active_profile;
2405         gchar *mail_tone;
2406         gchar *mail_volume;
2407         gint mail_volume_int;
2408         int ret;
2409         ca_context *ca_con = NULL;
2410         ca_proplist *pl = NULL;
2411
2412         active_profile = profile_get_profile ();
2413         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2414         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2415         mail_volume_int = profile_parse_int (mail_volume);
2416
2417         if (mail_volume_int > 0) {
2418
2419                 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2420                         g_warning("ca_context_create: %s\n", ca_strerror(ret));
2421                         return;
2422                 }
2423
2424                 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2425                         g_warning("ca_context_open: %s\n", ca_strerror(ret));
2426                         ca_context_destroy(ca_con);
2427                         return;
2428                 }
2429
2430                 ca_proplist_create(&pl);
2431                 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2432                 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2433
2434                 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2435                 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2436
2437                 ca_proplist_destroy(pl);
2438                 ca_context_destroy(ca_con);
2439         }
2440
2441         g_free (mail_volume);
2442         g_free (mail_tone);
2443         g_free (active_profile);
2444 }
2445
2446 static void
2447 on_move_to_dialog_folder_activated (GtkTreeView       *tree_view,
2448                                     GtkTreePath       *path,
2449                                     GtkTreeViewColumn *column,
2450                                     gpointer           user_data)
2451 {
2452         gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2453 }
2454
2455 GtkWidget *
2456 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2457                                        GtkWidget **folder_view)
2458 {
2459         GtkWidget *dialog, *folder_view_container;
2460
2461         /* Create dialog. We cannot use a touch selector because we
2462            need to use here the folder view widget directly */
2463         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2464                                               GTK_WINDOW (parent_window),
2465                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2466                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2467                                               _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2468                                               NULL);
2469
2470         /* Create folder view */
2471         *folder_view = modest_platform_create_folder_view (NULL);
2472
2473         /* Simulate the behaviour of a HildonPickerDialog by emitting
2474            a response when a folder is selected */
2475         g_signal_connect (*folder_view, "row-activated",
2476                           G_CALLBACK (on_move_to_dialog_folder_activated),
2477                           dialog);
2478
2479         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2480                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2481
2482         /* Create pannable and add it to the dialog */
2483         folder_view_container = hildon_pannable_area_new ();
2484         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2485         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2486
2487         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2488
2489         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2490         gtk_widget_show (folder_view_container);
2491         gtk_widget_show (*folder_view);
2492
2493         return dialog;
2494 }
2495
2496 TnyList *
2497 modest_platform_get_list_to_move (ModestWindow *window)
2498 {
2499         TnyList *list = NULL;
2500
2501         if (MODEST_IS_HEADER_WINDOW (window)) {
2502                 ModestHeaderView *header_view;
2503
2504                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2505                 list = modest_header_view_get_selected_headers (header_view);
2506         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2507                 ModestFolderView *folder_view;
2508                 TnyFolderStore *selected_folder;
2509
2510                 list = TNY_LIST (tny_simple_list_new ());
2511                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2512                 selected_folder = modest_folder_view_get_selected (folder_view);
2513                 if (selected_folder) {
2514                         tny_list_prepend (list, G_OBJECT (selected_folder));
2515                         g_object_unref (selected_folder);
2516                 }
2517                 return list;
2518         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2519                 TnyHeader *header;
2520
2521                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2522                 if (header) {
2523                         list = TNY_LIST (tny_simple_list_new ());
2524                         tny_list_prepend (list, G_OBJECT (header));
2525                         g_object_unref (header);
2526                 }
2527         } else {
2528                 g_return_val_if_reached (NULL);
2529         }
2530
2531         return list;
2532 }