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>
32 #include <modest-platform.h>
33 #include <modest-runtime.h>
34 #include <modest-main-window.h>
35 #include <modest-header-view.h>
36 #include "modest-hildon2-global-settings-dialog.h"
37 #include "modest-widget-memory.h"
38 #include <modest-hildon-includes.h>
39 #include <modest-maemo-utils.h>
40 #include <dbus_api/modest-dbus-callbacks.h>
41 #include <modest-osso-autosave-callbacks.h>
43 #include <tny-maemo-conic-device.h>
44 #include <tny-simple-list.h>
45 #include <tny-folder.h>
46 #include <gtk/gtkicontheme.h>
47 #include <gtk/gtkmenuitem.h>
48 #include <gtk/gtkmain.h>
49 #include <modest-text-utils.h>
50 #include "modest-tny-folder.h"
51 #include "modest-tny-account.h"
53 #include <libgnomevfs/gnome-vfs-mime-utils.h>
54 #include <modest-account-settings-dialog.h>
55 #include <modest-easysetup-wizard-dialog.h>
56 #include "modest-hildon2-sort-dialog.h"
57 #include <hildon/hildon-sound.h>
59 #include "hildon2/modest-hildon2-details-dialog.h"
60 #include "hildon2/modest-hildon2-window-mgr.h"
61 #include <keys_nokia.h>
62 #include <libprofile.h>
64 #include <modest-datetime-formatter.h>
65 #include "modest-header-window.h"
66 #include <modest-folder-window.h>
67 #include <modest-account-mgr.h>
68 #include <modest-account-mgr-helpers.h>
69 #include <modest-ui-constants.h>
70 #include <modest-selector-picker.h>
72 #ifdef MODEST_HAVE_MCE
73 #include <mce/dbus-names.h>
74 #endif /*MODEST_HAVE_MCE*/
76 #ifdef MODEST_HAVE_ABOOK
77 #include <libosso-abook/osso-abook.h>
78 #endif /*MODEST_HAVE_ABOOK*/
80 #ifdef MODEST_HAVE_LIBALARM
81 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
82 #endif /*MODEST_HAVE_LIBALARM*/
85 #define HILDON_OSSO_URI_ACTION "uri-action"
86 #define URI_ACTION_COPY "copy:"
87 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
88 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
89 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
91 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
92 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
94 static void _modest_platform_play_email_tone (void);
98 on_modest_conf_update_interval_changed (ModestConf* self,
100 ModestConfEvent event,
101 ModestConfNotificationId id,
104 g_return_if_fail (key);
106 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
107 const guint update_interval_minutes =
108 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
109 modest_platform_set_update_interval (update_interval_minutes);
116 check_required_files (void)
118 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
120 g_printerr ("modest: check for mcc file failed\n");
125 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
126 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
127 g_printerr ("modest: cannot find providers data\n");
135 /* the gpointer here is the osso_context. */
137 modest_platform_init (int argc, char *argv[])
139 osso_context_t *osso_context;
141 osso_hw_state_t hw_state = { 0 };
145 if (!check_required_files ()) {
146 g_printerr ("modest: missing required files\n");
150 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
153 g_printerr ("modest: failed to acquire osso context\n");
156 modest_maemo_utils_set_osso_context (osso_context);
158 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
159 g_printerr ("modest: could not get dbus connection\n");
163 /* Add a D-Bus handler to be used when the main osso-rpc
164 * D-Bus handler has not handled something.
165 * We use this for D-Bus methods that need to use more complex types
166 * than osso-rpc supports.
168 if (!dbus_connection_add_filter (con,
169 modest_dbus_req_filter,
173 g_printerr ("modest: Could not add D-Bus filter\n");
177 /* Register our simple D-Bus callbacks, via the osso API: */
178 osso_return_t result = osso_rpc_set_cb_f(osso_context,
182 modest_dbus_req_handler, NULL /* user_data */);
183 if (result != OSSO_OK) {
184 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
188 /* Register hardware event dbus callback: */
189 hw_state.shutdown_ind = TRUE;
190 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
192 /* Register osso auto-save callbacks: */
193 result = osso_application_set_autosave_cb (osso_context,
194 modest_on_osso_application_autosave, NULL /* user_data */);
195 if (result != OSSO_OK) {
196 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
201 /* Make sure that the update interval is changed whenever its gconf key
203 /* CAUTION: we're not using here the
204 modest_conf_listen_to_namespace because we know that there
205 are other parts of Modest listening for this namespace, so
206 we'll receive the notifications anyway. We basically do not
207 use it because there is no easy way to do the
208 modest_conf_forget_namespace */
209 ModestConf *conf = modest_runtime_get_conf ();
210 g_signal_connect (G_OBJECT(conf),
212 G_CALLBACK (on_modest_conf_update_interval_changed),
215 /* only force the setting of the default interval, if there are actually
217 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
219 /* Get the initial update interval from gconf: */
220 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
221 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
222 modest_account_mgr_free_account_names (acc_names);
226 #ifdef MODEST_HAVE_ABOOK
227 /* initialize the addressbook */
228 if (!osso_abook_init (&argc, &argv, osso_context)) {
229 g_printerr ("modest: failed to initialized addressbook\n");
232 #endif /*MODEST_HAVE_ABOOK*/
238 modest_platform_uninit (void)
240 osso_context_t *osso_context =
241 modest_maemo_utils_get_osso_context ();
243 osso_deinitialize (osso_context);
252 modest_platform_get_new_device (void)
254 return TNY_DEVICE (tny_maemo_conic_device_new ());
258 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
259 gchar **effective_mime_type)
261 GString *mime_str = NULL;
262 gchar *icon_name = NULL;
263 gchar **icons, **cursor;
265 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
266 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
268 mime_str = g_string_new (mime_type);
269 g_string_ascii_down (mime_str);
272 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
274 for (cursor = icons; cursor; ++cursor) {
275 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
276 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
277 icon_name = g_strdup ("qgn_list_messagin");
279 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
280 icon_name = g_strdup (*cursor);
286 if (effective_mime_type)
287 *effective_mime_type = g_string_free (mime_str, FALSE);
289 g_string_free (mime_str, TRUE);
296 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
301 g_return_val_if_fail (uri, FALSE);
303 result = hildon_uri_open (uri, action, &err);
305 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
306 uri, action, err && err->message ? err->message : "unknown error");
316 modest_platform_activate_uri (const gchar *uri)
318 HildonURIAction *action;
319 gboolean result = FALSE;
320 GSList *actions, *iter = NULL;
322 g_return_val_if_fail (uri, FALSE);
326 /* don't try to activate file: uri's -- they might confuse the user,
327 * and/or might have security implications */
328 if (!g_str_has_prefix (uri, "file:")) {
330 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
332 for (iter = actions; iter; iter = g_slist_next (iter)) {
333 action = (HildonURIAction*) iter->data;
334 if (action && strcmp (hildon_uri_action_get_service (action),
335 "com.nokia.modest") == 0) {
336 result = checked_hildon_uri_open (uri, action);
341 /* if we could not open it with email, try something else */
343 result = checked_hildon_uri_open (uri, NULL);
347 ModestWindow *parent =
348 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
349 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
350 _("mcen_ib_unsupported_link"));
351 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
358 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
362 gchar *uri_path = NULL;
364 uri_path = gnome_vfs_get_uri_from_local_path (path);
365 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
368 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
370 result = hildon_mime_open_file (con, uri_path);
372 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
380 } ModestPlatformPopupInfo;
383 delete_uri_popup (GtkWidget *menu,
387 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
389 g_free (popup_info->uri);
390 hildon_uri_free_actions (popup_info->actions);
396 activate_uri_popup_item (GtkMenuItem *menu_item,
400 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
401 const gchar* action_name;
403 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
405 g_printerr ("modest: no action name defined\n");
409 /* special handling for the copy menu item -- copy the uri to the clipboard */
410 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
411 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
412 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
413 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
415 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
416 action_name += strlen ("mailto:");
418 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
419 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
420 return; /* we're done */
423 /* now, the real uri-actions... */
424 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
425 HildonURIAction *action = (HildonURIAction *) node->data;
426 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
427 if (!checked_hildon_uri_open (popup_info->uri, action)) {
428 ModestWindow *parent =
429 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
430 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
431 _("mcen_ib_unsupported_link"));
439 modest_platform_show_uri_popup (const gchar *uri)
441 GSList *actions_list;
446 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
449 GtkWidget *menu = gtk_menu_new ();
450 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
452 /* don't add actions for file: uri's -- they might confuse the user,
453 * and/or might have security implications
454 * we still allow to copy the url though
456 if (!g_str_has_prefix (uri, "file:")) {
459 popup_info->actions = actions_list;
460 popup_info->uri = g_strdup (uri);
462 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
463 GtkWidget *menu_item;
464 const gchar *action_name;
465 const gchar *translation_domain;
466 HildonURIAction *action = (HildonURIAction *) node->data;
467 action_name = hildon_uri_action_get_name (action);
468 translation_domain = hildon_uri_action_get_translation_domain (action);
469 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
470 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
471 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
474 if (hildon_uri_is_default_action (action, NULL)) {
475 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
477 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
479 gtk_widget_show (menu_item);
483 /* always add the copy item */
484 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
485 "uri_link_copy_link_location"));
486 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
487 g_strconcat (URI_ACTION_COPY, uri, NULL),
489 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
490 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
491 gtk_widget_show (menu_item);
494 /* and what to do when the link is deleted */
495 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
496 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
499 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
507 modest_platform_get_icon (const gchar *name, guint icon_size)
510 GdkPixbuf* pixbuf = NULL;
511 GtkIconTheme *current_theme = NULL;
513 g_return_val_if_fail (name, NULL);
515 /* strlen == 0 is not really an error; it just
516 * means the icon is not available
518 if (!name || strlen(name) == 0)
521 current_theme = gtk_icon_theme_get_default ();
522 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
523 GTK_ICON_LOOKUP_NO_SVG,
526 g_printerr ("modest: error loading theme icon '%s': %s\n",
534 modest_platform_get_app_name (void)
536 return _("mcen_ap_name");
540 entry_insert_text (GtkEditable *editable,
549 chars = gtk_editable_get_chars (editable, 0, -1);
550 chars_length = g_utf8_strlen (chars, -1);
553 /* Show WID-INF036 */
554 if (chars_length >= 20) {
555 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
556 _CS("ckdg_ib_maximum_characters_reached"));
558 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
562 tmp = g_strndup (folder_name_forbidden_chars,
563 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
564 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
565 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
570 /* Write the text in the entry if it's valid */
571 g_signal_handlers_block_by_func (editable,
572 (gpointer) entry_insert_text, data);
573 gtk_editable_insert_text (editable, text, length, position);
574 g_signal_handlers_unblock_by_func (editable,
575 (gpointer) entry_insert_text, data);
578 /* Do not allow further processing */
579 g_signal_stop_emission_by_name (editable, "insert_text");
583 entry_changed (GtkEditable *editable,
587 GtkWidget *ok_button;
590 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
591 ok_button = GTK_WIDGET (buttons->data);
593 chars = gtk_editable_get_chars (editable, 0, -1);
594 g_return_if_fail (chars != NULL);
597 if (g_utf8_strlen (chars,-1) >= 20)
598 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
599 _CS("ckdg_ib_maximum_characters_reached"));
601 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
604 g_list_free (buttons);
611 on_response (GtkDialog *dialog,
615 GtkWidget *entry, *picker;
616 TnyFolderStore *parent;
617 const gchar *new_name;
620 if (response != GTK_RESPONSE_ACCEPT)
624 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
625 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
627 parent = TNY_FOLDER_STORE (user_data);
628 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
631 if (picker != NULL) {
632 const gchar *active_id;
634 active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (picker));
635 parent = TNY_FOLDER_STORE (
636 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
638 TNY_ACCOUNT_TYPE_STORE));
640 g_object_ref (parent);
642 /* Look for another folder with the same name */
643 if (modest_tny_folder_has_subfolder_with_name (parent,
650 if (TNY_IS_ACCOUNT (parent) &&
651 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
652 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
661 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
662 NULL, _CS("ckdg_ib_folder_already_exists"));
663 /* Select the text */
664 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
665 gtk_widget_grab_focus (entry);
666 /* Do not close the dialog */
667 g_signal_stop_emission_by_name (dialog, "response");
670 g_object_unref (parent);
674 order_by_acc_name (gconstpointer a,
677 ModestPair *pair_a, *pair_b;
679 pair_a = (ModestPair *) a;
680 pair_b = (ModestPair *) b;
682 if (pair_a->second && pair_b->second) {
683 gint compare = g_utf8_collate ((gchar *) pair_a->second,
684 (gchar *) pair_b->second);
687 else if (compare < 0)
696 static ModestPairList *
697 get_folders_accounts_list (void)
700 GSList *cursor, *account_names;
701 ModestAccountMgr *account_mgr;
704 account_mgr = modest_runtime_get_account_mgr ();
706 cursor = account_names = modest_account_mgr_account_names (account_mgr, TRUE /*only enabled*/);
709 ModestAccountSettings *settings;
710 ModestServerAccountSettings *store_settings;
712 account_name = (gchar*)cursor->data;
714 settings = modest_account_mgr_load_account_settings (account_mgr, account_name);
716 g_printerr ("modest: failed to get account data for %s\n", account_name);
719 store_settings = modest_account_settings_get_store_settings (settings);
721 /* don't display accounts not able to show folders */
722 if (modest_server_account_settings_get_account_name (store_settings) != NULL) {
723 ModestProtocolType protocol_type;
725 protocol_type = modest_server_account_settings_get_protocol (store_settings);
726 /* we cannot create folders on accounts without folders */
727 if (modest_protocol_registry_protocol_type_has_tag (modest_runtime_get_protocol_registry (),
729 MODEST_PROTOCOL_REGISTRY_STORE_HAS_FOLDERS)) {
730 if (modest_account_settings_get_enabled (settings)) {
732 pair = modest_pair_new (
733 g_strdup (account_name),
734 g_strdup (modest_account_settings_get_display_name (settings)),
736 list = g_slist_insert_sorted (list, pair, order_by_acc_name);
741 g_object_unref (store_settings);
742 g_object_unref (settings);
743 cursor = cursor->next;
746 /* Create also entries for local account and mmc */
747 pair = modest_pair_new (g_strdup (MODEST_LOCAL_FOLDERS_ACCOUNT_ID),
748 g_strdup (MODEST_LOCAL_FOLDERS_DEFAULT_DISPLAY_NAME),
750 list = g_slist_insert_sorted (list, pair, order_by_acc_name);
752 /* TODO: add mmc account */
754 return (ModestPairList *) g_slist_reverse (list);
760 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
761 TnyFolderStore *suggested_parent,
762 const gchar *dialog_title,
763 const gchar *label_text,
764 const gchar *suggested_name,
766 gboolean show_parent,
768 TnyFolderStore **parent)
770 GtkWidget *accept_btn = NULL;
771 GtkWidget *dialog, *entry, *label, *hbox;
772 GtkWidget *account_picker;
773 GList *buttons = NULL;
775 GSList *accounts_list;
777 /* Ask the user for the folder name */
778 dialog = gtk_dialog_new_with_buttons (dialog_title,
780 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
785 /* Add accept button (with unsensitive handler) */
786 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
787 accept_btn = GTK_WIDGET (buttons->data);
788 /* Create label and entry */
789 label = gtk_label_new (label_text);
792 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
793 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
796 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
798 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
799 gtk_entry_set_width_chars (GTK_ENTRY (entry),
800 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
801 g_utf8_strlen (_("mcen_ia_default_folder_name"), -1)));
802 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
807 accounts_list = get_folders_accounts_list ();
808 account_picker = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
809 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
812 /* TODO: set the active account in window */
813 hildon_button_set_title (HILDON_BUTTON (account_picker), _("TODO: Account:"));
816 /* Connect to the response method to avoid closing the dialog
817 when an invalid name is selected*/
818 g_signal_connect (dialog,
820 G_CALLBACK (on_response),
824 /* Track entry changes */
825 g_signal_connect (entry,
827 G_CALLBACK (entry_insert_text),
829 g_signal_connect (entry,
831 G_CALLBACK (entry_changed),
836 /* Some locales like pt_BR need this to get the full window
838 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
840 /* Create the hbox */
842 hbox = gtk_hbox_new (FALSE, 12);
843 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
844 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
846 /* Add hbox to dialog */
847 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
848 hbox, FALSE, FALSE, 0);
849 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
853 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
854 account_picker, FALSE, FALSE, 0);
855 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
857 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
858 GTK_WINDOW (dialog), parent_window);
859 gtk_widget_show_all (GTK_WIDGET(dialog));
861 result = gtk_dialog_run (GTK_DIALOG(dialog));
862 if (result == GTK_RESPONSE_ACCEPT) {
864 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
866 const gchar *active_id;
868 active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (account_picker));
869 *parent = TNY_FOLDER_STORE (
870 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
872 TNY_ACCOUNT_TYPE_STORE));
876 gtk_widget_destroy (dialog);
879 modest_pair_list_free (accounts_list);
882 while (gtk_events_pending ())
883 gtk_main_iteration ();
889 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
890 TnyFolderStore *suggested_folder,
891 gchar *suggested_name,
893 TnyFolderStore **parent_folder)
895 gchar *real_suggested_name = NULL, *tmp = NULL;
898 if(suggested_name == NULL)
900 const gchar *default_name = _("mcen_ia_default_folder_name");
904 for(i = 0; i < 100; ++ i) {
905 gboolean exists = FALSE;
907 sprintf(num_str, "%.2u", i);
910 real_suggested_name = g_strdup (default_name);
912 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
914 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
921 g_free (real_suggested_name);
924 /* Didn't find a free number */
926 real_suggested_name = g_strdup (default_name);
928 real_suggested_name = suggested_name;
931 tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
932 result = modest_platform_run_folder_common_dialog (parent_window,
934 _("mcen_ti_new_folder"),
943 if (suggested_name == NULL)
944 g_free(real_suggested_name);
950 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
951 TnyFolderStore *parent_folder,
952 const gchar *suggested_name,
955 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
957 return modest_platform_run_folder_common_dialog (parent_window,
959 _HL("ckdg_ti_rename_folder"),
960 _HL("ckdg_fi_rename_name"),
971 on_destroy_dialog (GtkWidget *dialog)
973 /* This could happen when the dialogs get programatically
974 hidden or destroyed (for example when closing the
975 application while a dialog is being shown) */
976 if (!GTK_IS_WIDGET (dialog))
979 gtk_widget_destroy (dialog);
981 if (gtk_events_pending ())
982 gtk_main_iteration ();
986 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
987 const gchar *message)
992 dialog = hildon_note_new_confirmation (parent_window, message);
993 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
994 GTK_WINDOW (dialog), parent_window);
996 response = gtk_dialog_run (GTK_DIALOG (dialog));
998 on_destroy_dialog (dialog);
1004 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1005 const gchar *message,
1006 const gchar *button_accept,
1007 const gchar *button_cancel)
1012 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1013 button_accept, GTK_RESPONSE_ACCEPT,
1014 button_cancel, GTK_RESPONSE_CANCEL,
1017 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1018 GTK_WINDOW (dialog), parent_window);
1020 response = gtk_dialog_run (GTK_DIALOG (dialog));
1022 on_destroy_dialog (dialog);
1028 modest_platform_run_information_dialog (GtkWindow *parent_window,
1029 const gchar *message,
1034 note = hildon_note_new_information (parent_window, message);
1036 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1037 GTK_WINDOW (note), parent_window);
1040 gtk_dialog_run (GTK_DIALOG (note));
1042 on_destroy_dialog (note);
1044 g_signal_connect_swapped (note,
1046 G_CALLBACK (on_destroy_dialog),
1049 gtk_widget_show_all (note);
1053 typedef struct _ConnectAndWaitData {
1055 GMainLoop *wait_loop;
1056 gboolean has_callback;
1058 } ConnectAndWaitData;
1062 quit_wait_loop (TnyAccount *account,
1063 ConnectAndWaitData *data)
1065 /* Set the has_callback to TRUE (means that the callback was
1066 executed and wake up every code waiting for cond to be
1068 g_mutex_lock (data->mutex);
1069 data->has_callback = TRUE;
1070 if (data->wait_loop)
1071 g_main_loop_quit (data->wait_loop);
1072 g_mutex_unlock (data->mutex);
1076 on_connection_status_changed (TnyAccount *account,
1077 TnyConnectionStatus status,
1080 TnyConnectionStatus conn_status;
1081 ConnectAndWaitData *data;
1083 /* Ignore if reconnecting or disconnected */
1084 conn_status = tny_account_get_connection_status (account);
1085 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1086 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1089 /* Remove the handler */
1090 data = (ConnectAndWaitData *) user_data;
1091 g_signal_handler_disconnect (account, data->handler);
1093 /* Quit from wait loop */
1094 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1098 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1103 /* Quit from wait loop */
1104 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1108 modest_platform_connect_and_wait (GtkWindow *parent_window,
1109 TnyAccount *account)
1111 ConnectAndWaitData *data = NULL;
1112 gboolean device_online;
1114 TnyConnectionStatus conn_status;
1115 gboolean user_requested;
1117 device = modest_runtime_get_device();
1118 device_online = tny_device_is_online (device);
1120 /* Whether the connection is user requested or automatically
1121 requested, for example via D-Bus */
1122 user_requested = (parent_window) ? TRUE : FALSE;
1124 /* If there is no account check only the device status */
1129 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1130 NULL, user_requested);
1133 /* Return if the account is already connected */
1134 conn_status = tny_account_get_connection_status (account);
1135 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1138 /* Create the helper */
1139 data = g_slice_new0 (ConnectAndWaitData);
1140 data->mutex = g_mutex_new ();
1141 data->has_callback = FALSE;
1143 /* Connect the device */
1144 if (!device_online) {
1145 /* Track account connection status changes */
1146 data->handler = g_signal_connect (account, "connection-status-changed",
1147 G_CALLBACK (on_connection_status_changed),
1149 /* Try to connect the device */
1150 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1151 NULL, user_requested);
1153 /* If the device connection failed then exit */
1154 if (!device_online && data->handler)
1157 /* Force a reconnection of the account */
1158 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1159 on_tny_camel_account_set_online_cb, data);
1162 /* Wait until the callback is executed */
1163 g_mutex_lock (data->mutex);
1164 if (!data->has_callback) {
1165 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1166 gdk_threads_leave ();
1167 g_mutex_unlock (data->mutex);
1168 g_main_loop_run (data->wait_loop);
1169 g_mutex_lock (data->mutex);
1170 gdk_threads_enter ();
1172 g_mutex_unlock (data->mutex);
1176 if (g_signal_handler_is_connected (account, data->handler))
1177 g_signal_handler_disconnect (account, data->handler);
1178 g_mutex_free (data->mutex);
1179 g_main_loop_unref (data->wait_loop);
1180 g_slice_free (ConnectAndWaitData, data);
1183 conn_status = tny_account_get_connection_status (account);
1184 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1188 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1190 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1191 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1192 /* This must be a maildir account, which does not require a connection: */
1197 return modest_platform_connect_and_wait (parent_window, account);
1201 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1204 return TRUE; /* Maybe it is something local. */
1206 gboolean result = TRUE;
1207 if (TNY_IS_FOLDER (folder_store)) {
1208 /* Get the folder's parent account: */
1209 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1210 if (account != NULL) {
1211 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1212 g_object_unref (account);
1214 } else if (TNY_IS_ACCOUNT (folder_store)) {
1215 /* Use the folder store as an account: */
1216 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1223 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1227 dialog = modest_hildon2_sort_dialog_new (parent_window);
1234 modest_platform_set_update_interval (guint minutes)
1236 #ifdef MODEST_HAVE_LIBALARM
1238 ModestConf *conf = modest_runtime_get_conf ();
1242 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1244 /* Delete any existing alarm,
1245 * because we will replace it: */
1247 if (alarmd_event_del(alarm_cookie) != 1)
1248 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1250 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1253 /* 0 means no updates: */
1258 /* Register alarm: */
1260 /* Set the interval in alarm_event_t structure: */
1261 alarm_event_t *event = alarm_event_create ();
1262 alarm_event_add_actions (event, 1);
1263 alarm_action_t *action = alarm_event_get_action (event, 0);
1264 event->alarm_time = minutes * 60; /* seconds */
1266 /* Set recurrence every few minutes: */
1267 event->recur_secs = minutes*60;
1268 event->recur_count = -1; /* Means infinite */
1270 /* Specify what should happen when the alarm happens:
1271 * It should call this D-Bus method: */
1273 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1274 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1275 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1276 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1277 action->flags = ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1279 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1280 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1281 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1282 * This is why we want to use the Alarm API instead of just g_timeout_add().
1283 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1284 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1286 event->flags = ALARM_EVENT_CONNECTED;
1288 alarm_cookie = alarmd_event_add (event);
1291 alarm_event_delete (event);
1293 /* Store the alarm ID in GConf, so we can remove it later:
1294 * This is apparently valid between application instances. */
1295 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1297 if (!alarm_cookie) {
1299 g_debug ("Error setting alarm event. \n");
1303 #endif /* MODEST_HAVE_LIBALARM */
1308 modest_platform_push_email_notification(void)
1310 gboolean screen_on = TRUE, app_in_foreground;
1312 /* Get the window status */
1313 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1315 /* If the screen is on and the app is in the
1316 foreground we don't show anything */
1317 if (!(screen_on && app_in_foreground)) {
1319 _modest_platform_play_email_tone ();
1321 /* Activate LED. This must be deactivated by
1322 modest_platform_remove_new_mail_notifications */
1323 #ifdef MODEST_HAVE_MCE
1324 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1328 MCE_ACTIVATE_LED_PATTERN,
1330 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1337 modest_platform_on_new_headers_received (TnyList *header_list,
1338 gboolean show_visual)
1340 g_return_if_fail (TNY_IS_LIST(header_list));
1342 if (tny_list_get_length(header_list) == 0) {
1343 g_warning ("%s: header list is empty", __FUNCTION__);
1348 modest_platform_push_email_notification ();
1349 /* We do a return here to avoid indentation with an else */
1353 #ifdef MODEST_HAVE_HILDON_NOTIFY
1354 HildonNotification *notification;
1356 GSList *notifications_list = NULL;
1358 /* Get previous notifications ids */
1359 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1360 MODEST_CONF_NOTIFICATION_IDS,
1361 MODEST_CONF_VALUE_INT, NULL);
1363 iter = tny_list_create_iterator (header_list);
1364 while (!tny_iterator_is_done (iter)) {
1365 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1366 const gchar *display_date;
1367 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1368 TnyFolder *folder = tny_header_get_folder (header);
1369 gboolean first_notification = TRUE;
1372 ModestDatetimeFormatter *datetime_formatter;
1374 /* constant string, don't free */
1375 datetime_formatter = modest_datetime_formatter_new ();
1376 display_date = modest_datetime_formatter_display_datetime (datetime_formatter,
1377 tny_header_get_date_received (header));
1378 g_object_unref (datetime_formatter);
1380 display_address = tny_header_dup_from (header);
1381 /* string is changed in-place */
1382 modest_text_utils_get_display_address (display_address);
1384 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1385 str = tny_header_dup_subject (header);
1386 notification = hildon_notification_new (summary,
1388 "qgn_list_messagin",
1391 /* Create the message URL */
1392 str = tny_header_dup_uid (header);
1393 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1397 hildon_notification_add_dbus_action(notification,
1400 MODEST_DBUS_SERVICE,
1403 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1407 /* Play sound if the user wants. Show the LED
1408 pattern. Show and play just one */
1409 if (G_UNLIKELY (first_notification)) {
1410 gchar *active_profile;
1413 gint mail_volume_int;
1415 first_notification = FALSE;
1417 active_profile = profile_get_profile ();
1418 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1419 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1420 mail_volume_int = profile_parse_int (mail_volume);
1422 if (mail_volume_int > 0)
1423 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1424 "sound-file", mail_tone);
1426 g_free (mail_volume);
1428 g_free (active_profile);
1430 /* Set the led pattern */
1431 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1433 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1435 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1438 /* Notify. We need to do this in an idle because this function
1439 could be called from a thread */
1440 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1442 /* Save id in the list */
1443 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1444 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1445 /* We don't listen for the "closed" signal, because we
1446 don't care about if the notification was removed or
1447 not to store the list in gconf */
1449 /* Free & carry on */
1450 g_free (display_address);
1453 g_object_unref (folder);
1454 g_object_unref (header);
1455 tny_iterator_next (iter);
1457 g_object_unref (iter);
1460 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1461 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1463 g_slist_free (notifications_list);
1465 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1469 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1472 #ifdef MODEST_HAVE_MCE
1473 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1477 MCE_DEACTIVATE_LED_PATTERN,
1479 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1485 #ifdef MODEST_HAVE_HILDON_NOTIFY
1486 GSList *notif_list = NULL;
1488 /* Get previous notifications ids */
1489 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1490 MODEST_CONF_NOTIFICATION_IDS,
1491 MODEST_CONF_VALUE_INT, NULL);
1493 while (notif_list) {
1495 NotifyNotification *notif;
1497 /* Nasty HACK to remove the notifications, set the id
1498 of the existing ones and then close them */
1499 notif_id = GPOINTER_TO_INT(notif_list->data);
1500 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1501 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1503 /* Close the notification, note that some ids could be
1504 already invalid, but we don't care because it does
1506 notify_notification_close(notif, NULL);
1507 g_object_unref(notif);
1509 /* Delete the link, it's like going to the next */
1510 notif_list = g_slist_delete_link (notif_list, notif_list);
1514 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1515 notif_list, MODEST_CONF_VALUE_INT, NULL);
1517 g_slist_free (notif_list);
1519 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1525 modest_platform_get_global_settings_dialog ()
1527 return modest_hildon2_global_settings_dialog_new ();
1531 modest_platform_show_help (GtkWindow *parent_window,
1532 const gchar *help_id)
1538 modest_platform_show_search_messages (GtkWindow *parent_window)
1540 osso_return_t result = OSSO_ERROR;
1542 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1543 "osso_global_search",
1544 "search_email", NULL, DBUS_TYPE_INVALID);
1546 if (result != OSSO_OK) {
1547 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1552 modest_platform_show_addressbook (GtkWindow *parent_window)
1554 osso_return_t result = OSSO_ERROR;
1556 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1558 "top_application", NULL, DBUS_TYPE_INVALID);
1560 if (result != OSSO_OK) {
1561 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1566 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1568 GtkWidget *widget = modest_folder_view_new (query);
1570 /* Show one account by default */
1571 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1572 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1574 /* Restore settings */
1575 modest_widget_memory_restore (modest_runtime_get_conf(),
1577 MODEST_CONF_FOLDER_VIEW_KEY);
1583 banner_finish (gpointer data, GObject *object)
1585 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1586 modest_window_mgr_unregister_banner (mgr);
1587 g_object_unref (mgr);
1591 modest_platform_information_banner (GtkWidget *parent,
1592 const gchar *icon_name,
1595 GtkWidget *banner, *banner_parent = NULL;
1596 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1598 if (modest_window_mgr_get_num_windows (mgr) == 0)
1601 if (parent && GTK_IS_WINDOW (parent)) {
1602 /* If the window is the active one then show the
1603 banner on top of this window */
1604 if (gtk_window_is_active (GTK_WINDOW (parent)))
1605 banner_parent = parent;
1606 /* If the window is not the topmost but it's visible
1607 (it's minimized for example) then show the banner
1609 else if (GTK_WIDGET_VISIBLE (parent))
1610 banner_parent = NULL;
1611 /* If the window is hidden (like the main window when
1612 running in the background) then do not show
1619 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1621 modest_window_mgr_register_banner (mgr);
1623 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1627 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1628 const gchar *icon_name,
1634 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1637 banner = hildon_banner_show_information (parent, icon_name, text);
1638 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1642 modest_platform_animation_banner (GtkWidget *parent,
1643 const gchar *animation_name,
1646 GtkWidget *inf_note = NULL;
1648 g_return_val_if_fail (text != NULL, NULL);
1650 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1653 /* If the parent is not visible then do not show */
1654 if (parent && !GTK_WIDGET_VISIBLE (parent))
1657 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1665 TnyAccount *account;
1668 } CheckAccountIdleData;
1670 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1673 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1675 gboolean stop_trying = FALSE;
1676 g_return_val_if_fail (data && data->account, FALSE);
1678 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1679 tny_account_get_connection_status (data->account));
1681 if (data && data->account &&
1682 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1683 * after which the account is likely to be usable, or never likely to be usable soon: */
1684 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1686 data->is_online = TRUE;
1690 /* Give up if we have tried too many times: */
1691 if (data->count_tries >= NUMBER_OF_TRIES) {
1694 /* Wait for another timeout: */
1695 ++(data->count_tries);
1700 /* Allow the function that requested this idle callback to continue: */
1702 g_main_loop_quit (data->loop);
1705 g_object_unref (data->account);
1707 return FALSE; /* Don't call this again. */
1709 return TRUE; /* Call this timeout callback again. */
1713 /* Return TRUE immediately if the account is already online,
1714 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1715 * soon as the account is online, or FALSE if the account does
1716 * not become online in the NUMBER_OF_TRIES seconds.
1717 * This is useful when the D-Bus method was run immediately after
1718 * the application was started (when using D-Bus activation),
1719 * because the account usually takes a short time to go online.
1720 * The return value is maybe not very useful.
1723 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1727 g_return_val_if_fail (account, FALSE);
1729 if (!tny_device_is_online (modest_runtime_get_device())) {
1730 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1734 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1735 * so we avoid wait unnecessarily: */
1736 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1739 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1740 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1741 * we want to avoid. */
1742 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1745 /* This blocks on the result: */
1746 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1747 data->is_online = FALSE;
1748 data->account = account;
1749 g_object_ref (data->account);
1750 data->count_tries = 0;
1752 GMainContext *context = NULL; /* g_main_context_new (); */
1753 data->loop = g_main_loop_new (context, FALSE /* not running */);
1755 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1757 /* This main loop will run until the idle handler has stopped it: */
1758 g_main_loop_run (data->loop);
1760 g_main_loop_unref (data->loop);
1761 /* g_main_context_unref (context); */
1763 is_online = data->is_online;
1764 g_slice_free (CheckAccountIdleData, data);
1772 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1774 /* GTK_RESPONSE_HELP means we need to show the certificate */
1775 if (response_id == GTK_RESPONSE_APPLY) {
1779 /* Do not close the dialog */
1780 g_signal_stop_emission_by_name (dialog, "response");
1782 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1783 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1784 gtk_dialog_run (GTK_DIALOG(note));
1785 gtk_widget_destroy (note);
1791 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1792 const gchar *certificate)
1797 HildonWindowStack *stack;
1799 stack = hildon_window_stack_get_default ();
1800 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1803 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1808 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1811 /* We use GTK_RESPONSE_APPLY because we want the button in the
1812 middle of OK and CANCEL the same as the browser does for
1813 example. With GTK_RESPONSE_HELP the view button is aligned
1814 to the left while the other two to the right */
1815 note = hildon_note_new_confirmation_add_buttons (
1818 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1819 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1820 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1823 g_signal_connect (G_OBJECT(note), "response",
1824 G_CALLBACK(on_cert_dialog_response),
1825 (gpointer) certificate);
1827 response = gtk_dialog_run(GTK_DIALOG(note));
1829 on_destroy_dialog (note);
1832 return response == GTK_RESPONSE_OK;
1836 modest_platform_run_alert_dialog (const gchar* prompt,
1837 gboolean is_question)
1839 ModestWindow *main_win;
1841 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1842 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1843 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1844 return is_question ? FALSE : TRUE;
1847 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1848 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1850 gboolean retval = TRUE;
1852 /* The Tinymail documentation says that we should show Yes and No buttons,
1853 * when it is a question.
1854 * Obviously, we need tinymail to use more specific error codes instead,
1855 * so we know what buttons to show. */
1856 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1858 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1859 GTK_WINDOW (dialog), GTK_WINDOW (main_win));
1861 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1862 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1864 on_destroy_dialog (dialog);
1866 /* Just show the error text and use the default response: */
1867 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1875 GtkWindow *parent_window;
1876 ModestConnectedPerformer callback;
1877 TnyAccount *account;
1884 on_went_online_info_free (OnWentOnlineInfo *info)
1886 /* And if we cleanup, we DO cleanup :-) */
1889 g_object_unref (info->device);
1892 if (info->parent_window)
1893 g_object_unref (info->parent_window);
1895 g_object_unref (info->account);
1897 g_slice_free (OnWentOnlineInfo, info);
1899 /* We're done ... */
1905 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1907 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1909 /* Now it's really time to callback to the caller. If going online didn't succeed,
1910 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1911 * canceled will be set. Etcetera etcetera. */
1913 if (info->callback) {
1914 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1917 /* This is our last call, we must cleanup here if we didn't yet do that */
1918 on_went_online_info_free (info);
1925 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1927 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1928 info->iap = g_strdup (iap_id);
1930 if (canceled || err || !info->account) {
1932 /* If there's a problem or if there's no account (then that's it for us, we callback
1933 * the caller's callback now. He'll have to handle err or canceled, of course.
1934 * We are not really online, as the account is not really online here ... */
1936 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1937 * this info. We don't cleanup err, Tinymail does that! */
1939 if (info->callback) {
1941 /* info->account can be NULL here, this means that the user did not
1942 * provide a nice account instance. We'll assume that the user knows
1943 * what he's doing and is happy with just the device going online.
1945 * We can't do magic, we don't know what account the user wants to
1946 * see going online. So just the device goes online, end of story */
1948 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1951 } else if (info->account) {
1953 /* If there's no problem and if we have an account, we'll put the account
1954 * online too. When done, the callback of bringing the account online
1955 * will callback the caller's callback. This is the most normal case. */
1957 info->device = TNY_DEVICE (g_object_ref (device));
1959 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1960 on_account_went_online, info);
1962 /* The on_account_went_online cb frees up the info, go look if you
1963 * don't believe me! (so we return here) */
1968 /* We cleanup if we are not bringing the account online too */
1969 on_went_online_info_free (info);
1975 modest_platform_connect_and_perform (GtkWindow *parent_window,
1977 TnyAccount *account,
1978 ModestConnectedPerformer callback,
1981 gboolean device_online;
1983 TnyConnectionStatus conn_status;
1984 OnWentOnlineInfo *info;
1986 device = modest_runtime_get_device();
1987 device_online = tny_device_is_online (device);
1989 /* If there is no account check only the device status */
1992 if (device_online) {
1994 /* We promise to instantly perform the callback, so ... */
1996 callback (FALSE, NULL, parent_window, account, user_data);
2001 info = g_slice_new0 (OnWentOnlineInfo);
2004 info->device = NULL;
2005 info->account = NULL;
2008 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2010 info->parent_window = NULL;
2011 info->user_data = user_data;
2012 info->callback = callback;
2014 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2015 force, on_conic_device_went_online,
2018 /* We'll cleanup in on_conic_device_went_online */
2021 /* The other code has no more reason to run. This is all that we can do for the
2022 * caller (he should have given us a nice and clean account instance!). We
2023 * can't do magic, we don't know what account he intends to bring online. So
2024 * we'll just bring the device online (and await his false bug report). */
2030 /* Return if the account is already connected */
2032 conn_status = tny_account_get_connection_status (account);
2033 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2035 /* We promise to instantly perform the callback, so ... */
2037 callback (FALSE, NULL, parent_window, account, user_data);
2043 /* Else, we are in a state that requires that we go online before we
2044 * call the caller's callback. */
2046 info = g_slice_new0 (OnWentOnlineInfo);
2048 info->device = NULL;
2050 info->account = TNY_ACCOUNT (g_object_ref (account));
2053 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2055 info->parent_window = NULL;
2057 /* So we'll put the callback away for later ... */
2059 info->user_data = user_data;
2060 info->callback = callback;
2062 if (!device_online) {
2064 /* If also the device is offline, then we connect both the device
2065 * and the account */
2067 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2068 force, on_conic_device_went_online,
2073 /* If the device is online, we'll just connect the account */
2075 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2076 on_account_went_online, info);
2079 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2080 * in both situations, go look if you don't believe me! */
2086 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2088 TnyFolderStore *folder_store,
2089 ModestConnectedPerformer callback,
2092 TnyAccount *account = NULL;
2094 if (!folder_store) {
2095 /* We promise to instantly perform the callback, so ... */
2097 callback (FALSE, NULL, parent_window, NULL, user_data);
2101 } else if (TNY_IS_FOLDER (folder_store)) {
2102 /* Get the folder's parent account: */
2103 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2104 } else if (TNY_IS_ACCOUNT (folder_store)) {
2105 /* Use the folder store as an account: */
2106 account = TNY_ACCOUNT (g_object_ref (folder_store));
2109 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2110 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2111 /* No need to connect a local account */
2113 callback (FALSE, NULL, parent_window, account, user_data);
2118 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2122 g_object_unref (account);
2126 src_account_connect_performer (gboolean canceled,
2128 GtkWindow *parent_window,
2129 TnyAccount *src_account,
2132 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2134 if (canceled || err) {
2135 /* If there was any error call the user callback */
2136 info->callback (canceled, err, parent_window, src_account, info->data);
2138 /* Connect the destination account */
2139 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2140 TNY_FOLDER_STORE (info->dst_account),
2141 info->callback, info->data);
2144 /* Free the info object */
2145 g_object_unref (info->dst_account);
2146 g_slice_free (DoubleConnectionInfo, info);
2151 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2153 TnyFolderStore *folder_store,
2154 DoubleConnectionInfo *connect_info)
2156 modest_platform_connect_if_remote_and_perform(parent_window,
2159 src_account_connect_performer,
2164 modest_platform_get_account_settings_wizard (void)
2166 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2168 return GTK_WIDGET (dialog);
2172 modest_platform_get_current_connection (void)
2174 TnyDevice *device = NULL;
2175 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2177 device = modest_runtime_get_device ();
2179 if (!tny_device_is_online (device))
2180 return MODEST_CONNECTED_VIA_ANY;
2182 #ifdef MODEST_HAVE_CONIC
2184 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2186 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2187 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2188 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2190 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2191 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2192 !strcmp (bearer_type, "WIMAX")) {
2193 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2195 retval = MODEST_CONNECTED_VIA_ANY;
2198 g_object_unref (iap);
2201 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2202 #endif /* MODEST_HAVE_CONIC */
2209 modest_platform_check_memory_low (ModestWindow *win,
2214 /* are we in low memory state? */
2215 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2217 if (win && lowmem && visuals)
2218 modest_platform_run_information_dialog (
2220 dgettext("ke-recv","memr_ib_operation_disabled"),
2224 g_debug ("%s: low memory reached. disallowing some operations",
2231 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2237 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2240 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2241 GTK_WINDOW (dialog),
2243 gtk_widget_show_all (dialog);
2245 g_signal_connect_swapped (dialog, "response",
2246 G_CALLBACK (gtk_widget_destroy),
2251 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2257 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2260 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2261 GTK_WINDOW (dialog),
2263 gtk_widget_show_all (dialog);
2265 g_signal_connect_swapped (dialog, "response",
2266 G_CALLBACK (gtk_widget_destroy),
2271 modest_platform_get_osso_context (void)
2273 return modest_maemo_utils_get_osso_context ();
2277 _modest_platform_play_email_tone (void)
2279 gchar *active_profile;
2282 gint mail_volume_int;
2284 ca_context *ca_con = NULL;
2285 ca_proplist *pl = NULL;
2287 active_profile = profile_get_profile ();
2288 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2289 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2290 mail_volume_int = profile_parse_int (mail_volume);
2292 if (mail_volume_int > 0) {
2294 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2295 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2299 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2300 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2301 ca_context_destroy(ca_con);
2305 ca_proplist_create(&pl);
2306 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2307 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2309 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2310 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2312 ca_proplist_destroy(pl);
2313 ca_context_destroy(ca_con);
2316 g_free (mail_volume);
2318 g_free (active_profile);
2322 on_move_to_dialog_folder_activated (GtkTreeView *tree_view,
2324 GtkTreeViewColumn *column,
2327 gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2331 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2332 GtkWidget **folder_view)
2334 GtkWidget *dialog, *folder_view_container;
2336 /* Create dialog. We cannot use a touch selector because we
2337 need to use here the folder view widget directly */
2338 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2339 GTK_WINDOW (parent_window),
2340 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2341 GTK_DIALOG_DESTROY_WITH_PARENT,
2342 _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2345 /* Create folder view */
2346 *folder_view = modest_platform_create_folder_view (NULL);
2348 /* Simulate the behaviour of a HildonPickerDialog by emitting
2349 a response when a folder is selected */
2350 g_signal_connect (*folder_view, "row-activated",
2351 G_CALLBACK (on_move_to_dialog_folder_activated),
2354 /* Create pannable and add it to the dialog */
2355 folder_view_container = hildon_pannable_area_new ();
2356 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2357 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2359 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2361 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2362 gtk_widget_show (folder_view_container);
2363 gtk_widget_show (*folder_view);
2369 modest_platform_get_list_to_move (ModestWindow *window)
2371 if (MODEST_IS_HEADER_WINDOW (window)) {
2372 ModestHeaderView *header_view;
2374 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2376 return modest_header_view_get_selected_headers (header_view);
2377 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2378 ModestFolderView *folder_view;
2379 TnyFolderStore *selected_folder;
2382 list = TNY_LIST (tny_simple_list_new ());
2383 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2384 selected_folder = modest_folder_view_get_selected (folder_view);
2385 if (selected_folder) {
2386 tny_list_prepend (list, G_OBJECT (selected_folder));
2387 g_object_unref (selected_folder);