** Use the new hint "amount" to set into a single notification the number of new...
[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_warning ("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         ModestMsgNotificationData *data;
1575         gint notif_id;
1576         gchar *from;
1577         TnyAccountStore *acc_store;
1578         TnyAccount *account;
1579
1580         data = (ModestMsgNotificationData *) URI_list->data;
1581
1582         /* String is changed in-place. There is no need to
1583            actually dup the data->from string but we just do
1584            it in order not to modify the original contents */
1585         from = g_strdup (data->from);
1586         modest_text_utils_get_display_address (from);
1587
1588         /* Create notification */
1589         notification = hildon_notification_new (from,
1590                                                 data->subject,
1591                                                 "qgn_list_messagin",
1592                                                 MODEST_NOTIFICATION_CATEGORY);
1593         g_free (from);
1594
1595         /* Add DBus action */
1596         hildon_notification_add_dbus_action(notification,
1597                                             "default",
1598                                             "Cancel",
1599                                             MODEST_DBUS_SERVICE,
1600                                             MODEST_DBUS_OBJECT,
1601                                             MODEST_DBUS_IFACE,
1602                                             MODEST_DBUS_METHOD_OPEN_MESSAGE,
1603                                             G_TYPE_STRING, data->uri,
1604                                             -1);
1605
1606         /* Set the led pattern */
1607         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1608                                             "dialog-type", 4);
1609         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1610                                             "led-pattern",
1611                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);
1612
1613         /* Make the notification persistent */
1614         notify_notification_set_hint_byte (NOTIFY_NOTIFICATION (notification),
1615                                            "persistent", TRUE);
1616
1617         /* Set the number of new notifications */
1618         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1619                                             "amount", g_list_length (URI_list));
1620
1621         /* Set the account of the headers */
1622         acc_store = (TnyAccountStore *) modest_runtime_get_account_store ();
1623         account = tny_account_store_find_account (acc_store, data->uri);
1624         if (account) {
1625                 const gchar *acc_name;
1626                 acc_name =
1627                         modest_tny_account_get_parent_modest_account_name_for_server_account (account);
1628                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1629                                                     "email-account",
1630                                                     acc_name);
1631                 g_object_unref (account);
1632         }
1633
1634         /* Play sound */
1635         modest_platform_play_email_tone ();
1636         if (notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1637                 GSList *notifications_list = NULL;
1638
1639                 /* Get previous notifications ids */
1640                 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1641                                                            MODEST_CONF_NOTIFICATION_IDS,
1642                                                            MODEST_CONF_VALUE_INT, NULL);
1643
1644                 /* Save id in the list */
1645                 g_object_get(G_OBJECT (notification), "id", &notif_id, NULL);
1646                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1647
1648                 /* We don't listen for the "closed" signal, because we
1649                    don't care about if the notification was removed or
1650                    not to store the list in gconf */
1651
1652                 /* Save the ids */
1653                 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1654                                       notifications_list, MODEST_CONF_VALUE_INT, NULL);
1655
1656                 g_slist_free (notifications_list);
1657         } else {
1658                 g_warning ("Failed to send notification");
1659         }
1660
1661 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1662 }
1663
1664 void
1665 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1666 {
1667         if (only_visuals) {
1668 #ifdef MODEST_HAVE_MCE
1669                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1670                                      MCE_SERVICE,
1671                                      MCE_REQUEST_PATH,
1672                                      MCE_REQUEST_IF,
1673                                      MCE_DEACTIVATE_LED_PATTERN,
1674                                      NULL,
1675                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1676                                      DBUS_TYPE_INVALID);
1677 #endif
1678                 return;
1679         }
1680
1681 #ifdef MODEST_HAVE_HILDON_NOTIFY
1682         GSList *notif_list = NULL;
1683
1684         /* Get previous notifications ids */
1685         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1686                                            MODEST_CONF_NOTIFICATION_IDS, 
1687                                            MODEST_CONF_VALUE_INT, NULL);
1688
1689         while (notif_list) {
1690                 gint notif_id;
1691                 NotifyNotification *notif;
1692
1693                 /* Nasty HACK to remove the notifications, set the id
1694                    of the existing ones and then close them */
1695                 notif_id = GPOINTER_TO_INT(notif_list->data);
1696                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1697                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1698
1699                 /* Close the notification, note that some ids could be
1700                    already invalid, but we don't care because it does
1701                    not fail */
1702                 notify_notification_close(notif, NULL);
1703                 g_object_unref(notif);
1704
1705                 /* Delete the link, it's like going to the next */
1706                 notif_list = g_slist_delete_link (notif_list, notif_list);
1707         }
1708
1709         /* Save the ids */
1710         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1711                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1712
1713         g_slist_free (notif_list);
1714
1715 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1716 }
1717
1718
1719
1720 GtkWidget * 
1721 modest_platform_get_global_settings_dialog ()
1722 {
1723         return modest_hildon2_global_settings_dialog_new ();
1724 }
1725
1726 void
1727 modest_platform_show_help (GtkWindow *parent_window, 
1728                            const gchar *help_id)
1729 {
1730         return;
1731 }
1732
1733 void 
1734 modest_platform_show_search_messages (GtkWindow *parent_window)
1735 {
1736         osso_return_t result = OSSO_ERROR;
1737         
1738         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1739                                              "osso_global_search",
1740                                              "search_email", NULL, DBUS_TYPE_INVALID);
1741
1742         if (result != OSSO_OK) {
1743                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1744         }
1745 }
1746
1747 void 
1748 modest_platform_show_addressbook (GtkWindow *parent_window)
1749 {
1750         osso_return_t result = OSSO_ERROR;
1751
1752         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1753                                              "osso_addressbook",
1754                                              "top_application", NULL, DBUS_TYPE_INVALID);
1755
1756         if (result != OSSO_OK) {
1757                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1758         }
1759 }
1760
1761 static GtkWidget *
1762 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1763 {
1764         GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1765
1766         /* Show one account by default */
1767         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1768                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1769
1770         /* Restore settings */
1771         modest_widget_memory_restore (modest_runtime_get_conf(), 
1772                                       G_OBJECT (widget),
1773                                       MODEST_CONF_FOLDER_VIEW_KEY);
1774
1775         return widget;
1776 }
1777
1778 GtkWidget *
1779 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1780 {
1781         return modest_platform_create_folder_view_full (query, TRUE);
1782 }
1783
1784 void
1785 banner_finish (gpointer data, GObject *object)
1786 {
1787         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1788         modest_window_mgr_unregister_banner (mgr);
1789         g_object_unref (mgr);
1790 }
1791
1792 void 
1793 modest_platform_information_banner (GtkWidget *parent,
1794                                     const gchar *icon_name,
1795                                     const gchar *text)
1796 {
1797         GtkWidget *banner_parent = NULL;
1798         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1799
1800         if (modest_window_mgr_get_num_windows (mgr) == 0)
1801                 return;
1802
1803         if (parent && GTK_IS_WINDOW (parent)) {
1804                 /* If the window is the active one then show the
1805                    banner on top of this window */
1806                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1807                         banner_parent = parent;
1808                 /* If the window is not the topmost but it's visible
1809                    (it's minimized for example) then show the banner
1810                    with no parent */ 
1811                 else if (GTK_WIDGET_VISIBLE (parent))
1812                         banner_parent = NULL;
1813                 /* If the window is hidden (like the main window when
1814                    running in the background) then do not show
1815                    anything */
1816                 else 
1817                         return;
1818         }
1819
1820         modest_platform_system_banner (banner_parent, icon_name, text);
1821 }
1822
1823 void 
1824 modest_platform_system_banner (GtkWidget *parent,
1825                                const gchar *icon_name,
1826                                const gchar *text)
1827 {
1828         GtkWidget *banner = NULL;
1829         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1830
1831         if (parent && GTK_IS_WINDOW (parent)) {
1832                 if (!gtk_window_is_active (GTK_WINDOW (parent)))
1833                         parent = NULL;
1834         }
1835
1836         banner = hildon_banner_show_information (parent, icon_name, text);
1837
1838         modest_window_mgr_register_banner (mgr);
1839         g_object_ref (mgr);
1840         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1841 }
1842
1843 void
1844 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1845                                                  const gchar *icon_name,
1846                                                  const gchar *text,
1847                                                  gint timeout)
1848 {
1849         GtkWidget *banner;
1850
1851         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1852                 return;
1853
1854         banner = hildon_banner_show_information (parent, icon_name, text);
1855         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1856 }
1857
1858 GtkWidget *
1859 modest_platform_animation_banner (GtkWidget *parent,
1860                                   const gchar *animation_name,
1861                                   const gchar *text)
1862 {
1863         GtkWidget *inf_note = NULL;
1864
1865         g_return_val_if_fail (text != NULL, NULL);
1866
1867         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1868                 return NULL;
1869
1870         /* If the parent is not visible then do not show */
1871         if (parent && !GTK_WIDGET_VISIBLE (parent))
1872                 return NULL;
1873
1874         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1875
1876         return inf_note;
1877 }
1878
1879 typedef struct
1880 {
1881         GMainLoop* loop;
1882         TnyAccount *account;
1883         gboolean is_online;
1884         gint count_tries;
1885 } CheckAccountIdleData;
1886
1887 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1888
1889 static gboolean 
1890 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1891 {
1892         gboolean stop_trying = FALSE;
1893         g_return_val_if_fail (data && data->account, FALSE);
1894         
1895         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1896                 tny_account_get_connection_status (data->account));     
1897         
1898         if (data && data->account && 
1899                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1900                  * after which the account is likely to be usable, or never likely to be usable soon: */
1901                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1902         {
1903                 data->is_online = TRUE;
1904                 
1905                 stop_trying = TRUE;
1906         } else {
1907                 /* Give up if we have tried too many times: */
1908                 if (data->count_tries >= NUMBER_OF_TRIES) {
1909                         stop_trying = TRUE;
1910                 } else {
1911                         /* Wait for another timeout: */
1912                         ++(data->count_tries);
1913                 }
1914         }
1915         
1916         if (stop_trying) {
1917                 /* Allow the function that requested this idle callback to continue: */
1918                 if (data->loop)
1919                         g_main_loop_quit (data->loop);
1920                         
1921                 if (data->account)
1922                         g_object_unref (data->account);
1923                 
1924                 return FALSE; /* Don't call this again. */
1925         } else {
1926                 return TRUE; /* Call this timeout callback again. */
1927         }
1928 }
1929
1930 /* Return TRUE immediately if the account is already online,
1931  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1932  * soon as the account is online, or FALSE if the account does 
1933  * not become online in the NUMBER_OF_TRIES seconds.
1934  * This is useful when the D-Bus method was run immediately after 
1935  * the application was started (when using D-Bus activation), 
1936  * because the account usually takes a short time to go online.
1937  * The return value is maybe not very useful.
1938  */
1939 gboolean
1940 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1941 {
1942         gboolean is_online;
1943
1944         g_return_val_if_fail (account, FALSE);
1945
1946         if (!tny_device_is_online (modest_runtime_get_device())) {
1947                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1948                 return FALSE;
1949         }
1950
1951         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1952          * so we avoid wait unnecessarily: */
1953         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1954                 return TRUE;
1955
1956         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1957          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1958          * we want to avoid. */
1959         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1960                 return TRUE;
1961                 
1962         /* This blocks on the result: */
1963         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1964         data->is_online = FALSE;
1965         data->account = account;
1966         g_object_ref (data->account);
1967         data->count_tries = 0;
1968                 
1969         GMainContext *context = NULL; /* g_main_context_new (); */
1970         data->loop = g_main_loop_new (context, FALSE /* not running */);
1971
1972         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1973
1974         /* This main loop will run until the idle handler has stopped it: */
1975         g_main_loop_run (data->loop);
1976
1977         g_main_loop_unref (data->loop);
1978         /* g_main_context_unref (context); */
1979
1980         is_online = data->is_online;
1981         g_slice_free (CheckAccountIdleData, data);
1982         
1983         return is_online;       
1984 }
1985
1986
1987
1988 static void
1989 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1990 {
1991         /* GTK_RESPONSE_HELP means we need to show the certificate */
1992         if (response_id == GTK_RESPONSE_APPLY) {
1993                 GtkWidget *note;
1994                 gchar *msg;
1995                 
1996                 /* Do not close the dialog */
1997                 g_signal_stop_emission_by_name (dialog, "response");
1998
1999                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
2000                 note = hildon_note_new_information (NULL, msg);
2001                 gtk_dialog_run (GTK_DIALOG(note));
2002                 gtk_widget_destroy (note);
2003         }
2004 }
2005
2006
2007 gboolean
2008 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
2009                                                      const gchar *certificate)
2010 {
2011         GtkWidget *note;
2012         gint response;
2013         ModestWindow *win;
2014         HildonWindowStack *stack;
2015
2016         stack = hildon_window_stack_get_default ();
2017         win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2018
2019         if (!win) {
2020                 g_debug ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2021                          __FUNCTION__);
2022                 return FALSE;
2023         }
2024
2025         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
2026                                            server_name);
2027
2028         /* We use GTK_RESPONSE_APPLY because we want the button in the
2029            middle of OK and CANCEL the same as the browser does for
2030            example. With GTK_RESPONSE_HELP the view button is aligned
2031            to the left while the other two to the right */
2032         note = hildon_note_new_confirmation_add_buttons  (
2033                 NULL,
2034                 question,
2035                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
2036                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
2037                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
2038                 NULL, NULL);
2039
2040         g_signal_connect (G_OBJECT(note), "response", 
2041                           G_CALLBACK(on_cert_dialog_response),
2042                           (gpointer) certificate);
2043
2044         response = gtk_dialog_run(GTK_DIALOG(note));
2045
2046         on_destroy_dialog (note);
2047         g_free (question);
2048
2049         return response == GTK_RESPONSE_OK;
2050 }
2051
2052 gboolean
2053 modest_platform_run_alert_dialog (const gchar* prompt,
2054                                   gboolean is_question)
2055 {
2056         ModestWindow *top_win;
2057         HildonWindowStack *stack;
2058
2059         stack = hildon_window_stack_get_default ();
2060         top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2061
2062         if (!top_win) {
2063                 g_debug ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2064                          __FUNCTION__);
2065                 return FALSE;
2066         }
2067
2068         gboolean retval = TRUE;
2069         if (is_question) {
2070                 /* The Tinymail documentation says that we should show Yes and No buttons,
2071                  * when it is a question.
2072                  * Obviously, we need tinymail to use more specific error codes instead,
2073                  * so we know what buttons to show. */
2074                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win), 
2075                                                                               prompt));
2076                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2077                                              GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2078
2079                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2080                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2081
2082                 on_destroy_dialog (dialog);
2083         } else {
2084                 /* Just show the error text and use the default response: */
2085                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
2086                                                         prompt, FALSE);
2087         }
2088         return retval;
2089 }
2090
2091 /***************/
2092 typedef struct {
2093         GtkWindow *parent_window;
2094         ModestConnectedPerformer callback;
2095         TnyAccount *account;
2096         gpointer user_data;
2097         gchar *iap;
2098         TnyDevice *device;
2099 } OnWentOnlineInfo;
2100  
2101 static void 
2102 on_went_online_info_free (OnWentOnlineInfo *info)
2103 {
2104         /* And if we cleanup, we DO cleanup  :-)  */
2105         
2106         if (info->device)
2107                 g_object_unref (info->device);
2108         if (info->iap)
2109                 g_free (info->iap);
2110         if (info->parent_window)
2111                 g_object_unref (info->parent_window);
2112         if (info->account)
2113                 g_object_unref (info->account);
2114         
2115         g_slice_free (OnWentOnlineInfo, info);
2116         
2117         /* We're done ... */
2118         
2119         return;
2120 }
2121  
2122 static void
2123 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2124 {
2125         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2126  
2127         /* Now it's really time to callback to the caller. If going online didn't succeed,
2128          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2129          * canceled will be set. Etcetera etcetera. */
2130         
2131         if (info->callback) {
2132                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2133         }
2134         
2135         /* This is our last call, we must cleanup here if we didn't yet do that */
2136         on_went_online_info_free (info);
2137         
2138         return;
2139 }
2140  
2141  
2142 static void
2143 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2144 {
2145         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2146         info->iap = g_strdup (iap_id);
2147         
2148         if (canceled || err || !info->account) {
2149         
2150                 /* If there's a problem or if there's no account (then that's it for us, we callback
2151                  * the caller's callback now. He'll have to handle err or canceled, of course.
2152                  * We are not really online, as the account is not really online here ... */    
2153                 
2154                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2155                  * this info. We don't cleanup err, Tinymail does that! */
2156                 
2157                 if (info->callback) {
2158                         
2159                         /* info->account can be NULL here, this means that the user did not
2160                          * provide a nice account instance. We'll assume that the user knows
2161                          * what he's doing and is happy with just the device going online. 
2162                          * 
2163                          * We can't do magic, we don't know what account the user wants to
2164                          * see going online. So just the device goes online, end of story */
2165                         
2166                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2167                 }
2168                 
2169         } else if (info->account) {
2170                 
2171                 /* If there's no problem and if we have an account, we'll put the account
2172                  * online too. When done, the callback of bringing the account online
2173                  * will callback the caller's callback. This is the most normal case. */
2174  
2175                 info->device = TNY_DEVICE (g_object_ref (device));
2176                 
2177                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2178                                               on_account_went_online, info);
2179                 
2180                 /* The on_account_went_online cb frees up the info, go look if you
2181                  * don't believe me! (so we return here) */
2182                 
2183                 return;
2184         }
2185         
2186         /* We cleanup if we are not bringing the account online too */
2187         on_went_online_info_free (info);
2188  
2189         return; 
2190 }
2191         
2192 void 
2193 modest_platform_connect_and_perform (GtkWindow *parent_window, 
2194                                      gboolean force,
2195                                      TnyAccount *account, 
2196                                      ModestConnectedPerformer callback, 
2197                                      gpointer user_data)
2198 {
2199         gboolean device_online;
2200         TnyDevice *device;
2201         TnyConnectionStatus conn_status;
2202         OnWentOnlineInfo *info;
2203         
2204         device = modest_runtime_get_device();
2205         device_online = tny_device_is_online (device);
2206
2207         /* If there is no account check only the device status */
2208         if (!account) {
2209                 
2210                 if (device_online) {
2211  
2212                         /* We promise to instantly perform the callback, so ... */
2213                         if (callback) {
2214                                 callback (FALSE, NULL, parent_window, account, user_data);
2215                         }
2216                         
2217                 } else {
2218                         
2219                         info = g_slice_new0 (OnWentOnlineInfo);
2220                         
2221                         info->iap = NULL;
2222                         info->device = NULL;
2223                         info->account = NULL;
2224                 
2225                         if (parent_window)
2226                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2227                         else
2228                                 info->parent_window = NULL;
2229                         info->user_data = user_data;
2230                         info->callback = callback;
2231                 
2232                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2233                                                               force, on_conic_device_went_online, 
2234                                                               info);
2235  
2236                         /* We'll cleanup in on_conic_device_went_online */
2237                 }
2238  
2239                 /* The other code has no more reason to run. This is all that we can do for the
2240                  * caller (he should have given us a nice and clean account instance!). We
2241                  * can't do magic, we don't know what account he intends to bring online. So
2242                  * we'll just bring the device online (and await his false bug report). */
2243                 
2244                 return;
2245         }
2246  
2247         
2248         /* Return if the account is already connected */
2249         
2250         conn_status = tny_account_get_connection_status (account);
2251         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2252  
2253                 /* We promise to instantly perform the callback, so ... */
2254                 if (callback) {
2255                         callback (FALSE, NULL, parent_window, account, user_data);
2256                 }
2257                 
2258                 return;
2259         }
2260         
2261         /* Else, we are in a state that requires that we go online before we
2262          * call the caller's callback. */
2263         
2264         info = g_slice_new0 (OnWentOnlineInfo);
2265         
2266         info->device = NULL;
2267         info->iap = NULL;
2268         info->account = TNY_ACCOUNT (g_object_ref (account));
2269         
2270         if (parent_window)
2271                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2272         else
2273                 info->parent_window = NULL;
2274         
2275         /* So we'll put the callback away for later ... */
2276         
2277         info->user_data = user_data;
2278         info->callback = callback;
2279         
2280         if (!device_online) {
2281  
2282                 /* If also the device is offline, then we connect both the device 
2283                  * and the account */
2284                 
2285                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2286                                                       force, on_conic_device_went_online, 
2287                                                       info);
2288                 
2289         } else {
2290                 
2291                 /* If the device is online, we'll just connect the account */
2292                 
2293                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2294                                               on_account_went_online, info);
2295         }
2296  
2297         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2298          * in both situations, go look if you don't believe me! */
2299         
2300         return;
2301 }
2302
2303 void
2304 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2305                                                gboolean force,
2306                                                TnyFolderStore *folder_store, 
2307                                                ModestConnectedPerformer callback, 
2308                                                gpointer user_data)
2309 {
2310         TnyAccount *account = NULL;
2311
2312         if (!folder_store ||
2313             (TNY_IS_MERGE_FOLDER (folder_store) &&
2314              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2315
2316                 /* We promise to instantly perform the callback, so ... */
2317                 if (callback) {
2318                         GError *error = NULL;
2319                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2320                                      "Unable to move or not found folder");
2321                         callback (FALSE, error, parent_window, NULL, user_data);
2322                         g_error_free (error);
2323                 }
2324                 return;
2325
2326         } else if (TNY_IS_FOLDER (folder_store)) {
2327                 /* Get the folder's parent account: */
2328                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2329         } else if (TNY_IS_ACCOUNT (folder_store)) {
2330                 /* Use the folder store as an account: */
2331                 account = TNY_ACCOUNT (g_object_ref (folder_store));
2332         }
2333
2334         if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2335                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2336                         /* No need to connect a local account */
2337                         if (callback)
2338                                 callback (FALSE, NULL, parent_window, account, user_data);
2339
2340                         goto clean;
2341                 }
2342         }
2343         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2344
2345  clean:
2346         if (account)
2347                 g_object_unref (account);
2348 }
2349
2350 static void
2351 src_account_connect_performer (gboolean canceled,
2352                                GError *err,
2353                                GtkWindow *parent_window,
2354                                TnyAccount *src_account,
2355                                gpointer user_data)
2356 {
2357         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2358
2359         if (canceled || err) {
2360                 /* If there was any error call the user callback */
2361                 info->callback (canceled, err, parent_window, src_account, info->data);
2362         } else {
2363                 /* Connect the destination account */
2364                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2365                                                                TNY_FOLDER_STORE (info->dst_account),
2366                                                                info->callback, info->data);
2367         }
2368
2369         /* Free the info object */
2370         g_object_unref (info->dst_account);
2371         g_slice_free (DoubleConnectionInfo, info);
2372 }
2373
2374
2375 void 
2376 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2377                                             gboolean force,
2378                                             TnyFolderStore *folder_store,
2379                                             DoubleConnectionInfo *connect_info)
2380 {
2381         modest_platform_connect_if_remote_and_perform(parent_window, 
2382                                                       force,
2383                                                       folder_store, 
2384                                                       src_account_connect_performer, 
2385                                                       connect_info);
2386 }
2387
2388 GtkWidget *
2389 modest_platform_get_account_settings_wizard (void)
2390 {
2391         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2392
2393         return GTK_WIDGET (dialog);
2394 }
2395
2396 ModestConnectedVia
2397 modest_platform_get_current_connection (void)
2398 {
2399         TnyDevice *device = NULL;
2400         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2401         
2402         device = modest_runtime_get_device ();
2403
2404         if (!tny_device_is_online (device))
2405                 return MODEST_CONNECTED_VIA_ANY;
2406
2407 #ifdef MODEST_HAVE_CONIC
2408         /* Get iap id */
2409         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2410         if (iap_id) {
2411                 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2412                         TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2413                 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2414                 if (bearer_type) {
2415                         if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2416                             !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2417                             !strcmp (bearer_type, "WIMAX")) {
2418                                 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2419                         } else {
2420                                 retval = MODEST_CONNECTED_VIA_ANY;
2421                         }
2422                 }       
2423                 g_object_unref (iap);
2424         }
2425 #else
2426         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
2427 #endif /* MODEST_HAVE_CONIC */
2428         return retval;
2429 }
2430
2431
2432
2433 gboolean
2434 modest_platform_check_memory_low (ModestWindow *win,
2435                                   gboolean visuals)
2436 {
2437         gboolean lowmem;
2438         
2439         /* are we in low memory state? */
2440         lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2441         
2442         if (win && lowmem && visuals)
2443                 modest_platform_run_information_dialog (
2444                         GTK_WINDOW(win),
2445                         _KR("memr_ib_operation_disabled"),
2446                         TRUE);
2447
2448         if (lowmem)
2449                 g_debug ("%s: low memory reached. disallowing some operations",
2450                          __FUNCTION__);
2451
2452         return lowmem;
2453 }
2454
2455 void 
2456 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2457                                            TnyFolder *folder)
2458 {
2459         GtkWidget *dialog;
2460         
2461         /* Create dialog */
2462         dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2463
2464         /* Run dialog */
2465         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2466                                      GTK_WINDOW (dialog), 
2467                                      parent_window);
2468         gtk_widget_show_all (dialog);
2469
2470         g_signal_connect_swapped (dialog, "response", 
2471                                   G_CALLBACK (gtk_widget_destroy),
2472                                   dialog);
2473 }
2474
2475 typedef struct _HeaderDetailsGetSizeInfo {
2476         GtkWidget *dialog;
2477         TnyMimePart *part;
2478         guint total;
2479 } HeaderDetailsGetSizeInfo;
2480
2481 static void 
2482 header_details_dialog_destroy (gpointer userdata,
2483                                GObject *object)
2484 {
2485         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2486
2487         info->dialog = NULL;
2488 }
2489
2490 static gboolean
2491 idle_get_mime_part_size_cb (gpointer userdata)
2492 {
2493         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2494         gdk_threads_enter ();
2495
2496         if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
2497                 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
2498                                                         info->total);
2499         }
2500
2501         if (info->dialog) {
2502                 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
2503                 info->dialog = NULL;
2504         }
2505         g_object_unref (info->part);
2506         g_slice_free (HeaderDetailsGetSizeInfo, info);
2507
2508         gdk_threads_leave ();
2509
2510         return FALSE;
2511 }
2512
2513 static gpointer
2514 get_mime_part_size_thread (gpointer thr_user_data)
2515 {
2516         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
2517         gssize result = 0;
2518         TnyStream *count_stream;
2519
2520         count_stream = modest_count_stream_new ();
2521         result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
2522         info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2523         if (info->total == 0) {
2524                 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
2525                 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
2526                 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2527         }
2528         
2529         /* if there was an error, don't set the size (this is pretty uncommon) */
2530         if (result < 0) {
2531                 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
2532         }
2533         g_idle_add (idle_get_mime_part_size_cb, info);
2534
2535         return NULL;
2536 }
2537
2538 void
2539 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2540                                            TnyHeader *header,
2541                                            gboolean async_get_size,
2542                                            TnyMsg *msg)
2543 {
2544         GtkWidget *dialog;
2545
2546         /* Create dialog */
2547         dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header, !async_get_size);
2548
2549         if (async_get_size && msg && TNY_IS_MSG (msg)) {
2550                 HeaderDetailsGetSizeInfo *info;
2551                 info = g_slice_new (HeaderDetailsGetSizeInfo);
2552                 info->dialog = dialog;
2553                 info->total = 0;
2554                 info->part = TNY_MIME_PART (g_object_ref (msg));
2555
2556                 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
2557                 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2558         }
2559
2560         /* Run dialog */
2561         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2562                                      GTK_WINDOW (dialog),
2563                                      parent_window);
2564         gtk_widget_show_all (dialog);
2565
2566         g_signal_connect_swapped (dialog, "response", 
2567                                   G_CALLBACK (gtk_widget_destroy),
2568                                   dialog);
2569 }
2570
2571 osso_context_t *
2572 modest_platform_get_osso_context (void)
2573 {
2574         return modest_maemo_utils_get_osso_context ();
2575 }
2576
2577 static void
2578 modest_platform_play_email_tone (void)
2579 {
2580         gchar *mail_tone;
2581         gint mail_volume_int;
2582         int ret;
2583         ca_context *ca_con = NULL;
2584         ca_proplist *pl = NULL;
2585
2586 #ifdef MODEST_USE_PROFILE
2587         gchar *active_profile;
2588         gchar *mail_volume;
2589
2590         active_profile = profile_get_profile ();
2591         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2592         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2593         mail_volume_int = profile_parse_int (mail_volume);
2594         g_free (mail_volume);
2595         g_free (active_profile);
2596 #else
2597         mail_tone = MAIL_TONE;
2598         mail_volume_int = 100;
2599 #endif
2600
2601         if (mail_tone && !strstr (mail_tone, "/")) {
2602                 gchar *tmp;
2603
2604                 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2605                 g_free (mail_tone);
2606                 mail_tone = tmp;
2607         }
2608
2609         if (mail_volume_int > 0) {
2610
2611                 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2612                         g_warning("ca_context_create: %s\n", ca_strerror(ret));
2613                         return;
2614                 }
2615
2616                 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2617                         g_warning("ca_context_open: %s\n", ca_strerror(ret));
2618                         ca_context_destroy(ca_con);
2619                         return;
2620                 }
2621
2622                 ca_proplist_create(&pl);
2623                 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2624                 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2625
2626                 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2627                 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2628
2629                 ca_proplist_destroy(pl);
2630                 ca_context_destroy(ca_con);
2631         }
2632
2633         g_free (mail_tone);
2634 }
2635
2636 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2637 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2638 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2639 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2640 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2641 #define MOVE_TO_FOLDER_SEPARATOR "/"
2642
2643 static void
2644 translate_path (gchar **path)
2645 {
2646         gchar **parts;
2647         gchar **current;
2648         GString *output;
2649         gboolean add_separator;
2650
2651         parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
2652         g_free (*path);
2653
2654         current = parts;
2655         output = g_string_new ("");
2656         add_separator = FALSE;
2657
2658         while (*current != NULL) {
2659                 TnyFolderType folder_type;
2660                 gchar *downcase;
2661
2662                 if (add_separator) {
2663                         output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
2664                 } else {
2665                         add_separator = TRUE;
2666                 }
2667
2668                 downcase = g_ascii_strdown (*current, -1);
2669                 folder_type = modest_local_folder_info_get_type (downcase);
2670                 if (strcmp (downcase, "inbox") == 0) {
2671                         output = g_string_append (output, _("mcen_me_folder_inbox"));
2672                 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
2673                     folder_type == TNY_FOLDER_TYPE_DRAFTS ||
2674                     folder_type == TNY_FOLDER_TYPE_SENT ||
2675                     folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2676                         output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
2677                 } else {
2678                         output = g_string_append (output, *current);
2679                 }
2680                 g_free (downcase);
2681
2682                 current++;
2683         }
2684
2685         g_strfreev (parts);
2686         *path = g_string_free (output, FALSE);
2687 }
2688
2689 static void
2690 move_to_dialog_set_selected_folder_store (GtkWidget *dialog, 
2691                                           TnyFolderStore *folder_store)
2692 {
2693         GtkWidget *action_button;
2694         GtkWidget *image = NULL;
2695         TnyAccount *account;
2696         gchar *account_name = NULL, *short_name = NULL;
2697
2698         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2699
2700         /* Get account name */
2701         if (TNY_IS_FOLDER (folder_store))
2702                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2703         else
2704                 account = g_object_ref (folder_store);
2705
2706         if (modest_tny_account_is_virtual_local_folders (account))
2707                 account_name = modest_conf_get_string (modest_runtime_get_conf(),
2708                                                        MODEST_CONF_DEVICE_NAME, NULL);
2709
2710         if (!account_name)
2711                 account_name = g_strdup (tny_account_get_name (account));
2712
2713         g_object_unref (account);
2714
2715         /* Set title of button: account or folder name */
2716         if (TNY_IS_FOLDER (folder_store))
2717                 short_name = folder_store_get_display_name (folder_store);
2718         else
2719                 short_name = g_strdup (account_name);
2720
2721         hildon_button_set_title (HILDON_BUTTON (action_button), short_name);
2722
2723         /* Set value of button, folder full name */
2724         if (TNY_IS_CAMEL_FOLDER (folder_store)) {
2725                 const gchar *camel_full_name;
2726                 gchar *last_slash, *full_name;
2727
2728                 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
2729                 last_slash = g_strrstr (camel_full_name, "/");
2730                 if (last_slash) {
2731                         gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
2732                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
2733                         g_free (prefix);
2734                 } else {
2735                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
2736                                                  short_name,
2737                                                  NULL);
2738                 }
2739                 translate_path (&full_name);
2740                 hildon_button_set_value (HILDON_BUTTON (action_button), full_name);
2741                 g_free (full_name);
2742         }
2743         g_free (account_name);
2744         g_free (short_name);
2745
2746         /* Set image for the button */
2747         image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
2748         if (image)
2749                 hildon_button_set_image (HILDON_BUTTON (action_button), image);
2750 }
2751
2752 static void
2753 move_to_dialog_show_accounts (GtkWidget *dialog)
2754 {
2755         GtkWidget *back_button;
2756         GtkWidget *folder_view;
2757         GtkWidget *pannable;
2758         GtkWidget *action_button;
2759
2760         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2761         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2762         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2763         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2764
2765         gtk_widget_set_sensitive (back_button, FALSE);
2766         gtk_widget_set_sensitive (action_button, FALSE);
2767
2768         /* Need to set this here, otherwise callbacks called because
2769            of filtering won't perform correctly */
2770         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2771
2772         /* Reset action button */
2773         hildon_button_set_title (HILDON_BUTTON (action_button), NULL);
2774         hildon_button_set_value (HILDON_BUTTON (action_button), NULL);
2775         hildon_button_set_image (HILDON_BUTTON (action_button), NULL);
2776
2777         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
2778         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2779         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2780         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2781                                          MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2782         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2783                                        MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2784         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), 
2785                                          MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2786         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), 
2787                                        MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2788         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2789 }
2790
2791 static void
2792 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2793 {
2794         GtkWidget *back_button;
2795         GtkWidget *folder_view;
2796         TnyAccount *account;
2797         const gchar *account_id;
2798         GtkWidget *pannable;
2799         GtkWidget *action_button;
2800
2801         back_button =
2802                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2803         action_button =
2804                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2805         folder_view =
2806                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2807         pannable =
2808                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2809
2810         gtk_widget_set_sensitive (back_button, TRUE);
2811         gtk_widget_set_sensitive (action_button, TRUE);
2812
2813         /* Need to set this here, otherwise callbacks called because
2814            of filtering won't perform correctly */
2815         g_object_set_data (G_OBJECT (dialog),
2816                            MOVE_TO_DIALOG_SHOWING_FOLDERS,
2817                            GINT_TO_POINTER (TRUE));
2818
2819         account = TNY_ACCOUNT (folder_store);
2820         if (modest_tny_account_is_virtual_local_folders (account)) {
2821                 account_id = tny_account_get_id (account);
2822                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2823                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2824         } else if (modest_tny_account_is_memory_card_account (account)) {
2825                 account_id = tny_account_get_id (account);
2826                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2827                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2828         } else {
2829                 account_id = tny_account_get_id (account);
2830                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2831                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2832                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2833                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2834         }
2835
2836         move_to_dialog_set_selected_folder_store (dialog, folder_store);
2837         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2838                                                                      account_id);
2839
2840         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2841         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2842         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2843         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2844         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2845 }
2846
2847 static void
2848 on_move_to_dialog_back_clicked (GtkButton *button,
2849                                 gpointer userdata)
2850 {
2851         GtkWidget *dialog = (GtkWidget *) userdata;
2852
2853         /* Back to show accounts */
2854         move_to_dialog_show_accounts (dialog);
2855 }
2856
2857 static void
2858 on_move_to_dialog_row_activated (GtkTreeView       *tree_view,
2859                                     GtkTreePath       *path,
2860                                     GtkTreeViewColumn *column,
2861                                     gpointer           user_data)
2862 {
2863         TnyFolderStore *selected = NULL;
2864         GtkWidget *dialog;
2865         GtkWidget *folder_view;
2866         gboolean showing_folders;
2867
2868         dialog = (GtkWidget *) user_data;
2869         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), 
2870                                                               MOVE_TO_DIALOG_SHOWING_FOLDERS));
2871
2872         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), 
2873                                                      MOVE_TO_DIALOG_FOLDER_VIEW));
2874
2875         selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2876         if (!selected)
2877                 return;
2878
2879         if (!showing_folders) {
2880                 gboolean valid = TRUE;
2881
2882                 if (TNY_IS_ACCOUNT (selected) &&
2883                     modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2884                         ModestProtocolType protocol_type;
2885
2886                         protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2887                         valid  = !modest_protocol_registry_protocol_type_has_tag 
2888                                 (modest_runtime_get_protocol_registry (),
2889                                  protocol_type,
2890                                  MODEST_PROTOCOL_REGISTRY_STORE_FORBID_MESSAGE_ADD);
2891                 }
2892                 if (valid)
2893                         move_to_dialog_show_folders (dialog, selected);
2894         } else {
2895                 move_to_dialog_set_selected_folder_store (dialog, selected);
2896         }
2897 }
2898
2899 static void
2900 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2901                                      gpointer          user_data)
2902 {
2903         gboolean showing_folders;
2904         GtkWidget *dialog;
2905
2906         dialog = (GtkWidget *) user_data;
2907         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2908         if (showing_folders) {
2909                 TnyFolderStore *selected;
2910                 GtkWidget *folder_view;
2911
2912                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2913                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2914
2915                 if (selected) {
2916                         move_to_dialog_set_selected_folder_store (dialog, selected);
2917                         g_object_unref (selected);
2918                 }
2919         }
2920 }
2921
2922 static void
2923 on_move_to_dialog_action_clicked (GtkButton *selection,
2924                                   gpointer   user_data)
2925 {
2926         GtkWidget *dialog;
2927         gboolean showing_folders;
2928
2929         dialog = (GtkWidget *) user_data;
2930         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2931         if (showing_folders) {
2932                 TnyFolderStore *selected;
2933                 GtkWidget *folder_view;
2934
2935                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2936                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2937
2938                 if (selected) {
2939                         gtk_dialog_response  (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2940                         g_object_unref (selected);
2941                 }
2942         }
2943 }
2944
2945 static void
2946 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2947 {
2948         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (dialog), activity?1:0);
2949 }
2950
2951 GtkWidget *
2952 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2953                                        GtkWidget **folder_view)
2954 {
2955         GtkWidget *dialog, *folder_view_container;
2956         GtkWidget *align;
2957         GtkWidget *buttons_hbox;
2958         GtkWidget *back_button;
2959         GdkPixbuf *back_pixbuf;
2960         GtkWidget *top_vbox;
2961         GtkWidget *action_button;
2962         GtkTreeSelection *selection;
2963
2964         /* Create dialog. We cannot use a touch selector because we
2965            need to use here the folder view widget directly */
2966         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2967                                               GTK_WINDOW (parent_window),
2968                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2969                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2970                                               _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2971                                               NULL);
2972
2973         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2974         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2975         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2976
2977         /* Create folder view */
2978         *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2979         g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2980                           dialog);
2981
2982         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2983                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2984         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2985                                                FALSE);
2986         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2987                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2988
2989         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2990         back_button = gtk_button_new ();
2991         back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2992         if (back_pixbuf) {
2993                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2994                 g_object_unref (back_pixbuf);
2995         }
2996
2997         action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
2998                                            HILDON_BUTTON_ARRANGEMENT_VERTICAL);
2999         gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
3000
3001         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
3002         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
3003         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
3004         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
3005         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
3006
3007         /* Create pannable and add it to the dialog */
3008         folder_view_container = hildon_pannable_area_new ();
3009         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
3010         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
3011
3012         gtk_container_add (GTK_CONTAINER (align), top_vbox);
3013         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
3014
3015         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
3016
3017         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
3018         gtk_widget_show (folder_view_container);
3019         gtk_widget_show (align);
3020         gtk_widget_show (top_vbox);
3021         gtk_widget_show (*folder_view);
3022         gtk_widget_show_all (back_button);
3023         gtk_widget_show (action_button);
3024         gtk_widget_show (buttons_hbox);
3025         gtk_widget_show (dialog);
3026
3027         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
3028         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
3029         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
3030         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
3031
3032         /* Simulate the behaviour of a HildonPickerDialog by emitting
3033            a response when a folder is selected */
3034         g_signal_connect (*folder_view, "row-activated",
3035                           G_CALLBACK (on_move_to_dialog_row_activated),
3036                           dialog);
3037
3038         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
3039         g_signal_connect (selection, "changed",
3040                           G_CALLBACK (on_move_to_dialog_selection_changed),
3041                           dialog);
3042
3043         g_signal_connect (action_button, "clicked",
3044                           G_CALLBACK (on_move_to_dialog_action_clicked),
3045                           dialog);
3046
3047         g_signal_connect (back_button, "clicked",
3048                           G_CALLBACK (on_move_to_dialog_back_clicked),
3049                           dialog);
3050
3051         move_to_dialog_show_accounts (dialog);
3052
3053         return dialog;
3054 }
3055
3056 TnyList *
3057 modest_platform_get_list_to_move (ModestWindow *window)
3058 {
3059         TnyList *list = NULL;
3060
3061         if (MODEST_IS_HEADER_WINDOW (window)) {
3062                 ModestHeaderView *header_view;
3063
3064                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
3065                 list = modest_header_view_get_selected_headers (header_view);
3066         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
3067                 ModestFolderView *folder_view;
3068                 TnyFolderStore *selected_folder;
3069
3070                 list = TNY_LIST (tny_simple_list_new ());
3071                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
3072                 selected_folder = modest_folder_view_get_selected (folder_view);
3073                 if (selected_folder) {
3074                         tny_list_prepend (list, G_OBJECT (selected_folder));
3075                         g_object_unref (selected_folder);
3076                 }
3077                 return list;
3078         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3079                 TnyHeader *header;
3080
3081                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
3082                 if (header) {
3083                         list = TNY_LIST (tny_simple_list_new ());
3084                         tny_list_prepend (list, G_OBJECT (header));
3085                         g_object_unref (header);
3086                 }
3087         } else {
3088                 g_return_val_if_reached (NULL);
3089         }
3090
3091         return list;
3092 }