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