Me card contact is normally a OssoABookContact and not a EContact
[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 (TnyList *header_list,
1543                                          gboolean show_visual)
1544 {
1545         g_return_if_fail (TNY_IS_LIST (header_list));
1546
1547         if (tny_list_get_length (header_list) < 1)
1548                 return;
1549
1550         /* If the window is in the foreground don't do anything */
1551         if (hildon_program_get_is_topmost (hildon_program_get_instance ()))
1552                 return;
1553
1554 #ifdef MODEST_HAVE_HILDON_NOTIFY
1555         /* For any other case issue a notification */
1556         HildonNotification *notification;
1557         TnyIterator *iter;
1558         GSList *notifications_list = NULL;
1559
1560         /* Get previous notifications ids */
1561         notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1562                                                    MODEST_CONF_NOTIFICATION_IDS,
1563                                                    MODEST_CONF_VALUE_INT, NULL);
1564
1565         iter = tny_list_create_iterator (header_list);
1566         while (!tny_iterator_is_done (iter)) {
1567                 gchar *url = NULL, *display_address = NULL;
1568                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1569                 TnyFolder *folder = tny_header_get_folder (header);
1570                 gboolean first_notification = TRUE;
1571                 gint notif_id;
1572                 gchar *str;
1573
1574                 display_address = tny_header_dup_from (header);
1575                 /* string is changed in-place */
1576                 modest_text_utils_get_display_address (display_address);
1577
1578                 str = tny_header_dup_subject (header);
1579                 notification = hildon_notification_new (display_address,
1580                                                         str,
1581                                                         "qgn_list_messagin",
1582                                                         MODEST_NOTIFICATION_CATEGORY);
1583                 g_free (str);
1584                 /* Create the message URL */
1585                 str = tny_header_dup_uid (header);
1586                 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder), 
1587                                        str);
1588                 g_free (str);
1589
1590                 hildon_notification_add_dbus_action(notification,
1591                                                     "default",
1592                                                     "Cancel",
1593                                                     MODEST_DBUS_SERVICE,
1594                                                     MODEST_DBUS_OBJECT,
1595                                                     MODEST_DBUS_IFACE,
1596                                                     MODEST_DBUS_METHOD_OPEN_MESSAGE,
1597                                                     G_TYPE_STRING, url,
1598                                                     -1);
1599
1600                 /* Play sound if the user wants. Show the LED
1601                    pattern. Show and play just one */
1602                 if (G_UNLIKELY (first_notification)) {
1603                         TnyAccount *account;
1604
1605                         first_notification = FALSE;
1606
1607                         /* Set the led pattern */
1608                         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1609                                                             "dialog-type", 4);
1610                         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1611                                                             "led-pattern",
1612                                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);
1613
1614                         /* Set the account of the headers */
1615                         account = tny_folder_get_account (folder);
1616                         if (account) {
1617                                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1618                                                                     "email-account",
1619                                                                     tny_account_get_id (account));
1620                                 g_object_unref (account);
1621                         }
1622                 }
1623
1624                 /* Notify. We need to do this in an idle because this function
1625                    could be called from a thread */
1626                 if (!notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1627                         g_warning ("Failed to send notification");
1628                 }
1629
1630                 /* Save id in the list */
1631                 g_object_get(G_OBJECT(notification), "id", &notif_id, NULL);
1632                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1633                 /* We don't listen for the "closed" signal, because we
1634                    don't care about if the notification was removed or
1635                    not to store the list in gconf */
1636
1637                 /* Free & carry on */
1638                 g_free (display_address);
1639                 g_free (url);
1640                 g_object_unref (folder);
1641                 g_object_unref (header);
1642                 tny_iterator_next (iter);
1643         }
1644         g_object_unref (iter);
1645
1646         /* Save the ids */
1647         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1648                               notifications_list, MODEST_CONF_VALUE_INT, NULL);
1649
1650         g_slist_free (notifications_list);
1651
1652 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1653 }
1654
1655 void
1656 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1657 {
1658         if (only_visuals) {
1659 #ifdef MODEST_HAVE_MCE
1660                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1661                                      MCE_SERVICE,
1662                                      MCE_REQUEST_PATH,
1663                                      MCE_REQUEST_IF,
1664                                      MCE_DEACTIVATE_LED_PATTERN,
1665                                      NULL,
1666                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1667                                      DBUS_TYPE_INVALID);
1668 #endif
1669                 return;
1670         }
1671
1672 #ifdef MODEST_HAVE_HILDON_NOTIFY
1673         GSList *notif_list = NULL;
1674
1675         /* Get previous notifications ids */
1676         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1677                                            MODEST_CONF_NOTIFICATION_IDS, 
1678                                            MODEST_CONF_VALUE_INT, NULL);
1679
1680         while (notif_list) {
1681                 gint notif_id;
1682                 NotifyNotification *notif;
1683
1684                 /* Nasty HACK to remove the notifications, set the id
1685                    of the existing ones and then close them */
1686                 notif_id = GPOINTER_TO_INT(notif_list->data);
1687                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1688                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1689
1690                 /* Close the notification, note that some ids could be
1691                    already invalid, but we don't care because it does
1692                    not fail */
1693                 notify_notification_close(notif, NULL);
1694                 g_object_unref(notif);
1695
1696                 /* Delete the link, it's like going to the next */
1697                 notif_list = g_slist_delete_link (notif_list, notif_list);
1698         }
1699
1700         /* Save the ids */
1701         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1702                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1703
1704         g_slist_free (notif_list);
1705
1706 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1707 }
1708
1709
1710
1711 GtkWidget * 
1712 modest_platform_get_global_settings_dialog ()
1713 {
1714         return modest_hildon2_global_settings_dialog_new ();
1715 }
1716
1717 void
1718 modest_platform_show_help (GtkWindow *parent_window, 
1719                            const gchar *help_id)
1720 {
1721         return;
1722 }
1723
1724 void 
1725 modest_platform_show_search_messages (GtkWindow *parent_window)
1726 {
1727         osso_return_t result = OSSO_ERROR;
1728         
1729         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1730                                              "osso_global_search",
1731                                              "search_email", NULL, DBUS_TYPE_INVALID);
1732
1733         if (result != OSSO_OK) {
1734                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1735         }
1736 }
1737
1738 void 
1739 modest_platform_show_addressbook (GtkWindow *parent_window)
1740 {
1741         osso_return_t result = OSSO_ERROR;
1742
1743         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1744                                              "osso_addressbook",
1745                                              "top_application", NULL, DBUS_TYPE_INVALID);
1746
1747         if (result != OSSO_OK) {
1748                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1749         }
1750 }
1751
1752 static GtkWidget *
1753 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1754 {
1755         GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1756
1757         /* Show one account by default */
1758         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1759                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1760
1761         /* Restore settings */
1762         modest_widget_memory_restore (modest_runtime_get_conf(), 
1763                                       G_OBJECT (widget),
1764                                       MODEST_CONF_FOLDER_VIEW_KEY);
1765
1766         return widget;
1767 }
1768
1769 GtkWidget *
1770 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1771 {
1772         return modest_platform_create_folder_view_full (query, TRUE);
1773 }
1774
1775 void
1776 banner_finish (gpointer data, GObject *object)
1777 {
1778         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1779         modest_window_mgr_unregister_banner (mgr);
1780         g_object_unref (mgr);
1781 }
1782
1783 void 
1784 modest_platform_information_banner (GtkWidget *parent,
1785                                     const gchar *icon_name,
1786                                     const gchar *text)
1787 {
1788         GtkWidget *banner, *banner_parent = NULL;
1789         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1790
1791         if (modest_window_mgr_get_num_windows (mgr) == 0)
1792                 return;
1793
1794         if (parent && GTK_IS_WINDOW (parent)) {
1795                 /* If the window is the active one then show the
1796                    banner on top of this window */
1797                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1798                         banner_parent = parent;
1799                 /* If the window is not the topmost but it's visible
1800                    (it's minimized for example) then show the banner
1801                    with no parent */ 
1802                 else if (GTK_WIDGET_VISIBLE (parent))
1803                         banner_parent = NULL;
1804                 /* If the window is hidden (like the main window when
1805                    running in the background) then do not show
1806                    anything */
1807                 else 
1808                         return;
1809         }
1810
1811
1812         banner = hildon_banner_show_information (banner_parent, icon_name, text);
1813
1814         modest_window_mgr_register_banner (mgr);
1815         g_object_ref (mgr);
1816         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1817 }
1818
1819 void
1820 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1821                                                  const gchar *icon_name,
1822                                                  const gchar *text,
1823                                                  gint timeout)
1824 {
1825         GtkWidget *banner;
1826
1827         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1828                 return;
1829
1830         banner = hildon_banner_show_information (parent, icon_name, text);
1831         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1832 }
1833
1834 GtkWidget *
1835 modest_platform_animation_banner (GtkWidget *parent,
1836                                   const gchar *animation_name,
1837                                   const gchar *text)
1838 {
1839         GtkWidget *inf_note = NULL;
1840
1841         g_return_val_if_fail (text != NULL, NULL);
1842
1843         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1844                 return NULL;
1845
1846         /* If the parent is not visible then do not show */
1847         if (parent && !GTK_WIDGET_VISIBLE (parent))
1848                 return NULL;
1849
1850         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1851
1852         return inf_note;
1853 }
1854
1855 typedef struct
1856 {
1857         GMainLoop* loop;
1858         TnyAccount *account;
1859         gboolean is_online;
1860         gint count_tries;
1861 } CheckAccountIdleData;
1862
1863 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1864
1865 static gboolean 
1866 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1867 {
1868         gboolean stop_trying = FALSE;
1869         g_return_val_if_fail (data && data->account, FALSE);
1870         
1871         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1872                 tny_account_get_connection_status (data->account));     
1873         
1874         if (data && data->account && 
1875                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1876                  * after which the account is likely to be usable, or never likely to be usable soon: */
1877                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1878         {
1879                 data->is_online = TRUE;
1880                 
1881                 stop_trying = TRUE;
1882         } else {
1883                 /* Give up if we have tried too many times: */
1884                 if (data->count_tries >= NUMBER_OF_TRIES) {
1885                         stop_trying = TRUE;
1886                 } else {
1887                         /* Wait for another timeout: */
1888                         ++(data->count_tries);
1889                 }
1890         }
1891         
1892         if (stop_trying) {
1893                 /* Allow the function that requested this idle callback to continue: */
1894                 if (data->loop)
1895                         g_main_loop_quit (data->loop);
1896                         
1897                 if (data->account)
1898                         g_object_unref (data->account);
1899                 
1900                 return FALSE; /* Don't call this again. */
1901         } else {
1902                 return TRUE; /* Call this timeout callback again. */
1903         }
1904 }
1905
1906 /* Return TRUE immediately if the account is already online,
1907  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1908  * soon as the account is online, or FALSE if the account does 
1909  * not become online in the NUMBER_OF_TRIES seconds.
1910  * This is useful when the D-Bus method was run immediately after 
1911  * the application was started (when using D-Bus activation), 
1912  * because the account usually takes a short time to go online.
1913  * The return value is maybe not very useful.
1914  */
1915 gboolean
1916 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1917 {
1918         gboolean is_online;
1919
1920         g_return_val_if_fail (account, FALSE);
1921
1922         if (!tny_device_is_online (modest_runtime_get_device())) {
1923                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1924                 return FALSE;
1925         }
1926
1927         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1928          * so we avoid wait unnecessarily: */
1929         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1930                 return TRUE;
1931
1932         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1933          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1934          * we want to avoid. */
1935         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1936                 return TRUE;
1937                 
1938         /* This blocks on the result: */
1939         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1940         data->is_online = FALSE;
1941         data->account = account;
1942         g_object_ref (data->account);
1943         data->count_tries = 0;
1944                 
1945         GMainContext *context = NULL; /* g_main_context_new (); */
1946         data->loop = g_main_loop_new (context, FALSE /* not running */);
1947
1948         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1949
1950         /* This main loop will run until the idle handler has stopped it: */
1951         g_main_loop_run (data->loop);
1952
1953         g_main_loop_unref (data->loop);
1954         /* g_main_context_unref (context); */
1955
1956         is_online = data->is_online;
1957         g_slice_free (CheckAccountIdleData, data);
1958         
1959         return is_online;       
1960 }
1961
1962
1963
1964 static void
1965 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1966 {
1967         /* GTK_RESPONSE_HELP means we need to show the certificate */
1968         if (response_id == GTK_RESPONSE_APPLY) {
1969                 GtkWidget *note;
1970                 gchar *msg;
1971                 
1972                 /* Do not close the dialog */
1973                 g_signal_stop_emission_by_name (dialog, "response");
1974
1975                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1976                 note = hildon_note_new_information (NULL, msg);
1977                 gtk_dialog_run (GTK_DIALOG(note));
1978                 gtk_widget_destroy (note);
1979         }
1980 }
1981
1982
1983 gboolean
1984 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1985                                                      const gchar *certificate)
1986 {
1987         GtkWidget *note;
1988         gint response;
1989         ModestWindow *win;
1990         HildonWindowStack *stack;
1991
1992         stack = hildon_window_stack_get_default ();
1993         win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1994
1995         if (!win) {
1996           g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1997                            __FUNCTION__);
1998                 return FALSE;
1999         }
2000
2001         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
2002                                            server_name);
2003
2004         /* We use GTK_RESPONSE_APPLY because we want the button in the
2005            middle of OK and CANCEL the same as the browser does for
2006            example. With GTK_RESPONSE_HELP the view button is aligned
2007            to the left while the other two to the right */
2008         note = hildon_note_new_confirmation_add_buttons  (
2009                 NULL,
2010                 question,
2011                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
2012                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
2013                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
2014                 NULL, NULL);
2015
2016         g_signal_connect (G_OBJECT(note), "response", 
2017                           G_CALLBACK(on_cert_dialog_response),
2018                           (gpointer) certificate);
2019
2020         response = gtk_dialog_run(GTK_DIALOG(note));
2021
2022         on_destroy_dialog (note);
2023         g_free (question);
2024
2025         return response == GTK_RESPONSE_OK;
2026 }
2027
2028 gboolean
2029 modest_platform_run_alert_dialog (const gchar* prompt,
2030                                   gboolean is_question)
2031 {
2032         ModestWindow *top_win;
2033         HildonWindowStack *stack;
2034
2035         stack = hildon_window_stack_get_default ();
2036         top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2037
2038         if (!top_win) {
2039                 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2040                            __FUNCTION__);
2041                 return FALSE;
2042         }
2043
2044         gboolean retval = TRUE;
2045         if (is_question) {
2046                 /* The Tinymail documentation says that we should show Yes and No buttons,
2047                  * when it is a question.
2048                  * Obviously, we need tinymail to use more specific error codes instead,
2049                  * so we know what buttons to show. */
2050                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win), 
2051                                                                               prompt));
2052                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2053                                              GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2054
2055                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2056                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2057
2058                 on_destroy_dialog (dialog);
2059         } else {
2060                 /* Just show the error text and use the default response: */
2061                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
2062                                                         prompt, FALSE);
2063         }
2064         return retval;
2065 }
2066
2067 /***************/
2068 typedef struct {
2069         GtkWindow *parent_window;
2070         ModestConnectedPerformer callback;
2071         TnyAccount *account;
2072         gpointer user_data;
2073         gchar *iap;
2074         TnyDevice *device;
2075 } OnWentOnlineInfo;
2076  
2077 static void 
2078 on_went_online_info_free (OnWentOnlineInfo *info)
2079 {
2080         /* And if we cleanup, we DO cleanup  :-)  */
2081         
2082         if (info->device)
2083                 g_object_unref (info->device);
2084         if (info->iap)
2085                 g_free (info->iap);
2086         if (info->parent_window)
2087                 g_object_unref (info->parent_window);
2088         if (info->account)
2089                 g_object_unref (info->account);
2090         
2091         g_slice_free (OnWentOnlineInfo, info);
2092         
2093         /* We're done ... */
2094         
2095         return;
2096 }
2097  
2098 static void
2099 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2100 {
2101         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2102  
2103         /* Now it's really time to callback to the caller. If going online didn't succeed,
2104          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2105          * canceled will be set. Etcetera etcetera. */
2106         
2107         if (info->callback) {
2108                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2109         }
2110         
2111         /* This is our last call, we must cleanup here if we didn't yet do that */
2112         on_went_online_info_free (info);
2113         
2114         return;
2115 }
2116  
2117  
2118 static void
2119 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2120 {
2121         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2122         info->iap = g_strdup (iap_id);
2123         
2124         if (canceled || err || !info->account) {
2125         
2126                 /* If there's a problem or if there's no account (then that's it for us, we callback
2127                  * the caller's callback now. He'll have to handle err or canceled, of course.
2128                  * We are not really online, as the account is not really online here ... */    
2129                 
2130                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2131                  * this info. We don't cleanup err, Tinymail does that! */
2132                 
2133                 if (info->callback) {
2134                         
2135                         /* info->account can be NULL here, this means that the user did not
2136                          * provide a nice account instance. We'll assume that the user knows
2137                          * what he's doing and is happy with just the device going online. 
2138                          * 
2139                          * We can't do magic, we don't know what account the user wants to
2140                          * see going online. So just the device goes online, end of story */
2141                         
2142                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2143                 }
2144                 
2145         } else if (info->account) {
2146                 
2147                 /* If there's no problem and if we have an account, we'll put the account
2148                  * online too. When done, the callback of bringing the account online
2149                  * will callback the caller's callback. This is the most normal case. */
2150  
2151                 info->device = TNY_DEVICE (g_object_ref (device));
2152                 
2153                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2154                                               on_account_went_online, info);
2155                 
2156                 /* The on_account_went_online cb frees up the info, go look if you
2157                  * don't believe me! (so we return here) */
2158                 
2159                 return;
2160         }
2161         
2162         /* We cleanup if we are not bringing the account online too */
2163         on_went_online_info_free (info);
2164  
2165         return; 
2166 }
2167         
2168 void 
2169 modest_platform_connect_and_perform (GtkWindow *parent_window, 
2170                                      gboolean force,
2171                                      TnyAccount *account, 
2172                                      ModestConnectedPerformer callback, 
2173                                      gpointer user_data)
2174 {
2175         gboolean device_online;
2176         TnyDevice *device;
2177         TnyConnectionStatus conn_status;
2178         OnWentOnlineInfo *info;
2179         
2180         device = modest_runtime_get_device();
2181         device_online = tny_device_is_online (device);
2182
2183         /* If there is no account check only the device status */
2184         if (!account) {
2185                 
2186                 if (device_online) {
2187  
2188                         /* We promise to instantly perform the callback, so ... */
2189                         if (callback) {
2190                                 callback (FALSE, NULL, parent_window, account, user_data);
2191                         }
2192                         
2193                 } else {
2194                         
2195                         info = g_slice_new0 (OnWentOnlineInfo);
2196                         
2197                         info->iap = NULL;
2198                         info->device = NULL;
2199                         info->account = NULL;
2200                 
2201                         if (parent_window)
2202                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2203                         else
2204                                 info->parent_window = NULL;
2205                         info->user_data = user_data;
2206                         info->callback = callback;
2207                 
2208                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2209                                                               force, on_conic_device_went_online, 
2210                                                               info);
2211  
2212                         /* We'll cleanup in on_conic_device_went_online */
2213                 }
2214  
2215                 /* The other code has no more reason to run. This is all that we can do for the
2216                  * caller (he should have given us a nice and clean account instance!). We
2217                  * can't do magic, we don't know what account he intends to bring online. So
2218                  * we'll just bring the device online (and await his false bug report). */
2219                 
2220                 return;
2221         }
2222  
2223         
2224         /* Return if the account is already connected */
2225         
2226         conn_status = tny_account_get_connection_status (account);
2227         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2228  
2229                 /* We promise to instantly perform the callback, so ... */
2230                 if (callback) {
2231                         callback (FALSE, NULL, parent_window, account, user_data);
2232                 }
2233                 
2234                 return;
2235         }
2236         
2237         /* Else, we are in a state that requires that we go online before we
2238          * call the caller's callback. */
2239         
2240         info = g_slice_new0 (OnWentOnlineInfo);
2241         
2242         info->device = NULL;
2243         info->iap = NULL;
2244         info->account = TNY_ACCOUNT (g_object_ref (account));
2245         
2246         if (parent_window)
2247                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2248         else
2249                 info->parent_window = NULL;
2250         
2251         /* So we'll put the callback away for later ... */
2252         
2253         info->user_data = user_data;
2254         info->callback = callback;
2255         
2256         if (!device_online) {
2257  
2258                 /* If also the device is offline, then we connect both the device 
2259                  * and the account */
2260                 
2261                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2262                                                       force, on_conic_device_went_online, 
2263                                                       info);
2264                 
2265         } else {
2266                 
2267                 /* If the device is online, we'll just connect the account */
2268                 
2269                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2270                                               on_account_went_online, info);
2271         }
2272  
2273         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2274          * in both situations, go look if you don't believe me! */
2275         
2276         return;
2277 }
2278
2279 void
2280 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2281                                                gboolean force,
2282                                                TnyFolderStore *folder_store, 
2283                                                ModestConnectedPerformer callback, 
2284                                                gpointer user_data)
2285 {
2286         TnyAccount *account = NULL;
2287
2288         if (!folder_store ||
2289             (TNY_IS_MERGE_FOLDER (folder_store) &&
2290              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2291
2292                 /* We promise to instantly perform the callback, so ... */
2293                 if (callback) {
2294                         GError *error = NULL;
2295                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2296                                      "Unable to move or not found folder");
2297                         callback (FALSE, error, parent_window, NULL, user_data);
2298                         g_error_free (error);
2299                 }
2300                 return;
2301
2302         } else if (TNY_IS_FOLDER (folder_store)) {
2303                 /* Get the folder's parent account: */
2304                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2305         } else if (TNY_IS_ACCOUNT (folder_store)) {
2306                 /* Use the folder store as an account: */
2307                 account = TNY_ACCOUNT (g_object_ref (folder_store));
2308         }
2309
2310         if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2311                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2312                         /* No need to connect a local account */
2313                         if (callback)
2314                                 callback (FALSE, NULL, parent_window, account, user_data);
2315
2316                         goto clean;
2317                 }
2318         }
2319         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2320
2321  clean:
2322         if (account)
2323                 g_object_unref (account);
2324 }
2325
2326 static void
2327 src_account_connect_performer (gboolean canceled,
2328                                GError *err,
2329                                GtkWindow *parent_window,
2330                                TnyAccount *src_account,
2331                                gpointer user_data)
2332 {
2333         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2334
2335         if (canceled || err) {
2336                 /* If there was any error call the user callback */
2337                 info->callback (canceled, err, parent_window, src_account, info->data);
2338         } else {
2339                 /* Connect the destination account */
2340                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2341                                                                TNY_FOLDER_STORE (info->dst_account),
2342                                                                info->callback, info->data);
2343         }
2344
2345         /* Free the info object */
2346         g_object_unref (info->dst_account);
2347         g_slice_free (DoubleConnectionInfo, info);
2348 }
2349
2350
2351 void 
2352 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2353                                             gboolean force,
2354                                             TnyFolderStore *folder_store,
2355                                             DoubleConnectionInfo *connect_info)
2356 {
2357         modest_platform_connect_if_remote_and_perform(parent_window, 
2358                                                       force,
2359                                                       folder_store, 
2360                                                       src_account_connect_performer, 
2361                                                       connect_info);
2362 }
2363
2364 GtkWidget *
2365 modest_platform_get_account_settings_wizard (void)
2366 {
2367         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2368
2369         return GTK_WIDGET (dialog);
2370 }
2371
2372 ModestConnectedVia
2373 modest_platform_get_current_connection (void)
2374 {
2375         TnyDevice *device = NULL;
2376         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2377         
2378         device = modest_runtime_get_device ();
2379
2380         if (!tny_device_is_online (device))
2381                 return MODEST_CONNECTED_VIA_ANY;
2382
2383 #ifdef MODEST_HAVE_CONIC
2384         /* Get iap id */
2385         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2386         if (iap_id) {
2387                 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2388                         TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2389                 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2390                 if (bearer_type) {
2391                         if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2392                             !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2393                             !strcmp (bearer_type, "WIMAX")) {
2394                                 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2395                         } else {
2396                                 retval = MODEST_CONNECTED_VIA_ANY;
2397                         }
2398                 }       
2399                 g_object_unref (iap);
2400         }
2401 #else
2402         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
2403 #endif /* MODEST_HAVE_CONIC */
2404         return retval;
2405 }
2406
2407
2408
2409 gboolean
2410 modest_platform_check_memory_low (ModestWindow *win,
2411                                   gboolean visuals)
2412 {
2413         gboolean lowmem;
2414         
2415         /* are we in low memory state? */
2416         lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2417         
2418         if (win && lowmem && visuals)
2419                 modest_platform_run_information_dialog (
2420                         GTK_WINDOW(win),
2421                         _KR("memr_ib_operation_disabled"),
2422                         TRUE);
2423
2424         if (lowmem)
2425                 g_debug ("%s: low memory reached. disallowing some operations",
2426                          __FUNCTION__);
2427
2428         return lowmem;
2429 }
2430
2431 void 
2432 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2433                                            TnyFolder *folder)
2434 {
2435         GtkWidget *dialog;
2436         
2437         /* Create dialog */
2438         dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2439
2440         /* Run dialog */
2441         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2442                                      GTK_WINDOW (dialog), 
2443                                      parent_window);
2444         gtk_widget_show_all (dialog);
2445
2446         g_signal_connect_swapped (dialog, "response", 
2447                                   G_CALLBACK (gtk_widget_destroy),
2448                                   dialog);
2449 }
2450
2451 typedef struct _HeaderDetailsGetSizeInfo {
2452         GtkWidget *dialog;
2453         TnyMimePart *part;
2454         guint total;
2455 } HeaderDetailsGetSizeInfo;
2456
2457 static void 
2458 header_details_dialog_destroy (gpointer userdata,
2459                                GObject *object)
2460 {
2461         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2462
2463         info->dialog = NULL;
2464 }
2465
2466 static gboolean
2467 idle_get_mime_part_size_cb (gpointer userdata)
2468 {
2469         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2470         gdk_threads_enter ();
2471
2472         if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
2473                 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
2474                                                         info->total);
2475         }
2476
2477         if (info->dialog) {
2478                 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
2479                 info->dialog = NULL;
2480         }
2481         g_object_unref (info->part);
2482         g_slice_free (HeaderDetailsGetSizeInfo, info);
2483
2484         gdk_threads_leave ();
2485
2486         return FALSE;
2487 }
2488
2489 static gpointer
2490 get_mime_part_size_thread (gpointer thr_user_data)
2491 {
2492         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
2493         gssize result = 0;
2494         TnyStream *count_stream;
2495
2496         count_stream = modest_count_stream_new ();
2497         result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
2498         info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2499         if (info->total == 0) {
2500                 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
2501                 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
2502                 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2503         }
2504         
2505         /* if there was an error, don't set the size (this is pretty uncommon) */
2506         if (result < 0) {
2507                 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
2508         }
2509         g_idle_add (idle_get_mime_part_size_cb, info);
2510
2511         return NULL;
2512 }
2513
2514 void
2515 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2516                                            TnyHeader *header,
2517                                            gboolean async_get_size,
2518                                            TnyMsg *msg)
2519 {
2520         GtkWidget *dialog;
2521
2522         /* Create dialog */
2523         dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header, !async_get_size);
2524
2525         if (async_get_size && msg && TNY_IS_MSG (msg)) {
2526                 HeaderDetailsGetSizeInfo *info;
2527                 info = g_slice_new (HeaderDetailsGetSizeInfo);
2528                 info->dialog = dialog;
2529                 info->total = 0;
2530                 info->part = TNY_MIME_PART (g_object_ref (msg));
2531
2532                 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
2533                 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2534         }
2535
2536         /* Run dialog */
2537         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2538                                      GTK_WINDOW (dialog),
2539                                      parent_window);
2540         gtk_widget_show_all (dialog);
2541
2542         g_signal_connect_swapped (dialog, "response", 
2543                                   G_CALLBACK (gtk_widget_destroy),
2544                                   dialog);
2545 }
2546
2547 osso_context_t *
2548 modest_platform_get_osso_context (void)
2549 {
2550         return modest_maemo_utils_get_osso_context ();
2551 }
2552
2553 static void
2554 _modest_platform_play_email_tone (void)
2555 {
2556         gchar *mail_tone;
2557         gint mail_volume_int;
2558         int ret;
2559         ca_context *ca_con = NULL;
2560         ca_proplist *pl = NULL;
2561
2562 #ifdef MODEST_USE_PROFILE
2563         gchar *active_profile;
2564         gchar *mail_volume;
2565
2566         active_profile = profile_get_profile ();
2567         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2568         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2569         mail_volume_int = profile_parse_int (mail_volume);
2570         g_free (mail_volume);
2571         g_free (active_profile);
2572 #else
2573         mail_tone = MAIL_TONE;
2574         mail_volume_int = 100;
2575 #endif
2576
2577         if (mail_tone && !strstr (mail_tone, "/")) {
2578                 gchar *tmp;
2579
2580                 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2581                 g_free (mail_tone);
2582                 mail_tone = tmp;
2583         }
2584
2585         if (mail_volume_int > 0) {
2586
2587                 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2588                         g_warning("ca_context_create: %s\n", ca_strerror(ret));
2589                         return;
2590                 }
2591
2592                 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2593                         g_warning("ca_context_open: %s\n", ca_strerror(ret));
2594                         ca_context_destroy(ca_con);
2595                         return;
2596                 }
2597
2598                 ca_proplist_create(&pl);
2599                 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2600                 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2601
2602                 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2603                 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2604
2605                 ca_proplist_destroy(pl);
2606                 ca_context_destroy(ca_con);
2607         }
2608
2609         g_free (mail_tone);
2610 }
2611
2612 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2613 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2614 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2615 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2616 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2617 #define MOVE_TO_FOLDER_SEPARATOR "/"
2618
2619 static void
2620 move_to_dialog_set_selected_folder_store (GtkWidget *dialog, 
2621                                           TnyFolderStore *folder_store)
2622 {
2623         GtkWidget *action_button;
2624         GtkWidget *image = NULL;
2625         TnyAccount *account;
2626         gchar *account_name = NULL, *short_name = NULL;
2627
2628         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2629
2630         /* Get account name */
2631         if (TNY_IS_FOLDER (folder_store))
2632                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2633         else
2634                 account = g_object_ref (folder_store);
2635
2636         if (modest_tny_account_is_virtual_local_folders (account))
2637                 account_name = modest_conf_get_string (modest_runtime_get_conf(),
2638                                                        MODEST_CONF_DEVICE_NAME, NULL);
2639
2640         if (!account_name)
2641                 account_name = g_strdup (tny_account_get_name (account));
2642
2643         g_object_unref (account);
2644
2645         /* Set title of button: account or folder name */
2646         if (TNY_IS_FOLDER (folder_store))
2647                 short_name = folder_store_get_display_name (folder_store);
2648         else
2649                 short_name = g_strdup (account_name);
2650
2651         hildon_button_set_title (HILDON_BUTTON (action_button), short_name);
2652
2653         /* Set value of button, folder full name */
2654         if (TNY_IS_CAMEL_FOLDER (folder_store)) {
2655                 const gchar *camel_full_name;
2656                 gchar *last_slash, *full_name;
2657
2658                 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
2659                 last_slash = g_strrstr (camel_full_name, "/");
2660                 if (last_slash) {
2661                         gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
2662                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
2663                         g_free (prefix);
2664                 } else {
2665                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
2666                                                  short_name,
2667                                                  NULL);
2668                 }
2669                 hildon_button_set_value (HILDON_BUTTON (action_button), full_name);
2670                 g_free (full_name);
2671         }
2672         g_free (account_name);
2673         g_free (short_name);
2674
2675         /* Set image for the button */
2676         image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
2677         if (image)
2678                 hildon_button_set_image (HILDON_BUTTON (action_button), image);
2679 }
2680
2681 static void
2682 move_to_dialog_show_accounts (GtkWidget *dialog)
2683 {
2684         GtkWidget *back_button;
2685         GtkWidget *folder_view;
2686         GtkWidget *pannable;
2687         GtkWidget *action_button;
2688
2689         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2690         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2691         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2692         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2693
2694         gtk_widget_set_sensitive (back_button, FALSE);
2695         gtk_widget_set_sensitive (action_button, FALSE);
2696
2697         /* Need to set this here, otherwise callbacks called because
2698            of filtering won't perform correctly */
2699         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2700
2701         /* Reset action button */
2702         hildon_button_set_title (HILDON_BUTTON (action_button), NULL);
2703         hildon_button_set_value (HILDON_BUTTON (action_button), NULL);
2704         hildon_button_set_image (HILDON_BUTTON (action_button), NULL);
2705
2706         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
2707         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2708         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2709         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2710                                          MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2711         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2712                                        MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2713         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), 
2714                                          MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2715         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), 
2716                                        MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2717         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2718 }
2719
2720 static void
2721 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2722 {
2723         GtkWidget *back_button;
2724         GtkWidget *folder_view;
2725         TnyAccount *account;
2726         const gchar *account_id;
2727         GtkWidget *pannable;
2728         GtkWidget *action_button;
2729
2730         back_button =
2731                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2732         action_button =
2733                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2734         folder_view =
2735                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2736         pannable =
2737                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2738
2739         gtk_widget_set_sensitive (back_button, TRUE);
2740         gtk_widget_set_sensitive (action_button, TRUE);
2741
2742         /* Need to set this here, otherwise callbacks called because
2743            of filtering won't perform correctly */
2744         g_object_set_data (G_OBJECT (dialog),
2745                            MOVE_TO_DIALOG_SHOWING_FOLDERS,
2746                            GINT_TO_POINTER (TRUE));
2747
2748         account = TNY_ACCOUNT (folder_store);
2749         if (modest_tny_account_is_virtual_local_folders (account)) {
2750                 account_id = tny_account_get_id (account);
2751                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2752                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2753         } else if (modest_tny_account_is_memory_card_account (account)) {
2754                 account_id = tny_account_get_id (account);
2755                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2756                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2757         } else {
2758                 account_id = tny_account_get_id (account);
2759                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2760                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2761                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2762                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2763         }
2764
2765         move_to_dialog_set_selected_folder_store (dialog, folder_store);
2766         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2767                                                                      account_id);
2768
2769         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2770         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2771         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2772         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2773         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2774 }
2775
2776 static void
2777 on_move_to_dialog_back_clicked (GtkButton *button,
2778                                 gpointer userdata)
2779 {
2780         GtkWidget *dialog = (GtkWidget *) userdata;
2781
2782         /* Back to show accounts */
2783         move_to_dialog_show_accounts (dialog);
2784 }
2785
2786 static void
2787 on_move_to_dialog_row_activated (GtkTreeView       *tree_view,
2788                                     GtkTreePath       *path,
2789                                     GtkTreeViewColumn *column,
2790                                     gpointer           user_data)
2791 {
2792         TnyFolderStore *selected = NULL;
2793         GtkWidget *dialog;
2794         GtkWidget *folder_view;
2795         gboolean showing_folders;
2796
2797         dialog = (GtkWidget *) user_data;
2798         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), 
2799                                                               MOVE_TO_DIALOG_SHOWING_FOLDERS));
2800
2801         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), 
2802                                                      MOVE_TO_DIALOG_FOLDER_VIEW));
2803
2804         selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2805         if (!selected)
2806                 return;
2807
2808         if (!showing_folders) {
2809                 gboolean valid = TRUE;
2810
2811                 if (TNY_IS_ACCOUNT (selected) &&
2812                     modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2813                         ModestProtocolType protocol_type;
2814
2815                         protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2816                         valid  = !modest_protocol_registry_protocol_type_has_tag 
2817                                 (modest_runtime_get_protocol_registry (),
2818                                  protocol_type,
2819                                  MODEST_PROTOCOL_REGISTRY_STORE_FORBID_MESSAGE_ADD);
2820                 }
2821                 if (valid)
2822                         move_to_dialog_show_folders (dialog, selected);
2823         } else {
2824                 move_to_dialog_set_selected_folder_store (dialog, selected);
2825         }
2826 }
2827
2828 static void
2829 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2830                                      gpointer          user_data)
2831 {
2832         gboolean showing_folders;
2833         GtkWidget *dialog;
2834
2835         dialog = (GtkWidget *) user_data;
2836         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2837         if (showing_folders) {
2838                 TnyFolderStore *selected;
2839                 GtkWidget *folder_view;
2840
2841                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2842                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2843
2844                 if (selected) {
2845                         move_to_dialog_set_selected_folder_store (dialog, selected);
2846                         g_object_unref (selected);
2847                 }
2848         }
2849 }
2850
2851 static void
2852 on_move_to_dialog_action_clicked (GtkButton *selection,
2853                                   gpointer   user_data)
2854 {
2855         GtkWidget *dialog;
2856         gboolean showing_folders;
2857
2858         dialog = (GtkWidget *) user_data;
2859         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2860         if (showing_folders) {
2861                 TnyFolderStore *selected;
2862                 GtkWidget *folder_view;
2863
2864                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2865                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2866
2867                 if (selected) {
2868                         gtk_dialog_response  (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2869                         g_object_unref (selected);
2870                 }
2871         }
2872 }
2873
2874 static void
2875 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2876 {
2877         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (dialog), activity?1:0);
2878 }
2879
2880 GtkWidget *
2881 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2882                                        GtkWidget **folder_view)
2883 {
2884         GtkWidget *dialog, *folder_view_container;
2885         GtkWidget *align;
2886         GtkWidget *buttons_hbox;
2887         GtkWidget *back_button;
2888         GdkPixbuf *back_pixbuf;
2889         GtkWidget *top_vbox;
2890         GtkWidget *action_button;
2891         GtkTreeSelection *selection;
2892
2893         /* Create dialog. We cannot use a touch selector because we
2894            need to use here the folder view widget directly */
2895         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2896                                               GTK_WINDOW (parent_window),
2897                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2898                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2899                                               _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2900                                               NULL);
2901
2902         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2903         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2904         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2905
2906         /* Create folder view */
2907         *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2908         g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2909                           dialog);
2910
2911         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2912                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2913         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2914                                                FALSE);
2915         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2916                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2917
2918         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2919         back_button = gtk_button_new ();
2920         back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2921         if (back_pixbuf) {
2922                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2923                 g_object_unref (back_pixbuf);
2924         }
2925
2926         action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
2927                                            HILDON_BUTTON_ARRANGEMENT_VERTICAL);
2928         gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2929
2930         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2931         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2932         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2933         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2934         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2935
2936         /* Create pannable and add it to the dialog */
2937         folder_view_container = hildon_pannable_area_new ();
2938         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2939         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2940
2941         gtk_container_add (GTK_CONTAINER (align), top_vbox);
2942         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2943
2944         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2945
2946         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2947         gtk_widget_show (folder_view_container);
2948         gtk_widget_show (align);
2949         gtk_widget_show (top_vbox);
2950         gtk_widget_show (*folder_view);
2951         gtk_widget_show_all (back_button);
2952         gtk_widget_show (action_button);
2953         gtk_widget_show (buttons_hbox);
2954         gtk_widget_show (dialog);
2955
2956         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2957         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2958         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2959         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2960
2961         /* Simulate the behaviour of a HildonPickerDialog by emitting
2962            a response when a folder is selected */
2963         g_signal_connect (*folder_view, "row-activated",
2964                           G_CALLBACK (on_move_to_dialog_row_activated),
2965                           dialog);
2966
2967         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2968         g_signal_connect (selection, "changed",
2969                           G_CALLBACK (on_move_to_dialog_selection_changed),
2970                           dialog);
2971
2972         g_signal_connect (action_button, "clicked",
2973                           G_CALLBACK (on_move_to_dialog_action_clicked),
2974                           dialog);
2975
2976         g_signal_connect (back_button, "clicked",
2977                           G_CALLBACK (on_move_to_dialog_back_clicked),
2978                           dialog);
2979
2980         move_to_dialog_show_accounts (dialog);
2981
2982         return dialog;
2983 }
2984
2985 TnyList *
2986 modest_platform_get_list_to_move (ModestWindow *window)
2987 {
2988         TnyList *list = NULL;
2989
2990         if (MODEST_IS_HEADER_WINDOW (window)) {
2991                 ModestHeaderView *header_view;
2992
2993                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2994                 list = modest_header_view_get_selected_headers (header_view);
2995         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2996                 ModestFolderView *folder_view;
2997                 TnyFolderStore *selected_folder;
2998
2999                 list = TNY_LIST (tny_simple_list_new ());
3000                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
3001                 selected_folder = modest_folder_view_get_selected (folder_view);
3002                 if (selected_folder) {
3003                         tny_list_prepend (list, G_OBJECT (selected_folder));
3004                         g_object_unref (selected_folder);
3005                 }
3006                 return list;
3007         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3008                 TnyHeader *header;
3009
3010                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
3011                 if (header) {
3012                         list = TNY_LIST (tny_simple_list_new ());
3013                         tny_list_prepend (list, G_OBJECT (header));
3014                         g_object_unref (header);
3015                 }
3016         } else {
3017                 g_return_val_if_reached (NULL);
3018         }
3019
3020         return list;
3021 }