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