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