eb9d8becc75258f47394c195b40861d3e2ae3506
[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_debug ("%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, TnyFolderStore *current)
696 {
697         GtkWidget *folder_view;
698         FolderChooserData userdata = {NULL, NULL};
699         GtkWidget *pannable;
700         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         if (TNY_IS_FOLDER_STORE (current)) {
712                 if (TNY_IS_ACCOUNT (current)) {
713                         visible_id = g_strdup (tny_account_get_id (TNY_ACCOUNT (current)));
714                 } else if (TNY_IS_FOLDER (current)) {
715                         TnyAccount *account;
716
717                         account = tny_folder_get_account (TNY_FOLDER (current));
718                         if (account) {
719                                 visible_id = g_strdup (tny_account_get_id (TNY_ACCOUNT (current)));
720                         }
721                 }
722         }
723
724         if (visible_id == NULL) {
725                 visible_id = g_strdup (
726                         modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original)));
727         }
728
729         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
730                                                                      visible_id);
731         g_free (visible_id);
732
733         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
734         gtk_container_add (GTK_CONTAINER (pannable), folder_view);
735         gtk_widget_set_size_request (pannable, -1, 320);
736
737         gtk_widget_show (folder_view);
738         gtk_widget_show (pannable);
739         gtk_widget_show (userdata.dialog);
740         g_signal_connect (G_OBJECT (folder_view), "folder-activated", 
741                           G_CALLBACK (folder_chooser_activated), 
742                           (gpointer) &userdata);
743
744         gtk_dialog_run (GTK_DIALOG (userdata.dialog));
745         gtk_widget_destroy (userdata.dialog);
746
747         return userdata.store;
748 }
749
750 static gchar *
751 folder_store_get_display_name (TnyFolderStore *store)
752 {
753         if (TNY_IS_ACCOUNT (store)) {
754                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
755                         return modest_conf_get_string (modest_runtime_get_conf(),
756                                                        MODEST_CONF_DEVICE_NAME, NULL);
757                 else
758                         return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
759         } else {
760                 gchar *fname;
761                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
762
763                 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
764                 type = tny_folder_get_folder_type (TNY_FOLDER (store));
765                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
766                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
767                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
768                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
769                                 g_free (fname);
770                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
771                         }
772                 } else {
773                         /* Sometimes an special folder is reported by the server as
774                            NORMAL, like some versions of Dovecot */
775                         if (type == TNY_FOLDER_TYPE_NORMAL ||
776                             type == TNY_FOLDER_TYPE_UNKNOWN) {
777                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
778                         }
779                 }
780
781                 if (type == TNY_FOLDER_TYPE_INBOX) {
782                         g_free (fname);
783                         fname = g_strdup (_("mcen_me_folder_inbox"));
784                 }
785                 return fname;
786         }
787 }
788
789 GtkWidget *
790 get_image_for_folder_store (TnyFolderStore *store,
791                             gint size)
792 {
793         GdkPixbuf *pixbuf;
794         const gchar *icon_name = NULL;
795         GtkWidget *image = NULL;
796
797         if (TNY_IS_ACCOUNT (store)) {
798                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
799                         icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
800                 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
801                         icon_name = MODEST_FOLDER_ICON_MMC;
802                 else
803                         icon_name = MODEST_FOLDER_ICON_ACCOUNT;
804         } else {
805                 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
806                 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
807                         switch (type) {
808                         case TNY_FOLDER_TYPE_INBOX:
809                                 icon_name = MODEST_FOLDER_ICON_INBOX;
810                                 break;
811                         default:
812                                 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
813                         }
814                 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
815                         switch (type) {
816                         case TNY_FOLDER_TYPE_OUTBOX:
817                                 icon_name = MODEST_FOLDER_ICON_OUTBOX;
818                                 break;
819                         case TNY_FOLDER_TYPE_DRAFTS:
820                                 icon_name = MODEST_FOLDER_ICON_DRAFTS;
821                                 break;
822                         case TNY_FOLDER_TYPE_SENT:
823                                 icon_name = MODEST_FOLDER_ICON_SENT;
824                                 break;
825                         default:
826                                 icon_name = MODEST_FOLDER_ICON_NORMAL;
827                         }
828                 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
829                         icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
830                 }
831         }
832
833         /* Set icon */
834         pixbuf = modest_platform_get_icon (icon_name, size);
835
836         if (pixbuf) {
837                 image = gtk_image_new_from_pixbuf (pixbuf);
838                 g_object_unref (pixbuf);
839         }
840
841         return image;
842 }
843
844 static void
845 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
846 {
847         gchar *name;
848
849         if (store == NULL) {
850                 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
851         } else {
852                 GtkWidget *image;
853
854                 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
855                                         g_object_ref (store),
856                                         (GDestroyNotify) g_object_unref);
857                 name = folder_store_get_display_name (store);
858                 hildon_button_set_value (HILDON_BUTTON (button), name);
859                 g_free (name);
860
861                 /* Select icon */
862                 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
863                 if (image)
864                         hildon_button_set_image (HILDON_BUTTON (button), image);
865         }
866 }
867
868 /* Always returns DUPs so you must free the returned value */
869 static gchar *
870 get_next_folder_name (const gchar *suggested_name, 
871                       TnyFolderStore *suggested_folder)
872 {
873         const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
874         unsigned int i;
875         gchar *real_suggested_name;
876
877         if (suggested_name !=NULL) {
878                 return g_strdup (suggested_name);
879         }
880
881         for(i = 0; i < 100; ++ i) {
882                 gboolean exists = FALSE;
883
884                 if (i == 0)
885                         real_suggested_name = g_strdup (default_name);
886                 else
887                         real_suggested_name = g_strdup_printf ("%s(%d)",
888                                                                _FM("ckdg_va_new_folder_name_stub"),
889                                                                i);
890                 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
891                                                                     real_suggested_name,
892                                                                     TRUE);
893
894                 if (!exists)
895                         break;
896
897                 g_free (real_suggested_name);
898         }
899
900         /* Didn't find a free number */
901         if (i == 100)
902                 real_suggested_name = g_strdup (default_name);
903
904         return real_suggested_name;
905 }
906
907 typedef struct {
908         ModestFolderView *folder_view;
909         GtkEntry *entry;
910 } FolderPickerHelper;
911
912 static void
913 folder_picker_clicked (GtkButton *button,
914                        FolderPickerHelper *helper)
915 {
916         TnyFolderStore *store, *current;
917
918         current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
919
920         store = folder_chooser_dialog_run (helper->folder_view, current);
921         if (store) {
922                 const gchar *current_name;
923                 gboolean exists = FALSE;
924
925                 folder_picker_set_store (GTK_BUTTON (button), store);
926
927                 /* Update the name of the folder */
928                 current_name = gtk_entry_get_text (helper->entry);
929
930                 if (TNY_IS_FOLDER_STORE (store))
931                         exists = modest_tny_folder_has_subfolder_with_name (store,
932                                                                             current_name,
933                                                                             TRUE);
934                 if (exists) {
935                         gchar *new_name = get_next_folder_name (NULL, store);
936                         gtk_entry_set_text (helper->entry, new_name);
937                         g_free (new_name);
938                 }
939         }
940 }
941
942 static GtkWidget *
943 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
944 {
945         GtkWidget *button;
946
947         button = hildon_button_new (MODEST_EDITABLE_SIZE,
948                                     HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
949
950         hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
951
952         if (suggested)
953                 folder_picker_set_store (GTK_BUTTON (button), suggested);
954
955         g_signal_connect (G_OBJECT (button), "clicked",
956                           G_CALLBACK (folder_picker_clicked),
957                           helper);
958
959         return button;
960 }
961
962
963 static gint
964 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
965                                           TnyFolderStore *suggested_parent,
966                                           const gchar *dialog_title,
967                                           const gchar *label_text,
968                                           const gchar *suggested_name,
969                                           gboolean show_name,
970                                           gboolean show_parent,
971                                           gchar **folder_name,
972                                           TnyFolderStore **parent)
973 {
974         GtkWidget *accept_btn = NULL; 
975         GtkWidget *dialog, *entry = NULL, *label_entry = NULL,  *label_location = NULL, *hbox;
976         GtkWidget *account_picker = NULL;
977         GList *buttons = NULL;
978         gint result;
979         GtkSizeGroup *sizegroup;
980         ModestFolderView *folder_view;
981         ModestWindow *folder_window;
982         ModestHildon2WindowMgr *window_mgr;
983         FolderPickerHelper *helper = NULL;
984         GtkWidget *top_vbox, *top_align;
985
986         window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
987         folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
988         g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
989         
990         folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
991         
992         top_vbox = gtk_vbox_new (FALSE, 0);
993         top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
994         gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
995         
996         /* Ask the user for the folder name */
997         dialog = gtk_dialog_new_with_buttons (dialog_title,
998                                               parent_window,
999                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
1000                                               _FM("ckdg_bd_new_folder_dialog_ok"),
1001                                               GTK_RESPONSE_ACCEPT,
1002                                               NULL);
1003
1004         /* Add accept button (with unsensitive handler) */
1005         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
1006         accept_btn = GTK_WIDGET (buttons->data);
1007
1008         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
1009
1010         if (show_name) {
1011                 label_entry = gtk_label_new (label_text);
1012                 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
1013                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
1014
1015                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
1016                 gtk_size_group_add_widget (sizegroup, label_entry);
1017                 
1018                 if (suggested_name)
1019                   gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
1020                 else
1021                         gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
1022                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
1023                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
1024                                                 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
1025                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
1026         }
1027         
1028         if (show_parent) {
1029           
1030                 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
1031
1032                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
1033                 gtk_size_group_add_widget (sizegroup, label_location);
1034
1035                 helper = g_slice_new0 (FolderPickerHelper);
1036                 helper->folder_view = folder_view;
1037                 helper->entry = (GtkEntry *) entry;
1038
1039                 account_picker = folder_picker_new (suggested_parent, helper);
1040         }
1041
1042         g_object_unref (sizegroup);
1043         
1044         /* Connect to the response method to avoid closing the dialog
1045            when an invalid name is selected*/
1046         g_signal_connect (dialog,
1047                           "response",
1048                           G_CALLBACK (on_response),
1049                           suggested_parent);
1050         
1051         if (show_name) {
1052                 /* Track entry changes */
1053                 g_signal_connect (entry,
1054                                   "insert-text",
1055                                   G_CALLBACK (entry_insert_text),
1056                                   dialog);
1057                 g_signal_connect (entry,
1058                                   "changed",
1059                                   G_CALLBACK (entry_changed),
1060                                   dialog);
1061         }
1062         
1063         
1064         /* Some locales like pt_BR need this to get the full window
1065            title shown */
1066         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
1067         
1068         /* Create the hbox */
1069         if (show_name) {
1070                 hbox = gtk_hbox_new (FALSE, 12);
1071                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
1072                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
1073                 
1074                 /* Add hbox to dialog */
1075                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1076                                     hbox, FALSE, FALSE, 0);
1077                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
1078         }
1079
1080         if (show_parent) {
1081                 hbox = gtk_hbox_new (FALSE, 12);
1082                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
1083                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
1084
1085                 /* Add hbox to dialog */
1086                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1087                                     hbox, FALSE, FALSE, 0);
1088                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
1089         }
1090         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1091                                      GTK_WINDOW (dialog), parent_window);
1092
1093         gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
1094         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
1095
1096         gtk_widget_show_all (GTK_WIDGET(dialog));
1097
1098         result = gtk_dialog_run (GTK_DIALOG(dialog));
1099         if (result == GTK_RESPONSE_ACCEPT) {
1100                 if (show_name)
1101                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1102                 if (show_parent) {
1103                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
1104                         if (*parent)
1105                                 g_object_ref (*parent);
1106                 }
1107         }
1108
1109         gtk_widget_destroy (dialog);
1110
1111         if (helper)
1112                 g_slice_free (FolderPickerHelper, helper);
1113
1114         while (gtk_events_pending ())
1115                 gtk_main_iteration ();
1116
1117         return result;
1118 }
1119
1120 gint
1121 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
1122                                        TnyFolderStore *suggested_folder,
1123                                        gchar *suggested_name,
1124                                        gchar **folder_name,
1125                                        TnyFolderStore **parent_folder)
1126 {
1127         gchar *real_suggested_name = NULL;
1128         gint result;
1129         ModestTnyAccountStore *acc_store;
1130         TnyAccount *account;
1131         gboolean do_free = FALSE;
1132
1133         real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
1134                                                     suggested_folder);
1135
1136         /* In hildon 2.2 we always suggest the archive folder as parent */
1137         acc_store = modest_runtime_get_account_store ();
1138         account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1139         if (account) {
1140                 suggested_folder = (TnyFolderStore *)
1141                         modest_tny_account_get_special_folder (account,
1142                                                                TNY_FOLDER_TYPE_ARCHIVE);
1143                 g_object_unref (account);
1144                 account = NULL;
1145         }
1146
1147         /* If there is not archive folder then fallback to local folders account */
1148         if (!suggested_folder) {
1149                 do_free = TRUE;
1150                 suggested_folder = (TnyFolderStore *)
1151                         modest_tny_account_store_get_local_folders_account (acc_store);
1152         }
1153
1154         result = modest_platform_run_folder_common_dialog (parent_window,
1155                                                            suggested_folder,
1156                                                            _HL("ckdg_ti_new_folder"),
1157                                                            _FM("ckdg_fi_new_folder_name"),
1158                                                            real_suggested_name,
1159                                                            TRUE,
1160                                                            TRUE,
1161                                                            folder_name,
1162                                                            parent_folder);
1163
1164         if (do_free)
1165                 g_object_unref (suggested_folder);
1166
1167         g_free(real_suggested_name);
1168
1169         return result;
1170 }
1171
1172 gint
1173 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1174                                           TnyFolderStore *parent_folder,
1175                                           const gchar *suggested_name,
1176                                           gchar **folder_name)
1177 {
1178         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1179
1180         return modest_platform_run_folder_common_dialog (parent_window, 
1181                                                          parent_folder,
1182                                                          _HL("ckdg_ti_rename_folder"),
1183                                                          _HL("ckdg_fi_rename_name"),
1184                                                          suggested_name,
1185                                                          TRUE,
1186                                                          FALSE,
1187                                                          folder_name,
1188                                                          NULL);
1189 }
1190
1191
1192
1193 static void
1194 on_destroy_dialog (GtkWidget *dialog)
1195 {
1196         /* This could happen when the dialogs get programatically
1197            hidden or destroyed (for example when closing the
1198            application while a dialog is being shown) */
1199         if (!GTK_IS_WIDGET (dialog))
1200                 return;
1201
1202         gtk_widget_destroy (dialog);
1203
1204         if (gtk_events_pending ())
1205                 gtk_main_iteration ();
1206 }
1207
1208 gint
1209 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1210                                          const gchar *message)
1211 {
1212         GtkWidget *dialog;
1213         gint response;
1214         
1215         dialog = hildon_note_new_confirmation (parent_window, message);
1216         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1217                                      GTK_WINDOW (dialog), parent_window);
1218
1219         response = gtk_dialog_run (GTK_DIALOG (dialog));
1220
1221         on_destroy_dialog (dialog);
1222
1223         return response;
1224 }
1225
1226 gint
1227 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1228                                                       const gchar *message,
1229                                                       const gchar *button_accept,
1230                                                       const gchar *button_cancel)
1231 {
1232         GtkWidget *dialog;
1233         gint response;
1234         
1235         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1236                                                            button_accept, GTK_RESPONSE_ACCEPT,
1237                                                            button_cancel, GTK_RESPONSE_CANCEL,
1238                                                            NULL);
1239
1240         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1241                                      GTK_WINDOW (dialog), parent_window);
1242
1243         response = gtk_dialog_run (GTK_DIALOG (dialog));
1244
1245         on_destroy_dialog (dialog);
1246
1247         return response;
1248 }
1249         
1250 void
1251 modest_platform_run_information_dialog (GtkWindow *parent_window,
1252                                         const gchar *message,
1253                                         gboolean block)
1254 {
1255         GtkWidget *note;
1256         
1257         note = hildon_note_new_information (parent_window, message);
1258         if (block)
1259                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1260                                              GTK_WINDOW (note), parent_window);
1261         
1262         if (block) {
1263                 gtk_dialog_run (GTK_DIALOG (note));
1264         
1265                 on_destroy_dialog (note);
1266         } else {
1267                 g_signal_connect_swapped (note,
1268                                           "response", 
1269                                           G_CALLBACK (on_destroy_dialog),
1270                                           note);
1271
1272                 gtk_widget_show_all (note);
1273         }
1274 }
1275
1276 typedef struct _ConnectAndWaitData {
1277         GMutex *mutex;
1278         GMainLoop *wait_loop;
1279         gboolean has_callback;
1280         gulong handler;
1281 } ConnectAndWaitData;
1282
1283
1284 static void
1285 quit_wait_loop (TnyAccount *account,
1286                 ConnectAndWaitData *data) 
1287 {
1288         /* Set the has_callback to TRUE (means that the callback was
1289            executed and wake up every code waiting for cond to be
1290            TRUE */
1291         g_mutex_lock (data->mutex);
1292         data->has_callback = TRUE;
1293         if (data->wait_loop)
1294                 g_main_loop_quit (data->wait_loop);
1295         g_mutex_unlock (data->mutex);
1296 }
1297
1298 static void
1299 on_connection_status_changed (TnyAccount *account, 
1300                               TnyConnectionStatus status,
1301                               gpointer user_data)
1302 {
1303         TnyConnectionStatus conn_status;
1304         ConnectAndWaitData *data;
1305                         
1306         /* Ignore if reconnecting or disconnected */
1307         conn_status = tny_account_get_connection_status (account);
1308         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1309             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1310                 return;
1311
1312         /* Remove the handler */
1313         data = (ConnectAndWaitData *) user_data;
1314         g_signal_handler_disconnect (account, data->handler);
1315
1316         /* Quit from wait loop */
1317         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1318 }
1319
1320 static void
1321 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
1322                                     gboolean canceled, 
1323                                     GError *err, 
1324                                     gpointer user_data)
1325 {
1326         /* Quit from wait loop */
1327         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1328 }
1329
1330 gboolean 
1331 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1332                                   TnyAccount *account)
1333 {
1334         ConnectAndWaitData *data = NULL;
1335         gboolean device_online;
1336         TnyDevice *device;
1337         TnyConnectionStatus conn_status;
1338         gboolean user_requested;
1339         
1340         device = modest_runtime_get_device();
1341         device_online = tny_device_is_online (device);
1342
1343         /* Whether the connection is user requested or automatically
1344            requested, for example via D-Bus */
1345         user_requested = (parent_window) ? TRUE : FALSE;
1346
1347         /* If there is no account check only the device status */
1348         if (!account) {
1349                 if (device_online)
1350                         return TRUE;
1351                 else
1352                         return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1353                                                                NULL, user_requested);
1354         }
1355
1356         /* Return if the account is already connected */
1357         conn_status = tny_account_get_connection_status (account);
1358         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1359                 return TRUE;
1360
1361         /* Create the helper */
1362         data = g_slice_new0 (ConnectAndWaitData);
1363         data->mutex = g_mutex_new ();
1364         data->has_callback = FALSE;
1365
1366         /* Connect the device */
1367         if (!device_online) {
1368                 /* Track account connection status changes */
1369                 data->handler = g_signal_connect (account, "connection-status-changed",
1370                                                   G_CALLBACK (on_connection_status_changed),
1371                                                   data);
1372                 /* Try to connect the device */
1373                 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1374                                                                 NULL, user_requested);
1375
1376                 /* If the device connection failed then exit */
1377                 if (!device_online && data->handler)
1378                         goto frees;
1379         } else {
1380                 /* Force a reconnection of the account */
1381                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1382                                               on_tny_camel_account_set_online_cb, data);
1383         }
1384
1385         /* Wait until the callback is executed */
1386         g_mutex_lock (data->mutex);
1387         if (!data->has_callback) {
1388                 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1389                 gdk_threads_leave ();
1390                 g_mutex_unlock (data->mutex);
1391                 g_main_loop_run (data->wait_loop);
1392                 g_mutex_lock (data->mutex);
1393                 gdk_threads_enter ();
1394         }
1395         g_mutex_unlock (data->mutex);
1396
1397  frees:
1398         if (g_signal_handler_is_connected (account, data->handler))
1399                 g_signal_handler_disconnect (account, data->handler);
1400         g_mutex_free (data->mutex);
1401         g_main_loop_unref (data->wait_loop);
1402         g_slice_free (ConnectAndWaitData, data);
1403
1404         conn_status = tny_account_get_connection_status (account);
1405         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1406 }
1407
1408 gboolean 
1409 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1410 {
1411         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1412                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1413                         /* This must be a maildir account, which does not require a connection: */
1414                         return TRUE;
1415                 }
1416         }
1417
1418         return modest_platform_connect_and_wait (parent_window, account);
1419 }
1420
1421 gboolean 
1422 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1423 {
1424         if (!folder_store)
1425                 return TRUE; /* Maybe it is something local. */
1426                 
1427         gboolean result = TRUE;
1428         if (TNY_IS_FOLDER (folder_store)) {
1429                 /* Get the folder's parent account: */
1430                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1431                 if (account != NULL) {
1432                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1433                         g_object_unref (account);
1434                 }
1435         } else if (TNY_IS_ACCOUNT (folder_store)) {
1436                 /* Use the folder store as an account: */
1437                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1438         }
1439
1440         return result;
1441 }
1442
1443 GtkWidget *
1444 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1445 {
1446         GtkWidget *dialog;
1447
1448         dialog = modest_hildon2_sort_dialog_new (parent_window);
1449
1450         return dialog;
1451 }
1452
1453
1454 gboolean 
1455 modest_platform_set_update_interval (guint minutes)
1456 {
1457 #ifdef MODEST_HAVE_LIBALARM
1458         
1459         ModestConf *conf = modest_runtime_get_conf ();
1460         if (!conf)
1461                 return FALSE;
1462                 
1463         cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1464
1465         /* Delete any existing alarm,
1466          * because we will replace it: */
1467         if (alarm_cookie) {
1468                 if (alarmd_event_del(alarm_cookie) != 0)
1469                         g_debug ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1470                 alarm_cookie = 0;
1471                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1472         }
1473         
1474         /* 0 means no updates: */
1475         if (minutes == 0)
1476                 return TRUE;
1477         
1478      
1479         /* Register alarm: */
1480         
1481         /* Set the interval in alarm_event_t structure: */
1482         alarm_event_t *event = alarm_event_create ();
1483         alarm_event_add_actions (event, 1);
1484         alarm_action_t *action = alarm_event_get_action (event, 0);
1485         alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1486         event->alarm_time = minutes * 60; /* seconds */
1487         
1488         /* Set recurrence every few minutes: */
1489         event->recur_secs = minutes*60;
1490         event->recur_count = -1; /* Means infinite */
1491
1492         /* Specify what should happen when the alarm happens:
1493          * It should call this D-Bus method: */
1494          
1495         action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1496         action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1497         action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1498         action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1499         action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1500
1501         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1502          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1503          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1504          * This is why we want to use the Alarm API instead of just g_timeout_add().
1505          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1506          * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1507          */
1508         event->flags = ALARM_EVENT_CONNECTED;
1509         
1510         alarm_cookie = alarmd_event_add (event);
1511
1512         /* now, free it */
1513         alarm_event_delete (event);
1514         
1515         /* Store the alarm ID in GConf, so we can remove it later:
1516          * This is apparently valid between application instances. */
1517         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1518         
1519         if (!alarm_cookie) {
1520             /* Error */
1521             g_warning ("Error setting alarm event. \n");
1522             
1523             return FALSE;
1524         }
1525 #endif /* MODEST_HAVE_LIBALARM */       
1526         return TRUE;
1527 }
1528
1529 void
1530 modest_platform_push_email_notification(void)
1531 {
1532         gboolean screen_on, app_in_foreground;
1533
1534         /* Get the window status */
1535         app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1536
1537         screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1538
1539         /* If the screen is on and the app is in the
1540            foreground we don't show anything */
1541         if (!(screen_on && app_in_foreground)) {
1542
1543                 modest_platform_play_email_tone ();
1544
1545                 /* Activate LED. This must be deactivated by
1546                    modest_platform_remove_new_mail_notifications */
1547 #ifdef MODEST_HAVE_MCE
1548                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1549                                      MCE_SERVICE,
1550                                      MCE_REQUEST_PATH,
1551                                      MCE_REQUEST_IF,
1552                                      MCE_ACTIVATE_LED_PATTERN,
1553                                      NULL,
1554                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1555                                      DBUS_TYPE_INVALID);
1556 #endif
1557         }
1558 }
1559
1560 void
1561 modest_platform_on_new_headers_received (GList *URI_list,
1562                                          gboolean show_visual)
1563 {
1564         if (g_list_length (URI_list) == 0)
1565                 return;
1566
1567         /* If the window is in the foreground don't do anything */
1568         if (hildon_program_get_is_topmost (hildon_program_get_instance ()))
1569                 return;
1570
1571 #ifdef MODEST_HAVE_HILDON_NOTIFY
1572         /* For any other case issue a notification */
1573         HildonNotification *notification;
1574         GList *iter;
1575         GSList *notifications_list = NULL;
1576
1577         /* Get previous notifications ids */
1578         notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1579                                                    MODEST_CONF_NOTIFICATION_IDS,
1580                                                    MODEST_CONF_VALUE_INT, NULL);
1581
1582         iter = URI_list;
1583         while (iter) {
1584                 ModestMsgNotificationData *data;
1585                 gboolean first_notification = TRUE;
1586                 gint notif_id;
1587                 gchar *from;
1588
1589                 data = (ModestMsgNotificationData *) iter->data;
1590
1591                 /* String is changed in-place. There is no need to
1592                    actually dup the data->from string but we just do
1593                    it in order not to modify the original contents */
1594                 from = g_strdup (data->from);
1595                 modest_text_utils_get_display_address (from);
1596
1597                 notification = hildon_notification_new (from,
1598                                                         data->subject,
1599                                                         "qgn_list_messagin",
1600                                                         MODEST_NOTIFICATION_CATEGORY);
1601                 g_free (from);
1602
1603                 hildon_notification_add_dbus_action(notification,
1604                                                     "default",
1605                                                     "Cancel",
1606                                                     MODEST_DBUS_SERVICE,
1607                                                     MODEST_DBUS_OBJECT,
1608                                                     MODEST_DBUS_IFACE,
1609                                                     MODEST_DBUS_METHOD_OPEN_MESSAGE,
1610                                                     G_TYPE_STRING, data->uri,
1611                                                     -1);
1612
1613                 /* Play sound if the user wants. Show the LED
1614                    pattern. Show and play just one */
1615                 if (G_UNLIKELY (first_notification)) {
1616                         TnyAccountStore *acc_store;
1617                         TnyAccount *account;
1618
1619                         first_notification = FALSE;
1620
1621                         /* Set the led pattern and make the notification persistent */
1622                         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1623                                                             "dialog-type", 4);
1624                         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1625                                                             "led-pattern",
1626                                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);
1627                         notify_notification_set_hint_byte (NOTIFY_NOTIFICATION (notification),
1628                                                            "persistent", TRUE);
1629
1630                         /* Set the account of the headers */
1631                         acc_store = (TnyAccountStore *) modest_runtime_get_account_store ();
1632                         account = tny_account_store_find_account (acc_store, data->uri);
1633                         if (account) {
1634                                 const gchar *acc_name;
1635                                 acc_name =
1636                                         modest_tny_account_get_parent_modest_account_name_for_server_account (account);
1637                                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1638                                                                     "email-account",
1639                                                                     acc_name);
1640                                 g_object_unref (account);
1641                         }
1642
1643                         /* Play sound */
1644                         modest_platform_play_email_tone ();
1645                 }
1646
1647                 /* Notify. We need to do this in an idle because this function
1648                    could be called from a thread */
1649                 if (!notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1650                         g_warning ("Failed to send notification");
1651                 }
1652
1653                 /* Save id in the list */
1654                 g_object_get(G_OBJECT(notification), "id", &notif_id, NULL);
1655                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1656                 /* We don't listen for the "closed" signal, because we
1657                    don't care about if the notification was removed or
1658                    not to store the list in gconf */
1659
1660                 /* Free & carry on */
1661                 iter = g_list_next (iter);
1662         }
1663
1664         /* Save the ids */
1665         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1666                               notifications_list, MODEST_CONF_VALUE_INT, NULL);
1667
1668         g_slist_free (notifications_list);
1669
1670 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1671 }
1672
1673 void
1674 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1675 {
1676         if (only_visuals) {
1677 #ifdef MODEST_HAVE_MCE
1678                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1679                                      MCE_SERVICE,
1680                                      MCE_REQUEST_PATH,
1681                                      MCE_REQUEST_IF,
1682                                      MCE_DEACTIVATE_LED_PATTERN,
1683                                      NULL,
1684                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1685                                      DBUS_TYPE_INVALID);
1686 #endif
1687                 return;
1688         }
1689
1690 #ifdef MODEST_HAVE_HILDON_NOTIFY
1691         GSList *notif_list = NULL;
1692
1693         /* Get previous notifications ids */
1694         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1695                                            MODEST_CONF_NOTIFICATION_IDS, 
1696                                            MODEST_CONF_VALUE_INT, NULL);
1697
1698         while (notif_list) {
1699                 gint notif_id;
1700                 NotifyNotification *notif;
1701
1702                 /* Nasty HACK to remove the notifications, set the id
1703                    of the existing ones and then close them */
1704                 notif_id = GPOINTER_TO_INT(notif_list->data);
1705                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1706                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1707
1708                 /* Close the notification, note that some ids could be
1709                    already invalid, but we don't care because it does
1710                    not fail */
1711                 notify_notification_close(notif, NULL);
1712                 g_object_unref(notif);
1713
1714                 /* Delete the link, it's like going to the next */
1715                 notif_list = g_slist_delete_link (notif_list, notif_list);
1716         }
1717
1718         /* Save the ids */
1719         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1720                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1721
1722         g_slist_free (notif_list);
1723
1724 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1725 }
1726
1727
1728
1729 GtkWidget * 
1730 modest_platform_get_global_settings_dialog ()
1731 {
1732         return modest_hildon2_global_settings_dialog_new ();
1733 }
1734
1735 void
1736 modest_platform_show_help (GtkWindow *parent_window, 
1737                            const gchar *help_id)
1738 {
1739         return;
1740 }
1741
1742 void 
1743 modest_platform_show_search_messages (GtkWindow *parent_window)
1744 {
1745         osso_return_t result = OSSO_ERROR;
1746         
1747         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1748                                              "osso_global_search",
1749                                              "search_email", NULL, DBUS_TYPE_INVALID);
1750
1751         if (result != OSSO_OK) {
1752                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1753         }
1754 }
1755
1756 void 
1757 modest_platform_show_addressbook (GtkWindow *parent_window)
1758 {
1759         osso_return_t result = OSSO_ERROR;
1760
1761         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1762                                              "osso_addressbook",
1763                                              "top_application", NULL, DBUS_TYPE_INVALID);
1764
1765         if (result != OSSO_OK) {
1766                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1767         }
1768 }
1769
1770 static GtkWidget *
1771 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1772 {
1773         GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1774
1775         /* Show one account by default */
1776         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1777                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1778
1779         /* Restore settings */
1780         modest_widget_memory_restore (modest_runtime_get_conf(), 
1781                                       G_OBJECT (widget),
1782                                       MODEST_CONF_FOLDER_VIEW_KEY);
1783
1784         return widget;
1785 }
1786
1787 GtkWidget *
1788 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1789 {
1790         return modest_platform_create_folder_view_full (query, TRUE);
1791 }
1792
1793 void
1794 banner_finish (gpointer data, GObject *object)
1795 {
1796         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1797         modest_window_mgr_unregister_banner (mgr);
1798         g_object_unref (mgr);
1799 }
1800
1801 void 
1802 modest_platform_information_banner (GtkWidget *parent,
1803                                     const gchar *icon_name,
1804                                     const gchar *text)
1805 {
1806         GtkWidget *banner, *banner_parent = NULL;
1807         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1808
1809         if (modest_window_mgr_get_num_windows (mgr) == 0)
1810                 return;
1811
1812         if (parent && GTK_IS_WINDOW (parent)) {
1813                 /* If the window is the active one then show the
1814                    banner on top of this window */
1815                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1816                         banner_parent = parent;
1817                 /* If the window is not the topmost but it's visible
1818                    (it's minimized for example) then show the banner
1819                    with no parent */ 
1820                 else if (GTK_WIDGET_VISIBLE (parent))
1821                         banner_parent = NULL;
1822                 /* If the window is hidden (like the main window when
1823                    running in the background) then do not show
1824                    anything */
1825                 else 
1826                         return;
1827         }
1828
1829
1830         banner = hildon_banner_show_information (banner_parent, icon_name, text);
1831
1832         modest_window_mgr_register_banner (mgr);
1833         g_object_ref (mgr);
1834         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1835 }
1836
1837 void
1838 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1839                                                  const gchar *icon_name,
1840                                                  const gchar *text,
1841                                                  gint timeout)
1842 {
1843         GtkWidget *banner;
1844
1845         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1846                 return;
1847
1848         banner = hildon_banner_show_information (parent, icon_name, text);
1849         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1850 }
1851
1852 GtkWidget *
1853 modest_platform_animation_banner (GtkWidget *parent,
1854                                   const gchar *animation_name,
1855                                   const gchar *text)
1856 {
1857         GtkWidget *inf_note = NULL;
1858
1859         g_return_val_if_fail (text != NULL, NULL);
1860
1861         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1862                 return NULL;
1863
1864         /* If the parent is not visible then do not show */
1865         if (parent && !GTK_WIDGET_VISIBLE (parent))
1866                 return NULL;
1867
1868         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1869
1870         return inf_note;
1871 }
1872
1873 typedef struct
1874 {
1875         GMainLoop* loop;
1876         TnyAccount *account;
1877         gboolean is_online;
1878         gint count_tries;
1879 } CheckAccountIdleData;
1880
1881 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1882
1883 static gboolean 
1884 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1885 {
1886         gboolean stop_trying = FALSE;
1887         g_return_val_if_fail (data && data->account, FALSE);
1888         
1889         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1890                 tny_account_get_connection_status (data->account));     
1891         
1892         if (data && data->account && 
1893                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1894                  * after which the account is likely to be usable, or never likely to be usable soon: */
1895                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1896         {
1897                 data->is_online = TRUE;
1898                 
1899                 stop_trying = TRUE;
1900         } else {
1901                 /* Give up if we have tried too many times: */
1902                 if (data->count_tries >= NUMBER_OF_TRIES) {
1903                         stop_trying = TRUE;
1904                 } else {
1905                         /* Wait for another timeout: */
1906                         ++(data->count_tries);
1907                 }
1908         }
1909         
1910         if (stop_trying) {
1911                 /* Allow the function that requested this idle callback to continue: */
1912                 if (data->loop)
1913                         g_main_loop_quit (data->loop);
1914                         
1915                 if (data->account)
1916                         g_object_unref (data->account);
1917                 
1918                 return FALSE; /* Don't call this again. */
1919         } else {
1920                 return TRUE; /* Call this timeout callback again. */
1921         }
1922 }
1923
1924 /* Return TRUE immediately if the account is already online,
1925  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1926  * soon as the account is online, or FALSE if the account does 
1927  * not become online in the NUMBER_OF_TRIES seconds.
1928  * This is useful when the D-Bus method was run immediately after 
1929  * the application was started (when using D-Bus activation), 
1930  * because the account usually takes a short time to go online.
1931  * The return value is maybe not very useful.
1932  */
1933 gboolean
1934 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1935 {
1936         gboolean is_online;
1937
1938         g_return_val_if_fail (account, FALSE);
1939
1940         if (!tny_device_is_online (modest_runtime_get_device())) {
1941                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1942                 return FALSE;
1943         }
1944
1945         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1946          * so we avoid wait unnecessarily: */
1947         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1948                 return TRUE;
1949
1950         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1951          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1952          * we want to avoid. */
1953         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1954                 return TRUE;
1955                 
1956         /* This blocks on the result: */
1957         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1958         data->is_online = FALSE;
1959         data->account = account;
1960         g_object_ref (data->account);
1961         data->count_tries = 0;
1962                 
1963         GMainContext *context = NULL; /* g_main_context_new (); */
1964         data->loop = g_main_loop_new (context, FALSE /* not running */);
1965
1966         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1967
1968         /* This main loop will run until the idle handler has stopped it: */
1969         g_main_loop_run (data->loop);
1970
1971         g_main_loop_unref (data->loop);
1972         /* g_main_context_unref (context); */
1973
1974         is_online = data->is_online;
1975         g_slice_free (CheckAccountIdleData, data);
1976         
1977         return is_online;       
1978 }
1979
1980
1981
1982 static void
1983 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1984 {
1985         /* GTK_RESPONSE_HELP means we need to show the certificate */
1986         if (response_id == GTK_RESPONSE_APPLY) {
1987                 GtkWidget *note;
1988                 gchar *msg;
1989                 
1990                 /* Do not close the dialog */
1991                 g_signal_stop_emission_by_name (dialog, "response");
1992
1993                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1994                 note = hildon_note_new_information (NULL, msg);
1995                 gtk_dialog_run (GTK_DIALOG(note));
1996                 gtk_widget_destroy (note);
1997         }
1998 }
1999
2000
2001 gboolean
2002 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
2003                                                      const gchar *certificate)
2004 {
2005         GtkWidget *note;
2006         gint response;
2007         ModestWindow *win;
2008         HildonWindowStack *stack;
2009
2010         stack = hildon_window_stack_get_default ();
2011         win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2012
2013         if (!win) {
2014                 g_debug ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2015                          __FUNCTION__);
2016                 return FALSE;
2017         }
2018
2019         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
2020                                            server_name);
2021
2022         /* We use GTK_RESPONSE_APPLY because we want the button in the
2023            middle of OK and CANCEL the same as the browser does for
2024            example. With GTK_RESPONSE_HELP the view button is aligned
2025            to the left while the other two to the right */
2026         note = hildon_note_new_confirmation_add_buttons  (
2027                 NULL,
2028                 question,
2029                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
2030                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
2031                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
2032                 NULL, NULL);
2033
2034         g_signal_connect (G_OBJECT(note), "response", 
2035                           G_CALLBACK(on_cert_dialog_response),
2036                           (gpointer) certificate);
2037
2038         response = gtk_dialog_run(GTK_DIALOG(note));
2039
2040         on_destroy_dialog (note);
2041         g_free (question);
2042
2043         return response == GTK_RESPONSE_OK;
2044 }
2045
2046 gboolean
2047 modest_platform_run_alert_dialog (const gchar* prompt,
2048                                   gboolean is_question)
2049 {
2050         ModestWindow *top_win;
2051         HildonWindowStack *stack;
2052
2053         stack = hildon_window_stack_get_default ();
2054         top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2055
2056         if (!top_win) {
2057                 g_debug ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2058                          __FUNCTION__);
2059                 return FALSE;
2060         }
2061
2062         gboolean retval = TRUE;
2063         if (is_question) {
2064                 /* The Tinymail documentation says that we should show Yes and No buttons,
2065                  * when it is a question.
2066                  * Obviously, we need tinymail to use more specific error codes instead,
2067                  * so we know what buttons to show. */
2068                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win), 
2069                                                                               prompt));
2070                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2071                                              GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2072
2073                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2074                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2075
2076                 on_destroy_dialog (dialog);
2077         } else {
2078                 /* Just show the error text and use the default response: */
2079                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
2080                                                         prompt, FALSE);
2081         }
2082         return retval;
2083 }
2084
2085 /***************/
2086 typedef struct {
2087         GtkWindow *parent_window;
2088         ModestConnectedPerformer callback;
2089         TnyAccount *account;
2090         gpointer user_data;
2091         gchar *iap;
2092         TnyDevice *device;
2093 } OnWentOnlineInfo;
2094  
2095 static void 
2096 on_went_online_info_free (OnWentOnlineInfo *info)
2097 {
2098         /* And if we cleanup, we DO cleanup  :-)  */
2099         
2100         if (info->device)
2101                 g_object_unref (info->device);
2102         if (info->iap)
2103                 g_free (info->iap);
2104         if (info->parent_window)
2105                 g_object_unref (info->parent_window);
2106         if (info->account)
2107                 g_object_unref (info->account);
2108         
2109         g_slice_free (OnWentOnlineInfo, info);
2110         
2111         /* We're done ... */
2112         
2113         return;
2114 }
2115  
2116 static void
2117 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2118 {
2119         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2120  
2121         /* Now it's really time to callback to the caller. If going online didn't succeed,
2122          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2123          * canceled will be set. Etcetera etcetera. */
2124         
2125         if (info->callback) {
2126                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2127         }
2128         
2129         /* This is our last call, we must cleanup here if we didn't yet do that */
2130         on_went_online_info_free (info);
2131         
2132         return;
2133 }
2134  
2135  
2136 static void
2137 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2138 {
2139         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2140         info->iap = g_strdup (iap_id);
2141         
2142         if (canceled || err || !info->account) {
2143         
2144                 /* If there's a problem or if there's no account (then that's it for us, we callback
2145                  * the caller's callback now. He'll have to handle err or canceled, of course.
2146                  * We are not really online, as the account is not really online here ... */    
2147                 
2148                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2149                  * this info. We don't cleanup err, Tinymail does that! */
2150                 
2151                 if (info->callback) {
2152                         
2153                         /* info->account can be NULL here, this means that the user did not
2154                          * provide a nice account instance. We'll assume that the user knows
2155                          * what he's doing and is happy with just the device going online. 
2156                          * 
2157                          * We can't do magic, we don't know what account the user wants to
2158                          * see going online. So just the device goes online, end of story */
2159                         
2160                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2161                 }
2162                 
2163         } else if (info->account) {
2164                 
2165                 /* If there's no problem and if we have an account, we'll put the account
2166                  * online too. When done, the callback of bringing the account online
2167                  * will callback the caller's callback. This is the most normal case. */
2168  
2169                 info->device = TNY_DEVICE (g_object_ref (device));
2170                 
2171                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2172                                               on_account_went_online, info);
2173                 
2174                 /* The on_account_went_online cb frees up the info, go look if you
2175                  * don't believe me! (so we return here) */
2176                 
2177                 return;
2178         }
2179         
2180         /* We cleanup if we are not bringing the account online too */
2181         on_went_online_info_free (info);
2182  
2183         return; 
2184 }
2185         
2186 void 
2187 modest_platform_connect_and_perform (GtkWindow *parent_window, 
2188                                      gboolean force,
2189                                      TnyAccount *account, 
2190                                      ModestConnectedPerformer callback, 
2191                                      gpointer user_data)
2192 {
2193         gboolean device_online;
2194         TnyDevice *device;
2195         TnyConnectionStatus conn_status;
2196         OnWentOnlineInfo *info;
2197         
2198         device = modest_runtime_get_device();
2199         device_online = tny_device_is_online (device);
2200
2201         /* If there is no account check only the device status */
2202         if (!account) {
2203                 
2204                 if (device_online) {
2205  
2206                         /* We promise to instantly perform the callback, so ... */
2207                         if (callback) {
2208                                 callback (FALSE, NULL, parent_window, account, user_data);
2209                         }
2210                         
2211                 } else {
2212                         
2213                         info = g_slice_new0 (OnWentOnlineInfo);
2214                         
2215                         info->iap = NULL;
2216                         info->device = NULL;
2217                         info->account = NULL;
2218                 
2219                         if (parent_window)
2220                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2221                         else
2222                                 info->parent_window = NULL;
2223                         info->user_data = user_data;
2224                         info->callback = callback;
2225                 
2226                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2227                                                               force, on_conic_device_went_online, 
2228                                                               info);
2229  
2230                         /* We'll cleanup in on_conic_device_went_online */
2231                 }
2232  
2233                 /* The other code has no more reason to run. This is all that we can do for the
2234                  * caller (he should have given us a nice and clean account instance!). We
2235                  * can't do magic, we don't know what account he intends to bring online. So
2236                  * we'll just bring the device online (and await his false bug report). */
2237                 
2238                 return;
2239         }
2240  
2241         
2242         /* Return if the account is already connected */
2243         
2244         conn_status = tny_account_get_connection_status (account);
2245         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2246  
2247                 /* We promise to instantly perform the callback, so ... */
2248                 if (callback) {
2249                         callback (FALSE, NULL, parent_window, account, user_data);
2250                 }
2251                 
2252                 return;
2253         }
2254         
2255         /* Else, we are in a state that requires that we go online before we
2256          * call the caller's callback. */
2257         
2258         info = g_slice_new0 (OnWentOnlineInfo);
2259         
2260         info->device = NULL;
2261         info->iap = NULL;
2262         info->account = TNY_ACCOUNT (g_object_ref (account));
2263         
2264         if (parent_window)
2265                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2266         else
2267                 info->parent_window = NULL;
2268         
2269         /* So we'll put the callback away for later ... */
2270         
2271         info->user_data = user_data;
2272         info->callback = callback;
2273         
2274         if (!device_online) {
2275  
2276                 /* If also the device is offline, then we connect both the device 
2277                  * and the account */
2278                 
2279                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2280                                                       force, on_conic_device_went_online, 
2281                                                       info);
2282                 
2283         } else {
2284                 
2285                 /* If the device is online, we'll just connect the account */
2286                 
2287                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2288                                               on_account_went_online, info);
2289         }
2290  
2291         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2292          * in both situations, go look if you don't believe me! */
2293         
2294         return;
2295 }
2296
2297 void
2298 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2299                                                gboolean force,
2300                                                TnyFolderStore *folder_store, 
2301                                                ModestConnectedPerformer callback, 
2302                                                gpointer user_data)
2303 {
2304         TnyAccount *account = NULL;
2305
2306         if (!folder_store ||
2307             (TNY_IS_MERGE_FOLDER (folder_store) &&
2308              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2309
2310                 /* We promise to instantly perform the callback, so ... */
2311                 if (callback) {
2312                         GError *error = NULL;
2313                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2314                                      "Unable to move or not found folder");
2315                         callback (FALSE, error, parent_window, NULL, user_data);
2316                         g_error_free (error);
2317                 }
2318                 return;
2319
2320         } else if (TNY_IS_FOLDER (folder_store)) {
2321                 /* Get the folder's parent account: */
2322                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2323         } else if (TNY_IS_ACCOUNT (folder_store)) {
2324                 /* Use the folder store as an account: */
2325                 account = TNY_ACCOUNT (g_object_ref (folder_store));
2326         }
2327
2328         if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2329                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2330                         /* No need to connect a local account */
2331                         if (callback)
2332                                 callback (FALSE, NULL, parent_window, account, user_data);
2333
2334                         goto clean;
2335                 }
2336         }
2337         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2338
2339  clean:
2340         if (account)
2341                 g_object_unref (account);
2342 }
2343
2344 static void
2345 src_account_connect_performer (gboolean canceled,
2346                                GError *err,
2347                                GtkWindow *parent_window,
2348                                TnyAccount *src_account,
2349                                gpointer user_data)
2350 {
2351         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2352
2353         if (canceled || err) {
2354                 /* If there was any error call the user callback */
2355                 info->callback (canceled, err, parent_window, src_account, info->data);
2356         } else {
2357                 /* Connect the destination account */
2358                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2359                                                                TNY_FOLDER_STORE (info->dst_account),
2360                                                                info->callback, info->data);
2361         }
2362
2363         /* Free the info object */
2364         g_object_unref (info->dst_account);
2365         g_slice_free (DoubleConnectionInfo, info);
2366 }
2367
2368
2369 void 
2370 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2371                                             gboolean force,
2372                                             TnyFolderStore *folder_store,
2373                                             DoubleConnectionInfo *connect_info)
2374 {
2375         modest_platform_connect_if_remote_and_perform(parent_window, 
2376                                                       force,
2377                                                       folder_store, 
2378                                                       src_account_connect_performer, 
2379                                                       connect_info);
2380 }
2381
2382 GtkWidget *
2383 modest_platform_get_account_settings_wizard (void)
2384 {
2385         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2386
2387         return GTK_WIDGET (dialog);
2388 }
2389
2390 ModestConnectedVia
2391 modest_platform_get_current_connection (void)
2392 {
2393         TnyDevice *device = NULL;
2394         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2395         
2396         device = modest_runtime_get_device ();
2397
2398         if (!tny_device_is_online (device))
2399                 return MODEST_CONNECTED_VIA_ANY;
2400
2401 #ifdef MODEST_HAVE_CONIC
2402         /* Get iap id */
2403         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2404         if (iap_id) {
2405                 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2406                         TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2407                 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2408                 if (bearer_type) {
2409                         if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2410                             !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2411                             !strcmp (bearer_type, "WIMAX")) {
2412                                 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2413                         } else {
2414                                 retval = MODEST_CONNECTED_VIA_ANY;
2415                         }
2416                 }       
2417                 g_object_unref (iap);
2418         }
2419 #else
2420         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
2421 #endif /* MODEST_HAVE_CONIC */
2422         return retval;
2423 }
2424
2425
2426
2427 gboolean
2428 modest_platform_check_memory_low (ModestWindow *win,
2429                                   gboolean visuals)
2430 {
2431         gboolean lowmem;
2432         
2433         /* are we in low memory state? */
2434         lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2435         
2436         if (win && lowmem && visuals)
2437                 modest_platform_run_information_dialog (
2438                         GTK_WINDOW(win),
2439                         _KR("memr_ib_operation_disabled"),
2440                         TRUE);
2441
2442         if (lowmem)
2443                 g_debug ("%s: low memory reached. disallowing some operations",
2444                          __FUNCTION__);
2445
2446         return lowmem;
2447 }
2448
2449 void 
2450 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2451                                            TnyFolder *folder)
2452 {
2453         GtkWidget *dialog;
2454         
2455         /* Create dialog */
2456         dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2457
2458         /* Run dialog */
2459         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2460                                      GTK_WINDOW (dialog), 
2461                                      parent_window);
2462         gtk_widget_show_all (dialog);
2463
2464         g_signal_connect_swapped (dialog, "response", 
2465                                   G_CALLBACK (gtk_widget_destroy),
2466                                   dialog);
2467 }
2468
2469 typedef struct _HeaderDetailsGetSizeInfo {
2470         GtkWidget *dialog;
2471         TnyMimePart *part;
2472         guint total;
2473 } HeaderDetailsGetSizeInfo;
2474
2475 static void 
2476 header_details_dialog_destroy (gpointer userdata,
2477                                GObject *object)
2478 {
2479         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2480
2481         info->dialog = NULL;
2482 }
2483
2484 static gboolean
2485 idle_get_mime_part_size_cb (gpointer userdata)
2486 {
2487         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2488         gdk_threads_enter ();
2489
2490         if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
2491                 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
2492                                                         info->total);
2493         }
2494
2495         if (info->dialog) {
2496                 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
2497                 info->dialog = NULL;
2498         }
2499         g_object_unref (info->part);
2500         g_slice_free (HeaderDetailsGetSizeInfo, info);
2501
2502         gdk_threads_leave ();
2503
2504         return FALSE;
2505 }
2506
2507 static gpointer
2508 get_mime_part_size_thread (gpointer thr_user_data)
2509 {
2510         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
2511         gssize result = 0;
2512         TnyStream *count_stream;
2513
2514         count_stream = modest_count_stream_new ();
2515         result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
2516         info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2517         if (info->total == 0) {
2518                 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
2519                 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
2520                 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2521         }
2522         
2523         /* if there was an error, don't set the size (this is pretty uncommon) */
2524         if (result < 0) {
2525                 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
2526         }
2527         g_idle_add (idle_get_mime_part_size_cb, info);
2528
2529         return NULL;
2530 }
2531
2532 void
2533 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2534                                            TnyHeader *header,
2535                                            gboolean async_get_size,
2536                                            TnyMsg *msg)
2537 {
2538         GtkWidget *dialog;
2539
2540         /* Create dialog */
2541         dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header, !async_get_size);
2542
2543         if (async_get_size && msg && TNY_IS_MSG (msg)) {
2544                 HeaderDetailsGetSizeInfo *info;
2545                 info = g_slice_new (HeaderDetailsGetSizeInfo);
2546                 info->dialog = dialog;
2547                 info->total = 0;
2548                 info->part = TNY_MIME_PART (g_object_ref (msg));
2549
2550                 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
2551                 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2552         }
2553
2554         /* Run dialog */
2555         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2556                                      GTK_WINDOW (dialog),
2557                                      parent_window);
2558         gtk_widget_show_all (dialog);
2559
2560         g_signal_connect_swapped (dialog, "response", 
2561                                   G_CALLBACK (gtk_widget_destroy),
2562                                   dialog);
2563 }
2564
2565 osso_context_t *
2566 modest_platform_get_osso_context (void)
2567 {
2568         return modest_maemo_utils_get_osso_context ();
2569 }
2570
2571 static void
2572 modest_platform_play_email_tone (void)
2573 {
2574         gchar *mail_tone;
2575         gint mail_volume_int;
2576         int ret;
2577         ca_context *ca_con = NULL;
2578         ca_proplist *pl = NULL;
2579
2580 #ifdef MODEST_USE_PROFILE
2581         gchar *active_profile;
2582         gchar *mail_volume;
2583
2584         active_profile = profile_get_profile ();
2585         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2586         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2587         mail_volume_int = profile_parse_int (mail_volume);
2588         g_free (mail_volume);
2589         g_free (active_profile);
2590 #else
2591         mail_tone = MAIL_TONE;
2592         mail_volume_int = 100;
2593 #endif
2594
2595         if (mail_tone && !strstr (mail_tone, "/")) {
2596                 gchar *tmp;
2597
2598                 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2599                 g_free (mail_tone);
2600                 mail_tone = tmp;
2601         }
2602
2603         if (mail_volume_int > 0) {
2604
2605                 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2606                         g_warning("ca_context_create: %s\n", ca_strerror(ret));
2607                         return;
2608                 }
2609
2610                 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2611                         g_warning("ca_context_open: %s\n", ca_strerror(ret));
2612                         ca_context_destroy(ca_con);
2613                         return;
2614                 }
2615
2616                 ca_proplist_create(&pl);
2617                 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2618                 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2619
2620                 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2621                 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2622
2623                 ca_proplist_destroy(pl);
2624                 ca_context_destroy(ca_con);
2625         }
2626
2627         g_free (mail_tone);
2628 }
2629
2630 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2631 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2632 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2633 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2634 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2635 #define MOVE_TO_FOLDER_SEPARATOR "/"
2636
2637 static void
2638 move_to_dialog_set_selected_folder_store (GtkWidget *dialog, 
2639                                           TnyFolderStore *folder_store)
2640 {
2641         GtkWidget *action_button;
2642         GtkWidget *image = NULL;
2643         TnyAccount *account;
2644         gchar *account_name = NULL, *short_name = NULL;
2645
2646         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2647
2648         /* Get account name */
2649         if (TNY_IS_FOLDER (folder_store))
2650                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2651         else
2652                 account = g_object_ref (folder_store);
2653
2654         if (modest_tny_account_is_virtual_local_folders (account))
2655                 account_name = modest_conf_get_string (modest_runtime_get_conf(),
2656                                                        MODEST_CONF_DEVICE_NAME, NULL);
2657
2658         if (!account_name)
2659                 account_name = g_strdup (tny_account_get_name (account));
2660
2661         g_object_unref (account);
2662
2663         /* Set title of button: account or folder name */
2664         if (TNY_IS_FOLDER (folder_store))
2665                 short_name = folder_store_get_display_name (folder_store);
2666         else
2667                 short_name = g_strdup (account_name);
2668
2669         hildon_button_set_title (HILDON_BUTTON (action_button), short_name);
2670
2671         /* Set value of button, folder full name */
2672         if (TNY_IS_CAMEL_FOLDER (folder_store)) {
2673                 const gchar *camel_full_name;
2674                 gchar *last_slash, *full_name;
2675
2676                 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
2677                 last_slash = g_strrstr (camel_full_name, "/");
2678                 if (last_slash) {
2679                         gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
2680                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
2681                         g_free (prefix);
2682                 } else {
2683                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
2684                                                  short_name,
2685                                                  NULL);
2686                 }
2687                 hildon_button_set_value (HILDON_BUTTON (action_button), full_name);
2688                 g_free (full_name);
2689         }
2690         g_free (account_name);
2691         g_free (short_name);
2692
2693         /* Set image for the button */
2694         image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
2695         if (image)
2696                 hildon_button_set_image (HILDON_BUTTON (action_button), image);
2697 }
2698
2699 static void
2700 move_to_dialog_show_accounts (GtkWidget *dialog)
2701 {
2702         GtkWidget *back_button;
2703         GtkWidget *folder_view;
2704         GtkWidget *pannable;
2705         GtkWidget *action_button;
2706
2707         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2708         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2709         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2710         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2711
2712         gtk_widget_set_sensitive (back_button, FALSE);
2713         gtk_widget_set_sensitive (action_button, FALSE);
2714
2715         /* Need to set this here, otherwise callbacks called because
2716            of filtering won't perform correctly */
2717         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2718
2719         /* Reset action button */
2720         hildon_button_set_title (HILDON_BUTTON (action_button), NULL);
2721         hildon_button_set_value (HILDON_BUTTON (action_button), NULL);
2722         hildon_button_set_image (HILDON_BUTTON (action_button), NULL);
2723
2724         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
2725         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2726         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2727         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2728                                          MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2729         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2730                                        MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2731         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), 
2732                                          MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2733         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), 
2734                                        MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2735         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2736 }
2737
2738 static void
2739 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2740 {
2741         GtkWidget *back_button;
2742         GtkWidget *folder_view;
2743         TnyAccount *account;
2744         const gchar *account_id;
2745         GtkWidget *pannable;
2746         GtkWidget *action_button;
2747
2748         back_button =
2749                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2750         action_button =
2751                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2752         folder_view =
2753                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2754         pannable =
2755                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2756
2757         gtk_widget_set_sensitive (back_button, TRUE);
2758         gtk_widget_set_sensitive (action_button, TRUE);
2759
2760         /* Need to set this here, otherwise callbacks called because
2761            of filtering won't perform correctly */
2762         g_object_set_data (G_OBJECT (dialog),
2763                            MOVE_TO_DIALOG_SHOWING_FOLDERS,
2764                            GINT_TO_POINTER (TRUE));
2765
2766         account = TNY_ACCOUNT (folder_store);
2767         if (modest_tny_account_is_virtual_local_folders (account)) {
2768                 account_id = tny_account_get_id (account);
2769                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2770                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2771         } else if (modest_tny_account_is_memory_card_account (account)) {
2772                 account_id = tny_account_get_id (account);
2773                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2774                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2775         } else {
2776                 account_id = tny_account_get_id (account);
2777                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2778                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2779                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2780                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2781         }
2782
2783         move_to_dialog_set_selected_folder_store (dialog, folder_store);
2784         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2785                                                                      account_id);
2786
2787         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2788         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2789         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2790         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2791         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2792 }
2793
2794 static void
2795 on_move_to_dialog_back_clicked (GtkButton *button,
2796                                 gpointer userdata)
2797 {
2798         GtkWidget *dialog = (GtkWidget *) userdata;
2799
2800         /* Back to show accounts */
2801         move_to_dialog_show_accounts (dialog);
2802 }
2803
2804 static void
2805 on_move_to_dialog_row_activated (GtkTreeView       *tree_view,
2806                                     GtkTreePath       *path,
2807                                     GtkTreeViewColumn *column,
2808                                     gpointer           user_data)
2809 {
2810         TnyFolderStore *selected = NULL;
2811         GtkWidget *dialog;
2812         GtkWidget *folder_view;
2813         gboolean showing_folders;
2814
2815         dialog = (GtkWidget *) user_data;
2816         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), 
2817                                                               MOVE_TO_DIALOG_SHOWING_FOLDERS));
2818
2819         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), 
2820                                                      MOVE_TO_DIALOG_FOLDER_VIEW));
2821
2822         selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2823         if (!selected)
2824                 return;
2825
2826         if (!showing_folders) {
2827                 gboolean valid = TRUE;
2828
2829                 if (TNY_IS_ACCOUNT (selected) &&
2830                     modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2831                         ModestProtocolType protocol_type;
2832
2833                         protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2834                         valid  = !modest_protocol_registry_protocol_type_has_tag 
2835                                 (modest_runtime_get_protocol_registry (),
2836                                  protocol_type,
2837                                  MODEST_PROTOCOL_REGISTRY_STORE_FORBID_MESSAGE_ADD);
2838                 }
2839                 if (valid)
2840                         move_to_dialog_show_folders (dialog, selected);
2841         } else {
2842                 move_to_dialog_set_selected_folder_store (dialog, selected);
2843         }
2844 }
2845
2846 static void
2847 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2848                                      gpointer          user_data)
2849 {
2850         gboolean showing_folders;
2851         GtkWidget *dialog;
2852
2853         dialog = (GtkWidget *) user_data;
2854         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2855         if (showing_folders) {
2856                 TnyFolderStore *selected;
2857                 GtkWidget *folder_view;
2858
2859                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2860                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2861
2862                 if (selected) {
2863                         move_to_dialog_set_selected_folder_store (dialog, selected);
2864                         g_object_unref (selected);
2865                 }
2866         }
2867 }
2868
2869 static void
2870 on_move_to_dialog_action_clicked (GtkButton *selection,
2871                                   gpointer   user_data)
2872 {
2873         GtkWidget *dialog;
2874         gboolean showing_folders;
2875
2876         dialog = (GtkWidget *) user_data;
2877         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2878         if (showing_folders) {
2879                 TnyFolderStore *selected;
2880                 GtkWidget *folder_view;
2881
2882                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2883                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2884
2885                 if (selected) {
2886                         gtk_dialog_response  (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2887                         g_object_unref (selected);
2888                 }
2889         }
2890 }
2891
2892 static void
2893 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2894 {
2895         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (dialog), activity?1:0);
2896 }
2897
2898 GtkWidget *
2899 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2900                                        GtkWidget **folder_view)
2901 {
2902         GtkWidget *dialog, *folder_view_container;
2903         GtkWidget *align;
2904         GtkWidget *buttons_hbox;
2905         GtkWidget *back_button;
2906         GdkPixbuf *back_pixbuf;
2907         GtkWidget *top_vbox;
2908         GtkWidget *action_button;
2909         GtkTreeSelection *selection;
2910
2911         /* Create dialog. We cannot use a touch selector because we
2912            need to use here the folder view widget directly */
2913         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2914                                               GTK_WINDOW (parent_window),
2915                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2916                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2917                                               _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2918                                               NULL);
2919
2920         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2921         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2922         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2923
2924         /* Create folder view */
2925         *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2926         g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2927                           dialog);
2928
2929         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2930                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2931         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2932                                                FALSE);
2933         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2934                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2935
2936         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2937         back_button = gtk_button_new ();
2938         back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2939         if (back_pixbuf) {
2940                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2941                 g_object_unref (back_pixbuf);
2942         }
2943
2944         action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
2945                                            HILDON_BUTTON_ARRANGEMENT_VERTICAL);
2946         gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2947
2948         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2949         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2950         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2951         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2952         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2953
2954         /* Create pannable and add it to the dialog */
2955         folder_view_container = hildon_pannable_area_new ();
2956         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2957         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2958
2959         gtk_container_add (GTK_CONTAINER (align), top_vbox);
2960         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2961
2962         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2963
2964         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2965         gtk_widget_show (folder_view_container);
2966         gtk_widget_show (align);
2967         gtk_widget_show (top_vbox);
2968         gtk_widget_show (*folder_view);
2969         gtk_widget_show_all (back_button);
2970         gtk_widget_show (action_button);
2971         gtk_widget_show (buttons_hbox);
2972         gtk_widget_show (dialog);
2973
2974         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2975         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2976         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2977         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2978
2979         /* Simulate the behaviour of a HildonPickerDialog by emitting
2980            a response when a folder is selected */
2981         g_signal_connect (*folder_view, "row-activated",
2982                           G_CALLBACK (on_move_to_dialog_row_activated),
2983                           dialog);
2984
2985         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2986         g_signal_connect (selection, "changed",
2987                           G_CALLBACK (on_move_to_dialog_selection_changed),
2988                           dialog);
2989
2990         g_signal_connect (action_button, "clicked",
2991                           G_CALLBACK (on_move_to_dialog_action_clicked),
2992                           dialog);
2993
2994         g_signal_connect (back_button, "clicked",
2995                           G_CALLBACK (on_move_to_dialog_back_clicked),
2996                           dialog);
2997
2998         move_to_dialog_show_accounts (dialog);
2999
3000         return dialog;
3001 }
3002
3003 TnyList *
3004 modest_platform_get_list_to_move (ModestWindow *window)
3005 {
3006         TnyList *list = NULL;
3007
3008         if (MODEST_IS_HEADER_WINDOW (window)) {
3009                 ModestHeaderView *header_view;
3010
3011                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
3012                 list = modest_header_view_get_selected_headers (header_view);
3013         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
3014                 ModestFolderView *folder_view;
3015                 TnyFolderStore *selected_folder;
3016
3017                 list = TNY_LIST (tny_simple_list_new ());
3018                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
3019                 selected_folder = modest_folder_view_get_selected (folder_view);
3020                 if (selected_folder) {
3021                         tny_list_prepend (list, G_OBJECT (selected_folder));
3022                         g_object_unref (selected_folder);
3023                 }
3024                 return list;
3025         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3026                 TnyHeader *header;
3027
3028                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
3029                 if (header) {
3030                         list = TNY_LIST (tny_simple_list_new ());
3031                         tny_list_prepend (list, G_OBJECT (header));
3032                         g_object_unref (header);
3033                 }
3034         } else {
3035                 g_return_val_if_reached (NULL);
3036         }
3037
3038         return list;
3039 }