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