Added action button to move to dialog
[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 (data) {
1350                 if (g_signal_handler_is_connected (account, data->handler))
1351                         g_signal_handler_disconnect (account, data->handler);
1352                 g_mutex_free (data->mutex);
1353                 g_main_loop_unref (data->wait_loop);
1354                 g_slice_free (ConnectAndWaitData, data);
1355         }
1356
1357         conn_status = tny_account_get_connection_status (account);
1358         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1359 }
1360
1361 gboolean 
1362 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1363 {
1364         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1365                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1366                         /* This must be a maildir account, which does not require a connection: */
1367                         return TRUE;
1368                 }
1369         }
1370
1371         return modest_platform_connect_and_wait (parent_window, account);
1372 }
1373
1374 gboolean 
1375 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1376 {
1377         if (!folder_store)
1378                 return TRUE; /* Maybe it is something local. */
1379                 
1380         gboolean result = TRUE;
1381         if (TNY_IS_FOLDER (folder_store)) {
1382                 /* Get the folder's parent account: */
1383                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1384                 if (account != NULL) {
1385                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1386                         g_object_unref (account);
1387                 }
1388         } else if (TNY_IS_ACCOUNT (folder_store)) {
1389                 /* Use the folder store as an account: */
1390                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1391         }
1392
1393         return result;
1394 }
1395
1396 GtkWidget *
1397 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1398 {
1399         GtkWidget *dialog;
1400
1401         dialog = modest_hildon2_sort_dialog_new (parent_window);
1402
1403         return dialog;
1404 }
1405
1406
1407 gboolean 
1408 modest_platform_set_update_interval (guint minutes)
1409 {
1410 #ifdef MODEST_HAVE_LIBALARM
1411         
1412         ModestConf *conf = modest_runtime_get_conf ();
1413         if (!conf)
1414                 return FALSE;
1415                 
1416         cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1417
1418         /* Delete any existing alarm,
1419          * because we will replace it: */
1420         if (alarm_cookie) {
1421                 if (alarmd_event_del(alarm_cookie) != 0)
1422                         g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1423                 alarm_cookie = 0;
1424                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1425         }
1426         
1427         /* 0 means no updates: */
1428         if (minutes == 0)
1429                 return TRUE;
1430         
1431      
1432         /* Register alarm: */
1433         
1434         /* Set the interval in alarm_event_t structure: */
1435         alarm_event_t *event = alarm_event_create ();
1436         alarm_event_add_actions (event, 1);
1437         alarm_action_t *action = alarm_event_get_action (event, 0);
1438         alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1439         event->alarm_time = minutes * 60; /* seconds */
1440         
1441         /* Set recurrence every few minutes: */
1442         event->recur_secs = minutes*60;
1443         event->recur_count = -1; /* Means infinite */
1444
1445         /* Specify what should happen when the alarm happens:
1446          * It should call this D-Bus method: */
1447          
1448         action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1449         action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1450         action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1451         action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1452         action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1453
1454         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1455          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1456          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1457          * This is why we want to use the Alarm API instead of just g_timeout_add().
1458          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1459          * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1460          */
1461         event->flags = ALARM_EVENT_CONNECTED;
1462         
1463         alarm_cookie = alarmd_event_add (event);
1464
1465         /* now, free it */
1466         alarm_event_delete (event);
1467         
1468         /* Store the alarm ID in GConf, so we can remove it later:
1469          * This is apparently valid between application instances. */
1470         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1471         
1472         if (!alarm_cookie) {
1473             /* Error */
1474             g_debug ("Error setting alarm event. \n");
1475             
1476             return FALSE;
1477         }
1478 #endif /* MODEST_HAVE_LIBALARM */       
1479         return TRUE;
1480 }
1481
1482 void
1483 modest_platform_push_email_notification(void)
1484 {
1485         gboolean screen_on, app_in_foreground;
1486
1487         /* Get the window status */
1488         app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1489
1490         screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1491
1492         /* If the screen is on and the app is in the
1493            foreground we don't show anything */
1494         if (!(screen_on && app_in_foreground)) {
1495
1496                 _modest_platform_play_email_tone ();
1497
1498                 /* Activate LED. This must be deactivated by
1499                    modest_platform_remove_new_mail_notifications */
1500 #ifdef MODEST_HAVE_MCE
1501                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1502                                      MCE_SERVICE,
1503                                      MCE_REQUEST_PATH,
1504                                      MCE_REQUEST_IF,
1505                                      MCE_ACTIVATE_LED_PATTERN,
1506                                      NULL,
1507                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1508                                      DBUS_TYPE_INVALID);
1509 #endif
1510         }
1511 }
1512
1513 void 
1514 modest_platform_on_new_headers_received (TnyList *header_list,
1515                                          gboolean show_visual)
1516 {
1517         g_return_if_fail (TNY_IS_LIST(header_list));
1518
1519         if (tny_list_get_length(header_list) == 0) {
1520                 g_warning ("%s: header list is empty", __FUNCTION__);
1521                 return;
1522         }
1523
1524         if (!show_visual) {
1525                 modest_platform_push_email_notification ();
1526                 /* We do a return here to avoid indentation with an else */
1527                 return;
1528         }
1529
1530 #ifdef MODEST_HAVE_HILDON_NOTIFY
1531         HildonNotification *notification;
1532         TnyIterator *iter;
1533         GSList *notifications_list = NULL;
1534
1535         /* Get previous notifications ids */
1536         notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1537                                                    MODEST_CONF_NOTIFICATION_IDS,
1538                                                    MODEST_CONF_VALUE_INT, NULL);
1539
1540         iter = tny_list_create_iterator (header_list);
1541         while (!tny_iterator_is_done (iter)) {
1542                 gchar *url = NULL, *display_address = NULL;
1543                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1544                 TnyFolder *folder = tny_header_get_folder (header);
1545                 gboolean first_notification = TRUE;
1546                 gint notif_id;
1547                 gchar *str;
1548
1549                 display_address = tny_header_dup_from (header);
1550                 /* string is changed in-place */
1551                 modest_text_utils_get_display_address (display_address);
1552
1553                 str = tny_header_dup_subject (header);
1554                 notification = hildon_notification_new (display_address,
1555                                                         str,
1556                                                         "qgn_list_messagin",
1557                                                         MODEST_NOTIFICATION_CATEGORY);
1558                 g_free (str);
1559                 /* Create the message URL */
1560                 str = tny_header_dup_uid (header);
1561                 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder), 
1562                                        str);
1563                 g_free (str);
1564
1565                 hildon_notification_add_dbus_action(notification,
1566                                                     "default",
1567                                                     "Cancel",
1568                                                     MODEST_DBUS_SERVICE,
1569                                                     MODEST_DBUS_OBJECT,
1570                                                     MODEST_DBUS_IFACE,
1571                                                     MODEST_DBUS_METHOD_OPEN_MESSAGE,
1572                                                     G_TYPE_STRING, url,
1573                                                     -1);
1574
1575                 /* Play sound if the user wants. Show the LED
1576                    pattern. Show and play just one */
1577                 if (G_UNLIKELY (first_notification)) {
1578                         TnyAccount *account;
1579
1580                         first_notification = FALSE;
1581
1582                         /* Set the led pattern */
1583                         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1584                                                             "dialog-type", 4);
1585                         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1586                                                             "led-pattern",
1587                                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);
1588
1589                         /* Set the account of the headers */
1590                         account = tny_folder_get_account (folder);
1591                         if (account) {
1592                                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1593                                                                     "email-account",
1594                                                                     tny_account_get_id (account));
1595                                 g_object_unref (account);
1596                         }
1597                 }
1598
1599                 /* Notify. We need to do this in an idle because this function
1600                    could be called from a thread */
1601                 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1602
1603                 /* Save id in the list */
1604                 g_object_get(G_OBJECT(notification), "id", &notif_id, NULL);
1605                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1606                 /* We don't listen for the "closed" signal, because we
1607                    don't care about if the notification was removed or
1608                    not to store the list in gconf */
1609         
1610                 /* Free & carry on */
1611                 g_free (display_address);
1612                 g_free (url);
1613                 g_object_unref (folder);
1614                 g_object_unref (header);
1615                 tny_iterator_next (iter);
1616         }
1617         g_object_unref (iter);
1618
1619         /* Save the ids */
1620         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1621                               notifications_list, MODEST_CONF_VALUE_INT, NULL);
1622
1623         g_slist_free (notifications_list);
1624         
1625 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1626 }
1627
1628 void
1629 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1630 {
1631         if (only_visuals) {
1632 #ifdef MODEST_HAVE_MCE
1633                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1634                                      MCE_SERVICE,
1635                                      MCE_REQUEST_PATH,
1636                                      MCE_REQUEST_IF,
1637                                      MCE_DEACTIVATE_LED_PATTERN,
1638                                      NULL,
1639                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1640                                      DBUS_TYPE_INVALID);
1641 #endif
1642                 return;
1643         }
1644
1645 #ifdef MODEST_HAVE_HILDON_NOTIFY
1646         GSList *notif_list = NULL;
1647
1648         /* Get previous notifications ids */
1649         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1650                                            MODEST_CONF_NOTIFICATION_IDS, 
1651                                            MODEST_CONF_VALUE_INT, NULL);
1652
1653         while (notif_list) {
1654                 gint notif_id;
1655                 NotifyNotification *notif;
1656
1657                 /* Nasty HACK to remove the notifications, set the id
1658                    of the existing ones and then close them */
1659                 notif_id = GPOINTER_TO_INT(notif_list->data);
1660                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1661                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1662
1663                 /* Close the notification, note that some ids could be
1664                    already invalid, but we don't care because it does
1665                    not fail */
1666                 notify_notification_close(notif, NULL);
1667                 g_object_unref(notif);
1668
1669                 /* Delete the link, it's like going to the next */
1670                 notif_list = g_slist_delete_link (notif_list, notif_list);
1671         }
1672
1673         /* Save the ids */
1674         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1675                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1676
1677         g_slist_free (notif_list);
1678
1679 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1680 }
1681
1682
1683
1684 GtkWidget * 
1685 modest_platform_get_global_settings_dialog ()
1686 {
1687         return modest_hildon2_global_settings_dialog_new ();
1688 }
1689
1690 void
1691 modest_platform_show_help (GtkWindow *parent_window, 
1692                            const gchar *help_id)
1693 {
1694         return;
1695 }
1696
1697 void 
1698 modest_platform_show_search_messages (GtkWindow *parent_window)
1699 {
1700         osso_return_t result = OSSO_ERROR;
1701         
1702         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1703                                              "osso_global_search",
1704                                              "search_email", NULL, DBUS_TYPE_INVALID);
1705
1706         if (result != OSSO_OK) {
1707                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1708         }
1709 }
1710
1711 void 
1712 modest_platform_show_addressbook (GtkWindow *parent_window)
1713 {
1714         osso_return_t result = OSSO_ERROR;
1715
1716         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1717                                              "osso_addressbook",
1718                                              "top_application", NULL, DBUS_TYPE_INVALID);
1719
1720         if (result != OSSO_OK) {
1721                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1722         }
1723 }
1724
1725 GtkWidget *
1726 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1727 {
1728         GtkWidget *widget = modest_folder_view_new (query);
1729
1730         /* Show one account by default */
1731         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1732                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1733
1734         /* Restore settings */
1735         modest_widget_memory_restore (modest_runtime_get_conf(), 
1736                                       G_OBJECT (widget),
1737                                       MODEST_CONF_FOLDER_VIEW_KEY);
1738
1739         return widget;
1740 }
1741
1742 void
1743 banner_finish (gpointer data, GObject *object)
1744 {
1745         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1746         modest_window_mgr_unregister_banner (mgr);
1747         g_object_unref (mgr);
1748 }
1749
1750 void 
1751 modest_platform_information_banner (GtkWidget *parent,
1752                                     const gchar *icon_name,
1753                                     const gchar *text)
1754 {
1755         GtkWidget *banner, *banner_parent = NULL;
1756         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1757
1758         if (modest_window_mgr_get_num_windows (mgr) == 0)
1759                 return;
1760
1761         if (parent && GTK_IS_WINDOW (parent)) {
1762                 /* If the window is the active one then show the
1763                    banner on top of this window */
1764                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1765                         banner_parent = parent;
1766                 /* If the window is not the topmost but it's visible
1767                    (it's minimized for example) then show the banner
1768                    with no parent */ 
1769                 else if (GTK_WIDGET_VISIBLE (parent))
1770                         banner_parent = NULL;
1771                 /* If the window is hidden (like the main window when
1772                    running in the background) then do not show
1773                    anything */
1774                 else 
1775                         return;
1776         }
1777
1778
1779         banner = hildon_banner_show_information (banner_parent, icon_name, text);
1780
1781         modest_window_mgr_register_banner (mgr);
1782         g_object_ref (mgr);
1783         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1784 }
1785
1786 void
1787 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1788                                                  const gchar *icon_name,
1789                                                  const gchar *text,
1790                                                  gint timeout)
1791 {
1792         GtkWidget *banner;
1793
1794         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1795                 return;
1796
1797         banner = hildon_banner_show_information (parent, icon_name, text);
1798         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1799 }
1800
1801 GtkWidget *
1802 modest_platform_animation_banner (GtkWidget *parent,
1803                                   const gchar *animation_name,
1804                                   const gchar *text)
1805 {
1806         GtkWidget *inf_note = NULL;
1807
1808         g_return_val_if_fail (text != NULL, NULL);
1809
1810         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1811                 return NULL;
1812
1813         /* If the parent is not visible then do not show */
1814         if (parent && !GTK_WIDGET_VISIBLE (parent))
1815                 return NULL;
1816
1817         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1818
1819         return inf_note;
1820 }
1821
1822 typedef struct
1823 {
1824         GMainLoop* loop;
1825         TnyAccount *account;
1826         gboolean is_online;
1827         gint count_tries;
1828 } CheckAccountIdleData;
1829
1830 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1831
1832 static gboolean 
1833 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1834 {
1835         gboolean stop_trying = FALSE;
1836         g_return_val_if_fail (data && data->account, FALSE);
1837         
1838         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1839                 tny_account_get_connection_status (data->account));     
1840         
1841         if (data && data->account && 
1842                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1843                  * after which the account is likely to be usable, or never likely to be usable soon: */
1844                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1845         {
1846                 data->is_online = TRUE;
1847                 
1848                 stop_trying = TRUE;
1849         } else {
1850                 /* Give up if we have tried too many times: */
1851                 if (data->count_tries >= NUMBER_OF_TRIES) {
1852                         stop_trying = TRUE;
1853                 } else {
1854                         /* Wait for another timeout: */
1855                         ++(data->count_tries);
1856                 }
1857         }
1858         
1859         if (stop_trying) {
1860                 /* Allow the function that requested this idle callback to continue: */
1861                 if (data->loop)
1862                         g_main_loop_quit (data->loop);
1863                         
1864                 if (data->account)
1865                         g_object_unref (data->account);
1866                 
1867                 return FALSE; /* Don't call this again. */
1868         } else {
1869                 return TRUE; /* Call this timeout callback again. */
1870         }
1871 }
1872
1873 /* Return TRUE immediately if the account is already online,
1874  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1875  * soon as the account is online, or FALSE if the account does 
1876  * not become online in the NUMBER_OF_TRIES seconds.
1877  * This is useful when the D-Bus method was run immediately after 
1878  * the application was started (when using D-Bus activation), 
1879  * because the account usually takes a short time to go online.
1880  * The return value is maybe not very useful.
1881  */
1882 gboolean
1883 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1884 {
1885         gboolean is_online;
1886
1887         g_return_val_if_fail (account, FALSE);
1888
1889         if (!tny_device_is_online (modest_runtime_get_device())) {
1890                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1891                 return FALSE;
1892         }
1893
1894         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1895          * so we avoid wait unnecessarily: */
1896         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1897                 return TRUE;
1898
1899         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1900          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1901          * we want to avoid. */
1902         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1903                 return TRUE;
1904                 
1905         /* This blocks on the result: */
1906         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1907         data->is_online = FALSE;
1908         data->account = account;
1909         g_object_ref (data->account);
1910         data->count_tries = 0;
1911                 
1912         GMainContext *context = NULL; /* g_main_context_new (); */
1913         data->loop = g_main_loop_new (context, FALSE /* not running */);
1914
1915         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1916
1917         /* This main loop will run until the idle handler has stopped it: */
1918         g_main_loop_run (data->loop);
1919
1920         g_main_loop_unref (data->loop);
1921         /* g_main_context_unref (context); */
1922
1923         is_online = data->is_online;
1924         g_slice_free (CheckAccountIdleData, data);
1925         
1926         return is_online;       
1927 }
1928
1929
1930
1931 static void
1932 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1933 {
1934         /* GTK_RESPONSE_HELP means we need to show the certificate */
1935         if (response_id == GTK_RESPONSE_APPLY) {
1936                 GtkWidget *note;
1937                 gchar *msg;
1938                 
1939                 /* Do not close the dialog */
1940                 g_signal_stop_emission_by_name (dialog, "response");
1941
1942                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1943                 note = hildon_note_new_information (NULL, msg);
1944                 gtk_dialog_run (GTK_DIALOG(note));
1945                 gtk_widget_destroy (note);
1946         }
1947 }
1948
1949
1950 gboolean
1951 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1952                                                      const gchar *certificate)
1953 {
1954         GtkWidget *note;
1955         gint response;
1956         ModestWindow *win;
1957         HildonWindowStack *stack;
1958
1959         stack = hildon_window_stack_get_default ();
1960         win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1961
1962         if (!win) {
1963           g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1964                            __FUNCTION__);
1965                 return FALSE;
1966         }
1967
1968         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1969                                            server_name);
1970
1971         /* We use GTK_RESPONSE_APPLY because we want the button in the
1972            middle of OK and CANCEL the same as the browser does for
1973            example. With GTK_RESPONSE_HELP the view button is aligned
1974            to the left while the other two to the right */
1975         note = hildon_note_new_confirmation_add_buttons  (
1976                 NULL,
1977                 question,
1978                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
1979                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
1980                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1981                 NULL, NULL);
1982
1983         g_signal_connect (G_OBJECT(note), "response", 
1984                           G_CALLBACK(on_cert_dialog_response),
1985                           (gpointer) certificate);
1986
1987         response = gtk_dialog_run(GTK_DIALOG(note));
1988
1989         on_destroy_dialog (note);
1990         g_free (question);
1991
1992         return response == GTK_RESPONSE_OK;
1993 }
1994
1995 gboolean
1996 modest_platform_run_alert_dialog (const gchar* prompt,
1997                                   gboolean is_question)
1998 {
1999         ModestWindow *top_win;
2000         HildonWindowStack *stack;
2001
2002         stack = hildon_window_stack_get_default ();
2003         top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2004
2005         if (!top_win) {
2006                 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2007                            __FUNCTION__);
2008                 return FALSE;
2009         }
2010
2011         gboolean retval = TRUE;
2012         if (is_question) {
2013                 /* The Tinymail documentation says that we should show Yes and No buttons,
2014                  * when it is a question.
2015                  * Obviously, we need tinymail to use more specific error codes instead,
2016                  * so we know what buttons to show. */
2017                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win), 
2018                                                                               prompt));
2019                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2020                                              GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2021
2022                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2023                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2024
2025                 on_destroy_dialog (dialog);
2026         } else {
2027                 /* Just show the error text and use the default response: */
2028                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
2029                                                         prompt, FALSE);
2030         }
2031         return retval;
2032 }
2033
2034 /***************/
2035 typedef struct {
2036         GtkWindow *parent_window;
2037         ModestConnectedPerformer callback;
2038         TnyAccount *account;
2039         gpointer user_data;
2040         gchar *iap;
2041         TnyDevice *device;
2042 } OnWentOnlineInfo;
2043  
2044 static void 
2045 on_went_online_info_free (OnWentOnlineInfo *info)
2046 {
2047         /* And if we cleanup, we DO cleanup  :-)  */
2048         
2049         if (info->device)
2050                 g_object_unref (info->device);
2051         if (info->iap)
2052                 g_free (info->iap);
2053         if (info->parent_window)
2054                 g_object_unref (info->parent_window);
2055         if (info->account)
2056                 g_object_unref (info->account);
2057         
2058         g_slice_free (OnWentOnlineInfo, info);
2059         
2060         /* We're done ... */
2061         
2062         return;
2063 }
2064  
2065 static void
2066 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2067 {
2068         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2069  
2070         /* Now it's really time to callback to the caller. If going online didn't succeed,
2071          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2072          * canceled will be set. Etcetera etcetera. */
2073         
2074         if (info->callback) {
2075                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2076         }
2077         
2078         /* This is our last call, we must cleanup here if we didn't yet do that */
2079         on_went_online_info_free (info);
2080         
2081         return;
2082 }
2083  
2084  
2085 static void
2086 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2087 {
2088         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2089         info->iap = g_strdup (iap_id);
2090         
2091         if (canceled || err || !info->account) {
2092         
2093                 /* If there's a problem or if there's no account (then that's it for us, we callback
2094                  * the caller's callback now. He'll have to handle err or canceled, of course.
2095                  * We are not really online, as the account is not really online here ... */    
2096                 
2097                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2098                  * this info. We don't cleanup err, Tinymail does that! */
2099                 
2100                 if (info->callback) {
2101                         
2102                         /* info->account can be NULL here, this means that the user did not
2103                          * provide a nice account instance. We'll assume that the user knows
2104                          * what he's doing and is happy with just the device going online. 
2105                          * 
2106                          * We can't do magic, we don't know what account the user wants to
2107                          * see going online. So just the device goes online, end of story */
2108                         
2109                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2110                 }
2111                 
2112         } else if (info->account) {
2113                 
2114                 /* If there's no problem and if we have an account, we'll put the account
2115                  * online too. When done, the callback of bringing the account online
2116                  * will callback the caller's callback. This is the most normal case. */
2117  
2118                 info->device = TNY_DEVICE (g_object_ref (device));
2119                 
2120                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2121                                               on_account_went_online, info);
2122                 
2123                 /* The on_account_went_online cb frees up the info, go look if you
2124                  * don't believe me! (so we return here) */
2125                 
2126                 return;
2127         }
2128         
2129         /* We cleanup if we are not bringing the account online too */
2130         on_went_online_info_free (info);
2131  
2132         return; 
2133 }
2134         
2135 void 
2136 modest_platform_connect_and_perform (GtkWindow *parent_window, 
2137                                      gboolean force,
2138                                      TnyAccount *account, 
2139                                      ModestConnectedPerformer callback, 
2140                                      gpointer user_data)
2141 {
2142         gboolean device_online;
2143         TnyDevice *device;
2144         TnyConnectionStatus conn_status;
2145         OnWentOnlineInfo *info;
2146         
2147         device = modest_runtime_get_device();
2148         device_online = tny_device_is_online (device);
2149
2150         /* If there is no account check only the device status */
2151         if (!account) {
2152                 
2153                 if (device_online) {
2154  
2155                         /* We promise to instantly perform the callback, so ... */
2156                         if (callback) {
2157                                 callback (FALSE, NULL, parent_window, account, user_data);
2158                         }
2159                         
2160                 } else {
2161                         
2162                         info = g_slice_new0 (OnWentOnlineInfo);
2163                         
2164                         info->iap = NULL;
2165                         info->device = NULL;
2166                         info->account = NULL;
2167                 
2168                         if (parent_window)
2169                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2170                         else
2171                                 info->parent_window = NULL;
2172                         info->user_data = user_data;
2173                         info->callback = callback;
2174                 
2175                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2176                                                               force, on_conic_device_went_online, 
2177                                                               info);
2178  
2179                         /* We'll cleanup in on_conic_device_went_online */
2180                 }
2181  
2182                 /* The other code has no more reason to run. This is all that we can do for the
2183                  * caller (he should have given us a nice and clean account instance!). We
2184                  * can't do magic, we don't know what account he intends to bring online. So
2185                  * we'll just bring the device online (and await his false bug report). */
2186                 
2187                 return;
2188         }
2189  
2190         
2191         /* Return if the account is already connected */
2192         
2193         conn_status = tny_account_get_connection_status (account);
2194         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2195  
2196                 /* We promise to instantly perform the callback, so ... */
2197                 if (callback) {
2198                         callback (FALSE, NULL, parent_window, account, user_data);
2199                 }
2200                 
2201                 return;
2202         }
2203         
2204         /* Else, we are in a state that requires that we go online before we
2205          * call the caller's callback. */
2206         
2207         info = g_slice_new0 (OnWentOnlineInfo);
2208         
2209         info->device = NULL;
2210         info->iap = NULL;
2211         info->account = TNY_ACCOUNT (g_object_ref (account));
2212         
2213         if (parent_window)
2214                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2215         else
2216                 info->parent_window = NULL;
2217         
2218         /* So we'll put the callback away for later ... */
2219         
2220         info->user_data = user_data;
2221         info->callback = callback;
2222         
2223         if (!device_online) {
2224  
2225                 /* If also the device is offline, then we connect both the device 
2226                  * and the account */
2227                 
2228                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2229                                                       force, on_conic_device_went_online, 
2230                                                       info);
2231                 
2232         } else {
2233                 
2234                 /* If the device is online, we'll just connect the account */
2235                 
2236                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2237                                               on_account_went_online, info);
2238         }
2239  
2240         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2241          * in both situations, go look if you don't believe me! */
2242         
2243         return;
2244 }
2245
2246 void
2247 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2248                                                gboolean force,
2249                                                TnyFolderStore *folder_store, 
2250                                                ModestConnectedPerformer callback, 
2251                                                gpointer user_data)
2252 {
2253         TnyAccount *account = NULL;
2254
2255         if (!folder_store ||
2256             (TNY_IS_MERGE_FOLDER (folder_store) &&
2257              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2258
2259                 /* We promise to instantly perform the callback, so ... */
2260                 if (callback) {
2261                         GError *error = NULL;
2262                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2263                                      "Unable to move or not found folder");
2264                         callback (FALSE, error, parent_window, NULL, user_data);
2265                         g_error_free (error);
2266                 }
2267                 return;
2268
2269         } else if (TNY_IS_FOLDER (folder_store)) {
2270                 /* Get the folder's parent account: */
2271                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2272         } else if (TNY_IS_ACCOUNT (folder_store)) {
2273                 /* Use the folder store as an account: */
2274                 account = TNY_ACCOUNT (g_object_ref (folder_store));
2275         }
2276
2277         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2278                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2279                         /* No need to connect a local account */
2280                         if (callback)
2281                                 callback (FALSE, NULL, parent_window, account, user_data);
2282
2283                         goto clean;
2284                 }
2285         }
2286         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2287
2288  clean:
2289         if (account)
2290                 g_object_unref (account);
2291 }
2292
2293 static void
2294 src_account_connect_performer (gboolean canceled,
2295                                GError *err,
2296                                GtkWindow *parent_window,
2297                                TnyAccount *src_account,
2298                                gpointer user_data)
2299 {
2300         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2301
2302         if (canceled || err) {
2303                 /* If there was any error call the user callback */
2304                 info->callback (canceled, err, parent_window, src_account, info->data);
2305         } else {
2306                 /* Connect the destination account */
2307                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2308                                                                TNY_FOLDER_STORE (info->dst_account),
2309                                                                info->callback, info->data);
2310         }
2311
2312         /* Free the info object */
2313         g_object_unref (info->dst_account);
2314         g_slice_free (DoubleConnectionInfo, info);
2315 }
2316
2317
2318 void 
2319 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2320                                             gboolean force,
2321                                             TnyFolderStore *folder_store,
2322                                             DoubleConnectionInfo *connect_info)
2323 {
2324         modest_platform_connect_if_remote_and_perform(parent_window, 
2325                                                       force,
2326                                                       folder_store, 
2327                                                       src_account_connect_performer, 
2328                                                       connect_info);
2329 }
2330
2331 GtkWidget *
2332 modest_platform_get_account_settings_wizard (void)
2333 {
2334         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2335
2336         return GTK_WIDGET (dialog);
2337 }
2338
2339 ModestConnectedVia
2340 modest_platform_get_current_connection (void)
2341 {
2342         TnyDevice *device = NULL;
2343         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2344         
2345         device = modest_runtime_get_device ();
2346
2347         if (!tny_device_is_online (device))
2348                 return MODEST_CONNECTED_VIA_ANY;
2349
2350 #ifdef MODEST_HAVE_CONIC
2351         /* Get iap id */
2352         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2353         if (iap_id) {
2354                 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2355                         TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2356                 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2357                 if (bearer_type) {
2358                         if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2359                             !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2360                             !strcmp (bearer_type, "WIMAX")) {
2361                                 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2362                         } else {
2363                                 retval = MODEST_CONNECTED_VIA_ANY;
2364                         }
2365                 }       
2366                 g_object_unref (iap);
2367         }
2368 #else
2369         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
2370 #endif /* MODEST_HAVE_CONIC */
2371         return retval;
2372 }
2373
2374
2375
2376 gboolean
2377 modest_platform_check_memory_low (ModestWindow *win,
2378                                   gboolean visuals)
2379 {
2380         gboolean lowmem;
2381         
2382         /* are we in low memory state? */
2383         lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2384         
2385         if (win && lowmem && visuals)
2386                 modest_platform_run_information_dialog (
2387                         GTK_WINDOW(win),
2388                         _KR("memr_ib_operation_disabled"),
2389                         TRUE);
2390
2391         if (lowmem)
2392                 g_debug ("%s: low memory reached. disallowing some operations",
2393                          __FUNCTION__);
2394
2395         return lowmem;
2396 }
2397
2398 void 
2399 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2400                                            TnyFolder *folder)
2401 {
2402         GtkWidget *dialog;
2403         
2404         /* Create dialog */
2405         dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2406
2407         /* Run dialog */
2408         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2409                                      GTK_WINDOW (dialog), 
2410                                      parent_window);
2411         gtk_widget_show_all (dialog);
2412
2413         g_signal_connect_swapped (dialog, "response", 
2414                                   G_CALLBACK (gtk_widget_destroy),
2415                                   dialog);
2416 }
2417
2418 void
2419 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2420                                            TnyHeader *header)
2421 {
2422         GtkWidget *dialog;
2423
2424         /* Create dialog */
2425         dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2426
2427         /* Run dialog */
2428         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2429                                      GTK_WINDOW (dialog),
2430                                      parent_window);
2431         gtk_widget_show_all (dialog);
2432
2433         g_signal_connect_swapped (dialog, "response", 
2434                                   G_CALLBACK (gtk_widget_destroy),
2435                                   dialog);
2436 }
2437
2438 osso_context_t *
2439 modest_platform_get_osso_context (void)
2440 {
2441         return modest_maemo_utils_get_osso_context ();
2442 }
2443
2444 static void
2445 _modest_platform_play_email_tone (void)
2446 {
2447         gchar *active_profile;
2448         gchar *mail_tone;
2449         gchar *mail_volume;
2450         gint mail_volume_int;
2451         int ret;
2452         ca_context *ca_con = NULL;
2453         ca_proplist *pl = NULL;
2454
2455         active_profile = profile_get_profile ();
2456         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2457         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2458         mail_volume_int = profile_parse_int (mail_volume);
2459
2460         if (mail_tone && !strstr (mail_tone, "/")) {
2461                 gchar *tmp;
2462
2463                 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2464                 g_free (mail_tone);
2465                 mail_tone = tmp;
2466         }
2467
2468         if (mail_volume_int > 0) {
2469
2470                 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2471                         g_warning("ca_context_create: %s\n", ca_strerror(ret));
2472                         return;
2473                 }
2474
2475                 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2476                         g_warning("ca_context_open: %s\n", ca_strerror(ret));
2477                         ca_context_destroy(ca_con);
2478                         return;
2479                 }
2480
2481                 ca_proplist_create(&pl);
2482                 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2483                 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2484
2485                 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2486                 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2487
2488                 ca_proplist_destroy(pl);
2489                 ca_context_destroy(ca_con);
2490         }
2491
2492         g_free (mail_volume);
2493         g_free (mail_tone);
2494         g_free (active_profile);
2495 }
2496
2497 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2498 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2499 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2500 #define MOVE_TO_DIALOG_SELECTION_LABEL "selection-label"
2501 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2502 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2503
2504 static void
2505 move_to_dialog_show_accounts (GtkWidget *dialog)
2506 {
2507         GtkWidget *selection_label;
2508         GtkWidget *back_button;
2509         GtkWidget *folder_view;
2510         GtkWidget *pannable;
2511         GtkWidget *action_button;
2512
2513         selection_label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL));
2514         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2515         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2516         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2517         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2518
2519         gtk_widget_set_sensitive (back_button, FALSE);
2520         gtk_widget_set_sensitive (action_button, FALSE);
2521
2522         gtk_label_set_text (GTK_LABEL (selection_label), "");
2523         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2524         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2525         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2526         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2527
2528         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2529 }
2530
2531 static void
2532 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2533 {
2534         GtkWidget *selection_label;
2535         GtkWidget *back_button;
2536         GtkWidget *folder_view;
2537         TnyAccount *account;
2538         const gchar *account_id;
2539         gchar *selection_label_text;
2540         GtkWidget *pannable;
2541         GtkWidget *action_button;
2542
2543         selection_label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL));
2544         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2545         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2546         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2547         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2548
2549         gtk_widget_set_sensitive (back_button, TRUE);
2550         gtk_widget_set_sensitive (action_button, FALSE);
2551
2552         account = TNY_ACCOUNT (folder_store);
2553         if (modest_tny_account_is_virtual_local_folders (account)) {
2554                 gchar *device_name;
2555                 account_id = tny_account_get_id (account);
2556                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2557                                                       MODEST_CONF_DEVICE_NAME, NULL);
2558                 if (device_name) {
2559                         selection_label_text = g_strconcat (device_name, "/", NULL);
2560                         g_free (device_name);
2561                 } else {
2562                         selection_label_text = g_strconcat (tny_account_get_name (account), "/", NULL);
2563                 }
2564                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2565                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2566         } else if (modest_tny_account_is_memory_card_account (account)) {
2567                 account_id = tny_account_get_id (account);
2568                 selection_label_text = g_strconcat (tny_account_get_name (account), "/", NULL);
2569                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2570                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2571         } else {
2572                 account_id = tny_account_get_id (account);
2573
2574                 selection_label_text = g_strconcat (tny_account_get_name (account), "/", NULL);
2575                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2576                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2577                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2578                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2579         }
2580         gtk_label_set_text (GTK_LABEL (selection_label), selection_label_text);
2581         g_free (selection_label_text);
2582
2583         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2584                                                                      account_id);
2585
2586         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2587         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2588         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2589         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2590
2591         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (TRUE));
2592 }
2593
2594 static void
2595 on_move_to_dialog_back_clicked (GtkButton *button,
2596                                 gpointer userdata)
2597 {
2598         GtkWidget *dialog = (GtkWidget *) userdata;
2599         ModestFolderView *folder_view;
2600
2601         /* Revert the effect of show_folders filters */
2602         folder_view = MODEST_FOLDER_VIEW (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2603         modest_folder_view_set_account_id_of_visible_server_account (folder_view, NULL);
2604         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2605         modest_folder_view_unset_filter (folder_view, MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2606         modest_folder_view_unset_filter (folder_view, MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2607
2608         /* Back to show accounts */
2609         move_to_dialog_show_accounts (dialog);
2610 }
2611
2612 static void
2613 on_move_to_dialog_folder_activated (GtkTreeView       *tree_view,
2614                                     GtkTreePath       *path,
2615                                     GtkTreeViewColumn *column,
2616                                     gpointer           user_data)
2617 {
2618         TnyFolderStore *selected;
2619         GtkWidget *dialog;
2620         GtkWidget *folder_view;
2621         gboolean showing_folders;
2622
2623         dialog = (GtkWidget *) user_data;
2624         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2625         if (showing_folders) {
2626                 gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2627         } else {
2628                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2629
2630                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2631                 if (selected) {
2632                         move_to_dialog_show_folders (dialog, selected);
2633                 }
2634         }
2635 }
2636
2637 GtkWidget *
2638 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2639                                        GtkWidget **folder_view)
2640 {
2641         GtkWidget *dialog, *folder_view_container;
2642         GtkWidget *align;
2643         GtkWidget *buttons_hbox;
2644         GtkWidget *back_button, *selection_label;
2645         GdkPixbuf *back_pixbuf;
2646         GtkWidget *top_vbox;
2647         GtkWidget *action_button;
2648
2649         /* Create dialog. We cannot use a touch selector because we
2650            need to use here the folder view widget directly */
2651         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2652                                               GTK_WINDOW (parent_window),
2653                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2654                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2655                                               _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2656                                               NULL);
2657
2658         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2659         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2660         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2661
2662         /* Create folder view */
2663         *folder_view = modest_platform_create_folder_view (NULL);
2664
2665         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2666                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2667         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2668                                                FALSE);
2669         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2670                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2671
2672         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2673         back_button = gtk_button_new ();
2674         back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2675         if (back_pixbuf) {
2676                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2677                 g_object_unref (back_pixbuf);
2678         }
2679         selection_label = gtk_label_new ("");
2680         gtk_misc_set_alignment (GTK_MISC (selection_label), 0.0, 0.5);
2681
2682         action_button = gtk_button_new ();
2683         gtk_container_add (GTK_CONTAINER (action_button), selection_label);
2684
2685         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2686         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2687         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2688         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2689         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2690
2691         /* Create pannable and add it to the dialog */
2692         folder_view_container = hildon_pannable_area_new ();
2693         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2694         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2695
2696         gtk_container_add (GTK_CONTAINER (align), top_vbox);
2697         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2698
2699         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2700
2701         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2702         gtk_widget_show (folder_view_container);
2703         gtk_widget_show (align);
2704         gtk_widget_show (top_vbox);
2705         gtk_widget_show (*folder_view);
2706         gtk_widget_show_all (back_button);
2707         gtk_widget_show (selection_label);
2708         gtk_widget_show (action_button);
2709         gtk_widget_show (buttons_hbox);
2710
2711         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2712         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2713         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2714         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL, selection_label);
2715         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2716
2717         /* Simulate the behaviour of a HildonPickerDialog by emitting
2718            a response when a folder is selected */
2719         g_signal_connect (*folder_view, "row-activated",
2720                           G_CALLBACK (on_move_to_dialog_folder_activated),
2721                           dialog);
2722
2723         g_signal_connect (back_button, "clicked",
2724                           G_CALLBACK (on_move_to_dialog_back_clicked),
2725                           dialog);
2726
2727         move_to_dialog_show_accounts (dialog);
2728
2729         return dialog;
2730 }
2731
2732 TnyList *
2733 modest_platform_get_list_to_move (ModestWindow *window)
2734 {
2735         TnyList *list = NULL;
2736
2737         if (MODEST_IS_HEADER_WINDOW (window)) {
2738                 ModestHeaderView *header_view;
2739
2740                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2741                 list = modest_header_view_get_selected_headers (header_view);
2742         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2743                 ModestFolderView *folder_view;
2744                 TnyFolderStore *selected_folder;
2745
2746                 list = TNY_LIST (tny_simple_list_new ());
2747                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2748                 selected_folder = modest_folder_view_get_selected (folder_view);
2749                 if (selected_folder) {
2750                         tny_list_prepend (list, G_OBJECT (selected_folder));
2751                         g_object_unref (selected_folder);
2752                 }
2753                 return list;
2754         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2755                 TnyHeader *header;
2756
2757                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2758                 if (header) {
2759                         list = TNY_LIST (tny_simple_list_new ());
2760                         tny_list_prepend (list, G_OBJECT (header));
2761                         g_object_unref (header);
2762                 }
2763         } else {
2764                 g_return_val_if_reached (NULL);
2765         }
2766
2767         return list;
2768 }