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