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