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>
81 #include <modest-count-stream.h>
83 #ifdef MODEST_HAVE_MCE
84 #include <mce/dbus-names.h>
85 #endif /*MODEST_HAVE_MCE*/
87 #ifdef MODEST_HAVE_ABOOK
88 #include <libosso-abook/osso-abook.h>
89 #endif /*MODEST_HAVE_ABOOK*/
91 #ifdef MODEST_HAVE_LIBALARM
92 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
93 #endif /*MODEST_HAVE_LIBALARM*/
96 #define HILDON_OSSO_URI_ACTION "uri-action"
97 #define URI_ACTION_COPY "copy:"
98 #define MODEST_NOTIFICATION_CATEGORY "email-message"
99 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
100 #ifdef MODEST_USE_PROFILE
101 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
102 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
104 #define MAIL_TONE "message-new-email"
107 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
108 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
109 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
110 #define MODEST_ALARMD_APPID PACKAGE_NAME
113 static void _modest_platform_play_email_tone (void);
117 on_modest_conf_update_interval_changed (ModestConf* self,
119 ModestConfEvent event,
120 ModestConfNotificationId id,
123 g_return_if_fail (key);
125 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
126 const guint update_interval_minutes =
127 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
128 modest_platform_set_update_interval (update_interval_minutes);
135 check_required_files (void)
137 FILE *mcc_file = modest_utils_open_mcc_mapping_file (NULL);
139 g_printerr ("modest: check for mcc file failed\n");
144 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
145 access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
146 g_printerr ("modest: cannot find providers data\n");
154 /* the gpointer here is the osso_context. */
156 modest_platform_init (int argc, char *argv[])
158 osso_context_t *osso_context;
160 osso_hw_state_t hw_state = { 0 };
164 if (!check_required_files ()) {
165 g_printerr ("modest: missing required files\n");
169 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
172 g_printerr ("modest: failed to acquire osso context\n");
175 modest_maemo_utils_set_osso_context (osso_context);
177 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
178 g_printerr ("modest: could not get dbus connection\n");
182 /* Add a D-Bus handler to be used when the main osso-rpc
183 * D-Bus handler has not handled something.
184 * We use this for D-Bus methods that need to use more complex types
185 * than osso-rpc supports.
187 if (!dbus_connection_add_filter (con,
188 modest_dbus_req_filter,
192 g_printerr ("modest: Could not add D-Bus filter\n");
196 /* Register our simple D-Bus callbacks, via the osso API: */
197 osso_return_t result = osso_rpc_set_cb_f(osso_context,
201 modest_dbus_req_handler, NULL /* user_data */);
202 if (result != OSSO_OK) {
203 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
207 /* Register hardware event dbus callback: */
208 hw_state.shutdown_ind = TRUE;
209 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
211 /* Register osso auto-save callbacks: */
212 result = osso_application_set_autosave_cb (osso_context,
213 modest_on_osso_application_autosave, NULL /* user_data */);
214 if (result != OSSO_OK) {
215 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
220 /* Make sure that the update interval is changed whenever its gconf key
222 /* CAUTION: we're not using here the
223 modest_conf_listen_to_namespace because we know that there
224 are other parts of Modest listening for this namespace, so
225 we'll receive the notifications anyway. We basically do not
226 use it because there is no easy way to do the
227 modest_conf_forget_namespace */
228 ModestConf *conf = modest_runtime_get_conf ();
229 g_signal_connect (G_OBJECT(conf),
231 G_CALLBACK (on_modest_conf_update_interval_changed),
234 /* only force the setting of the default interval, if there are actually
236 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
238 /* Get the initial update interval from gconf: */
239 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
240 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
241 modest_account_mgr_free_account_names (acc_names);
245 #ifdef MODEST_HAVE_ABOOK
246 /* initialize the addressbook */
247 if (!osso_abook_init (&argc, &argv, osso_context)) {
248 g_printerr ("modest: failed to initialized addressbook\n");
251 #endif /*MODEST_HAVE_ABOOK*/
257 modest_platform_uninit (void)
259 osso_context_t *osso_context =
260 modest_maemo_utils_get_osso_context ();
262 osso_deinitialize (osso_context);
271 modest_platform_get_new_device (void)
273 return TNY_DEVICE (tny_maemo_conic_device_new ());
277 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
278 gchar **effective_mime_type)
280 GString *mime_str = NULL;
281 gchar *icon_name = NULL;
282 gchar **icons, **cursor;
284 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
285 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
287 mime_str = g_string_new (mime_type);
288 g_string_ascii_down (mime_str);
291 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
293 for (cursor = icons; cursor; ++cursor) {
294 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
295 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
296 icon_name = g_strdup ("qgn_list_messagin");
298 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
299 icon_name = g_strdup (*cursor);
305 if (effective_mime_type)
306 *effective_mime_type = g_string_free (mime_str, FALSE);
308 g_string_free (mime_str, TRUE);
315 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
320 g_return_val_if_fail (uri, FALSE);
322 result = hildon_uri_open (uri, action, &err);
324 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
325 uri, action, err && err->message ? err->message : "unknown error");
335 modest_platform_activate_uri (const gchar *uri)
337 HildonURIAction *action;
338 gboolean result = FALSE;
339 GSList *actions, *iter = NULL;
341 g_return_val_if_fail (uri, FALSE);
345 /* don't try to activate file: uri's -- they might confuse the user,
346 * and/or might have security implications */
347 if (!g_str_has_prefix (uri, "file:")) {
349 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
351 for (iter = actions; iter; iter = g_slist_next (iter)) {
352 action = (HildonURIAction*) iter->data;
353 if (action && strcmp (hildon_uri_action_get_service (action),
354 "com.nokia.modest") == 0) {
355 result = checked_hildon_uri_open (uri, action);
360 /* if we could not open it with email, try something else */
362 result = checked_hildon_uri_open (uri, NULL);
366 ModestWindow *parent =
367 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
368 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
369 _("mcen_ib_unsupported_link"));
370 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
377 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
381 gchar *uri_path = NULL;
383 uri_path = gnome_vfs_get_uri_from_local_path (path);
384 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
387 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
389 result = hildon_mime_open_file (con, uri_path);
391 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
399 } ModestPlatformPopupInfo;
402 delete_uri_popup (GtkWidget *menu,
406 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
408 g_free (popup_info->uri);
409 hildon_uri_free_actions (popup_info->actions);
415 activate_uri_popup_item (GtkMenuItem *menu_item,
419 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
420 const gchar* action_name;
422 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
424 g_printerr ("modest: no action name defined\n");
428 /* special handling for the copy menu item -- copy the uri to the clipboard */
429 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
430 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
431 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
432 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
434 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
435 action_name += strlen ("mailto:");
437 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
438 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
439 return; /* we're done */
442 /* now, the real uri-actions... */
443 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
444 HildonURIAction *action = (HildonURIAction *) node->data;
445 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
446 if (!checked_hildon_uri_open (popup_info->uri, action)) {
447 ModestWindow *parent =
448 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
449 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
450 _("mcen_ib_unsupported_link"));
458 modest_platform_show_uri_popup (const gchar *uri)
460 GSList *actions_list;
465 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
468 GtkWidget *menu = gtk_menu_new ();
469 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
471 /* don't add actions for file: uri's -- they might confuse the user,
472 * and/or might have security implications
473 * we still allow to copy the url though
475 if (!g_str_has_prefix (uri, "file:")) {
478 popup_info->actions = actions_list;
479 popup_info->uri = g_strdup (uri);
481 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
482 GtkWidget *menu_item;
483 const gchar *action_name;
484 const gchar *translation_domain;
485 HildonURIAction *action = (HildonURIAction *) node->data;
486 action_name = hildon_uri_action_get_name (action);
487 translation_domain = hildon_uri_action_get_translation_domain (action);
488 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
489 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
490 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
493 if (hildon_uri_is_default_action (action, NULL)) {
494 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
496 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
498 gtk_widget_show (menu_item);
503 /* and what to do when the link is deleted */
504 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
505 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
508 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
516 modest_platform_get_icon (const gchar *name, guint icon_size)
519 GdkPixbuf* pixbuf = NULL;
520 GtkIconTheme *current_theme = NULL;
522 g_return_val_if_fail (name, NULL);
524 /* strlen == 0 is not really an error; it just
525 * means the icon is not available
527 if (!name || strlen(name) == 0)
530 current_theme = gtk_icon_theme_get_default ();
531 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
532 GTK_ICON_LOOKUP_NO_SVG,
535 g_printerr ("modest: error loading theme icon '%s': %s\n",
543 modest_platform_get_app_name (void)
545 return _("mcen_ap_name");
549 entry_insert_text (GtkEditable *editable,
558 chars = gtk_editable_get_chars (editable, 0, -1);
559 chars_length = g_utf8_strlen (chars, -1);
562 /* Show WID-INF036 */
563 if (chars_length >= 20) {
564 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
565 _CS("ckdg_ib_maximum_characters_reached"));
567 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
571 tmp = g_strndup (folder_name_forbidden_chars,
572 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
573 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
574 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
580 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
581 _CS("ckdg_ib_maximum_characters_reached"));
583 /* Write the text in the entry if it's valid */
584 g_signal_handlers_block_by_func (editable,
585 (gpointer) entry_insert_text, data);
586 gtk_editable_insert_text (editable, text, length, position);
587 g_signal_handlers_unblock_by_func (editable,
588 (gpointer) entry_insert_text, data);
591 /* Do not allow further processing */
592 g_signal_stop_emission_by_name (editable, "insert_text");
596 entry_changed (GtkEditable *editable,
600 GtkWidget *ok_button;
603 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
604 ok_button = GTK_WIDGET (buttons->data);
606 chars = gtk_editable_get_chars (editable, 0, -1);
607 g_return_if_fail (chars != NULL);
610 if (g_utf8_strlen (chars,-1) >= 20) {
611 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
612 _CS("ckdg_ib_maximum_characters_reached"));
614 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
617 g_list_free (buttons);
624 on_response (GtkDialog *dialog,
628 GtkWidget *entry, *picker;
629 TnyFolderStore *parent;
630 const gchar *new_name;
633 if (response != GTK_RESPONSE_ACCEPT)
637 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
638 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
640 parent = TNY_FOLDER_STORE (user_data);
641 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
645 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
647 /* Look for another folder with the same name */
648 if (modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
652 if (TNY_IS_ACCOUNT (parent) &&
653 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
654 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
662 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
663 NULL, _CS("ckdg_ib_folder_already_exists"));
664 /* Select the text */
665 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
666 gtk_widget_grab_focus (entry);
667 /* Do not close the dialog */
668 g_signal_stop_emission_by_name (dialog, "response");
672 typedef struct _FolderChooserData {
673 TnyFolderStore *store;
678 folder_chooser_activated (ModestFolderView *folder_view,
679 TnyFolderStore *folder,
680 FolderChooserData *userdata)
682 userdata->store = folder;
683 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
686 static TnyFolderStore *
687 folder_chooser_dialog_run (ModestFolderView *original)
689 GtkWidget *folder_view;
690 FolderChooserData userdata = {NULL, NULL};
692 const gchar *visible_id = NULL;
694 userdata.dialog = hildon_dialog_new ();
695 pannable = hildon_pannable_area_new ();
696 folder_view = modest_platform_create_folder_view (NULL);
698 gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
700 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
701 MODEST_FOLDER_VIEW (folder_view));
704 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
705 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
708 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
709 gtk_container_add (GTK_CONTAINER (pannable), folder_view);
710 gtk_widget_set_size_request (pannable, -1, 320);
712 gtk_widget_show (folder_view);
713 gtk_widget_show (pannable);
714 gtk_widget_show (userdata.dialog);
715 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
716 G_CALLBACK (folder_chooser_activated),
717 (gpointer) &userdata);
719 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
720 gtk_widget_destroy (userdata.dialog);
722 return userdata.store;
726 folder_store_get_display_name (TnyFolderStore *store)
728 if (TNY_IS_ACCOUNT (store)) {
729 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
730 return modest_conf_get_string (modest_runtime_get_conf(),
731 MODEST_CONF_DEVICE_NAME, NULL);
733 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
736 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
738 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
739 type = tny_folder_get_folder_type (TNY_FOLDER (store));
740 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
741 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
742 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
743 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
745 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
748 /* Sometimes an special folder is reported by the server as
749 NORMAL, like some versions of Dovecot */
750 if (type == TNY_FOLDER_TYPE_NORMAL ||
751 type == TNY_FOLDER_TYPE_UNKNOWN) {
752 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
756 if (type == TNY_FOLDER_TYPE_INBOX) {
758 fname = g_strdup (_("mcen_me_folder_inbox"));
765 get_image_for_folder_store (TnyFolderStore *store,
769 const gchar *icon_name = NULL;
770 GtkWidget *image = NULL;
772 if (TNY_IS_ACCOUNT (store)) {
773 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
774 icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
775 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
776 icon_name = MODEST_FOLDER_ICON_MMC;
778 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
780 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
781 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
783 case TNY_FOLDER_TYPE_INBOX:
784 icon_name = MODEST_FOLDER_ICON_INBOX;
787 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
789 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
791 case TNY_FOLDER_TYPE_OUTBOX:
792 icon_name = MODEST_FOLDER_ICON_OUTBOX;
794 case TNY_FOLDER_TYPE_DRAFTS:
795 icon_name = MODEST_FOLDER_ICON_DRAFTS;
797 case TNY_FOLDER_TYPE_SENT:
798 icon_name = MODEST_FOLDER_ICON_SENT;
801 icon_name = MODEST_FOLDER_ICON_NORMAL;
803 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
804 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
809 pixbuf = modest_platform_get_icon (icon_name, size);
812 image = gtk_image_new_from_pixbuf (pixbuf);
813 g_object_unref (pixbuf);
820 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
825 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
829 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
830 g_object_ref (store),
831 (GDestroyNotify) g_object_unref);
832 name = folder_store_get_display_name (store);
833 hildon_button_set_value (HILDON_BUTTON (button), name);
837 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
839 hildon_button_set_image (HILDON_BUTTON (button), image);
843 /* Always returns DUPs so you must free the returned value */
845 get_next_folder_name (const gchar *suggested_name,
846 TnyFolderStore *suggested_folder)
848 const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
850 gchar *real_suggested_name;
852 if (suggested_name !=NULL) {
853 return g_strdup (suggested_name);
856 for(i = 0; i < 100; ++ i) {
857 gboolean exists = FALSE;
860 real_suggested_name = g_strdup (default_name);
862 real_suggested_name = g_strdup_printf ("%s(%d)",
863 _FM("ckdg_va_new_folder_name_stub"),
865 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
872 g_free (real_suggested_name);
875 /* Didn't find a free number */
877 real_suggested_name = g_strdup (default_name);
879 return real_suggested_name;
883 ModestFolderView *folder_view;
885 } FolderPickerHelper;
888 folder_picker_clicked (GtkButton *button,
889 FolderPickerHelper *helper)
891 TnyFolderStore *store;
893 store = folder_chooser_dialog_run (helper->folder_view);
895 const gchar *current_name;
898 folder_picker_set_store (GTK_BUTTON (button), store);
900 /* Update the name of the folder */
901 current_name = gtk_entry_get_text (helper->entry);
902 exists = modest_tny_folder_has_subfolder_with_name (store,
906 gchar *new_name = get_next_folder_name (NULL, store);
907 gtk_entry_set_text (helper->entry, new_name);
914 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
918 button = hildon_button_new (MODEST_EDITABLE_SIZE,
919 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
921 hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
924 folder_picker_set_store (GTK_BUTTON (button), suggested);
926 g_signal_connect (G_OBJECT (button), "clicked",
927 G_CALLBACK (folder_picker_clicked),
935 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
936 TnyFolderStore *suggested_parent,
937 const gchar *dialog_title,
938 const gchar *label_text,
939 const gchar *suggested_name,
941 gboolean show_parent,
943 TnyFolderStore **parent)
945 GtkWidget *accept_btn = NULL;
946 GtkWidget *dialog, *entry = NULL, *label_entry = NULL, *label_location = NULL, *hbox;
947 GtkWidget *account_picker = NULL;
948 GList *buttons = NULL;
950 GtkSizeGroup *sizegroup;
951 ModestFolderView *folder_view;
952 ModestWindow *folder_window;
953 ModestHildon2WindowMgr *window_mgr;
954 FolderPickerHelper *helper = NULL;
955 GtkWidget *top_vbox, *top_align;
957 window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
958 folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
959 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
961 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
963 top_vbox = gtk_vbox_new (FALSE, 0);
964 top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
965 gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
967 /* Ask the user for the folder name */
968 dialog = gtk_dialog_new_with_buttons (dialog_title,
970 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
971 _FM("ckdg_bd_new_folder_dialog_ok"),
975 /* Add accept button (with unsensitive handler) */
976 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
977 accept_btn = GTK_WIDGET (buttons->data);
979 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
982 label_entry = gtk_label_new (label_text);
983 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
984 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
986 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
987 gtk_size_group_add_widget (sizegroup, label_entry);
990 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
992 gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
993 gtk_entry_set_width_chars (GTK_ENTRY (entry),
994 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
995 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
996 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
1001 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
1003 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
1004 gtk_size_group_add_widget (sizegroup, label_location);
1006 helper = g_slice_new0 (FolderPickerHelper);
1007 helper->folder_view = folder_view;
1008 helper->entry = (GtkEntry *) entry;
1010 account_picker = folder_picker_new (suggested_parent, helper);
1013 g_object_unref (sizegroup);
1015 /* Connect to the response method to avoid closing the dialog
1016 when an invalid name is selected*/
1017 g_signal_connect (dialog,
1019 G_CALLBACK (on_response),
1023 /* Track entry changes */
1024 g_signal_connect (entry,
1026 G_CALLBACK (entry_insert_text),
1028 g_signal_connect (entry,
1030 G_CALLBACK (entry_changed),
1035 /* Some locales like pt_BR need this to get the full window
1037 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
1039 /* Create the hbox */
1041 hbox = gtk_hbox_new (FALSE, 12);
1042 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
1043 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
1045 /* Add hbox to dialog */
1046 gtk_box_pack_start (GTK_BOX (top_vbox),
1047 hbox, FALSE, FALSE, 0);
1048 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
1052 hbox = gtk_hbox_new (FALSE, 12);
1053 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
1054 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
1056 /* Add hbox to dialog */
1057 gtk_box_pack_start (GTK_BOX (top_vbox),
1058 hbox, FALSE, FALSE, 0);
1059 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
1061 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1062 GTK_WINDOW (dialog), parent_window);
1064 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
1065 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
1067 gtk_widget_show_all (GTK_WIDGET(dialog));
1069 result = gtk_dialog_run (GTK_DIALOG(dialog));
1070 if (result == GTK_RESPONSE_ACCEPT) {
1072 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1074 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
1076 g_object_ref (*parent);
1080 gtk_widget_destroy (dialog);
1083 g_slice_free (FolderPickerHelper, helper);
1085 while (gtk_events_pending ())
1086 gtk_main_iteration ();
1092 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
1093 TnyFolderStore *suggested_folder,
1094 gchar *suggested_name,
1095 gchar **folder_name,
1096 TnyFolderStore **parent_folder)
1098 gchar *real_suggested_name = NULL;
1100 ModestTnyAccountStore *acc_store;
1101 TnyAccount *account;
1102 gboolean do_free = FALSE;
1104 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
1107 /* In hildon 2.2 we always suggest the archive folder as parent */
1108 acc_store = modest_runtime_get_account_store ();
1109 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1111 suggested_folder = (TnyFolderStore *)
1112 modest_tny_account_get_special_folder (account,
1113 TNY_FOLDER_TYPE_ARCHIVE);
1114 g_object_unref (account);
1118 /* If there is not archive folder then fallback to local folders account */
1119 if (!suggested_folder) {
1121 suggested_folder = (TnyFolderStore *)
1122 modest_tny_account_store_get_local_folders_account (acc_store);
1125 result = modest_platform_run_folder_common_dialog (parent_window,
1127 _HL("ckdg_ti_new_folder"),
1128 _FM("ckdg_fi_new_folder_name"),
1129 real_suggested_name,
1136 g_object_unref (suggested_folder);
1138 g_free(real_suggested_name);
1144 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1145 TnyFolderStore *parent_folder,
1146 const gchar *suggested_name,
1147 gchar **folder_name)
1149 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1151 return modest_platform_run_folder_common_dialog (parent_window,
1153 _HL("ckdg_ti_rename_folder"),
1154 _HL("ckdg_fi_rename_name"),
1165 on_destroy_dialog (GtkWidget *dialog)
1167 /* This could happen when the dialogs get programatically
1168 hidden or destroyed (for example when closing the
1169 application while a dialog is being shown) */
1170 if (!GTK_IS_WIDGET (dialog))
1173 gtk_widget_destroy (dialog);
1175 if (gtk_events_pending ())
1176 gtk_main_iteration ();
1180 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1181 const gchar *message)
1186 dialog = hildon_note_new_confirmation (parent_window, message);
1187 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1188 GTK_WINDOW (dialog), parent_window);
1190 response = gtk_dialog_run (GTK_DIALOG (dialog));
1192 on_destroy_dialog (dialog);
1198 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1199 const gchar *message,
1200 const gchar *button_accept,
1201 const gchar *button_cancel)
1206 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1207 button_accept, GTK_RESPONSE_ACCEPT,
1208 button_cancel, GTK_RESPONSE_CANCEL,
1211 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1212 GTK_WINDOW (dialog), parent_window);
1214 response = gtk_dialog_run (GTK_DIALOG (dialog));
1216 on_destroy_dialog (dialog);
1222 modest_platform_run_information_dialog (GtkWindow *parent_window,
1223 const gchar *message,
1228 note = hildon_note_new_information (parent_window, message);
1230 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1231 GTK_WINDOW (note), parent_window);
1234 gtk_dialog_run (GTK_DIALOG (note));
1236 on_destroy_dialog (note);
1238 g_signal_connect_swapped (note,
1240 G_CALLBACK (on_destroy_dialog),
1243 gtk_widget_show_all (note);
1247 typedef struct _ConnectAndWaitData {
1249 GMainLoop *wait_loop;
1250 gboolean has_callback;
1252 } ConnectAndWaitData;
1256 quit_wait_loop (TnyAccount *account,
1257 ConnectAndWaitData *data)
1259 /* Set the has_callback to TRUE (means that the callback was
1260 executed and wake up every code waiting for cond to be
1262 g_mutex_lock (data->mutex);
1263 data->has_callback = TRUE;
1264 if (data->wait_loop)
1265 g_main_loop_quit (data->wait_loop);
1266 g_mutex_unlock (data->mutex);
1270 on_connection_status_changed (TnyAccount *account,
1271 TnyConnectionStatus status,
1274 TnyConnectionStatus conn_status;
1275 ConnectAndWaitData *data;
1277 /* Ignore if reconnecting or disconnected */
1278 conn_status = tny_account_get_connection_status (account);
1279 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1280 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1283 /* Remove the handler */
1284 data = (ConnectAndWaitData *) user_data;
1285 g_signal_handler_disconnect (account, data->handler);
1287 /* Quit from wait loop */
1288 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1292 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1297 /* Quit from wait loop */
1298 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1302 modest_platform_connect_and_wait (GtkWindow *parent_window,
1303 TnyAccount *account)
1305 ConnectAndWaitData *data = NULL;
1306 gboolean device_online;
1308 TnyConnectionStatus conn_status;
1309 gboolean user_requested;
1311 device = modest_runtime_get_device();
1312 device_online = tny_device_is_online (device);
1314 /* Whether the connection is user requested or automatically
1315 requested, for example via D-Bus */
1316 user_requested = (parent_window) ? TRUE : FALSE;
1318 /* If there is no account check only the device status */
1323 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1324 NULL, user_requested);
1327 /* Return if the account is already connected */
1328 conn_status = tny_account_get_connection_status (account);
1329 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1332 /* Create the helper */
1333 data = g_slice_new0 (ConnectAndWaitData);
1334 data->mutex = g_mutex_new ();
1335 data->has_callback = FALSE;
1337 /* Connect the device */
1338 if (!device_online) {
1339 /* Track account connection status changes */
1340 data->handler = g_signal_connect (account, "connection-status-changed",
1341 G_CALLBACK (on_connection_status_changed),
1343 /* Try to connect the device */
1344 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1345 NULL, user_requested);
1347 /* If the device connection failed then exit */
1348 if (!device_online && data->handler)
1351 /* Force a reconnection of the account */
1352 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1353 on_tny_camel_account_set_online_cb, data);
1356 /* Wait until the callback is executed */
1357 g_mutex_lock (data->mutex);
1358 if (!data->has_callback) {
1359 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1360 gdk_threads_leave ();
1361 g_mutex_unlock (data->mutex);
1362 g_main_loop_run (data->wait_loop);
1363 g_mutex_lock (data->mutex);
1364 gdk_threads_enter ();
1366 g_mutex_unlock (data->mutex);
1369 if (g_signal_handler_is_connected (account, data->handler))
1370 g_signal_handler_disconnect (account, data->handler);
1371 g_mutex_free (data->mutex);
1372 g_main_loop_unref (data->wait_loop);
1373 g_slice_free (ConnectAndWaitData, data);
1375 conn_status = tny_account_get_connection_status (account);
1376 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1380 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1382 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1383 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1384 /* This must be a maildir account, which does not require a connection: */
1389 return modest_platform_connect_and_wait (parent_window, account);
1393 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1396 return TRUE; /* Maybe it is something local. */
1398 gboolean result = TRUE;
1399 if (TNY_IS_FOLDER (folder_store)) {
1400 /* Get the folder's parent account: */
1401 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1402 if (account != NULL) {
1403 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1404 g_object_unref (account);
1406 } else if (TNY_IS_ACCOUNT (folder_store)) {
1407 /* Use the folder store as an account: */
1408 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1415 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1419 dialog = modest_hildon2_sort_dialog_new (parent_window);
1426 modest_platform_set_update_interval (guint minutes)
1428 #ifdef MODEST_HAVE_LIBALARM
1430 ModestConf *conf = modest_runtime_get_conf ();
1434 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1436 /* Delete any existing alarm,
1437 * because we will replace it: */
1439 if (alarmd_event_del(alarm_cookie) != 0)
1440 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1442 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1445 /* 0 means no updates: */
1450 /* Register alarm: */
1452 /* Set the interval in alarm_event_t structure: */
1453 alarm_event_t *event = alarm_event_create ();
1454 alarm_event_add_actions (event, 1);
1455 alarm_action_t *action = alarm_event_get_action (event, 0);
1456 alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1457 event->alarm_time = minutes * 60; /* seconds */
1459 /* Set recurrence every few minutes: */
1460 event->recur_secs = minutes*60;
1461 event->recur_count = -1; /* Means infinite */
1463 /* Specify what should happen when the alarm happens:
1464 * It should call this D-Bus method: */
1466 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1467 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1468 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1469 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1470 action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1472 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1473 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1474 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1475 * This is why we want to use the Alarm API instead of just g_timeout_add().
1476 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1477 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1479 event->flags = ALARM_EVENT_CONNECTED;
1481 alarm_cookie = alarmd_event_add (event);
1484 alarm_event_delete (event);
1486 /* Store the alarm ID in GConf, so we can remove it later:
1487 * This is apparently valid between application instances. */
1488 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1490 if (!alarm_cookie) {
1492 g_debug ("Error setting alarm event. \n");
1496 #endif /* MODEST_HAVE_LIBALARM */
1501 modest_platform_push_email_notification(void)
1503 gboolean screen_on, app_in_foreground;
1505 /* Get the window status */
1506 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1508 screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1510 /* If the screen is on and the app is in the
1511 foreground we don't show anything */
1512 if (!(screen_on && app_in_foreground)) {
1514 _modest_platform_play_email_tone ();
1516 /* Activate LED. This must be deactivated by
1517 modest_platform_remove_new_mail_notifications */
1518 #ifdef MODEST_HAVE_MCE
1519 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1523 MCE_ACTIVATE_LED_PATTERN,
1525 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1532 modest_platform_on_new_headers_received (TnyList *header_list,
1533 gboolean show_visual)
1535 g_return_if_fail (TNY_IS_LIST(header_list));
1537 if (tny_list_get_length(header_list) == 0) {
1538 g_warning ("%s: header list is empty", __FUNCTION__);
1543 modest_platform_push_email_notification ();
1544 /* We do a return here to avoid indentation with an else */
1548 #ifdef MODEST_HAVE_HILDON_NOTIFY
1549 HildonNotification *notification;
1551 GSList *notifications_list = NULL;
1553 /* Get previous notifications ids */
1554 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1555 MODEST_CONF_NOTIFICATION_IDS,
1556 MODEST_CONF_VALUE_INT, NULL);
1558 iter = tny_list_create_iterator (header_list);
1559 while (!tny_iterator_is_done (iter)) {
1560 gchar *url = NULL, *display_address = NULL;
1561 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1562 TnyFolder *folder = tny_header_get_folder (header);
1563 gboolean first_notification = TRUE;
1567 display_address = tny_header_dup_from (header);
1568 /* string is changed in-place */
1569 modest_text_utils_get_display_address (display_address);
1571 str = tny_header_dup_subject (header);
1572 notification = hildon_notification_new (display_address,
1574 "qgn_list_messagin",
1575 MODEST_NOTIFICATION_CATEGORY);
1577 /* Create the message URL */
1578 str = tny_header_dup_uid (header);
1579 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1583 hildon_notification_add_dbus_action(notification,
1586 MODEST_DBUS_SERVICE,
1589 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1593 /* Play sound if the user wants. Show the LED
1594 pattern. Show and play just one */
1595 if (G_UNLIKELY (first_notification)) {
1596 TnyAccount *account;
1598 first_notification = FALSE;
1600 /* Set the led pattern */
1601 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1603 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1605 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1607 /* Set the account of the headers */
1608 account = tny_folder_get_account (folder);
1610 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1612 tny_account_get_id (account));
1613 g_object_unref (account);
1617 /* Notify. We need to do this in an idle because this function
1618 could be called from a thread */
1619 if (!notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1620 g_warning ("Failed to send notification");
1623 /* Save id in the list */
1624 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1625 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1626 /* We don't listen for the "closed" signal, because we
1627 don't care about if the notification was removed or
1628 not to store the list in gconf */
1630 /* Free & carry on */
1631 g_free (display_address);
1633 g_object_unref (folder);
1634 g_object_unref (header);
1635 tny_iterator_next (iter);
1637 g_object_unref (iter);
1640 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1641 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1643 g_slist_free (notifications_list);
1645 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1649 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1652 #ifdef MODEST_HAVE_MCE
1653 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1657 MCE_DEACTIVATE_LED_PATTERN,
1659 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1665 #ifdef MODEST_HAVE_HILDON_NOTIFY
1666 GSList *notif_list = NULL;
1668 /* Get previous notifications ids */
1669 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1670 MODEST_CONF_NOTIFICATION_IDS,
1671 MODEST_CONF_VALUE_INT, NULL);
1673 while (notif_list) {
1675 NotifyNotification *notif;
1677 /* Nasty HACK to remove the notifications, set the id
1678 of the existing ones and then close them */
1679 notif_id = GPOINTER_TO_INT(notif_list->data);
1680 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1681 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1683 /* Close the notification, note that some ids could be
1684 already invalid, but we don't care because it does
1686 notify_notification_close(notif, NULL);
1687 g_object_unref(notif);
1689 /* Delete the link, it's like going to the next */
1690 notif_list = g_slist_delete_link (notif_list, notif_list);
1694 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1695 notif_list, MODEST_CONF_VALUE_INT, NULL);
1697 g_slist_free (notif_list);
1699 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1705 modest_platform_get_global_settings_dialog ()
1707 return modest_hildon2_global_settings_dialog_new ();
1711 modest_platform_show_help (GtkWindow *parent_window,
1712 const gchar *help_id)
1718 modest_platform_show_search_messages (GtkWindow *parent_window)
1720 osso_return_t result = OSSO_ERROR;
1722 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1723 "osso_global_search",
1724 "search_email", NULL, DBUS_TYPE_INVALID);
1726 if (result != OSSO_OK) {
1727 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1732 modest_platform_show_addressbook (GtkWindow *parent_window)
1734 osso_return_t result = OSSO_ERROR;
1736 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1738 "top_application", NULL, DBUS_TYPE_INVALID);
1740 if (result != OSSO_OK) {
1741 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1746 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1748 GtkWidget *widget = modest_folder_view_new (query);
1750 /* Show one account by default */
1751 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1752 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1754 /* Restore settings */
1755 modest_widget_memory_restore (modest_runtime_get_conf(),
1757 MODEST_CONF_FOLDER_VIEW_KEY);
1763 banner_finish (gpointer data, GObject *object)
1765 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1766 modest_window_mgr_unregister_banner (mgr);
1767 g_object_unref (mgr);
1771 modest_platform_information_banner (GtkWidget *parent,
1772 const gchar *icon_name,
1775 GtkWidget *banner, *banner_parent = NULL;
1776 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1778 if (modest_window_mgr_get_num_windows (mgr) == 0)
1781 if (parent && GTK_IS_WINDOW (parent)) {
1782 /* If the window is the active one then show the
1783 banner on top of this window */
1784 if (gtk_window_is_active (GTK_WINDOW (parent)))
1785 banner_parent = parent;
1786 /* If the window is not the topmost but it's visible
1787 (it's minimized for example) then show the banner
1789 else if (GTK_WIDGET_VISIBLE (parent))
1790 banner_parent = NULL;
1791 /* If the window is hidden (like the main window when
1792 running in the background) then do not show
1799 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1801 modest_window_mgr_register_banner (mgr);
1803 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1807 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1808 const gchar *icon_name,
1814 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1817 banner = hildon_banner_show_information (parent, icon_name, text);
1818 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1822 modest_platform_animation_banner (GtkWidget *parent,
1823 const gchar *animation_name,
1826 GtkWidget *inf_note = NULL;
1828 g_return_val_if_fail (text != NULL, NULL);
1830 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1833 /* If the parent is not visible then do not show */
1834 if (parent && !GTK_WIDGET_VISIBLE (parent))
1837 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1845 TnyAccount *account;
1848 } CheckAccountIdleData;
1850 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1853 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1855 gboolean stop_trying = FALSE;
1856 g_return_val_if_fail (data && data->account, FALSE);
1858 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1859 tny_account_get_connection_status (data->account));
1861 if (data && data->account &&
1862 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1863 * after which the account is likely to be usable, or never likely to be usable soon: */
1864 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1866 data->is_online = TRUE;
1870 /* Give up if we have tried too many times: */
1871 if (data->count_tries >= NUMBER_OF_TRIES) {
1874 /* Wait for another timeout: */
1875 ++(data->count_tries);
1880 /* Allow the function that requested this idle callback to continue: */
1882 g_main_loop_quit (data->loop);
1885 g_object_unref (data->account);
1887 return FALSE; /* Don't call this again. */
1889 return TRUE; /* Call this timeout callback again. */
1893 /* Return TRUE immediately if the account is already online,
1894 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1895 * soon as the account is online, or FALSE if the account does
1896 * not become online in the NUMBER_OF_TRIES seconds.
1897 * This is useful when the D-Bus method was run immediately after
1898 * the application was started (when using D-Bus activation),
1899 * because the account usually takes a short time to go online.
1900 * The return value is maybe not very useful.
1903 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1907 g_return_val_if_fail (account, FALSE);
1909 if (!tny_device_is_online (modest_runtime_get_device())) {
1910 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1914 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1915 * so we avoid wait unnecessarily: */
1916 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1919 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1920 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1921 * we want to avoid. */
1922 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1925 /* This blocks on the result: */
1926 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1927 data->is_online = FALSE;
1928 data->account = account;
1929 g_object_ref (data->account);
1930 data->count_tries = 0;
1932 GMainContext *context = NULL; /* g_main_context_new (); */
1933 data->loop = g_main_loop_new (context, FALSE /* not running */);
1935 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1937 /* This main loop will run until the idle handler has stopped it: */
1938 g_main_loop_run (data->loop);
1940 g_main_loop_unref (data->loop);
1941 /* g_main_context_unref (context); */
1943 is_online = data->is_online;
1944 g_slice_free (CheckAccountIdleData, data);
1952 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1954 /* GTK_RESPONSE_HELP means we need to show the certificate */
1955 if (response_id == GTK_RESPONSE_APPLY) {
1959 /* Do not close the dialog */
1960 g_signal_stop_emission_by_name (dialog, "response");
1962 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1963 note = hildon_note_new_information (NULL, msg);
1964 gtk_dialog_run (GTK_DIALOG(note));
1965 gtk_widget_destroy (note);
1971 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1972 const gchar *certificate)
1977 HildonWindowStack *stack;
1979 stack = hildon_window_stack_get_default ();
1980 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1983 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1988 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1991 /* We use GTK_RESPONSE_APPLY because we want the button in the
1992 middle of OK and CANCEL the same as the browser does for
1993 example. With GTK_RESPONSE_HELP the view button is aligned
1994 to the left while the other two to the right */
1995 note = hildon_note_new_confirmation_add_buttons (
1998 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1999 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
2000 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
2003 g_signal_connect (G_OBJECT(note), "response",
2004 G_CALLBACK(on_cert_dialog_response),
2005 (gpointer) certificate);
2007 response = gtk_dialog_run(GTK_DIALOG(note));
2009 on_destroy_dialog (note);
2012 return response == GTK_RESPONSE_OK;
2016 modest_platform_run_alert_dialog (const gchar* prompt,
2017 gboolean is_question)
2019 ModestWindow *top_win;
2020 HildonWindowStack *stack;
2022 stack = hildon_window_stack_get_default ();
2023 top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2026 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2031 gboolean retval = TRUE;
2033 /* The Tinymail documentation says that we should show Yes and No buttons,
2034 * when it is a question.
2035 * Obviously, we need tinymail to use more specific error codes instead,
2036 * so we know what buttons to show. */
2037 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win),
2039 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2040 GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2042 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2043 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2045 on_destroy_dialog (dialog);
2047 /* Just show the error text and use the default response: */
2048 modest_platform_run_information_dialog (GTK_WINDOW (top_win),
2056 GtkWindow *parent_window;
2057 ModestConnectedPerformer callback;
2058 TnyAccount *account;
2065 on_went_online_info_free (OnWentOnlineInfo *info)
2067 /* And if we cleanup, we DO cleanup :-) */
2070 g_object_unref (info->device);
2073 if (info->parent_window)
2074 g_object_unref (info->parent_window);
2076 g_object_unref (info->account);
2078 g_slice_free (OnWentOnlineInfo, info);
2080 /* We're done ... */
2086 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2088 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2090 /* Now it's really time to callback to the caller. If going online didn't succeed,
2091 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2092 * canceled will be set. Etcetera etcetera. */
2094 if (info->callback) {
2095 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2098 /* This is our last call, we must cleanup here if we didn't yet do that */
2099 on_went_online_info_free (info);
2106 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2108 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2109 info->iap = g_strdup (iap_id);
2111 if (canceled || err || !info->account) {
2113 /* If there's a problem or if there's no account (then that's it for us, we callback
2114 * the caller's callback now. He'll have to handle err or canceled, of course.
2115 * We are not really online, as the account is not really online here ... */
2117 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2118 * this info. We don't cleanup err, Tinymail does that! */
2120 if (info->callback) {
2122 /* info->account can be NULL here, this means that the user did not
2123 * provide a nice account instance. We'll assume that the user knows
2124 * what he's doing and is happy with just the device going online.
2126 * We can't do magic, we don't know what account the user wants to
2127 * see going online. So just the device goes online, end of story */
2129 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2132 } else if (info->account) {
2134 /* If there's no problem and if we have an account, we'll put the account
2135 * online too. When done, the callback of bringing the account online
2136 * will callback the caller's callback. This is the most normal case. */
2138 info->device = TNY_DEVICE (g_object_ref (device));
2140 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2141 on_account_went_online, info);
2143 /* The on_account_went_online cb frees up the info, go look if you
2144 * don't believe me! (so we return here) */
2149 /* We cleanup if we are not bringing the account online too */
2150 on_went_online_info_free (info);
2156 modest_platform_connect_and_perform (GtkWindow *parent_window,
2158 TnyAccount *account,
2159 ModestConnectedPerformer callback,
2162 gboolean device_online;
2164 TnyConnectionStatus conn_status;
2165 OnWentOnlineInfo *info;
2167 device = modest_runtime_get_device();
2168 device_online = tny_device_is_online (device);
2170 /* If there is no account check only the device status */
2173 if (device_online) {
2175 /* We promise to instantly perform the callback, so ... */
2177 callback (FALSE, NULL, parent_window, account, user_data);
2182 info = g_slice_new0 (OnWentOnlineInfo);
2185 info->device = NULL;
2186 info->account = NULL;
2189 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2191 info->parent_window = NULL;
2192 info->user_data = user_data;
2193 info->callback = callback;
2195 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2196 force, on_conic_device_went_online,
2199 /* We'll cleanup in on_conic_device_went_online */
2202 /* The other code has no more reason to run. This is all that we can do for the
2203 * caller (he should have given us a nice and clean account instance!). We
2204 * can't do magic, we don't know what account he intends to bring online. So
2205 * we'll just bring the device online (and await his false bug report). */
2211 /* Return if the account is already connected */
2213 conn_status = tny_account_get_connection_status (account);
2214 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2216 /* We promise to instantly perform the callback, so ... */
2218 callback (FALSE, NULL, parent_window, account, user_data);
2224 /* Else, we are in a state that requires that we go online before we
2225 * call the caller's callback. */
2227 info = g_slice_new0 (OnWentOnlineInfo);
2229 info->device = NULL;
2231 info->account = TNY_ACCOUNT (g_object_ref (account));
2234 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2236 info->parent_window = NULL;
2238 /* So we'll put the callback away for later ... */
2240 info->user_data = user_data;
2241 info->callback = callback;
2243 if (!device_online) {
2245 /* If also the device is offline, then we connect both the device
2246 * and the account */
2248 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2249 force, on_conic_device_went_online,
2254 /* If the device is online, we'll just connect the account */
2256 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2257 on_account_went_online, info);
2260 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2261 * in both situations, go look if you don't believe me! */
2267 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2269 TnyFolderStore *folder_store,
2270 ModestConnectedPerformer callback,
2273 TnyAccount *account = NULL;
2275 if (!folder_store ||
2276 (TNY_IS_MERGE_FOLDER (folder_store) &&
2277 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2279 /* We promise to instantly perform the callback, so ... */
2281 GError *error = NULL;
2282 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2283 "Unable to move or not found folder");
2284 callback (FALSE, error, parent_window, NULL, user_data);
2285 g_error_free (error);
2289 } else if (TNY_IS_FOLDER (folder_store)) {
2290 /* Get the folder's parent account: */
2291 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2292 } else if (TNY_IS_ACCOUNT (folder_store)) {
2293 /* Use the folder store as an account: */
2294 account = TNY_ACCOUNT (g_object_ref (folder_store));
2297 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2298 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2299 /* No need to connect a local account */
2301 callback (FALSE, NULL, parent_window, account, user_data);
2306 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2310 g_object_unref (account);
2314 src_account_connect_performer (gboolean canceled,
2316 GtkWindow *parent_window,
2317 TnyAccount *src_account,
2320 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2322 if (canceled || err) {
2323 /* If there was any error call the user callback */
2324 info->callback (canceled, err, parent_window, src_account, info->data);
2326 /* Connect the destination account */
2327 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2328 TNY_FOLDER_STORE (info->dst_account),
2329 info->callback, info->data);
2332 /* Free the info object */
2333 g_object_unref (info->dst_account);
2334 g_slice_free (DoubleConnectionInfo, info);
2339 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2341 TnyFolderStore *folder_store,
2342 DoubleConnectionInfo *connect_info)
2344 modest_platform_connect_if_remote_and_perform(parent_window,
2347 src_account_connect_performer,
2352 modest_platform_get_account_settings_wizard (void)
2354 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2356 return GTK_WIDGET (dialog);
2360 modest_platform_get_current_connection (void)
2362 TnyDevice *device = NULL;
2363 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2365 device = modest_runtime_get_device ();
2367 if (!tny_device_is_online (device))
2368 return MODEST_CONNECTED_VIA_ANY;
2370 #ifdef MODEST_HAVE_CONIC
2372 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2374 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2375 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2376 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2378 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2379 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2380 !strcmp (bearer_type, "WIMAX")) {
2381 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2383 retval = MODEST_CONNECTED_VIA_ANY;
2386 g_object_unref (iap);
2389 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2390 #endif /* MODEST_HAVE_CONIC */
2397 modest_platform_check_memory_low (ModestWindow *win,
2402 /* are we in low memory state? */
2403 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2405 if (win && lowmem && visuals)
2406 modest_platform_run_information_dialog (
2408 _KR("memr_ib_operation_disabled"),
2412 g_debug ("%s: low memory reached. disallowing some operations",
2419 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2425 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2428 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2429 GTK_WINDOW (dialog),
2431 gtk_widget_show_all (dialog);
2433 g_signal_connect_swapped (dialog, "response",
2434 G_CALLBACK (gtk_widget_destroy),
2438 typedef struct _HeaderDetailsGetSizeInfo {
2442 } HeaderDetailsGetSizeInfo;
2445 header_details_dialog_destroy (gpointer userdata,
2448 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2450 info->dialog = NULL;
2454 idle_get_mime_part_size_cb (gpointer userdata)
2456 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2457 gdk_threads_enter ();
2459 if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
2460 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
2465 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
2466 info->dialog = NULL;
2468 g_object_unref (info->part);
2469 g_slice_free (HeaderDetailsGetSizeInfo, info);
2471 gdk_threads_leave ();
2477 get_mime_part_size_thread (gpointer thr_user_data)
2479 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
2481 TnyStream *count_stream;
2483 count_stream = modest_count_stream_new ();
2484 result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
2485 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2486 if (info->total == 0) {
2487 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
2488 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
2489 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2492 /* if there was an error, don't set the size (this is pretty uncommon) */
2494 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
2496 g_idle_add (idle_get_mime_part_size_cb, info);
2502 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2504 gboolean async_get_size,
2510 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header, !async_get_size);
2512 if (async_get_size && msg && TNY_IS_MSG (msg)) {
2513 HeaderDetailsGetSizeInfo *info;
2514 info = g_slice_new (HeaderDetailsGetSizeInfo);
2515 info->dialog = dialog;
2517 info->part = TNY_MIME_PART (g_object_ref (msg));
2519 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
2520 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2524 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2525 GTK_WINDOW (dialog),
2527 gtk_widget_show_all (dialog);
2529 g_signal_connect_swapped (dialog, "response",
2530 G_CALLBACK (gtk_widget_destroy),
2535 modest_platform_get_osso_context (void)
2537 return modest_maemo_utils_get_osso_context ();
2541 _modest_platform_play_email_tone (void)
2544 gint mail_volume_int;
2546 ca_context *ca_con = NULL;
2547 ca_proplist *pl = NULL;
2549 #ifdef MODEST_USE_PROFILE
2550 gchar *active_profile;
2553 active_profile = profile_get_profile ();
2554 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2555 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2556 mail_volume_int = profile_parse_int (mail_volume);
2557 g_free (mail_volume);
2558 g_free (active_profile);
2560 mail_tone = MAIL_TONE;
2561 mail_volume_int = 100;
2564 if (mail_tone && !strstr (mail_tone, "/")) {
2567 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2572 if (mail_volume_int > 0) {
2574 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2575 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2579 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2580 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2581 ca_context_destroy(ca_con);
2585 ca_proplist_create(&pl);
2586 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2587 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2589 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2590 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2592 ca_proplist_destroy(pl);
2593 ca_context_destroy(ca_con);
2599 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2600 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2601 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2602 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2603 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2604 #define MOVE_TO_FOLDER_SEPARATOR "/"
2607 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
2608 TnyFolderStore *folder_store)
2610 GtkWidget *action_button;
2611 GtkWidget *image = NULL;
2612 TnyAccount *account;
2613 gchar *account_name = NULL;
2615 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2617 /* Get account name */
2618 if (TNY_IS_FOLDER (folder_store))
2619 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2621 account = g_object_ref (folder_store);
2623 if (modest_tny_account_is_virtual_local_folders (account))
2624 account_name = modest_conf_get_string (modest_runtime_get_conf(),
2625 MODEST_CONF_DEVICE_NAME, NULL);
2628 account_name = g_strdup (tny_account_get_name (account));
2630 g_object_unref (account);
2632 /* Set title of button: account or folder name */
2633 if (TNY_IS_FOLDER (folder_store)) {
2634 hildon_button_set_title (HILDON_BUTTON (action_button),
2635 tny_folder_get_name (TNY_FOLDER (folder_store)));
2637 hildon_button_set_title (HILDON_BUTTON (action_button), account_name);
2640 /* Set value of button, folder full name */
2641 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
2642 gchar *full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
2643 tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store)),
2645 hildon_button_set_value (HILDON_BUTTON (action_button), full_name);
2648 g_free (account_name);
2650 /* Set image for the button */
2651 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
2653 hildon_button_set_image (HILDON_BUTTON (action_button), image);
2657 move_to_dialog_show_accounts (GtkWidget *dialog)
2659 GtkWidget *back_button;
2660 GtkWidget *folder_view;
2661 GtkWidget *pannable;
2662 GtkWidget *action_button;
2664 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2665 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2666 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2667 pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2669 gtk_widget_set_sensitive (back_button, FALSE);
2670 gtk_widget_set_sensitive (action_button, FALSE);
2672 /* Need to set this here, otherwise callbacks called because
2673 of filtering won't perform correctly */
2674 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2676 /* Reset action button */
2677 hildon_button_set_title (HILDON_BUTTON (action_button), NULL);
2678 hildon_button_set_value (HILDON_BUTTON (action_button), NULL);
2679 hildon_button_set_image (HILDON_BUTTON (action_button), NULL);
2681 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
2682 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2683 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2684 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2685 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2686 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2687 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2688 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2689 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2690 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2691 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2692 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2696 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2698 GtkWidget *back_button;
2699 GtkWidget *folder_view;
2700 TnyAccount *account;
2701 const gchar *account_id;
2702 GtkWidget *pannable;
2703 GtkWidget *action_button;
2706 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2708 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2710 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2712 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2714 gtk_widget_set_sensitive (back_button, TRUE);
2715 gtk_widget_set_sensitive (action_button, TRUE);
2717 /* Need to set this here, otherwise callbacks called because
2718 of filtering won't perform correctly */
2719 g_object_set_data (G_OBJECT (dialog),
2720 MOVE_TO_DIALOG_SHOWING_FOLDERS,
2721 GINT_TO_POINTER (TRUE));
2723 account = TNY_ACCOUNT (folder_store);
2724 if (modest_tny_account_is_virtual_local_folders (account)) {
2725 account_id = tny_account_get_id (account);
2726 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2727 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2728 } else if (modest_tny_account_is_memory_card_account (account)) {
2729 account_id = tny_account_get_id (account);
2730 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2731 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2733 account_id = tny_account_get_id (account);
2734 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2735 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2736 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2737 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2740 move_to_dialog_set_selected_folder_store (dialog, folder_store);
2741 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2744 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2745 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2746 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2747 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2748 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2752 on_move_to_dialog_back_clicked (GtkButton *button,
2755 GtkWidget *dialog = (GtkWidget *) userdata;
2757 /* Back to show accounts */
2758 move_to_dialog_show_accounts (dialog);
2762 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
2764 GtkTreeViewColumn *column,
2767 TnyFolderStore *selected = NULL;
2769 GtkWidget *folder_view;
2770 gboolean showing_folders;
2772 dialog = (GtkWidget *) user_data;
2773 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
2774 MOVE_TO_DIALOG_SHOWING_FOLDERS));
2776 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
2777 MOVE_TO_DIALOG_FOLDER_VIEW));
2779 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2783 if (!showing_folders) {
2784 gboolean valid = TRUE;
2786 if (TNY_IS_ACCOUNT (selected) &&
2787 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2788 ModestProtocolType protocol_type;
2790 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2791 valid = !modest_protocol_registry_protocol_type_has_tag
2792 (modest_runtime_get_protocol_registry (),
2794 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_MESSAGE_ADD);
2797 move_to_dialog_show_folders (dialog, selected);
2799 move_to_dialog_set_selected_folder_store (dialog, selected);
2804 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2807 gboolean showing_folders;
2810 dialog = (GtkWidget *) user_data;
2811 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2812 if (showing_folders) {
2813 TnyFolderStore *selected;
2814 GtkWidget *folder_view;
2816 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2817 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2820 move_to_dialog_set_selected_folder_store (dialog, selected);
2821 g_object_unref (selected);
2827 on_move_to_dialog_action_clicked (GtkButton *selection,
2830 TnyFolderStore *selected;
2832 GtkWidget *folder_view;
2833 gboolean showing_folders;
2835 dialog = (GtkWidget *) user_data;
2836 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2837 if (showing_folders) {
2838 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2839 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2842 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2847 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2848 GtkWidget **folder_view)
2850 GtkWidget *dialog, *folder_view_container;
2852 GtkWidget *buttons_hbox;
2853 GtkWidget *back_button;
2854 GdkPixbuf *back_pixbuf;
2855 GtkWidget *top_vbox;
2856 GtkWidget *action_button;
2857 GtkTreeSelection *selection;
2859 /* Create dialog. We cannot use a touch selector because we
2860 need to use here the folder view widget directly */
2861 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2862 GTK_WINDOW (parent_window),
2863 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2864 GTK_DIALOG_DESTROY_WITH_PARENT,
2865 _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2868 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2869 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2870 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2872 /* Create folder view */
2873 *folder_view = modest_platform_create_folder_view (NULL);
2875 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2876 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2877 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2879 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2880 (TnyAccountStore *) modest_runtime_get_account_store ());
2882 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2883 back_button = gtk_button_new ();
2884 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2886 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2887 g_object_unref (back_pixbuf);
2890 action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
2891 HILDON_BUTTON_ARRANGEMENT_VERTICAL);
2892 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2894 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2895 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2896 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2897 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2898 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2900 /* Create pannable and add it to the dialog */
2901 folder_view_container = hildon_pannable_area_new ();
2902 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2903 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2905 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2906 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2908 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2910 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2911 gtk_widget_show (folder_view_container);
2912 gtk_widget_show (align);
2913 gtk_widget_show (top_vbox);
2914 gtk_widget_show (*folder_view);
2915 gtk_widget_show_all (back_button);
2916 gtk_widget_show (action_button);
2917 gtk_widget_show (buttons_hbox);
2918 gtk_widget_show (dialog);
2920 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2921 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2922 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2923 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2925 /* Simulate the behaviour of a HildonPickerDialog by emitting
2926 a response when a folder is selected */
2927 g_signal_connect (*folder_view, "row-activated",
2928 G_CALLBACK (on_move_to_dialog_row_activated),
2931 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2932 g_signal_connect (selection, "changed",
2933 G_CALLBACK (on_move_to_dialog_selection_changed),
2936 g_signal_connect (action_button, "clicked",
2937 G_CALLBACK (on_move_to_dialog_action_clicked),
2940 g_signal_connect (back_button, "clicked",
2941 G_CALLBACK (on_move_to_dialog_back_clicked),
2944 move_to_dialog_show_accounts (dialog);
2950 modest_platform_get_list_to_move (ModestWindow *window)
2952 TnyList *list = NULL;
2954 if (MODEST_IS_HEADER_WINDOW (window)) {
2955 ModestHeaderView *header_view;
2957 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2958 list = modest_header_view_get_selected_headers (header_view);
2959 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2960 ModestFolderView *folder_view;
2961 TnyFolderStore *selected_folder;
2963 list = TNY_LIST (tny_simple_list_new ());
2964 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2965 selected_folder = modest_folder_view_get_selected (folder_view);
2966 if (selected_folder) {
2967 tny_list_prepend (list, G_OBJECT (selected_folder));
2968 g_object_unref (selected_folder);
2971 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2974 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2976 list = TNY_LIST (tny_simple_list_new ());
2977 tny_list_prepend (list, G_OBJECT (header));
2978 g_object_unref (header);
2981 g_return_val_if_reached (NULL);