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