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