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