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