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