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