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) < 1)
1540 /* If the window is in the foreground don't do anything */
1541 if (hildon_program_get_is_topmost (hildon_program_get_instance ()))
1544 #ifdef MODEST_HAVE_HILDON_NOTIFY
1545 /* For any other case issue a notification */
1546 HildonNotification *notification;
1548 GSList *notifications_list = NULL;
1550 /* Get previous notifications ids */
1551 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1552 MODEST_CONF_NOTIFICATION_IDS,
1553 MODEST_CONF_VALUE_INT, NULL);
1555 iter = tny_list_create_iterator (header_list);
1556 while (!tny_iterator_is_done (iter)) {
1557 gchar *url = NULL, *display_address = NULL;
1558 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1559 TnyFolder *folder = tny_header_get_folder (header);
1560 gboolean first_notification = TRUE;
1564 display_address = tny_header_dup_from (header);
1565 /* string is changed in-place */
1566 modest_text_utils_get_display_address (display_address);
1568 str = tny_header_dup_subject (header);
1569 notification = hildon_notification_new (display_address,
1571 "qgn_list_messagin",
1572 MODEST_NOTIFICATION_CATEGORY);
1574 /* Create the message URL */
1575 str = tny_header_dup_uid (header);
1576 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1580 hildon_notification_add_dbus_action(notification,
1583 MODEST_DBUS_SERVICE,
1586 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1590 /* Play sound if the user wants. Show the LED
1591 pattern. Show and play just one */
1592 if (G_UNLIKELY (first_notification)) {
1593 TnyAccount *account;
1595 first_notification = FALSE;
1597 /* Set the led pattern */
1598 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1600 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1602 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1604 /* Set the account of the headers */
1605 account = tny_folder_get_account (folder);
1607 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1609 tny_account_get_id (account));
1610 g_object_unref (account);
1614 /* Notify. We need to do this in an idle because this function
1615 could be called from a thread */
1616 if (!notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1617 g_warning ("Failed to send notification");
1620 /* Save id in the list */
1621 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1622 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1623 /* We don't listen for the "closed" signal, because we
1624 don't care about if the notification was removed or
1625 not to store the list in gconf */
1627 /* Free & carry on */
1628 g_free (display_address);
1630 g_object_unref (folder);
1631 g_object_unref (header);
1632 tny_iterator_next (iter);
1634 g_object_unref (iter);
1637 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1638 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1640 g_slist_free (notifications_list);
1642 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1646 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1649 #ifdef MODEST_HAVE_MCE
1650 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1654 MCE_DEACTIVATE_LED_PATTERN,
1656 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1662 #ifdef MODEST_HAVE_HILDON_NOTIFY
1663 GSList *notif_list = NULL;
1665 /* Get previous notifications ids */
1666 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1667 MODEST_CONF_NOTIFICATION_IDS,
1668 MODEST_CONF_VALUE_INT, NULL);
1670 while (notif_list) {
1672 NotifyNotification *notif;
1674 /* Nasty HACK to remove the notifications, set the id
1675 of the existing ones and then close them */
1676 notif_id = GPOINTER_TO_INT(notif_list->data);
1677 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1678 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1680 /* Close the notification, note that some ids could be
1681 already invalid, but we don't care because it does
1683 notify_notification_close(notif, NULL);
1684 g_object_unref(notif);
1686 /* Delete the link, it's like going to the next */
1687 notif_list = g_slist_delete_link (notif_list, notif_list);
1691 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1692 notif_list, MODEST_CONF_VALUE_INT, NULL);
1694 g_slist_free (notif_list);
1696 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1702 modest_platform_get_global_settings_dialog ()
1704 return modest_hildon2_global_settings_dialog_new ();
1708 modest_platform_show_help (GtkWindow *parent_window,
1709 const gchar *help_id)
1715 modest_platform_show_search_messages (GtkWindow *parent_window)
1717 osso_return_t result = OSSO_ERROR;
1719 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1720 "osso_global_search",
1721 "search_email", NULL, DBUS_TYPE_INVALID);
1723 if (result != OSSO_OK) {
1724 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1729 modest_platform_show_addressbook (GtkWindow *parent_window)
1731 osso_return_t result = OSSO_ERROR;
1733 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1735 "top_application", NULL, DBUS_TYPE_INVALID);
1737 if (result != OSSO_OK) {
1738 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1743 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1745 GtkWidget *widget = modest_folder_view_new (query);
1747 /* Show one account by default */
1748 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1749 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1751 /* Restore settings */
1752 modest_widget_memory_restore (modest_runtime_get_conf(),
1754 MODEST_CONF_FOLDER_VIEW_KEY);
1760 banner_finish (gpointer data, GObject *object)
1762 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1763 modest_window_mgr_unregister_banner (mgr);
1764 g_object_unref (mgr);
1768 modest_platform_information_banner (GtkWidget *parent,
1769 const gchar *icon_name,
1772 GtkWidget *banner, *banner_parent = NULL;
1773 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1775 if (modest_window_mgr_get_num_windows (mgr) == 0)
1778 if (parent && GTK_IS_WINDOW (parent)) {
1779 /* If the window is the active one then show the
1780 banner on top of this window */
1781 if (gtk_window_is_active (GTK_WINDOW (parent)))
1782 banner_parent = parent;
1783 /* If the window is not the topmost but it's visible
1784 (it's minimized for example) then show the banner
1786 else if (GTK_WIDGET_VISIBLE (parent))
1787 banner_parent = NULL;
1788 /* If the window is hidden (like the main window when
1789 running in the background) then do not show
1796 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1798 modest_window_mgr_register_banner (mgr);
1800 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1804 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1805 const gchar *icon_name,
1811 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1814 banner = hildon_banner_show_information (parent, icon_name, text);
1815 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1819 modest_platform_animation_banner (GtkWidget *parent,
1820 const gchar *animation_name,
1823 GtkWidget *inf_note = NULL;
1825 g_return_val_if_fail (text != NULL, NULL);
1827 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1830 /* If the parent is not visible then do not show */
1831 if (parent && !GTK_WIDGET_VISIBLE (parent))
1834 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1842 TnyAccount *account;
1845 } CheckAccountIdleData;
1847 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1850 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1852 gboolean stop_trying = FALSE;
1853 g_return_val_if_fail (data && data->account, FALSE);
1855 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1856 tny_account_get_connection_status (data->account));
1858 if (data && data->account &&
1859 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1860 * after which the account is likely to be usable, or never likely to be usable soon: */
1861 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1863 data->is_online = TRUE;
1867 /* Give up if we have tried too many times: */
1868 if (data->count_tries >= NUMBER_OF_TRIES) {
1871 /* Wait for another timeout: */
1872 ++(data->count_tries);
1877 /* Allow the function that requested this idle callback to continue: */
1879 g_main_loop_quit (data->loop);
1882 g_object_unref (data->account);
1884 return FALSE; /* Don't call this again. */
1886 return TRUE; /* Call this timeout callback again. */
1890 /* Return TRUE immediately if the account is already online,
1891 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1892 * soon as the account is online, or FALSE if the account does
1893 * not become online in the NUMBER_OF_TRIES seconds.
1894 * This is useful when the D-Bus method was run immediately after
1895 * the application was started (when using D-Bus activation),
1896 * because the account usually takes a short time to go online.
1897 * The return value is maybe not very useful.
1900 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1904 g_return_val_if_fail (account, FALSE);
1906 if (!tny_device_is_online (modest_runtime_get_device())) {
1907 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1911 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1912 * so we avoid wait unnecessarily: */
1913 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1916 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1917 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1918 * we want to avoid. */
1919 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1922 /* This blocks on the result: */
1923 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1924 data->is_online = FALSE;
1925 data->account = account;
1926 g_object_ref (data->account);
1927 data->count_tries = 0;
1929 GMainContext *context = NULL; /* g_main_context_new (); */
1930 data->loop = g_main_loop_new (context, FALSE /* not running */);
1932 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1934 /* This main loop will run until the idle handler has stopped it: */
1935 g_main_loop_run (data->loop);
1937 g_main_loop_unref (data->loop);
1938 /* g_main_context_unref (context); */
1940 is_online = data->is_online;
1941 g_slice_free (CheckAccountIdleData, data);
1949 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1951 /* GTK_RESPONSE_HELP means we need to show the certificate */
1952 if (response_id == GTK_RESPONSE_APPLY) {
1956 /* Do not close the dialog */
1957 g_signal_stop_emission_by_name (dialog, "response");
1959 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1960 note = hildon_note_new_information (NULL, msg);
1961 gtk_dialog_run (GTK_DIALOG(note));
1962 gtk_widget_destroy (note);
1968 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1969 const gchar *certificate)
1974 HildonWindowStack *stack;
1976 stack = hildon_window_stack_get_default ();
1977 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1980 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1985 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1988 /* We use GTK_RESPONSE_APPLY because we want the button in the
1989 middle of OK and CANCEL the same as the browser does for
1990 example. With GTK_RESPONSE_HELP the view button is aligned
1991 to the left while the other two to the right */
1992 note = hildon_note_new_confirmation_add_buttons (
1995 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1996 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1997 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
2000 g_signal_connect (G_OBJECT(note), "response",
2001 G_CALLBACK(on_cert_dialog_response),
2002 (gpointer) certificate);
2004 response = gtk_dialog_run(GTK_DIALOG(note));
2006 on_destroy_dialog (note);
2009 return response == GTK_RESPONSE_OK;
2013 modest_platform_run_alert_dialog (const gchar* prompt,
2014 gboolean is_question)
2016 ModestWindow *top_win;
2017 HildonWindowStack *stack;
2019 stack = hildon_window_stack_get_default ();
2020 top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2023 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2028 gboolean retval = TRUE;
2030 /* The Tinymail documentation says that we should show Yes and No buttons,
2031 * when it is a question.
2032 * Obviously, we need tinymail to use more specific error codes instead,
2033 * so we know what buttons to show. */
2034 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win),
2036 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2037 GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2039 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2040 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2042 on_destroy_dialog (dialog);
2044 /* Just show the error text and use the default response: */
2045 modest_platform_run_information_dialog (GTK_WINDOW (top_win),
2053 GtkWindow *parent_window;
2054 ModestConnectedPerformer callback;
2055 TnyAccount *account;
2062 on_went_online_info_free (OnWentOnlineInfo *info)
2064 /* And if we cleanup, we DO cleanup :-) */
2067 g_object_unref (info->device);
2070 if (info->parent_window)
2071 g_object_unref (info->parent_window);
2073 g_object_unref (info->account);
2075 g_slice_free (OnWentOnlineInfo, info);
2077 /* We're done ... */
2083 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2085 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2087 /* Now it's really time to callback to the caller. If going online didn't succeed,
2088 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2089 * canceled will be set. Etcetera etcetera. */
2091 if (info->callback) {
2092 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2095 /* This is our last call, we must cleanup here if we didn't yet do that */
2096 on_went_online_info_free (info);
2103 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2105 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2106 info->iap = g_strdup (iap_id);
2108 if (canceled || err || !info->account) {
2110 /* If there's a problem or if there's no account (then that's it for us, we callback
2111 * the caller's callback now. He'll have to handle err or canceled, of course.
2112 * We are not really online, as the account is not really online here ... */
2114 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2115 * this info. We don't cleanup err, Tinymail does that! */
2117 if (info->callback) {
2119 /* info->account can be NULL here, this means that the user did not
2120 * provide a nice account instance. We'll assume that the user knows
2121 * what he's doing and is happy with just the device going online.
2123 * We can't do magic, we don't know what account the user wants to
2124 * see going online. So just the device goes online, end of story */
2126 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2129 } else if (info->account) {
2131 /* If there's no problem and if we have an account, we'll put the account
2132 * online too. When done, the callback of bringing the account online
2133 * will callback the caller's callback. This is the most normal case. */
2135 info->device = TNY_DEVICE (g_object_ref (device));
2137 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2138 on_account_went_online, info);
2140 /* The on_account_went_online cb frees up the info, go look if you
2141 * don't believe me! (so we return here) */
2146 /* We cleanup if we are not bringing the account online too */
2147 on_went_online_info_free (info);
2153 modest_platform_connect_and_perform (GtkWindow *parent_window,
2155 TnyAccount *account,
2156 ModestConnectedPerformer callback,
2159 gboolean device_online;
2161 TnyConnectionStatus conn_status;
2162 OnWentOnlineInfo *info;
2164 device = modest_runtime_get_device();
2165 device_online = tny_device_is_online (device);
2167 /* If there is no account check only the device status */
2170 if (device_online) {
2172 /* We promise to instantly perform the callback, so ... */
2174 callback (FALSE, NULL, parent_window, account, user_data);
2179 info = g_slice_new0 (OnWentOnlineInfo);
2182 info->device = NULL;
2183 info->account = NULL;
2186 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2188 info->parent_window = NULL;
2189 info->user_data = user_data;
2190 info->callback = callback;
2192 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2193 force, on_conic_device_went_online,
2196 /* We'll cleanup in on_conic_device_went_online */
2199 /* The other code has no more reason to run. This is all that we can do for the
2200 * caller (he should have given us a nice and clean account instance!). We
2201 * can't do magic, we don't know what account he intends to bring online. So
2202 * we'll just bring the device online (and await his false bug report). */
2208 /* Return if the account is already connected */
2210 conn_status = tny_account_get_connection_status (account);
2211 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2213 /* We promise to instantly perform the callback, so ... */
2215 callback (FALSE, NULL, parent_window, account, user_data);
2221 /* Else, we are in a state that requires that we go online before we
2222 * call the caller's callback. */
2224 info = g_slice_new0 (OnWentOnlineInfo);
2226 info->device = NULL;
2228 info->account = TNY_ACCOUNT (g_object_ref (account));
2231 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2233 info->parent_window = NULL;
2235 /* So we'll put the callback away for later ... */
2237 info->user_data = user_data;
2238 info->callback = callback;
2240 if (!device_online) {
2242 /* If also the device is offline, then we connect both the device
2243 * and the account */
2245 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2246 force, on_conic_device_went_online,
2251 /* If the device is online, we'll just connect the account */
2253 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2254 on_account_went_online, info);
2257 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2258 * in both situations, go look if you don't believe me! */
2264 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2266 TnyFolderStore *folder_store,
2267 ModestConnectedPerformer callback,
2270 TnyAccount *account = NULL;
2272 if (!folder_store ||
2273 (TNY_IS_MERGE_FOLDER (folder_store) &&
2274 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2276 /* We promise to instantly perform the callback, so ... */
2278 GError *error = NULL;
2279 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2280 "Unable to move or not found folder");
2281 callback (FALSE, error, parent_window, NULL, user_data);
2282 g_error_free (error);
2286 } else if (TNY_IS_FOLDER (folder_store)) {
2287 /* Get the folder's parent account: */
2288 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2289 } else if (TNY_IS_ACCOUNT (folder_store)) {
2290 /* Use the folder store as an account: */
2291 account = TNY_ACCOUNT (g_object_ref (folder_store));
2294 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2295 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2296 /* No need to connect a local account */
2298 callback (FALSE, NULL, parent_window, account, user_data);
2303 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2307 g_object_unref (account);
2311 src_account_connect_performer (gboolean canceled,
2313 GtkWindow *parent_window,
2314 TnyAccount *src_account,
2317 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2319 if (canceled || err) {
2320 /* If there was any error call the user callback */
2321 info->callback (canceled, err, parent_window, src_account, info->data);
2323 /* Connect the destination account */
2324 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2325 TNY_FOLDER_STORE (info->dst_account),
2326 info->callback, info->data);
2329 /* Free the info object */
2330 g_object_unref (info->dst_account);
2331 g_slice_free (DoubleConnectionInfo, info);
2336 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2338 TnyFolderStore *folder_store,
2339 DoubleConnectionInfo *connect_info)
2341 modest_platform_connect_if_remote_and_perform(parent_window,
2344 src_account_connect_performer,
2349 modest_platform_get_account_settings_wizard (void)
2351 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2353 return GTK_WIDGET (dialog);
2357 modest_platform_get_current_connection (void)
2359 TnyDevice *device = NULL;
2360 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2362 device = modest_runtime_get_device ();
2364 if (!tny_device_is_online (device))
2365 return MODEST_CONNECTED_VIA_ANY;
2367 #ifdef MODEST_HAVE_CONIC
2369 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2371 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2372 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2373 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2375 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2376 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2377 !strcmp (bearer_type, "WIMAX")) {
2378 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2380 retval = MODEST_CONNECTED_VIA_ANY;
2383 g_object_unref (iap);
2386 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2387 #endif /* MODEST_HAVE_CONIC */
2394 modest_platform_check_memory_low (ModestWindow *win,
2399 /* are we in low memory state? */
2400 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2402 if (win && lowmem && visuals)
2403 modest_platform_run_information_dialog (
2405 _KR("memr_ib_operation_disabled"),
2409 g_debug ("%s: low memory reached. disallowing some operations",
2416 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2422 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2425 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2426 GTK_WINDOW (dialog),
2428 gtk_widget_show_all (dialog);
2430 g_signal_connect_swapped (dialog, "response",
2431 G_CALLBACK (gtk_widget_destroy),
2435 typedef struct _HeaderDetailsGetSizeInfo {
2439 } HeaderDetailsGetSizeInfo;
2442 header_details_dialog_destroy (gpointer userdata,
2445 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2447 info->dialog = NULL;
2451 idle_get_mime_part_size_cb (gpointer userdata)
2453 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2454 gdk_threads_enter ();
2456 if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
2457 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
2462 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
2463 info->dialog = NULL;
2465 g_object_unref (info->part);
2466 g_slice_free (HeaderDetailsGetSizeInfo, info);
2468 gdk_threads_leave ();
2474 get_mime_part_size_thread (gpointer thr_user_data)
2476 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
2478 TnyStream *count_stream;
2480 count_stream = modest_count_stream_new ();
2481 result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
2482 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2483 if (info->total == 0) {
2484 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
2485 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
2486 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2489 /* if there was an error, don't set the size (this is pretty uncommon) */
2491 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
2493 g_idle_add (idle_get_mime_part_size_cb, info);
2499 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2501 gboolean async_get_size,
2507 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header, !async_get_size);
2509 if (async_get_size && msg && TNY_IS_MSG (msg)) {
2510 HeaderDetailsGetSizeInfo *info;
2511 info = g_slice_new (HeaderDetailsGetSizeInfo);
2512 info->dialog = dialog;
2514 info->part = TNY_MIME_PART (g_object_ref (msg));
2516 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
2517 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2521 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2522 GTK_WINDOW (dialog),
2524 gtk_widget_show_all (dialog);
2526 g_signal_connect_swapped (dialog, "response",
2527 G_CALLBACK (gtk_widget_destroy),
2532 modest_platform_get_osso_context (void)
2534 return modest_maemo_utils_get_osso_context ();
2538 _modest_platform_play_email_tone (void)
2541 gint mail_volume_int;
2543 ca_context *ca_con = NULL;
2544 ca_proplist *pl = NULL;
2546 #ifdef MODEST_USE_PROFILE
2547 gchar *active_profile;
2550 active_profile = profile_get_profile ();
2551 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2552 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2553 mail_volume_int = profile_parse_int (mail_volume);
2554 g_free (mail_volume);
2555 g_free (active_profile);
2557 mail_tone = MAIL_TONE;
2558 mail_volume_int = 100;
2561 if (mail_tone && !strstr (mail_tone, "/")) {
2564 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2569 if (mail_volume_int > 0) {
2571 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2572 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2576 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2577 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2578 ca_context_destroy(ca_con);
2582 ca_proplist_create(&pl);
2583 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2584 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2586 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2587 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2589 ca_proplist_destroy(pl);
2590 ca_context_destroy(ca_con);
2596 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2597 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2598 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2599 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2600 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2601 #define MOVE_TO_FOLDER_SEPARATOR "/"
2604 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
2605 TnyFolderStore *folder_store)
2607 GtkWidget *action_button;
2608 GtkWidget *image = NULL;
2609 TnyAccount *account;
2610 gchar *account_name = NULL, *short_name = NULL;
2612 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2614 /* Get account name */
2615 if (TNY_IS_FOLDER (folder_store))
2616 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2618 account = g_object_ref (folder_store);
2620 if (modest_tny_account_is_virtual_local_folders (account))
2621 account_name = modest_conf_get_string (modest_runtime_get_conf(),
2622 MODEST_CONF_DEVICE_NAME, NULL);
2625 account_name = g_strdup (tny_account_get_name (account));
2627 g_object_unref (account);
2629 /* Set title of button: account or folder name */
2630 if (TNY_IS_FOLDER (folder_store))
2631 short_name = folder_store_get_display_name (folder_store);
2633 short_name = g_strdup (account_name);
2635 hildon_button_set_title (HILDON_BUTTON (action_button), short_name);
2637 /* Set value of button, folder full name */
2638 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
2639 const gchar *camel_full_name;
2640 gchar *last_slash, *full_name;
2642 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
2643 last_slash = g_strrstr (camel_full_name, "/");
2645 gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
2646 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
2649 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
2653 hildon_button_set_value (HILDON_BUTTON (action_button), full_name);
2656 g_free (account_name);
2657 g_free (short_name);
2659 /* Set image for the button */
2660 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
2662 hildon_button_set_image (HILDON_BUTTON (action_button), image);
2666 move_to_dialog_show_accounts (GtkWidget *dialog)
2668 GtkWidget *back_button;
2669 GtkWidget *folder_view;
2670 GtkWidget *pannable;
2671 GtkWidget *action_button;
2673 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2674 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2675 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2676 pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2678 gtk_widget_set_sensitive (back_button, FALSE);
2679 gtk_widget_set_sensitive (action_button, FALSE);
2681 /* Need to set this here, otherwise callbacks called because
2682 of filtering won't perform correctly */
2683 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2685 /* Reset action button */
2686 hildon_button_set_title (HILDON_BUTTON (action_button), NULL);
2687 hildon_button_set_value (HILDON_BUTTON (action_button), NULL);
2688 hildon_button_set_image (HILDON_BUTTON (action_button), NULL);
2690 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
2691 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2692 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2693 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2694 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2695 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2696 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2697 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2698 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2699 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2700 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2701 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2705 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2707 GtkWidget *back_button;
2708 GtkWidget *folder_view;
2709 TnyAccount *account;
2710 const gchar *account_id;
2711 GtkWidget *pannable;
2712 GtkWidget *action_button;
2715 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2717 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2719 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2721 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2723 gtk_widget_set_sensitive (back_button, TRUE);
2724 gtk_widget_set_sensitive (action_button, TRUE);
2726 /* Need to set this here, otherwise callbacks called because
2727 of filtering won't perform correctly */
2728 g_object_set_data (G_OBJECT (dialog),
2729 MOVE_TO_DIALOG_SHOWING_FOLDERS,
2730 GINT_TO_POINTER (TRUE));
2732 account = TNY_ACCOUNT (folder_store);
2733 if (modest_tny_account_is_virtual_local_folders (account)) {
2734 account_id = tny_account_get_id (account);
2735 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2736 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2737 } else if (modest_tny_account_is_memory_card_account (account)) {
2738 account_id = tny_account_get_id (account);
2739 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2740 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2742 account_id = tny_account_get_id (account);
2743 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2744 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2745 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2746 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2749 move_to_dialog_set_selected_folder_store (dialog, folder_store);
2750 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2753 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2754 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2755 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2756 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2757 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2761 on_move_to_dialog_back_clicked (GtkButton *button,
2764 GtkWidget *dialog = (GtkWidget *) userdata;
2766 /* Back to show accounts */
2767 move_to_dialog_show_accounts (dialog);
2771 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
2773 GtkTreeViewColumn *column,
2776 TnyFolderStore *selected = NULL;
2778 GtkWidget *folder_view;
2779 gboolean showing_folders;
2781 dialog = (GtkWidget *) user_data;
2782 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
2783 MOVE_TO_DIALOG_SHOWING_FOLDERS));
2785 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
2786 MOVE_TO_DIALOG_FOLDER_VIEW));
2788 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2792 if (!showing_folders) {
2793 gboolean valid = TRUE;
2795 if (TNY_IS_ACCOUNT (selected) &&
2796 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2797 ModestProtocolType protocol_type;
2799 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2800 valid = !modest_protocol_registry_protocol_type_has_tag
2801 (modest_runtime_get_protocol_registry (),
2803 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_MESSAGE_ADD);
2806 move_to_dialog_show_folders (dialog, selected);
2808 move_to_dialog_set_selected_folder_store (dialog, selected);
2813 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2816 gboolean showing_folders;
2819 dialog = (GtkWidget *) user_data;
2820 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2821 if (showing_folders) {
2822 TnyFolderStore *selected;
2823 GtkWidget *folder_view;
2825 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2826 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2829 move_to_dialog_set_selected_folder_store (dialog, selected);
2830 g_object_unref (selected);
2836 on_move_to_dialog_action_clicked (GtkButton *selection,
2839 TnyFolderStore *selected;
2841 GtkWidget *folder_view;
2842 gboolean showing_folders;
2844 dialog = (GtkWidget *) user_data;
2845 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2846 if (showing_folders) {
2847 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2848 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2851 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2856 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2857 GtkWidget **folder_view)
2859 GtkWidget *dialog, *folder_view_container;
2861 GtkWidget *buttons_hbox;
2862 GtkWidget *back_button;
2863 GdkPixbuf *back_pixbuf;
2864 GtkWidget *top_vbox;
2865 GtkWidget *action_button;
2866 GtkTreeSelection *selection;
2868 /* Create dialog. We cannot use a touch selector because we
2869 need to use here the folder view widget directly */
2870 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2871 GTK_WINDOW (parent_window),
2872 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2873 GTK_DIALOG_DESTROY_WITH_PARENT,
2874 _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2877 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2878 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2879 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2881 /* Create folder view */
2882 *folder_view = modest_platform_create_folder_view (NULL);
2884 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2885 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2886 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2888 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2889 (TnyAccountStore *) modest_runtime_get_account_store ());
2891 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2892 back_button = gtk_button_new ();
2893 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2895 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2896 g_object_unref (back_pixbuf);
2899 action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
2900 HILDON_BUTTON_ARRANGEMENT_VERTICAL);
2901 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2903 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2904 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2905 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2906 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2907 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2909 /* Create pannable and add it to the dialog */
2910 folder_view_container = hildon_pannable_area_new ();
2911 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2912 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2914 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2915 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2917 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2919 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2920 gtk_widget_show (folder_view_container);
2921 gtk_widget_show (align);
2922 gtk_widget_show (top_vbox);
2923 gtk_widget_show (*folder_view);
2924 gtk_widget_show_all (back_button);
2925 gtk_widget_show (action_button);
2926 gtk_widget_show (buttons_hbox);
2927 gtk_widget_show (dialog);
2929 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2930 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2931 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2932 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2934 /* Simulate the behaviour of a HildonPickerDialog by emitting
2935 a response when a folder is selected */
2936 g_signal_connect (*folder_view, "row-activated",
2937 G_CALLBACK (on_move_to_dialog_row_activated),
2940 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2941 g_signal_connect (selection, "changed",
2942 G_CALLBACK (on_move_to_dialog_selection_changed),
2945 g_signal_connect (action_button, "clicked",
2946 G_CALLBACK (on_move_to_dialog_action_clicked),
2949 g_signal_connect (back_button, "clicked",
2950 G_CALLBACK (on_move_to_dialog_back_clicked),
2953 move_to_dialog_show_accounts (dialog);
2959 modest_platform_get_list_to_move (ModestWindow *window)
2961 TnyList *list = NULL;
2963 if (MODEST_IS_HEADER_WINDOW (window)) {
2964 ModestHeaderView *header_view;
2966 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2967 list = modest_header_view_get_selected_headers (header_view);
2968 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2969 ModestFolderView *folder_view;
2970 TnyFolderStore *selected_folder;
2972 list = TNY_LIST (tny_simple_list_new ());
2973 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2974 selected_folder = modest_folder_view_get_selected (folder_view);
2975 if (selected_folder) {
2976 tny_list_prepend (list, G_OBJECT (selected_folder));
2977 g_object_unref (selected_folder);
2980 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2983 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2985 list = TNY_LIST (tny_simple_list_new ());
2986 tny_list_prepend (list, G_OBJECT (header));
2987 g_object_unref (header);
2990 g_return_val_if_reached (NULL);