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