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