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