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