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