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