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));
643 if (picker != NULL) {
645 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
648 /* Look for another folder with the same name */
649 if (modest_tny_folder_has_subfolder_with_name (parent,
656 if (TNY_IS_ACCOUNT (parent) &&
657 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
658 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
667 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
668 NULL, _CS("ckdg_ib_folder_already_exists"));
669 /* Select the text */
670 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
671 gtk_widget_grab_focus (entry);
672 /* Do not close the dialog */
673 g_signal_stop_emission_by_name (dialog, "response");
678 typedef struct _FolderChooserData {
679 TnyFolderStore *store;
684 folder_chooser_activated (ModestFolderView *folder_view,
685 TnyFolderStore *folder,
686 FolderChooserData *userdata)
688 userdata->store = folder;
689 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
692 static TnyFolderStore *
693 folder_chooser_dialog_run (ModestFolderView *original)
695 GtkWidget *folder_view;
696 FolderChooserData userdata = {NULL, NULL};
698 const gchar *visible_id = NULL;
700 userdata.dialog = hildon_dialog_new ();
701 pannable = hildon_pannable_area_new ();
702 folder_view = modest_platform_create_folder_view (NULL);
704 gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
706 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
707 MODEST_FOLDER_VIEW (folder_view));
710 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
711 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
714 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
715 gtk_container_add (GTK_CONTAINER (pannable), folder_view);
716 gtk_widget_set_size_request (pannable, -1, 320);
718 gtk_widget_show (folder_view);
719 gtk_widget_show (pannable);
720 gtk_widget_show (userdata.dialog);
721 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
722 G_CALLBACK (folder_chooser_activated),
723 (gpointer) &userdata);
725 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
726 gtk_widget_destroy (userdata.dialog);
728 return userdata.store;
732 folder_store_get_display_name (TnyFolderStore *store)
734 if (TNY_IS_ACCOUNT (store)) {
735 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
736 return modest_conf_get_string (modest_runtime_get_conf(),
737 MODEST_CONF_DEVICE_NAME, NULL);
739 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
742 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
744 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
745 type = tny_folder_get_folder_type (TNY_FOLDER (store));
746 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
747 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
748 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
749 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
751 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
754 /* Sometimes an special folder is reported by the server as
755 NORMAL, like some versions of Dovecot */
756 if (type == TNY_FOLDER_TYPE_NORMAL ||
757 type == TNY_FOLDER_TYPE_UNKNOWN) {
758 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
762 if (type == TNY_FOLDER_TYPE_INBOX) {
764 fname = g_strdup (_("mcen_me_folder_inbox"));
771 get_image_for_folder_store (TnyFolderStore *store,
775 const gchar *icon_name = NULL;
776 GtkWidget *image = NULL;
778 if (TNY_IS_ACCOUNT (store)) {
779 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
780 icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
781 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
782 icon_name = MODEST_FOLDER_ICON_MMC;
784 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
786 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
787 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
789 case TNY_FOLDER_TYPE_INBOX:
790 icon_name = MODEST_FOLDER_ICON_INBOX;
793 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
795 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
797 case TNY_FOLDER_TYPE_OUTBOX:
798 icon_name = MODEST_FOLDER_ICON_OUTBOX;
800 case TNY_FOLDER_TYPE_DRAFTS:
801 icon_name = MODEST_FOLDER_ICON_DRAFTS;
803 case TNY_FOLDER_TYPE_SENT:
804 icon_name = MODEST_FOLDER_ICON_SENT;
807 icon_name = MODEST_FOLDER_ICON_NORMAL;
809 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
810 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
815 pixbuf = modest_platform_get_icon (icon_name, size);
818 image = gtk_image_new_from_pixbuf (pixbuf);
819 g_object_unref (pixbuf);
826 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
831 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
835 g_object_ref (store);
836 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
837 store, (GDestroyNotify) g_object_unref);
838 name = folder_store_get_display_name (store);
839 hildon_button_set_value (HILDON_BUTTON (button), name);
843 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
845 hildon_button_set_image (HILDON_BUTTON (button), image);
849 /* Always returns DUPs so you must free the returned value */
851 get_next_folder_name (const gchar *suggested_name,
852 TnyFolderStore *suggested_folder)
854 const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
856 gchar *real_suggested_name;
858 if (suggested_name !=NULL) {
859 return g_strdup (suggested_name);
862 for(i = 0; i < 100; ++ i) {
863 gboolean exists = FALSE;
866 real_suggested_name = g_strdup (default_name);
868 real_suggested_name = g_strdup_printf ("%s(%d)",
869 _FM("ckdg_va_new_folder_name_stub"),
871 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
878 g_free (real_suggested_name);
881 /* Didn't find a free number */
883 real_suggested_name = g_strdup (default_name);
885 return real_suggested_name;
889 ModestFolderView *folder_view;
891 } FolderPickerHelper;
894 folder_picker_clicked (GtkButton *button,
895 FolderPickerHelper *helper)
897 TnyFolderStore *store;
899 store = folder_chooser_dialog_run (helper->folder_view);
901 const gchar *current_name;
904 folder_picker_set_store (GTK_BUTTON (button), store);
906 /* Update the name of the folder */
907 current_name = gtk_entry_get_text (helper->entry);
908 exists = modest_tny_folder_has_subfolder_with_name (store,
912 gchar *new_name = get_next_folder_name (NULL, store);
913 gtk_entry_set_text (helper->entry, new_name);
920 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
924 button = hildon_button_new (MODEST_EDITABLE_SIZE,
925 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
927 hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
930 folder_picker_set_store (GTK_BUTTON (button), suggested);
933 g_signal_connect (G_OBJECT (button), "clicked",
934 G_CALLBACK (folder_picker_clicked),
942 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
943 TnyFolderStore *suggested_parent,
944 const gchar *dialog_title,
945 const gchar *label_text,
946 const gchar *suggested_name,
948 gboolean show_parent,
950 TnyFolderStore **parent)
952 GtkWidget *accept_btn = NULL;
953 GtkWidget *dialog, *entry = NULL, *label_entry = NULL, *label_location = NULL, *hbox;
954 GtkWidget *account_picker = NULL;
955 GList *buttons = NULL;
957 GtkSizeGroup *sizegroup;
958 ModestFolderView *folder_view;
959 ModestWindow *folder_window;
960 ModestHildon2WindowMgr *window_mgr;
961 FolderPickerHelper *helper = NULL;
962 GtkWidget *top_vbox, *top_align;
964 window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
965 folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
966 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
968 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
970 top_vbox = gtk_vbox_new (FALSE, 0);
971 top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
972 gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
974 /* Ask the user for the folder name */
975 dialog = gtk_dialog_new_with_buttons (dialog_title,
977 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
978 _FM("ckdg_bd_new_folder_dialog_ok"),
982 /* Add accept button (with unsensitive handler) */
983 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
984 accept_btn = GTK_WIDGET (buttons->data);
986 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
989 label_entry = gtk_label_new (label_text);
990 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
991 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
993 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
994 gtk_size_group_add_widget (sizegroup, label_entry);
997 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
999 gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
1000 gtk_entry_set_width_chars (GTK_ENTRY (entry),
1001 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
1002 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
1003 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
1008 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
1010 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
1011 gtk_size_group_add_widget (sizegroup, label_location);
1013 helper = g_slice_new0 (FolderPickerHelper);
1014 helper->folder_view = folder_view;
1015 helper->entry = (GtkEntry *) entry;
1017 account_picker = folder_picker_new (suggested_parent, helper);
1020 g_object_unref (sizegroup);
1022 /* Connect to the response method to avoid closing the dialog
1023 when an invalid name is selected*/
1024 g_signal_connect (dialog,
1026 G_CALLBACK (on_response),
1030 /* Track entry changes */
1031 g_signal_connect (entry,
1033 G_CALLBACK (entry_insert_text),
1035 g_signal_connect (entry,
1037 G_CALLBACK (entry_changed),
1042 /* Some locales like pt_BR need this to get the full window
1044 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
1046 /* Create the hbox */
1048 hbox = gtk_hbox_new (FALSE, 12);
1049 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
1050 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
1052 /* Add hbox to dialog */
1053 gtk_box_pack_start (GTK_BOX (top_vbox),
1054 hbox, FALSE, FALSE, 0);
1055 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
1059 hbox = gtk_hbox_new (FALSE, 12);
1060 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
1061 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
1063 /* Add hbox to dialog */
1064 gtk_box_pack_start (GTK_BOX (top_vbox),
1065 hbox, FALSE, FALSE, 0);
1066 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
1068 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1069 GTK_WINDOW (dialog), parent_window);
1071 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
1072 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
1074 gtk_widget_show_all (GTK_WIDGET(dialog));
1076 result = gtk_dialog_run (GTK_DIALOG(dialog));
1077 if (result == GTK_RESPONSE_ACCEPT) {
1079 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1081 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
1083 g_object_ref (*parent);
1087 gtk_widget_destroy (dialog);
1090 g_slice_free (FolderPickerHelper, helper);
1092 while (gtk_events_pending ())
1093 gtk_main_iteration ();
1099 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
1100 TnyFolderStore *suggested_folder,
1101 gchar *suggested_name,
1102 gchar **folder_name,
1103 TnyFolderStore **parent_folder)
1105 gchar *real_suggested_name = NULL;
1107 ModestTnyAccountStore *acc_store;
1108 TnyAccount *account;
1110 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
1113 /* In hildon 2.2 we always suggest the archive folder as parent */
1114 acc_store = modest_runtime_get_account_store ();
1115 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1117 suggested_folder = (TnyFolderStore *)
1118 modest_tny_account_get_special_folder (account,
1119 TNY_FOLDER_TYPE_ARCHIVE);
1120 g_object_unref (account);
1124 /* If there is not archive folder then fallback to local folders account */
1125 if (!suggested_folder)
1126 suggested_folder = (TnyFolderStore *)
1127 modest_tny_account_store_get_local_folders_account (acc_store);
1129 result = modest_platform_run_folder_common_dialog (parent_window,
1131 _HL("ckdg_ti_new_folder"),
1132 _FM("ckdg_fi_new_folder_name"),
1133 real_suggested_name,
1139 g_free(real_suggested_name);
1145 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1146 TnyFolderStore *parent_folder,
1147 const gchar *suggested_name,
1148 gchar **folder_name)
1150 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1152 return modest_platform_run_folder_common_dialog (parent_window,
1154 _HL("ckdg_ti_rename_folder"),
1155 _HL("ckdg_fi_rename_name"),
1166 on_destroy_dialog (GtkWidget *dialog)
1168 /* This could happen when the dialogs get programatically
1169 hidden or destroyed (for example when closing the
1170 application while a dialog is being shown) */
1171 if (!GTK_IS_WIDGET (dialog))
1174 gtk_widget_destroy (dialog);
1176 if (gtk_events_pending ())
1177 gtk_main_iteration ();
1181 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1182 const gchar *message)
1187 dialog = hildon_note_new_confirmation (parent_window, message);
1188 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1189 GTK_WINDOW (dialog), parent_window);
1191 response = gtk_dialog_run (GTK_DIALOG (dialog));
1193 on_destroy_dialog (dialog);
1199 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1200 const gchar *message,
1201 const gchar *button_accept,
1202 const gchar *button_cancel)
1207 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1208 button_accept, GTK_RESPONSE_ACCEPT,
1209 button_cancel, GTK_RESPONSE_CANCEL,
1212 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1213 GTK_WINDOW (dialog), parent_window);
1215 response = gtk_dialog_run (GTK_DIALOG (dialog));
1217 on_destroy_dialog (dialog);
1223 modest_platform_run_information_dialog (GtkWindow *parent_window,
1224 const gchar *message,
1229 note = hildon_note_new_information (parent_window, message);
1231 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1232 GTK_WINDOW (note), parent_window);
1235 gtk_dialog_run (GTK_DIALOG (note));
1237 on_destroy_dialog (note);
1239 g_signal_connect_swapped (note,
1241 G_CALLBACK (on_destroy_dialog),
1244 gtk_widget_show_all (note);
1248 typedef struct _ConnectAndWaitData {
1250 GMainLoop *wait_loop;
1251 gboolean has_callback;
1253 } ConnectAndWaitData;
1257 quit_wait_loop (TnyAccount *account,
1258 ConnectAndWaitData *data)
1260 /* Set the has_callback to TRUE (means that the callback was
1261 executed and wake up every code waiting for cond to be
1263 g_mutex_lock (data->mutex);
1264 data->has_callback = TRUE;
1265 if (data->wait_loop)
1266 g_main_loop_quit (data->wait_loop);
1267 g_mutex_unlock (data->mutex);
1271 on_connection_status_changed (TnyAccount *account,
1272 TnyConnectionStatus status,
1275 TnyConnectionStatus conn_status;
1276 ConnectAndWaitData *data;
1278 /* Ignore if reconnecting or disconnected */
1279 conn_status = tny_account_get_connection_status (account);
1280 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1281 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1284 /* Remove the handler */
1285 data = (ConnectAndWaitData *) user_data;
1286 g_signal_handler_disconnect (account, data->handler);
1288 /* Quit from wait loop */
1289 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1293 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1298 /* Quit from wait loop */
1299 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1303 modest_platform_connect_and_wait (GtkWindow *parent_window,
1304 TnyAccount *account)
1306 ConnectAndWaitData *data = NULL;
1307 gboolean device_online;
1309 TnyConnectionStatus conn_status;
1310 gboolean user_requested;
1312 device = modest_runtime_get_device();
1313 device_online = tny_device_is_online (device);
1315 /* Whether the connection is user requested or automatically
1316 requested, for example via D-Bus */
1317 user_requested = (parent_window) ? TRUE : FALSE;
1319 /* If there is no account check only the device status */
1324 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1325 NULL, user_requested);
1328 /* Return if the account is already connected */
1329 conn_status = tny_account_get_connection_status (account);
1330 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1333 /* Create the helper */
1334 data = g_slice_new0 (ConnectAndWaitData);
1335 data->mutex = g_mutex_new ();
1336 data->has_callback = FALSE;
1338 /* Connect the device */
1339 if (!device_online) {
1340 /* Track account connection status changes */
1341 data->handler = g_signal_connect (account, "connection-status-changed",
1342 G_CALLBACK (on_connection_status_changed),
1344 /* Try to connect the device */
1345 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1346 NULL, user_requested);
1348 /* If the device connection failed then exit */
1349 if (!device_online && data->handler)
1352 /* Force a reconnection of the account */
1353 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1354 on_tny_camel_account_set_online_cb, data);
1357 /* Wait until the callback is executed */
1358 g_mutex_lock (data->mutex);
1359 if (!data->has_callback) {
1360 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1361 gdk_threads_leave ();
1362 g_mutex_unlock (data->mutex);
1363 g_main_loop_run (data->wait_loop);
1364 g_mutex_lock (data->mutex);
1365 gdk_threads_enter ();
1367 g_mutex_unlock (data->mutex);
1370 if (g_signal_handler_is_connected (account, data->handler))
1371 g_signal_handler_disconnect (account, data->handler);
1372 g_mutex_free (data->mutex);
1373 g_main_loop_unref (data->wait_loop);
1374 g_slice_free (ConnectAndWaitData, data);
1376 conn_status = tny_account_get_connection_status (account);
1377 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1381 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1383 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1384 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1385 /* This must be a maildir account, which does not require a connection: */
1390 return modest_platform_connect_and_wait (parent_window, account);
1394 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1397 return TRUE; /* Maybe it is something local. */
1399 gboolean result = TRUE;
1400 if (TNY_IS_FOLDER (folder_store)) {
1401 /* Get the folder's parent account: */
1402 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1403 if (account != NULL) {
1404 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1405 g_object_unref (account);
1407 } else if (TNY_IS_ACCOUNT (folder_store)) {
1408 /* Use the folder store as an account: */
1409 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1416 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1420 dialog = modest_hildon2_sort_dialog_new (parent_window);
1427 modest_platform_set_update_interval (guint minutes)
1429 #ifdef MODEST_HAVE_LIBALARM
1431 ModestConf *conf = modest_runtime_get_conf ();
1435 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1437 /* Delete any existing alarm,
1438 * because we will replace it: */
1440 if (alarmd_event_del(alarm_cookie) != 0)
1441 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1443 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1446 /* 0 means no updates: */
1451 /* Register alarm: */
1453 /* Set the interval in alarm_event_t structure: */
1454 alarm_event_t *event = alarm_event_create ();
1455 alarm_event_add_actions (event, 1);
1456 alarm_action_t *action = alarm_event_get_action (event, 0);
1457 alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1458 event->alarm_time = minutes * 60; /* seconds */
1460 /* Set recurrence every few minutes: */
1461 event->recur_secs = minutes*60;
1462 event->recur_count = -1; /* Means infinite */
1464 /* Specify what should happen when the alarm happens:
1465 * It should call this D-Bus method: */
1467 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1468 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1469 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1470 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1471 action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1473 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1474 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1475 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1476 * This is why we want to use the Alarm API instead of just g_timeout_add().
1477 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1478 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1480 event->flags = ALARM_EVENT_CONNECTED;
1482 alarm_cookie = alarmd_event_add (event);
1485 alarm_event_delete (event);
1487 /* Store the alarm ID in GConf, so we can remove it later:
1488 * This is apparently valid between application instances. */
1489 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1491 if (!alarm_cookie) {
1493 g_debug ("Error setting alarm event. \n");
1497 #endif /* MODEST_HAVE_LIBALARM */
1502 modest_platform_push_email_notification(void)
1504 gboolean screen_on, app_in_foreground;
1506 /* Get the window status */
1507 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1509 screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1511 /* If the screen is on and the app is in the
1512 foreground we don't show anything */
1513 if (!(screen_on && app_in_foreground)) {
1515 _modest_platform_play_email_tone ();
1517 /* Activate LED. This must be deactivated by
1518 modest_platform_remove_new_mail_notifications */
1519 #ifdef MODEST_HAVE_MCE
1520 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1524 MCE_ACTIVATE_LED_PATTERN,
1526 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1533 modest_platform_on_new_headers_received (TnyList *header_list,
1534 gboolean show_visual)
1536 g_return_if_fail (TNY_IS_LIST(header_list));
1538 if (tny_list_get_length(header_list) == 0) {
1539 g_warning ("%s: header list is empty", __FUNCTION__);
1544 modest_platform_push_email_notification ();
1545 /* We do a return here to avoid indentation with an else */
1549 #ifdef MODEST_HAVE_HILDON_NOTIFY
1550 HildonNotification *notification;
1552 GSList *notifications_list = NULL;
1554 /* Get previous notifications ids */
1555 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1556 MODEST_CONF_NOTIFICATION_IDS,
1557 MODEST_CONF_VALUE_INT, NULL);
1559 iter = tny_list_create_iterator (header_list);
1560 while (!tny_iterator_is_done (iter)) {
1561 gchar *url = NULL, *display_address = NULL;
1562 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1563 TnyFolder *folder = tny_header_get_folder (header);
1564 gboolean first_notification = TRUE;
1568 display_address = tny_header_dup_from (header);
1569 /* string is changed in-place */
1570 modest_text_utils_get_display_address (display_address);
1572 str = tny_header_dup_subject (header);
1573 notification = hildon_notification_new (display_address,
1575 "qgn_list_messagin",
1576 MODEST_NOTIFICATION_CATEGORY);
1578 /* Create the message URL */
1579 str = tny_header_dup_uid (header);
1580 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1584 hildon_notification_add_dbus_action(notification,
1587 MODEST_DBUS_SERVICE,
1590 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1594 /* Play sound if the user wants. Show the LED
1595 pattern. Show and play just one */
1596 if (G_UNLIKELY (first_notification)) {
1597 TnyAccount *account;
1599 first_notification = FALSE;
1601 /* Set the led pattern */
1602 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1604 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1606 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1608 /* Set the account of the headers */
1609 account = tny_folder_get_account (folder);
1611 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1613 tny_account_get_id (account));
1614 g_object_unref (account);
1618 /* Notify. We need to do this in an idle because this function
1619 could be called from a thread */
1620 if (!notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1621 g_warning ("Failed to send notification");
1624 /* Save id in the list */
1625 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1626 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1627 /* We don't listen for the "closed" signal, because we
1628 don't care about if the notification was removed or
1629 not to store the list in gconf */
1631 /* Free & carry on */
1632 g_free (display_address);
1634 g_object_unref (folder);
1635 g_object_unref (header);
1636 tny_iterator_next (iter);
1638 g_object_unref (iter);
1641 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1642 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1644 g_slist_free (notifications_list);
1646 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1650 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1653 #ifdef MODEST_HAVE_MCE
1654 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1658 MCE_DEACTIVATE_LED_PATTERN,
1660 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1666 #ifdef MODEST_HAVE_HILDON_NOTIFY
1667 GSList *notif_list = NULL;
1669 /* Get previous notifications ids */
1670 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1671 MODEST_CONF_NOTIFICATION_IDS,
1672 MODEST_CONF_VALUE_INT, NULL);
1674 while (notif_list) {
1676 NotifyNotification *notif;
1678 /* Nasty HACK to remove the notifications, set the id
1679 of the existing ones and then close them */
1680 notif_id = GPOINTER_TO_INT(notif_list->data);
1681 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1682 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1684 /* Close the notification, note that some ids could be
1685 already invalid, but we don't care because it does
1687 notify_notification_close(notif, NULL);
1688 g_object_unref(notif);
1690 /* Delete the link, it's like going to the next */
1691 notif_list = g_slist_delete_link (notif_list, notif_list);
1695 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1696 notif_list, MODEST_CONF_VALUE_INT, NULL);
1698 g_slist_free (notif_list);
1700 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1706 modest_platform_get_global_settings_dialog ()
1708 return modest_hildon2_global_settings_dialog_new ();
1712 modest_platform_show_help (GtkWindow *parent_window,
1713 const gchar *help_id)
1719 modest_platform_show_search_messages (GtkWindow *parent_window)
1721 osso_return_t result = OSSO_ERROR;
1723 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1724 "osso_global_search",
1725 "search_email", NULL, DBUS_TYPE_INVALID);
1727 if (result != OSSO_OK) {
1728 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1733 modest_platform_show_addressbook (GtkWindow *parent_window)
1735 osso_return_t result = OSSO_ERROR;
1737 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1739 "top_application", NULL, DBUS_TYPE_INVALID);
1741 if (result != OSSO_OK) {
1742 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1747 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1749 GtkWidget *widget = modest_folder_view_new (query);
1751 /* Show one account by default */
1752 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1753 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1755 /* Restore settings */
1756 modest_widget_memory_restore (modest_runtime_get_conf(),
1758 MODEST_CONF_FOLDER_VIEW_KEY);
1764 banner_finish (gpointer data, GObject *object)
1766 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1767 modest_window_mgr_unregister_banner (mgr);
1768 g_object_unref (mgr);
1772 modest_platform_information_banner (GtkWidget *parent,
1773 const gchar *icon_name,
1776 GtkWidget *banner, *banner_parent = NULL;
1777 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1779 if (modest_window_mgr_get_num_windows (mgr) == 0)
1782 if (parent && GTK_IS_WINDOW (parent)) {
1783 /* If the window is the active one then show the
1784 banner on top of this window */
1785 if (gtk_window_is_active (GTK_WINDOW (parent)))
1786 banner_parent = parent;
1787 /* If the window is not the topmost but it's visible
1788 (it's minimized for example) then show the banner
1790 else if (GTK_WIDGET_VISIBLE (parent))
1791 banner_parent = NULL;
1792 /* If the window is hidden (like the main window when
1793 running in the background) then do not show
1800 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1802 modest_window_mgr_register_banner (mgr);
1804 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1808 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1809 const gchar *icon_name,
1815 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1818 banner = hildon_banner_show_information (parent, icon_name, text);
1819 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1823 modest_platform_animation_banner (GtkWidget *parent,
1824 const gchar *animation_name,
1827 GtkWidget *inf_note = NULL;
1829 g_return_val_if_fail (text != NULL, NULL);
1831 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1834 /* If the parent is not visible then do not show */
1835 if (parent && !GTK_WIDGET_VISIBLE (parent))
1838 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1846 TnyAccount *account;
1849 } CheckAccountIdleData;
1851 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1854 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1856 gboolean stop_trying = FALSE;
1857 g_return_val_if_fail (data && data->account, FALSE);
1859 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1860 tny_account_get_connection_status (data->account));
1862 if (data && data->account &&
1863 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1864 * after which the account is likely to be usable, or never likely to be usable soon: */
1865 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1867 data->is_online = TRUE;
1871 /* Give up if we have tried too many times: */
1872 if (data->count_tries >= NUMBER_OF_TRIES) {
1875 /* Wait for another timeout: */
1876 ++(data->count_tries);
1881 /* Allow the function that requested this idle callback to continue: */
1883 g_main_loop_quit (data->loop);
1886 g_object_unref (data->account);
1888 return FALSE; /* Don't call this again. */
1890 return TRUE; /* Call this timeout callback again. */
1894 /* Return TRUE immediately if the account is already online,
1895 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1896 * soon as the account is online, or FALSE if the account does
1897 * not become online in the NUMBER_OF_TRIES seconds.
1898 * This is useful when the D-Bus method was run immediately after
1899 * the application was started (when using D-Bus activation),
1900 * because the account usually takes a short time to go online.
1901 * The return value is maybe not very useful.
1904 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1908 g_return_val_if_fail (account, FALSE);
1910 if (!tny_device_is_online (modest_runtime_get_device())) {
1911 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1915 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1916 * so we avoid wait unnecessarily: */
1917 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1920 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1921 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1922 * we want to avoid. */
1923 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1926 /* This blocks on the result: */
1927 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1928 data->is_online = FALSE;
1929 data->account = account;
1930 g_object_ref (data->account);
1931 data->count_tries = 0;
1933 GMainContext *context = NULL; /* g_main_context_new (); */
1934 data->loop = g_main_loop_new (context, FALSE /* not running */);
1936 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1938 /* This main loop will run until the idle handler has stopped it: */
1939 g_main_loop_run (data->loop);
1941 g_main_loop_unref (data->loop);
1942 /* g_main_context_unref (context); */
1944 is_online = data->is_online;
1945 g_slice_free (CheckAccountIdleData, data);
1953 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1955 /* GTK_RESPONSE_HELP means we need to show the certificate */
1956 if (response_id == GTK_RESPONSE_APPLY) {
1960 /* Do not close the dialog */
1961 g_signal_stop_emission_by_name (dialog, "response");
1963 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1964 note = hildon_note_new_information (NULL, msg);
1965 gtk_dialog_run (GTK_DIALOG(note));
1966 gtk_widget_destroy (note);
1972 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1973 const gchar *certificate)
1978 HildonWindowStack *stack;
1980 stack = hildon_window_stack_get_default ();
1981 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1984 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1989 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1992 /* We use GTK_RESPONSE_APPLY because we want the button in the
1993 middle of OK and CANCEL the same as the browser does for
1994 example. With GTK_RESPONSE_HELP the view button is aligned
1995 to the left while the other two to the right */
1996 note = hildon_note_new_confirmation_add_buttons (
1999 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
2000 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
2001 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
2004 g_signal_connect (G_OBJECT(note), "response",
2005 G_CALLBACK(on_cert_dialog_response),
2006 (gpointer) certificate);
2008 response = gtk_dialog_run(GTK_DIALOG(note));
2010 on_destroy_dialog (note);
2013 return response == GTK_RESPONSE_OK;
2017 modest_platform_run_alert_dialog (const gchar* prompt,
2018 gboolean is_question)
2020 ModestWindow *top_win;
2021 HildonWindowStack *stack;
2023 stack = hildon_window_stack_get_default ();
2024 top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2027 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2032 gboolean retval = TRUE;
2034 /* The Tinymail documentation says that we should show Yes and No buttons,
2035 * when it is a question.
2036 * Obviously, we need tinymail to use more specific error codes instead,
2037 * so we know what buttons to show. */
2038 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win),
2040 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2041 GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2043 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2044 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2046 on_destroy_dialog (dialog);
2048 /* Just show the error text and use the default response: */
2049 modest_platform_run_information_dialog (GTK_WINDOW (top_win),
2057 GtkWindow *parent_window;
2058 ModestConnectedPerformer callback;
2059 TnyAccount *account;
2066 on_went_online_info_free (OnWentOnlineInfo *info)
2068 /* And if we cleanup, we DO cleanup :-) */
2071 g_object_unref (info->device);
2074 if (info->parent_window)
2075 g_object_unref (info->parent_window);
2077 g_object_unref (info->account);
2079 g_slice_free (OnWentOnlineInfo, info);
2081 /* We're done ... */
2087 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2089 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2091 /* Now it's really time to callback to the caller. If going online didn't succeed,
2092 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2093 * canceled will be set. Etcetera etcetera. */
2095 if (info->callback) {
2096 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2099 /* This is our last call, we must cleanup here if we didn't yet do that */
2100 on_went_online_info_free (info);
2107 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2109 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2110 info->iap = g_strdup (iap_id);
2112 if (canceled || err || !info->account) {
2114 /* If there's a problem or if there's no account (then that's it for us, we callback
2115 * the caller's callback now. He'll have to handle err or canceled, of course.
2116 * We are not really online, as the account is not really online here ... */
2118 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2119 * this info. We don't cleanup err, Tinymail does that! */
2121 if (info->callback) {
2123 /* info->account can be NULL here, this means that the user did not
2124 * provide a nice account instance. We'll assume that the user knows
2125 * what he's doing and is happy with just the device going online.
2127 * We can't do magic, we don't know what account the user wants to
2128 * see going online. So just the device goes online, end of story */
2130 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2133 } else if (info->account) {
2135 /* If there's no problem and if we have an account, we'll put the account
2136 * online too. When done, the callback of bringing the account online
2137 * will callback the caller's callback. This is the most normal case. */
2139 info->device = TNY_DEVICE (g_object_ref (device));
2141 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2142 on_account_went_online, info);
2144 /* The on_account_went_online cb frees up the info, go look if you
2145 * don't believe me! (so we return here) */
2150 /* We cleanup if we are not bringing the account online too */
2151 on_went_online_info_free (info);
2157 modest_platform_connect_and_perform (GtkWindow *parent_window,
2159 TnyAccount *account,
2160 ModestConnectedPerformer callback,
2163 gboolean device_online;
2165 TnyConnectionStatus conn_status;
2166 OnWentOnlineInfo *info;
2168 device = modest_runtime_get_device();
2169 device_online = tny_device_is_online (device);
2171 /* If there is no account check only the device status */
2174 if (device_online) {
2176 /* We promise to instantly perform the callback, so ... */
2178 callback (FALSE, NULL, parent_window, account, user_data);
2183 info = g_slice_new0 (OnWentOnlineInfo);
2186 info->device = NULL;
2187 info->account = NULL;
2190 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2192 info->parent_window = NULL;
2193 info->user_data = user_data;
2194 info->callback = callback;
2196 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2197 force, on_conic_device_went_online,
2200 /* We'll cleanup in on_conic_device_went_online */
2203 /* The other code has no more reason to run. This is all that we can do for the
2204 * caller (he should have given us a nice and clean account instance!). We
2205 * can't do magic, we don't know what account he intends to bring online. So
2206 * we'll just bring the device online (and await his false bug report). */
2212 /* Return if the account is already connected */
2214 conn_status = tny_account_get_connection_status (account);
2215 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2217 /* We promise to instantly perform the callback, so ... */
2219 callback (FALSE, NULL, parent_window, account, user_data);
2225 /* Else, we are in a state that requires that we go online before we
2226 * call the caller's callback. */
2228 info = g_slice_new0 (OnWentOnlineInfo);
2230 info->device = NULL;
2232 info->account = TNY_ACCOUNT (g_object_ref (account));
2235 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2237 info->parent_window = NULL;
2239 /* So we'll put the callback away for later ... */
2241 info->user_data = user_data;
2242 info->callback = callback;
2244 if (!device_online) {
2246 /* If also the device is offline, then we connect both the device
2247 * and the account */
2249 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2250 force, on_conic_device_went_online,
2255 /* If the device is online, we'll just connect the account */
2257 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2258 on_account_went_online, info);
2261 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2262 * in both situations, go look if you don't believe me! */
2268 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2270 TnyFolderStore *folder_store,
2271 ModestConnectedPerformer callback,
2274 TnyAccount *account = NULL;
2276 if (!folder_store ||
2277 (TNY_IS_MERGE_FOLDER (folder_store) &&
2278 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2280 /* We promise to instantly perform the callback, so ... */
2282 GError *error = NULL;
2283 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2284 "Unable to move or not found folder");
2285 callback (FALSE, error, parent_window, NULL, user_data);
2286 g_error_free (error);
2290 } else if (TNY_IS_FOLDER (folder_store)) {
2291 /* Get the folder's parent account: */
2292 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2293 } else if (TNY_IS_ACCOUNT (folder_store)) {
2294 /* Use the folder store as an account: */
2295 account = TNY_ACCOUNT (g_object_ref (folder_store));
2298 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2299 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2300 /* No need to connect a local account */
2302 callback (FALSE, NULL, parent_window, account, user_data);
2307 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2311 g_object_unref (account);
2315 src_account_connect_performer (gboolean canceled,
2317 GtkWindow *parent_window,
2318 TnyAccount *src_account,
2321 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2323 if (canceled || err) {
2324 /* If there was any error call the user callback */
2325 info->callback (canceled, err, parent_window, src_account, info->data);
2327 /* Connect the destination account */
2328 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2329 TNY_FOLDER_STORE (info->dst_account),
2330 info->callback, info->data);
2333 /* Free the info object */
2334 g_object_unref (info->dst_account);
2335 g_slice_free (DoubleConnectionInfo, info);
2340 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2342 TnyFolderStore *folder_store,
2343 DoubleConnectionInfo *connect_info)
2345 modest_platform_connect_if_remote_and_perform(parent_window,
2348 src_account_connect_performer,
2353 modest_platform_get_account_settings_wizard (void)
2355 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2357 return GTK_WIDGET (dialog);
2361 modest_platform_get_current_connection (void)
2363 TnyDevice *device = NULL;
2364 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2366 device = modest_runtime_get_device ();
2368 if (!tny_device_is_online (device))
2369 return MODEST_CONNECTED_VIA_ANY;
2371 #ifdef MODEST_HAVE_CONIC
2373 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2375 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2376 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2377 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2379 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2380 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2381 !strcmp (bearer_type, "WIMAX")) {
2382 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2384 retval = MODEST_CONNECTED_VIA_ANY;
2387 g_object_unref (iap);
2390 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2391 #endif /* MODEST_HAVE_CONIC */
2398 modest_platform_check_memory_low (ModestWindow *win,
2403 /* are we in low memory state? */
2404 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2406 if (win && lowmem && visuals)
2407 modest_platform_run_information_dialog (
2409 _KR("memr_ib_operation_disabled"),
2413 g_debug ("%s: low memory reached. disallowing some operations",
2420 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2426 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2429 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2430 GTK_WINDOW (dialog),
2432 gtk_widget_show_all (dialog);
2434 g_signal_connect_swapped (dialog, "response",
2435 G_CALLBACK (gtk_widget_destroy),
2440 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2446 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2449 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2450 GTK_WINDOW (dialog),
2452 gtk_widget_show_all (dialog);
2454 g_signal_connect_swapped (dialog, "response",
2455 G_CALLBACK (gtk_widget_destroy),
2460 modest_platform_get_osso_context (void)
2462 return modest_maemo_utils_get_osso_context ();
2466 _modest_platform_play_email_tone (void)
2469 gint mail_volume_int;
2471 ca_context *ca_con = NULL;
2472 ca_proplist *pl = NULL;
2474 #ifdef MODEST_USE_PROFILE
2475 gchar *active_profile;
2478 active_profile = profile_get_profile ();
2479 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2480 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2481 mail_volume_int = profile_parse_int (mail_volume);
2482 g_free (mail_volume);
2483 g_free (active_profile);
2485 mail_tone = MAIL_TONE;
2486 mail_volume_int = 100;
2489 if (mail_tone && !strstr (mail_tone, "/")) {
2492 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2497 if (mail_volume_int > 0) {
2499 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2500 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2504 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2505 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2506 ca_context_destroy(ca_con);
2510 ca_proplist_create(&pl);
2511 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2512 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2514 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2515 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2517 ca_proplist_destroy(pl);
2518 ca_context_destroy(ca_con);
2524 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2525 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2526 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2527 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2528 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2529 #define MOVE_TO_FOLDER_SEPARATOR "/"
2532 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
2533 TnyFolderStore *folder_store)
2535 GtkWidget *action_button;
2536 GtkWidget *image = NULL;
2537 TnyAccount *account;
2538 gchar *account_name = NULL;
2540 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2542 /* Get account name */
2543 if (TNY_IS_FOLDER (folder_store))
2544 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2546 account = g_object_ref (folder_store);
2548 if (modest_tny_account_is_virtual_local_folders (account))
2549 account_name = modest_conf_get_string (modest_runtime_get_conf(),
2550 MODEST_CONF_DEVICE_NAME, NULL);
2553 account_name = g_strdup (tny_account_get_name (account));
2555 g_object_unref (account);
2557 /* Set title of button: account or folder name */
2558 if (TNY_IS_FOLDER (folder_store)) {
2559 hildon_button_set_title (HILDON_BUTTON (action_button),
2560 tny_folder_get_name (TNY_FOLDER (folder_store)));
2562 hildon_button_set_title (HILDON_BUTTON (action_button), account_name);
2565 /* Set value of button, folder full name */
2566 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
2567 gchar *full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
2568 tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store)),
2570 hildon_button_set_value (HILDON_BUTTON (action_button), full_name);
2573 g_free (account_name);
2575 /* Set image for the button */
2576 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
2578 hildon_button_set_image (HILDON_BUTTON (action_button), image);
2582 move_to_dialog_show_accounts (GtkWidget *dialog)
2584 GtkWidget *back_button;
2585 GtkWidget *folder_view;
2586 GtkWidget *pannable;
2587 GtkWidget *action_button;
2589 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2590 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2591 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2592 pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2594 gtk_widget_set_sensitive (back_button, FALSE);
2595 gtk_widget_set_sensitive (action_button, FALSE);
2597 /* Need to set this here, otherwise callbacks called because
2598 of filtering won't perform correctly */
2599 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2601 /* Reset action button */
2602 hildon_button_set_title (HILDON_BUTTON (action_button), NULL);
2603 hildon_button_set_value (HILDON_BUTTON (action_button), NULL);
2604 hildon_button_set_image (HILDON_BUTTON (action_button), NULL);
2606 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
2607 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2608 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2609 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2610 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2611 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2612 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2613 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2614 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2615 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2616 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2617 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2621 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2623 GtkWidget *back_button;
2624 GtkWidget *folder_view;
2625 TnyAccount *account;
2626 const gchar *account_id;
2627 GtkWidget *pannable;
2628 GtkWidget *action_button;
2631 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2633 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2635 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2637 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2639 gtk_widget_set_sensitive (back_button, TRUE);
2640 gtk_widget_set_sensitive (action_button, TRUE);
2642 /* Need to set this here, otherwise callbacks called because
2643 of filtering won't perform correctly */
2644 g_object_set_data (G_OBJECT (dialog),
2645 MOVE_TO_DIALOG_SHOWING_FOLDERS,
2646 GINT_TO_POINTER (TRUE));
2648 account = TNY_ACCOUNT (folder_store);
2649 if (modest_tny_account_is_virtual_local_folders (account)) {
2650 account_id = tny_account_get_id (account);
2651 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2652 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2653 } else if (modest_tny_account_is_memory_card_account (account)) {
2654 account_id = tny_account_get_id (account);
2655 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2656 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2658 account_id = tny_account_get_id (account);
2659 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2660 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2661 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2662 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2665 move_to_dialog_set_selected_folder_store (dialog, folder_store);
2666 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2669 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2670 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2671 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2672 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2673 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2677 on_move_to_dialog_back_clicked (GtkButton *button,
2680 GtkWidget *dialog = (GtkWidget *) userdata;
2682 /* Back to show accounts */
2683 move_to_dialog_show_accounts (dialog);
2687 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
2689 GtkTreeViewColumn *column,
2692 TnyFolderStore *selected = NULL;
2694 GtkWidget *folder_view;
2695 gboolean showing_folders;
2697 dialog = (GtkWidget *) user_data;
2698 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
2699 MOVE_TO_DIALOG_SHOWING_FOLDERS));
2701 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
2702 MOVE_TO_DIALOG_FOLDER_VIEW));
2704 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2708 if (!showing_folders) {
2709 gboolean valid = TRUE;
2711 if (TNY_IS_ACCOUNT (selected) &&
2712 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2713 ModestProtocolType protocol_type;
2715 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2716 valid = !modest_protocol_registry_protocol_type_has_tag
2717 (modest_runtime_get_protocol_registry (),
2719 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_MESSAGE_ADD);
2722 move_to_dialog_show_folders (dialog, selected);
2724 move_to_dialog_set_selected_folder_store (dialog, selected);
2729 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2732 gboolean showing_folders;
2735 dialog = (GtkWidget *) user_data;
2736 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2737 if (showing_folders) {
2738 TnyFolderStore *selected;
2739 GtkWidget *folder_view;
2741 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2742 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2745 move_to_dialog_set_selected_folder_store (dialog, selected);
2746 g_object_unref (selected);
2752 on_move_to_dialog_action_clicked (GtkButton *selection,
2755 TnyFolderStore *selected;
2757 GtkWidget *folder_view;
2758 gboolean showing_folders;
2760 dialog = (GtkWidget *) user_data;
2761 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2762 if (showing_folders) {
2763 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2764 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2767 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2772 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2773 GtkWidget **folder_view)
2775 GtkWidget *dialog, *folder_view_container;
2777 GtkWidget *buttons_hbox;
2778 GtkWidget *back_button;
2779 GdkPixbuf *back_pixbuf;
2780 GtkWidget *top_vbox;
2781 GtkWidget *action_button;
2782 GtkTreeSelection *selection;
2784 /* Create dialog. We cannot use a touch selector because we
2785 need to use here the folder view widget directly */
2786 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2787 GTK_WINDOW (parent_window),
2788 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2789 GTK_DIALOG_DESTROY_WITH_PARENT,
2790 _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2793 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2794 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2795 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2797 /* Create folder view */
2798 *folder_view = modest_platform_create_folder_view (NULL);
2800 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2801 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2802 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2804 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2805 (TnyAccountStore *) modest_runtime_get_account_store ());
2807 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2808 back_button = gtk_button_new ();
2809 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2811 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2812 g_object_unref (back_pixbuf);
2815 action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
2816 HILDON_BUTTON_ARRANGEMENT_VERTICAL);
2817 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2819 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2820 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2821 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2822 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2823 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2825 /* Create pannable and add it to the dialog */
2826 folder_view_container = hildon_pannable_area_new ();
2827 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2828 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2830 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2831 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2833 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2835 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2836 gtk_widget_show (folder_view_container);
2837 gtk_widget_show (align);
2838 gtk_widget_show (top_vbox);
2839 gtk_widget_show (*folder_view);
2840 gtk_widget_show_all (back_button);
2841 gtk_widget_show (action_button);
2842 gtk_widget_show (buttons_hbox);
2843 gtk_widget_show (dialog);
2845 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2846 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2847 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2848 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2850 /* Simulate the behaviour of a HildonPickerDialog by emitting
2851 a response when a folder is selected */
2852 g_signal_connect (*folder_view, "row-activated",
2853 G_CALLBACK (on_move_to_dialog_row_activated),
2856 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2857 g_signal_connect (selection, "changed",
2858 G_CALLBACK (on_move_to_dialog_selection_changed),
2861 g_signal_connect (action_button, "clicked",
2862 G_CALLBACK (on_move_to_dialog_action_clicked),
2865 g_signal_connect (back_button, "clicked",
2866 G_CALLBACK (on_move_to_dialog_back_clicked),
2869 move_to_dialog_show_accounts (dialog);
2875 modest_platform_get_list_to_move (ModestWindow *window)
2877 TnyList *list = NULL;
2879 if (MODEST_IS_HEADER_WINDOW (window)) {
2880 ModestHeaderView *header_view;
2882 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2883 list = modest_header_view_get_selected_headers (header_view);
2884 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2885 ModestFolderView *folder_view;
2886 TnyFolderStore *selected_folder;
2888 list = TNY_LIST (tny_simple_list_new ());
2889 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2890 selected_folder = modest_folder_view_get_selected (folder_view);
2891 if (selected_folder) {
2892 tny_list_prepend (list, G_OBJECT (selected_folder));
2893 g_object_unref (selected_folder);
2896 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2899 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2901 list = TNY_LIST (tny_simple_list_new ());
2902 tny_list_prepend (list, G_OBJECT (header));
2903 g_object_unref (header);
2906 g_return_val_if_reached (NULL);