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>
68 #ifdef MODEST_HAVE_MCE
69 #include <mce/dbus-names.h>
70 #endif /*MODEST_HAVE_MCE*/
72 #ifdef MODEST_HAVE_ABOOK
73 #include <libosso-abook/osso-abook.h>
74 #endif /*MODEST_HAVE_ABOOK*/
76 #ifdef MODEST_HAVE_LIBALARM
77 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
78 #endif /*MODEST_HAVE_LIBALARM*/
81 #define HILDON_OSSO_URI_ACTION "uri-action"
82 #define URI_ACTION_COPY "copy:"
83 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
84 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
85 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
87 static void _modest_platform_play_email_tone (void);
91 on_modest_conf_update_interval_changed (ModestConf* self,
93 ModestConfEvent event,
94 ModestConfNotificationId id,
97 g_return_if_fail (key);
99 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
100 const guint update_interval_minutes =
101 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
102 modest_platform_set_update_interval (update_interval_minutes);
109 check_required_files (void)
111 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
113 g_printerr ("modest: check for mcc file failed\n");
118 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
119 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
120 g_printerr ("modest: cannot find providers data\n");
128 /* the gpointer here is the osso_context. */
130 modest_platform_init (int argc, char *argv[])
132 osso_context_t *osso_context;
134 osso_hw_state_t hw_state = { 0 };
138 if (!check_required_files ()) {
139 g_printerr ("modest: missing required files\n");
143 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
146 g_printerr ("modest: failed to acquire osso context\n");
149 modest_maemo_utils_set_osso_context (osso_context);
151 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
152 g_printerr ("modest: could not get dbus connection\n");
156 /* Add a D-Bus handler to be used when the main osso-rpc
157 * D-Bus handler has not handled something.
158 * We use this for D-Bus methods that need to use more complex types
159 * than osso-rpc supports.
161 if (!dbus_connection_add_filter (con,
162 modest_dbus_req_filter,
166 g_printerr ("modest: Could not add D-Bus filter\n");
170 /* Register our simple D-Bus callbacks, via the osso API: */
171 osso_return_t result = osso_rpc_set_cb_f(osso_context,
175 modest_dbus_req_handler, NULL /* user_data */);
176 if (result != OSSO_OK) {
177 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
181 /* Register hardware event dbus callback: */
182 hw_state.shutdown_ind = TRUE;
183 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
185 /* Register osso auto-save callbacks: */
186 result = osso_application_set_autosave_cb (osso_context,
187 modest_on_osso_application_autosave, NULL /* user_data */);
188 if (result != OSSO_OK) {
189 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
194 /* Make sure that the update interval is changed whenever its gconf key
196 /* CAUTION: we're not using here the
197 modest_conf_listen_to_namespace because we know that there
198 are other parts of Modest listening for this namespace, so
199 we'll receive the notifications anyway. We basically do not
200 use it because there is no easy way to do the
201 modest_conf_forget_namespace */
202 ModestConf *conf = modest_runtime_get_conf ();
203 g_signal_connect (G_OBJECT(conf),
205 G_CALLBACK (on_modest_conf_update_interval_changed),
208 /* only force the setting of the default interval, if there are actually
210 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
212 /* Get the initial update interval from gconf: */
213 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
214 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
215 modest_account_mgr_free_account_names (acc_names);
219 #ifdef MODEST_HAVE_ABOOK
220 /* initialize the addressbook */
221 if (!osso_abook_init (&argc, &argv, osso_context)) {
222 g_printerr ("modest: failed to initialized addressbook\n");
225 #endif /*MODEST_HAVE_ABOOK*/
231 modest_platform_uninit (void)
233 osso_context_t *osso_context =
234 modest_maemo_utils_get_osso_context ();
236 osso_deinitialize (osso_context);
245 modest_platform_get_new_device (void)
247 return TNY_DEVICE (tny_maemo_conic_device_new ());
251 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
252 gchar **effective_mime_type)
254 GString *mime_str = NULL;
255 gchar *icon_name = NULL;
256 gchar **icons, **cursor;
258 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
259 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
261 mime_str = g_string_new (mime_type);
262 g_string_ascii_down (mime_str);
265 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
267 for (cursor = icons; cursor; ++cursor) {
268 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
269 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
270 icon_name = g_strdup ("qgn_list_messagin");
272 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
273 icon_name = g_strdup (*cursor);
279 if (effective_mime_type)
280 *effective_mime_type = g_string_free (mime_str, FALSE);
282 g_string_free (mime_str, TRUE);
289 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
294 g_return_val_if_fail (uri, FALSE);
296 result = hildon_uri_open (uri, action, &err);
298 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
299 uri, action, err && err->message ? err->message : "unknown error");
309 modest_platform_activate_uri (const gchar *uri)
311 HildonURIAction *action;
312 gboolean result = FALSE;
313 GSList *actions, *iter = NULL;
315 g_return_val_if_fail (uri, FALSE);
319 /* don't try to activate file: uri's -- they might confuse the user,
320 * and/or might have security implications */
321 if (!g_str_has_prefix (uri, "file:")) {
323 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
325 for (iter = actions; iter; iter = g_slist_next (iter)) {
326 action = (HildonURIAction*) iter->data;
327 if (action && strcmp (hildon_uri_action_get_service (action),
328 "com.nokia.modest") == 0) {
329 result = checked_hildon_uri_open (uri, action);
334 /* if we could not open it with email, try something else */
336 result = checked_hildon_uri_open (uri, NULL);
340 ModestWindow *parent =
341 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
342 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
343 _("mcen_ib_unsupported_link"));
344 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
351 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
355 gchar *uri_path = NULL;
357 uri_path = gnome_vfs_get_uri_from_local_path (path);
358 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
361 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
363 result = hildon_mime_open_file (con, uri_path);
365 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
373 } ModestPlatformPopupInfo;
376 delete_uri_popup (GtkWidget *menu,
380 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
382 g_free (popup_info->uri);
383 hildon_uri_free_actions (popup_info->actions);
389 activate_uri_popup_item (GtkMenuItem *menu_item,
393 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
394 const gchar* action_name;
396 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
398 g_printerr ("modest: no action name defined\n");
402 /* special handling for the copy menu item -- copy the uri to the clipboard */
403 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
404 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
405 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
406 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
408 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
409 action_name += strlen ("mailto:");
411 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
412 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
413 return; /* we're done */
416 /* now, the real uri-actions... */
417 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
418 HildonURIAction *action = (HildonURIAction *) node->data;
419 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
420 if (!checked_hildon_uri_open (popup_info->uri, action)) {
421 ModestWindow *parent =
422 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
423 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
424 _("mcen_ib_unsupported_link"));
432 modest_platform_show_uri_popup (const gchar *uri)
434 GSList *actions_list;
439 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
442 GtkWidget *menu = gtk_menu_new ();
443 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
445 /* don't add actions for file: uri's -- they might confuse the user,
446 * and/or might have security implications
447 * we still allow to copy the url though
449 if (!g_str_has_prefix (uri, "file:")) {
452 popup_info->actions = actions_list;
453 popup_info->uri = g_strdup (uri);
455 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
456 GtkWidget *menu_item;
457 const gchar *action_name;
458 const gchar *translation_domain;
459 HildonURIAction *action = (HildonURIAction *) node->data;
460 action_name = hildon_uri_action_get_name (action);
461 translation_domain = hildon_uri_action_get_translation_domain (action);
462 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
463 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
464 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
467 if (hildon_uri_is_default_action (action, NULL)) {
468 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
470 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
472 gtk_widget_show (menu_item);
476 /* always add the copy item */
477 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
478 "uri_link_copy_link_location"));
479 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
480 g_strconcat (URI_ACTION_COPY, uri, NULL),
482 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
483 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
484 gtk_widget_show (menu_item);
487 /* and what to do when the link is deleted */
488 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
489 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
492 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
500 modest_platform_get_icon (const gchar *name, guint icon_size)
503 GdkPixbuf* pixbuf = NULL;
504 GtkIconTheme *current_theme = NULL;
506 g_return_val_if_fail (name, NULL);
508 /* strlen == 0 is not really an error; it just
509 * means the icon is not available
511 if (!name || strlen(name) == 0)
514 current_theme = gtk_icon_theme_get_default ();
515 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
516 GTK_ICON_LOOKUP_NO_SVG,
519 g_printerr ("modest: error loading theme icon '%s': %s\n",
527 modest_platform_get_app_name (void)
529 return _("mcen_ap_name");
533 entry_insert_text (GtkEditable *editable,
542 chars = gtk_editable_get_chars (editable, 0, -1);
543 chars_length = g_utf8_strlen (chars, -1);
546 /* Show WID-INF036 */
547 if (chars_length >= 20) {
548 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
549 _CS("ckdg_ib_maximum_characters_reached"));
551 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
555 tmp = g_strndup (folder_name_forbidden_chars,
556 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
557 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
558 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
563 /* Write the text in the entry if it's valid */
564 g_signal_handlers_block_by_func (editable,
565 (gpointer) entry_insert_text, data);
566 gtk_editable_insert_text (editable, text, length, position);
567 g_signal_handlers_unblock_by_func (editable,
568 (gpointer) entry_insert_text, data);
571 /* Do not allow further processing */
572 g_signal_stop_emission_by_name (editable, "insert_text");
576 entry_changed (GtkEditable *editable,
580 GtkWidget *ok_button;
583 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
584 ok_button = GTK_WIDGET (buttons->data);
586 chars = gtk_editable_get_chars (editable, 0, -1);
587 g_return_if_fail (chars != NULL);
590 if (g_utf8_strlen (chars,-1) >= 20)
591 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
592 _CS("ckdg_ib_maximum_characters_reached"));
594 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
597 g_list_free (buttons);
604 on_response (GtkDialog *dialog,
608 GList *child_vbox, *child_hbox;
609 GtkWidget *hbox, *entry;
610 TnyFolderStore *parent;
611 const gchar *new_name;
614 if (response != GTK_RESPONSE_ACCEPT)
618 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
619 hbox = child_vbox->data;
620 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
621 entry = child_hbox->next->data;
623 parent = TNY_FOLDER_STORE (user_data);
624 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
627 /* Look for another folder with the same name */
628 if (modest_tny_folder_has_subfolder_with_name (parent,
635 if (TNY_IS_ACCOUNT (parent) &&
636 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
637 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
646 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
647 NULL, _CS("ckdg_ib_folder_already_exists"));
648 /* Select the text */
649 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
650 gtk_widget_grab_focus (entry);
651 /* Do not close the dialog */
652 g_signal_stop_emission_by_name (dialog, "response");
659 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
660 TnyFolderStore *parent,
661 const gchar *dialog_title,
662 const gchar *label_text,
663 const gchar *suggested_name,
666 GtkWidget *accept_btn = NULL;
667 GtkWidget *dialog, *entry, *label, *hbox;
668 GList *buttons = NULL;
671 /* Ask the user for the folder name */
672 dialog = gtk_dialog_new_with_buttons (dialog_title,
674 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
679 /* Add accept button (with unsensitive handler) */
680 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
681 accept_btn = GTK_WIDGET (buttons->data);
682 /* Create label and entry */
683 label = gtk_label_new (label_text);
685 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
686 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
689 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
691 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
692 gtk_entry_set_width_chars (GTK_ENTRY (entry),
693 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
694 g_utf8_strlen (_("mcen_ia_default_folder_name"), -1)));
695 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
697 /* Connect to the response method to avoid closing the dialog
698 when an invalid name is selected*/
699 g_signal_connect (dialog,
701 G_CALLBACK (on_response),
704 /* Track entry changes */
705 g_signal_connect (entry,
707 G_CALLBACK (entry_insert_text),
709 g_signal_connect (entry,
711 G_CALLBACK (entry_changed),
715 /* Some locales like pt_BR need this to get the full window
717 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
719 /* Create the hbox */
720 hbox = gtk_hbox_new (FALSE, 12);
721 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
722 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
724 /* Add hbox to dialog */
725 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
726 hbox, FALSE, FALSE, 0);
727 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
728 GTK_WINDOW (dialog), parent_window);
729 gtk_widget_show_all (GTK_WIDGET(dialog));
731 result = gtk_dialog_run (GTK_DIALOG(dialog));
732 if (result == GTK_RESPONSE_ACCEPT)
733 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
735 gtk_widget_destroy (dialog);
737 while (gtk_events_pending ())
738 gtk_main_iteration ();
744 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
745 TnyFolderStore *parent_folder,
746 gchar *suggested_name,
749 gchar *real_suggested_name = NULL, *tmp = NULL;
752 if(suggested_name == NULL)
754 const gchar *default_name = _("mcen_ia_default_folder_name");
758 for(i = 0; i < 100; ++ i) {
759 gboolean exists = FALSE;
761 sprintf(num_str, "%.2u", i);
764 real_suggested_name = g_strdup (default_name);
766 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
768 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
775 g_free (real_suggested_name);
778 /* Didn't find a free number */
780 real_suggested_name = g_strdup (default_name);
782 real_suggested_name = suggested_name;
785 tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
786 result = modest_platform_run_folder_name_dialog (parent_window,
788 _("mcen_ti_new_folder"),
794 if (suggested_name == NULL)
795 g_free(real_suggested_name);
801 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
802 TnyFolderStore *parent_folder,
803 const gchar *suggested_name,
806 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
808 return modest_platform_run_folder_name_dialog (parent_window,
810 _HL("ckdg_ti_rename_folder"),
811 _HL("ckdg_fi_rename_name"),
819 on_destroy_dialog (GtkWidget *dialog)
821 /* This could happen when the dialogs get programatically
822 hidden or destroyed (for example when closing the
823 application while a dialog is being shown) */
824 if (!GTK_IS_WIDGET (dialog))
827 gtk_widget_destroy (dialog);
829 if (gtk_events_pending ())
830 gtk_main_iteration ();
834 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
835 const gchar *message)
840 dialog = hildon_note_new_confirmation (parent_window, message);
841 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
842 GTK_WINDOW (dialog), parent_window);
844 response = gtk_dialog_run (GTK_DIALOG (dialog));
846 on_destroy_dialog (dialog);
852 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
853 const gchar *message,
854 const gchar *button_accept,
855 const gchar *button_cancel)
860 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
861 button_accept, GTK_RESPONSE_ACCEPT,
862 button_cancel, GTK_RESPONSE_CANCEL,
865 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
866 GTK_WINDOW (dialog), parent_window);
868 response = gtk_dialog_run (GTK_DIALOG (dialog));
870 on_destroy_dialog (dialog);
876 modest_platform_run_information_dialog (GtkWindow *parent_window,
877 const gchar *message,
882 note = hildon_note_new_information (parent_window, message);
884 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
885 GTK_WINDOW (note), parent_window);
888 gtk_dialog_run (GTK_DIALOG (note));
890 on_destroy_dialog (note);
892 g_signal_connect_swapped (note,
894 G_CALLBACK (on_destroy_dialog),
897 gtk_widget_show_all (note);
901 typedef struct _ConnectAndWaitData {
903 GMainLoop *wait_loop;
904 gboolean has_callback;
906 } ConnectAndWaitData;
910 quit_wait_loop (TnyAccount *account,
911 ConnectAndWaitData *data)
913 /* Set the has_callback to TRUE (means that the callback was
914 executed and wake up every code waiting for cond to be
916 g_mutex_lock (data->mutex);
917 data->has_callback = TRUE;
919 g_main_loop_quit (data->wait_loop);
920 g_mutex_unlock (data->mutex);
924 on_connection_status_changed (TnyAccount *account,
925 TnyConnectionStatus status,
928 TnyConnectionStatus conn_status;
929 ConnectAndWaitData *data;
931 /* Ignore if reconnecting or disconnected */
932 conn_status = tny_account_get_connection_status (account);
933 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
934 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
937 /* Remove the handler */
938 data = (ConnectAndWaitData *) user_data;
939 g_signal_handler_disconnect (account, data->handler);
941 /* Quit from wait loop */
942 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
946 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
951 /* Quit from wait loop */
952 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
956 modest_platform_connect_and_wait (GtkWindow *parent_window,
959 ConnectAndWaitData *data = NULL;
960 gboolean device_online;
962 TnyConnectionStatus conn_status;
963 gboolean user_requested;
965 device = modest_runtime_get_device();
966 device_online = tny_device_is_online (device);
968 /* Whether the connection is user requested or automatically
969 requested, for example via D-Bus */
970 user_requested = (parent_window) ? TRUE : FALSE;
972 /* If there is no account check only the device status */
977 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
978 NULL, user_requested);
981 /* Return if the account is already connected */
982 conn_status = tny_account_get_connection_status (account);
983 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
986 /* Create the helper */
987 data = g_slice_new0 (ConnectAndWaitData);
988 data->mutex = g_mutex_new ();
989 data->has_callback = FALSE;
991 /* Connect the device */
992 if (!device_online) {
993 /* Track account connection status changes */
994 data->handler = g_signal_connect (account, "connection-status-changed",
995 G_CALLBACK (on_connection_status_changed),
997 /* Try to connect the device */
998 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
999 NULL, user_requested);
1001 /* If the device connection failed then exit */
1002 if (!device_online && data->handler)
1005 /* Force a reconnection of the account */
1006 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1007 on_tny_camel_account_set_online_cb, data);
1010 /* Wait until the callback is executed */
1011 g_mutex_lock (data->mutex);
1012 if (!data->has_callback) {
1013 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1014 gdk_threads_leave ();
1015 g_mutex_unlock (data->mutex);
1016 g_main_loop_run (data->wait_loop);
1017 g_mutex_lock (data->mutex);
1018 gdk_threads_enter ();
1020 g_mutex_unlock (data->mutex);
1024 if (g_signal_handler_is_connected (account, data->handler))
1025 g_signal_handler_disconnect (account, data->handler);
1026 g_mutex_free (data->mutex);
1027 g_main_loop_unref (data->wait_loop);
1028 g_slice_free (ConnectAndWaitData, data);
1031 conn_status = tny_account_get_connection_status (account);
1032 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1036 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1038 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1039 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1040 /* This must be a maildir account, which does not require a connection: */
1045 return modest_platform_connect_and_wait (parent_window, account);
1049 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1052 return TRUE; /* Maybe it is something local. */
1054 gboolean result = TRUE;
1055 if (TNY_IS_FOLDER (folder_store)) {
1056 /* Get the folder's parent account: */
1057 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1058 if (account != NULL) {
1059 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1060 g_object_unref (account);
1062 } else if (TNY_IS_ACCOUNT (folder_store)) {
1063 /* Use the folder store as an account: */
1064 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1071 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1075 dialog = modest_hildon2_sort_dialog_new (parent_window);
1082 modest_platform_set_update_interval (guint minutes)
1084 #ifdef MODEST_HAVE_LIBALARM
1086 ModestConf *conf = modest_runtime_get_conf ();
1090 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1092 /* Delete any existing alarm,
1093 * because we will replace it: */
1095 if (alarmd_event_del(alarm_cookie) != 1)
1096 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1098 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1101 /* 0 means no updates: */
1106 /* Register alarm: */
1108 /* Set the interval in alarm_event_t structure: */
1109 alarm_event_t *event = alarm_event_create ();
1110 alarm_event_add_actions (event, 1);
1111 alarm_action_t *action = alarm_event_get_action (event, 0);
1112 event->alarm_time = minutes * 60; /* seconds */
1114 /* Set recurrence every few minutes: */
1115 event->recur_secs = minutes*60;
1116 event->recur_count = -1; /* Means infinite */
1118 /* Specify what should happen when the alarm happens:
1119 * It should call this D-Bus method: */
1121 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1122 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1123 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1124 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1125 action->flags = ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1127 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1128 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1129 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1130 * This is why we want to use the Alarm API instead of just g_timeout_add().
1131 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1132 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1134 event->flags = ALARM_EVENT_CONNECTED;
1136 alarm_cookie = alarmd_event_add (event);
1139 alarm_event_delete (event);
1141 /* Store the alarm ID in GConf, so we can remove it later:
1142 * This is apparently valid between application instances. */
1143 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1145 if (!alarm_cookie) {
1147 g_debug ("Error setting alarm event. \n");
1151 #endif /* MODEST_HAVE_LIBALARM */
1156 modest_platform_push_email_notification(void)
1158 gboolean screen_on = TRUE, app_in_foreground;
1160 /* Get the window status */
1161 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1163 /* If the screen is on and the app is in the
1164 foreground we don't show anything */
1165 if (!(screen_on && app_in_foreground)) {
1167 _modest_platform_play_email_tone ();
1169 /* Activate LED. This must be deactivated by
1170 modest_platform_remove_new_mail_notifications */
1171 #ifdef MODEST_HAVE_MCE
1172 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1176 MCE_ACTIVATE_LED_PATTERN,
1178 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1185 modest_platform_on_new_headers_received (TnyList *header_list,
1186 gboolean show_visual)
1188 g_return_if_fail (TNY_IS_LIST(header_list));
1190 if (tny_list_get_length(header_list) == 0) {
1191 g_warning ("%s: header list is empty", __FUNCTION__);
1196 modest_platform_push_email_notification ();
1197 /* We do a return here to avoid indentation with an else */
1201 #ifdef MODEST_HAVE_HILDON_NOTIFY
1202 HildonNotification *notification;
1204 GSList *notifications_list = NULL;
1206 /* Get previous notifications ids */
1207 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1208 MODEST_CONF_NOTIFICATION_IDS,
1209 MODEST_CONF_VALUE_INT, NULL);
1211 iter = tny_list_create_iterator (header_list);
1212 while (!tny_iterator_is_done (iter)) {
1213 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1214 const gchar *display_date;
1215 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1216 TnyFolder *folder = tny_header_get_folder (header);
1217 gboolean first_notification = TRUE;
1220 ModestDatetimeFormatter *datetime_formatter;
1222 /* constant string, don't free */
1223 datetime_formatter = modest_datetime_formatter_new ();
1224 display_date = modest_datetime_formatter_display_datetime (datetime_formatter,
1225 tny_header_get_date_received (header));
1226 g_object_unref (datetime_formatter);
1228 display_address = tny_header_dup_from (header);
1229 /* string is changed in-place */
1230 modest_text_utils_get_display_address (display_address);
1232 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1233 str = tny_header_dup_subject (header);
1234 notification = hildon_notification_new (summary,
1236 "qgn_list_messagin",
1239 /* Create the message URL */
1240 str = tny_header_dup_uid (header);
1241 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1245 hildon_notification_add_dbus_action(notification,
1248 MODEST_DBUS_SERVICE,
1251 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1255 /* Play sound if the user wants. Show the LED
1256 pattern. Show and play just one */
1257 if (G_UNLIKELY (first_notification)) {
1258 gchar *active_profile;
1261 gint mail_volume_int;
1263 first_notification = FALSE;
1265 active_profile = profile_get_profile ();
1266 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1267 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1268 mail_volume_int = profile_parse_int (mail_volume);
1270 if (mail_volume_int > 0)
1271 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1272 "sound-file", mail_tone);
1274 g_free (mail_volume);
1276 g_free (active_profile);
1278 /* Set the led pattern */
1279 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1281 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1283 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1286 /* Notify. We need to do this in an idle because this function
1287 could be called from a thread */
1288 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1290 /* Save id in the list */
1291 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1292 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1293 /* We don't listen for the "closed" signal, because we
1294 don't care about if the notification was removed or
1295 not to store the list in gconf */
1297 /* Free & carry on */
1298 g_free (display_address);
1301 g_object_unref (folder);
1302 g_object_unref (header);
1303 tny_iterator_next (iter);
1305 g_object_unref (iter);
1308 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1309 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1311 g_slist_free (notifications_list);
1313 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1317 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1320 #ifdef MODEST_HAVE_MCE
1321 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1325 MCE_DEACTIVATE_LED_PATTERN,
1327 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1333 #ifdef MODEST_HAVE_HILDON_NOTIFY
1334 GSList *notif_list = NULL;
1336 /* Get previous notifications ids */
1337 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1338 MODEST_CONF_NOTIFICATION_IDS,
1339 MODEST_CONF_VALUE_INT, NULL);
1341 while (notif_list) {
1343 NotifyNotification *notif;
1345 /* Nasty HACK to remove the notifications, set the id
1346 of the existing ones and then close them */
1347 notif_id = GPOINTER_TO_INT(notif_list->data);
1348 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1349 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1351 /* Close the notification, note that some ids could be
1352 already invalid, but we don't care because it does
1354 notify_notification_close(notif, NULL);
1355 g_object_unref(notif);
1357 /* Delete the link, it's like going to the next */
1358 notif_list = g_slist_delete_link (notif_list, notif_list);
1362 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1363 notif_list, MODEST_CONF_VALUE_INT, NULL);
1365 g_slist_free (notif_list);
1367 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1373 modest_platform_get_global_settings_dialog ()
1375 return modest_hildon2_global_settings_dialog_new ();
1379 modest_platform_show_help (GtkWindow *parent_window,
1380 const gchar *help_id)
1386 modest_platform_show_search_messages (GtkWindow *parent_window)
1388 osso_return_t result = OSSO_ERROR;
1390 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1391 "osso_global_search",
1392 "search_email", NULL, DBUS_TYPE_INVALID);
1394 if (result != OSSO_OK) {
1395 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1400 modest_platform_show_addressbook (GtkWindow *parent_window)
1402 osso_return_t result = OSSO_ERROR;
1404 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1406 "top_application", NULL, DBUS_TYPE_INVALID);
1408 if (result != OSSO_OK) {
1409 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1414 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1416 GtkWidget *widget = modest_folder_view_new (query);
1418 /* Show one account by default */
1419 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1420 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1422 /* Restore settings */
1423 modest_widget_memory_restore (modest_runtime_get_conf(),
1425 MODEST_CONF_FOLDER_VIEW_KEY);
1431 banner_finish (gpointer data, GObject *object)
1433 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1434 modest_window_mgr_unregister_banner (mgr);
1435 g_object_unref (mgr);
1439 modest_platform_information_banner (GtkWidget *parent,
1440 const gchar *icon_name,
1443 GtkWidget *banner, *banner_parent = NULL;
1444 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1446 if (modest_window_mgr_get_num_windows (mgr) == 0)
1449 if (parent && GTK_IS_WINDOW (parent)) {
1450 /* If the window is the active one then show the
1451 banner on top of this window */
1452 if (gtk_window_is_active (GTK_WINDOW (parent)))
1453 banner_parent = parent;
1454 /* If the window is not the topmost but it's visible
1455 (it's minimized for example) then show the banner
1457 else if (GTK_WIDGET_VISIBLE (parent))
1458 banner_parent = NULL;
1459 /* If the window is hidden (like the main window when
1460 running in the background) then do not show
1467 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1469 modest_window_mgr_register_banner (mgr);
1471 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1475 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1476 const gchar *icon_name,
1482 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1485 banner = hildon_banner_show_information (parent, icon_name, text);
1486 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1490 modest_platform_animation_banner (GtkWidget *parent,
1491 const gchar *animation_name,
1494 GtkWidget *inf_note = NULL;
1496 g_return_val_if_fail (text != NULL, NULL);
1498 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1501 /* If the parent is not visible then do not show */
1502 if (parent && !GTK_WIDGET_VISIBLE (parent))
1505 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1513 TnyAccount *account;
1516 } CheckAccountIdleData;
1518 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1521 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1523 gboolean stop_trying = FALSE;
1524 g_return_val_if_fail (data && data->account, FALSE);
1526 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1527 tny_account_get_connection_status (data->account));
1529 if (data && data->account &&
1530 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1531 * after which the account is likely to be usable, or never likely to be usable soon: */
1532 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1534 data->is_online = TRUE;
1538 /* Give up if we have tried too many times: */
1539 if (data->count_tries >= NUMBER_OF_TRIES) {
1542 /* Wait for another timeout: */
1543 ++(data->count_tries);
1548 /* Allow the function that requested this idle callback to continue: */
1550 g_main_loop_quit (data->loop);
1553 g_object_unref (data->account);
1555 return FALSE; /* Don't call this again. */
1557 return TRUE; /* Call this timeout callback again. */
1561 /* Return TRUE immediately if the account is already online,
1562 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1563 * soon as the account is online, or FALSE if the account does
1564 * not become online in the NUMBER_OF_TRIES seconds.
1565 * This is useful when the D-Bus method was run immediately after
1566 * the application was started (when using D-Bus activation),
1567 * because the account usually takes a short time to go online.
1568 * The return value is maybe not very useful.
1571 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1575 g_return_val_if_fail (account, FALSE);
1577 if (!tny_device_is_online (modest_runtime_get_device())) {
1578 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1582 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1583 * so we avoid wait unnecessarily: */
1584 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1587 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1588 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1589 * we want to avoid. */
1590 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1593 /* This blocks on the result: */
1594 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1595 data->is_online = FALSE;
1596 data->account = account;
1597 g_object_ref (data->account);
1598 data->count_tries = 0;
1600 GMainContext *context = NULL; /* g_main_context_new (); */
1601 data->loop = g_main_loop_new (context, FALSE /* not running */);
1603 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1605 /* This main loop will run until the idle handler has stopped it: */
1606 g_main_loop_run (data->loop);
1608 g_main_loop_unref (data->loop);
1609 /* g_main_context_unref (context); */
1611 is_online = data->is_online;
1612 g_slice_free (CheckAccountIdleData, data);
1620 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1622 /* GTK_RESPONSE_HELP means we need to show the certificate */
1623 if (response_id == GTK_RESPONSE_APPLY) {
1627 /* Do not close the dialog */
1628 g_signal_stop_emission_by_name (dialog, "response");
1630 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1631 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1632 gtk_dialog_run (GTK_DIALOG(note));
1633 gtk_widget_destroy (note);
1639 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1640 const gchar *certificate)
1645 HildonWindowStack *stack;
1647 stack = hildon_window_stack_get_default ();
1648 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1651 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1656 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1659 /* We use GTK_RESPONSE_APPLY because we want the button in the
1660 middle of OK and CANCEL the same as the browser does for
1661 example. With GTK_RESPONSE_HELP the view button is aligned
1662 to the left while the other two to the right */
1663 note = hildon_note_new_confirmation_add_buttons (
1666 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1667 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1668 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1671 g_signal_connect (G_OBJECT(note), "response",
1672 G_CALLBACK(on_cert_dialog_response),
1673 (gpointer) certificate);
1675 response = gtk_dialog_run(GTK_DIALOG(note));
1677 on_destroy_dialog (note);
1680 return response == GTK_RESPONSE_OK;
1684 modest_platform_run_alert_dialog (const gchar* prompt,
1685 gboolean is_question)
1687 ModestWindow *main_win;
1689 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1690 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1691 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1692 return is_question ? FALSE : TRUE;
1695 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1696 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1698 gboolean retval = TRUE;
1700 /* The Tinymail documentation says that we should show Yes and No buttons,
1701 * when it is a question.
1702 * Obviously, we need tinymail to use more specific error codes instead,
1703 * so we know what buttons to show. */
1704 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1706 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1707 GTK_WINDOW (dialog), GTK_WINDOW (main_win));
1709 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1710 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1712 on_destroy_dialog (dialog);
1714 /* Just show the error text and use the default response: */
1715 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1723 GtkWindow *parent_window;
1724 ModestConnectedPerformer callback;
1725 TnyAccount *account;
1732 on_went_online_info_free (OnWentOnlineInfo *info)
1734 /* And if we cleanup, we DO cleanup :-) */
1737 g_object_unref (info->device);
1740 if (info->parent_window)
1741 g_object_unref (info->parent_window);
1743 g_object_unref (info->account);
1745 g_slice_free (OnWentOnlineInfo, info);
1747 /* We're done ... */
1753 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1755 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1757 /* Now it's really time to callback to the caller. If going online didn't succeed,
1758 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1759 * canceled will be set. Etcetera etcetera. */
1761 if (info->callback) {
1762 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1765 /* This is our last call, we must cleanup here if we didn't yet do that */
1766 on_went_online_info_free (info);
1773 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1775 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1776 info->iap = g_strdup (iap_id);
1778 if (canceled || err || !info->account) {
1780 /* If there's a problem or if there's no account (then that's it for us, we callback
1781 * the caller's callback now. He'll have to handle err or canceled, of course.
1782 * We are not really online, as the account is not really online here ... */
1784 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1785 * this info. We don't cleanup err, Tinymail does that! */
1787 if (info->callback) {
1789 /* info->account can be NULL here, this means that the user did not
1790 * provide a nice account instance. We'll assume that the user knows
1791 * what he's doing and is happy with just the device going online.
1793 * We can't do magic, we don't know what account the user wants to
1794 * see going online. So just the device goes online, end of story */
1796 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1799 } else if (info->account) {
1801 /* If there's no problem and if we have an account, we'll put the account
1802 * online too. When done, the callback of bringing the account online
1803 * will callback the caller's callback. This is the most normal case. */
1805 info->device = TNY_DEVICE (g_object_ref (device));
1807 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1808 on_account_went_online, info);
1810 /* The on_account_went_online cb frees up the info, go look if you
1811 * don't believe me! (so we return here) */
1816 /* We cleanup if we are not bringing the account online too */
1817 on_went_online_info_free (info);
1823 modest_platform_connect_and_perform (GtkWindow *parent_window,
1825 TnyAccount *account,
1826 ModestConnectedPerformer callback,
1829 gboolean device_online;
1831 TnyConnectionStatus conn_status;
1832 OnWentOnlineInfo *info;
1834 device = modest_runtime_get_device();
1835 device_online = tny_device_is_online (device);
1837 /* If there is no account check only the device status */
1840 if (device_online) {
1842 /* We promise to instantly perform the callback, so ... */
1844 callback (FALSE, NULL, parent_window, account, user_data);
1849 info = g_slice_new0 (OnWentOnlineInfo);
1852 info->device = NULL;
1853 info->account = NULL;
1856 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1858 info->parent_window = NULL;
1859 info->user_data = user_data;
1860 info->callback = callback;
1862 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1863 force, on_conic_device_went_online,
1866 /* We'll cleanup in on_conic_device_went_online */
1869 /* The other code has no more reason to run. This is all that we can do for the
1870 * caller (he should have given us a nice and clean account instance!). We
1871 * can't do magic, we don't know what account he intends to bring online. So
1872 * we'll just bring the device online (and await his false bug report). */
1878 /* Return if the account is already connected */
1880 conn_status = tny_account_get_connection_status (account);
1881 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1883 /* We promise to instantly perform the callback, so ... */
1885 callback (FALSE, NULL, parent_window, account, user_data);
1891 /* Else, we are in a state that requires that we go online before we
1892 * call the caller's callback. */
1894 info = g_slice_new0 (OnWentOnlineInfo);
1896 info->device = NULL;
1898 info->account = TNY_ACCOUNT (g_object_ref (account));
1901 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1903 info->parent_window = NULL;
1905 /* So we'll put the callback away for later ... */
1907 info->user_data = user_data;
1908 info->callback = callback;
1910 if (!device_online) {
1912 /* If also the device is offline, then we connect both the device
1913 * and the account */
1915 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1916 force, on_conic_device_went_online,
1921 /* If the device is online, we'll just connect the account */
1923 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1924 on_account_went_online, info);
1927 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1928 * in both situations, go look if you don't believe me! */
1934 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1936 TnyFolderStore *folder_store,
1937 ModestConnectedPerformer callback,
1940 TnyAccount *account = NULL;
1942 if (!folder_store) {
1943 /* We promise to instantly perform the callback, so ... */
1945 callback (FALSE, NULL, parent_window, NULL, user_data);
1949 } else if (TNY_IS_FOLDER (folder_store)) {
1950 /* Get the folder's parent account: */
1951 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1952 } else if (TNY_IS_ACCOUNT (folder_store)) {
1953 /* Use the folder store as an account: */
1954 account = TNY_ACCOUNT (g_object_ref (folder_store));
1957 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1958 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1959 /* No need to connect a local account */
1961 callback (FALSE, NULL, parent_window, account, user_data);
1966 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1970 g_object_unref (account);
1974 src_account_connect_performer (gboolean canceled,
1976 GtkWindow *parent_window,
1977 TnyAccount *src_account,
1980 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1982 if (canceled || err) {
1983 /* If there was any error call the user callback */
1984 info->callback (canceled, err, parent_window, src_account, info->data);
1986 /* Connect the destination account */
1987 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1988 TNY_FOLDER_STORE (info->dst_account),
1989 info->callback, info->data);
1992 /* Free the info object */
1993 g_object_unref (info->dst_account);
1994 g_slice_free (DoubleConnectionInfo, info);
1999 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2001 TnyFolderStore *folder_store,
2002 DoubleConnectionInfo *connect_info)
2004 modest_platform_connect_if_remote_and_perform(parent_window,
2007 src_account_connect_performer,
2012 modest_platform_get_account_settings_wizard (void)
2014 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2016 return GTK_WIDGET (dialog);
2020 modest_platform_get_current_connection (void)
2022 TnyDevice *device = NULL;
2023 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2025 device = modest_runtime_get_device ();
2027 if (!tny_device_is_online (device))
2028 return MODEST_CONNECTED_VIA_ANY;
2030 #ifdef MODEST_HAVE_CONIC
2032 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2034 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2035 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2036 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2038 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2039 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2040 !strcmp (bearer_type, "WIMAX")) {
2041 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2043 retval = MODEST_CONNECTED_VIA_ANY;
2046 g_object_unref (iap);
2049 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2050 #endif /* MODEST_HAVE_CONIC */
2057 modest_platform_check_memory_low (ModestWindow *win,
2062 /* are we in low memory state? */
2063 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2065 if (win && lowmem && visuals)
2066 modest_platform_run_information_dialog (
2068 dgettext("ke-recv","memr_ib_operation_disabled"),
2072 g_debug ("%s: low memory reached. disallowing some operations",
2079 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2085 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2088 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2089 GTK_WINDOW (dialog),
2091 gtk_widget_show_all (dialog);
2093 g_signal_connect_swapped (dialog, "response",
2094 G_CALLBACK (gtk_widget_destroy),
2099 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2105 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2108 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2109 GTK_WINDOW (dialog),
2111 gtk_widget_show_all (dialog);
2113 g_signal_connect_swapped (dialog, "response",
2114 G_CALLBACK (gtk_widget_destroy),
2119 modest_platform_get_osso_context (void)
2121 return modest_maemo_utils_get_osso_context ();
2125 _modest_platform_play_email_tone (void)
2127 gchar *active_profile;
2130 gint mail_volume_int;
2132 ca_context *ca_con = NULL;
2133 ca_proplist *pl = NULL;
2135 active_profile = profile_get_profile ();
2136 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2137 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2138 mail_volume_int = profile_parse_int (mail_volume);
2140 if (mail_volume_int > 0) {
2142 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2143 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2147 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2148 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2149 ca_context_destroy(ca_con);
2153 ca_proplist_create(&pl);
2154 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2155 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2157 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2158 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2160 ca_proplist_destroy(pl);
2161 ca_context_destroy(ca_con);
2164 g_free (mail_volume);
2166 g_free (active_profile);
2170 on_move_to_dialog_folder_activated (GtkTreeView *tree_view,
2172 GtkTreeViewColumn *column,
2175 gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2179 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2180 GtkWidget **folder_view)
2182 GtkWidget *dialog, *folder_view_container;
2184 /* Create dialog. We cannot use a touch selector because we
2185 need to use here the folder view widget directly */
2186 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2187 GTK_WINDOW (parent_window),
2188 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2189 GTK_DIALOG_DESTROY_WITH_PARENT,
2190 _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2193 /* Create folder view */
2194 *folder_view = modest_platform_create_folder_view (NULL);
2196 /* Simulate the behaviour of a HildonPickerDialog by emitting
2197 a response when a folder is selected */
2198 g_signal_connect (*folder_view, "row-activated",
2199 G_CALLBACK (on_move_to_dialog_folder_activated),
2202 /* Create pannable and add it to the dialog */
2203 folder_view_container = hildon_pannable_area_new ();
2204 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2205 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2207 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2209 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2210 gtk_widget_show (folder_view_container);
2211 gtk_widget_show (*folder_view);
2217 modest_platform_get_list_to_move (ModestWindow *window)
2219 if (MODEST_IS_HEADER_WINDOW (window)) {
2220 ModestHeaderView *header_view;
2222 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2224 return modest_header_view_get_selected_headers (header_view);
2225 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2226 ModestFolderView *folder_view;
2227 TnyFolderStore *selected_folder;
2230 list = TNY_LIST (tny_simple_list_new ());
2231 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2232 selected_folder = modest_folder_view_get_selected (folder_view);
2233 if (selected_folder) {
2234 tny_list_prepend (list, G_OBJECT (selected_folder));
2235 g_object_unref (selected_folder);