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