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);
699 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
700 MODEST_FOLDER_VIEW_FILTER_CAN_HAVE_FOLDERS);
702 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original), MODEST_FOLDER_VIEW (folder_view));
705 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
706 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
709 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
710 gtk_container_add (GTK_CONTAINER (pannable), folder_view);
711 gtk_widget_show (folder_view);
712 gtk_widget_show (pannable);
713 gtk_widget_show_all (userdata.dialog);
714 gtk_widget_set_size_request (pannable, -1, 320);
715 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
716 G_CALLBACK (folder_chooser_activated),
717 (gpointer) &userdata);
719 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
720 gtk_widget_destroy (userdata.dialog);
722 return userdata.store;
725 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
728 folder_store_get_display_name (TnyFolderStore *store)
730 if (TNY_IS_ACCOUNT (store)) {
731 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
734 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
736 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
737 type = tny_folder_get_folder_type (TNY_FOLDER (store));
738 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
739 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
740 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
741 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
743 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
746 /* Sometimes an special folder is reported by the server as
747 NORMAL, like some versions of Dovecot */
748 if (type == TNY_FOLDER_TYPE_NORMAL ||
749 type == TNY_FOLDER_TYPE_UNKNOWN) {
750 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
754 if (type == TNY_FOLDER_TYPE_INBOX) {
756 fname = g_strdup (_("mcen_me_folder_inbox"));
763 folder_picker_clicked (GtkButton *button,
764 ModestFolderView *folder_view)
766 TnyFolderStore *store;
768 store = folder_chooser_dialog_run (folder_view);
771 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, store);
772 name = folder_store_get_display_name (store);
773 hildon_button_set_value (HILDON_BUTTON (button), name);
779 folder_picker_new (ModestFolderView *folder_view)
784 button = hildon_button_new (MODEST_EDITABLE_SIZE,
785 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
786 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL,
787 MODEST_ICON_SIZE_SMALL);
789 hildon_button_set_image (HILDON_BUTTON (button),
790 gtk_image_new_from_pixbuf (pixbuf));
791 hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
793 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (folder_picker_clicked), folder_view);
800 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
801 TnyFolderStore *suggested_parent,
802 const gchar *dialog_title,
803 const gchar *label_text,
804 const gchar *suggested_name,
806 gboolean show_parent,
808 TnyFolderStore **parent)
810 GtkWidget *accept_btn = NULL;
811 GtkWidget *dialog, *entry, *label_entry, *label_location, *hbox;
812 GtkWidget *account_picker;
813 GList *buttons = NULL;
815 GtkSizeGroup *sizegroup;
816 ModestFolderView *folder_view;
818 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (parent_window), GTK_RESPONSE_NONE);
820 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (parent_window));
822 /* Ask the user for the folder name */
823 dialog = gtk_dialog_new_with_buttons (dialog_title,
825 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
826 _FM("ckdg_bd_new_folder_dialog_ok"),
830 /* Add accept button (with unsensitive handler) */
831 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
832 accept_btn = GTK_WIDGET (buttons->data);
834 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
837 label_entry = gtk_label_new (label_text);
838 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
839 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
841 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
842 gtk_size_group_add_widget (sizegroup, label_entry);
845 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
847 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
848 gtk_entry_set_width_chars (GTK_ENTRY (entry),
849 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
850 g_utf8_strlen (_("mcen_ia_default_folder_name"), -1)));
851 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
856 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
858 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
859 gtk_size_group_add_widget (sizegroup, label_location);
861 account_picker = folder_picker_new (folder_view);
864 g_object_unref (sizegroup);
866 /* Connect to the response method to avoid closing the dialog
867 when an invalid name is selected*/
868 g_signal_connect (dialog,
870 G_CALLBACK (on_response),
874 /* Track entry changes */
875 g_signal_connect (entry,
877 G_CALLBACK (entry_insert_text),
879 g_signal_connect (entry,
881 G_CALLBACK (entry_changed),
886 /* Some locales like pt_BR need this to get the full window
888 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
890 /* Create the hbox */
892 hbox = gtk_hbox_new (FALSE, 12);
893 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
894 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
896 /* Add hbox to dialog */
897 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
898 hbox, FALSE, FALSE, 0);
899 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
903 hbox = gtk_hbox_new (FALSE, 12);
904 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
905 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
907 /* Add hbox to dialog */
908 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
909 hbox, FALSE, FALSE, 0);
910 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
912 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
913 GTK_WINDOW (dialog), parent_window);
914 gtk_widget_show_all (GTK_WIDGET(dialog));
916 result = gtk_dialog_run (GTK_DIALOG(dialog));
917 if (result == GTK_RESPONSE_ACCEPT) {
919 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
921 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
925 gtk_widget_destroy (dialog);
927 while (gtk_events_pending ())
928 gtk_main_iteration ();
934 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
935 TnyFolderStore *suggested_folder,
936 gchar *suggested_name,
938 TnyFolderStore **parent_folder)
940 gchar *real_suggested_name = NULL, *tmp = NULL;
943 if(suggested_name == NULL)
945 const gchar *default_name = _("mcen_ia_default_folder_name");
949 for(i = 0; i < 100; ++ i) {
950 gboolean exists = FALSE;
952 sprintf(num_str, "%.2u", i);
955 real_suggested_name = g_strdup (default_name);
957 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
959 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
966 g_free (real_suggested_name);
969 /* Didn't find a free number */
971 real_suggested_name = g_strdup (default_name);
973 real_suggested_name = suggested_name;
976 tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
977 result = modest_platform_run_folder_common_dialog (parent_window,
979 _("mcen_ti_new_folder"),
988 if (suggested_name == NULL)
989 g_free(real_suggested_name);
995 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
996 TnyFolderStore *parent_folder,
997 const gchar *suggested_name,
1000 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1002 return modest_platform_run_folder_common_dialog (parent_window,
1004 _HL("ckdg_ti_rename_folder"),
1005 _HL("ckdg_fi_rename_name"),
1016 on_destroy_dialog (GtkWidget *dialog)
1018 /* This could happen when the dialogs get programatically
1019 hidden or destroyed (for example when closing the
1020 application while a dialog is being shown) */
1021 if (!GTK_IS_WIDGET (dialog))
1024 gtk_widget_destroy (dialog);
1026 if (gtk_events_pending ())
1027 gtk_main_iteration ();
1031 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1032 const gchar *message)
1037 dialog = hildon_note_new_confirmation (parent_window, message);
1038 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1039 GTK_WINDOW (dialog), parent_window);
1041 response = gtk_dialog_run (GTK_DIALOG (dialog));
1043 on_destroy_dialog (dialog);
1049 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1050 const gchar *message,
1051 const gchar *button_accept,
1052 const gchar *button_cancel)
1057 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1058 button_accept, GTK_RESPONSE_ACCEPT,
1059 button_cancel, GTK_RESPONSE_CANCEL,
1062 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1063 GTK_WINDOW (dialog), parent_window);
1065 response = gtk_dialog_run (GTK_DIALOG (dialog));
1067 on_destroy_dialog (dialog);
1073 modest_platform_run_information_dialog (GtkWindow *parent_window,
1074 const gchar *message,
1079 note = hildon_note_new_information (parent_window, message);
1081 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1082 GTK_WINDOW (note), parent_window);
1085 gtk_dialog_run (GTK_DIALOG (note));
1087 on_destroy_dialog (note);
1089 g_signal_connect_swapped (note,
1091 G_CALLBACK (on_destroy_dialog),
1094 gtk_widget_show_all (note);
1098 typedef struct _ConnectAndWaitData {
1100 GMainLoop *wait_loop;
1101 gboolean has_callback;
1103 } ConnectAndWaitData;
1107 quit_wait_loop (TnyAccount *account,
1108 ConnectAndWaitData *data)
1110 /* Set the has_callback to TRUE (means that the callback was
1111 executed and wake up every code waiting for cond to be
1113 g_mutex_lock (data->mutex);
1114 data->has_callback = TRUE;
1115 if (data->wait_loop)
1116 g_main_loop_quit (data->wait_loop);
1117 g_mutex_unlock (data->mutex);
1121 on_connection_status_changed (TnyAccount *account,
1122 TnyConnectionStatus status,
1125 TnyConnectionStatus conn_status;
1126 ConnectAndWaitData *data;
1128 /* Ignore if reconnecting or disconnected */
1129 conn_status = tny_account_get_connection_status (account);
1130 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1131 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1134 /* Remove the handler */
1135 data = (ConnectAndWaitData *) user_data;
1136 g_signal_handler_disconnect (account, data->handler);
1138 /* Quit from wait loop */
1139 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1143 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1148 /* Quit from wait loop */
1149 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1153 modest_platform_connect_and_wait (GtkWindow *parent_window,
1154 TnyAccount *account)
1156 ConnectAndWaitData *data = NULL;
1157 gboolean device_online;
1159 TnyConnectionStatus conn_status;
1160 gboolean user_requested;
1162 device = modest_runtime_get_device();
1163 device_online = tny_device_is_online (device);
1165 /* Whether the connection is user requested or automatically
1166 requested, for example via D-Bus */
1167 user_requested = (parent_window) ? TRUE : FALSE;
1169 /* If there is no account check only the device status */
1174 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1175 NULL, user_requested);
1178 /* Return if the account is already connected */
1179 conn_status = tny_account_get_connection_status (account);
1180 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1183 /* Create the helper */
1184 data = g_slice_new0 (ConnectAndWaitData);
1185 data->mutex = g_mutex_new ();
1186 data->has_callback = FALSE;
1188 /* Connect the device */
1189 if (!device_online) {
1190 /* Track account connection status changes */
1191 data->handler = g_signal_connect (account, "connection-status-changed",
1192 G_CALLBACK (on_connection_status_changed),
1194 /* Try to connect the device */
1195 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1196 NULL, user_requested);
1198 /* If the device connection failed then exit */
1199 if (!device_online && data->handler)
1202 /* Force a reconnection of the account */
1203 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1204 on_tny_camel_account_set_online_cb, data);
1207 /* Wait until the callback is executed */
1208 g_mutex_lock (data->mutex);
1209 if (!data->has_callback) {
1210 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1211 gdk_threads_leave ();
1212 g_mutex_unlock (data->mutex);
1213 g_main_loop_run (data->wait_loop);
1214 g_mutex_lock (data->mutex);
1215 gdk_threads_enter ();
1217 g_mutex_unlock (data->mutex);
1221 if (g_signal_handler_is_connected (account, data->handler))
1222 g_signal_handler_disconnect (account, data->handler);
1223 g_mutex_free (data->mutex);
1224 g_main_loop_unref (data->wait_loop);
1225 g_slice_free (ConnectAndWaitData, data);
1228 conn_status = tny_account_get_connection_status (account);
1229 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1233 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1235 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1236 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1237 /* This must be a maildir account, which does not require a connection: */
1242 return modest_platform_connect_and_wait (parent_window, account);
1246 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1249 return TRUE; /* Maybe it is something local. */
1251 gboolean result = TRUE;
1252 if (TNY_IS_FOLDER (folder_store)) {
1253 /* Get the folder's parent account: */
1254 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1255 if (account != NULL) {
1256 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1257 g_object_unref (account);
1259 } else if (TNY_IS_ACCOUNT (folder_store)) {
1260 /* Use the folder store as an account: */
1261 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1268 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1272 dialog = modest_hildon2_sort_dialog_new (parent_window);
1279 modest_platform_set_update_interval (guint minutes)
1281 #ifdef MODEST_HAVE_LIBALARM
1283 ModestConf *conf = modest_runtime_get_conf ();
1287 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1289 /* Delete any existing alarm,
1290 * because we will replace it: */
1292 if (alarmd_event_del(alarm_cookie) != 1)
1293 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1295 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1298 /* 0 means no updates: */
1303 /* Register alarm: */
1305 /* Set the interval in alarm_event_t structure: */
1306 alarm_event_t *event = alarm_event_create ();
1307 alarm_event_add_actions (event, 1);
1308 alarm_action_t *action = alarm_event_get_action (event, 0);
1309 event->alarm_time = minutes * 60; /* seconds */
1311 /* Set recurrence every few minutes: */
1312 event->recur_secs = minutes*60;
1313 event->recur_count = -1; /* Means infinite */
1315 /* Specify what should happen when the alarm happens:
1316 * It should call this D-Bus method: */
1318 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1319 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1320 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1321 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1322 action->flags = ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1324 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1325 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1326 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1327 * This is why we want to use the Alarm API instead of just g_timeout_add().
1328 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1329 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1331 event->flags = ALARM_EVENT_CONNECTED;
1333 alarm_cookie = alarmd_event_add (event);
1336 alarm_event_delete (event);
1338 /* Store the alarm ID in GConf, so we can remove it later:
1339 * This is apparently valid between application instances. */
1340 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1342 if (!alarm_cookie) {
1344 g_debug ("Error setting alarm event. \n");
1348 #endif /* MODEST_HAVE_LIBALARM */
1353 modest_platform_push_email_notification(void)
1355 gboolean screen_on = TRUE, app_in_foreground;
1357 /* Get the window status */
1358 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1360 /* If the screen is on and the app is in the
1361 foreground we don't show anything */
1362 if (!(screen_on && app_in_foreground)) {
1364 _modest_platform_play_email_tone ();
1366 /* Activate LED. This must be deactivated by
1367 modest_platform_remove_new_mail_notifications */
1368 #ifdef MODEST_HAVE_MCE
1369 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1373 MCE_ACTIVATE_LED_PATTERN,
1375 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1382 modest_platform_on_new_headers_received (TnyList *header_list,
1383 gboolean show_visual)
1385 g_return_if_fail (TNY_IS_LIST(header_list));
1387 if (tny_list_get_length(header_list) == 0) {
1388 g_warning ("%s: header list is empty", __FUNCTION__);
1393 modest_platform_push_email_notification ();
1394 /* We do a return here to avoid indentation with an else */
1398 #ifdef MODEST_HAVE_HILDON_NOTIFY
1399 HildonNotification *notification;
1401 GSList *notifications_list = NULL;
1403 /* Get previous notifications ids */
1404 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1405 MODEST_CONF_NOTIFICATION_IDS,
1406 MODEST_CONF_VALUE_INT, NULL);
1408 iter = tny_list_create_iterator (header_list);
1409 while (!tny_iterator_is_done (iter)) {
1410 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1411 const gchar *display_date;
1412 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1413 TnyFolder *folder = tny_header_get_folder (header);
1414 gboolean first_notification = TRUE;
1417 ModestDatetimeFormatter *datetime_formatter;
1419 /* constant string, don't free */
1420 datetime_formatter = modest_datetime_formatter_new ();
1421 display_date = modest_datetime_formatter_display_datetime (datetime_formatter,
1422 tny_header_get_date_received (header));
1423 g_object_unref (datetime_formatter);
1425 display_address = tny_header_dup_from (header);
1426 /* string is changed in-place */
1427 modest_text_utils_get_display_address (display_address);
1429 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1430 str = tny_header_dup_subject (header);
1431 notification = hildon_notification_new (summary,
1433 "qgn_list_messagin",
1436 /* Create the message URL */
1437 str = tny_header_dup_uid (header);
1438 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1442 hildon_notification_add_dbus_action(notification,
1445 MODEST_DBUS_SERVICE,
1448 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1452 /* Play sound if the user wants. Show the LED
1453 pattern. Show and play just one */
1454 if (G_UNLIKELY (first_notification)) {
1455 gchar *active_profile;
1458 gint mail_volume_int;
1460 first_notification = FALSE;
1462 active_profile = profile_get_profile ();
1463 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1464 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1465 mail_volume_int = profile_parse_int (mail_volume);
1467 if (mail_volume_int > 0)
1468 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1469 "sound-file", mail_tone);
1471 g_free (mail_volume);
1473 g_free (active_profile);
1475 /* Set the led pattern */
1476 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1478 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1480 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1483 /* Notify. We need to do this in an idle because this function
1484 could be called from a thread */
1485 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1487 /* Save id in the list */
1488 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1489 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1490 /* We don't listen for the "closed" signal, because we
1491 don't care about if the notification was removed or
1492 not to store the list in gconf */
1494 /* Free & carry on */
1495 g_free (display_address);
1498 g_object_unref (folder);
1499 g_object_unref (header);
1500 tny_iterator_next (iter);
1502 g_object_unref (iter);
1505 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1506 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1508 g_slist_free (notifications_list);
1510 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1514 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1517 #ifdef MODEST_HAVE_MCE
1518 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1522 MCE_DEACTIVATE_LED_PATTERN,
1524 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1530 #ifdef MODEST_HAVE_HILDON_NOTIFY
1531 GSList *notif_list = NULL;
1533 /* Get previous notifications ids */
1534 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1535 MODEST_CONF_NOTIFICATION_IDS,
1536 MODEST_CONF_VALUE_INT, NULL);
1538 while (notif_list) {
1540 NotifyNotification *notif;
1542 /* Nasty HACK to remove the notifications, set the id
1543 of the existing ones and then close them */
1544 notif_id = GPOINTER_TO_INT(notif_list->data);
1545 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1546 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1548 /* Close the notification, note that some ids could be
1549 already invalid, but we don't care because it does
1551 notify_notification_close(notif, NULL);
1552 g_object_unref(notif);
1554 /* Delete the link, it's like going to the next */
1555 notif_list = g_slist_delete_link (notif_list, notif_list);
1559 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1560 notif_list, MODEST_CONF_VALUE_INT, NULL);
1562 g_slist_free (notif_list);
1564 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1570 modest_platform_get_global_settings_dialog ()
1572 return modest_hildon2_global_settings_dialog_new ();
1576 modest_platform_show_help (GtkWindow *parent_window,
1577 const gchar *help_id)
1583 modest_platform_show_search_messages (GtkWindow *parent_window)
1585 osso_return_t result = OSSO_ERROR;
1587 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1588 "osso_global_search",
1589 "search_email", NULL, DBUS_TYPE_INVALID);
1591 if (result != OSSO_OK) {
1592 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1597 modest_platform_show_addressbook (GtkWindow *parent_window)
1599 osso_return_t result = OSSO_ERROR;
1601 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1603 "top_application", NULL, DBUS_TYPE_INVALID);
1605 if (result != OSSO_OK) {
1606 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1611 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1613 GtkWidget *widget = modest_folder_view_new (query);
1615 /* Show one account by default */
1616 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1617 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1619 /* Restore settings */
1620 modest_widget_memory_restore (modest_runtime_get_conf(),
1622 MODEST_CONF_FOLDER_VIEW_KEY);
1628 banner_finish (gpointer data, GObject *object)
1630 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1631 modest_window_mgr_unregister_banner (mgr);
1632 g_object_unref (mgr);
1636 modest_platform_information_banner (GtkWidget *parent,
1637 const gchar *icon_name,
1640 GtkWidget *banner, *banner_parent = NULL;
1641 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1643 if (modest_window_mgr_get_num_windows (mgr) == 0)
1646 if (parent && GTK_IS_WINDOW (parent)) {
1647 /* If the window is the active one then show the
1648 banner on top of this window */
1649 if (gtk_window_is_active (GTK_WINDOW (parent)))
1650 banner_parent = parent;
1651 /* If the window is not the topmost but it's visible
1652 (it's minimized for example) then show the banner
1654 else if (GTK_WIDGET_VISIBLE (parent))
1655 banner_parent = NULL;
1656 /* If the window is hidden (like the main window when
1657 running in the background) then do not show
1664 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1666 modest_window_mgr_register_banner (mgr);
1668 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1672 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1673 const gchar *icon_name,
1679 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1682 banner = hildon_banner_show_information (parent, icon_name, text);
1683 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1687 modest_platform_animation_banner (GtkWidget *parent,
1688 const gchar *animation_name,
1691 GtkWidget *inf_note = NULL;
1693 g_return_val_if_fail (text != NULL, NULL);
1695 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1698 /* If the parent is not visible then do not show */
1699 if (parent && !GTK_WIDGET_VISIBLE (parent))
1702 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1710 TnyAccount *account;
1713 } CheckAccountIdleData;
1715 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1718 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1720 gboolean stop_trying = FALSE;
1721 g_return_val_if_fail (data && data->account, FALSE);
1723 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1724 tny_account_get_connection_status (data->account));
1726 if (data && data->account &&
1727 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1728 * after which the account is likely to be usable, or never likely to be usable soon: */
1729 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1731 data->is_online = TRUE;
1735 /* Give up if we have tried too many times: */
1736 if (data->count_tries >= NUMBER_OF_TRIES) {
1739 /* Wait for another timeout: */
1740 ++(data->count_tries);
1745 /* Allow the function that requested this idle callback to continue: */
1747 g_main_loop_quit (data->loop);
1750 g_object_unref (data->account);
1752 return FALSE; /* Don't call this again. */
1754 return TRUE; /* Call this timeout callback again. */
1758 /* Return TRUE immediately if the account is already online,
1759 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1760 * soon as the account is online, or FALSE if the account does
1761 * not become online in the NUMBER_OF_TRIES seconds.
1762 * This is useful when the D-Bus method was run immediately after
1763 * the application was started (when using D-Bus activation),
1764 * because the account usually takes a short time to go online.
1765 * The return value is maybe not very useful.
1768 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1772 g_return_val_if_fail (account, FALSE);
1774 if (!tny_device_is_online (modest_runtime_get_device())) {
1775 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1779 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1780 * so we avoid wait unnecessarily: */
1781 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1784 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1785 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1786 * we want to avoid. */
1787 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1790 /* This blocks on the result: */
1791 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1792 data->is_online = FALSE;
1793 data->account = account;
1794 g_object_ref (data->account);
1795 data->count_tries = 0;
1797 GMainContext *context = NULL; /* g_main_context_new (); */
1798 data->loop = g_main_loop_new (context, FALSE /* not running */);
1800 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1802 /* This main loop will run until the idle handler has stopped it: */
1803 g_main_loop_run (data->loop);
1805 g_main_loop_unref (data->loop);
1806 /* g_main_context_unref (context); */
1808 is_online = data->is_online;
1809 g_slice_free (CheckAccountIdleData, data);
1817 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1819 /* GTK_RESPONSE_HELP means we need to show the certificate */
1820 if (response_id == GTK_RESPONSE_APPLY) {
1824 /* Do not close the dialog */
1825 g_signal_stop_emission_by_name (dialog, "response");
1827 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1828 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1829 gtk_dialog_run (GTK_DIALOG(note));
1830 gtk_widget_destroy (note);
1836 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1837 const gchar *certificate)
1842 HildonWindowStack *stack;
1844 stack = hildon_window_stack_get_default ();
1845 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1848 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1853 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1856 /* We use GTK_RESPONSE_APPLY because we want the button in the
1857 middle of OK and CANCEL the same as the browser does for
1858 example. With GTK_RESPONSE_HELP the view button is aligned
1859 to the left while the other two to the right */
1860 note = hildon_note_new_confirmation_add_buttons (
1863 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1864 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1865 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1868 g_signal_connect (G_OBJECT(note), "response",
1869 G_CALLBACK(on_cert_dialog_response),
1870 (gpointer) certificate);
1872 response = gtk_dialog_run(GTK_DIALOG(note));
1874 on_destroy_dialog (note);
1877 return response == GTK_RESPONSE_OK;
1881 modest_platform_run_alert_dialog (const gchar* prompt,
1882 gboolean is_question)
1884 ModestWindow *main_win;
1886 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1887 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1888 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1889 return is_question ? FALSE : TRUE;
1892 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1893 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1895 gboolean retval = TRUE;
1897 /* The Tinymail documentation says that we should show Yes and No buttons,
1898 * when it is a question.
1899 * Obviously, we need tinymail to use more specific error codes instead,
1900 * so we know what buttons to show. */
1901 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1903 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1904 GTK_WINDOW (dialog), GTK_WINDOW (main_win));
1906 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1907 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1909 on_destroy_dialog (dialog);
1911 /* Just show the error text and use the default response: */
1912 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1920 GtkWindow *parent_window;
1921 ModestConnectedPerformer callback;
1922 TnyAccount *account;
1929 on_went_online_info_free (OnWentOnlineInfo *info)
1931 /* And if we cleanup, we DO cleanup :-) */
1934 g_object_unref (info->device);
1937 if (info->parent_window)
1938 g_object_unref (info->parent_window);
1940 g_object_unref (info->account);
1942 g_slice_free (OnWentOnlineInfo, info);
1944 /* We're done ... */
1950 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1952 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1954 /* Now it's really time to callback to the caller. If going online didn't succeed,
1955 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1956 * canceled will be set. Etcetera etcetera. */
1958 if (info->callback) {
1959 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1962 /* This is our last call, we must cleanup here if we didn't yet do that */
1963 on_went_online_info_free (info);
1970 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1972 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1973 info->iap = g_strdup (iap_id);
1975 if (canceled || err || !info->account) {
1977 /* If there's a problem or if there's no account (then that's it for us, we callback
1978 * the caller's callback now. He'll have to handle err or canceled, of course.
1979 * We are not really online, as the account is not really online here ... */
1981 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1982 * this info. We don't cleanup err, Tinymail does that! */
1984 if (info->callback) {
1986 /* info->account can be NULL here, this means that the user did not
1987 * provide a nice account instance. We'll assume that the user knows
1988 * what he's doing and is happy with just the device going online.
1990 * We can't do magic, we don't know what account the user wants to
1991 * see going online. So just the device goes online, end of story */
1993 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1996 } else if (info->account) {
1998 /* If there's no problem and if we have an account, we'll put the account
1999 * online too. When done, the callback of bringing the account online
2000 * will callback the caller's callback. This is the most normal case. */
2002 info->device = TNY_DEVICE (g_object_ref (device));
2004 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2005 on_account_went_online, info);
2007 /* The on_account_went_online cb frees up the info, go look if you
2008 * don't believe me! (so we return here) */
2013 /* We cleanup if we are not bringing the account online too */
2014 on_went_online_info_free (info);
2020 modest_platform_connect_and_perform (GtkWindow *parent_window,
2022 TnyAccount *account,
2023 ModestConnectedPerformer callback,
2026 gboolean device_online;
2028 TnyConnectionStatus conn_status;
2029 OnWentOnlineInfo *info;
2031 device = modest_runtime_get_device();
2032 device_online = tny_device_is_online (device);
2034 /* If there is no account check only the device status */
2037 if (device_online) {
2039 /* We promise to instantly perform the callback, so ... */
2041 callback (FALSE, NULL, parent_window, account, user_data);
2046 info = g_slice_new0 (OnWentOnlineInfo);
2049 info->device = NULL;
2050 info->account = NULL;
2053 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2055 info->parent_window = NULL;
2056 info->user_data = user_data;
2057 info->callback = callback;
2059 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2060 force, on_conic_device_went_online,
2063 /* We'll cleanup in on_conic_device_went_online */
2066 /* The other code has no more reason to run. This is all that we can do for the
2067 * caller (he should have given us a nice and clean account instance!). We
2068 * can't do magic, we don't know what account he intends to bring online. So
2069 * we'll just bring the device online (and await his false bug report). */
2075 /* Return if the account is already connected */
2077 conn_status = tny_account_get_connection_status (account);
2078 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2080 /* We promise to instantly perform the callback, so ... */
2082 callback (FALSE, NULL, parent_window, account, user_data);
2088 /* Else, we are in a state that requires that we go online before we
2089 * call the caller's callback. */
2091 info = g_slice_new0 (OnWentOnlineInfo);
2093 info->device = NULL;
2095 info->account = TNY_ACCOUNT (g_object_ref (account));
2098 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2100 info->parent_window = NULL;
2102 /* So we'll put the callback away for later ... */
2104 info->user_data = user_data;
2105 info->callback = callback;
2107 if (!device_online) {
2109 /* If also the device is offline, then we connect both the device
2110 * and the account */
2112 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2113 force, on_conic_device_went_online,
2118 /* If the device is online, we'll just connect the account */
2120 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2121 on_account_went_online, info);
2124 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2125 * in both situations, go look if you don't believe me! */
2131 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2133 TnyFolderStore *folder_store,
2134 ModestConnectedPerformer callback,
2137 TnyAccount *account = NULL;
2139 if (!folder_store) {
2140 /* We promise to instantly perform the callback, so ... */
2142 callback (FALSE, NULL, parent_window, NULL, user_data);
2146 } else if (TNY_IS_FOLDER (folder_store)) {
2147 /* Get the folder's parent account: */
2148 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2149 } else if (TNY_IS_ACCOUNT (folder_store)) {
2150 /* Use the folder store as an account: */
2151 account = TNY_ACCOUNT (g_object_ref (folder_store));
2154 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2155 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2156 /* No need to connect a local account */
2158 callback (FALSE, NULL, parent_window, account, user_data);
2163 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2167 g_object_unref (account);
2171 src_account_connect_performer (gboolean canceled,
2173 GtkWindow *parent_window,
2174 TnyAccount *src_account,
2177 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2179 if (canceled || err) {
2180 /* If there was any error call the user callback */
2181 info->callback (canceled, err, parent_window, src_account, info->data);
2183 /* Connect the destination account */
2184 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2185 TNY_FOLDER_STORE (info->dst_account),
2186 info->callback, info->data);
2189 /* Free the info object */
2190 g_object_unref (info->dst_account);
2191 g_slice_free (DoubleConnectionInfo, info);
2196 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2198 TnyFolderStore *folder_store,
2199 DoubleConnectionInfo *connect_info)
2201 modest_platform_connect_if_remote_and_perform(parent_window,
2204 src_account_connect_performer,
2209 modest_platform_get_account_settings_wizard (void)
2211 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2213 return GTK_WIDGET (dialog);
2217 modest_platform_get_current_connection (void)
2219 TnyDevice *device = NULL;
2220 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2222 device = modest_runtime_get_device ();
2224 if (!tny_device_is_online (device))
2225 return MODEST_CONNECTED_VIA_ANY;
2227 #ifdef MODEST_HAVE_CONIC
2229 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2231 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2232 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2233 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2235 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2236 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2237 !strcmp (bearer_type, "WIMAX")) {
2238 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2240 retval = MODEST_CONNECTED_VIA_ANY;
2243 g_object_unref (iap);
2246 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2247 #endif /* MODEST_HAVE_CONIC */
2254 modest_platform_check_memory_low (ModestWindow *win,
2259 /* are we in low memory state? */
2260 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2262 if (win && lowmem && visuals)
2263 modest_platform_run_information_dialog (
2265 dgettext("ke-recv","memr_ib_operation_disabled"),
2269 g_debug ("%s: low memory reached. disallowing some operations",
2276 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2282 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2285 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2286 GTK_WINDOW (dialog),
2288 gtk_widget_show_all (dialog);
2290 g_signal_connect_swapped (dialog, "response",
2291 G_CALLBACK (gtk_widget_destroy),
2296 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2302 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2305 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2306 GTK_WINDOW (dialog),
2308 gtk_widget_show_all (dialog);
2310 g_signal_connect_swapped (dialog, "response",
2311 G_CALLBACK (gtk_widget_destroy),
2316 modest_platform_get_osso_context (void)
2318 return modest_maemo_utils_get_osso_context ();
2322 _modest_platform_play_email_tone (void)
2324 gchar *active_profile;
2327 gint mail_volume_int;
2329 ca_context *ca_con = NULL;
2330 ca_proplist *pl = NULL;
2332 active_profile = profile_get_profile ();
2333 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2334 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2335 mail_volume_int = profile_parse_int (mail_volume);
2337 if (mail_volume_int > 0) {
2339 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2340 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2344 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2345 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2346 ca_context_destroy(ca_con);
2350 ca_proplist_create(&pl);
2351 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2352 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2354 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2355 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2357 ca_proplist_destroy(pl);
2358 ca_context_destroy(ca_con);
2361 g_free (mail_volume);
2363 g_free (active_profile);
2367 on_move_to_dialog_folder_activated (GtkTreeView *tree_view,
2369 GtkTreeViewColumn *column,
2372 gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2376 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2377 GtkWidget **folder_view)
2379 GtkWidget *dialog, *folder_view_container;
2381 /* Create dialog. We cannot use a touch selector because we
2382 need to use here the folder view widget directly */
2383 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2384 GTK_WINDOW (parent_window),
2385 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2386 GTK_DIALOG_DESTROY_WITH_PARENT,
2387 _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2390 /* Create folder view */
2391 *folder_view = modest_platform_create_folder_view (NULL);
2393 /* Simulate the behaviour of a HildonPickerDialog by emitting
2394 a response when a folder is selected */
2395 g_signal_connect (*folder_view, "row-activated",
2396 G_CALLBACK (on_move_to_dialog_folder_activated),
2399 /* Create pannable and add it to the dialog */
2400 folder_view_container = hildon_pannable_area_new ();
2401 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2402 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2404 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2406 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2407 gtk_widget_show (folder_view_container);
2408 gtk_widget_show (*folder_view);
2414 modest_platform_get_list_to_move (ModestWindow *window)
2416 if (MODEST_IS_HEADER_WINDOW (window)) {
2417 ModestHeaderView *header_view;
2419 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2421 return modest_header_view_get_selected_headers (header_view);
2422 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2423 ModestFolderView *folder_view;
2424 TnyFolderStore *selected_folder;
2427 list = TNY_LIST (tny_simple_list_new ());
2428 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2429 selected_folder = modest_folder_view_get_selected (folder_view);
2430 if (selected_folder) {
2431 tny_list_prepend (list, G_OBJECT (selected_folder));
2432 g_object_unref (selected_folder);