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