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