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>
33 #include <modest-platform.h>
34 #include <modest-defs.h>
35 #include <modest-runtime.h>
36 #include <modest-main-window.h>
37 #include <modest-header-view.h>
38 #include "modest-hildon2-global-settings-dialog.h"
39 #include "modest-widget-memory.h"
40 #include <modest-hildon-includes.h>
41 #include <modest-maemo-utils.h>
42 #include <dbus_api/modest-dbus-callbacks.h>
43 #include <modest-osso-autosave-callbacks.h>
45 #include <tny-maemo-conic-device.h>
46 #include <tny-camel-folder.h>
47 #include <tny-simple-list.h>
48 #include <tny-merge-folder.h>
49 #include <tny-error.h>
50 #include <tny-folder.h>
51 #include <tny-account-store-view.h>
52 #include <gtk/gtkicontheme.h>
53 #include <gtk/gtkmenuitem.h>
54 #include <gtk/gtkmain.h>
55 #include <modest-text-utils.h>
56 #include "modest-tny-folder.h"
57 #include "modest-tny-account.h"
59 #include <libgnomevfs/gnome-vfs-mime-utils.h>
60 #include <modest-account-settings-dialog.h>
61 #include <modest-easysetup-wizard-dialog.h>
62 #include "modest-hildon2-sort-dialog.h"
63 #include <hildon/hildon.h>
65 #include "hildon2/modest-hildon2-details-dialog.h"
66 #include "hildon2/modest-hildon2-window-mgr.h"
67 #ifdef MODEST_USE_PROFILE
68 #include <keys_nokia.h>
69 #include <libprofile.h>
72 #include <modest-datetime-formatter.h>
73 #include "modest-header-window.h"
74 #include <modest-folder-window.h>
75 #include <modest-account-mgr.h>
76 #include <modest-account-mgr-helpers.h>
77 #include <modest-ui-constants.h>
78 #include <modest-selector-picker.h>
79 #include <modest-icon-names.h>
81 #ifdef MODEST_HAVE_MCE
82 #include <mce/dbus-names.h>
83 #endif /*MODEST_HAVE_MCE*/
85 #ifdef MODEST_HAVE_ABOOK
86 #include <libosso-abook/osso-abook.h>
87 #endif /*MODEST_HAVE_ABOOK*/
89 #ifdef MODEST_HAVE_LIBALARM
90 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
91 #endif /*MODEST_HAVE_LIBALARM*/
94 #define HILDON_OSSO_URI_ACTION "uri-action"
95 #define URI_ACTION_COPY "copy:"
96 #define MODEST_NOTIFICATION_CATEGORY "email-message"
97 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
98 #ifdef MODEST_USE_PROFILE
99 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
100 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
102 #define MAIL_TONE "message-new-email"
105 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
106 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
107 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
108 #define MODEST_ALARMD_APPID PACKAGE_NAME
111 static void _modest_platform_play_email_tone (void);
115 on_modest_conf_update_interval_changed (ModestConf* self,
117 ModestConfEvent event,
118 ModestConfNotificationId id,
121 g_return_if_fail (key);
123 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
124 const guint update_interval_minutes =
125 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
126 modest_platform_set_update_interval (update_interval_minutes);
133 check_required_files (void)
135 FILE *mcc_file = modest_maemo_open_mcc_mapping_file (NULL);
137 g_printerr ("modest: check for mcc file failed\n");
142 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
143 access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
144 g_printerr ("modest: cannot find providers data\n");
152 /* the gpointer here is the osso_context. */
154 modest_platform_init (int argc, char *argv[])
156 osso_context_t *osso_context;
158 osso_hw_state_t hw_state = { 0 };
162 if (!check_required_files ()) {
163 g_printerr ("modest: missing required files\n");
167 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
170 g_printerr ("modest: failed to acquire osso context\n");
173 modest_maemo_utils_set_osso_context (osso_context);
175 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
176 g_printerr ("modest: could not get dbus connection\n");
180 /* Add a D-Bus handler to be used when the main osso-rpc
181 * D-Bus handler has not handled something.
182 * We use this for D-Bus methods that need to use more complex types
183 * than osso-rpc supports.
185 if (!dbus_connection_add_filter (con,
186 modest_dbus_req_filter,
190 g_printerr ("modest: Could not add D-Bus filter\n");
194 /* Register our simple D-Bus callbacks, via the osso API: */
195 osso_return_t result = osso_rpc_set_cb_f(osso_context,
199 modest_dbus_req_handler, NULL /* user_data */);
200 if (result != OSSO_OK) {
201 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
205 /* Register hardware event dbus callback: */
206 hw_state.shutdown_ind = TRUE;
207 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
209 /* Register osso auto-save callbacks: */
210 result = osso_application_set_autosave_cb (osso_context,
211 modest_on_osso_application_autosave, NULL /* user_data */);
212 if (result != OSSO_OK) {
213 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
218 /* Make sure that the update interval is changed whenever its gconf key
220 /* CAUTION: we're not using here the
221 modest_conf_listen_to_namespace because we know that there
222 are other parts of Modest listening for this namespace, so
223 we'll receive the notifications anyway. We basically do not
224 use it because there is no easy way to do the
225 modest_conf_forget_namespace */
226 ModestConf *conf = modest_runtime_get_conf ();
227 g_signal_connect (G_OBJECT(conf),
229 G_CALLBACK (on_modest_conf_update_interval_changed),
232 /* only force the setting of the default interval, if there are actually
234 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
236 /* Get the initial update interval from gconf: */
237 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
238 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
239 modest_account_mgr_free_account_names (acc_names);
243 #ifdef MODEST_HAVE_ABOOK
244 /* initialize the addressbook */
245 if (!osso_abook_init (&argc, &argv, osso_context)) {
246 g_printerr ("modest: failed to initialized addressbook\n");
249 #endif /*MODEST_HAVE_ABOOK*/
255 modest_platform_uninit (void)
257 osso_context_t *osso_context =
258 modest_maemo_utils_get_osso_context ();
260 osso_deinitialize (osso_context);
269 modest_platform_get_new_device (void)
271 return TNY_DEVICE (tny_maemo_conic_device_new ());
275 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
276 gchar **effective_mime_type)
278 GString *mime_str = NULL;
279 gchar *icon_name = NULL;
280 gchar **icons, **cursor;
282 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
283 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
285 mime_str = g_string_new (mime_type);
286 g_string_ascii_down (mime_str);
289 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
291 for (cursor = icons; cursor; ++cursor) {
292 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
293 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
294 icon_name = g_strdup ("qgn_list_messagin");
296 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
297 icon_name = g_strdup (*cursor);
303 if (effective_mime_type)
304 *effective_mime_type = g_string_free (mime_str, FALSE);
306 g_string_free (mime_str, TRUE);
313 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
318 g_return_val_if_fail (uri, FALSE);
320 result = hildon_uri_open (uri, action, &err);
322 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
323 uri, action, err && err->message ? err->message : "unknown error");
333 modest_platform_activate_uri (const gchar *uri)
335 HildonURIAction *action;
336 gboolean result = FALSE;
337 GSList *actions, *iter = NULL;
339 g_return_val_if_fail (uri, FALSE);
343 /* don't try to activate file: uri's -- they might confuse the user,
344 * and/or might have security implications */
345 if (!g_str_has_prefix (uri, "file:")) {
347 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
349 for (iter = actions; iter; iter = g_slist_next (iter)) {
350 action = (HildonURIAction*) iter->data;
351 if (action && strcmp (hildon_uri_action_get_service (action),
352 "com.nokia.modest") == 0) {
353 result = checked_hildon_uri_open (uri, action);
358 /* if we could not open it with email, try something else */
360 result = checked_hildon_uri_open (uri, NULL);
364 ModestWindow *parent =
365 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
366 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
367 _("mcen_ib_unsupported_link"));
368 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
375 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
379 gchar *uri_path = NULL;
381 uri_path = gnome_vfs_get_uri_from_local_path (path);
382 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
385 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
387 result = hildon_mime_open_file (con, uri_path);
389 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
397 } ModestPlatformPopupInfo;
400 delete_uri_popup (GtkWidget *menu,
404 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
406 g_free (popup_info->uri);
407 hildon_uri_free_actions (popup_info->actions);
413 activate_uri_popup_item (GtkMenuItem *menu_item,
417 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
418 const gchar* action_name;
420 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
422 g_printerr ("modest: no action name defined\n");
426 /* special handling for the copy menu item -- copy the uri to the clipboard */
427 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
428 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
429 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
430 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
432 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
433 action_name += strlen ("mailto:");
435 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
436 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
437 return; /* we're done */
440 /* now, the real uri-actions... */
441 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
442 HildonURIAction *action = (HildonURIAction *) node->data;
443 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
444 if (!checked_hildon_uri_open (popup_info->uri, action)) {
445 ModestWindow *parent =
446 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
447 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
448 _("mcen_ib_unsupported_link"));
456 modest_platform_show_uri_popup (const gchar *uri)
458 GSList *actions_list;
463 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
466 GtkWidget *menu = gtk_menu_new ();
467 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
469 /* don't add actions for file: uri's -- they might confuse the user,
470 * and/or might have security implications
471 * we still allow to copy the url though
473 if (!g_str_has_prefix (uri, "file:")) {
476 popup_info->actions = actions_list;
477 popup_info->uri = g_strdup (uri);
479 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
480 GtkWidget *menu_item;
481 const gchar *action_name;
482 const gchar *translation_domain;
483 HildonURIAction *action = (HildonURIAction *) node->data;
484 action_name = hildon_uri_action_get_name (action);
485 translation_domain = hildon_uri_action_get_translation_domain (action);
486 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
487 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
488 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
491 if (hildon_uri_is_default_action (action, NULL)) {
492 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
494 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
496 gtk_widget_show (menu_item);
501 /* and what to do when the link is deleted */
502 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
503 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
506 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
514 modest_platform_get_icon (const gchar *name, guint icon_size)
517 GdkPixbuf* pixbuf = NULL;
518 GtkIconTheme *current_theme = NULL;
520 g_return_val_if_fail (name, NULL);
522 /* strlen == 0 is not really an error; it just
523 * means the icon is not available
525 if (!name || strlen(name) == 0)
528 current_theme = gtk_icon_theme_get_default ();
529 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
530 GTK_ICON_LOOKUP_NO_SVG,
533 g_printerr ("modest: error loading theme icon '%s': %s\n",
541 modest_platform_get_app_name (void)
543 return _("mcen_ap_name");
547 entry_insert_text (GtkEditable *editable,
556 chars = gtk_editable_get_chars (editable, 0, -1);
557 chars_length = g_utf8_strlen (chars, -1);
560 /* Show WID-INF036 */
561 if (chars_length >= 20) {
562 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
563 _CS("ckdg_ib_maximum_characters_reached"));
565 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
569 tmp = g_strndup (folder_name_forbidden_chars,
570 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
571 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
572 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
578 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
579 _CS("ckdg_ib_maximum_characters_reached"));
581 /* Write the text in the entry if it's valid */
582 g_signal_handlers_block_by_func (editable,
583 (gpointer) entry_insert_text, data);
584 gtk_editable_insert_text (editable, text, length, position);
585 g_signal_handlers_unblock_by_func (editable,
586 (gpointer) entry_insert_text, data);
589 /* Do not allow further processing */
590 g_signal_stop_emission_by_name (editable, "insert_text");
594 entry_changed (GtkEditable *editable,
598 GtkWidget *ok_button;
601 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
602 ok_button = GTK_WIDGET (buttons->data);
604 chars = gtk_editable_get_chars (editable, 0, -1);
605 g_return_if_fail (chars != NULL);
608 if (g_utf8_strlen (chars,-1) >= 20) {
609 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
610 _CS("ckdg_ib_maximum_characters_reached"));
612 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
615 g_list_free (buttons);
622 on_response (GtkDialog *dialog,
626 GtkWidget *entry, *picker;
627 TnyFolderStore *parent;
628 const gchar *new_name;
631 if (response != GTK_RESPONSE_ACCEPT)
635 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
636 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
638 parent = TNY_FOLDER_STORE (user_data);
639 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
642 if (picker != NULL) {
644 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
647 /* Look for another folder with the same name */
648 if (modest_tny_folder_has_subfolder_with_name (parent,
655 if (TNY_IS_ACCOUNT (parent) &&
656 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
657 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
666 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
667 NULL, _CS("ckdg_ib_folder_already_exists"));
668 /* Select the text */
669 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
670 gtk_widget_grab_focus (entry);
671 /* Do not close the dialog */
672 g_signal_stop_emission_by_name (dialog, "response");
677 typedef struct _FolderChooserData {
678 TnyFolderStore *store;
683 folder_chooser_activated (ModestFolderView *folder_view,
684 TnyFolderStore *folder,
685 FolderChooserData *userdata)
687 userdata->store = folder;
688 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
691 static TnyFolderStore *
692 folder_chooser_dialog_run (ModestFolderView *original)
694 GtkWidget *folder_view;
695 FolderChooserData userdata = {NULL, NULL};
697 const gchar *visible_id = NULL;
699 userdata.dialog = hildon_dialog_new ();
700 pannable = hildon_pannable_area_new ();
701 folder_view = modest_platform_create_folder_view (NULL);
703 gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
705 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
706 MODEST_FOLDER_VIEW (folder_view));
709 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
710 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
713 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
714 gtk_container_add (GTK_CONTAINER (pannable), folder_view);
715 gtk_widget_set_size_request (pannable, -1, 320);
717 gtk_widget_show (folder_view);
718 gtk_widget_show (pannable);
719 gtk_widget_show (userdata.dialog);
720 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
721 G_CALLBACK (folder_chooser_activated),
722 (gpointer) &userdata);
724 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
725 gtk_widget_destroy (userdata.dialog);
727 return userdata.store;
731 folder_store_get_display_name (TnyFolderStore *store)
733 if (TNY_IS_ACCOUNT (store)) {
734 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
735 return modest_conf_get_string (modest_runtime_get_conf(),
736 MODEST_CONF_DEVICE_NAME, NULL);
738 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
741 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
743 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
744 type = tny_folder_get_folder_type (TNY_FOLDER (store));
745 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
746 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
747 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
748 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
750 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
753 /* Sometimes an special folder is reported by the server as
754 NORMAL, like some versions of Dovecot */
755 if (type == TNY_FOLDER_TYPE_NORMAL ||
756 type == TNY_FOLDER_TYPE_UNKNOWN) {
757 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
761 if (type == TNY_FOLDER_TYPE_INBOX) {
763 fname = g_strdup (_("mcen_me_folder_inbox"));
770 get_image_for_folder_store (TnyFolderStore *store,
774 const gchar *icon_name = NULL;
775 GtkWidget *image = NULL;
777 if (TNY_IS_ACCOUNT (store)) {
778 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
779 icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
780 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
781 icon_name = MODEST_FOLDER_ICON_MMC;
783 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
785 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
786 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
788 case TNY_FOLDER_TYPE_INBOX:
789 icon_name = MODEST_FOLDER_ICON_INBOX;
792 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
794 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
796 case TNY_FOLDER_TYPE_OUTBOX:
797 icon_name = MODEST_FOLDER_ICON_OUTBOX;
799 case TNY_FOLDER_TYPE_DRAFTS:
800 icon_name = MODEST_FOLDER_ICON_DRAFTS;
802 case TNY_FOLDER_TYPE_SENT:
803 icon_name = MODEST_FOLDER_ICON_SENT;
806 icon_name = MODEST_FOLDER_ICON_NORMAL;
808 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
809 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
814 pixbuf = modest_platform_get_icon (icon_name, size);
817 image = gtk_image_new_from_pixbuf (pixbuf);
818 g_object_unref (pixbuf);
825 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
830 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
834 g_object_ref (store);
835 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
836 store, (GDestroyNotify) g_object_unref);
837 name = folder_store_get_display_name (store);
838 hildon_button_set_value (HILDON_BUTTON (button), name);
842 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
844 hildon_button_set_image (HILDON_BUTTON (button), image);
848 /* Always returns DUPs so you must free the returned value */
850 get_next_folder_name (const gchar *suggested_name,
851 TnyFolderStore *suggested_folder)
853 const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
855 gchar *real_suggested_name;
857 if (suggested_name !=NULL) {
858 return g_strdup (suggested_name);
861 for(i = 0; i < 100; ++ i) {
862 gboolean exists = FALSE;
865 real_suggested_name = g_strdup (default_name);
867 real_suggested_name = g_strdup_printf ("%s(%d)",
868 _FM("ckdg_va_new_folder_name_stub"),
870 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
877 g_free (real_suggested_name);
880 /* Didn't find a free number */
882 real_suggested_name = g_strdup (default_name);
884 return real_suggested_name;
888 ModestFolderView *folder_view;
890 } FolderPickerHelper;
893 folder_picker_clicked (GtkButton *button,
894 FolderPickerHelper *helper)
896 TnyFolderStore *store;
898 store = folder_chooser_dialog_run (helper->folder_view);
900 const gchar *current_name;
903 folder_picker_set_store (GTK_BUTTON (button), store);
905 /* Update the name of the folder */
906 current_name = gtk_entry_get_text (helper->entry);
907 exists = modest_tny_folder_has_subfolder_with_name (store,
911 gchar *new_name = get_next_folder_name (NULL, store);
912 gtk_entry_set_text (helper->entry, new_name);
919 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
923 button = hildon_button_new (MODEST_EDITABLE_SIZE,
924 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
926 hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
929 folder_picker_set_store (GTK_BUTTON (button), suggested);
932 g_signal_connect (G_OBJECT (button), "clicked",
933 G_CALLBACK (folder_picker_clicked),
941 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
942 TnyFolderStore *suggested_parent,
943 const gchar *dialog_title,
944 const gchar *label_text,
945 const gchar *suggested_name,
947 gboolean show_parent,
949 TnyFolderStore **parent)
951 GtkWidget *accept_btn = NULL;
952 GtkWidget *dialog, *entry = NULL, *label_entry = NULL, *label_location = NULL, *hbox;
953 GtkWidget *account_picker = NULL;
954 GList *buttons = NULL;
956 GtkSizeGroup *sizegroup;
957 ModestFolderView *folder_view;
958 ModestWindow *folder_window;
959 ModestHildon2WindowMgr *window_mgr;
960 FolderPickerHelper *helper = NULL;
961 GtkWidget *top_vbox, *top_align;
963 window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
964 folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
965 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
967 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
969 top_vbox = gtk_vbox_new (FALSE, 0);
970 top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
971 gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
973 /* Ask the user for the folder name */
974 dialog = gtk_dialog_new_with_buttons (dialog_title,
976 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
977 _FM("ckdg_bd_new_folder_dialog_ok"),
981 /* Add accept button (with unsensitive handler) */
982 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
983 accept_btn = GTK_WIDGET (buttons->data);
985 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
988 label_entry = gtk_label_new (label_text);
989 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
990 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
992 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
993 gtk_size_group_add_widget (sizegroup, label_entry);
996 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
998 gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
999 gtk_entry_set_width_chars (GTK_ENTRY (entry),
1000 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
1001 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
1002 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
1007 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
1009 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
1010 gtk_size_group_add_widget (sizegroup, label_location);
1012 helper = g_slice_new0 (FolderPickerHelper);
1013 helper->folder_view = folder_view;
1014 helper->entry = (GtkEntry *) entry;
1016 account_picker = folder_picker_new (suggested_parent, helper);
1019 g_object_unref (sizegroup);
1021 /* Connect to the response method to avoid closing the dialog
1022 when an invalid name is selected*/
1023 g_signal_connect (dialog,
1025 G_CALLBACK (on_response),
1029 /* Track entry changes */
1030 g_signal_connect (entry,
1032 G_CALLBACK (entry_insert_text),
1034 g_signal_connect (entry,
1036 G_CALLBACK (entry_changed),
1041 /* Some locales like pt_BR need this to get the full window
1043 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
1045 /* Create the hbox */
1047 hbox = gtk_hbox_new (FALSE, 12);
1048 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
1049 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
1051 /* Add hbox to dialog */
1052 gtk_box_pack_start (GTK_BOX (top_vbox),
1053 hbox, FALSE, FALSE, 0);
1054 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
1058 hbox = gtk_hbox_new (FALSE, 12);
1059 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
1060 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
1062 /* Add hbox to dialog */
1063 gtk_box_pack_start (GTK_BOX (top_vbox),
1064 hbox, FALSE, FALSE, 0);
1065 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
1067 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1068 GTK_WINDOW (dialog), parent_window);
1070 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
1071 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
1073 gtk_widget_show_all (GTK_WIDGET(dialog));
1075 result = gtk_dialog_run (GTK_DIALOG(dialog));
1076 if (result == GTK_RESPONSE_ACCEPT) {
1078 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1080 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
1082 g_object_ref (*parent);
1086 gtk_widget_destroy (dialog);
1089 g_slice_free (FolderPickerHelper, helper);
1091 while (gtk_events_pending ())
1092 gtk_main_iteration ();
1098 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
1099 TnyFolderStore *suggested_folder,
1100 gchar *suggested_name,
1101 gchar **folder_name,
1102 TnyFolderStore **parent_folder)
1104 gchar *real_suggested_name = NULL;
1106 ModestTnyAccountStore *acc_store;
1107 TnyAccount *account;
1109 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
1112 /* In hildon 2.2 we always suggest the archive folder as parent */
1113 acc_store = modest_runtime_get_account_store ();
1114 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1116 suggested_folder = (TnyFolderStore *)
1117 modest_tny_account_get_special_folder (account,
1118 TNY_FOLDER_TYPE_ARCHIVE);
1119 g_object_unref (account);
1123 /* If there is not archive folder then fallback to local folders account */
1124 if (!suggested_folder)
1125 suggested_folder = (TnyFolderStore *)
1126 modest_tny_account_store_get_local_folders_account (acc_store);
1128 result = modest_platform_run_folder_common_dialog (parent_window,
1130 _HL("ckdg_ti_new_folder"),
1131 _FM("ckdg_fi_new_folder_name"),
1132 real_suggested_name,
1138 g_free(real_suggested_name);
1144 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1145 TnyFolderStore *parent_folder,
1146 const gchar *suggested_name,
1147 gchar **folder_name)
1149 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1151 return modest_platform_run_folder_common_dialog (parent_window,
1153 _HL("ckdg_ti_rename_folder"),
1154 _HL("ckdg_fi_rename_name"),
1165 on_destroy_dialog (GtkWidget *dialog)
1167 /* This could happen when the dialogs get programatically
1168 hidden or destroyed (for example when closing the
1169 application while a dialog is being shown) */
1170 if (!GTK_IS_WIDGET (dialog))
1173 gtk_widget_destroy (dialog);
1175 if (gtk_events_pending ())
1176 gtk_main_iteration ();
1180 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1181 const gchar *message)
1186 dialog = hildon_note_new_confirmation (parent_window, message);
1187 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1188 GTK_WINDOW (dialog), parent_window);
1190 response = gtk_dialog_run (GTK_DIALOG (dialog));
1192 on_destroy_dialog (dialog);
1198 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1199 const gchar *message,
1200 const gchar *button_accept,
1201 const gchar *button_cancel)
1206 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1207 button_accept, GTK_RESPONSE_ACCEPT,
1208 button_cancel, GTK_RESPONSE_CANCEL,
1211 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1212 GTK_WINDOW (dialog), parent_window);
1214 response = gtk_dialog_run (GTK_DIALOG (dialog));
1216 on_destroy_dialog (dialog);
1222 modest_platform_run_information_dialog (GtkWindow *parent_window,
1223 const gchar *message,
1228 note = hildon_note_new_information (parent_window, message);
1230 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1231 GTK_WINDOW (note), parent_window);
1234 gtk_dialog_run (GTK_DIALOG (note));
1236 on_destroy_dialog (note);
1238 g_signal_connect_swapped (note,
1240 G_CALLBACK (on_destroy_dialog),
1243 gtk_widget_show_all (note);
1247 typedef struct _ConnectAndWaitData {
1249 GMainLoop *wait_loop;
1250 gboolean has_callback;
1252 } ConnectAndWaitData;
1256 quit_wait_loop (TnyAccount *account,
1257 ConnectAndWaitData *data)
1259 /* Set the has_callback to TRUE (means that the callback was
1260 executed and wake up every code waiting for cond to be
1262 g_mutex_lock (data->mutex);
1263 data->has_callback = TRUE;
1264 if (data->wait_loop)
1265 g_main_loop_quit (data->wait_loop);
1266 g_mutex_unlock (data->mutex);
1270 on_connection_status_changed (TnyAccount *account,
1271 TnyConnectionStatus status,
1274 TnyConnectionStatus conn_status;
1275 ConnectAndWaitData *data;
1277 /* Ignore if reconnecting or disconnected */
1278 conn_status = tny_account_get_connection_status (account);
1279 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1280 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1283 /* Remove the handler */
1284 data = (ConnectAndWaitData *) user_data;
1285 g_signal_handler_disconnect (account, data->handler);
1287 /* Quit from wait loop */
1288 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1292 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1297 /* Quit from wait loop */
1298 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1302 modest_platform_connect_and_wait (GtkWindow *parent_window,
1303 TnyAccount *account)
1305 ConnectAndWaitData *data = NULL;
1306 gboolean device_online;
1308 TnyConnectionStatus conn_status;
1309 gboolean user_requested;
1311 device = modest_runtime_get_device();
1312 device_online = tny_device_is_online (device);
1314 /* Whether the connection is user requested or automatically
1315 requested, for example via D-Bus */
1316 user_requested = (parent_window) ? TRUE : FALSE;
1318 /* If there is no account check only the device status */
1323 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1324 NULL, user_requested);
1327 /* Return if the account is already connected */
1328 conn_status = tny_account_get_connection_status (account);
1329 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1332 /* Create the helper */
1333 data = g_slice_new0 (ConnectAndWaitData);
1334 data->mutex = g_mutex_new ();
1335 data->has_callback = FALSE;
1337 /* Connect the device */
1338 if (!device_online) {
1339 /* Track account connection status changes */
1340 data->handler = g_signal_connect (account, "connection-status-changed",
1341 G_CALLBACK (on_connection_status_changed),
1343 /* Try to connect the device */
1344 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1345 NULL, user_requested);
1347 /* If the device connection failed then exit */
1348 if (!device_online && data->handler)
1351 /* Force a reconnection of the account */
1352 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1353 on_tny_camel_account_set_online_cb, data);
1356 /* Wait until the callback is executed */
1357 g_mutex_lock (data->mutex);
1358 if (!data->has_callback) {
1359 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1360 gdk_threads_leave ();
1361 g_mutex_unlock (data->mutex);
1362 g_main_loop_run (data->wait_loop);
1363 g_mutex_lock (data->mutex);
1364 gdk_threads_enter ();
1366 g_mutex_unlock (data->mutex);
1369 if (g_signal_handler_is_connected (account, data->handler))
1370 g_signal_handler_disconnect (account, data->handler);
1371 g_mutex_free (data->mutex);
1372 g_main_loop_unref (data->wait_loop);
1373 g_slice_free (ConnectAndWaitData, data);
1375 conn_status = tny_account_get_connection_status (account);
1376 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1380 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1382 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1383 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1384 /* This must be a maildir account, which does not require a connection: */
1389 return modest_platform_connect_and_wait (parent_window, account);
1393 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1396 return TRUE; /* Maybe it is something local. */
1398 gboolean result = TRUE;
1399 if (TNY_IS_FOLDER (folder_store)) {
1400 /* Get the folder's parent account: */
1401 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1402 if (account != NULL) {
1403 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1404 g_object_unref (account);
1406 } else if (TNY_IS_ACCOUNT (folder_store)) {
1407 /* Use the folder store as an account: */
1408 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1415 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1419 dialog = modest_hildon2_sort_dialog_new (parent_window);
1426 modest_platform_set_update_interval (guint minutes)
1428 #ifdef MODEST_HAVE_LIBALARM
1430 ModestConf *conf = modest_runtime_get_conf ();
1434 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1436 /* Delete any existing alarm,
1437 * because we will replace it: */
1439 if (alarmd_event_del(alarm_cookie) != 0)
1440 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1442 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1445 /* 0 means no updates: */
1450 /* Register alarm: */
1452 /* Set the interval in alarm_event_t structure: */
1453 alarm_event_t *event = alarm_event_create ();
1454 alarm_event_add_actions (event, 1);
1455 alarm_action_t *action = alarm_event_get_action (event, 0);
1456 alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1457 event->alarm_time = minutes * 60; /* seconds */
1459 /* Set recurrence every few minutes: */
1460 event->recur_secs = minutes*60;
1461 event->recur_count = -1; /* Means infinite */
1463 /* Specify what should happen when the alarm happens:
1464 * It should call this D-Bus method: */
1466 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1467 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1468 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1469 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1470 action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1472 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1473 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1474 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1475 * This is why we want to use the Alarm API instead of just g_timeout_add().
1476 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1477 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1479 event->flags = ALARM_EVENT_CONNECTED;
1481 alarm_cookie = alarmd_event_add (event);
1484 alarm_event_delete (event);
1486 /* Store the alarm ID in GConf, so we can remove it later:
1487 * This is apparently valid between application instances. */
1488 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1490 if (!alarm_cookie) {
1492 g_debug ("Error setting alarm event. \n");
1496 #endif /* MODEST_HAVE_LIBALARM */
1501 modest_platform_push_email_notification(void)
1503 gboolean screen_on, app_in_foreground;
1505 /* Get the window status */
1506 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1508 screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1510 /* If the screen is on and the app is in the
1511 foreground we don't show anything */
1512 if (!(screen_on && app_in_foreground)) {
1514 _modest_platform_play_email_tone ();
1516 /* Activate LED. This must be deactivated by
1517 modest_platform_remove_new_mail_notifications */
1518 #ifdef MODEST_HAVE_MCE
1519 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1523 MCE_ACTIVATE_LED_PATTERN,
1525 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1532 modest_platform_on_new_headers_received (TnyList *header_list,
1533 gboolean show_visual)
1535 g_return_if_fail (TNY_IS_LIST(header_list));
1537 if (tny_list_get_length(header_list) == 0) {
1538 g_warning ("%s: header list is empty", __FUNCTION__);
1543 modest_platform_push_email_notification ();
1544 /* We do a return here to avoid indentation with an else */
1548 #ifdef MODEST_HAVE_HILDON_NOTIFY
1549 HildonNotification *notification;
1551 GSList *notifications_list = NULL;
1553 /* Get previous notifications ids */
1554 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1555 MODEST_CONF_NOTIFICATION_IDS,
1556 MODEST_CONF_VALUE_INT, NULL);
1558 iter = tny_list_create_iterator (header_list);
1559 while (!tny_iterator_is_done (iter)) {
1560 gchar *url = NULL, *display_address = NULL;
1561 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1562 TnyFolder *folder = tny_header_get_folder (header);
1563 gboolean first_notification = TRUE;
1567 display_address = tny_header_dup_from (header);
1568 /* string is changed in-place */
1569 modest_text_utils_get_display_address (display_address);
1571 str = tny_header_dup_subject (header);
1572 notification = hildon_notification_new (display_address,
1574 "qgn_list_messagin",
1575 MODEST_NOTIFICATION_CATEGORY);
1577 /* Create the message URL */
1578 str = tny_header_dup_uid (header);
1579 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1583 hildon_notification_add_dbus_action(notification,
1586 MODEST_DBUS_SERVICE,
1589 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1593 /* Play sound if the user wants. Show the LED
1594 pattern. Show and play just one */
1595 if (G_UNLIKELY (first_notification)) {
1596 TnyAccount *account;
1598 first_notification = FALSE;
1600 /* Set the led pattern */
1601 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1603 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1605 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1607 /* Set the account of the headers */
1608 account = tny_folder_get_account (folder);
1610 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1612 tny_account_get_id (account));
1613 g_object_unref (account);
1617 /* Notify. We need to do this in an idle because this function
1618 could be called from a thread */
1619 if (!notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1620 g_warning ("Failed to send notification");
1623 /* Save id in the list */
1624 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1625 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1626 /* We don't listen for the "closed" signal, because we
1627 don't care about if the notification was removed or
1628 not to store the list in gconf */
1630 /* Free & carry on */
1631 g_free (display_address);
1633 g_object_unref (folder);
1634 g_object_unref (header);
1635 tny_iterator_next (iter);
1637 g_object_unref (iter);
1640 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1641 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1643 g_slist_free (notifications_list);
1645 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1649 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1652 #ifdef MODEST_HAVE_MCE
1653 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1657 MCE_DEACTIVATE_LED_PATTERN,
1659 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1665 #ifdef MODEST_HAVE_HILDON_NOTIFY
1666 GSList *notif_list = NULL;
1668 /* Get previous notifications ids */
1669 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1670 MODEST_CONF_NOTIFICATION_IDS,
1671 MODEST_CONF_VALUE_INT, NULL);
1673 while (notif_list) {
1675 NotifyNotification *notif;
1677 /* Nasty HACK to remove the notifications, set the id
1678 of the existing ones and then close them */
1679 notif_id = GPOINTER_TO_INT(notif_list->data);
1680 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1681 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1683 /* Close the notification, note that some ids could be
1684 already invalid, but we don't care because it does
1686 notify_notification_close(notif, NULL);
1687 g_object_unref(notif);
1689 /* Delete the link, it's like going to the next */
1690 notif_list = g_slist_delete_link (notif_list, notif_list);
1694 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1695 notif_list, MODEST_CONF_VALUE_INT, NULL);
1697 g_slist_free (notif_list);
1699 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1705 modest_platform_get_global_settings_dialog ()
1707 return modest_hildon2_global_settings_dialog_new ();
1711 modest_platform_show_help (GtkWindow *parent_window,
1712 const gchar *help_id)
1718 modest_platform_show_search_messages (GtkWindow *parent_window)
1720 osso_return_t result = OSSO_ERROR;
1722 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1723 "osso_global_search",
1724 "search_email", NULL, DBUS_TYPE_INVALID);
1726 if (result != OSSO_OK) {
1727 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1732 modest_platform_show_addressbook (GtkWindow *parent_window)
1734 osso_return_t result = OSSO_ERROR;
1736 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1738 "top_application", NULL, DBUS_TYPE_INVALID);
1740 if (result != OSSO_OK) {
1741 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1746 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1748 GtkWidget *widget = modest_folder_view_new (query);
1750 /* Show one account by default */
1751 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1752 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1754 /* Restore settings */
1755 modest_widget_memory_restore (modest_runtime_get_conf(),
1757 MODEST_CONF_FOLDER_VIEW_KEY);
1763 banner_finish (gpointer data, GObject *object)
1765 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1766 modest_window_mgr_unregister_banner (mgr);
1767 g_object_unref (mgr);
1771 modest_platform_information_banner (GtkWidget *parent,
1772 const gchar *icon_name,
1775 GtkWidget *banner, *banner_parent = NULL;
1776 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1778 if (modest_window_mgr_get_num_windows (mgr) == 0)
1781 if (parent && GTK_IS_WINDOW (parent)) {
1782 /* If the window is the active one then show the
1783 banner on top of this window */
1784 if (gtk_window_is_active (GTK_WINDOW (parent)))
1785 banner_parent = parent;
1786 /* If the window is not the topmost but it's visible
1787 (it's minimized for example) then show the banner
1789 else if (GTK_WIDGET_VISIBLE (parent))
1790 banner_parent = NULL;
1791 /* If the window is hidden (like the main window when
1792 running in the background) then do not show
1799 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1801 modest_window_mgr_register_banner (mgr);
1803 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1807 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1808 const gchar *icon_name,
1814 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1817 banner = hildon_banner_show_information (parent, icon_name, text);
1818 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1822 modest_platform_animation_banner (GtkWidget *parent,
1823 const gchar *animation_name,
1826 GtkWidget *inf_note = NULL;
1828 g_return_val_if_fail (text != NULL, NULL);
1830 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1833 /* If the parent is not visible then do not show */
1834 if (parent && !GTK_WIDGET_VISIBLE (parent))
1837 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1845 TnyAccount *account;
1848 } CheckAccountIdleData;
1850 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1853 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1855 gboolean stop_trying = FALSE;
1856 g_return_val_if_fail (data && data->account, FALSE);
1858 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1859 tny_account_get_connection_status (data->account));
1861 if (data && data->account &&
1862 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1863 * after which the account is likely to be usable, or never likely to be usable soon: */
1864 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1866 data->is_online = TRUE;
1870 /* Give up if we have tried too many times: */
1871 if (data->count_tries >= NUMBER_OF_TRIES) {
1874 /* Wait for another timeout: */
1875 ++(data->count_tries);
1880 /* Allow the function that requested this idle callback to continue: */
1882 g_main_loop_quit (data->loop);
1885 g_object_unref (data->account);
1887 return FALSE; /* Don't call this again. */
1889 return TRUE; /* Call this timeout callback again. */
1893 /* Return TRUE immediately if the account is already online,
1894 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1895 * soon as the account is online, or FALSE if the account does
1896 * not become online in the NUMBER_OF_TRIES seconds.
1897 * This is useful when the D-Bus method was run immediately after
1898 * the application was started (when using D-Bus activation),
1899 * because the account usually takes a short time to go online.
1900 * The return value is maybe not very useful.
1903 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1907 g_return_val_if_fail (account, FALSE);
1909 if (!tny_device_is_online (modest_runtime_get_device())) {
1910 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1914 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1915 * so we avoid wait unnecessarily: */
1916 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1919 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1920 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1921 * we want to avoid. */
1922 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1925 /* This blocks on the result: */
1926 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1927 data->is_online = FALSE;
1928 data->account = account;
1929 g_object_ref (data->account);
1930 data->count_tries = 0;
1932 GMainContext *context = NULL; /* g_main_context_new (); */
1933 data->loop = g_main_loop_new (context, FALSE /* not running */);
1935 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1937 /* This main loop will run until the idle handler has stopped it: */
1938 g_main_loop_run (data->loop);
1940 g_main_loop_unref (data->loop);
1941 /* g_main_context_unref (context); */
1943 is_online = data->is_online;
1944 g_slice_free (CheckAccountIdleData, data);
1952 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1954 /* GTK_RESPONSE_HELP means we need to show the certificate */
1955 if (response_id == GTK_RESPONSE_APPLY) {
1959 /* Do not close the dialog */
1960 g_signal_stop_emission_by_name (dialog, "response");
1962 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1963 note = hildon_note_new_information (NULL, msg);
1964 gtk_dialog_run (GTK_DIALOG(note));
1965 gtk_widget_destroy (note);
1971 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1972 const gchar *certificate)
1977 HildonWindowStack *stack;
1979 stack = hildon_window_stack_get_default ();
1980 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1983 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1988 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1991 /* We use GTK_RESPONSE_APPLY because we want the button in the
1992 middle of OK and CANCEL the same as the browser does for
1993 example. With GTK_RESPONSE_HELP the view button is aligned
1994 to the left while the other two to the right */
1995 note = hildon_note_new_confirmation_add_buttons (
1998 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1999 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
2000 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
2003 g_signal_connect (G_OBJECT(note), "response",
2004 G_CALLBACK(on_cert_dialog_response),
2005 (gpointer) certificate);
2007 response = gtk_dialog_run(GTK_DIALOG(note));
2009 on_destroy_dialog (note);
2012 return response == GTK_RESPONSE_OK;
2016 modest_platform_run_alert_dialog (const gchar* prompt,
2017 gboolean is_question)
2019 ModestWindow *top_win;
2020 HildonWindowStack *stack;
2022 stack = hildon_window_stack_get_default ();
2023 top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2026 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2031 gboolean retval = TRUE;
2033 /* The Tinymail documentation says that we should show Yes and No buttons,
2034 * when it is a question.
2035 * Obviously, we need tinymail to use more specific error codes instead,
2036 * so we know what buttons to show. */
2037 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win),
2039 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2040 GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2042 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2043 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2045 on_destroy_dialog (dialog);
2047 /* Just show the error text and use the default response: */
2048 modest_platform_run_information_dialog (GTK_WINDOW (top_win),
2056 GtkWindow *parent_window;
2057 ModestConnectedPerformer callback;
2058 TnyAccount *account;
2065 on_went_online_info_free (OnWentOnlineInfo *info)
2067 /* And if we cleanup, we DO cleanup :-) */
2070 g_object_unref (info->device);
2073 if (info->parent_window)
2074 g_object_unref (info->parent_window);
2076 g_object_unref (info->account);
2078 g_slice_free (OnWentOnlineInfo, info);
2080 /* We're done ... */
2086 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2088 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2090 /* Now it's really time to callback to the caller. If going online didn't succeed,
2091 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2092 * canceled will be set. Etcetera etcetera. */
2094 if (info->callback) {
2095 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2098 /* This is our last call, we must cleanup here if we didn't yet do that */
2099 on_went_online_info_free (info);
2106 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2108 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2109 info->iap = g_strdup (iap_id);
2111 if (canceled || err || !info->account) {
2113 /* If there's a problem or if there's no account (then that's it for us, we callback
2114 * the caller's callback now. He'll have to handle err or canceled, of course.
2115 * We are not really online, as the account is not really online here ... */
2117 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2118 * this info. We don't cleanup err, Tinymail does that! */
2120 if (info->callback) {
2122 /* info->account can be NULL here, this means that the user did not
2123 * provide a nice account instance. We'll assume that the user knows
2124 * what he's doing and is happy with just the device going online.
2126 * We can't do magic, we don't know what account the user wants to
2127 * see going online. So just the device goes online, end of story */
2129 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2132 } else if (info->account) {
2134 /* If there's no problem and if we have an account, we'll put the account
2135 * online too. When done, the callback of bringing the account online
2136 * will callback the caller's callback. This is the most normal case. */
2138 info->device = TNY_DEVICE (g_object_ref (device));
2140 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2141 on_account_went_online, info);
2143 /* The on_account_went_online cb frees up the info, go look if you
2144 * don't believe me! (so we return here) */
2149 /* We cleanup if we are not bringing the account online too */
2150 on_went_online_info_free (info);
2156 modest_platform_connect_and_perform (GtkWindow *parent_window,
2158 TnyAccount *account,
2159 ModestConnectedPerformer callback,
2162 gboolean device_online;
2164 TnyConnectionStatus conn_status;
2165 OnWentOnlineInfo *info;
2167 device = modest_runtime_get_device();
2168 device_online = tny_device_is_online (device);
2170 /* If there is no account check only the device status */
2173 if (device_online) {
2175 /* We promise to instantly perform the callback, so ... */
2177 callback (FALSE, NULL, parent_window, account, user_data);
2182 info = g_slice_new0 (OnWentOnlineInfo);
2185 info->device = NULL;
2186 info->account = NULL;
2189 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2191 info->parent_window = NULL;
2192 info->user_data = user_data;
2193 info->callback = callback;
2195 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2196 force, on_conic_device_went_online,
2199 /* We'll cleanup in on_conic_device_went_online */
2202 /* The other code has no more reason to run. This is all that we can do for the
2203 * caller (he should have given us a nice and clean account instance!). We
2204 * can't do magic, we don't know what account he intends to bring online. So
2205 * we'll just bring the device online (and await his false bug report). */
2211 /* Return if the account is already connected */
2213 conn_status = tny_account_get_connection_status (account);
2214 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2216 /* We promise to instantly perform the callback, so ... */
2218 callback (FALSE, NULL, parent_window, account, user_data);
2224 /* Else, we are in a state that requires that we go online before we
2225 * call the caller's callback. */
2227 info = g_slice_new0 (OnWentOnlineInfo);
2229 info->device = NULL;
2231 info->account = TNY_ACCOUNT (g_object_ref (account));
2234 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2236 info->parent_window = NULL;
2238 /* So we'll put the callback away for later ... */
2240 info->user_data = user_data;
2241 info->callback = callback;
2243 if (!device_online) {
2245 /* If also the device is offline, then we connect both the device
2246 * and the account */
2248 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2249 force, on_conic_device_went_online,
2254 /* If the device is online, we'll just connect the account */
2256 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2257 on_account_went_online, info);
2260 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2261 * in both situations, go look if you don't believe me! */
2267 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2269 TnyFolderStore *folder_store,
2270 ModestConnectedPerformer callback,
2273 TnyAccount *account = NULL;
2275 if (!folder_store ||
2276 (TNY_IS_MERGE_FOLDER (folder_store) &&
2277 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2279 /* We promise to instantly perform the callback, so ... */
2281 GError *error = NULL;
2282 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2283 "Unable to move or not found folder");
2284 callback (FALSE, error, parent_window, NULL, user_data);
2285 g_error_free (error);
2289 } else if (TNY_IS_FOLDER (folder_store)) {
2290 /* Get the folder's parent account: */
2291 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2292 } else if (TNY_IS_ACCOUNT (folder_store)) {
2293 /* Use the folder store as an account: */
2294 account = TNY_ACCOUNT (g_object_ref (folder_store));
2297 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2298 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2299 /* No need to connect a local account */
2301 callback (FALSE, NULL, parent_window, account, user_data);
2306 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2310 g_object_unref (account);
2314 src_account_connect_performer (gboolean canceled,
2316 GtkWindow *parent_window,
2317 TnyAccount *src_account,
2320 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2322 if (canceled || err) {
2323 /* If there was any error call the user callback */
2324 info->callback (canceled, err, parent_window, src_account, info->data);
2326 /* Connect the destination account */
2327 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2328 TNY_FOLDER_STORE (info->dst_account),
2329 info->callback, info->data);
2332 /* Free the info object */
2333 g_object_unref (info->dst_account);
2334 g_slice_free (DoubleConnectionInfo, info);
2339 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2341 TnyFolderStore *folder_store,
2342 DoubleConnectionInfo *connect_info)
2344 modest_platform_connect_if_remote_and_perform(parent_window,
2347 src_account_connect_performer,
2352 modest_platform_get_account_settings_wizard (void)
2354 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2356 return GTK_WIDGET (dialog);
2360 modest_platform_get_current_connection (void)
2362 TnyDevice *device = NULL;
2363 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2365 device = modest_runtime_get_device ();
2367 if (!tny_device_is_online (device))
2368 return MODEST_CONNECTED_VIA_ANY;
2370 #ifdef MODEST_HAVE_CONIC
2372 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2374 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2375 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2376 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2378 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2379 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2380 !strcmp (bearer_type, "WIMAX")) {
2381 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2383 retval = MODEST_CONNECTED_VIA_ANY;
2386 g_object_unref (iap);
2389 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2390 #endif /* MODEST_HAVE_CONIC */
2397 modest_platform_check_memory_low (ModestWindow *win,
2402 /* are we in low memory state? */
2403 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2405 if (win && lowmem && visuals)
2406 modest_platform_run_information_dialog (
2408 _KR("memr_ib_operation_disabled"),
2412 g_debug ("%s: low memory reached. disallowing some operations",
2419 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2425 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2428 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2429 GTK_WINDOW (dialog),
2431 gtk_widget_show_all (dialog);
2433 g_signal_connect_swapped (dialog, "response",
2434 G_CALLBACK (gtk_widget_destroy),
2439 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2445 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2448 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2449 GTK_WINDOW (dialog),
2451 gtk_widget_show_all (dialog);
2453 g_signal_connect_swapped (dialog, "response",
2454 G_CALLBACK (gtk_widget_destroy),
2459 modest_platform_get_osso_context (void)
2461 return modest_maemo_utils_get_osso_context ();
2465 _modest_platform_play_email_tone (void)
2468 gint mail_volume_int;
2470 ca_context *ca_con = NULL;
2471 ca_proplist *pl = NULL;
2473 #ifdef MODEST_USE_PROFILE
2474 gchar *active_profile;
2477 active_profile = profile_get_profile ();
2478 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2479 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2480 mail_volume_int = profile_parse_int (mail_volume);
2481 g_free (mail_volume);
2482 g_free (active_profile);
2484 mail_tone = MAIL_TONE;
2485 mail_volume_int = 100;
2488 if (mail_tone && !strstr (mail_tone, "/")) {
2491 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2496 if (mail_volume_int > 0) {
2498 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2499 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2503 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2504 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2505 ca_context_destroy(ca_con);
2509 ca_proplist_create(&pl);
2510 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2511 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2513 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2514 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2516 ca_proplist_destroy(pl);
2517 ca_context_destroy(ca_con);
2523 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2524 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2525 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2526 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2527 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2528 #define MOVE_TO_FOLDER_SEPARATOR "/"
2531 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
2532 TnyFolderStore *folder_store)
2534 GtkWidget *action_button;
2535 GtkWidget *image = NULL;
2536 TnyAccount *account;
2537 gchar *account_name = NULL;
2539 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2541 /* Get account name */
2542 if (TNY_IS_FOLDER (folder_store))
2543 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2545 account = g_object_ref (folder_store);
2547 if (modest_tny_account_is_virtual_local_folders (account))
2548 account_name = modest_conf_get_string (modest_runtime_get_conf(),
2549 MODEST_CONF_DEVICE_NAME, NULL);
2552 account_name = g_strdup (tny_account_get_name (account));
2554 g_object_unref (account);
2556 /* Set title of button: account or folder name */
2557 if (TNY_IS_FOLDER (folder_store)) {
2558 hildon_button_set_title (HILDON_BUTTON (action_button),
2559 tny_folder_get_name (TNY_FOLDER (folder_store)));
2561 hildon_button_set_title (HILDON_BUTTON (action_button), account_name);
2564 /* Set value of button, folder full name */
2565 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
2566 gchar *full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
2567 tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store)),
2569 hildon_button_set_value (HILDON_BUTTON (action_button), full_name);
2572 g_free (account_name);
2574 /* Set image for the button */
2575 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
2577 hildon_button_set_image (HILDON_BUTTON (action_button), image);
2581 move_to_dialog_show_accounts (GtkWidget *dialog)
2583 GtkWidget *back_button;
2584 GtkWidget *folder_view;
2585 GtkWidget *pannable;
2586 GtkWidget *action_button;
2588 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2589 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2590 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2591 pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2593 gtk_widget_set_sensitive (back_button, FALSE);
2594 gtk_widget_set_sensitive (action_button, FALSE);
2596 /* Need to set this here, otherwise callbacks called because
2597 of filtering won't perform correctly */
2598 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2600 /* Reset action button */
2601 hildon_button_set_title (HILDON_BUTTON (action_button), NULL);
2602 hildon_button_set_value (HILDON_BUTTON (action_button), NULL);
2603 hildon_button_set_image (HILDON_BUTTON (action_button), NULL);
2605 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
2606 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2607 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2608 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2609 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2610 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2611 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2612 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2613 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2614 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2615 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2616 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2620 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2622 GtkWidget *back_button;
2623 GtkWidget *folder_view;
2624 TnyAccount *account;
2625 const gchar *account_id;
2626 GtkWidget *pannable;
2627 GtkWidget *action_button;
2630 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2632 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2634 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2636 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2638 gtk_widget_set_sensitive (back_button, TRUE);
2639 gtk_widget_set_sensitive (action_button, TRUE);
2641 /* Need to set this here, otherwise callbacks called because
2642 of filtering won't perform correctly */
2643 g_object_set_data (G_OBJECT (dialog),
2644 MOVE_TO_DIALOG_SHOWING_FOLDERS,
2645 GINT_TO_POINTER (TRUE));
2647 account = TNY_ACCOUNT (folder_store);
2648 if (modest_tny_account_is_virtual_local_folders (account)) {
2649 account_id = tny_account_get_id (account);
2650 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2651 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2652 } else if (modest_tny_account_is_memory_card_account (account)) {
2653 account_id = tny_account_get_id (account);
2654 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2655 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2657 account_id = tny_account_get_id (account);
2658 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2659 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2660 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2661 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2664 move_to_dialog_set_selected_folder_store (dialog, folder_store);
2665 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2668 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2669 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2670 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2671 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2672 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2676 on_move_to_dialog_back_clicked (GtkButton *button,
2679 GtkWidget *dialog = (GtkWidget *) userdata;
2681 /* Back to show accounts */
2682 move_to_dialog_show_accounts (dialog);
2686 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
2688 GtkTreeViewColumn *column,
2691 TnyFolderStore *selected = NULL;
2693 GtkWidget *folder_view;
2694 gboolean showing_folders;
2696 dialog = (GtkWidget *) user_data;
2697 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
2698 MOVE_TO_DIALOG_SHOWING_FOLDERS));
2700 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
2701 MOVE_TO_DIALOG_FOLDER_VIEW));
2703 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2707 if (!showing_folders) {
2708 gboolean valid = TRUE;
2710 if (TNY_IS_ACCOUNT (selected) &&
2711 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2712 ModestProtocolType protocol_type;
2714 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2715 valid = !modest_protocol_registry_protocol_type_has_tag
2716 (modest_runtime_get_protocol_registry (),
2718 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_MESSAGE_ADD);
2721 move_to_dialog_show_folders (dialog, selected);
2723 move_to_dialog_set_selected_folder_store (dialog, selected);
2728 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2731 gboolean showing_folders;
2734 dialog = (GtkWidget *) user_data;
2735 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2736 if (showing_folders) {
2737 TnyFolderStore *selected;
2738 GtkWidget *folder_view;
2740 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2741 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2744 move_to_dialog_set_selected_folder_store (dialog, selected);
2745 g_object_unref (selected);
2751 on_move_to_dialog_action_clicked (GtkButton *selection,
2754 TnyFolderStore *selected;
2756 GtkWidget *folder_view;
2757 gboolean showing_folders;
2759 dialog = (GtkWidget *) user_data;
2760 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2761 if (showing_folders) {
2762 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2763 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2766 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2771 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2772 GtkWidget **folder_view)
2774 GtkWidget *dialog, *folder_view_container;
2776 GtkWidget *buttons_hbox;
2777 GtkWidget *back_button;
2778 GdkPixbuf *back_pixbuf;
2779 GtkWidget *top_vbox;
2780 GtkWidget *action_button;
2781 GtkTreeSelection *selection;
2783 /* Create dialog. We cannot use a touch selector because we
2784 need to use here the folder view widget directly */
2785 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2786 GTK_WINDOW (parent_window),
2787 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2788 GTK_DIALOG_DESTROY_WITH_PARENT,
2789 _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2792 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2793 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2794 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2796 /* Create folder view */
2797 *folder_view = modest_platform_create_folder_view (NULL);
2799 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2800 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2801 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2803 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2804 (TnyAccountStore *) modest_runtime_get_account_store ());
2806 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2807 back_button = gtk_button_new ();
2808 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2810 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2811 g_object_unref (back_pixbuf);
2814 action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
2815 HILDON_BUTTON_ARRANGEMENT_VERTICAL);
2816 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2818 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2819 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2820 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2821 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2822 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2824 /* Create pannable and add it to the dialog */
2825 folder_view_container = hildon_pannable_area_new ();
2826 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2827 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2829 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2830 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2832 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2834 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2835 gtk_widget_show (folder_view_container);
2836 gtk_widget_show (align);
2837 gtk_widget_show (top_vbox);
2838 gtk_widget_show (*folder_view);
2839 gtk_widget_show_all (back_button);
2840 gtk_widget_show (action_button);
2841 gtk_widget_show (buttons_hbox);
2842 gtk_widget_show (dialog);
2844 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2845 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2846 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2847 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2849 /* Simulate the behaviour of a HildonPickerDialog by emitting
2850 a response when a folder is selected */
2851 g_signal_connect (*folder_view, "row-activated",
2852 G_CALLBACK (on_move_to_dialog_row_activated),
2855 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2856 g_signal_connect (selection, "changed",
2857 G_CALLBACK (on_move_to_dialog_selection_changed),
2860 g_signal_connect (action_button, "clicked",
2861 G_CALLBACK (on_move_to_dialog_action_clicked),
2864 g_signal_connect (back_button, "clicked",
2865 G_CALLBACK (on_move_to_dialog_back_clicked),
2868 move_to_dialog_show_accounts (dialog);
2874 modest_platform_get_list_to_move (ModestWindow *window)
2876 TnyList *list = NULL;
2878 if (MODEST_IS_HEADER_WINDOW (window)) {
2879 ModestHeaderView *header_view;
2881 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2882 list = modest_header_view_get_selected_headers (header_view);
2883 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2884 ModestFolderView *folder_view;
2885 TnyFolderStore *selected_folder;
2887 list = TNY_LIST (tny_simple_list_new ());
2888 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2889 selected_folder = modest_folder_view_get_selected (folder_view);
2890 if (selected_folder) {
2891 tny_list_prepend (list, G_OBJECT (selected_folder));
2892 g_object_unref (selected_folder);
2895 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2898 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2900 list = TNY_LIST (tny_simple_list_new ());
2901 tny_list_prepend (list, G_OBJECT (header));
2902 g_object_unref (header);
2905 g_return_val_if_reached (NULL);