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