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