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