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