1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
31 #include <glib/gi18n.h>
32 #include <modest-platform.h>
33 #include <modest-runtime.h>
34 #include <modest-main-window.h>
35 #include <modest-header-view.h>
36 #include "modest-hildon2-global-settings-dialog.h"
37 #include "modest-widget-memory.h"
38 #include <modest-hildon-includes.h>
39 #include <modest-maemo-utils.h>
40 #include <dbus_api/modest-dbus-callbacks.h>
41 #include <modest-osso-autosave-callbacks.h>
43 #include <tny-maemo-conic-device.h>
44 #include <tny-simple-list.h>
45 #include <tny-folder.h>
46 #include <gtk/gtkicontheme.h>
47 #include <gtk/gtkmenuitem.h>
48 #include <gtk/gtkmain.h>
49 #include <modest-text-utils.h>
50 #include "modest-tny-folder.h"
51 #include "modest-tny-account.h"
53 #include <libgnomevfs/gnome-vfs-mime-utils.h>
54 #include <modest-account-settings-dialog.h>
55 #include <modest-easysetup-wizard-dialog.h>
56 #include "modest-hildon2-sort-dialog.h"
57 #include <hildon/hildon-sound.h>
59 #include "hildon2/modest-hildon2-details-dialog.h"
60 #include "hildon2/modest-hildon2-window-mgr.h"
61 #include <keys_nokia.h>
62 #include <libprofile.h>
64 #include <modest-datetime-formatter.h>
65 #include "modest-header-window.h"
66 #include <modest-folder-window.h>
67 #include <modest-account-mgr.h>
68 #include <modest-account-mgr-helpers.h>
69 #include <modest-ui-constants.h>
70 #include <modest-selector-picker.h>
71 #include <modest-icon-names.h>
73 #ifdef MODEST_HAVE_MCE
74 #include <mce/dbus-names.h>
75 #endif /*MODEST_HAVE_MCE*/
77 #ifdef MODEST_HAVE_ABOOK
78 #include <libosso-abook/osso-abook.h>
79 #endif /*MODEST_HAVE_ABOOK*/
81 #ifdef MODEST_HAVE_LIBALARM
82 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
83 #endif /*MODEST_HAVE_LIBALARM*/
86 #define HILDON_OSSO_URI_ACTION "uri-action"
87 #define URI_ACTION_COPY "copy:"
88 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
89 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
90 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
92 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
93 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
95 static void _modest_platform_play_email_tone (void);
99 on_modest_conf_update_interval_changed (ModestConf* self,
101 ModestConfEvent event,
102 ModestConfNotificationId id,
105 g_return_if_fail (key);
107 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
108 const guint update_interval_minutes =
109 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
110 modest_platform_set_update_interval (update_interval_minutes);
117 check_required_files (void)
119 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
121 g_printerr ("modest: check for mcc file failed\n");
126 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
127 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
128 g_printerr ("modest: cannot find providers data\n");
136 /* the gpointer here is the osso_context. */
138 modest_platform_init (int argc, char *argv[])
140 osso_context_t *osso_context;
142 osso_hw_state_t hw_state = { 0 };
146 if (!check_required_files ()) {
147 g_printerr ("modest: missing required files\n");
151 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
154 g_printerr ("modest: failed to acquire osso context\n");
157 modest_maemo_utils_set_osso_context (osso_context);
159 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
160 g_printerr ("modest: could not get dbus connection\n");
164 /* Add a D-Bus handler to be used when the main osso-rpc
165 * D-Bus handler has not handled something.
166 * We use this for D-Bus methods that need to use more complex types
167 * than osso-rpc supports.
169 if (!dbus_connection_add_filter (con,
170 modest_dbus_req_filter,
174 g_printerr ("modest: Could not add D-Bus filter\n");
178 /* Register our simple D-Bus callbacks, via the osso API: */
179 osso_return_t result = osso_rpc_set_cb_f(osso_context,
183 modest_dbus_req_handler, NULL /* user_data */);
184 if (result != OSSO_OK) {
185 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
189 /* Register hardware event dbus callback: */
190 hw_state.shutdown_ind = TRUE;
191 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
193 /* Register osso auto-save callbacks: */
194 result = osso_application_set_autosave_cb (osso_context,
195 modest_on_osso_application_autosave, NULL /* user_data */);
196 if (result != OSSO_OK) {
197 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
202 /* Make sure that the update interval is changed whenever its gconf key
204 /* CAUTION: we're not using here the
205 modest_conf_listen_to_namespace because we know that there
206 are other parts of Modest listening for this namespace, so
207 we'll receive the notifications anyway. We basically do not
208 use it because there is no easy way to do the
209 modest_conf_forget_namespace */
210 ModestConf *conf = modest_runtime_get_conf ();
211 g_signal_connect (G_OBJECT(conf),
213 G_CALLBACK (on_modest_conf_update_interval_changed),
216 /* only force the setting of the default interval, if there are actually
218 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
220 /* Get the initial update interval from gconf: */
221 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
222 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
223 modest_account_mgr_free_account_names (acc_names);
227 #ifdef MODEST_HAVE_ABOOK
228 /* initialize the addressbook */
229 if (!osso_abook_init (&argc, &argv, osso_context)) {
230 g_printerr ("modest: failed to initialized addressbook\n");
233 #endif /*MODEST_HAVE_ABOOK*/
239 modest_platform_uninit (void)
241 osso_context_t *osso_context =
242 modest_maemo_utils_get_osso_context ();
244 osso_deinitialize (osso_context);
253 modest_platform_get_new_device (void)
255 return TNY_DEVICE (tny_maemo_conic_device_new ());
259 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
260 gchar **effective_mime_type)
262 GString *mime_str = NULL;
263 gchar *icon_name = NULL;
264 gchar **icons, **cursor;
266 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
267 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
269 mime_str = g_string_new (mime_type);
270 g_string_ascii_down (mime_str);
273 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
275 for (cursor = icons; cursor; ++cursor) {
276 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
277 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
278 icon_name = g_strdup ("qgn_list_messagin");
280 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
281 icon_name = g_strdup (*cursor);
287 if (effective_mime_type)
288 *effective_mime_type = g_string_free (mime_str, FALSE);
290 g_string_free (mime_str, TRUE);
297 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
302 g_return_val_if_fail (uri, FALSE);
304 result = hildon_uri_open (uri, action, &err);
306 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
307 uri, action, err && err->message ? err->message : "unknown error");
317 modest_platform_activate_uri (const gchar *uri)
319 HildonURIAction *action;
320 gboolean result = FALSE;
321 GSList *actions, *iter = NULL;
323 g_return_val_if_fail (uri, FALSE);
327 /* don't try to activate file: uri's -- they might confuse the user,
328 * and/or might have security implications */
329 if (!g_str_has_prefix (uri, "file:")) {
331 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
333 for (iter = actions; iter; iter = g_slist_next (iter)) {
334 action = (HildonURIAction*) iter->data;
335 if (action && strcmp (hildon_uri_action_get_service (action),
336 "com.nokia.modest") == 0) {
337 result = checked_hildon_uri_open (uri, action);
342 /* if we could not open it with email, try something else */
344 result = checked_hildon_uri_open (uri, NULL);
348 ModestWindow *parent =
349 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
350 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
351 _("mcen_ib_unsupported_link"));
352 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
359 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
363 gchar *uri_path = NULL;
365 uri_path = gnome_vfs_get_uri_from_local_path (path);
366 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
369 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
371 result = hildon_mime_open_file (con, uri_path);
373 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
381 } ModestPlatformPopupInfo;
384 delete_uri_popup (GtkWidget *menu,
388 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
390 g_free (popup_info->uri);
391 hildon_uri_free_actions (popup_info->actions);
397 activate_uri_popup_item (GtkMenuItem *menu_item,
401 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
402 const gchar* action_name;
404 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
406 g_printerr ("modest: no action name defined\n");
410 /* special handling for the copy menu item -- copy the uri to the clipboard */
411 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
412 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
413 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
414 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
416 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
417 action_name += strlen ("mailto:");
419 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
420 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
421 return; /* we're done */
424 /* now, the real uri-actions... */
425 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
426 HildonURIAction *action = (HildonURIAction *) node->data;
427 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
428 if (!checked_hildon_uri_open (popup_info->uri, action)) {
429 ModestWindow *parent =
430 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
431 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
432 _("mcen_ib_unsupported_link"));
440 modest_platform_show_uri_popup (const gchar *uri)
442 GSList *actions_list;
447 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
450 GtkWidget *menu = gtk_menu_new ();
451 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
453 /* don't add actions for file: uri's -- they might confuse the user,
454 * and/or might have security implications
455 * we still allow to copy the url though
457 if (!g_str_has_prefix (uri, "file:")) {
460 popup_info->actions = actions_list;
461 popup_info->uri = g_strdup (uri);
463 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
464 GtkWidget *menu_item;
465 const gchar *action_name;
466 const gchar *translation_domain;
467 HildonURIAction *action = (HildonURIAction *) node->data;
468 action_name = hildon_uri_action_get_name (action);
469 translation_domain = hildon_uri_action_get_translation_domain (action);
470 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
471 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
472 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
475 if (hildon_uri_is_default_action (action, NULL)) {
476 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
478 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
480 gtk_widget_show (menu_item);
484 /* always add the copy item */
485 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
486 "uri_link_copy_link_location"));
487 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
488 g_strconcat (URI_ACTION_COPY, uri, NULL),
490 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
491 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
492 gtk_widget_show (menu_item);
495 /* and what to do when the link is deleted */
496 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
497 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
500 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
508 modest_platform_get_icon (const gchar *name, guint icon_size)
511 GdkPixbuf* pixbuf = NULL;
512 GtkIconTheme *current_theme = NULL;
514 g_return_val_if_fail (name, NULL);
516 /* strlen == 0 is not really an error; it just
517 * means the icon is not available
519 if (!name || strlen(name) == 0)
522 current_theme = gtk_icon_theme_get_default ();
523 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
524 GTK_ICON_LOOKUP_NO_SVG,
527 g_printerr ("modest: error loading theme icon '%s': %s\n",
535 modest_platform_get_app_name (void)
537 return _("mcen_ap_name");
541 entry_insert_text (GtkEditable *editable,
550 chars = gtk_editable_get_chars (editable, 0, -1);
551 chars_length = g_utf8_strlen (chars, -1);
554 /* Show WID-INF036 */
555 if (chars_length >= 20) {
556 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
557 _CS("ckdg_ib_maximum_characters_reached"));
559 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
563 tmp = g_strndup (folder_name_forbidden_chars,
564 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
565 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
566 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
571 /* Write the text in the entry if it's valid */
572 g_signal_handlers_block_by_func (editable,
573 (gpointer) entry_insert_text, data);
574 gtk_editable_insert_text (editable, text, length, position);
575 g_signal_handlers_unblock_by_func (editable,
576 (gpointer) entry_insert_text, data);
579 /* Do not allow further processing */
580 g_signal_stop_emission_by_name (editable, "insert_text");
584 entry_changed (GtkEditable *editable,
588 GtkWidget *ok_button;
591 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
592 ok_button = GTK_WIDGET (buttons->data);
594 chars = gtk_editable_get_chars (editable, 0, -1);
595 g_return_if_fail (chars != NULL);
598 if (g_utf8_strlen (chars,-1) >= 20)
599 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
600 _CS("ckdg_ib_maximum_characters_reached"));
602 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
605 g_list_free (buttons);
612 on_response (GtkDialog *dialog,
616 GtkWidget *entry, *picker;
617 TnyFolderStore *parent;
618 const gchar *new_name;
621 if (response != GTK_RESPONSE_ACCEPT)
625 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
626 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
628 parent = TNY_FOLDER_STORE (user_data);
629 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
632 if (picker != NULL) {
633 const gchar *active_id;
635 active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (picker));
636 parent = TNY_FOLDER_STORE (
637 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
639 TNY_ACCOUNT_TYPE_STORE));
641 g_object_ref (parent);
643 /* Look for another folder with the same name */
644 if (modest_tny_folder_has_subfolder_with_name (parent,
651 if (TNY_IS_ACCOUNT (parent) &&
652 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
653 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
662 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
663 NULL, _CS("ckdg_ib_folder_already_exists"));
664 /* Select the text */
665 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
666 gtk_widget_grab_focus (entry);
667 /* Do not close the dialog */
668 g_signal_stop_emission_by_name (dialog, "response");
671 g_object_unref (parent);
674 typedef struct _FolderChooserData {
675 TnyFolderStore *store;
680 folder_chooser_activated (ModestFolderView *folder_view,
681 TnyFolderStore *folder,
682 FolderChooserData *userdata)
684 userdata->store = folder;
685 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
688 static TnyFolderStore *
689 folder_chooser_dialog_run (ModestFolderView *original)
691 GtkWidget *folder_view;
692 FolderChooserData userdata = {NULL, NULL};
694 const gchar *visible_id = NULL;
696 userdata.dialog = hildon_dialog_new ();
697 pannable = hildon_pannable_area_new ();
698 folder_view = modest_platform_create_folder_view (NULL);
700 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original), MODEST_FOLDER_VIEW (folder_view));
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),
707 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
708 gtk_container_add (GTK_CONTAINER (pannable), folder_view);
709 gtk_widget_show (folder_view);
710 gtk_widget_show (pannable);
711 gtk_widget_show_all (userdata.dialog);
712 gtk_widget_set_size_request (pannable, -1, 320);
713 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
714 G_CALLBACK (folder_chooser_activated),
715 (gpointer) &userdata);
717 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
718 gtk_widget_destroy (userdata.dialog);
720 return userdata.store;
723 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
726 folder_store_get_display_name (TnyFolderStore *store)
728 if (TNY_IS_ACCOUNT (store)) {
729 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
732 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
734 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
735 type = tny_folder_get_folder_type (TNY_FOLDER (store));
736 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
737 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
738 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
739 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
741 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
744 /* Sometimes an special folder is reported by the server as
745 NORMAL, like some versions of Dovecot */
746 if (type == TNY_FOLDER_TYPE_NORMAL ||
747 type == TNY_FOLDER_TYPE_UNKNOWN) {
748 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
752 if (type == TNY_FOLDER_TYPE_INBOX) {
754 fname = g_strdup (_("mcen_me_folder_inbox"));
761 folder_picker_clicked (GtkButton *button,
762 ModestFolderView *folder_view)
764 TnyFolderStore *store;
766 store = folder_chooser_dialog_run (folder_view);
769 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, store);
770 name = folder_store_get_display_name (store);
771 hildon_button_set_value (HILDON_BUTTON (button), name);
777 folder_picker_new (ModestFolderView *folder_view)
782 button = hildon_button_new (MODEST_EDITABLE_SIZE,
783 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
784 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL,
785 MODEST_ICON_SIZE_SMALL);
787 hildon_button_set_image (HILDON_BUTTON (button),
788 gtk_image_new_from_pixbuf (pixbuf));
789 hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
791 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (folder_picker_clicked), folder_view);
798 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
799 TnyFolderStore *suggested_parent,
800 const gchar *dialog_title,
801 const gchar *label_text,
802 const gchar *suggested_name,
804 gboolean show_parent,
806 TnyFolderStore **parent)
808 GtkWidget *accept_btn = NULL;
809 GtkWidget *dialog, *entry, *label_entry, *label_location, *hbox;
810 GtkWidget *account_picker;
811 GList *buttons = NULL;
813 GtkSizeGroup *sizegroup;
814 ModestFolderView *folder_view;
816 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (parent_window), GTK_RESPONSE_NONE);
818 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (parent_window));
820 /* Ask the user for the folder name */
821 dialog = gtk_dialog_new_with_buttons (dialog_title,
823 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
824 _FM("ckdg_bd_new_folder_dialog_ok"),
828 /* Add accept button (with unsensitive handler) */
829 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
830 accept_btn = GTK_WIDGET (buttons->data);
832 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
835 label_entry = gtk_label_new (label_text);
836 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
837 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
839 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
840 gtk_size_group_add_widget (sizegroup, label_entry);
843 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
845 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
846 gtk_entry_set_width_chars (GTK_ENTRY (entry),
847 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
848 g_utf8_strlen (_("mcen_ia_default_folder_name"), -1)));
849 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
854 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
856 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
857 gtk_size_group_add_widget (sizegroup, label_location);
859 account_picker = folder_picker_new (folder_view);
862 g_object_unref (sizegroup);
864 /* Connect to the response method to avoid closing the dialog
865 when an invalid name is selected*/
866 g_signal_connect (dialog,
868 G_CALLBACK (on_response),
872 /* Track entry changes */
873 g_signal_connect (entry,
875 G_CALLBACK (entry_insert_text),
877 g_signal_connect (entry,
879 G_CALLBACK (entry_changed),
884 /* Some locales like pt_BR need this to get the full window
886 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
888 /* Create the hbox */
890 hbox = gtk_hbox_new (FALSE, 12);
891 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
892 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
894 /* Add hbox to dialog */
895 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
896 hbox, FALSE, FALSE, 0);
897 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
901 hbox = gtk_hbox_new (FALSE, 12);
902 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
903 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
905 /* Add hbox to dialog */
906 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
907 hbox, FALSE, FALSE, 0);
908 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
910 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
911 GTK_WINDOW (dialog), parent_window);
912 gtk_widget_show_all (GTK_WIDGET(dialog));
914 result = gtk_dialog_run (GTK_DIALOG(dialog));
915 if (result == GTK_RESPONSE_ACCEPT) {
917 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
919 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
923 gtk_widget_destroy (dialog);
925 while (gtk_events_pending ())
926 gtk_main_iteration ();
932 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
933 TnyFolderStore *suggested_folder,
934 gchar *suggested_name,
936 TnyFolderStore **parent_folder)
938 gchar *real_suggested_name = NULL, *tmp = NULL;
941 if(suggested_name == NULL)
943 const gchar *default_name = _("mcen_ia_default_folder_name");
947 for(i = 0; i < 100; ++ i) {
948 gboolean exists = FALSE;
950 sprintf(num_str, "%.2u", i);
953 real_suggested_name = g_strdup (default_name);
955 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
957 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
964 g_free (real_suggested_name);
967 /* Didn't find a free number */
969 real_suggested_name = g_strdup (default_name);
971 real_suggested_name = suggested_name;
974 tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
975 result = modest_platform_run_folder_common_dialog (parent_window,
977 _("mcen_ti_new_folder"),
986 if (suggested_name == NULL)
987 g_free(real_suggested_name);
993 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
994 TnyFolderStore *parent_folder,
995 const gchar *suggested_name,
998 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1000 return modest_platform_run_folder_common_dialog (parent_window,
1002 _HL("ckdg_ti_rename_folder"),
1003 _HL("ckdg_fi_rename_name"),
1014 on_destroy_dialog (GtkWidget *dialog)
1016 /* This could happen when the dialogs get programatically
1017 hidden or destroyed (for example when closing the
1018 application while a dialog is being shown) */
1019 if (!GTK_IS_WIDGET (dialog))
1022 gtk_widget_destroy (dialog);
1024 if (gtk_events_pending ())
1025 gtk_main_iteration ();
1029 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1030 const gchar *message)
1035 dialog = hildon_note_new_confirmation (parent_window, message);
1036 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1037 GTK_WINDOW (dialog), parent_window);
1039 response = gtk_dialog_run (GTK_DIALOG (dialog));
1041 on_destroy_dialog (dialog);
1047 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1048 const gchar *message,
1049 const gchar *button_accept,
1050 const gchar *button_cancel)
1055 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1056 button_accept, GTK_RESPONSE_ACCEPT,
1057 button_cancel, GTK_RESPONSE_CANCEL,
1060 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1061 GTK_WINDOW (dialog), parent_window);
1063 response = gtk_dialog_run (GTK_DIALOG (dialog));
1065 on_destroy_dialog (dialog);
1071 modest_platform_run_information_dialog (GtkWindow *parent_window,
1072 const gchar *message,
1077 note = hildon_note_new_information (parent_window, message);
1079 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1080 GTK_WINDOW (note), parent_window);
1083 gtk_dialog_run (GTK_DIALOG (note));
1085 on_destroy_dialog (note);
1087 g_signal_connect_swapped (note,
1089 G_CALLBACK (on_destroy_dialog),
1092 gtk_widget_show_all (note);
1096 typedef struct _ConnectAndWaitData {
1098 GMainLoop *wait_loop;
1099 gboolean has_callback;
1101 } ConnectAndWaitData;
1105 quit_wait_loop (TnyAccount *account,
1106 ConnectAndWaitData *data)
1108 /* Set the has_callback to TRUE (means that the callback was
1109 executed and wake up every code waiting for cond to be
1111 g_mutex_lock (data->mutex);
1112 data->has_callback = TRUE;
1113 if (data->wait_loop)
1114 g_main_loop_quit (data->wait_loop);
1115 g_mutex_unlock (data->mutex);
1119 on_connection_status_changed (TnyAccount *account,
1120 TnyConnectionStatus status,
1123 TnyConnectionStatus conn_status;
1124 ConnectAndWaitData *data;
1126 /* Ignore if reconnecting or disconnected */
1127 conn_status = tny_account_get_connection_status (account);
1128 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1129 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1132 /* Remove the handler */
1133 data = (ConnectAndWaitData *) user_data;
1134 g_signal_handler_disconnect (account, data->handler);
1136 /* Quit from wait loop */
1137 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1141 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1146 /* Quit from wait loop */
1147 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1151 modest_platform_connect_and_wait (GtkWindow *parent_window,
1152 TnyAccount *account)
1154 ConnectAndWaitData *data = NULL;
1155 gboolean device_online;
1157 TnyConnectionStatus conn_status;
1158 gboolean user_requested;
1160 device = modest_runtime_get_device();
1161 device_online = tny_device_is_online (device);
1163 /* Whether the connection is user requested or automatically
1164 requested, for example via D-Bus */
1165 user_requested = (parent_window) ? TRUE : FALSE;
1167 /* If there is no account check only the device status */
1172 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1173 NULL, user_requested);
1176 /* Return if the account is already connected */
1177 conn_status = tny_account_get_connection_status (account);
1178 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1181 /* Create the helper */
1182 data = g_slice_new0 (ConnectAndWaitData);
1183 data->mutex = g_mutex_new ();
1184 data->has_callback = FALSE;
1186 /* Connect the device */
1187 if (!device_online) {
1188 /* Track account connection status changes */
1189 data->handler = g_signal_connect (account, "connection-status-changed",
1190 G_CALLBACK (on_connection_status_changed),
1192 /* Try to connect the device */
1193 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1194 NULL, user_requested);
1196 /* If the device connection failed then exit */
1197 if (!device_online && data->handler)
1200 /* Force a reconnection of the account */
1201 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1202 on_tny_camel_account_set_online_cb, data);
1205 /* Wait until the callback is executed */
1206 g_mutex_lock (data->mutex);
1207 if (!data->has_callback) {
1208 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1209 gdk_threads_leave ();
1210 g_mutex_unlock (data->mutex);
1211 g_main_loop_run (data->wait_loop);
1212 g_mutex_lock (data->mutex);
1213 gdk_threads_enter ();
1215 g_mutex_unlock (data->mutex);
1219 if (g_signal_handler_is_connected (account, data->handler))
1220 g_signal_handler_disconnect (account, data->handler);
1221 g_mutex_free (data->mutex);
1222 g_main_loop_unref (data->wait_loop);
1223 g_slice_free (ConnectAndWaitData, data);
1226 conn_status = tny_account_get_connection_status (account);
1227 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1231 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1233 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1234 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1235 /* This must be a maildir account, which does not require a connection: */
1240 return modest_platform_connect_and_wait (parent_window, account);
1244 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1247 return TRUE; /* Maybe it is something local. */
1249 gboolean result = TRUE;
1250 if (TNY_IS_FOLDER (folder_store)) {
1251 /* Get the folder's parent account: */
1252 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1253 if (account != NULL) {
1254 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1255 g_object_unref (account);
1257 } else if (TNY_IS_ACCOUNT (folder_store)) {
1258 /* Use the folder store as an account: */
1259 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1266 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1270 dialog = modest_hildon2_sort_dialog_new (parent_window);
1277 modest_platform_set_update_interval (guint minutes)
1279 #ifdef MODEST_HAVE_LIBALARM
1281 ModestConf *conf = modest_runtime_get_conf ();
1285 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1287 /* Delete any existing alarm,
1288 * because we will replace it: */
1290 if (alarmd_event_del(alarm_cookie) != 1)
1291 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1293 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1296 /* 0 means no updates: */
1301 /* Register alarm: */
1303 /* Set the interval in alarm_event_t structure: */
1304 alarm_event_t *event = alarm_event_create ();
1305 alarm_event_add_actions (event, 1);
1306 alarm_action_t *action = alarm_event_get_action (event, 0);
1307 event->alarm_time = minutes * 60; /* seconds */
1309 /* Set recurrence every few minutes: */
1310 event->recur_secs = minutes*60;
1311 event->recur_count = -1; /* Means infinite */
1313 /* Specify what should happen when the alarm happens:
1314 * It should call this D-Bus method: */
1316 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1317 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1318 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1319 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1320 action->flags = ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1322 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1323 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1324 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1325 * This is why we want to use the Alarm API instead of just g_timeout_add().
1326 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1327 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1329 event->flags = ALARM_EVENT_CONNECTED;
1331 alarm_cookie = alarmd_event_add (event);
1334 alarm_event_delete (event);
1336 /* Store the alarm ID in GConf, so we can remove it later:
1337 * This is apparently valid between application instances. */
1338 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1340 if (!alarm_cookie) {
1342 g_debug ("Error setting alarm event. \n");
1346 #endif /* MODEST_HAVE_LIBALARM */
1351 modest_platform_push_email_notification(void)
1353 gboolean screen_on = TRUE, app_in_foreground;
1355 /* Get the window status */
1356 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1358 /* If the screen is on and the app is in the
1359 foreground we don't show anything */
1360 if (!(screen_on && app_in_foreground)) {
1362 _modest_platform_play_email_tone ();
1364 /* Activate LED. This must be deactivated by
1365 modest_platform_remove_new_mail_notifications */
1366 #ifdef MODEST_HAVE_MCE
1367 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1371 MCE_ACTIVATE_LED_PATTERN,
1373 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1380 modest_platform_on_new_headers_received (TnyList *header_list,
1381 gboolean show_visual)
1383 g_return_if_fail (TNY_IS_LIST(header_list));
1385 if (tny_list_get_length(header_list) == 0) {
1386 g_warning ("%s: header list is empty", __FUNCTION__);
1391 modest_platform_push_email_notification ();
1392 /* We do a return here to avoid indentation with an else */
1396 #ifdef MODEST_HAVE_HILDON_NOTIFY
1397 HildonNotification *notification;
1399 GSList *notifications_list = NULL;
1401 /* Get previous notifications ids */
1402 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1403 MODEST_CONF_NOTIFICATION_IDS,
1404 MODEST_CONF_VALUE_INT, NULL);
1406 iter = tny_list_create_iterator (header_list);
1407 while (!tny_iterator_is_done (iter)) {
1408 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1409 const gchar *display_date;
1410 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1411 TnyFolder *folder = tny_header_get_folder (header);
1412 gboolean first_notification = TRUE;
1415 ModestDatetimeFormatter *datetime_formatter;
1417 /* constant string, don't free */
1418 datetime_formatter = modest_datetime_formatter_new ();
1419 display_date = modest_datetime_formatter_display_datetime (datetime_formatter,
1420 tny_header_get_date_received (header));
1421 g_object_unref (datetime_formatter);
1423 display_address = tny_header_dup_from (header);
1424 /* string is changed in-place */
1425 modest_text_utils_get_display_address (display_address);
1427 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1428 str = tny_header_dup_subject (header);
1429 notification = hildon_notification_new (summary,
1431 "qgn_list_messagin",
1434 /* Create the message URL */
1435 str = tny_header_dup_uid (header);
1436 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1440 hildon_notification_add_dbus_action(notification,
1443 MODEST_DBUS_SERVICE,
1446 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1450 /* Play sound if the user wants. Show the LED
1451 pattern. Show and play just one */
1452 if (G_UNLIKELY (first_notification)) {
1453 gchar *active_profile;
1456 gint mail_volume_int;
1458 first_notification = FALSE;
1460 active_profile = profile_get_profile ();
1461 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1462 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1463 mail_volume_int = profile_parse_int (mail_volume);
1465 if (mail_volume_int > 0)
1466 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1467 "sound-file", mail_tone);
1469 g_free (mail_volume);
1471 g_free (active_profile);
1473 /* Set the led pattern */
1474 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1476 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1478 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1481 /* Notify. We need to do this in an idle because this function
1482 could be called from a thread */
1483 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1485 /* Save id in the list */
1486 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1487 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1488 /* We don't listen for the "closed" signal, because we
1489 don't care about if the notification was removed or
1490 not to store the list in gconf */
1492 /* Free & carry on */
1493 g_free (display_address);
1496 g_object_unref (folder);
1497 g_object_unref (header);
1498 tny_iterator_next (iter);
1500 g_object_unref (iter);
1503 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1504 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1506 g_slist_free (notifications_list);
1508 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1512 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1515 #ifdef MODEST_HAVE_MCE
1516 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1520 MCE_DEACTIVATE_LED_PATTERN,
1522 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1528 #ifdef MODEST_HAVE_HILDON_NOTIFY
1529 GSList *notif_list = NULL;
1531 /* Get previous notifications ids */
1532 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1533 MODEST_CONF_NOTIFICATION_IDS,
1534 MODEST_CONF_VALUE_INT, NULL);
1536 while (notif_list) {
1538 NotifyNotification *notif;
1540 /* Nasty HACK to remove the notifications, set the id
1541 of the existing ones and then close them */
1542 notif_id = GPOINTER_TO_INT(notif_list->data);
1543 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1544 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1546 /* Close the notification, note that some ids could be
1547 already invalid, but we don't care because it does
1549 notify_notification_close(notif, NULL);
1550 g_object_unref(notif);
1552 /* Delete the link, it's like going to the next */
1553 notif_list = g_slist_delete_link (notif_list, notif_list);
1557 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1558 notif_list, MODEST_CONF_VALUE_INT, NULL);
1560 g_slist_free (notif_list);
1562 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1568 modest_platform_get_global_settings_dialog ()
1570 return modest_hildon2_global_settings_dialog_new ();
1574 modest_platform_show_help (GtkWindow *parent_window,
1575 const gchar *help_id)
1581 modest_platform_show_search_messages (GtkWindow *parent_window)
1583 osso_return_t result = OSSO_ERROR;
1585 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1586 "osso_global_search",
1587 "search_email", NULL, DBUS_TYPE_INVALID);
1589 if (result != OSSO_OK) {
1590 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1595 modest_platform_show_addressbook (GtkWindow *parent_window)
1597 osso_return_t result = OSSO_ERROR;
1599 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1601 "top_application", NULL, DBUS_TYPE_INVALID);
1603 if (result != OSSO_OK) {
1604 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1609 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1611 GtkWidget *widget = modest_folder_view_new (query);
1613 /* Show one account by default */
1614 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1615 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1617 /* Restore settings */
1618 modest_widget_memory_restore (modest_runtime_get_conf(),
1620 MODEST_CONF_FOLDER_VIEW_KEY);
1626 banner_finish (gpointer data, GObject *object)
1628 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1629 modest_window_mgr_unregister_banner (mgr);
1630 g_object_unref (mgr);
1634 modest_platform_information_banner (GtkWidget *parent,
1635 const gchar *icon_name,
1638 GtkWidget *banner, *banner_parent = NULL;
1639 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1641 if (modest_window_mgr_get_num_windows (mgr) == 0)
1644 if (parent && GTK_IS_WINDOW (parent)) {
1645 /* If the window is the active one then show the
1646 banner on top of this window */
1647 if (gtk_window_is_active (GTK_WINDOW (parent)))
1648 banner_parent = parent;
1649 /* If the window is not the topmost but it's visible
1650 (it's minimized for example) then show the banner
1652 else if (GTK_WIDGET_VISIBLE (parent))
1653 banner_parent = NULL;
1654 /* If the window is hidden (like the main window when
1655 running in the background) then do not show
1662 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1664 modest_window_mgr_register_banner (mgr);
1666 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1670 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1671 const gchar *icon_name,
1677 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1680 banner = hildon_banner_show_information (parent, icon_name, text);
1681 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1685 modest_platform_animation_banner (GtkWidget *parent,
1686 const gchar *animation_name,
1689 GtkWidget *inf_note = NULL;
1691 g_return_val_if_fail (text != NULL, NULL);
1693 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1696 /* If the parent is not visible then do not show */
1697 if (parent && !GTK_WIDGET_VISIBLE (parent))
1700 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1708 TnyAccount *account;
1711 } CheckAccountIdleData;
1713 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1716 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1718 gboolean stop_trying = FALSE;
1719 g_return_val_if_fail (data && data->account, FALSE);
1721 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1722 tny_account_get_connection_status (data->account));
1724 if (data && data->account &&
1725 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1726 * after which the account is likely to be usable, or never likely to be usable soon: */
1727 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1729 data->is_online = TRUE;
1733 /* Give up if we have tried too many times: */
1734 if (data->count_tries >= NUMBER_OF_TRIES) {
1737 /* Wait for another timeout: */
1738 ++(data->count_tries);
1743 /* Allow the function that requested this idle callback to continue: */
1745 g_main_loop_quit (data->loop);
1748 g_object_unref (data->account);
1750 return FALSE; /* Don't call this again. */
1752 return TRUE; /* Call this timeout callback again. */
1756 /* Return TRUE immediately if the account is already online,
1757 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1758 * soon as the account is online, or FALSE if the account does
1759 * not become online in the NUMBER_OF_TRIES seconds.
1760 * This is useful when the D-Bus method was run immediately after
1761 * the application was started (when using D-Bus activation),
1762 * because the account usually takes a short time to go online.
1763 * The return value is maybe not very useful.
1766 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1770 g_return_val_if_fail (account, FALSE);
1772 if (!tny_device_is_online (modest_runtime_get_device())) {
1773 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1777 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1778 * so we avoid wait unnecessarily: */
1779 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1782 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1783 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1784 * we want to avoid. */
1785 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1788 /* This blocks on the result: */
1789 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1790 data->is_online = FALSE;
1791 data->account = account;
1792 g_object_ref (data->account);
1793 data->count_tries = 0;
1795 GMainContext *context = NULL; /* g_main_context_new (); */
1796 data->loop = g_main_loop_new (context, FALSE /* not running */);
1798 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1800 /* This main loop will run until the idle handler has stopped it: */
1801 g_main_loop_run (data->loop);
1803 g_main_loop_unref (data->loop);
1804 /* g_main_context_unref (context); */
1806 is_online = data->is_online;
1807 g_slice_free (CheckAccountIdleData, data);
1815 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1817 /* GTK_RESPONSE_HELP means we need to show the certificate */
1818 if (response_id == GTK_RESPONSE_APPLY) {
1822 /* Do not close the dialog */
1823 g_signal_stop_emission_by_name (dialog, "response");
1825 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1826 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1827 gtk_dialog_run (GTK_DIALOG(note));
1828 gtk_widget_destroy (note);
1834 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1835 const gchar *certificate)
1840 HildonWindowStack *stack;
1842 stack = hildon_window_stack_get_default ();
1843 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1846 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1851 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1854 /* We use GTK_RESPONSE_APPLY because we want the button in the
1855 middle of OK and CANCEL the same as the browser does for
1856 example. With GTK_RESPONSE_HELP the view button is aligned
1857 to the left while the other two to the right */
1858 note = hildon_note_new_confirmation_add_buttons (
1861 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1862 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1863 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1866 g_signal_connect (G_OBJECT(note), "response",
1867 G_CALLBACK(on_cert_dialog_response),
1868 (gpointer) certificate);
1870 response = gtk_dialog_run(GTK_DIALOG(note));
1872 on_destroy_dialog (note);
1875 return response == GTK_RESPONSE_OK;
1879 modest_platform_run_alert_dialog (const gchar* prompt,
1880 gboolean is_question)
1882 ModestWindow *main_win;
1884 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1885 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1886 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1887 return is_question ? FALSE : TRUE;
1890 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1891 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1893 gboolean retval = TRUE;
1895 /* The Tinymail documentation says that we should show Yes and No buttons,
1896 * when it is a question.
1897 * Obviously, we need tinymail to use more specific error codes instead,
1898 * so we know what buttons to show. */
1899 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1901 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1902 GTK_WINDOW (dialog), GTK_WINDOW (main_win));
1904 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1905 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1907 on_destroy_dialog (dialog);
1909 /* Just show the error text and use the default response: */
1910 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1918 GtkWindow *parent_window;
1919 ModestConnectedPerformer callback;
1920 TnyAccount *account;
1927 on_went_online_info_free (OnWentOnlineInfo *info)
1929 /* And if we cleanup, we DO cleanup :-) */
1932 g_object_unref (info->device);
1935 if (info->parent_window)
1936 g_object_unref (info->parent_window);
1938 g_object_unref (info->account);
1940 g_slice_free (OnWentOnlineInfo, info);
1942 /* We're done ... */
1948 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1950 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1952 /* Now it's really time to callback to the caller. If going online didn't succeed,
1953 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1954 * canceled will be set. Etcetera etcetera. */
1956 if (info->callback) {
1957 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1960 /* This is our last call, we must cleanup here if we didn't yet do that */
1961 on_went_online_info_free (info);
1968 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1970 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1971 info->iap = g_strdup (iap_id);
1973 if (canceled || err || !info->account) {
1975 /* If there's a problem or if there's no account (then that's it for us, we callback
1976 * the caller's callback now. He'll have to handle err or canceled, of course.
1977 * We are not really online, as the account is not really online here ... */
1979 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1980 * this info. We don't cleanup err, Tinymail does that! */
1982 if (info->callback) {
1984 /* info->account can be NULL here, this means that the user did not
1985 * provide a nice account instance. We'll assume that the user knows
1986 * what he's doing and is happy with just the device going online.
1988 * We can't do magic, we don't know what account the user wants to
1989 * see going online. So just the device goes online, end of story */
1991 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1994 } else if (info->account) {
1996 /* If there's no problem and if we have an account, we'll put the account
1997 * online too. When done, the callback of bringing the account online
1998 * will callback the caller's callback. This is the most normal case. */
2000 info->device = TNY_DEVICE (g_object_ref (device));
2002 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2003 on_account_went_online, info);
2005 /* The on_account_went_online cb frees up the info, go look if you
2006 * don't believe me! (so we return here) */
2011 /* We cleanup if we are not bringing the account online too */
2012 on_went_online_info_free (info);
2018 modest_platform_connect_and_perform (GtkWindow *parent_window,
2020 TnyAccount *account,
2021 ModestConnectedPerformer callback,
2024 gboolean device_online;
2026 TnyConnectionStatus conn_status;
2027 OnWentOnlineInfo *info;
2029 device = modest_runtime_get_device();
2030 device_online = tny_device_is_online (device);
2032 /* If there is no account check only the device status */
2035 if (device_online) {
2037 /* We promise to instantly perform the callback, so ... */
2039 callback (FALSE, NULL, parent_window, account, user_data);
2044 info = g_slice_new0 (OnWentOnlineInfo);
2047 info->device = NULL;
2048 info->account = NULL;
2051 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2053 info->parent_window = NULL;
2054 info->user_data = user_data;
2055 info->callback = callback;
2057 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2058 force, on_conic_device_went_online,
2061 /* We'll cleanup in on_conic_device_went_online */
2064 /* The other code has no more reason to run. This is all that we can do for the
2065 * caller (he should have given us a nice and clean account instance!). We
2066 * can't do magic, we don't know what account he intends to bring online. So
2067 * we'll just bring the device online (and await his false bug report). */
2073 /* Return if the account is already connected */
2075 conn_status = tny_account_get_connection_status (account);
2076 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2078 /* We promise to instantly perform the callback, so ... */
2080 callback (FALSE, NULL, parent_window, account, user_data);
2086 /* Else, we are in a state that requires that we go online before we
2087 * call the caller's callback. */
2089 info = g_slice_new0 (OnWentOnlineInfo);
2091 info->device = NULL;
2093 info->account = TNY_ACCOUNT (g_object_ref (account));
2096 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2098 info->parent_window = NULL;
2100 /* So we'll put the callback away for later ... */
2102 info->user_data = user_data;
2103 info->callback = callback;
2105 if (!device_online) {
2107 /* If also the device is offline, then we connect both the device
2108 * and the account */
2110 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2111 force, on_conic_device_went_online,
2116 /* If the device is online, we'll just connect the account */
2118 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2119 on_account_went_online, info);
2122 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2123 * in both situations, go look if you don't believe me! */
2129 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2131 TnyFolderStore *folder_store,
2132 ModestConnectedPerformer callback,
2135 TnyAccount *account = NULL;
2137 if (!folder_store) {
2138 /* We promise to instantly perform the callback, so ... */
2140 callback (FALSE, NULL, parent_window, NULL, user_data);
2144 } else if (TNY_IS_FOLDER (folder_store)) {
2145 /* Get the folder's parent account: */
2146 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2147 } else if (TNY_IS_ACCOUNT (folder_store)) {
2148 /* Use the folder store as an account: */
2149 account = TNY_ACCOUNT (g_object_ref (folder_store));
2152 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2153 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2154 /* No need to connect a local account */
2156 callback (FALSE, NULL, parent_window, account, user_data);
2161 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2165 g_object_unref (account);
2169 src_account_connect_performer (gboolean canceled,
2171 GtkWindow *parent_window,
2172 TnyAccount *src_account,
2175 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2177 if (canceled || err) {
2178 /* If there was any error call the user callback */
2179 info->callback (canceled, err, parent_window, src_account, info->data);
2181 /* Connect the destination account */
2182 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2183 TNY_FOLDER_STORE (info->dst_account),
2184 info->callback, info->data);
2187 /* Free the info object */
2188 g_object_unref (info->dst_account);
2189 g_slice_free (DoubleConnectionInfo, info);
2194 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2196 TnyFolderStore *folder_store,
2197 DoubleConnectionInfo *connect_info)
2199 modest_platform_connect_if_remote_and_perform(parent_window,
2202 src_account_connect_performer,
2207 modest_platform_get_account_settings_wizard (void)
2209 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2211 return GTK_WIDGET (dialog);
2215 modest_platform_get_current_connection (void)
2217 TnyDevice *device = NULL;
2218 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2220 device = modest_runtime_get_device ();
2222 if (!tny_device_is_online (device))
2223 return MODEST_CONNECTED_VIA_ANY;
2225 #ifdef MODEST_HAVE_CONIC
2227 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2229 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2230 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2231 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2233 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2234 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2235 !strcmp (bearer_type, "WIMAX")) {
2236 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2238 retval = MODEST_CONNECTED_VIA_ANY;
2241 g_object_unref (iap);
2244 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2245 #endif /* MODEST_HAVE_CONIC */
2252 modest_platform_check_memory_low (ModestWindow *win,
2257 /* are we in low memory state? */
2258 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2260 if (win && lowmem && visuals)
2261 modest_platform_run_information_dialog (
2263 dgettext("ke-recv","memr_ib_operation_disabled"),
2267 g_debug ("%s: low memory reached. disallowing some operations",
2274 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2280 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2283 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2284 GTK_WINDOW (dialog),
2286 gtk_widget_show_all (dialog);
2288 g_signal_connect_swapped (dialog, "response",
2289 G_CALLBACK (gtk_widget_destroy),
2294 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2300 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2303 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2304 GTK_WINDOW (dialog),
2306 gtk_widget_show_all (dialog);
2308 g_signal_connect_swapped (dialog, "response",
2309 G_CALLBACK (gtk_widget_destroy),
2314 modest_platform_get_osso_context (void)
2316 return modest_maemo_utils_get_osso_context ();
2320 _modest_platform_play_email_tone (void)
2322 gchar *active_profile;
2325 gint mail_volume_int;
2327 ca_context *ca_con = NULL;
2328 ca_proplist *pl = NULL;
2330 active_profile = profile_get_profile ();
2331 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2332 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2333 mail_volume_int = profile_parse_int (mail_volume);
2335 if (mail_volume_int > 0) {
2337 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2338 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2342 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2343 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2344 ca_context_destroy(ca_con);
2348 ca_proplist_create(&pl);
2349 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2350 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2352 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2353 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2355 ca_proplist_destroy(pl);
2356 ca_context_destroy(ca_con);
2359 g_free (mail_volume);
2361 g_free (active_profile);
2365 on_move_to_dialog_folder_activated (GtkTreeView *tree_view,
2367 GtkTreeViewColumn *column,
2370 gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2374 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2375 GtkWidget **folder_view)
2377 GtkWidget *dialog, *folder_view_container;
2379 /* Create dialog. We cannot use a touch selector because we
2380 need to use here the folder view widget directly */
2381 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2382 GTK_WINDOW (parent_window),
2383 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2384 GTK_DIALOG_DESTROY_WITH_PARENT,
2385 _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2388 /* Create folder view */
2389 *folder_view = modest_platform_create_folder_view (NULL);
2391 /* Simulate the behaviour of a HildonPickerDialog by emitting
2392 a response when a folder is selected */
2393 g_signal_connect (*folder_view, "row-activated",
2394 G_CALLBACK (on_move_to_dialog_folder_activated),
2397 /* Create pannable and add it to the dialog */
2398 folder_view_container = hildon_pannable_area_new ();
2399 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2400 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2402 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2404 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2405 gtk_widget_show (folder_view_container);
2406 gtk_widget_show (*folder_view);
2412 modest_platform_get_list_to_move (ModestWindow *window)
2414 if (MODEST_IS_HEADER_WINDOW (window)) {
2415 ModestHeaderView *header_view;
2417 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2419 return modest_header_view_get_selected_headers (header_view);
2420 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2421 ModestFolderView *folder_view;
2422 TnyFolderStore *selected_folder;
2425 list = TNY_LIST (tny_simple_list_new ());
2426 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2427 selected_folder = modest_folder_view_get_selected (folder_view);
2428 if (selected_folder) {
2429 tny_list_prepend (list, G_OBJECT (selected_folder));
2430 g_object_unref (selected_folder);