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