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 <modest-utils.h>
43 #include <dbus_api/modest-dbus-callbacks.h>
44 #include <modest-osso-autosave-callbacks.h>
46 #include <tny-maemo-conic-device.h>
47 #include <tny-camel-folder.h>
48 #include <tny-simple-list.h>
49 #include <tny-merge-folder.h>
50 #include <tny-error.h>
51 #include <tny-folder.h>
52 #include <tny-account-store-view.h>
53 #include <gtk/gtkicontheme.h>
54 #include <gtk/gtkmenuitem.h>
55 #include <gtk/gtkmain.h>
56 #include <modest-text-utils.h>
57 #include "modest-tny-folder.h"
58 #include "modest-tny-account.h"
60 #include <libgnomevfs/gnome-vfs-mime-utils.h>
61 #include <modest-account-settings-dialog.h>
62 #include <modest-easysetup-wizard-dialog.h>
63 #include "modest-hildon2-sort-dialog.h"
64 #include <hildon/hildon.h>
66 #include "hildon2/modest-hildon2-details-dialog.h"
67 #include "hildon2/modest-hildon2-window-mgr.h"
68 #ifdef MODEST_USE_PROFILE
69 #include <keys_nokia.h>
70 #include <libprofile.h>
73 #include <modest-datetime-formatter.h>
74 #include "modest-header-window.h"
75 #include <modest-folder-window.h>
76 #include <modest-account-mgr.h>
77 #include <modest-account-mgr-helpers.h>
78 #include <modest-ui-constants.h>
79 #include <modest-selector-picker.h>
80 #include <modest-icon-names.h>
82 #ifdef MODEST_HAVE_MCE
83 #include <mce/dbus-names.h>
84 #endif /*MODEST_HAVE_MCE*/
86 #ifdef MODEST_HAVE_ABOOK
87 #include <libosso-abook/osso-abook.h>
88 #endif /*MODEST_HAVE_ABOOK*/
90 #ifdef MODEST_HAVE_LIBALARM
91 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
92 #endif /*MODEST_HAVE_LIBALARM*/
95 #define HILDON_OSSO_URI_ACTION "uri-action"
96 #define URI_ACTION_COPY "copy:"
97 #define MODEST_NOTIFICATION_CATEGORY "email-message"
98 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
99 #ifdef MODEST_USE_PROFILE
100 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
101 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
103 #define MAIL_TONE "message-new-email"
106 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
107 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
108 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
109 #define MODEST_ALARMD_APPID PACKAGE_NAME
112 static void _modest_platform_play_email_tone (void);
116 on_modest_conf_update_interval_changed (ModestConf* self,
118 ModestConfEvent event,
119 ModestConfNotificationId id,
122 g_return_if_fail (key);
124 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
125 const guint update_interval_minutes =
126 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
127 modest_platform_set_update_interval (update_interval_minutes);
134 check_required_files (void)
136 FILE *mcc_file = modest_utils_open_mcc_mapping_file (NULL);
138 g_printerr ("modest: check for mcc file failed\n");
143 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
144 access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
145 g_printerr ("modest: cannot find providers data\n");
153 /* the gpointer here is the osso_context. */
155 modest_platform_init (int argc, char *argv[])
157 osso_context_t *osso_context;
159 osso_hw_state_t hw_state = { 0 };
163 if (!check_required_files ()) {
164 g_printerr ("modest: missing required files\n");
168 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
171 g_printerr ("modest: failed to acquire osso context\n");
174 modest_maemo_utils_set_osso_context (osso_context);
176 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
177 g_printerr ("modest: could not get dbus connection\n");
181 /* Add a D-Bus handler to be used when the main osso-rpc
182 * D-Bus handler has not handled something.
183 * We use this for D-Bus methods that need to use more complex types
184 * than osso-rpc supports.
186 if (!dbus_connection_add_filter (con,
187 modest_dbus_req_filter,
191 g_printerr ("modest: Could not add D-Bus filter\n");
195 /* Register our simple D-Bus callbacks, via the osso API: */
196 osso_return_t result = osso_rpc_set_cb_f(osso_context,
200 modest_dbus_req_handler, NULL /* user_data */);
201 if (result != OSSO_OK) {
202 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
206 /* Register hardware event dbus callback: */
207 hw_state.shutdown_ind = TRUE;
208 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
210 /* Register osso auto-save callbacks: */
211 result = osso_application_set_autosave_cb (osso_context,
212 modest_on_osso_application_autosave, NULL /* user_data */);
213 if (result != OSSO_OK) {
214 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
219 /* Make sure that the update interval is changed whenever its gconf key
221 /* CAUTION: we're not using here the
222 modest_conf_listen_to_namespace because we know that there
223 are other parts of Modest listening for this namespace, so
224 we'll receive the notifications anyway. We basically do not
225 use it because there is no easy way to do the
226 modest_conf_forget_namespace */
227 ModestConf *conf = modest_runtime_get_conf ();
228 g_signal_connect (G_OBJECT(conf),
230 G_CALLBACK (on_modest_conf_update_interval_changed),
233 /* only force the setting of the default interval, if there are actually
235 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
237 /* Get the initial update interval from gconf: */
238 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
239 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
240 modest_account_mgr_free_account_names (acc_names);
244 #ifdef MODEST_HAVE_ABOOK
245 /* initialize the addressbook */
246 if (!osso_abook_init (&argc, &argv, osso_context)) {
247 g_printerr ("modest: failed to initialized addressbook\n");
250 #endif /*MODEST_HAVE_ABOOK*/
256 modest_platform_uninit (void)
258 osso_context_t *osso_context =
259 modest_maemo_utils_get_osso_context ();
261 osso_deinitialize (osso_context);
270 modest_platform_get_new_device (void)
272 return TNY_DEVICE (tny_maemo_conic_device_new ());
276 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
277 gchar **effective_mime_type)
279 GString *mime_str = NULL;
280 gchar *icon_name = NULL;
281 gchar **icons, **cursor;
283 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
284 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
286 mime_str = g_string_new (mime_type);
287 g_string_ascii_down (mime_str);
290 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
292 for (cursor = icons; cursor; ++cursor) {
293 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
294 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
295 icon_name = g_strdup ("qgn_list_messagin");
297 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
298 icon_name = g_strdup (*cursor);
304 if (effective_mime_type)
305 *effective_mime_type = g_string_free (mime_str, FALSE);
307 g_string_free (mime_str, TRUE);
314 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
319 g_return_val_if_fail (uri, FALSE);
321 result = hildon_uri_open (uri, action, &err);
323 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
324 uri, action, err && err->message ? err->message : "unknown error");
334 modest_platform_activate_uri (const gchar *uri)
336 HildonURIAction *action;
337 gboolean result = FALSE;
338 GSList *actions, *iter = NULL;
340 g_return_val_if_fail (uri, FALSE);
344 /* don't try to activate file: uri's -- they might confuse the user,
345 * and/or might have security implications */
346 if (!g_str_has_prefix (uri, "file:")) {
348 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
350 for (iter = actions; iter; iter = g_slist_next (iter)) {
351 action = (HildonURIAction*) iter->data;
352 if (action && strcmp (hildon_uri_action_get_service (action),
353 "com.nokia.modest") == 0) {
354 result = checked_hildon_uri_open (uri, action);
359 /* if we could not open it with email, try something else */
361 result = checked_hildon_uri_open (uri, NULL);
365 ModestWindow *parent =
366 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
367 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
368 _("mcen_ib_unsupported_link"));
369 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
376 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
380 gchar *uri_path = NULL;
382 uri_path = gnome_vfs_get_uri_from_local_path (path);
383 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
386 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
388 result = hildon_mime_open_file (con, uri_path);
390 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
398 } ModestPlatformPopupInfo;
401 delete_uri_popup (GtkWidget *menu,
405 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
407 g_free (popup_info->uri);
408 hildon_uri_free_actions (popup_info->actions);
414 activate_uri_popup_item (GtkMenuItem *menu_item,
418 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
419 const gchar* action_name;
421 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
423 g_printerr ("modest: no action name defined\n");
427 /* special handling for the copy menu item -- copy the uri to the clipboard */
428 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
429 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
430 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
431 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
433 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
434 action_name += strlen ("mailto:");
436 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
437 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
438 return; /* we're done */
441 /* now, the real uri-actions... */
442 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
443 HildonURIAction *action = (HildonURIAction *) node->data;
444 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
445 if (!checked_hildon_uri_open (popup_info->uri, action)) {
446 ModestWindow *parent =
447 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
448 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
449 _("mcen_ib_unsupported_link"));
457 modest_platform_show_uri_popup (const gchar *uri)
459 GSList *actions_list;
464 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
467 GtkWidget *menu = gtk_menu_new ();
468 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
470 /* don't add actions for file: uri's -- they might confuse the user,
471 * and/or might have security implications
472 * we still allow to copy the url though
474 if (!g_str_has_prefix (uri, "file:")) {
477 popup_info->actions = actions_list;
478 popup_info->uri = g_strdup (uri);
480 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
481 GtkWidget *menu_item;
482 const gchar *action_name;
483 const gchar *translation_domain;
484 HildonURIAction *action = (HildonURIAction *) node->data;
485 action_name = hildon_uri_action_get_name (action);
486 translation_domain = hildon_uri_action_get_translation_domain (action);
487 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
488 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
489 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
492 if (hildon_uri_is_default_action (action, NULL)) {
493 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
495 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
497 gtk_widget_show (menu_item);
502 /* and what to do when the link is deleted */
503 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
504 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
507 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
515 modest_platform_get_icon (const gchar *name, guint icon_size)
518 GdkPixbuf* pixbuf = NULL;
519 GtkIconTheme *current_theme = NULL;
521 g_return_val_if_fail (name, NULL);
523 /* strlen == 0 is not really an error; it just
524 * means the icon is not available
526 if (!name || strlen(name) == 0)
529 current_theme = gtk_icon_theme_get_default ();
530 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
531 GTK_ICON_LOOKUP_NO_SVG,
534 g_printerr ("modest: error loading theme icon '%s': %s\n",
542 modest_platform_get_app_name (void)
544 return _("mcen_ap_name");
548 entry_insert_text (GtkEditable *editable,
557 chars = gtk_editable_get_chars (editable, 0, -1);
558 chars_length = g_utf8_strlen (chars, -1);
561 /* Show WID-INF036 */
562 if (chars_length >= 20) {
563 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
564 _CS("ckdg_ib_maximum_characters_reached"));
566 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
570 tmp = g_strndup (folder_name_forbidden_chars,
571 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
572 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
573 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
579 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
580 _CS("ckdg_ib_maximum_characters_reached"));
582 /* Write the text in the entry if it's valid */
583 g_signal_handlers_block_by_func (editable,
584 (gpointer) entry_insert_text, data);
585 gtk_editable_insert_text (editable, text, length, position);
586 g_signal_handlers_unblock_by_func (editable,
587 (gpointer) entry_insert_text, data);
590 /* Do not allow further processing */
591 g_signal_stop_emission_by_name (editable, "insert_text");
595 entry_changed (GtkEditable *editable,
599 GtkWidget *ok_button;
602 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
603 ok_button = GTK_WIDGET (buttons->data);
605 chars = gtk_editable_get_chars (editable, 0, -1);
606 g_return_if_fail (chars != NULL);
609 if (g_utf8_strlen (chars,-1) >= 20) {
610 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
611 _CS("ckdg_ib_maximum_characters_reached"));
613 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
616 g_list_free (buttons);
623 on_response (GtkDialog *dialog,
627 GtkWidget *entry, *picker;
628 TnyFolderStore *parent;
629 const gchar *new_name;
632 if (response != GTK_RESPONSE_ACCEPT)
636 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
637 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
639 parent = TNY_FOLDER_STORE (user_data);
640 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
644 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
646 /* Look for another folder with the same name */
647 if (modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
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),
661 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
662 NULL, _CS("ckdg_ib_folder_already_exists"));
663 /* Select the text */
664 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
665 gtk_widget_grab_focus (entry);
666 /* Do not close the dialog */
667 g_signal_stop_emission_by_name (dialog, "response");
671 typedef struct _FolderChooserData {
672 TnyFolderStore *store;
677 folder_chooser_activated (ModestFolderView *folder_view,
678 TnyFolderStore *folder,
679 FolderChooserData *userdata)
681 userdata->store = folder;
682 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
685 static TnyFolderStore *
686 folder_chooser_dialog_run (ModestFolderView *original)
688 GtkWidget *folder_view;
689 FolderChooserData userdata = {NULL, NULL};
691 const gchar *visible_id = NULL;
693 userdata.dialog = hildon_dialog_new ();
694 pannable = hildon_pannable_area_new ();
695 folder_view = modest_platform_create_folder_view (NULL);
697 gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
699 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
700 MODEST_FOLDER_VIEW (folder_view));
703 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
704 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
707 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
708 gtk_container_add (GTK_CONTAINER (pannable), folder_view);
709 gtk_widget_set_size_request (pannable, -1, 320);
711 gtk_widget_show (folder_view);
712 gtk_widget_show (pannable);
713 gtk_widget_show (userdata.dialog);
714 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
715 G_CALLBACK (folder_chooser_activated),
716 (gpointer) &userdata);
718 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
719 gtk_widget_destroy (userdata.dialog);
721 return userdata.store;
725 folder_store_get_display_name (TnyFolderStore *store)
727 if (TNY_IS_ACCOUNT (store)) {
728 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
729 return modest_conf_get_string (modest_runtime_get_conf(),
730 MODEST_CONF_DEVICE_NAME, NULL);
732 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
735 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
737 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
738 type = tny_folder_get_folder_type (TNY_FOLDER (store));
739 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
740 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
741 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
742 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
744 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
747 /* Sometimes an special folder is reported by the server as
748 NORMAL, like some versions of Dovecot */
749 if (type == TNY_FOLDER_TYPE_NORMAL ||
750 type == TNY_FOLDER_TYPE_UNKNOWN) {
751 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
755 if (type == TNY_FOLDER_TYPE_INBOX) {
757 fname = g_strdup (_("mcen_me_folder_inbox"));
764 get_image_for_folder_store (TnyFolderStore *store,
768 const gchar *icon_name = NULL;
769 GtkWidget *image = NULL;
771 if (TNY_IS_ACCOUNT (store)) {
772 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
773 icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
774 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
775 icon_name = MODEST_FOLDER_ICON_MMC;
777 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
779 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
780 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
782 case TNY_FOLDER_TYPE_INBOX:
783 icon_name = MODEST_FOLDER_ICON_INBOX;
786 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
788 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
790 case TNY_FOLDER_TYPE_OUTBOX:
791 icon_name = MODEST_FOLDER_ICON_OUTBOX;
793 case TNY_FOLDER_TYPE_DRAFTS:
794 icon_name = MODEST_FOLDER_ICON_DRAFTS;
796 case TNY_FOLDER_TYPE_SENT:
797 icon_name = MODEST_FOLDER_ICON_SENT;
800 icon_name = MODEST_FOLDER_ICON_NORMAL;
802 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
803 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
808 pixbuf = modest_platform_get_icon (icon_name, size);
811 image = gtk_image_new_from_pixbuf (pixbuf);
812 g_object_unref (pixbuf);
819 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
824 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
828 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
829 g_object_ref (store),
830 (GDestroyNotify) g_object_unref);
831 name = folder_store_get_display_name (store);
832 hildon_button_set_value (HILDON_BUTTON (button), name);
836 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
838 hildon_button_set_image (HILDON_BUTTON (button), image);
842 /* Always returns DUPs so you must free the returned value */
844 get_next_folder_name (const gchar *suggested_name,
845 TnyFolderStore *suggested_folder)
847 const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
849 gchar *real_suggested_name;
851 if (suggested_name !=NULL) {
852 return g_strdup (suggested_name);
855 for(i = 0; i < 100; ++ i) {
856 gboolean exists = FALSE;
859 real_suggested_name = g_strdup (default_name);
861 real_suggested_name = g_strdup_printf ("%s(%d)",
862 _FM("ckdg_va_new_folder_name_stub"),
864 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
871 g_free (real_suggested_name);
874 /* Didn't find a free number */
876 real_suggested_name = g_strdup (default_name);
878 return real_suggested_name;
882 ModestFolderView *folder_view;
884 } FolderPickerHelper;
887 folder_picker_clicked (GtkButton *button,
888 FolderPickerHelper *helper)
890 TnyFolderStore *store;
892 store = folder_chooser_dialog_run (helper->folder_view);
894 const gchar *current_name;
897 folder_picker_set_store (GTK_BUTTON (button), store);
899 /* Update the name of the folder */
900 current_name = gtk_entry_get_text (helper->entry);
901 exists = modest_tny_folder_has_subfolder_with_name (store,
905 gchar *new_name = get_next_folder_name (NULL, store);
906 gtk_entry_set_text (helper->entry, new_name);
913 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
917 button = hildon_button_new (MODEST_EDITABLE_SIZE,
918 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
920 hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
923 folder_picker_set_store (GTK_BUTTON (button), suggested);
925 g_signal_connect (G_OBJECT (button), "clicked",
926 G_CALLBACK (folder_picker_clicked),
934 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
935 TnyFolderStore *suggested_parent,
936 const gchar *dialog_title,
937 const gchar *label_text,
938 const gchar *suggested_name,
940 gboolean show_parent,
942 TnyFolderStore **parent)
944 GtkWidget *accept_btn = NULL;
945 GtkWidget *dialog, *entry = NULL, *label_entry = NULL, *label_location = NULL, *hbox;
946 GtkWidget *account_picker = NULL;
947 GList *buttons = NULL;
949 GtkSizeGroup *sizegroup;
950 ModestFolderView *folder_view;
951 ModestWindow *folder_window;
952 ModestHildon2WindowMgr *window_mgr;
953 FolderPickerHelper *helper = NULL;
954 GtkWidget *top_vbox, *top_align;
956 window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
957 folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
958 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
960 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
962 top_vbox = gtk_vbox_new (FALSE, 0);
963 top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
964 gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
966 /* Ask the user for the folder name */
967 dialog = gtk_dialog_new_with_buttons (dialog_title,
969 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
970 _FM("ckdg_bd_new_folder_dialog_ok"),
974 /* Add accept button (with unsensitive handler) */
975 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
976 accept_btn = GTK_WIDGET (buttons->data);
978 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
981 label_entry = gtk_label_new (label_text);
982 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
983 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
985 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
986 gtk_size_group_add_widget (sizegroup, label_entry);
989 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
991 gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
992 gtk_entry_set_width_chars (GTK_ENTRY (entry),
993 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
994 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
995 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
1000 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
1002 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
1003 gtk_size_group_add_widget (sizegroup, label_location);
1005 helper = g_slice_new0 (FolderPickerHelper);
1006 helper->folder_view = folder_view;
1007 helper->entry = (GtkEntry *) entry;
1009 account_picker = folder_picker_new (suggested_parent, helper);
1012 g_object_unref (sizegroup);
1014 /* Connect to the response method to avoid closing the dialog
1015 when an invalid name is selected*/
1016 g_signal_connect (dialog,
1018 G_CALLBACK (on_response),
1022 /* Track entry changes */
1023 g_signal_connect (entry,
1025 G_CALLBACK (entry_insert_text),
1027 g_signal_connect (entry,
1029 G_CALLBACK (entry_changed),
1034 /* Some locales like pt_BR need this to get the full window
1036 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
1038 /* Create the hbox */
1040 hbox = gtk_hbox_new (FALSE, 12);
1041 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
1042 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
1044 /* Add hbox to dialog */
1045 gtk_box_pack_start (GTK_BOX (top_vbox),
1046 hbox, FALSE, FALSE, 0);
1047 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
1051 hbox = gtk_hbox_new (FALSE, 12);
1052 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
1053 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
1055 /* Add hbox to dialog */
1056 gtk_box_pack_start (GTK_BOX (top_vbox),
1057 hbox, FALSE, FALSE, 0);
1058 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
1060 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1061 GTK_WINDOW (dialog), parent_window);
1063 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
1064 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
1066 gtk_widget_show_all (GTK_WIDGET(dialog));
1068 result = gtk_dialog_run (GTK_DIALOG(dialog));
1069 if (result == GTK_RESPONSE_ACCEPT) {
1071 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1073 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
1075 g_object_ref (*parent);
1079 gtk_widget_destroy (dialog);
1082 g_slice_free (FolderPickerHelper, helper);
1084 while (gtk_events_pending ())
1085 gtk_main_iteration ();
1091 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
1092 TnyFolderStore *suggested_folder,
1093 gchar *suggested_name,
1094 gchar **folder_name,
1095 TnyFolderStore **parent_folder)
1097 gchar *real_suggested_name = NULL;
1099 ModestTnyAccountStore *acc_store;
1100 TnyAccount *account;
1101 gboolean do_free = FALSE;
1103 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
1106 /* In hildon 2.2 we always suggest the archive folder as parent */
1107 acc_store = modest_runtime_get_account_store ();
1108 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1110 suggested_folder = (TnyFolderStore *)
1111 modest_tny_account_get_special_folder (account,
1112 TNY_FOLDER_TYPE_ARCHIVE);
1113 g_object_unref (account);
1117 /* If there is not archive folder then fallback to local folders account */
1118 if (!suggested_folder) {
1120 suggested_folder = (TnyFolderStore *)
1121 modest_tny_account_store_get_local_folders_account (acc_store);
1124 result = modest_platform_run_folder_common_dialog (parent_window,
1126 _HL("ckdg_ti_new_folder"),
1127 _FM("ckdg_fi_new_folder_name"),
1128 real_suggested_name,
1135 g_object_unref (suggested_folder);
1137 g_free(real_suggested_name);
1143 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1144 TnyFolderStore *parent_folder,
1145 const gchar *suggested_name,
1146 gchar **folder_name)
1148 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1150 return modest_platform_run_folder_common_dialog (parent_window,
1152 _HL("ckdg_ti_rename_folder"),
1153 _HL("ckdg_fi_rename_name"),
1164 on_destroy_dialog (GtkWidget *dialog)
1166 /* This could happen when the dialogs get programatically
1167 hidden or destroyed (for example when closing the
1168 application while a dialog is being shown) */
1169 if (!GTK_IS_WIDGET (dialog))
1172 gtk_widget_destroy (dialog);
1174 if (gtk_events_pending ())
1175 gtk_main_iteration ();
1179 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1180 const gchar *message)
1185 dialog = hildon_note_new_confirmation (parent_window, message);
1186 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1187 GTK_WINDOW (dialog), parent_window);
1189 response = gtk_dialog_run (GTK_DIALOG (dialog));
1191 on_destroy_dialog (dialog);
1197 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1198 const gchar *message,
1199 const gchar *button_accept,
1200 const gchar *button_cancel)
1205 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1206 button_accept, GTK_RESPONSE_ACCEPT,
1207 button_cancel, GTK_RESPONSE_CANCEL,
1210 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1211 GTK_WINDOW (dialog), parent_window);
1213 response = gtk_dialog_run (GTK_DIALOG (dialog));
1215 on_destroy_dialog (dialog);
1221 modest_platform_run_information_dialog (GtkWindow *parent_window,
1222 const gchar *message,
1227 note = hildon_note_new_information (parent_window, message);
1229 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1230 GTK_WINDOW (note), parent_window);
1233 gtk_dialog_run (GTK_DIALOG (note));
1235 on_destroy_dialog (note);
1237 g_signal_connect_swapped (note,
1239 G_CALLBACK (on_destroy_dialog),
1242 gtk_widget_show_all (note);
1246 typedef struct _ConnectAndWaitData {
1248 GMainLoop *wait_loop;
1249 gboolean has_callback;
1251 } ConnectAndWaitData;
1255 quit_wait_loop (TnyAccount *account,
1256 ConnectAndWaitData *data)
1258 /* Set the has_callback to TRUE (means that the callback was
1259 executed and wake up every code waiting for cond to be
1261 g_mutex_lock (data->mutex);
1262 data->has_callback = TRUE;
1263 if (data->wait_loop)
1264 g_main_loop_quit (data->wait_loop);
1265 g_mutex_unlock (data->mutex);
1269 on_connection_status_changed (TnyAccount *account,
1270 TnyConnectionStatus status,
1273 TnyConnectionStatus conn_status;
1274 ConnectAndWaitData *data;
1276 /* Ignore if reconnecting or disconnected */
1277 conn_status = tny_account_get_connection_status (account);
1278 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1279 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1282 /* Remove the handler */
1283 data = (ConnectAndWaitData *) user_data;
1284 g_signal_handler_disconnect (account, data->handler);
1286 /* Quit from wait loop */
1287 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1291 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1296 /* Quit from wait loop */
1297 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1301 modest_platform_connect_and_wait (GtkWindow *parent_window,
1302 TnyAccount *account)
1304 ConnectAndWaitData *data = NULL;
1305 gboolean device_online;
1307 TnyConnectionStatus conn_status;
1308 gboolean user_requested;
1310 device = modest_runtime_get_device();
1311 device_online = tny_device_is_online (device);
1313 /* Whether the connection is user requested or automatically
1314 requested, for example via D-Bus */
1315 user_requested = (parent_window) ? TRUE : FALSE;
1317 /* If there is no account check only the device status */
1322 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1323 NULL, user_requested);
1326 /* Return if the account is already connected */
1327 conn_status = tny_account_get_connection_status (account);
1328 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1331 /* Create the helper */
1332 data = g_slice_new0 (ConnectAndWaitData);
1333 data->mutex = g_mutex_new ();
1334 data->has_callback = FALSE;
1336 /* Connect the device */
1337 if (!device_online) {
1338 /* Track account connection status changes */
1339 data->handler = g_signal_connect (account, "connection-status-changed",
1340 G_CALLBACK (on_connection_status_changed),
1342 /* Try to connect the device */
1343 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1344 NULL, user_requested);
1346 /* If the device connection failed then exit */
1347 if (!device_online && data->handler)
1350 /* Force a reconnection of the account */
1351 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1352 on_tny_camel_account_set_online_cb, data);
1355 /* Wait until the callback is executed */
1356 g_mutex_lock (data->mutex);
1357 if (!data->has_callback) {
1358 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1359 gdk_threads_leave ();
1360 g_mutex_unlock (data->mutex);
1361 g_main_loop_run (data->wait_loop);
1362 g_mutex_lock (data->mutex);
1363 gdk_threads_enter ();
1365 g_mutex_unlock (data->mutex);
1368 if (g_signal_handler_is_connected (account, data->handler))
1369 g_signal_handler_disconnect (account, data->handler);
1370 g_mutex_free (data->mutex);
1371 g_main_loop_unref (data->wait_loop);
1372 g_slice_free (ConnectAndWaitData, data);
1374 conn_status = tny_account_get_connection_status (account);
1375 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1379 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1381 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1382 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1383 /* This must be a maildir account, which does not require a connection: */
1388 return modest_platform_connect_and_wait (parent_window, account);
1392 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1395 return TRUE; /* Maybe it is something local. */
1397 gboolean result = TRUE;
1398 if (TNY_IS_FOLDER (folder_store)) {
1399 /* Get the folder's parent account: */
1400 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1401 if (account != NULL) {
1402 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1403 g_object_unref (account);
1405 } else if (TNY_IS_ACCOUNT (folder_store)) {
1406 /* Use the folder store as an account: */
1407 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1414 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1418 dialog = modest_hildon2_sort_dialog_new (parent_window);
1425 modest_platform_set_update_interval (guint minutes)
1427 #ifdef MODEST_HAVE_LIBALARM
1429 ModestConf *conf = modest_runtime_get_conf ();
1433 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1435 /* Delete any existing alarm,
1436 * because we will replace it: */
1438 if (alarmd_event_del(alarm_cookie) != 0)
1439 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1441 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1444 /* 0 means no updates: */
1449 /* Register alarm: */
1451 /* Set the interval in alarm_event_t structure: */
1452 alarm_event_t *event = alarm_event_create ();
1453 alarm_event_add_actions (event, 1);
1454 alarm_action_t *action = alarm_event_get_action (event, 0);
1455 alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1456 event->alarm_time = minutes * 60; /* seconds */
1458 /* Set recurrence every few minutes: */
1459 event->recur_secs = minutes*60;
1460 event->recur_count = -1; /* Means infinite */
1462 /* Specify what should happen when the alarm happens:
1463 * It should call this D-Bus method: */
1465 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1466 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1467 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1468 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1469 action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1471 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1472 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1473 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1474 * This is why we want to use the Alarm API instead of just g_timeout_add().
1475 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1476 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1478 event->flags = ALARM_EVENT_CONNECTED;
1480 alarm_cookie = alarmd_event_add (event);
1483 alarm_event_delete (event);
1485 /* Store the alarm ID in GConf, so we can remove it later:
1486 * This is apparently valid between application instances. */
1487 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1489 if (!alarm_cookie) {
1491 g_debug ("Error setting alarm event. \n");
1495 #endif /* MODEST_HAVE_LIBALARM */
1500 modest_platform_push_email_notification(void)
1502 gboolean screen_on, app_in_foreground;
1504 /* Get the window status */
1505 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1507 screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1509 /* If the screen is on and the app is in the
1510 foreground we don't show anything */
1511 if (!(screen_on && app_in_foreground)) {
1513 _modest_platform_play_email_tone ();
1515 /* Activate LED. This must be deactivated by
1516 modest_platform_remove_new_mail_notifications */
1517 #ifdef MODEST_HAVE_MCE
1518 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1522 MCE_ACTIVATE_LED_PATTERN,
1524 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1531 modest_platform_on_new_headers_received (TnyList *header_list,
1532 gboolean show_visual)
1534 g_return_if_fail (TNY_IS_LIST(header_list));
1536 if (tny_list_get_length(header_list) == 0) {
1537 g_warning ("%s: header list is empty", __FUNCTION__);
1542 modest_platform_push_email_notification ();
1543 /* We do a return here to avoid indentation with an else */
1547 #ifdef MODEST_HAVE_HILDON_NOTIFY
1548 HildonNotification *notification;
1550 GSList *notifications_list = NULL;
1552 /* Get previous notifications ids */
1553 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1554 MODEST_CONF_NOTIFICATION_IDS,
1555 MODEST_CONF_VALUE_INT, NULL);
1557 iter = tny_list_create_iterator (header_list);
1558 while (!tny_iterator_is_done (iter)) {
1559 gchar *url = NULL, *display_address = NULL;
1560 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1561 TnyFolder *folder = tny_header_get_folder (header);
1562 gboolean first_notification = TRUE;
1566 display_address = tny_header_dup_from (header);
1567 /* string is changed in-place */
1568 modest_text_utils_get_display_address (display_address);
1570 str = tny_header_dup_subject (header);
1571 notification = hildon_notification_new (display_address,
1573 "qgn_list_messagin",
1574 MODEST_NOTIFICATION_CATEGORY);
1576 /* Create the message URL */
1577 str = tny_header_dup_uid (header);
1578 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1582 hildon_notification_add_dbus_action(notification,
1585 MODEST_DBUS_SERVICE,
1588 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1592 /* Play sound if the user wants. Show the LED
1593 pattern. Show and play just one */
1594 if (G_UNLIKELY (first_notification)) {
1595 TnyAccount *account;
1597 first_notification = FALSE;
1599 /* Set the led pattern */
1600 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1602 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1604 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1606 /* Set the account of the headers */
1607 account = tny_folder_get_account (folder);
1609 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1611 tny_account_get_id (account));
1612 g_object_unref (account);
1616 /* Notify. We need to do this in an idle because this function
1617 could be called from a thread */
1618 if (!notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1619 g_warning ("Failed to send notification");
1622 /* Save id in the list */
1623 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1624 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1625 /* We don't listen for the "closed" signal, because we
1626 don't care about if the notification was removed or
1627 not to store the list in gconf */
1629 /* Free & carry on */
1630 g_free (display_address);
1632 g_object_unref (folder);
1633 g_object_unref (header);
1634 tny_iterator_next (iter);
1636 g_object_unref (iter);
1639 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1640 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1642 g_slist_free (notifications_list);
1644 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1648 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1651 #ifdef MODEST_HAVE_MCE
1652 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1656 MCE_DEACTIVATE_LED_PATTERN,
1658 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1664 #ifdef MODEST_HAVE_HILDON_NOTIFY
1665 GSList *notif_list = NULL;
1667 /* Get previous notifications ids */
1668 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1669 MODEST_CONF_NOTIFICATION_IDS,
1670 MODEST_CONF_VALUE_INT, NULL);
1672 while (notif_list) {
1674 NotifyNotification *notif;
1676 /* Nasty HACK to remove the notifications, set the id
1677 of the existing ones and then close them */
1678 notif_id = GPOINTER_TO_INT(notif_list->data);
1679 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1680 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1682 /* Close the notification, note that some ids could be
1683 already invalid, but we don't care because it does
1685 notify_notification_close(notif, NULL);
1686 g_object_unref(notif);
1688 /* Delete the link, it's like going to the next */
1689 notif_list = g_slist_delete_link (notif_list, notif_list);
1693 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1694 notif_list, MODEST_CONF_VALUE_INT, NULL);
1696 g_slist_free (notif_list);
1698 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1704 modest_platform_get_global_settings_dialog ()
1706 return modest_hildon2_global_settings_dialog_new ();
1710 modest_platform_show_help (GtkWindow *parent_window,
1711 const gchar *help_id)
1717 modest_platform_show_search_messages (GtkWindow *parent_window)
1719 osso_return_t result = OSSO_ERROR;
1721 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1722 "osso_global_search",
1723 "search_email", NULL, DBUS_TYPE_INVALID);
1725 if (result != OSSO_OK) {
1726 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1731 modest_platform_show_addressbook (GtkWindow *parent_window)
1733 osso_return_t result = OSSO_ERROR;
1735 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1737 "top_application", NULL, DBUS_TYPE_INVALID);
1739 if (result != OSSO_OK) {
1740 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1745 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1747 GtkWidget *widget = modest_folder_view_new (query);
1749 /* Show one account by default */
1750 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1751 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1753 /* Restore settings */
1754 modest_widget_memory_restore (modest_runtime_get_conf(),
1756 MODEST_CONF_FOLDER_VIEW_KEY);
1762 banner_finish (gpointer data, GObject *object)
1764 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1765 modest_window_mgr_unregister_banner (mgr);
1766 g_object_unref (mgr);
1770 modest_platform_information_banner (GtkWidget *parent,
1771 const gchar *icon_name,
1774 GtkWidget *banner, *banner_parent = NULL;
1775 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1777 if (modest_window_mgr_get_num_windows (mgr) == 0)
1780 if (parent && GTK_IS_WINDOW (parent)) {
1781 /* If the window is the active one then show the
1782 banner on top of this window */
1783 if (gtk_window_is_active (GTK_WINDOW (parent)))
1784 banner_parent = parent;
1785 /* If the window is not the topmost but it's visible
1786 (it's minimized for example) then show the banner
1788 else if (GTK_WIDGET_VISIBLE (parent))
1789 banner_parent = NULL;
1790 /* If the window is hidden (like the main window when
1791 running in the background) then do not show
1798 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1800 modest_window_mgr_register_banner (mgr);
1802 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1806 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1807 const gchar *icon_name,
1813 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1816 banner = hildon_banner_show_information (parent, icon_name, text);
1817 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1821 modest_platform_animation_banner (GtkWidget *parent,
1822 const gchar *animation_name,
1825 GtkWidget *inf_note = NULL;
1827 g_return_val_if_fail (text != NULL, NULL);
1829 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1832 /* If the parent is not visible then do not show */
1833 if (parent && !GTK_WIDGET_VISIBLE (parent))
1836 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1844 TnyAccount *account;
1847 } CheckAccountIdleData;
1849 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1852 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1854 gboolean stop_trying = FALSE;
1855 g_return_val_if_fail (data && data->account, FALSE);
1857 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1858 tny_account_get_connection_status (data->account));
1860 if (data && data->account &&
1861 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1862 * after which the account is likely to be usable, or never likely to be usable soon: */
1863 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1865 data->is_online = TRUE;
1869 /* Give up if we have tried too many times: */
1870 if (data->count_tries >= NUMBER_OF_TRIES) {
1873 /* Wait for another timeout: */
1874 ++(data->count_tries);
1879 /* Allow the function that requested this idle callback to continue: */
1881 g_main_loop_quit (data->loop);
1884 g_object_unref (data->account);
1886 return FALSE; /* Don't call this again. */
1888 return TRUE; /* Call this timeout callback again. */
1892 /* Return TRUE immediately if the account is already online,
1893 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1894 * soon as the account is online, or FALSE if the account does
1895 * not become online in the NUMBER_OF_TRIES seconds.
1896 * This is useful when the D-Bus method was run immediately after
1897 * the application was started (when using D-Bus activation),
1898 * because the account usually takes a short time to go online.
1899 * The return value is maybe not very useful.
1902 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1906 g_return_val_if_fail (account, FALSE);
1908 if (!tny_device_is_online (modest_runtime_get_device())) {
1909 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1913 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1914 * so we avoid wait unnecessarily: */
1915 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1918 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1919 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1920 * we want to avoid. */
1921 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1924 /* This blocks on the result: */
1925 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1926 data->is_online = FALSE;
1927 data->account = account;
1928 g_object_ref (data->account);
1929 data->count_tries = 0;
1931 GMainContext *context = NULL; /* g_main_context_new (); */
1932 data->loop = g_main_loop_new (context, FALSE /* not running */);
1934 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1936 /* This main loop will run until the idle handler has stopped it: */
1937 g_main_loop_run (data->loop);
1939 g_main_loop_unref (data->loop);
1940 /* g_main_context_unref (context); */
1942 is_online = data->is_online;
1943 g_slice_free (CheckAccountIdleData, data);
1951 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1953 /* GTK_RESPONSE_HELP means we need to show the certificate */
1954 if (response_id == GTK_RESPONSE_APPLY) {
1958 /* Do not close the dialog */
1959 g_signal_stop_emission_by_name (dialog, "response");
1961 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1962 note = hildon_note_new_information (NULL, msg);
1963 gtk_dialog_run (GTK_DIALOG(note));
1964 gtk_widget_destroy (note);
1970 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1971 const gchar *certificate)
1976 HildonWindowStack *stack;
1978 stack = hildon_window_stack_get_default ();
1979 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1982 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1987 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1990 /* We use GTK_RESPONSE_APPLY because we want the button in the
1991 middle of OK and CANCEL the same as the browser does for
1992 example. With GTK_RESPONSE_HELP the view button is aligned
1993 to the left while the other two to the right */
1994 note = hildon_note_new_confirmation_add_buttons (
1997 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1998 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1999 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
2002 g_signal_connect (G_OBJECT(note), "response",
2003 G_CALLBACK(on_cert_dialog_response),
2004 (gpointer) certificate);
2006 response = gtk_dialog_run(GTK_DIALOG(note));
2008 on_destroy_dialog (note);
2011 return response == GTK_RESPONSE_OK;
2015 modest_platform_run_alert_dialog (const gchar* prompt,
2016 gboolean is_question)
2018 ModestWindow *top_win;
2019 HildonWindowStack *stack;
2021 stack = hildon_window_stack_get_default ();
2022 top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2025 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2030 gboolean retval = TRUE;
2032 /* The Tinymail documentation says that we should show Yes and No buttons,
2033 * when it is a question.
2034 * Obviously, we need tinymail to use more specific error codes instead,
2035 * so we know what buttons to show. */
2036 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win),
2038 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2039 GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2041 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2042 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2044 on_destroy_dialog (dialog);
2046 /* Just show the error text and use the default response: */
2047 modest_platform_run_information_dialog (GTK_WINDOW (top_win),
2055 GtkWindow *parent_window;
2056 ModestConnectedPerformer callback;
2057 TnyAccount *account;
2064 on_went_online_info_free (OnWentOnlineInfo *info)
2066 /* And if we cleanup, we DO cleanup :-) */
2069 g_object_unref (info->device);
2072 if (info->parent_window)
2073 g_object_unref (info->parent_window);
2075 g_object_unref (info->account);
2077 g_slice_free (OnWentOnlineInfo, info);
2079 /* We're done ... */
2085 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2087 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2089 /* Now it's really time to callback to the caller. If going online didn't succeed,
2090 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2091 * canceled will be set. Etcetera etcetera. */
2093 if (info->callback) {
2094 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2097 /* This is our last call, we must cleanup here if we didn't yet do that */
2098 on_went_online_info_free (info);
2105 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2107 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2108 info->iap = g_strdup (iap_id);
2110 if (canceled || err || !info->account) {
2112 /* If there's a problem or if there's no account (then that's it for us, we callback
2113 * the caller's callback now. He'll have to handle err or canceled, of course.
2114 * We are not really online, as the account is not really online here ... */
2116 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2117 * this info. We don't cleanup err, Tinymail does that! */
2119 if (info->callback) {
2121 /* info->account can be NULL here, this means that the user did not
2122 * provide a nice account instance. We'll assume that the user knows
2123 * what he's doing and is happy with just the device going online.
2125 * We can't do magic, we don't know what account the user wants to
2126 * see going online. So just the device goes online, end of story */
2128 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2131 } else if (info->account) {
2133 /* If there's no problem and if we have an account, we'll put the account
2134 * online too. When done, the callback of bringing the account online
2135 * will callback the caller's callback. This is the most normal case. */
2137 info->device = TNY_DEVICE (g_object_ref (device));
2139 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2140 on_account_went_online, info);
2142 /* The on_account_went_online cb frees up the info, go look if you
2143 * don't believe me! (so we return here) */
2148 /* We cleanup if we are not bringing the account online too */
2149 on_went_online_info_free (info);
2155 modest_platform_connect_and_perform (GtkWindow *parent_window,
2157 TnyAccount *account,
2158 ModestConnectedPerformer callback,
2161 gboolean device_online;
2163 TnyConnectionStatus conn_status;
2164 OnWentOnlineInfo *info;
2166 device = modest_runtime_get_device();
2167 device_online = tny_device_is_online (device);
2169 /* If there is no account check only the device status */
2172 if (device_online) {
2174 /* We promise to instantly perform the callback, so ... */
2176 callback (FALSE, NULL, parent_window, account, user_data);
2181 info = g_slice_new0 (OnWentOnlineInfo);
2184 info->device = NULL;
2185 info->account = NULL;
2188 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2190 info->parent_window = NULL;
2191 info->user_data = user_data;
2192 info->callback = callback;
2194 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2195 force, on_conic_device_went_online,
2198 /* We'll cleanup in on_conic_device_went_online */
2201 /* The other code has no more reason to run. This is all that we can do for the
2202 * caller (he should have given us a nice and clean account instance!). We
2203 * can't do magic, we don't know what account he intends to bring online. So
2204 * we'll just bring the device online (and await his false bug report). */
2210 /* Return if the account is already connected */
2212 conn_status = tny_account_get_connection_status (account);
2213 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2215 /* We promise to instantly perform the callback, so ... */
2217 callback (FALSE, NULL, parent_window, account, user_data);
2223 /* Else, we are in a state that requires that we go online before we
2224 * call the caller's callback. */
2226 info = g_slice_new0 (OnWentOnlineInfo);
2228 info->device = NULL;
2230 info->account = TNY_ACCOUNT (g_object_ref (account));
2233 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2235 info->parent_window = NULL;
2237 /* So we'll put the callback away for later ... */
2239 info->user_data = user_data;
2240 info->callback = callback;
2242 if (!device_online) {
2244 /* If also the device is offline, then we connect both the device
2245 * and the account */
2247 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2248 force, on_conic_device_went_online,
2253 /* If the device is online, we'll just connect the account */
2255 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2256 on_account_went_online, info);
2259 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2260 * in both situations, go look if you don't believe me! */
2266 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2268 TnyFolderStore *folder_store,
2269 ModestConnectedPerformer callback,
2272 TnyAccount *account = NULL;
2274 if (!folder_store ||
2275 (TNY_IS_MERGE_FOLDER (folder_store) &&
2276 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2278 /* We promise to instantly perform the callback, so ... */
2280 GError *error = NULL;
2281 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2282 "Unable to move or not found folder");
2283 callback (FALSE, error, parent_window, NULL, user_data);
2284 g_error_free (error);
2288 } else if (TNY_IS_FOLDER (folder_store)) {
2289 /* Get the folder's parent account: */
2290 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2291 } else if (TNY_IS_ACCOUNT (folder_store)) {
2292 /* Use the folder store as an account: */
2293 account = TNY_ACCOUNT (g_object_ref (folder_store));
2296 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2297 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2298 /* No need to connect a local account */
2300 callback (FALSE, NULL, parent_window, account, user_data);
2305 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2309 g_object_unref (account);
2313 src_account_connect_performer (gboolean canceled,
2315 GtkWindow *parent_window,
2316 TnyAccount *src_account,
2319 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2321 if (canceled || err) {
2322 /* If there was any error call the user callback */
2323 info->callback (canceled, err, parent_window, src_account, info->data);
2325 /* Connect the destination account */
2326 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2327 TNY_FOLDER_STORE (info->dst_account),
2328 info->callback, info->data);
2331 /* Free the info object */
2332 g_object_unref (info->dst_account);
2333 g_slice_free (DoubleConnectionInfo, info);
2338 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2340 TnyFolderStore *folder_store,
2341 DoubleConnectionInfo *connect_info)
2343 modest_platform_connect_if_remote_and_perform(parent_window,
2346 src_account_connect_performer,
2351 modest_platform_get_account_settings_wizard (void)
2353 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2355 return GTK_WIDGET (dialog);
2359 modest_platform_get_current_connection (void)
2361 TnyDevice *device = NULL;
2362 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2364 device = modest_runtime_get_device ();
2366 if (!tny_device_is_online (device))
2367 return MODEST_CONNECTED_VIA_ANY;
2369 #ifdef MODEST_HAVE_CONIC
2371 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2373 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2374 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2375 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2377 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2378 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2379 !strcmp (bearer_type, "WIMAX")) {
2380 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2382 retval = MODEST_CONNECTED_VIA_ANY;
2385 g_object_unref (iap);
2388 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2389 #endif /* MODEST_HAVE_CONIC */
2396 modest_platform_check_memory_low (ModestWindow *win,
2401 /* are we in low memory state? */
2402 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2404 if (win && lowmem && visuals)
2405 modest_platform_run_information_dialog (
2407 _KR("memr_ib_operation_disabled"),
2411 g_debug ("%s: low memory reached. disallowing some operations",
2418 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2424 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2427 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2428 GTK_WINDOW (dialog),
2430 gtk_widget_show_all (dialog);
2432 g_signal_connect_swapped (dialog, "response",
2433 G_CALLBACK (gtk_widget_destroy),
2438 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2444 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header, TRUE);
2447 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2448 GTK_WINDOW (dialog),
2450 gtk_widget_show_all (dialog);
2452 g_signal_connect_swapped (dialog, "response",
2453 G_CALLBACK (gtk_widget_destroy),
2458 modest_platform_get_osso_context (void)
2460 return modest_maemo_utils_get_osso_context ();
2464 _modest_platform_play_email_tone (void)
2467 gint mail_volume_int;
2469 ca_context *ca_con = NULL;
2470 ca_proplist *pl = NULL;
2472 #ifdef MODEST_USE_PROFILE
2473 gchar *active_profile;
2476 active_profile = profile_get_profile ();
2477 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2478 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2479 mail_volume_int = profile_parse_int (mail_volume);
2480 g_free (mail_volume);
2481 g_free (active_profile);
2483 mail_tone = MAIL_TONE;
2484 mail_volume_int = 100;
2487 if (mail_tone && !strstr (mail_tone, "/")) {
2490 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2495 if (mail_volume_int > 0) {
2497 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2498 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2502 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2503 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2504 ca_context_destroy(ca_con);
2508 ca_proplist_create(&pl);
2509 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2510 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2512 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2513 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2515 ca_proplist_destroy(pl);
2516 ca_context_destroy(ca_con);
2522 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2523 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2524 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2525 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2526 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2527 #define MOVE_TO_FOLDER_SEPARATOR "/"
2530 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
2531 TnyFolderStore *folder_store)
2533 GtkWidget *action_button;
2534 GtkWidget *image = NULL;
2535 TnyAccount *account;
2536 gchar *account_name = NULL;
2538 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2540 /* Get account name */
2541 if (TNY_IS_FOLDER (folder_store))
2542 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2544 account = g_object_ref (folder_store);
2546 if (modest_tny_account_is_virtual_local_folders (account))
2547 account_name = modest_conf_get_string (modest_runtime_get_conf(),
2548 MODEST_CONF_DEVICE_NAME, NULL);
2551 account_name = g_strdup (tny_account_get_name (account));
2553 g_object_unref (account);
2555 /* Set title of button: account or folder name */
2556 if (TNY_IS_FOLDER (folder_store)) {
2557 hildon_button_set_title (HILDON_BUTTON (action_button),
2558 tny_folder_get_name (TNY_FOLDER (folder_store)));
2560 hildon_button_set_title (HILDON_BUTTON (action_button), account_name);
2563 /* Set value of button, folder full name */
2564 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
2565 gchar *full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
2566 tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store)),
2568 hildon_button_set_value (HILDON_BUTTON (action_button), full_name);
2571 g_free (account_name);
2573 /* Set image for the button */
2574 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
2576 hildon_button_set_image (HILDON_BUTTON (action_button), image);
2580 move_to_dialog_show_accounts (GtkWidget *dialog)
2582 GtkWidget *back_button;
2583 GtkWidget *folder_view;
2584 GtkWidget *pannable;
2585 GtkWidget *action_button;
2587 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2588 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2589 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2590 pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2592 gtk_widget_set_sensitive (back_button, FALSE);
2593 gtk_widget_set_sensitive (action_button, FALSE);
2595 /* Need to set this here, otherwise callbacks called because
2596 of filtering won't perform correctly */
2597 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2599 /* Reset action button */
2600 hildon_button_set_title (HILDON_BUTTON (action_button), NULL);
2601 hildon_button_set_value (HILDON_BUTTON (action_button), NULL);
2602 hildon_button_set_image (HILDON_BUTTON (action_button), NULL);
2604 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
2605 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2606 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2607 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2608 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2609 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2610 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2611 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2612 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2613 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2614 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2615 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2619 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2621 GtkWidget *back_button;
2622 GtkWidget *folder_view;
2623 TnyAccount *account;
2624 const gchar *account_id;
2625 GtkWidget *pannable;
2626 GtkWidget *action_button;
2629 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2631 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2633 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2635 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2637 gtk_widget_set_sensitive (back_button, TRUE);
2638 gtk_widget_set_sensitive (action_button, TRUE);
2640 /* Need to set this here, otherwise callbacks called because
2641 of filtering won't perform correctly */
2642 g_object_set_data (G_OBJECT (dialog),
2643 MOVE_TO_DIALOG_SHOWING_FOLDERS,
2644 GINT_TO_POINTER (TRUE));
2646 account = TNY_ACCOUNT (folder_store);
2647 if (modest_tny_account_is_virtual_local_folders (account)) {
2648 account_id = tny_account_get_id (account);
2649 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2650 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2651 } else if (modest_tny_account_is_memory_card_account (account)) {
2652 account_id = tny_account_get_id (account);
2653 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2654 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2656 account_id = tny_account_get_id (account);
2657 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2658 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2659 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2660 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2663 move_to_dialog_set_selected_folder_store (dialog, folder_store);
2664 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2667 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2668 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2669 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2670 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2671 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2675 on_move_to_dialog_back_clicked (GtkButton *button,
2678 GtkWidget *dialog = (GtkWidget *) userdata;
2680 /* Back to show accounts */
2681 move_to_dialog_show_accounts (dialog);
2685 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
2687 GtkTreeViewColumn *column,
2690 TnyFolderStore *selected = NULL;
2692 GtkWidget *folder_view;
2693 gboolean showing_folders;
2695 dialog = (GtkWidget *) user_data;
2696 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
2697 MOVE_TO_DIALOG_SHOWING_FOLDERS));
2699 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
2700 MOVE_TO_DIALOG_FOLDER_VIEW));
2702 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2706 if (!showing_folders) {
2707 gboolean valid = TRUE;
2709 if (TNY_IS_ACCOUNT (selected) &&
2710 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2711 ModestProtocolType protocol_type;
2713 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2714 valid = !modest_protocol_registry_protocol_type_has_tag
2715 (modest_runtime_get_protocol_registry (),
2717 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_MESSAGE_ADD);
2720 move_to_dialog_show_folders (dialog, selected);
2722 move_to_dialog_set_selected_folder_store (dialog, selected);
2727 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2730 gboolean showing_folders;
2733 dialog = (GtkWidget *) user_data;
2734 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2735 if (showing_folders) {
2736 TnyFolderStore *selected;
2737 GtkWidget *folder_view;
2739 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2740 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2743 move_to_dialog_set_selected_folder_store (dialog, selected);
2744 g_object_unref (selected);
2750 on_move_to_dialog_action_clicked (GtkButton *selection,
2753 TnyFolderStore *selected;
2755 GtkWidget *folder_view;
2756 gboolean showing_folders;
2758 dialog = (GtkWidget *) user_data;
2759 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2760 if (showing_folders) {
2761 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2762 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2765 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2770 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2771 GtkWidget **folder_view)
2773 GtkWidget *dialog, *folder_view_container;
2775 GtkWidget *buttons_hbox;
2776 GtkWidget *back_button;
2777 GdkPixbuf *back_pixbuf;
2778 GtkWidget *top_vbox;
2779 GtkWidget *action_button;
2780 GtkTreeSelection *selection;
2782 /* Create dialog. We cannot use a touch selector because we
2783 need to use here the folder view widget directly */
2784 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2785 GTK_WINDOW (parent_window),
2786 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2787 GTK_DIALOG_DESTROY_WITH_PARENT,
2788 _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2791 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2792 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2793 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2795 /* Create folder view */
2796 *folder_view = modest_platform_create_folder_view (NULL);
2798 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2799 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2800 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2802 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2803 (TnyAccountStore *) modest_runtime_get_account_store ());
2805 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2806 back_button = gtk_button_new ();
2807 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2809 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2810 g_object_unref (back_pixbuf);
2813 action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
2814 HILDON_BUTTON_ARRANGEMENT_VERTICAL);
2815 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2817 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2818 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2819 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2820 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2821 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2823 /* Create pannable and add it to the dialog */
2824 folder_view_container = hildon_pannable_area_new ();
2825 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2826 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2828 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2829 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2831 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2833 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2834 gtk_widget_show (folder_view_container);
2835 gtk_widget_show (align);
2836 gtk_widget_show (top_vbox);
2837 gtk_widget_show (*folder_view);
2838 gtk_widget_show_all (back_button);
2839 gtk_widget_show (action_button);
2840 gtk_widget_show (buttons_hbox);
2841 gtk_widget_show (dialog);
2843 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2844 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2845 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2846 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2848 /* Simulate the behaviour of a HildonPickerDialog by emitting
2849 a response when a folder is selected */
2850 g_signal_connect (*folder_view, "row-activated",
2851 G_CALLBACK (on_move_to_dialog_row_activated),
2854 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2855 g_signal_connect (selection, "changed",
2856 G_CALLBACK (on_move_to_dialog_selection_changed),
2859 g_signal_connect (action_button, "clicked",
2860 G_CALLBACK (on_move_to_dialog_action_clicked),
2863 g_signal_connect (back_button, "clicked",
2864 G_CALLBACK (on_move_to_dialog_back_clicked),
2867 move_to_dialog_show_accounts (dialog);
2873 modest_platform_get_list_to_move (ModestWindow *window)
2875 TnyList *list = NULL;
2877 if (MODEST_IS_HEADER_WINDOW (window)) {
2878 ModestHeaderView *header_view;
2880 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2881 list = modest_header_view_get_selected_headers (header_view);
2882 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2883 ModestFolderView *folder_view;
2884 TnyFolderStore *selected_folder;
2886 list = TNY_LIST (tny_simple_list_new ());
2887 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2888 selected_folder = modest_folder_view_get_selected (folder_view);
2889 if (selected_folder) {
2890 tny_list_prepend (list, G_OBJECT (selected_folder));
2891 g_object_unref (selected_folder);
2894 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2897 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2899 list = TNY_LIST (tny_simple_list_new ());
2900 tny_list_prepend (list, G_OBJECT (header));
2901 g_object_unref (header);
2904 g_return_val_if_reached (NULL);