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