e46686fc8f3f640184070a46591f4d6c93da8317
[modest] / src / hildon2 / modest-platform.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31 #include <glib/gi18n.h>
32
33 #include <modest-platform.h>
34 #include <modest-defs.h>
35 #include <modest-runtime.h>
36 #include <modest-main-window.h>
37 #include <modest-header-view.h>
38 #include "modest-hildon2-global-settings-dialog.h"
39 #include "modest-widget-memory.h"
40 #include <modest-hildon-includes.h>
41 #include <modest-maemo-utils.h>
42 #include <modest-utils.h>
43 #include <dbus_api/modest-dbus-callbacks.h>
44 #include <libosso.h>
45 #include <tny-maemo-conic-device.h>
46 #include <tny-camel-folder.h>
47 #include <tny-simple-list.h>
48 #include <tny-merge-folder.h>
49 #include <tny-error.h>
50 #include <tny-folder.h>
51 #include <tny-account-store-view.h>
52 #include <gtk/gtkicontheme.h>
53 #include <gtk/gtkmenuitem.h>
54 #include <gtk/gtkmain.h>
55 #include <modest-text-utils.h>
56 #include "modest-tny-folder.h"
57 #include "modest-tny-account.h"
58 #include <string.h>
59 #include <libgnomevfs/gnome-vfs-mime-utils.h>
60 #include <modest-account-settings-dialog.h>
61 #include <modest-easysetup-wizard-dialog.h>
62 #include "modest-hildon2-sort-dialog.h"
63 #include <hildon/hildon.h>
64 #include <osso-mem.h>
65 #include "hildon2/modest-hildon2-details-dialog.h"
66 #include "hildon2/modest-hildon2-window-mgr.h"
67 #ifdef MODEST_USE_PROFILE
68 #include <keys_nokia.h>
69 #include <libprofile.h>
70 #endif
71 #include <canberra.h>
72 #include <modest-datetime-formatter.h>
73 #include "modest-header-window.h"
74 #include <modest-folder-window.h>
75 #include <modest-account-mgr.h>
76 #include <modest-account-mgr-helpers.h>
77 #include <modest-ui-constants.h>
78 #include <modest-selector-picker.h>
79 #include <modest-icon-names.h>
80 #include <modest-count-stream.h>
81 #include <math.h>
82
83 #ifdef MODEST_HAVE_MCE
84 #include <mce/dbus-names.h>
85 #endif /*MODEST_HAVE_MCE*/
86
87 #ifdef MODEST_HAVE_ABOOK
88 #include <libosso-abook/osso-abook.h>
89 #endif /*MODEST_HAVE_ABOOK*/
90
91 #ifdef MODEST_HAVE_LIBALARM
92 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
93 #endif /*MODEST_HAVE_LIBALARM*/
94
95
96 #define HILDON_OSSO_URI_ACTION "uri-action"
97 #define URI_ACTION_COPY "copy:"
98 #define MODEST_NOTIFICATION_CATEGORY "email-message"
99 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
100 #ifdef MODEST_USE_PROFILE
101 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
102 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
103 #else
104 #define MAIL_TONE "message-new-email"
105 #endif
106
107 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
108 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
109 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
110 #define FOLDER_PICKER_ORIGINAL_ACCOUNT "original-account"
111 #define MODEST_ALARMD_APPID PACKAGE_NAME
112
113 static ca_context *ca_con = NULL;
114 static gboolean ca_con_opened = FALSE;
115
116
117 static void modest_platform_play_email_tone (void);
118
119
120 static void     
121 on_modest_conf_update_interval_changed (ModestConf* self, 
122                                         const gchar *key, 
123                                         ModestConfEvent event,
124                                         ModestConfNotificationId id, 
125                                         gpointer user_data)
126 {
127         g_return_if_fail (key);
128         
129         if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
130                 const guint update_interval_minutes = 
131                         modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
132                 modest_platform_set_update_interval (update_interval_minutes);
133         }
134 }
135
136
137
138 static gboolean
139 check_required_files (void)
140 {
141         FILE *mcc_file = modest_utils_open_mcc_mapping_file ();
142
143         if (!mcc_file) {
144                 g_printerr ("modest: check for mcc file (for LANG) failed\n");
145                 return FALSE;
146         } else {
147                 fclose (mcc_file);
148         }
149
150         if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
151             access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
152                 g_printerr ("modest: cannot find providers data\n");
153                 return FALSE;
154         }
155
156         return TRUE;
157 }
158
159
160 /* the gpointer here is the osso_context. */
161 gboolean
162 modest_platform_init (int argc, char *argv[])
163 {
164         osso_context_t *osso_context;
165         osso_hw_state_t hw_state = { 0 };
166         DBusConnection *con;
167         GSList *acc_names;
168
169         if (!check_required_files ()) {
170                 g_printerr ("modest: missing required files\n");
171                 return FALSE;
172         }
173
174         osso_context = modest_maemo_utils_get_osso_context();
175
176         if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
177                 g_printerr ("modest: could not get dbus connection\n");
178                 return FALSE;
179         }
180
181         /* Add a D-Bus handler to be used when the main osso-rpc 
182          * D-Bus handler has not handled something.
183          * We use this for D-Bus methods that need to use more complex types 
184          * than osso-rpc supports. 
185          */
186         if (!dbus_connection_add_filter (con,
187                                          modest_dbus_req_filter,
188                                          NULL,
189                                          NULL)) {
190
191                 g_printerr ("modest: Could not add D-Bus filter\n");
192                 return FALSE;
193         }
194
195         /* Register our simple D-Bus callbacks, via the osso API: */
196         osso_return_t result = osso_rpc_set_cb_f(osso_context, 
197                                MODEST_DBUS_SERVICE, 
198                                MODEST_DBUS_OBJECT, 
199                                MODEST_DBUS_IFACE,
200                                modest_dbus_req_handler, NULL /* user_data */);
201         if (result != OSSO_OK) {
202                 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
203                 return FALSE;
204         }
205
206         /* Register hardware event dbus callback: */
207         hw_state.shutdown_ind = TRUE;
208         osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
209
210         /* Make sure that the update interval is changed whenever its gconf key 
211          * is changed */
212         /* CAUTION: we're not using here the
213            modest_conf_listen_to_namespace because we know that there
214            are other parts of Modest listening for this namespace, so
215            we'll receive the notifications anyway. We basically do not
216            use it because there is no easy way to do the
217            modest_conf_forget_namespace */
218         ModestConf *conf = modest_runtime_get_conf ();
219         g_signal_connect (G_OBJECT(conf),
220                           "key_changed",
221                           G_CALLBACK (on_modest_conf_update_interval_changed), 
222                           NULL);
223
224         /* only force the setting of the default interval, if there are actually
225          * any accounts */
226         acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
227         if (acc_names) {
228                 /* Get the initial update interval from gconf: */
229                 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
230                                                        MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
231                 modest_account_mgr_free_account_names (acc_names);
232         }
233
234         
235 #ifdef MODEST_HAVE_ABOOK
236         /* initialize the addressbook */
237         if (!osso_abook_init (&argc, &argv, osso_context)) {
238                 g_printerr ("modest: failed to initialized addressbook\n");
239                 return FALSE;
240         }
241 #endif /*MODEST_HAVE_ABOOK*/
242
243         return TRUE;
244 }
245
246 gboolean
247 modest_platform_uninit (void)
248 {
249         osso_context_t *osso_context =
250                 modest_maemo_utils_get_osso_context ();
251         if (osso_context)
252                 osso_deinitialize (osso_context);
253
254         return TRUE;
255 }
256
257
258
259
260 TnyDevice*
261 modest_platform_get_new_device (void)
262 {
263         return TNY_DEVICE (tny_maemo_conic_device_new ());
264 }
265
266 gchar*
267 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
268                                     gchar **effective_mime_type)
269 {
270         GString *mime_str = NULL;
271         gchar *icon_name  = NULL;
272         gchar **icons, **cursor;
273         
274         if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) 
275                 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
276         else {
277                 mime_str = g_string_new (mime_type);
278                 g_string_ascii_down (mime_str);
279         }
280         
281         icons = hildon_mime_get_icon_names (mime_str->str, NULL);
282         
283         for (cursor = icons; cursor; ++cursor) {
284                 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
285                     !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
286                         icon_name = g_strdup ("qgn_list_messagin");
287                         break;
288                 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
289                         icon_name = g_strdup (*cursor);
290                         break;
291                 }
292         }
293         g_strfreev (icons);
294
295         if (effective_mime_type)
296                 *effective_mime_type = g_string_free (mime_str, FALSE);
297         else
298                 g_string_free (mime_str, TRUE);
299         
300         return icon_name;
301 }
302
303
304 static gboolean
305 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
306 {
307         GError *err = NULL;
308         gboolean result;
309
310         g_return_val_if_fail (uri, FALSE);
311         
312         result = hildon_uri_open (uri, action, &err);
313         if (!result) {
314                 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
315                             uri, action,  err && err->message ? err->message : "unknown error");
316                 if (err)
317                         g_error_free (err);
318         }
319         return result;
320 }
321
322
323
324 gboolean 
325 modest_platform_activate_uri (const gchar *uri)
326 {
327         HildonURIAction *action;
328         gboolean result = FALSE;
329         GSList *actions, *iter = NULL;
330         
331         g_return_val_if_fail (uri, FALSE);
332         if (!uri)
333                 return FALSE;
334
335         /* don't try to activate file: uri's -- they might confuse the user,
336          * and/or might have security implications */
337         if (!g_str_has_prefix (uri, "file:")) {
338                 
339                 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
340                 
341                 for (iter = actions; iter; iter = g_slist_next (iter)) {
342                         action = (HildonURIAction*) iter->data;
343                         if (action && strcmp (hildon_uri_action_get_service (action),
344                                               "com.nokia.modest") == 0) {
345                                 result = checked_hildon_uri_open (uri, action);
346                                 break;
347                         }
348                 }
349                 
350                 /* if we could not open it with email, try something else */
351                 if (!result)
352                         result = checked_hildon_uri_open (uri, NULL);   
353         } 
354         
355         if (!result) {
356                 ModestWindow *parent =
357                         modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
358                 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
359                                                 _("mcen_ib_unsupported_link"));
360                 g_debug ("%s: cannot open uri '%s'", __FUNCTION__,uri);
361         } 
362         
363         return result;
364 }
365
366 gboolean 
367 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
368 {
369         gint result = 0;
370         DBusConnection *con;
371         gchar *uri_path = NULL;
372         
373         uri_path = gnome_vfs_get_uri_from_local_path (path);    
374         con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
375         
376         if (mime_type)
377                 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
378         if (result != 1)
379                 result = hildon_mime_open_file (con, uri_path);
380         if (result != 1)
381                 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
382         
383         return result != 1;
384 }
385
386 typedef struct  {
387         GSList *actions;
388         gchar  *uri;
389 } ModestPlatformPopupInfo;
390
391 static gboolean
392 delete_uri_popup (GtkWidget *menu,
393                   GdkEvent *event,
394                   gpointer userdata)
395 {
396         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
397
398         g_free (popup_info->uri);
399         hildon_uri_free_actions (popup_info->actions);
400
401         return FALSE;
402 }
403
404 static void
405 activate_uri_popup_item (GtkMenuItem *menu_item,
406                          gpointer userdata)
407 {
408         GSList *node;
409         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
410         const gchar* action_name;
411
412         action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
413         if (!action_name) {
414                 g_printerr ("modest: no action name defined\n");
415                 return;
416         }
417
418         /* special handling for the copy menu item -- copy the uri to the clipboard */
419         /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
420         if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
421                 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
422                 const gchar *uri = (const gchar *) popup_info->uri;
423
424                 /* Special case: ignore "mailto:" prefixes */
425                 if (g_str_has_prefix (uri, "mailto:"))
426                         uri = popup_info->uri + strlen ("mailto:");
427
428                 gtk_clipboard_set_text (clipboard, uri, strlen (uri));
429                 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
430                 return; /* we're done */
431         }
432
433         /* now, the real uri-actions... */
434         for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
435                 HildonURIAction *action = (HildonURIAction *) node->data;
436                 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
437                         if (!checked_hildon_uri_open (popup_info->uri, action)) {
438                                 ModestWindow *parent =
439                                         modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
440                                 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
441                                                                 _("mcen_ib_unsupported_link"));
442                         }
443                         break;
444                 }
445         }
446 }
447
448 gboolean
449 modest_platform_show_uri_popup (const gchar *uri)
450 {
451         GSList *actions_list, *node;
452         GtkWidget *menu;
453         ModestPlatformPopupInfo *popup_info;
454         GtkWidget *menu_item;
455
456         if (uri == NULL)
457                 return FALSE;
458
459         /* Create menu */
460         menu = gtk_menu_new ();
461         popup_info = g_new0 (ModestPlatformPopupInfo, 1);
462         popup_info->uri = g_strdup (uri);
463
464         /* don't add actions for file: uri's -- they might confuse the user,
465          * and/or might have security implications
466          * we still allow to copy the url though
467          */
468         if (g_str_has_prefix (uri, "file:"))
469                 goto add_copy_link;
470
471         actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
472         if (!actions_list)
473                 goto add_copy_link;
474
475         popup_info->actions = actions_list;
476         for (node = actions_list; node != NULL; node = g_slist_next (node)) {
477                 const gchar *action_name;
478                 const gchar *translation_domain;
479                 HildonURIAction *action = (HildonURIAction *) node->data;
480                 action_name = hildon_uri_action_get_name (action);
481                 translation_domain = hildon_uri_action_get_translation_domain (action);
482                 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
483                 hildon_gtk_widget_set_theme_size (menu_item, MODEST_EDITABLE_SIZE);
484                 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);  /* hack */
485                 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
486                                   popup_info);
487
488                 if (hildon_uri_is_default_action (action, NULL)) {
489                         gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
490                 } else {
491                         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
492                 }
493                 gtk_widget_show (menu_item);
494         }
495
496  add_copy_link:
497         /* Add the "Copy link" menu option */
498         menu_item = gtk_menu_item_new_with_label (_UR("uri_link_copy_link_location"));
499         hildon_gtk_widget_set_theme_size (menu_item, MODEST_EDITABLE_SIZE);
500         g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer) URI_ACTION_COPY);
501         g_signal_connect (G_OBJECT (menu_item), "activate", (GCallback) activate_uri_popup_item, popup_info);
502         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
503         gtk_widget_show (menu_item);
504
505         /* and what to do when the link is deleted */
506         g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
507         gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
508
509         return TRUE;
510 }
511
512
513 GdkPixbuf*
514 modest_platform_get_icon (const gchar *name, guint icon_size)
515 {
516         GError *err = NULL;
517         GdkPixbuf* pixbuf = NULL;
518         GtkIconTheme *current_theme = NULL;
519
520         g_return_val_if_fail (name, NULL);
521
522         /* strlen == 0 is not really an error; it just
523          * means the icon is not available
524          */
525         if (!name || strlen(name) == 0)
526                 return NULL;
527
528         current_theme = gtk_icon_theme_get_default ();
529         pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
530                                            GTK_ICON_LOOKUP_NO_SVG,
531                                            &err);
532         if (!pixbuf) {
533                 g_warning ("Error loading theme icon '%s': %s\n",
534                             name, err->message);
535                 g_error_free (err);
536         } 
537         return pixbuf;
538 }
539
540 const gchar*
541 modest_platform_get_app_name (void)
542 {
543         return _("mcen_ap_name");
544 }
545
546 static void
547 entry_insert_text (GtkEditable *editable,
548                    const gchar *text,
549                    gint         length,
550                    gint        *position,
551                    gpointer     data)
552 {
553         gchar *chars;
554         gint chars_length;
555
556         chars = gtk_editable_get_chars (editable, 0, -1);
557         chars_length = g_utf8_strlen (chars, -1);
558         g_free (chars);
559
560         /* Show WID-INF036 */
561         if (chars_length >= 20) {
562                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
563                                                  _CS("ckdg_ib_maximum_characters_reached"));
564         } else {
565                 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
566                         /* Show an error */
567                         gchar *tmp, *msg;
568
569                         tmp = g_strndup (folder_name_forbidden_chars,
570                                          FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
571                         msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
572                         hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)),
573                                                          NULL, msg);
574                         g_free (msg);
575                         g_free (tmp);
576                 } else {
577                         if (length >= 20) {
578                                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
579                                                                  _CS("ckdg_ib_maximum_characters_reached"));
580                         }
581                         /* Write the text in the entry if it's valid */
582                         g_signal_handlers_block_by_func (editable,
583                                                          (gpointer) entry_insert_text, data);
584                         gtk_editable_insert_text (editable, text, length, position);
585                         g_signal_handlers_unblock_by_func (editable,
586                                                            (gpointer) entry_insert_text, data);
587                 }
588         }
589         /* Do not allow further processing */
590         g_signal_stop_emission_by_name (editable, "insert_text");
591 }
592
593 static void
594 entry_changed (GtkEditable *editable,
595                gpointer     user_data)
596 {
597         gchar *chars;
598         GtkWidget *ok_button;
599         GList *buttons;
600
601         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
602         ok_button = GTK_WIDGET (buttons->data);
603
604         chars = gtk_editable_get_chars (editable, 0, -1);
605         g_return_if_fail (chars != NULL);
606
607
608         if (g_utf8_strlen (chars,-1) >= 20) {
609                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
610                                                  _CS("ckdg_ib_maximum_characters_reached"));
611         }
612         gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
613
614         /* Free */
615         g_list_free (buttons);
616         g_free (chars);
617 }
618
619
620
621 static void
622 on_response (GtkDialog *dialog,
623              gint response,
624              gpointer user_data)
625 {
626         GtkWidget *entry, *picker;
627         TnyFolderStore *parent;
628         const gchar *new_name;
629         gboolean exists;
630
631         if (response != GTK_RESPONSE_ACCEPT)
632                 return;
633
634         /* Get entry */
635         entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
636         picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
637
638         parent = TNY_FOLDER_STORE (user_data);
639         new_name = gtk_entry_get_text (GTK_ENTRY (entry));
640         exists = FALSE;
641
642         if (picker != NULL)
643                 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
644
645         /* Look for another folder with the same name */
646         if (!TNY_IS_MERGE_FOLDER (parent) &&
647             modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
648                 exists = TRUE;
649
650         if (!exists) {
651                 if (TNY_IS_ACCOUNT (parent) &&
652                     modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
653                     modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
654                                                                          new_name)) {
655                         exists = TRUE;
656                 }
657         }
658
659         if (exists) {
660                 /* Show an error */
661                 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)), 
662                                                 NULL, _CS("ckdg_ib_folder_already_exists"));
663                 /* Select the text */
664                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
665                 gtk_widget_grab_focus (entry);
666                 /* Do not close the dialog */
667                 g_signal_stop_emission_by_name (dialog, "response");
668         }
669 }
670
671 typedef struct _FolderChooserData {
672         TnyFolderStore *store;
673         GtkWidget *dialog;
674 } FolderChooserData;
675
676 static void
677 folder_chooser_activated (ModestFolderView *folder_view,
678                           TnyFolderStore *folder,
679                           FolderChooserData *userdata)
680 {
681         userdata->store = folder;
682         gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
683 }
684
685 static TnyFolderStore *
686 folder_chooser_dialog_run (ModestFolderView *original,
687                            TnyFolderStore *current,
688                            GtkButton *picker)
689 {
690         GtkWidget *folder_view;
691         FolderChooserData userdata = {NULL, NULL};
692         GtkWidget *pannable;
693         const gchar *visible_id = NULL;
694
695         userdata.dialog = gtk_dialog_new ();
696         pannable = hildon_pannable_area_new ();
697         folder_view = modest_platform_create_folder_view (NULL);
698
699         gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
700
701         modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
702                                        MODEST_FOLDER_VIEW (folder_view));
703
704         if (TNY_IS_ACCOUNT (current)) {
705                 /* Local folders and MMC account are always shown
706                    along with the currently visible server account */
707                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (current)) ||
708                     modest_tny_account_is_memory_card_account (TNY_ACCOUNT (current)))
709                         visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
710                 else
711                         visible_id = tny_account_get_id (TNY_ACCOUNT (current));
712         } else if (TNY_IS_FOLDER (current)) {
713                 TnyAccount *account;
714                 account = modest_tny_folder_get_account ((TnyFolder *) current);
715                 if (account) {
716                         if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (account)) ||
717                             modest_tny_account_is_memory_card_account (TNY_ACCOUNT (account))) {
718                                 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
719                         } else {
720                                 visible_id = tny_account_get_id (account);
721                         }
722                         g_object_unref (account);
723                 }
724         } else {
725                 visible_id =
726                         modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
727         }
728
729         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
730                                                                      visible_id);
731
732         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
733         gtk_container_add (GTK_CONTAINER (pannable), folder_view);
734         gtk_widget_set_size_request (pannable, -1, 320);
735
736         gtk_widget_show (folder_view);
737         gtk_widget_show (pannable);
738         gtk_widget_show (userdata.dialog);
739         g_signal_connect (G_OBJECT (folder_view), "folder-activated", 
740                           G_CALLBACK (folder_chooser_activated), 
741                           (gpointer) &userdata);
742
743         gtk_dialog_run (GTK_DIALOG (userdata.dialog));
744         gtk_widget_destroy (userdata.dialog);
745
746         return userdata.store;
747 }
748
749 static gchar *
750 folder_store_get_display_name (TnyFolderStore *store)
751 {
752         if (TNY_IS_ACCOUNT (store)) {
753                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
754                         return modest_conf_get_string (modest_runtime_get_conf(),
755                                                        MODEST_CONF_DEVICE_NAME, NULL);
756                 else
757                         return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
758         } else {
759                 gchar *fname;
760                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
761
762                 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
763                 type = tny_folder_get_folder_type (TNY_FOLDER (store));
764                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
765                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
766                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
767                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
768                                 g_free (fname);
769                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
770                         }
771                 } else {
772                         /* Sometimes an special folder is reported by the server as
773                            NORMAL, like some versions of Dovecot */
774                         if (type == TNY_FOLDER_TYPE_NORMAL ||
775                             type == TNY_FOLDER_TYPE_UNKNOWN) {
776                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
777                         }
778                 }
779
780                 if (type == TNY_FOLDER_TYPE_INBOX) {
781                         g_free (fname);
782                         fname = g_strdup (_("mcen_me_folder_inbox"));
783                 }
784                 return fname;
785         }
786 }
787
788 GtkWidget *
789 get_image_for_folder_store (TnyFolderStore *store,
790                             gint size)
791 {
792         GdkPixbuf *pixbuf;
793         const gchar *icon_name = NULL;
794         GtkWidget *image = NULL;
795
796         if (TNY_IS_ACCOUNT (store)) {
797                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
798                         icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
799                 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
800                         icon_name = MODEST_FOLDER_ICON_MMC;
801                 else
802                         icon_name = MODEST_FOLDER_ICON_ACCOUNT;
803         } else {
804                 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
805                 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
806                         switch (type) {
807                         case TNY_FOLDER_TYPE_INBOX:
808                                 icon_name = MODEST_FOLDER_ICON_INBOX;
809                                 break;
810                         default:
811                                 icon_name = MODEST_FOLDER_ICON_REMOTE_FOLDER;
812                         }
813                 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
814                         switch (type) {
815                         case TNY_FOLDER_TYPE_OUTBOX:
816                                 icon_name = MODEST_FOLDER_ICON_OUTBOX;
817                                 break;
818                         case TNY_FOLDER_TYPE_DRAFTS:
819                                 icon_name = MODEST_FOLDER_ICON_DRAFTS;
820                                 break;
821                         case TNY_FOLDER_TYPE_SENT:
822                                 icon_name = MODEST_FOLDER_ICON_SENT;
823                                 break;
824                         default:
825                                 icon_name = MODEST_FOLDER_ICON_NORMAL;
826                         }
827                 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
828                         icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
829                 }
830         }
831
832         /* Set icon */
833         pixbuf = modest_platform_get_icon (icon_name, size);
834
835         if (pixbuf) {
836                 image = gtk_image_new_from_pixbuf (pixbuf);
837                 g_object_unref (pixbuf);
838         }
839
840         return image;
841 }
842
843 static void
844 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
845 {
846         gchar *name;
847
848         if (store == NULL) {
849                 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
850         } else {
851                 GtkWidget *image;
852
853                 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
854                                         g_object_ref (store),
855                                         (GDestroyNotify) g_object_unref);
856                 name = folder_store_get_display_name (store);
857                 hildon_button_set_value (HILDON_BUTTON (button), name);
858                 g_free (name);
859
860                 /* Select icon */
861                 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
862                 if (image)
863                         hildon_button_set_image (HILDON_BUTTON (button), image);
864         }
865 }
866
867 /* Always returns DUPs so you must free the returned value */
868 static gchar *
869 get_next_folder_name (const gchar *suggested_name, 
870                       TnyFolderStore *suggested_folder)
871 {
872         const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
873         unsigned int i;
874         gchar *real_suggested_name;
875
876         if (suggested_name !=NULL) {
877                 return g_strdup (suggested_name);
878         }
879
880         for(i = 0; i < 100; ++ i) {
881                 gboolean exists = FALSE;
882
883                 if (i == 0)
884                         real_suggested_name = g_strdup (default_name);
885                 else
886                         real_suggested_name = g_strdup_printf ("%s(%d)",
887                                                                _FM("ckdg_va_new_folder_name_stub"),
888                                                                i);
889                 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
890                                                                     real_suggested_name,
891                                                                     TRUE);
892
893                 if (!exists)
894                         break;
895
896                 g_free (real_suggested_name);
897         }
898
899         /* Didn't find a free number */
900         if (i == 100)
901                 real_suggested_name = g_strdup (default_name);
902
903         return real_suggested_name;
904 }
905
906 typedef struct {
907         ModestFolderView *folder_view;
908         GtkEntry *entry;
909 } FolderPickerHelper;
910
911 static void
912 folder_picker_clicked (GtkButton *button,
913                        FolderPickerHelper *helper)
914 {
915         TnyFolderStore *store, *current;
916
917         current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
918
919         store = folder_chooser_dialog_run (helper->folder_view, current, button);
920         if (store) {
921                 const gchar *current_name;
922                 gboolean exists = FALSE;
923
924                 folder_picker_set_store (GTK_BUTTON (button), store);
925
926                 /* Update the name of the folder */
927                 current_name = gtk_entry_get_text (helper->entry);
928
929                 if (TNY_IS_FOLDER_STORE (store))
930                         exists = modest_tny_folder_has_subfolder_with_name (store,
931                                                                             current_name,
932                                                                             TRUE);
933                 if (exists) {
934                         gchar *new_name = get_next_folder_name (NULL, store);
935                         gtk_entry_set_text (helper->entry, new_name);
936                         g_free (new_name);
937                 }
938         }
939 }
940
941 static GtkWidget *
942 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
943 {
944         GtkWidget *button;
945         const gchar *acc_id = NULL;
946
947         button = hildon_button_new (MODEST_EDITABLE_SIZE,
948                                     HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
949
950         hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
951
952         if (suggested) {
953
954                 folder_picker_set_store (GTK_BUTTON (button), suggested);
955
956                 if (TNY_IS_ACCOUNT (suggested)) {
957                         if (!modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (suggested)) &&
958                             !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (suggested)))
959                                 acc_id = tny_account_get_id ((TnyAccount *) suggested);
960                 } else {
961                         TnyAccount *account = modest_tny_folder_get_account ((TnyFolder *) suggested);
962                         if (account) {
963                                 acc_id = tny_account_get_id ((TnyAccount *) account);
964                                 g_object_unref (account);
965                         }
966                 }
967         }
968
969         if (!acc_id)
970                 acc_id = modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(helper->folder_view));
971
972         g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_ORIGINAL_ACCOUNT,
973                                 g_strdup (acc_id), (GDestroyNotify) g_free);
974
975
976         g_signal_connect (G_OBJECT (button), "clicked",
977                           G_CALLBACK (folder_picker_clicked),
978                           helper);
979
980         return button;
981 }
982
983
984 static gint
985 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
986                                           TnyFolderStore *suggested_parent,
987                                           const gchar *dialog_title,
988                                           const gchar *label_text,
989                                           const gchar *suggested_name,
990                                           gboolean show_name,
991                                           gboolean show_parent,
992                                           gchar **folder_name,
993                                           TnyFolderStore **parent)
994 {
995         GtkWidget *accept_btn = NULL;
996         GtkWidget *dialog, *entry = NULL, *label_entry = NULL,  *label_location = NULL, *hbox;
997         GtkWidget *account_picker = NULL;
998         GList *buttons = NULL;
999         gint result;
1000         GtkSizeGroup *sizegroup;
1001         ModestFolderView *folder_view;
1002         ModestWindow *folder_window;
1003         ModestHildon2WindowMgr *window_mgr;
1004         FolderPickerHelper *helper = NULL;
1005         GtkWidget *top_vbox, *top_align;
1006
1007         window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
1008         folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
1009         g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
1010         
1011         folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
1012         
1013         top_vbox = gtk_vbox_new (FALSE, 0);
1014         top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1015         gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1016         
1017         /* Ask the user for the folder name */
1018         dialog = gtk_dialog_new_with_buttons (dialog_title,
1019                                               parent_window,
1020                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
1021                                               _FM("ckdg_bd_new_folder_dialog_ok"),
1022                                               GTK_RESPONSE_ACCEPT,
1023                                               NULL);
1024
1025         /* Add accept button (with unsensitive handler) */
1026         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
1027         accept_btn = GTK_WIDGET (buttons->data);
1028
1029         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
1030
1031         if (show_name) {
1032                 label_entry = gtk_label_new (label_text);
1033                 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
1034                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
1035
1036                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
1037                 gtk_size_group_add_widget (sizegroup, label_entry);
1038                 
1039                 if (suggested_name)
1040                   gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
1041                 else
1042                         gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
1043                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
1044                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
1045                                                 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
1046                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
1047         }
1048         
1049         if (show_parent) {
1050           
1051                 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
1052
1053                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
1054                 gtk_size_group_add_widget (sizegroup, label_location);
1055
1056                 helper = g_slice_new0 (FolderPickerHelper);
1057                 helper->folder_view = folder_view;
1058                 helper->entry = (GtkEntry *) entry;
1059
1060                 account_picker = folder_picker_new (suggested_parent, helper);
1061         }
1062
1063         g_object_unref (sizegroup);
1064         
1065         /* Connect to the response method to avoid closing the dialog
1066            when an invalid name is selected*/
1067         g_signal_connect (dialog,
1068                           "response",
1069                           G_CALLBACK (on_response),
1070                           suggested_parent);
1071         
1072         if (show_name) {
1073                 /* Track entry changes */
1074                 g_signal_connect (entry,
1075                                   "insert-text",
1076                                   G_CALLBACK (entry_insert_text),
1077                                   dialog);
1078                 g_signal_connect (entry,
1079                                   "changed",
1080                                   G_CALLBACK (entry_changed),
1081                                   dialog);
1082         }
1083         
1084         
1085         /* Some locales like pt_BR need this to get the full window
1086            title shown */
1087         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
1088         
1089         /* Create the hbox */
1090         if (show_name) {
1091                 hbox = gtk_hbox_new (FALSE, 12);
1092                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
1093                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
1094                 
1095                 /* Add hbox to dialog */
1096                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1097                                     hbox, FALSE, FALSE, 0);
1098                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
1099         }
1100
1101         if (show_parent) {
1102                 hbox = gtk_hbox_new (FALSE, 12);
1103                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
1104                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
1105
1106                 /* Add hbox to dialog */
1107                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1108                                     hbox, FALSE, FALSE, 0);
1109                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
1110         }
1111         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1112                                      GTK_WINDOW (dialog), parent_window);
1113
1114         gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
1115         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
1116
1117         gtk_widget_show_all (GTK_WIDGET(dialog));
1118
1119         result = gtk_dialog_run (GTK_DIALOG(dialog));
1120         if (result == GTK_RESPONSE_ACCEPT) {
1121                 if (show_name)
1122                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1123                 if (show_parent) {
1124                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
1125                         if (*parent)
1126                                 g_object_ref (*parent);
1127                 }
1128         }
1129
1130         gtk_widget_destroy (dialog);
1131
1132         if (helper)
1133                 g_slice_free (FolderPickerHelper, helper);
1134
1135         while (gtk_events_pending ())
1136                 gtk_main_iteration ();
1137
1138         return result;
1139 }
1140
1141 gint
1142 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
1143                                        TnyFolderStore *suggested_folder,
1144                                        gchar *suggested_name,
1145                                        gchar **folder_name,
1146                                        TnyFolderStore **parent_folder)
1147 {
1148         gchar *real_suggested_name = NULL;
1149         gint result;
1150         ModestTnyAccountStore *acc_store;
1151         TnyAccount *account;
1152         gboolean do_free = FALSE;
1153
1154         real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
1155                                                     suggested_folder);
1156
1157         /* In hildon 2.2 we always suggest the archive folder as parent */
1158         if (!suggested_folder) {
1159                 acc_store = modest_runtime_get_account_store ();
1160                 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1161                 if (account) {
1162                         suggested_folder = (TnyFolderStore *)
1163                                 modest_tny_account_get_special_folder (account,
1164                                                                        TNY_FOLDER_TYPE_ARCHIVE);
1165                         g_object_unref (account);
1166                         account = NULL;
1167                 }
1168         }
1169
1170         /* If there is not archive folder then fallback to local folders account */
1171         if (!suggested_folder) {
1172                 do_free = TRUE;
1173                 suggested_folder = (TnyFolderStore *)
1174                         modest_tny_account_store_get_local_folders_account (acc_store);
1175         }
1176
1177         result = modest_platform_run_folder_common_dialog (parent_window,
1178                                                            suggested_folder,
1179                                                            _HL("ckdg_ti_new_folder"),
1180                                                            _FM("ckdg_fi_new_folder_name"),
1181                                                            real_suggested_name,
1182                                                            TRUE,
1183                                                            TRUE,
1184                                                            folder_name,
1185                                                            parent_folder);
1186
1187         if (do_free)
1188                 g_object_unref (suggested_folder);
1189
1190         g_free(real_suggested_name);
1191
1192         return result;
1193 }
1194
1195 gint
1196 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1197                                           TnyFolderStore *parent_folder,
1198                                           const gchar *suggested_name,
1199                                           gchar **folder_name)
1200 {
1201         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1202
1203         return modest_platform_run_folder_common_dialog (parent_window, 
1204                                                          parent_folder,
1205                                                          _HL("ckdg_ti_rename_folder"),
1206                                                          _HL("ckdg_fi_rename_name"),
1207                                                          suggested_name,
1208                                                          TRUE,
1209                                                          FALSE,
1210                                                          folder_name,
1211                                                          NULL);
1212 }
1213
1214
1215
1216 static void
1217 on_destroy_dialog (GtkWidget *dialog)
1218 {
1219         /* This could happen when the dialogs get programatically
1220            hidden or destroyed (for example when closing the
1221            application while a dialog is being shown) */
1222         if (!GTK_IS_WIDGET (dialog))
1223                 return;
1224
1225         gtk_widget_destroy (dialog);
1226
1227         if (gtk_events_pending ())
1228                 gtk_main_iteration ();
1229 }
1230
1231 gint
1232 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1233                                          const gchar *message)
1234 {
1235         GtkWidget *dialog;
1236         gint response;
1237         
1238         dialog = hildon_note_new_confirmation (parent_window, message);
1239         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1240                                      GTK_WINDOW (dialog), parent_window);
1241
1242         response = gtk_dialog_run (GTK_DIALOG (dialog));
1243
1244         on_destroy_dialog (dialog);
1245
1246         return response;
1247 }
1248
1249 gint
1250 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1251                                                       const gchar *message,
1252                                                       const gchar *button_accept,
1253                                                       const gchar *button_cancel)
1254 {
1255         GtkWidget *dialog;
1256         gint response;
1257         
1258         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1259                                                            button_accept, GTK_RESPONSE_ACCEPT,
1260                                                            button_cancel, GTK_RESPONSE_CANCEL,
1261                                                            NULL);
1262
1263         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1264                                      GTK_WINDOW (dialog), parent_window);
1265
1266         response = gtk_dialog_run (GTK_DIALOG (dialog));
1267
1268         on_destroy_dialog (dialog);
1269
1270         return response;
1271 }
1272         
1273 void
1274 modest_platform_run_information_dialog (GtkWindow *parent_window,
1275                                         const gchar *message,
1276                                         gboolean block)
1277 {
1278         GtkWidget *note;
1279         
1280         note = hildon_note_new_information (parent_window, message);
1281         if (block)
1282                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1283                                              GTK_WINDOW (note), parent_window);
1284         
1285         if (block) {
1286                 gtk_dialog_run (GTK_DIALOG (note));
1287         
1288                 on_destroy_dialog (note);
1289         } else {
1290                 g_signal_connect_swapped (note,
1291                                           "response", 
1292                                           G_CALLBACK (on_destroy_dialog),
1293                                           note);
1294
1295                 gtk_widget_show_all (note);
1296         }
1297 }
1298
1299 typedef struct _ConnectAndWaitData {
1300         GMutex *mutex;
1301         GMainLoop *wait_loop;
1302         gboolean has_callback;
1303         gulong handler;
1304 } ConnectAndWaitData;
1305
1306
1307 static void
1308 quit_wait_loop (TnyAccount *account,
1309                 ConnectAndWaitData *data) 
1310 {
1311         /* Set the has_callback to TRUE (means that the callback was
1312            executed and wake up every code waiting for cond to be
1313            TRUE */
1314         g_mutex_lock (data->mutex);
1315         data->has_callback = TRUE;
1316         if (data->wait_loop)
1317                 g_main_loop_quit (data->wait_loop);
1318         g_mutex_unlock (data->mutex);
1319 }
1320
1321 static void
1322 on_connection_status_changed (TnyAccount *account, 
1323                               TnyConnectionStatus status,
1324                               gpointer user_data)
1325 {
1326         TnyConnectionStatus conn_status;
1327         ConnectAndWaitData *data;
1328                         
1329         /* Ignore if reconnecting or disconnected */
1330         conn_status = tny_account_get_connection_status (account);
1331         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1332             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1333                 return;
1334
1335         /* Remove the handler */
1336         data = (ConnectAndWaitData *) user_data;
1337         g_signal_handler_disconnect (account, data->handler);
1338
1339         /* Quit from wait loop */
1340         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1341 }
1342
1343 static void
1344 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
1345                                     gboolean canceled, 
1346                                     GError *err, 
1347                                     gpointer user_data)
1348 {
1349         /* Quit from wait loop */
1350         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1351 }
1352
1353 gboolean 
1354 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1355                                   TnyAccount *account)
1356 {
1357         ConnectAndWaitData *data = NULL;
1358         gboolean device_online;
1359         TnyDevice *device;
1360         TnyConnectionStatus conn_status;
1361         gboolean user_requested;
1362         
1363         device = modest_runtime_get_device();
1364         device_online = tny_device_is_online (device);
1365
1366         /* Whether the connection is user requested or automatically
1367            requested, for example via D-Bus */
1368         user_requested = (parent_window) ? TRUE : FALSE;
1369
1370         /* If there is no account check only the device status */
1371         if (!account) {
1372                 if (device_online)
1373                         return TRUE;
1374                 else
1375                         return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1376                                                                NULL, user_requested);
1377         }
1378
1379         /* Return if the account is already connected */
1380         conn_status = tny_account_get_connection_status (account);
1381         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1382                 return TRUE;
1383
1384         /* Create the helper */
1385         data = g_slice_new0 (ConnectAndWaitData);
1386         data->mutex = g_mutex_new ();
1387         data->has_callback = FALSE;
1388
1389         /* Connect the device */
1390         if (!device_online) {
1391                 /* Track account connection status changes */
1392                 data->handler = g_signal_connect (account, "connection-status-changed",
1393                                                   G_CALLBACK (on_connection_status_changed),
1394                                                   data);
1395                 /* Try to connect the device */
1396                 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1397                                                                 NULL, user_requested);
1398
1399                 /* If the device connection failed then exit */
1400                 if (!device_online && data->handler)
1401                         goto frees;
1402         } else {
1403                 /* Force a reconnection of the account */
1404                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1405                                               on_tny_camel_account_set_online_cb, data);
1406         }
1407
1408         /* Wait until the callback is executed */
1409         g_mutex_lock (data->mutex);
1410         if (!data->has_callback) {
1411                 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1412                 gdk_threads_leave ();
1413                 g_mutex_unlock (data->mutex);
1414                 g_main_loop_run (data->wait_loop);
1415                 g_mutex_lock (data->mutex);
1416                 gdk_threads_enter ();
1417         }
1418         g_mutex_unlock (data->mutex);
1419
1420  frees:
1421         if (g_signal_handler_is_connected (account, data->handler))
1422                 g_signal_handler_disconnect (account, data->handler);
1423         g_mutex_free (data->mutex);
1424         g_main_loop_unref (data->wait_loop);
1425         g_slice_free (ConnectAndWaitData, data);
1426
1427         conn_status = tny_account_get_connection_status (account);
1428         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1429 }
1430
1431 gboolean 
1432 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1433 {
1434         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1435                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1436                         /* This must be a maildir account, which does not require a connection: */
1437                         return TRUE;
1438                 }
1439         }
1440
1441         return modest_platform_connect_and_wait (parent_window, account);
1442 }
1443
1444 gboolean 
1445 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1446 {
1447         if (!folder_store)
1448                 return TRUE; /* Maybe it is something local. */
1449                 
1450         gboolean result = TRUE;
1451         if (TNY_IS_FOLDER (folder_store)) {
1452                 /* Get the folder's parent account: */
1453                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1454                 if (account != NULL) {
1455                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1456                         g_object_unref (account);
1457                 }
1458         } else if (TNY_IS_ACCOUNT (folder_store)) {
1459                 /* Use the folder store as an account: */
1460                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1461         }
1462
1463         return result;
1464 }
1465
1466 GtkWidget *
1467 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1468 {
1469         GtkWidget *dialog;
1470
1471         dialog = modest_hildon2_sort_dialog_new (parent_window);
1472
1473         return dialog;
1474 }
1475
1476
1477 gboolean 
1478 modest_platform_set_update_interval (guint minutes)
1479 {
1480 #ifdef MODEST_HAVE_LIBALARM
1481
1482         cookie_t alarm_cookie, *alarm_cookies;
1483         ModestConf *conf = modest_runtime_get_conf ();
1484         if (!conf)
1485                 return FALSE;
1486
1487         if (minutes > 0) {
1488                 GSList *acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1489                 if (!acc_names) {
1490                         minutes = 0;
1491                 } else {
1492                         modest_account_mgr_free_account_names (acc_names);
1493                 }
1494         }
1495
1496         /* cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL); */
1497
1498         /* Delete any existing alarm, because we will replace it: */
1499         alarm_cookies = alarmd_event_query (0,0, 0,0, MODEST_ALARMD_APPID);
1500         if (alarm_cookies) {
1501                 /* alarmd_event_query returns a zero terminated array */
1502                 for (; *alarm_cookies != 0; alarm_cookies++) {
1503                         alarmd_event_del (*alarm_cookies);
1504                 }
1505                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1506         }
1507
1508         /* 0 means no updates: */
1509         if (minutes == 0)
1510                 return TRUE;
1511
1512         /* Register alarm: */
1513
1514         /* Set the interval in alarm_event_t structure: */
1515         alarm_event_t *event = alarm_event_create ();
1516         alarm_event_add_actions (event, 1);
1517         alarm_action_t *action = alarm_event_get_action (event, 0);
1518         alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1519         event->alarm_time = minutes * 60; /* seconds */
1520
1521         /* Set recurrence every few minutes: */
1522         event->recur_secs = minutes*60;
1523         event->recur_count = -1; /* Means infinite */
1524
1525         /* Specify what should happen when the alarm happens:
1526          * It should call this D-Bus method: */
1527
1528         action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1529         action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1530         action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1531         action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1532         action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1533
1534         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1535          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1536          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1537          * This is why we want to use the Alarm API instead of just g_timeout_add().
1538          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1539          * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1540          */
1541         event->flags = ALARM_EVENT_CONNECTED | ALARM_EVENT_RUN_DELAYED;
1542
1543         alarm_cookie = alarmd_event_add (event);
1544
1545         /* now, free it */
1546         alarm_event_delete (event);
1547
1548         /* Store the alarm ID in GConf, so we can remove it later:
1549          * This is apparently valid between application instances. */
1550         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1551
1552         if (!alarm_cookie) {
1553             /* Error */
1554             g_warning ("Error setting alarm event. \n");
1555
1556             return FALSE;
1557         }
1558 #endif /* MODEST_HAVE_LIBALARM */
1559         return TRUE;
1560 }
1561
1562 void
1563 modest_platform_push_email_notification(void)
1564 {
1565         gboolean screen_on, app_in_foreground;
1566
1567         /* Get the window status */
1568         app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1569
1570         screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1571
1572         /* If the screen is on and the app is in the
1573            foreground we don't show anything */
1574         if (!(screen_on && app_in_foreground)) {
1575
1576                 modest_platform_play_email_tone ();
1577
1578                 /* Activate LED. This must be deactivated by
1579                    modest_platform_remove_new_mail_notifications */
1580 #ifdef MODEST_HAVE_MCE
1581                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1582                                      MCE_SERVICE,
1583                                      MCE_REQUEST_PATH,
1584                                      MCE_REQUEST_IF,
1585                                      MCE_ACTIVATE_LED_PATTERN,
1586                                      NULL,
1587                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1588                                      DBUS_TYPE_INVALID);
1589 #endif
1590         }
1591 }
1592
1593 void
1594 modest_platform_on_new_headers_received (GList *URI_list,
1595                                          gboolean show_visual)
1596 {
1597         /* Check if the user wants to show notifications or not */
1598         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATIONS, NULL))
1599                 return;
1600
1601         if (g_list_length (URI_list) == 0)
1602                 return;
1603
1604 #ifdef MODEST_HAVE_HILDON_NOTIFY
1605         /* For any other case issue a notification */
1606         HildonNotification *notification;
1607         ModestMsgNotificationData *data;
1608         gint notif_id;
1609         gchar *from;
1610         TnyAccountStore *acc_store;
1611         TnyAccount *account;
1612         gchar *acc_name;
1613
1614         data = (ModestMsgNotificationData *) URI_list->data;
1615
1616         /* String is changed in-place. There is no need to
1617            actually dup the data->from string but we just do
1618            it in order not to modify the original contents */
1619         from = g_strdup (data->from);
1620         modest_text_utils_get_display_address (from);
1621
1622         /* Create notification */
1623         notification = hildon_notification_new (from,
1624                                                 data->subject,
1625                                                 "qgn_list_messagin",
1626                                                 MODEST_NOTIFICATION_CATEGORY);
1627         g_free (from);
1628
1629         /* Add DBus action */
1630         hildon_notification_add_dbus_action(notification,
1631                                             "default",
1632                                             "Cancel",
1633                                             MODEST_DBUS_SERVICE,
1634                                             MODEST_DBUS_OBJECT,
1635                                             MODEST_DBUS_IFACE,
1636                                             MODEST_DBUS_METHOD_OPEN_MESSAGE,
1637                                             G_TYPE_STRING, data->uri,
1638                                             -1);
1639
1640         /* Set the led pattern */
1641         if (data->time)
1642                 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1643                                                     "time", data->time);
1644
1645         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1646                                             "dialog-type", 4);
1647         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1648                                             "led-pattern",
1649                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);
1650
1651         /* Make the notification persistent */
1652         notify_notification_set_hint_byte (NOTIFY_NOTIFICATION (notification),
1653                                            "persistent", TRUE);
1654
1655         /* Set the number of new notifications */
1656         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1657                                             "amount", g_list_length (URI_list));
1658
1659         /* Set the account of the headers */
1660         acc_store = (TnyAccountStore *) modest_runtime_get_account_store ();
1661         account = tny_account_store_find_account (acc_store, data->uri);
1662         acc_name = NULL;
1663         if (account) {
1664                 acc_name = g_strdup (modest_tny_account_get_parent_modest_account_name_for_server_account (account));
1665                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1666                                                     "email-account",
1667                                                     acc_name);
1668                 g_object_unref (account);
1669         }
1670
1671         if (notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1672                 GSList *notifications_list = NULL;
1673
1674                 /* Get previous notifications ids */
1675                 if (acc_name) {
1676                         notifications_list = modest_account_mgr_get_list (modest_runtime_get_account_mgr (), acc_name,
1677                                                                           MODEST_ACCOUNT_NOTIFICATION_IDS,
1678                                                                           MODEST_CONF_VALUE_INT, FALSE);
1679                 }
1680
1681                 /* Save id in the list */
1682                 g_object_get(G_OBJECT (notification), "id", &notif_id, NULL);
1683                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1684
1685                 /* We don't listen for the "closed" signal, because we
1686                    don't care about if the notification was removed or
1687                    not to store the list in gconf */
1688
1689                 /* Save the ids */
1690                 if (acc_name)
1691                         modest_account_mgr_set_list (modest_runtime_get_account_mgr (), acc_name,
1692                                                      MODEST_ACCOUNT_NOTIFICATION_IDS,
1693                                                      notifications_list, MODEST_CONF_VALUE_INT, FALSE);
1694                         
1695                 g_slist_free (notifications_list);
1696         } else {
1697                 g_warning ("Failed to send notification");
1698         }
1699         g_free (acc_name);
1700
1701 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1702 }
1703
1704 void
1705 modest_platform_remove_new_mail_notifications (gboolean only_visuals, const gchar *acc_name) 
1706 {
1707         if (only_visuals) {
1708 #ifdef MODEST_HAVE_MCE
1709                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1710                                      MCE_SERVICE,
1711                                      MCE_REQUEST_PATH,
1712                                      MCE_REQUEST_IF,
1713                                      MCE_DEACTIVATE_LED_PATTERN,
1714                                      NULL,
1715                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1716                                      DBUS_TYPE_INVALID);
1717 #endif
1718                 return;
1719         }
1720
1721 #ifdef MODEST_HAVE_HILDON_NOTIFY
1722         GSList *notif_list = NULL;
1723
1724         /* Get previous notifications ids */
1725         notif_list = modest_account_mgr_get_list (modest_runtime_get_account_mgr (), 
1726                                                   acc_name,
1727                                                   MODEST_ACCOUNT_NOTIFICATION_IDS, 
1728                                                   MODEST_CONF_VALUE_INT, FALSE);
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         if (notif_list) {
1752                 modest_account_mgr_set_list (modest_runtime_get_account_mgr (), acc_name,
1753                                              MODEST_ACCOUNT_NOTIFICATION_IDS,
1754                                              notif_list, MODEST_CONF_VALUE_INT, FALSE);
1755
1756                 g_slist_free (notif_list);
1757         }
1758
1759 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1760 }
1761
1762
1763
1764 GtkWidget * 
1765 modest_platform_get_global_settings_dialog ()
1766 {
1767         return modest_hildon2_global_settings_dialog_new ();
1768 }
1769
1770 void
1771 modest_platform_show_help (GtkWindow *parent_window, 
1772                            const gchar *help_id)
1773 {
1774         return;
1775 }
1776
1777 void 
1778 modest_platform_show_search_messages (GtkWindow *parent_window)
1779 {
1780         osso_return_t result = OSSO_ERROR;
1781         
1782         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1783                                              "osso_global_search",
1784                                              "search_email", NULL, DBUS_TYPE_INVALID);
1785
1786         if (result != OSSO_OK) {
1787                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1788         }
1789 }
1790
1791 void 
1792 modest_platform_show_addressbook (GtkWindow *parent_window)
1793 {
1794         osso_return_t result = OSSO_ERROR;
1795
1796         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1797                                              "osso_addressbook",
1798                                              "top_application", NULL, DBUS_TYPE_INVALID);
1799
1800         if (result != OSSO_OK) {
1801                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1802         }
1803 }
1804
1805 static GtkWidget *
1806 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1807 {
1808         GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1809
1810         /* Show one account by default */
1811         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1812                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1813
1814         return widget;
1815 }
1816
1817 GtkWidget *
1818 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1819 {
1820         return modest_platform_create_folder_view_full (query, TRUE);
1821 }
1822
1823 void
1824 banner_finish (gpointer data, GObject *object)
1825 {
1826         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1827         modest_window_mgr_unregister_banner (mgr);
1828         g_object_unref (mgr);
1829 }
1830
1831 void 
1832 modest_platform_information_banner (GtkWidget *parent,
1833                                     const gchar *icon_name,
1834                                     const gchar *text)
1835 {
1836         GtkWidget *banner_parent = NULL;
1837         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1838
1839         if (modest_window_mgr_get_num_windows (mgr) == 0)
1840                 return;
1841
1842         if (parent && GTK_IS_WINDOW (parent)) {
1843                 /* If the window is the active one then show the
1844                    banner on top of this window */
1845                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1846                         banner_parent = parent;
1847                 /* If the window is not the topmost but it's visible
1848                    (it's minimized for example) then show the banner
1849                    with no parent */ 
1850                 else if (GTK_WIDGET_VISIBLE (parent))
1851                         banner_parent = NULL;
1852                 /* If the window is hidden (like the main window when
1853                    running in the background) then do not show
1854                    anything */
1855                 else 
1856                         return;
1857         }
1858
1859         modest_platform_system_banner (banner_parent, icon_name, text);
1860 }
1861
1862 void 
1863 modest_platform_system_banner (GtkWidget *parent,
1864                                const gchar *icon_name,
1865                                const gchar *text)
1866 {
1867         GtkWidget *banner = NULL;
1868         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1869
1870         if (parent && GTK_IS_WINDOW (parent)) {
1871                 if (!gtk_window_is_active (GTK_WINDOW (parent)))
1872                         parent = NULL;
1873         }
1874
1875         banner = hildon_banner_show_information (parent, icon_name, text);
1876
1877         modest_window_mgr_register_banner (mgr);
1878         g_object_ref (mgr);
1879         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1880 }
1881
1882 void
1883 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1884                                                  const gchar *icon_name,
1885                                                  const gchar *text,
1886                                                  gint timeout)
1887 {
1888         GtkWidget *banner;
1889
1890         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1891                 return;
1892
1893         banner = hildon_banner_show_information (parent, icon_name, text);
1894         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1895 }
1896
1897 GtkWidget *
1898 modest_platform_animation_banner (GtkWidget *parent,
1899                                   const gchar *animation_name,
1900                                   const gchar *text)
1901 {
1902         GtkWidget *inf_note = NULL;
1903
1904         g_return_val_if_fail (text != NULL, NULL);
1905
1906         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1907                 return NULL;
1908
1909         /* If the parent is not visible then do not show */
1910         if (parent && !GTK_WIDGET_VISIBLE (parent))
1911                 return NULL;
1912
1913         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1914
1915         return inf_note;
1916 }
1917
1918 typedef struct
1919 {
1920         GMainLoop* loop;
1921         TnyAccount *account;
1922         gboolean is_online;
1923         gint count_tries;
1924 } CheckAccountIdleData;
1925
1926 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1927
1928 static gboolean 
1929 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1930 {
1931         gboolean stop_trying = FALSE;
1932         g_return_val_if_fail (data && data->account, FALSE);
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                                               _FM ("ckdg_bd_change_folder_new_folder"),
3042                                               MODEST_GTK_RESPONSE_NEW_FOLDER,
3043                                               NULL);
3044
3045         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3046         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
3047         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
3048
3049         /* Create folder view */
3050         *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
3051         g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
3052                           dialog);
3053
3054         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
3055                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
3056         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
3057                                                FALSE);
3058         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
3059                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
3060
3061         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
3062         back_button = gtk_button_new ();
3063         back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
3064         if (back_pixbuf) {
3065                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
3066                 g_object_unref (back_pixbuf);
3067         }
3068
3069         action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
3070                                            HILDON_BUTTON_ARRANGEMENT_VERTICAL);
3071         gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
3072
3073         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
3074         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
3075         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
3076         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
3077         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
3078
3079         /* Create pannable and add it to the dialog */
3080         folder_view_container = hildon_pannable_area_new ();
3081         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
3082         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
3083
3084         gtk_container_add (GTK_CONTAINER (align), top_vbox);
3085         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
3086
3087         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
3088
3089         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
3090         gtk_widget_show (folder_view_container);
3091         gtk_widget_show (align);
3092         gtk_widget_show (top_vbox);
3093         gtk_widget_show (*folder_view);
3094         gtk_widget_show_all (back_button);
3095         gtk_widget_show (action_button);
3096         gtk_widget_show (buttons_hbox);
3097         gtk_widget_show (dialog);
3098
3099         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
3100         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
3101         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
3102         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
3103
3104         /* Simulate the behaviour of a HildonPickerDialog by emitting
3105            a response when a folder is selected */
3106         g_signal_connect (*folder_view, "row-activated",
3107                           G_CALLBACK (on_move_to_dialog_row_activated),
3108                           dialog);
3109
3110         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
3111         g_signal_connect (selection, "changed",
3112                           G_CALLBACK (on_move_to_dialog_selection_changed),
3113                           dialog);
3114
3115         g_signal_connect (action_button, "clicked",
3116                           G_CALLBACK (on_move_to_dialog_action_clicked),
3117                           dialog);
3118
3119         g_signal_connect (back_button, "clicked",
3120                           G_CALLBACK (on_move_to_dialog_back_clicked),
3121                           dialog);
3122
3123         move_to_dialog_show_accounts (dialog);
3124
3125         return dialog;
3126 }
3127
3128 TnyList *
3129 modest_platform_get_list_to_move (ModestWindow *window)
3130 {
3131         TnyList *list = NULL;
3132
3133         if (MODEST_IS_HEADER_WINDOW (window)) {
3134                 ModestHeaderView *header_view;
3135
3136                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
3137                 list = modest_header_view_get_selected_headers (header_view);
3138         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
3139                 ModestFolderView *folder_view;
3140                 TnyFolderStore *selected_folder;
3141
3142                 list = TNY_LIST (tny_simple_list_new ());
3143                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
3144                 selected_folder = modest_folder_view_get_selected (folder_view);
3145                 if (selected_folder) {
3146                         tny_list_prepend (list, G_OBJECT (selected_folder));
3147                         g_object_unref (selected_folder);
3148                 }
3149                 return list;
3150         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3151                 TnyHeader *header;
3152
3153                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
3154                 if (header) {
3155                         list = TNY_LIST (tny_simple_list_new ());
3156                         tny_list_prepend (list, G_OBJECT (header));
3157                         g_object_unref (header);
3158                 }
3159         } else {
3160                 g_return_val_if_reached (NULL);
3161         }
3162
3163         return list;
3164 }
3165
3166 DBusConnection*
3167 modest_platform_get_dbus_connection (void)
3168 {
3169         osso_context_t *osso_context;
3170         DBusConnection *con;
3171
3172         osso_context = modest_maemo_utils_get_osso_context();
3173
3174         con = osso_get_dbus_connection (osso_context);
3175
3176         return con;
3177 }
3178
3179 void
3180 modest_platform_emit_folder_updated_signal (const gchar *account_id, const gchar *folder_id)
3181 {
3182         DBusConnection *con;
3183
3184         con = modest_platform_get_dbus_connection ();
3185         if (!con) return;
3186
3187         modest_dbus_emit_folder_updated_signal (con, account_id, folder_id);
3188 }