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