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