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