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