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