b8affcc42444730bce67ebc850b627ed5cb22dee
[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 (NULL);
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                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
728                         return modest_conf_get_string (modest_runtime_get_conf(),
729                                                        MODEST_CONF_DEVICE_NAME, NULL);
730                 else
731                         return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
732         } else {
733                 gchar *fname;
734                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
735
736                 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
737                 type = tny_folder_get_folder_type (TNY_FOLDER (store));
738                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
739                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
740                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
741                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
742                                 g_free (fname);
743                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
744                         }
745                 } else {
746                         /* Sometimes an special folder is reported by the server as
747                            NORMAL, like some versions of Dovecot */
748                         if (type == TNY_FOLDER_TYPE_NORMAL ||
749                             type == TNY_FOLDER_TYPE_UNKNOWN) {
750                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
751                         }
752                 }
753
754                 if (type == TNY_FOLDER_TYPE_INBOX) {
755                         g_free (fname);
756                         fname = g_strdup (_("mcen_me_folder_inbox"));
757                 }
758                 return fname;
759         }
760 }
761
762 static void
763 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
764 {
765         gchar *name;
766
767         if (store == NULL) {
768                 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
769         } else {
770                 GdkPixbuf *pixbuf;
771                 const gchar *icon_name = NULL;
772
773                 g_object_ref (store);
774                 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, 
775                                         store, (GDestroyNotify) g_object_unref);
776                 name = folder_store_get_display_name (store);
777                 hildon_button_set_value (HILDON_BUTTON (button), name);
778                 g_free (name);
779
780                 /* Select icon */
781                 if (TNY_IS_ACCOUNT (store)) {
782                         if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
783                             icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
784                         else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
785                                 icon_name = MODEST_FOLDER_ICON_MMC;
786                         else
787                                 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
788                 } else {
789                         TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
790                         if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
791                                 switch (type) {
792                                 case TNY_FOLDER_TYPE_INBOX:
793                                         icon_name = MODEST_FOLDER_ICON_INBOX;
794                                         break;
795                                 default:
796                                         icon_name = MODEST_FOLDER_ICON_ACCOUNT;
797                                 }
798                         } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
799                                 switch (type) {
800                                 case TNY_FOLDER_TYPE_OUTBOX:
801                                         icon_name = MODEST_FOLDER_ICON_OUTBOX;
802                                         break;
803                                 case TNY_FOLDER_TYPE_DRAFTS:
804                                         icon_name = MODEST_FOLDER_ICON_DRAFTS;
805                                         break;
806                                 case TNY_FOLDER_TYPE_SENT:
807                                         icon_name = MODEST_FOLDER_ICON_SENT;
808                                         break;
809                                 default:
810                                         icon_name = MODEST_FOLDER_ICON_NORMAL;
811                                 }
812                         } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
813                                 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
814                         }
815                 }
816
817                 /* Set icon */
818                 pixbuf = modest_platform_get_icon (icon_name, MODEST_ICON_SIZE_SMALL);
819
820                 if (pixbuf) {
821                         hildon_button_set_image (HILDON_BUTTON (button),
822                                                  gtk_image_new_from_pixbuf (pixbuf));
823                         g_object_unref (pixbuf);
824                 }
825         }
826 }
827
828 /* Always returns DUPs so you must free the returned value */
829 static gchar *
830 get_next_folder_name (const gchar *suggested_name, 
831                       TnyFolderStore *suggested_folder)
832 {
833         const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
834         unsigned int i;
835         gchar *real_suggested_name;
836
837         if (suggested_name !=NULL) {
838                 return g_strdup (suggested_name);
839         }
840
841         for(i = 0; i < 100; ++ i) {
842                 gboolean exists = FALSE;
843
844                 if (i == 0)
845                         real_suggested_name = g_strdup (default_name);
846                 else
847                         real_suggested_name = g_strdup_printf ("%s(%d)",
848                                                                _FM("ckdg_va_new_folder_name_stub"),
849                                                                i);
850                 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
851                                                                     real_suggested_name,
852                                                                     TRUE);
853
854                 if (!exists)
855                         break;
856
857                 g_free (real_suggested_name);
858         }
859
860         /* Didn't find a free number */
861         if (i == 100)
862                 real_suggested_name = g_strdup (default_name);
863
864         return real_suggested_name;
865 }
866
867 typedef struct {
868         ModestFolderView *folder_view;
869         GtkEntry *entry;
870 } FolderPickerHelper;
871
872 static void
873 folder_picker_clicked (GtkButton *button,
874                        FolderPickerHelper *helper)
875 {
876         TnyFolderStore *store;
877
878         store = folder_chooser_dialog_run (helper->folder_view);
879         if (store) {
880                 const gchar *current_name;
881                 gboolean exists;
882
883                 folder_picker_set_store (GTK_BUTTON (button), store);
884
885                 /* Update the name of the folder */
886                 current_name = gtk_entry_get_text (helper->entry);
887                 exists = modest_tny_folder_has_subfolder_with_name (store,
888                                                                     current_name,
889                                                                     TRUE);
890                 if (exists) {
891                         gchar *new_name = get_next_folder_name (NULL, store);
892                         gtk_entry_set_text (helper->entry, new_name);
893                         g_free (new_name);
894                 }
895         }
896 }
897
898 static GtkWidget *
899 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
900 {
901         GtkWidget *button;
902
903         button = hildon_button_new (MODEST_EDITABLE_SIZE,
904                                     HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
905
906         hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
907
908         if (suggested) {
909                 folder_picker_set_store (GTK_BUTTON (button), suggested);
910         }
911
912         g_signal_connect (G_OBJECT (button), "clicked",
913                           G_CALLBACK (folder_picker_clicked),
914                           helper);
915
916         return button;
917 }
918
919
920 static gint
921 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
922                                           TnyFolderStore *suggested_parent,
923                                           const gchar *dialog_title,
924                                           const gchar *label_text,
925                                           const gchar *suggested_name,
926                                           gboolean show_name,
927                                           gboolean show_parent,
928                                           gchar **folder_name,
929                                           TnyFolderStore **parent)
930 {
931         GtkWidget *accept_btn = NULL; 
932         GtkWidget *dialog, *entry = NULL, *label_entry = NULL,  *label_location = NULL, *hbox;
933         GtkWidget *account_picker = NULL;
934         GList *buttons = NULL;
935         gint result;
936         GtkSizeGroup *sizegroup;
937         ModestFolderView *folder_view;
938         ModestWindow *folder_window;
939         ModestHildon2WindowMgr *window_mgr;
940         FolderPickerHelper *helper = NULL;
941         GtkWidget *top_vbox, *top_align;
942
943         window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
944         folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
945         g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
946         
947         folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
948         
949         top_vbox = gtk_vbox_new (FALSE, 0);
950         top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
951         gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
952         
953         /* Ask the user for the folder name */
954         dialog = gtk_dialog_new_with_buttons (dialog_title,
955                                               parent_window,
956                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
957                                               _FM("ckdg_bd_new_folder_dialog_ok"),
958                                               GTK_RESPONSE_ACCEPT,
959                                               NULL);
960
961         /* Add accept button (with unsensitive handler) */
962         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
963         accept_btn = GTK_WIDGET (buttons->data);
964
965         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
966
967         if (show_name) {
968                 label_entry = gtk_label_new (label_text);
969                 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
970                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
971
972                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
973                 gtk_size_group_add_widget (sizegroup, label_entry);
974                 
975                 if (suggested_name)
976                   gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
977                 else
978                         gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
979                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
980                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
981                                                 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
982                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
983         }
984         
985         if (show_parent) {
986           
987                 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
988
989                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
990                 gtk_size_group_add_widget (sizegroup, label_location);
991
992                 helper = g_slice_new0 (FolderPickerHelper);
993                 helper->folder_view = folder_view;
994                 helper->entry = (GtkEntry *) entry;
995
996                 account_picker = folder_picker_new (suggested_parent, helper);
997         }
998
999         g_object_unref (sizegroup);
1000         
1001         /* Connect to the response method to avoid closing the dialog
1002            when an invalid name is selected*/
1003         g_signal_connect (dialog,
1004                           "response",
1005                           G_CALLBACK (on_response),
1006                           suggested_parent);
1007         
1008         if (show_name) {
1009                 /* Track entry changes */
1010                 g_signal_connect (entry,
1011                                   "insert-text",
1012                                   G_CALLBACK (entry_insert_text),
1013                                   dialog);
1014                 g_signal_connect (entry,
1015                                   "changed",
1016                                   G_CALLBACK (entry_changed),
1017                                   dialog);
1018         }
1019         
1020         
1021         /* Some locales like pt_BR need this to get the full window
1022            title shown */
1023         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
1024         
1025         /* Create the hbox */
1026         if (show_name) {
1027                 hbox = gtk_hbox_new (FALSE, 12);
1028                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
1029                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
1030                 
1031                 /* Add hbox to dialog */
1032                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1033                                     hbox, FALSE, FALSE, 0);
1034                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
1035         }
1036
1037         if (show_parent) {
1038                 hbox = gtk_hbox_new (FALSE, 12);
1039                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
1040                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
1041
1042                 /* Add hbox to dialog */
1043                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1044                                     hbox, FALSE, FALSE, 0);
1045                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
1046         }
1047         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1048                                      GTK_WINDOW (dialog), parent_window);
1049
1050         gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
1051         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
1052
1053         gtk_widget_show_all (GTK_WIDGET(dialog));
1054
1055         result = gtk_dialog_run (GTK_DIALOG(dialog));
1056         if (result == GTK_RESPONSE_ACCEPT) {
1057                 if (show_name)
1058                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1059                 if (show_parent) {
1060                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
1061                         if (*parent)
1062                                 g_object_ref (*parent);
1063                 }
1064         }
1065
1066         gtk_widget_destroy (dialog);
1067
1068         if (helper)
1069                 g_slice_free (FolderPickerHelper, helper);
1070
1071         while (gtk_events_pending ())
1072                 gtk_main_iteration ();
1073
1074         return result;
1075 }
1076
1077 gint
1078 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
1079                                        TnyFolderStore *suggested_folder,
1080                                        gchar *suggested_name,
1081                                        gchar **folder_name,
1082                                        TnyFolderStore **parent_folder)
1083 {
1084         gchar *real_suggested_name = NULL;
1085         gint result;
1086         ModestTnyAccountStore *acc_store;
1087         TnyAccount *account;
1088
1089         real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
1090                                                     suggested_folder);
1091
1092         /* In hildon 2.2 we always suggest the archive folder as parent */
1093         acc_store = modest_runtime_get_account_store ();
1094         account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1095         if (account) {
1096                 suggested_folder = (TnyFolderStore *)
1097                         modest_tny_account_get_special_folder (account,
1098                                                                TNY_FOLDER_TYPE_ARCHIVE);
1099                 g_object_unref (account);
1100                 account = NULL;
1101         }
1102
1103         /* If there is not archive folder then fallback to local folders account */
1104         if (!suggested_folder)
1105                 suggested_folder = (TnyFolderStore *)
1106                         modest_tny_account_store_get_local_folders_account (acc_store);
1107
1108         result = modest_platform_run_folder_common_dialog (parent_window,
1109                                                            suggested_folder,
1110                                                            _HL("ckdg_ti_new_folder"),
1111                                                            _FM("ckdg_fi_new_folder_name"),
1112                                                            real_suggested_name,
1113                                                            TRUE,
1114                                                            TRUE,
1115                                                            folder_name,
1116                                                            parent_folder);
1117
1118         g_free(real_suggested_name);
1119
1120         return result;
1121 }
1122
1123 gint
1124 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1125                                           TnyFolderStore *parent_folder,
1126                                           const gchar *suggested_name,
1127                                           gchar **folder_name)
1128 {
1129         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1130
1131         return modest_platform_run_folder_common_dialog (parent_window, 
1132                                                          parent_folder,
1133                                                          _HL("ckdg_ti_rename_folder"),
1134                                                          _HL("ckdg_fi_rename_name"),
1135                                                          suggested_name,
1136                                                          TRUE,
1137                                                          FALSE,
1138                                                          folder_name,
1139                                                          NULL);
1140 }
1141
1142
1143
1144 static void
1145 on_destroy_dialog (GtkWidget *dialog)
1146 {
1147         /* This could happen when the dialogs get programatically
1148            hidden or destroyed (for example when closing the
1149            application while a dialog is being shown) */
1150         if (!GTK_IS_WIDGET (dialog))
1151                 return;
1152
1153         gtk_widget_destroy (dialog);
1154
1155         if (gtk_events_pending ())
1156                 gtk_main_iteration ();
1157 }
1158
1159 gint
1160 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1161                                          const gchar *message)
1162 {
1163         GtkWidget *dialog;
1164         gint response;
1165         
1166         dialog = hildon_note_new_confirmation (parent_window, message);
1167         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1168                                      GTK_WINDOW (dialog), parent_window);
1169
1170         response = gtk_dialog_run (GTK_DIALOG (dialog));
1171
1172         on_destroy_dialog (dialog);
1173
1174         return response;
1175 }
1176
1177 gint
1178 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1179                                                       const gchar *message,
1180                                                       const gchar *button_accept,
1181                                                       const gchar *button_cancel)
1182 {
1183         GtkWidget *dialog;
1184         gint response;
1185         
1186         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1187                                                            button_accept, GTK_RESPONSE_ACCEPT,
1188                                                            button_cancel, GTK_RESPONSE_CANCEL,
1189                                                            NULL);
1190
1191         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1192                                      GTK_WINDOW (dialog), parent_window);
1193
1194         response = gtk_dialog_run (GTK_DIALOG (dialog));
1195
1196         on_destroy_dialog (dialog);
1197
1198         return response;
1199 }
1200         
1201 void
1202 modest_platform_run_information_dialog (GtkWindow *parent_window,
1203                                         const gchar *message,
1204                                         gboolean block)
1205 {
1206         GtkWidget *note;
1207         
1208         note = hildon_note_new_information (parent_window, message);
1209         if (block)
1210                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1211                                              GTK_WINDOW (note), parent_window);
1212         
1213         if (block) {
1214                 gtk_dialog_run (GTK_DIALOG (note));
1215         
1216                 on_destroy_dialog (note);
1217         } else {
1218                 g_signal_connect_swapped (note,
1219                                           "response", 
1220                                           G_CALLBACK (on_destroy_dialog),
1221                                           note);
1222
1223                 gtk_widget_show_all (note);
1224         }
1225 }
1226
1227 typedef struct _ConnectAndWaitData {
1228         GMutex *mutex;
1229         GMainLoop *wait_loop;
1230         gboolean has_callback;
1231         gulong handler;
1232 } ConnectAndWaitData;
1233
1234
1235 static void
1236 quit_wait_loop (TnyAccount *account,
1237                 ConnectAndWaitData *data) 
1238 {
1239         /* Set the has_callback to TRUE (means that the callback was
1240            executed and wake up every code waiting for cond to be
1241            TRUE */
1242         g_mutex_lock (data->mutex);
1243         data->has_callback = TRUE;
1244         if (data->wait_loop)
1245                 g_main_loop_quit (data->wait_loop);
1246         g_mutex_unlock (data->mutex);
1247 }
1248
1249 static void
1250 on_connection_status_changed (TnyAccount *account, 
1251                               TnyConnectionStatus status,
1252                               gpointer user_data)
1253 {
1254         TnyConnectionStatus conn_status;
1255         ConnectAndWaitData *data;
1256                         
1257         /* Ignore if reconnecting or disconnected */
1258         conn_status = tny_account_get_connection_status (account);
1259         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1260             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1261                 return;
1262
1263         /* Remove the handler */
1264         data = (ConnectAndWaitData *) user_data;
1265         g_signal_handler_disconnect (account, data->handler);
1266
1267         /* Quit from wait loop */
1268         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1269 }
1270
1271 static void
1272 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
1273                                     gboolean canceled, 
1274                                     GError *err, 
1275                                     gpointer user_data)
1276 {
1277         /* Quit from wait loop */
1278         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1279 }
1280
1281 gboolean 
1282 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1283                                   TnyAccount *account)
1284 {
1285         ConnectAndWaitData *data = NULL;
1286         gboolean device_online;
1287         TnyDevice *device;
1288         TnyConnectionStatus conn_status;
1289         gboolean user_requested;
1290         
1291         device = modest_runtime_get_device();
1292         device_online = tny_device_is_online (device);
1293
1294         /* Whether the connection is user requested or automatically
1295            requested, for example via D-Bus */
1296         user_requested = (parent_window) ? TRUE : FALSE;
1297
1298         /* If there is no account check only the device status */
1299         if (!account) {
1300                 if (device_online)
1301                         return TRUE;
1302                 else
1303                         return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1304                                                                NULL, user_requested);
1305         }
1306
1307         /* Return if the account is already connected */
1308         conn_status = tny_account_get_connection_status (account);
1309         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1310                 return TRUE;
1311
1312         /* Create the helper */
1313         data = g_slice_new0 (ConnectAndWaitData);
1314         data->mutex = g_mutex_new ();
1315         data->has_callback = FALSE;
1316
1317         /* Connect the device */
1318         if (!device_online) {
1319                 /* Track account connection status changes */
1320                 data->handler = g_signal_connect (account, "connection-status-changed",
1321                                                   G_CALLBACK (on_connection_status_changed),
1322                                                   data);
1323                 /* Try to connect the device */
1324                 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1325                                                                 NULL, user_requested);
1326
1327                 /* If the device connection failed then exit */
1328                 if (!device_online && data->handler)
1329                         goto frees;
1330         } else {
1331                 /* Force a reconnection of the account */
1332                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1333                                               on_tny_camel_account_set_online_cb, data);
1334         }
1335
1336         /* Wait until the callback is executed */
1337         g_mutex_lock (data->mutex);
1338         if (!data->has_callback) {
1339                 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1340                 gdk_threads_leave ();
1341                 g_mutex_unlock (data->mutex);
1342                 g_main_loop_run (data->wait_loop);
1343                 g_mutex_lock (data->mutex);
1344                 gdk_threads_enter ();
1345         }
1346         g_mutex_unlock (data->mutex);
1347
1348  frees:
1349         if (g_signal_handler_is_connected (account, data->handler))
1350                 g_signal_handler_disconnect (account, data->handler);
1351         g_mutex_free (data->mutex);
1352         g_main_loop_unref (data->wait_loop);
1353         g_slice_free (ConnectAndWaitData, data);
1354
1355         conn_status = tny_account_get_connection_status (account);
1356         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1357 }
1358
1359 gboolean 
1360 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1361 {
1362         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1363                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1364                         /* This must be a maildir account, which does not require a connection: */
1365                         return TRUE;
1366                 }
1367         }
1368
1369         return modest_platform_connect_and_wait (parent_window, account);
1370 }
1371
1372 gboolean 
1373 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1374 {
1375         if (!folder_store)
1376                 return TRUE; /* Maybe it is something local. */
1377                 
1378         gboolean result = TRUE;
1379         if (TNY_IS_FOLDER (folder_store)) {
1380                 /* Get the folder's parent account: */
1381                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1382                 if (account != NULL) {
1383                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1384                         g_object_unref (account);
1385                 }
1386         } else if (TNY_IS_ACCOUNT (folder_store)) {
1387                 /* Use the folder store as an account: */
1388                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1389         }
1390
1391         return result;
1392 }
1393
1394 GtkWidget *
1395 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1396 {
1397         GtkWidget *dialog;
1398
1399         dialog = modest_hildon2_sort_dialog_new (parent_window);
1400
1401         return dialog;
1402 }
1403
1404
1405 gboolean 
1406 modest_platform_set_update_interval (guint minutes)
1407 {
1408 #ifdef MODEST_HAVE_LIBALARM
1409         
1410         ModestConf *conf = modest_runtime_get_conf ();
1411         if (!conf)
1412                 return FALSE;
1413                 
1414         cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1415
1416         /* Delete any existing alarm,
1417          * because we will replace it: */
1418         if (alarm_cookie) {
1419                 if (alarmd_event_del(alarm_cookie) != 0)
1420                         g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1421                 alarm_cookie = 0;
1422                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1423         }
1424         
1425         /* 0 means no updates: */
1426         if (minutes == 0)
1427                 return TRUE;
1428         
1429      
1430         /* Register alarm: */
1431         
1432         /* Set the interval in alarm_event_t structure: */
1433         alarm_event_t *event = alarm_event_create ();
1434         alarm_event_add_actions (event, 1);
1435         alarm_action_t *action = alarm_event_get_action (event, 0);
1436         alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1437         event->alarm_time = minutes * 60; /* seconds */
1438         
1439         /* Set recurrence every few minutes: */
1440         event->recur_secs = minutes*60;
1441         event->recur_count = -1; /* Means infinite */
1442
1443         /* Specify what should happen when the alarm happens:
1444          * It should call this D-Bus method: */
1445          
1446         action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1447         action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1448         action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1449         action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1450         action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1451
1452         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1453          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1454          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1455          * This is why we want to use the Alarm API instead of just g_timeout_add().
1456          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1457          * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1458          */
1459         event->flags = ALARM_EVENT_CONNECTED;
1460         
1461         alarm_cookie = alarmd_event_add (event);
1462
1463         /* now, free it */
1464         alarm_event_delete (event);
1465         
1466         /* Store the alarm ID in GConf, so we can remove it later:
1467          * This is apparently valid between application instances. */
1468         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1469         
1470         if (!alarm_cookie) {
1471             /* Error */
1472             g_debug ("Error setting alarm event. \n");
1473             
1474             return FALSE;
1475         }
1476 #endif /* MODEST_HAVE_LIBALARM */       
1477         return TRUE;
1478 }
1479
1480 void
1481 modest_platform_push_email_notification(void)
1482 {
1483         gboolean screen_on, app_in_foreground;
1484
1485         /* Get the window status */
1486         app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1487
1488         screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1489
1490         /* If the screen is on and the app is in the
1491            foreground we don't show anything */
1492         if (!(screen_on && app_in_foreground)) {
1493
1494                 _modest_platform_play_email_tone ();
1495
1496                 /* Activate LED. This must be deactivated by
1497                    modest_platform_remove_new_mail_notifications */
1498 #ifdef MODEST_HAVE_MCE
1499                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1500                                      MCE_SERVICE,
1501                                      MCE_REQUEST_PATH,
1502                                      MCE_REQUEST_IF,
1503                                      MCE_ACTIVATE_LED_PATTERN,
1504                                      NULL,
1505                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1506                                      DBUS_TYPE_INVALID);
1507 #endif
1508         }
1509 }
1510
1511 void 
1512 modest_platform_on_new_headers_received (TnyList *header_list,
1513                                          gboolean show_visual)
1514 {
1515         g_return_if_fail (TNY_IS_LIST(header_list));
1516
1517         if (tny_list_get_length(header_list) == 0) {
1518                 g_warning ("%s: header list is empty", __FUNCTION__);
1519                 return;
1520         }
1521
1522         if (!show_visual) {
1523                 modest_platform_push_email_notification ();
1524                 /* We do a return here to avoid indentation with an else */
1525                 return;
1526         }
1527
1528 #ifdef MODEST_HAVE_HILDON_NOTIFY
1529         HildonNotification *notification;
1530         TnyIterator *iter;
1531         GSList *notifications_list = NULL;
1532
1533         /* Get previous notifications ids */
1534         notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1535                                                    MODEST_CONF_NOTIFICATION_IDS,
1536                                                    MODEST_CONF_VALUE_INT, NULL);
1537
1538         iter = tny_list_create_iterator (header_list);
1539         while (!tny_iterator_is_done (iter)) {
1540                 gchar *url = NULL, *display_address = NULL;
1541                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1542                 TnyFolder *folder = tny_header_get_folder (header);
1543                 gboolean first_notification = TRUE;
1544                 gint notif_id;
1545                 gchar *str;
1546
1547                 display_address = tny_header_dup_from (header);
1548                 /* string is changed in-place */
1549                 modest_text_utils_get_display_address (display_address);
1550
1551                 str = tny_header_dup_subject (header);
1552                 notification = hildon_notification_new (display_address,
1553                                                         str,
1554                                                         "qgn_list_messagin",
1555                                                         MODEST_NOTIFICATION_CATEGORY);
1556                 g_free (str);
1557                 /* Create the message URL */
1558                 str = tny_header_dup_uid (header);
1559                 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder), 
1560                                        str);
1561                 g_free (str);
1562
1563                 hildon_notification_add_dbus_action(notification,
1564                                                     "default",
1565                                                     "Cancel",
1566                                                     MODEST_DBUS_SERVICE,
1567                                                     MODEST_DBUS_OBJECT,
1568                                                     MODEST_DBUS_IFACE,
1569                                                     MODEST_DBUS_METHOD_OPEN_MESSAGE,
1570                                                     G_TYPE_STRING, url,
1571                                                     -1);
1572
1573                 /* Play sound if the user wants. Show the LED
1574                    pattern. Show and play just one */
1575                 if (G_UNLIKELY (first_notification)) {
1576                         TnyAccount *account;
1577
1578                         first_notification = FALSE;
1579
1580                         /* Set the led pattern */
1581                         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1582                                                             "dialog-type", 4);
1583                         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1584                                                             "led-pattern",
1585                                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);
1586
1587                         /* Set the account of the headers */
1588                         account = tny_folder_get_account (folder);
1589                         if (account) {
1590                                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1591                                                                     "email-account",
1592                                                                     tny_account_get_id (account));
1593                                 g_object_unref (account);
1594                         }
1595                 }
1596
1597                 /* Notify. We need to do this in an idle because this function
1598                    could be called from a thread */
1599                 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1600
1601                 /* Save id in the list */
1602                 g_object_get(G_OBJECT(notification), "id", &notif_id, NULL);
1603                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1604                 /* We don't listen for the "closed" signal, because we
1605                    don't care about if the notification was removed or
1606                    not to store the list in gconf */
1607         
1608                 /* Free & carry on */
1609                 g_free (display_address);
1610                 g_free (url);
1611                 g_object_unref (folder);
1612                 g_object_unref (header);
1613                 tny_iterator_next (iter);
1614         }
1615         g_object_unref (iter);
1616
1617         /* Save the ids */
1618         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1619                               notifications_list, MODEST_CONF_VALUE_INT, NULL);
1620
1621         g_slist_free (notifications_list);
1622         
1623 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1624 }
1625
1626 void
1627 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1628 {
1629         if (only_visuals) {
1630 #ifdef MODEST_HAVE_MCE
1631                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1632                                      MCE_SERVICE,
1633                                      MCE_REQUEST_PATH,
1634                                      MCE_REQUEST_IF,
1635                                      MCE_DEACTIVATE_LED_PATTERN,
1636                                      NULL,
1637                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1638                                      DBUS_TYPE_INVALID);
1639 #endif
1640                 return;
1641         }
1642
1643 #ifdef MODEST_HAVE_HILDON_NOTIFY
1644         GSList *notif_list = NULL;
1645
1646         /* Get previous notifications ids */
1647         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1648                                            MODEST_CONF_NOTIFICATION_IDS, 
1649                                            MODEST_CONF_VALUE_INT, NULL);
1650
1651         while (notif_list) {
1652                 gint notif_id;
1653                 NotifyNotification *notif;
1654
1655                 /* Nasty HACK to remove the notifications, set the id
1656                    of the existing ones and then close them */
1657                 notif_id = GPOINTER_TO_INT(notif_list->data);
1658                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1659                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1660
1661                 /* Close the notification, note that some ids could be
1662                    already invalid, but we don't care because it does
1663                    not fail */
1664                 notify_notification_close(notif, NULL);
1665                 g_object_unref(notif);
1666
1667                 /* Delete the link, it's like going to the next */
1668                 notif_list = g_slist_delete_link (notif_list, notif_list);
1669         }
1670
1671         /* Save the ids */
1672         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1673                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1674
1675         g_slist_free (notif_list);
1676
1677 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1678 }
1679
1680
1681
1682 GtkWidget * 
1683 modest_platform_get_global_settings_dialog ()
1684 {
1685         return modest_hildon2_global_settings_dialog_new ();
1686 }
1687
1688 void
1689 modest_platform_show_help (GtkWindow *parent_window, 
1690                            const gchar *help_id)
1691 {
1692         return;
1693 }
1694
1695 void 
1696 modest_platform_show_search_messages (GtkWindow *parent_window)
1697 {
1698         osso_return_t result = OSSO_ERROR;
1699         
1700         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1701                                              "osso_global_search",
1702                                              "search_email", NULL, DBUS_TYPE_INVALID);
1703
1704         if (result != OSSO_OK) {
1705                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1706         }
1707 }
1708
1709 void 
1710 modest_platform_show_addressbook (GtkWindow *parent_window)
1711 {
1712         osso_return_t result = OSSO_ERROR;
1713
1714         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1715                                              "osso_addressbook",
1716                                              "top_application", NULL, DBUS_TYPE_INVALID);
1717
1718         if (result != OSSO_OK) {
1719                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1720         }
1721 }
1722
1723 GtkWidget *
1724 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1725 {
1726         GtkWidget *widget = modest_folder_view_new (query);
1727
1728         /* Show one account by default */
1729         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1730                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1731
1732         /* Restore settings */
1733         modest_widget_memory_restore (modest_runtime_get_conf(), 
1734                                       G_OBJECT (widget),
1735                                       MODEST_CONF_FOLDER_VIEW_KEY);
1736
1737         return widget;
1738 }
1739
1740 void
1741 banner_finish (gpointer data, GObject *object)
1742 {
1743         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1744         modest_window_mgr_unregister_banner (mgr);
1745         g_object_unref (mgr);
1746 }
1747
1748 void 
1749 modest_platform_information_banner (GtkWidget *parent,
1750                                     const gchar *icon_name,
1751                                     const gchar *text)
1752 {
1753         GtkWidget *banner, *banner_parent = NULL;
1754         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1755
1756         if (modest_window_mgr_get_num_windows (mgr) == 0)
1757                 return;
1758
1759         if (parent && GTK_IS_WINDOW (parent)) {
1760                 /* If the window is the active one then show the
1761                    banner on top of this window */
1762                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1763                         banner_parent = parent;
1764                 /* If the window is not the topmost but it's visible
1765                    (it's minimized for example) then show the banner
1766                    with no parent */ 
1767                 else if (GTK_WIDGET_VISIBLE (parent))
1768                         banner_parent = NULL;
1769                 /* If the window is hidden (like the main window when
1770                    running in the background) then do not show
1771                    anything */
1772                 else 
1773                         return;
1774         }
1775
1776
1777         banner = hildon_banner_show_information (banner_parent, icon_name, text);
1778
1779         modest_window_mgr_register_banner (mgr);
1780         g_object_ref (mgr);
1781         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1782 }
1783
1784 void
1785 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1786                                                  const gchar *icon_name,
1787                                                  const gchar *text,
1788                                                  gint timeout)
1789 {
1790         GtkWidget *banner;
1791
1792         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1793                 return;
1794
1795         banner = hildon_banner_show_information (parent, icon_name, text);
1796         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1797 }
1798
1799 GtkWidget *
1800 modest_platform_animation_banner (GtkWidget *parent,
1801                                   const gchar *animation_name,
1802                                   const gchar *text)
1803 {
1804         GtkWidget *inf_note = NULL;
1805
1806         g_return_val_if_fail (text != NULL, NULL);
1807
1808         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1809                 return NULL;
1810
1811         /* If the parent is not visible then do not show */
1812         if (parent && !GTK_WIDGET_VISIBLE (parent))
1813                 return NULL;
1814
1815         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1816
1817         return inf_note;
1818 }
1819
1820 typedef struct
1821 {
1822         GMainLoop* loop;
1823         TnyAccount *account;
1824         gboolean is_online;
1825         gint count_tries;
1826 } CheckAccountIdleData;
1827
1828 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1829
1830 static gboolean 
1831 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1832 {
1833         gboolean stop_trying = FALSE;
1834         g_return_val_if_fail (data && data->account, FALSE);
1835         
1836         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1837                 tny_account_get_connection_status (data->account));     
1838         
1839         if (data && data->account && 
1840                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1841                  * after which the account is likely to be usable, or never likely to be usable soon: */
1842                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1843         {
1844                 data->is_online = TRUE;
1845                 
1846                 stop_trying = TRUE;
1847         } else {
1848                 /* Give up if we have tried too many times: */
1849                 if (data->count_tries >= NUMBER_OF_TRIES) {
1850                         stop_trying = TRUE;
1851                 } else {
1852                         /* Wait for another timeout: */
1853                         ++(data->count_tries);
1854                 }
1855         }
1856         
1857         if (stop_trying) {
1858                 /* Allow the function that requested this idle callback to continue: */
1859                 if (data->loop)
1860                         g_main_loop_quit (data->loop);
1861                         
1862                 if (data->account)
1863                         g_object_unref (data->account);
1864                 
1865                 return FALSE; /* Don't call this again. */
1866         } else {
1867                 return TRUE; /* Call this timeout callback again. */
1868         }
1869 }
1870
1871 /* Return TRUE immediately if the account is already online,
1872  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1873  * soon as the account is online, or FALSE if the account does 
1874  * not become online in the NUMBER_OF_TRIES seconds.
1875  * This is useful when the D-Bus method was run immediately after 
1876  * the application was started (when using D-Bus activation), 
1877  * because the account usually takes a short time to go online.
1878  * The return value is maybe not very useful.
1879  */
1880 gboolean
1881 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1882 {
1883         gboolean is_online;
1884
1885         g_return_val_if_fail (account, FALSE);
1886
1887         if (!tny_device_is_online (modest_runtime_get_device())) {
1888                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1889                 return FALSE;
1890         }
1891
1892         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1893          * so we avoid wait unnecessarily: */
1894         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1895                 return TRUE;
1896
1897         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1898          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1899          * we want to avoid. */
1900         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1901                 return TRUE;
1902                 
1903         /* This blocks on the result: */
1904         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1905         data->is_online = FALSE;
1906         data->account = account;
1907         g_object_ref (data->account);
1908         data->count_tries = 0;
1909                 
1910         GMainContext *context = NULL; /* g_main_context_new (); */
1911         data->loop = g_main_loop_new (context, FALSE /* not running */);
1912
1913         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1914
1915         /* This main loop will run until the idle handler has stopped it: */
1916         g_main_loop_run (data->loop);
1917
1918         g_main_loop_unref (data->loop);
1919         /* g_main_context_unref (context); */
1920
1921         is_online = data->is_online;
1922         g_slice_free (CheckAccountIdleData, data);
1923         
1924         return is_online;       
1925 }
1926
1927
1928
1929 static void
1930 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1931 {
1932         /* GTK_RESPONSE_HELP means we need to show the certificate */
1933         if (response_id == GTK_RESPONSE_APPLY) {
1934                 GtkWidget *note;
1935                 gchar *msg;
1936                 
1937                 /* Do not close the dialog */
1938                 g_signal_stop_emission_by_name (dialog, "response");
1939
1940                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1941                 note = hildon_note_new_information (NULL, msg);
1942                 gtk_dialog_run (GTK_DIALOG(note));
1943                 gtk_widget_destroy (note);
1944         }
1945 }
1946
1947
1948 gboolean
1949 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1950                                                      const gchar *certificate)
1951 {
1952         GtkWidget *note;
1953         gint response;
1954         ModestWindow *win;
1955         HildonWindowStack *stack;
1956
1957         stack = hildon_window_stack_get_default ();
1958         win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1959
1960         if (!win) {
1961           g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1962                            __FUNCTION__);
1963                 return FALSE;
1964         }
1965
1966         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1967                                            server_name);
1968
1969         /* We use GTK_RESPONSE_APPLY because we want the button in the
1970            middle of OK and CANCEL the same as the browser does for
1971            example. With GTK_RESPONSE_HELP the view button is aligned
1972            to the left while the other two to the right */
1973         note = hildon_note_new_confirmation_add_buttons  (
1974                 NULL,
1975                 question,
1976                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
1977                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
1978                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1979                 NULL, NULL);
1980
1981         g_signal_connect (G_OBJECT(note), "response", 
1982                           G_CALLBACK(on_cert_dialog_response),
1983                           (gpointer) certificate);
1984
1985         response = gtk_dialog_run(GTK_DIALOG(note));
1986
1987         on_destroy_dialog (note);
1988         g_free (question);
1989
1990         return response == GTK_RESPONSE_OK;
1991 }
1992
1993 gboolean
1994 modest_platform_run_alert_dialog (const gchar* prompt,
1995                                   gboolean is_question)
1996 {
1997         ModestWindow *top_win;
1998         HildonWindowStack *stack;
1999
2000         stack = hildon_window_stack_get_default ();
2001         top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2002
2003         if (!top_win) {
2004                 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2005                            __FUNCTION__);
2006                 return FALSE;
2007         }
2008
2009         gboolean retval = TRUE;
2010         if (is_question) {
2011                 /* The Tinymail documentation says that we should show Yes and No buttons,
2012                  * when it is a question.
2013                  * Obviously, we need tinymail to use more specific error codes instead,
2014                  * so we know what buttons to show. */
2015                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win), 
2016                                                                               prompt));
2017                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2018                                              GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2019
2020                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2021                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2022
2023                 on_destroy_dialog (dialog);
2024         } else {
2025                 /* Just show the error text and use the default response: */
2026                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
2027                                                         prompt, FALSE);
2028         }
2029         return retval;
2030 }
2031
2032 /***************/
2033 typedef struct {
2034         GtkWindow *parent_window;
2035         ModestConnectedPerformer callback;
2036         TnyAccount *account;
2037         gpointer user_data;
2038         gchar *iap;
2039         TnyDevice *device;
2040 } OnWentOnlineInfo;
2041  
2042 static void 
2043 on_went_online_info_free (OnWentOnlineInfo *info)
2044 {
2045         /* And if we cleanup, we DO cleanup  :-)  */
2046         
2047         if (info->device)
2048                 g_object_unref (info->device);
2049         if (info->iap)
2050                 g_free (info->iap);
2051         if (info->parent_window)
2052                 g_object_unref (info->parent_window);
2053         if (info->account)
2054                 g_object_unref (info->account);
2055         
2056         g_slice_free (OnWentOnlineInfo, info);
2057         
2058         /* We're done ... */
2059         
2060         return;
2061 }
2062  
2063 static void
2064 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2065 {
2066         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2067  
2068         /* Now it's really time to callback to the caller. If going online didn't succeed,
2069          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2070          * canceled will be set. Etcetera etcetera. */
2071         
2072         if (info->callback) {
2073                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2074         }
2075         
2076         /* This is our last call, we must cleanup here if we didn't yet do that */
2077         on_went_online_info_free (info);
2078         
2079         return;
2080 }
2081  
2082  
2083 static void
2084 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2085 {
2086         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2087         info->iap = g_strdup (iap_id);
2088         
2089         if (canceled || err || !info->account) {
2090         
2091                 /* If there's a problem or if there's no account (then that's it for us, we callback
2092                  * the caller's callback now. He'll have to handle err or canceled, of course.
2093                  * We are not really online, as the account is not really online here ... */    
2094                 
2095                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2096                  * this info. We don't cleanup err, Tinymail does that! */
2097                 
2098                 if (info->callback) {
2099                         
2100                         /* info->account can be NULL here, this means that the user did not
2101                          * provide a nice account instance. We'll assume that the user knows
2102                          * what he's doing and is happy with just the device going online. 
2103                          * 
2104                          * We can't do magic, we don't know what account the user wants to
2105                          * see going online. So just the device goes online, end of story */
2106                         
2107                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2108                 }
2109                 
2110         } else if (info->account) {
2111                 
2112                 /* If there's no problem and if we have an account, we'll put the account
2113                  * online too. When done, the callback of bringing the account online
2114                  * will callback the caller's callback. This is the most normal case. */
2115  
2116                 info->device = TNY_DEVICE (g_object_ref (device));
2117                 
2118                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2119                                               on_account_went_online, info);
2120                 
2121                 /* The on_account_went_online cb frees up the info, go look if you
2122                  * don't believe me! (so we return here) */
2123                 
2124                 return;
2125         }
2126         
2127         /* We cleanup if we are not bringing the account online too */
2128         on_went_online_info_free (info);
2129  
2130         return; 
2131 }
2132         
2133 void 
2134 modest_platform_connect_and_perform (GtkWindow *parent_window, 
2135                                      gboolean force,
2136                                      TnyAccount *account, 
2137                                      ModestConnectedPerformer callback, 
2138                                      gpointer user_data)
2139 {
2140         gboolean device_online;
2141         TnyDevice *device;
2142         TnyConnectionStatus conn_status;
2143         OnWentOnlineInfo *info;
2144         
2145         device = modest_runtime_get_device();
2146         device_online = tny_device_is_online (device);
2147
2148         /* If there is no account check only the device status */
2149         if (!account) {
2150                 
2151                 if (device_online) {
2152  
2153                         /* We promise to instantly perform the callback, so ... */
2154                         if (callback) {
2155                                 callback (FALSE, NULL, parent_window, account, user_data);
2156                         }
2157                         
2158                 } else {
2159                         
2160                         info = g_slice_new0 (OnWentOnlineInfo);
2161                         
2162                         info->iap = NULL;
2163                         info->device = NULL;
2164                         info->account = NULL;
2165                 
2166                         if (parent_window)
2167                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2168                         else
2169                                 info->parent_window = NULL;
2170                         info->user_data = user_data;
2171                         info->callback = callback;
2172                 
2173                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2174                                                               force, on_conic_device_went_online, 
2175                                                               info);
2176  
2177                         /* We'll cleanup in on_conic_device_went_online */
2178                 }
2179  
2180                 /* The other code has no more reason to run. This is all that we can do for the
2181                  * caller (he should have given us a nice and clean account instance!). We
2182                  * can't do magic, we don't know what account he intends to bring online. So
2183                  * we'll just bring the device online (and await his false bug report). */
2184                 
2185                 return;
2186         }
2187  
2188         
2189         /* Return if the account is already connected */
2190         
2191         conn_status = tny_account_get_connection_status (account);
2192         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2193  
2194                 /* We promise to instantly perform the callback, so ... */
2195                 if (callback) {
2196                         callback (FALSE, NULL, parent_window, account, user_data);
2197                 }
2198                 
2199                 return;
2200         }
2201         
2202         /* Else, we are in a state that requires that we go online before we
2203          * call the caller's callback. */
2204         
2205         info = g_slice_new0 (OnWentOnlineInfo);
2206         
2207         info->device = NULL;
2208         info->iap = NULL;
2209         info->account = TNY_ACCOUNT (g_object_ref (account));
2210         
2211         if (parent_window)
2212                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2213         else
2214                 info->parent_window = NULL;
2215         
2216         /* So we'll put the callback away for later ... */
2217         
2218         info->user_data = user_data;
2219         info->callback = callback;
2220         
2221         if (!device_online) {
2222  
2223                 /* If also the device is offline, then we connect both the device 
2224                  * and the account */
2225                 
2226                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2227                                                       force, on_conic_device_went_online, 
2228                                                       info);
2229                 
2230         } else {
2231                 
2232                 /* If the device is online, we'll just connect the account */
2233                 
2234                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2235                                               on_account_went_online, info);
2236         }
2237  
2238         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2239          * in both situations, go look if you don't believe me! */
2240         
2241         return;
2242 }
2243
2244 void
2245 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2246                                                gboolean force,
2247                                                TnyFolderStore *folder_store, 
2248                                                ModestConnectedPerformer callback, 
2249                                                gpointer user_data)
2250 {
2251         TnyAccount *account = NULL;
2252
2253         if (!folder_store ||
2254             (TNY_IS_MERGE_FOLDER (folder_store) &&
2255              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2256
2257                 /* We promise to instantly perform the callback, so ... */
2258                 if (callback) {
2259                         GError *error = NULL;
2260                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2261                                      "Unable to move or not found folder");
2262                         callback (FALSE, error, parent_window, NULL, user_data);
2263                         g_error_free (error);
2264                 }
2265                 return;
2266
2267         } else if (TNY_IS_FOLDER (folder_store)) {
2268                 /* Get the folder's parent account: */
2269                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2270         } else if (TNY_IS_ACCOUNT (folder_store)) {
2271                 /* Use the folder store as an account: */
2272                 account = TNY_ACCOUNT (g_object_ref (folder_store));
2273         }
2274
2275         if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2276                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2277                         /* No need to connect a local account */
2278                         if (callback)
2279                                 callback (FALSE, NULL, parent_window, account, user_data);
2280
2281                         goto clean;
2282                 }
2283         }
2284         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2285
2286  clean:
2287         if (account)
2288                 g_object_unref (account);
2289 }
2290
2291 static void
2292 src_account_connect_performer (gboolean canceled,
2293                                GError *err,
2294                                GtkWindow *parent_window,
2295                                TnyAccount *src_account,
2296                                gpointer user_data)
2297 {
2298         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2299
2300         if (canceled || err) {
2301                 /* If there was any error call the user callback */
2302                 info->callback (canceled, err, parent_window, src_account, info->data);
2303         } else {
2304                 /* Connect the destination account */
2305                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2306                                                                TNY_FOLDER_STORE (info->dst_account),
2307                                                                info->callback, info->data);
2308         }
2309
2310         /* Free the info object */
2311         g_object_unref (info->dst_account);
2312         g_slice_free (DoubleConnectionInfo, info);
2313 }
2314
2315
2316 void 
2317 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2318                                             gboolean force,
2319                                             TnyFolderStore *folder_store,
2320                                             DoubleConnectionInfo *connect_info)
2321 {
2322         modest_platform_connect_if_remote_and_perform(parent_window, 
2323                                                       force,
2324                                                       folder_store, 
2325                                                       src_account_connect_performer, 
2326                                                       connect_info);
2327 }
2328
2329 GtkWidget *
2330 modest_platform_get_account_settings_wizard (void)
2331 {
2332         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2333
2334         return GTK_WIDGET (dialog);
2335 }
2336
2337 ModestConnectedVia
2338 modest_platform_get_current_connection (void)
2339 {
2340         TnyDevice *device = NULL;
2341         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2342         
2343         device = modest_runtime_get_device ();
2344
2345         if (!tny_device_is_online (device))
2346                 return MODEST_CONNECTED_VIA_ANY;
2347
2348 #ifdef MODEST_HAVE_CONIC
2349         /* Get iap id */
2350         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2351         if (iap_id) {
2352                 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2353                         TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2354                 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2355                 if (bearer_type) {
2356                         if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2357                             !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2358                             !strcmp (bearer_type, "WIMAX")) {
2359                                 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2360                         } else {
2361                                 retval = MODEST_CONNECTED_VIA_ANY;
2362                         }
2363                 }       
2364                 g_object_unref (iap);
2365         }
2366 #else
2367         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
2368 #endif /* MODEST_HAVE_CONIC */
2369         return retval;
2370 }
2371
2372
2373
2374 gboolean
2375 modest_platform_check_memory_low (ModestWindow *win,
2376                                   gboolean visuals)
2377 {
2378         gboolean lowmem;
2379         
2380         /* are we in low memory state? */
2381         lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2382         
2383         if (win && lowmem && visuals)
2384                 modest_platform_run_information_dialog (
2385                         GTK_WINDOW(win),
2386                         _KR("memr_ib_operation_disabled"),
2387                         TRUE);
2388
2389         if (lowmem)
2390                 g_debug ("%s: low memory reached. disallowing some operations",
2391                          __FUNCTION__);
2392
2393         return lowmem;
2394 }
2395
2396 void 
2397 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2398                                            TnyFolder *folder)
2399 {
2400         GtkWidget *dialog;
2401         
2402         /* Create dialog */
2403         dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2404
2405         /* Run dialog */
2406         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2407                                      GTK_WINDOW (dialog), 
2408                                      parent_window);
2409         gtk_widget_show_all (dialog);
2410
2411         g_signal_connect_swapped (dialog, "response", 
2412                                   G_CALLBACK (gtk_widget_destroy),
2413                                   dialog);
2414 }
2415
2416 void
2417 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2418                                            TnyHeader *header)
2419 {
2420         GtkWidget *dialog;
2421
2422         /* Create dialog */
2423         dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2424
2425         /* Run dialog */
2426         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2427                                      GTK_WINDOW (dialog),
2428                                      parent_window);
2429         gtk_widget_show_all (dialog);
2430
2431         g_signal_connect_swapped (dialog, "response", 
2432                                   G_CALLBACK (gtk_widget_destroy),
2433                                   dialog);
2434 }
2435
2436 osso_context_t *
2437 modest_platform_get_osso_context (void)
2438 {
2439         return modest_maemo_utils_get_osso_context ();
2440 }
2441
2442 static void
2443 _modest_platform_play_email_tone (void)
2444 {
2445         gchar *active_profile;
2446         gchar *mail_tone;
2447         gchar *mail_volume;
2448         gint mail_volume_int;
2449         int ret;
2450         ca_context *ca_con = NULL;
2451         ca_proplist *pl = NULL;
2452
2453         active_profile = profile_get_profile ();
2454         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2455         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2456         mail_volume_int = profile_parse_int (mail_volume);
2457
2458         if (mail_tone && !strstr (mail_tone, "/")) {
2459                 gchar *tmp;
2460
2461                 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2462                 g_free (mail_tone);
2463                 mail_tone = tmp;
2464         }
2465
2466         if (mail_volume_int > 0) {
2467
2468                 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2469                         g_warning("ca_context_create: %s\n", ca_strerror(ret));
2470                         return;
2471                 }
2472
2473                 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2474                         g_warning("ca_context_open: %s\n", ca_strerror(ret));
2475                         ca_context_destroy(ca_con);
2476                         return;
2477                 }
2478
2479                 ca_proplist_create(&pl);
2480                 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2481                 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2482
2483                 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2484                 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2485
2486                 ca_proplist_destroy(pl);
2487                 ca_context_destroy(ca_con);
2488         }
2489
2490         g_free (mail_volume);
2491         g_free (mail_tone);
2492         g_free (active_profile);
2493 }
2494
2495 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2496 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2497 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2498 #define MOVE_TO_DIALOG_SELECTION_LABEL "selection-label"
2499 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2500 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2501
2502 static void
2503 move_to_dialog_show_accounts (GtkWidget *dialog)
2504 {
2505         GtkWidget *selection_label;
2506         GtkWidget *back_button;
2507         GtkWidget *folder_view;
2508         GtkWidget *pannable;
2509         GtkWidget *action_button;
2510
2511         selection_label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL));
2512         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2513         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2514         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2515         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2516
2517         gtk_widget_set_sensitive (back_button, FALSE);
2518         gtk_widget_set_sensitive (action_button, FALSE);
2519
2520         /* Need to set this here, otherwise callbacks called because
2521            of filtering won't perform correctly */
2522         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2523
2524         gtk_label_set_text (GTK_LABEL (selection_label), "");
2525         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2526         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2527         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2528         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2529
2530         g_object_set (G_OBJECT (folder_view), 
2531                       "hildon-ui-mode", HILDON_UI_MODE_NORMAL, 
2532                       NULL);
2533 }
2534
2535 static void
2536 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2537 {
2538         GtkWidget *selection_label;
2539         GtkWidget *back_button;
2540         GtkWidget *folder_view;
2541         TnyAccount *account;
2542         const gchar *account_id;
2543         gchar *selection_label_text;
2544         GtkWidget *pannable;
2545         GtkWidget *action_button;
2546
2547         selection_label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL));
2548         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2549         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2550         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2551         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2552
2553         gtk_widget_set_sensitive (back_button, TRUE);
2554         gtk_widget_set_sensitive (action_button, FALSE);
2555
2556         /* Need to set this here, otherwise callbacks called because
2557            of filtering won't perform correctly */
2558         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (TRUE));
2559
2560         g_object_set (G_OBJECT (folder_view),
2561                       "hildon-ui-mode", HILDON_UI_MODE_EDIT,
2562                       NULL);
2563
2564         account = TNY_ACCOUNT (folder_store);
2565         if (modest_tny_account_is_virtual_local_folders (account)) {
2566                 gchar *device_name;
2567                 account_id = tny_account_get_id (account);
2568                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2569                                                       MODEST_CONF_DEVICE_NAME, NULL);
2570                 if (device_name) {
2571                         selection_label_text = g_strconcat (device_name, "/", NULL);
2572                         g_free (device_name);
2573                 } else {
2574                         selection_label_text = g_strconcat (tny_account_get_name (account), "/", NULL);
2575                 }
2576                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2577                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2578         } else if (modest_tny_account_is_memory_card_account (account)) {
2579                 account_id = tny_account_get_id (account);
2580                 selection_label_text = g_strconcat (tny_account_get_name (account), "/", NULL);
2581                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2582                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2583         } else {
2584                 account_id = tny_account_get_id (account);
2585
2586                 selection_label_text = g_strconcat (tny_account_get_name (account), "/", NULL);
2587                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2588                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2589                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2590                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2591         }
2592         gtk_label_set_text (GTK_LABEL (selection_label), selection_label_text);
2593         g_free (selection_label_text);
2594
2595         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2596                                                                      account_id);
2597
2598         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2599         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2600         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2601         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2602 }
2603
2604 static void
2605 move_to_dialog_set_selected_folder (GtkWidget *dialog, TnyFolderStore *folder_store)
2606 {
2607         GtkWidget *selection_label;
2608         GtkWidget *action_button;
2609         gchar *folder_name;
2610
2611         selection_label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL));
2612         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2613
2614         gtk_widget_set_sensitive (action_button, TRUE);
2615
2616         if (TNY_IS_FOLDER (folder_store)) {
2617                 folder_name = modest_tny_folder_get_display_name (TNY_FOLDER (folder_store));
2618         } else if (TNY_IS_ACCOUNT (folder_store)) {
2619                 folder_name = g_strdup (tny_account_get_name (TNY_ACCOUNT (folder_store)));
2620         } else {
2621                 folder_name = g_strdup ("");
2622         }
2623
2624         gtk_label_set_text (GTK_LABEL (selection_label), folder_name);
2625         g_free (folder_name);
2626
2627 }
2628
2629 static void
2630 on_move_to_dialog_back_clicked (GtkButton *button,
2631                                 gpointer userdata)
2632 {
2633         GtkWidget *dialog = (GtkWidget *) userdata;
2634         ModestFolderView *folder_view;
2635
2636         /* Revert the effect of show_folders filters */
2637         folder_view = MODEST_FOLDER_VIEW (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2638         modest_folder_view_set_account_id_of_visible_server_account (folder_view, NULL);
2639         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2640         modest_folder_view_unset_filter (folder_view, MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2641         modest_folder_view_unset_filter (folder_view, MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2642
2643         /* Back to show accounts */
2644         move_to_dialog_show_accounts (dialog);
2645 }
2646
2647 static void
2648 on_move_to_dialog_folder_activated (GtkTreeView       *tree_view,
2649                                     GtkTreePath       *path,
2650                                     GtkTreeViewColumn *column,
2651                                     gpointer           user_data)
2652 {
2653         TnyFolderStore *selected;
2654         GtkWidget *dialog;
2655         GtkWidget *folder_view;
2656         gboolean showing_folders;
2657
2658         dialog = (GtkWidget *) user_data;
2659         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2660         if (!showing_folders) {
2661                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2662
2663                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2664                 if (selected) {
2665                         move_to_dialog_show_folders (dialog, selected);
2666                 }
2667         }
2668 }
2669
2670 static void
2671 on_move_to_dialog_selection_changed (GtkTreeSelection       *selection,
2672                                     gpointer           user_data)
2673 {
2674         gboolean showing_folders;
2675         GtkWidget *dialog;
2676
2677         dialog = (GtkWidget *) user_data;
2678         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2679         if (showing_folders) {
2680                 TnyFolderStore *selected;
2681                 GtkWidget *folder_view;
2682
2683                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2684                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2685
2686                 if (selected) {
2687                         move_to_dialog_set_selected_folder (dialog, selected);
2688                         g_object_unref (selected);
2689                 }
2690         }
2691 }
2692
2693 static void
2694 on_move_to_dialog_action_clicked (GtkButton       *selection,
2695                                   gpointer           user_data)
2696 {
2697         TnyFolderStore *selected;
2698         GtkWidget *dialog;
2699         GtkWidget *folder_view;
2700         gboolean showing_folders;
2701
2702         dialog = (GtkWidget *) user_data;
2703         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2704         if (showing_folders) {
2705                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2706                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2707
2708                 if (selected)
2709                         gtk_dialog_response  (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2710         }
2711 }
2712
2713 GtkWidget *
2714 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2715                                        GtkWidget **folder_view)
2716 {
2717         GtkWidget *dialog, *folder_view_container;
2718         GtkWidget *align;
2719         GtkWidget *buttons_hbox;
2720         GtkWidget *back_button, *selection_label;
2721         GdkPixbuf *back_pixbuf;
2722         GtkWidget *top_vbox;
2723         GtkWidget *action_button;
2724         GtkTreeSelection *selection;
2725
2726         /* Create dialog. We cannot use a touch selector because we
2727            need to use here the folder view widget directly */
2728         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2729                                               GTK_WINDOW (parent_window),
2730                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2731                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2732                                               _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2733                                               NULL);
2734
2735         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2736         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2737         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2738
2739         /* Create folder view */
2740         *folder_view = modest_platform_create_folder_view (NULL);
2741
2742         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2743                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2744         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2745                                                FALSE);
2746         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2747                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2748
2749         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2750         back_button = gtk_button_new ();
2751         back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2752         if (back_pixbuf) {
2753                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2754                 g_object_unref (back_pixbuf);
2755         }
2756         selection_label = gtk_label_new ("");
2757         gtk_misc_set_alignment (GTK_MISC (selection_label), 0.0, 0.5);
2758
2759         action_button = gtk_button_new ();
2760         gtk_container_add (GTK_CONTAINER (action_button), selection_label);
2761
2762         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2763         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2764         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2765         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2766         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2767
2768         /* Create pannable and add it to the dialog */
2769         folder_view_container = hildon_pannable_area_new ();
2770         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2771         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2772
2773         gtk_container_add (GTK_CONTAINER (align), top_vbox);
2774         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2775
2776         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2777
2778         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2779         gtk_widget_show (folder_view_container);
2780         gtk_widget_show (align);
2781         gtk_widget_show (top_vbox);
2782         gtk_widget_show (*folder_view);
2783         gtk_widget_show_all (back_button);
2784         gtk_widget_show (selection_label);
2785         gtk_widget_show (action_button);
2786         gtk_widget_show (buttons_hbox);
2787         gtk_widget_show (dialog);
2788
2789         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2790         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2791         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2792         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL, selection_label);
2793         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2794
2795         /* Simulate the behaviour of a HildonPickerDialog by emitting
2796            a response when a folder is selected */
2797         g_signal_connect (*folder_view, "row-activated",
2798                           G_CALLBACK (on_move_to_dialog_folder_activated),
2799                           dialog);
2800
2801         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2802         g_signal_connect (selection, "changed",
2803                           G_CALLBACK (on_move_to_dialog_selection_changed),
2804                           dialog);
2805
2806         g_signal_connect (action_button, "clicked",
2807                           G_CALLBACK (on_move_to_dialog_action_clicked),
2808                           dialog);
2809
2810         g_signal_connect (back_button, "clicked",
2811                           G_CALLBACK (on_move_to_dialog_back_clicked),
2812                           dialog);
2813
2814         move_to_dialog_show_accounts (dialog);
2815
2816         return dialog;
2817 }
2818
2819 TnyList *
2820 modest_platform_get_list_to_move (ModestWindow *window)
2821 {
2822         TnyList *list = NULL;
2823
2824         if (MODEST_IS_HEADER_WINDOW (window)) {
2825                 ModestHeaderView *header_view;
2826
2827                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2828                 list = modest_header_view_get_selected_headers (header_view);
2829         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2830                 ModestFolderView *folder_view;
2831                 TnyFolderStore *selected_folder;
2832
2833                 list = TNY_LIST (tny_simple_list_new ());
2834                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2835                 selected_folder = modest_folder_view_get_selected (folder_view);
2836                 if (selected_folder) {
2837                         tny_list_prepend (list, G_OBJECT (selected_folder));
2838                         g_object_unref (selected_folder);
2839                 }
2840                 return list;
2841         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2842                 TnyHeader *header;
2843
2844                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2845                 if (header) {
2846                         list = TNY_LIST (tny_simple_list_new ());
2847                         tny_list_prepend (list, G_OBJECT (header));
2848                         g_object_unref (header);
2849                 }
2850         } else {
2851                 g_return_val_if_reached (NULL);
2852         }
2853
2854         return list;
2855 }