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