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"
67 #ifdef MODEST_HAVE_MCE
68 #include <mce/dbus-names.h>
69 #endif /*MODEST_HAVE_MCE*/
71 #ifdef MODEST_HAVE_ABOOK
72 #include <libosso-abook/osso-abook.h>
73 #endif /*MODEST_HAVE_ABOOK*/
75 #ifdef MODEST_HAVE_LIBALARM
76 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
77 #endif /*MODEST_HAVE_LIBALARM*/
80 #define HILDON_OSSO_URI_ACTION "uri-action"
81 #define URI_ACTION_COPY "copy:"
82 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
83 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
84 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
86 static void _modest_platform_play_email_tone (void);
90 on_modest_conf_update_interval_changed (ModestConf* self,
92 ModestConfEvent event,
93 ModestConfNotificationId id,
96 g_return_if_fail (key);
98 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
99 const guint update_interval_minutes =
100 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
101 modest_platform_set_update_interval (update_interval_minutes);
108 check_required_files (void)
110 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
112 g_printerr ("modest: check for mcc file failed\n");
117 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
118 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
119 g_printerr ("modest: cannot find providers data\n");
127 /* the gpointer here is the osso_context. */
129 modest_platform_init (int argc, char *argv[])
131 osso_context_t *osso_context;
133 osso_hw_state_t hw_state = { 0 };
137 if (!check_required_files ()) {
138 g_printerr ("modest: missing required files\n");
142 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
145 g_printerr ("modest: failed to acquire osso context\n");
148 modest_maemo_utils_set_osso_context (osso_context);
150 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
151 g_printerr ("modest: could not get dbus connection\n");
155 /* Add a D-Bus handler to be used when the main osso-rpc
156 * D-Bus handler has not handled something.
157 * We use this for D-Bus methods that need to use more complex types
158 * than osso-rpc supports.
160 if (!dbus_connection_add_filter (con,
161 modest_dbus_req_filter,
165 g_printerr ("modest: Could not add D-Bus filter\n");
169 /* Register our simple D-Bus callbacks, via the osso API: */
170 osso_return_t result = osso_rpc_set_cb_f(osso_context,
174 modest_dbus_req_handler, NULL /* user_data */);
175 if (result != OSSO_OK) {
176 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
180 /* Register hardware event dbus callback: */
181 hw_state.shutdown_ind = TRUE;
182 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
184 /* Register osso auto-save callbacks: */
185 result = osso_application_set_autosave_cb (osso_context,
186 modest_on_osso_application_autosave, NULL /* user_data */);
187 if (result != OSSO_OK) {
188 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
193 /* Make sure that the update interval is changed whenever its gconf key
195 /* CAUTION: we're not using here the
196 modest_conf_listen_to_namespace because we know that there
197 are other parts of Modest listening for this namespace, so
198 we'll receive the notifications anyway. We basically do not
199 use it because there is no easy way to do the
200 modest_conf_forget_namespace */
201 ModestConf *conf = modest_runtime_get_conf ();
202 g_signal_connect (G_OBJECT(conf),
204 G_CALLBACK (on_modest_conf_update_interval_changed),
207 /* only force the setting of the default interval, if there are actually
209 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
211 /* Get the initial update interval from gconf: */
212 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
213 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
214 modest_account_mgr_free_account_names (acc_names);
218 #ifdef MODEST_HAVE_ABOOK
219 /* initialize the addressbook */
220 if (!osso_abook_init (&argc, &argv, osso_context)) {
221 g_printerr ("modest: failed to initialized addressbook\n");
224 #endif /*MODEST_HAVE_ABOOK*/
230 modest_platform_uninit (void)
232 osso_context_t *osso_context =
233 modest_maemo_utils_get_osso_context ();
235 osso_deinitialize (osso_context);
244 modest_platform_get_new_device (void)
246 return TNY_DEVICE (tny_maemo_conic_device_new ());
250 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
251 gchar **effective_mime_type)
253 GString *mime_str = NULL;
254 gchar *icon_name = NULL;
255 gchar **icons, **cursor;
257 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
258 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
260 mime_str = g_string_new (mime_type);
261 g_string_ascii_down (mime_str);
264 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
266 for (cursor = icons; cursor; ++cursor) {
267 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
268 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
269 icon_name = g_strdup ("qgn_list_messagin");
271 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
272 icon_name = g_strdup (*cursor);
278 if (effective_mime_type)
279 *effective_mime_type = g_string_free (mime_str, FALSE);
281 g_string_free (mime_str, TRUE);
288 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
293 g_return_val_if_fail (uri, FALSE);
295 result = hildon_uri_open (uri, action, &err);
297 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
298 uri, action, err && err->message ? err->message : "unknown error");
308 modest_platform_activate_uri (const gchar *uri)
310 HildonURIAction *action;
311 gboolean result = FALSE;
312 GSList *actions, *iter = NULL;
314 g_return_val_if_fail (uri, FALSE);
318 /* don't try to activate file: uri's -- they might confuse the user,
319 * and/or might have security implications */
320 if (!g_str_has_prefix (uri, "file:")) {
322 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
324 for (iter = actions; iter; iter = g_slist_next (iter)) {
325 action = (HildonURIAction*) iter->data;
326 if (action && strcmp (hildon_uri_action_get_service (action),
327 "com.nokia.modest") == 0) {
328 result = checked_hildon_uri_open (uri, action);
333 /* if we could not open it with email, try something else */
335 result = checked_hildon_uri_open (uri, NULL);
339 ModestWindow *parent =
340 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
341 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
342 _("mcen_ib_unsupported_link"));
343 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
350 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
354 gchar *uri_path = NULL;
356 uri_path = gnome_vfs_get_uri_from_local_path (path);
357 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
360 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
362 result = hildon_mime_open_file (con, uri_path);
364 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
372 } ModestPlatformPopupInfo;
375 delete_uri_popup (GtkWidget *menu,
379 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
381 g_free (popup_info->uri);
382 hildon_uri_free_actions (popup_info->actions);
388 activate_uri_popup_item (GtkMenuItem *menu_item,
392 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
393 const gchar* action_name;
395 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
397 g_printerr ("modest: no action name defined\n");
401 /* special handling for the copy menu item -- copy the uri to the clipboard */
402 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
403 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
404 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
405 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
407 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
408 action_name += strlen ("mailto:");
410 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
411 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
412 return; /* we're done */
415 /* now, the real uri-actions... */
416 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
417 HildonURIAction *action = (HildonURIAction *) node->data;
418 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
419 if (!checked_hildon_uri_open (popup_info->uri, action)) {
420 ModestWindow *parent =
421 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
422 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
423 _("mcen_ib_unsupported_link"));
431 modest_platform_show_uri_popup (const gchar *uri)
433 GSList *actions_list;
438 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
441 GtkWidget *menu = gtk_menu_new ();
442 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
444 /* don't add actions for file: uri's -- they might confuse the user,
445 * and/or might have security implications
446 * we still allow to copy the url though
448 if (!g_str_has_prefix (uri, "file:")) {
451 popup_info->actions = actions_list;
452 popup_info->uri = g_strdup (uri);
454 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
455 GtkWidget *menu_item;
456 const gchar *action_name;
457 const gchar *translation_domain;
458 HildonURIAction *action = (HildonURIAction *) node->data;
459 action_name = hildon_uri_action_get_name (action);
460 translation_domain = hildon_uri_action_get_translation_domain (action);
461 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
462 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
463 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
466 if (hildon_uri_is_default_action (action, NULL)) {
467 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
469 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
471 gtk_widget_show (menu_item);
475 /* always add the copy item */
476 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
477 "uri_link_copy_link_location"));
478 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
479 g_strconcat (URI_ACTION_COPY, uri, NULL),
481 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
482 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
483 gtk_widget_show (menu_item);
486 /* and what to do when the link is deleted */
487 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
488 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
491 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
499 modest_platform_get_icon (const gchar *name, guint icon_size)
502 GdkPixbuf* pixbuf = NULL;
503 GtkIconTheme *current_theme = NULL;
505 g_return_val_if_fail (name, NULL);
507 /* strlen == 0 is not really an error; it just
508 * means the icon is not available
510 if (!name || strlen(name) == 0)
513 current_theme = gtk_icon_theme_get_default ();
514 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
515 GTK_ICON_LOOKUP_NO_SVG,
518 g_printerr ("modest: error loading theme icon '%s': %s\n",
526 modest_platform_get_app_name (void)
528 return _("mcen_ap_name");
532 entry_insert_text (GtkEditable *editable,
541 chars = gtk_editable_get_chars (editable, 0, -1);
542 chars_length = g_utf8_strlen (chars, -1);
545 /* Show WID-INF036 */
546 if (chars_length >= 20) {
547 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
548 _CS("ckdg_ib_maximum_characters_reached"));
550 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
554 tmp = g_strndup (folder_name_forbidden_chars,
555 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
556 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
557 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
562 /* Write the text in the entry if it's valid */
563 g_signal_handlers_block_by_func (editable,
564 (gpointer) entry_insert_text, data);
565 gtk_editable_insert_text (editable, text, length, position);
566 g_signal_handlers_unblock_by_func (editable,
567 (gpointer) entry_insert_text, data);
570 /* Do not allow further processing */
571 g_signal_stop_emission_by_name (editable, "insert_text");
575 entry_changed (GtkEditable *editable,
579 GtkWidget *ok_button;
582 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
583 ok_button = GTK_WIDGET (buttons->data);
585 chars = gtk_editable_get_chars (editable, 0, -1);
586 g_return_if_fail (chars != NULL);
589 if (g_utf8_strlen (chars,-1) >= 20)
590 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
591 _CS("ckdg_ib_maximum_characters_reached"));
593 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
596 g_list_free (buttons);
603 on_response (GtkDialog *dialog,
607 GList *child_vbox, *child_hbox;
608 GtkWidget *hbox, *entry;
609 TnyFolderStore *parent;
610 const gchar *new_name;
613 if (response != GTK_RESPONSE_ACCEPT)
617 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
618 hbox = child_vbox->data;
619 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
620 entry = child_hbox->next->data;
622 parent = TNY_FOLDER_STORE (user_data);
623 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
626 /* Look for another folder with the same name */
627 if (modest_tny_folder_has_subfolder_with_name (parent,
634 if (TNY_IS_ACCOUNT (parent) &&
635 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
636 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
645 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
646 NULL, _CS("ckdg_ib_folder_already_exists"));
647 /* Select the text */
648 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
649 gtk_widget_grab_focus (entry);
650 /* Do not close the dialog */
651 g_signal_stop_emission_by_name (dialog, "response");
658 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
659 TnyFolderStore *parent,
660 const gchar *dialog_title,
661 const gchar *label_text,
662 const gchar *suggested_name,
665 GtkWidget *accept_btn = NULL;
666 GtkWidget *dialog, *entry, *label, *hbox;
667 GList *buttons = NULL;
670 /* Ask the user for the folder name */
671 dialog = gtk_dialog_new_with_buttons (dialog_title,
673 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
678 /* Add accept button (with unsensitive handler) */
679 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
680 accept_btn = GTK_WIDGET (buttons->data);
681 /* Create label and entry */
682 label = gtk_label_new (label_text);
684 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
685 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
688 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
690 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
691 gtk_entry_set_width_chars (GTK_ENTRY (entry),
692 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
693 g_utf8_strlen (_("mcen_ia_default_folder_name"), -1)));
694 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
696 /* Connect to the response method to avoid closing the dialog
697 when an invalid name is selected*/
698 g_signal_connect (dialog,
700 G_CALLBACK (on_response),
703 /* Track entry changes */
704 g_signal_connect (entry,
706 G_CALLBACK (entry_insert_text),
708 g_signal_connect (entry,
710 G_CALLBACK (entry_changed),
714 /* Some locales like pt_BR need this to get the full window
716 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
718 /* Create the hbox */
719 hbox = gtk_hbox_new (FALSE, 12);
720 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
721 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
723 /* Add hbox to dialog */
724 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
725 hbox, FALSE, FALSE, 0);
726 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
727 GTK_WINDOW (dialog), parent_window);
728 gtk_widget_show_all (GTK_WIDGET(dialog));
730 result = gtk_dialog_run (GTK_DIALOG(dialog));
731 if (result == GTK_RESPONSE_ACCEPT)
732 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
734 gtk_widget_destroy (dialog);
736 while (gtk_events_pending ())
737 gtk_main_iteration ();
743 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
744 TnyFolderStore *parent_folder,
745 gchar *suggested_name,
748 gchar *real_suggested_name = NULL, *tmp = NULL;
751 if(suggested_name == NULL)
753 const gchar *default_name = _("mcen_ia_default_folder_name");
757 for(i = 0; i < 100; ++ i) {
758 gboolean exists = FALSE;
760 sprintf(num_str, "%.2u", i);
763 real_suggested_name = g_strdup (default_name);
765 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
767 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
774 g_free (real_suggested_name);
777 /* Didn't find a free number */
779 real_suggested_name = g_strdup (default_name);
781 real_suggested_name = suggested_name;
784 tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
785 result = modest_platform_run_folder_name_dialog (parent_window,
787 _("mcen_ti_new_folder"),
793 if (suggested_name == NULL)
794 g_free(real_suggested_name);
800 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
801 TnyFolderStore *parent_folder,
802 const gchar *suggested_name,
805 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
807 return modest_platform_run_folder_name_dialog (parent_window,
809 _HL("ckdg_ti_rename_folder"),
810 _HL("ckdg_fi_rename_name"),
818 on_destroy_dialog (GtkWidget *dialog)
820 /* This could happen when the dialogs get programatically
821 hidden or destroyed (for example when closing the
822 application while a dialog is being shown) */
823 if (!GTK_IS_WIDGET (dialog))
826 gtk_widget_destroy (dialog);
828 if (gtk_events_pending ())
829 gtk_main_iteration ();
833 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
834 const gchar *message)
839 dialog = hildon_note_new_confirmation (parent_window, message);
840 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
841 GTK_WINDOW (dialog), parent_window);
843 response = gtk_dialog_run (GTK_DIALOG (dialog));
845 on_destroy_dialog (dialog);
851 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
852 const gchar *message,
853 const gchar *button_accept,
854 const gchar *button_cancel)
859 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
860 button_accept, GTK_RESPONSE_ACCEPT,
861 button_cancel, GTK_RESPONSE_CANCEL,
864 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
865 GTK_WINDOW (dialog), parent_window);
867 response = gtk_dialog_run (GTK_DIALOG (dialog));
869 on_destroy_dialog (dialog);
875 modest_platform_run_information_dialog (GtkWindow *parent_window,
876 const gchar *message,
881 note = hildon_note_new_information (parent_window, message);
883 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
884 GTK_WINDOW (note), parent_window);
887 gtk_dialog_run (GTK_DIALOG (note));
889 on_destroy_dialog (note);
891 g_signal_connect_swapped (note,
893 G_CALLBACK (on_destroy_dialog),
896 gtk_widget_show_all (note);
900 typedef struct _ConnectAndWaitData {
902 GMainLoop *wait_loop;
903 gboolean has_callback;
905 } ConnectAndWaitData;
909 quit_wait_loop (TnyAccount *account,
910 ConnectAndWaitData *data)
912 /* Set the has_callback to TRUE (means that the callback was
913 executed and wake up every code waiting for cond to be
915 g_mutex_lock (data->mutex);
916 data->has_callback = TRUE;
918 g_main_loop_quit (data->wait_loop);
919 g_mutex_unlock (data->mutex);
923 on_connection_status_changed (TnyAccount *account,
924 TnyConnectionStatus status,
927 TnyConnectionStatus conn_status;
928 ConnectAndWaitData *data;
930 /* Ignore if reconnecting or disconnected */
931 conn_status = tny_account_get_connection_status (account);
932 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
933 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
936 /* Remove the handler */
937 data = (ConnectAndWaitData *) user_data;
938 g_signal_handler_disconnect (account, data->handler);
940 /* Quit from wait loop */
941 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
945 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
950 /* Quit from wait loop */
951 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
955 modest_platform_connect_and_wait (GtkWindow *parent_window,
958 ConnectAndWaitData *data = NULL;
959 gboolean device_online;
961 TnyConnectionStatus conn_status;
962 gboolean user_requested;
964 device = modest_runtime_get_device();
965 device_online = tny_device_is_online (device);
967 /* Whether the connection is user requested or automatically
968 requested, for example via D-Bus */
969 user_requested = (parent_window) ? TRUE : FALSE;
971 /* If there is no account check only the device status */
976 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
977 NULL, user_requested);
980 /* Return if the account is already connected */
981 conn_status = tny_account_get_connection_status (account);
982 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
985 /* Create the helper */
986 data = g_slice_new0 (ConnectAndWaitData);
987 data->mutex = g_mutex_new ();
988 data->has_callback = FALSE;
990 /* Connect the device */
991 if (!device_online) {
992 /* Track account connection status changes */
993 data->handler = g_signal_connect (account, "connection-status-changed",
994 G_CALLBACK (on_connection_status_changed),
996 /* Try to connect the device */
997 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
998 NULL, user_requested);
1000 /* If the device connection failed then exit */
1001 if (!device_online && data->handler)
1004 /* Force a reconnection of the account */
1005 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1006 on_tny_camel_account_set_online_cb, data);
1009 /* Wait until the callback is executed */
1010 g_mutex_lock (data->mutex);
1011 if (!data->has_callback) {
1012 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1013 gdk_threads_leave ();
1014 g_mutex_unlock (data->mutex);
1015 g_main_loop_run (data->wait_loop);
1016 g_mutex_lock (data->mutex);
1017 gdk_threads_enter ();
1019 g_mutex_unlock (data->mutex);
1023 if (g_signal_handler_is_connected (account, data->handler))
1024 g_signal_handler_disconnect (account, data->handler);
1025 g_mutex_free (data->mutex);
1026 g_main_loop_unref (data->wait_loop);
1027 g_slice_free (ConnectAndWaitData, data);
1030 conn_status = tny_account_get_connection_status (account);
1031 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1035 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1037 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1038 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1039 /* This must be a maildir account, which does not require a connection: */
1044 return modest_platform_connect_and_wait (parent_window, account);
1048 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1051 return TRUE; /* Maybe it is something local. */
1053 gboolean result = TRUE;
1054 if (TNY_IS_FOLDER (folder_store)) {
1055 /* Get the folder's parent account: */
1056 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1057 if (account != NULL) {
1058 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1059 g_object_unref (account);
1061 } else if (TNY_IS_ACCOUNT (folder_store)) {
1062 /* Use the folder store as an account: */
1063 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1070 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1074 dialog = modest_hildon2_sort_dialog_new (parent_window);
1081 modest_platform_set_update_interval (guint minutes)
1083 #ifdef MODEST_HAVE_LIBALARM
1085 ModestConf *conf = modest_runtime_get_conf ();
1089 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1091 /* Delete any existing alarm,
1092 * because we will replace it: */
1094 if (alarmd_event_del(alarm_cookie) != 1)
1095 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1097 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1100 /* 0 means no updates: */
1105 /* Register alarm: */
1107 /* Set the interval in alarm_event_t structure: */
1108 alarm_event_t *event = alarm_event_create ();
1109 alarm_event_add_actions (event, 1);
1110 alarm_action_t *action = alarm_event_get_action (event, 0);
1111 event->alarm_time = minutes * 60; /* seconds */
1113 /* Set recurrence every few minutes: */
1114 event->recur_secs = minutes*60;
1115 event->recur_count = -1; /* Means infinite */
1117 /* Specify what should happen when the alarm happens:
1118 * It should call this D-Bus method: */
1120 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1121 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1122 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1123 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1124 action->flags = ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1126 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1127 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1128 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1129 * This is why we want to use the Alarm API instead of just g_timeout_add().
1130 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1131 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1133 event->flags = ALARM_EVENT_CONNECTED;
1135 alarm_cookie = alarmd_event_add (event);
1138 alarm_event_delete (event);
1140 /* Store the alarm ID in GConf, so we can remove it later:
1141 * This is apparently valid between application instances. */
1142 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1144 if (!alarm_cookie) {
1146 g_debug ("Error setting alarm event. \n");
1150 #endif /* MODEST_HAVE_LIBALARM */
1155 modest_platform_push_email_notification(void)
1157 gboolean screen_on = TRUE, app_in_foreground;
1159 /* Get the window status */
1160 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1162 /* If the screen is on and the app is in the
1163 foreground we don't show anything */
1164 if (!(screen_on && app_in_foreground)) {
1166 _modest_platform_play_email_tone ();
1168 /* Activate LED. This must be deactivated by
1169 modest_platform_remove_new_mail_notifications */
1170 #ifdef MODEST_HAVE_MCE
1171 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1175 MCE_ACTIVATE_LED_PATTERN,
1177 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1184 modest_platform_on_new_headers_received (TnyList *header_list,
1185 gboolean show_visual)
1187 g_return_if_fail (TNY_IS_LIST(header_list));
1189 if (tny_list_get_length(header_list) == 0) {
1190 g_warning ("%s: header list is empty", __FUNCTION__);
1195 modest_platform_push_email_notification ();
1196 /* We do a return here to avoid indentation with an else */
1200 #ifdef MODEST_HAVE_HILDON_NOTIFY
1201 HildonNotification *notification;
1203 GSList *notifications_list = NULL;
1205 /* Get previous notifications ids */
1206 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1207 MODEST_CONF_NOTIFICATION_IDS,
1208 MODEST_CONF_VALUE_INT, NULL);
1210 iter = tny_list_create_iterator (header_list);
1211 while (!tny_iterator_is_done (iter)) {
1212 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1213 const gchar *display_date;
1214 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1215 TnyFolder *folder = tny_header_get_folder (header);
1216 gboolean first_notification = TRUE;
1219 ModestDatetimeFormatter *datetime_formatter;
1221 /* constant string, don't free */
1222 datetime_formatter = modest_datetime_formatter_new ();
1223 display_date = modest_datetime_formatter_display_datetime (datetime_formatter,
1224 tny_header_get_date_received (header));
1225 g_object_unref (datetime_formatter);
1227 display_address = tny_header_dup_from (header);
1228 /* string is changed in-place */
1229 modest_text_utils_get_display_address (display_address);
1231 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1232 str = tny_header_dup_subject (header);
1233 notification = hildon_notification_new (summary,
1235 "qgn_list_messagin",
1238 /* Create the message URL */
1239 str = tny_header_dup_uid (header);
1240 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1244 hildon_notification_add_dbus_action(notification,
1247 MODEST_DBUS_SERVICE,
1250 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1254 /* Play sound if the user wants. Show the LED
1255 pattern. Show and play just one */
1256 if (G_UNLIKELY (first_notification)) {
1257 gchar *active_profile;
1260 gint mail_volume_int;
1262 first_notification = FALSE;
1264 active_profile = profile_get_profile ();
1265 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1266 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1267 mail_volume_int = profile_parse_int (mail_volume);
1269 if (mail_volume_int > 0)
1270 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1271 "sound-file", mail_tone);
1273 g_free (mail_volume);
1275 g_free (active_profile);
1277 /* Set the led pattern */
1278 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1280 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1282 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1285 /* Notify. We need to do this in an idle because this function
1286 could be called from a thread */
1287 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1289 /* Save id in the list */
1290 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1291 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1292 /* We don't listen for the "closed" signal, because we
1293 don't care about if the notification was removed or
1294 not to store the list in gconf */
1296 /* Free & carry on */
1297 g_free (display_address);
1300 g_object_unref (folder);
1301 g_object_unref (header);
1302 tny_iterator_next (iter);
1304 g_object_unref (iter);
1307 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1308 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1310 g_slist_free (notifications_list);
1312 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1316 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1319 #ifdef MODEST_HAVE_MCE
1320 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1324 MCE_DEACTIVATE_LED_PATTERN,
1326 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1332 #ifdef MODEST_HAVE_HILDON_NOTIFY
1333 GSList *notif_list = NULL;
1335 /* Get previous notifications ids */
1336 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1337 MODEST_CONF_NOTIFICATION_IDS,
1338 MODEST_CONF_VALUE_INT, NULL);
1340 while (notif_list) {
1342 NotifyNotification *notif;
1344 /* Nasty HACK to remove the notifications, set the id
1345 of the existing ones and then close them */
1346 notif_id = GPOINTER_TO_INT(notif_list->data);
1347 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1348 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1350 /* Close the notification, note that some ids could be
1351 already invalid, but we don't care because it does
1353 notify_notification_close(notif, NULL);
1354 g_object_unref(notif);
1356 /* Delete the link, it's like going to the next */
1357 notif_list = g_slist_delete_link (notif_list, notif_list);
1361 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1362 notif_list, MODEST_CONF_VALUE_INT, NULL);
1364 g_slist_free (notif_list);
1366 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1372 modest_platform_get_global_settings_dialog ()
1374 return modest_hildon2_global_settings_dialog_new ();
1378 modest_platform_show_help (GtkWindow *parent_window,
1379 const gchar *help_id)
1385 modest_platform_show_search_messages (GtkWindow *parent_window)
1387 osso_return_t result = OSSO_ERROR;
1389 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1390 "osso_global_search",
1391 "search_email", NULL, DBUS_TYPE_INVALID);
1393 if (result != OSSO_OK) {
1394 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1399 modest_platform_show_addressbook (GtkWindow *parent_window)
1401 osso_return_t result = OSSO_ERROR;
1403 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1405 "top_application", NULL, DBUS_TYPE_INVALID);
1407 if (result != OSSO_OK) {
1408 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1413 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1415 GtkWidget *widget = modest_folder_view_new (query);
1417 /* Show one account by default */
1418 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1419 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1421 /* Restore settings */
1422 modest_widget_memory_restore (modest_runtime_get_conf(),
1424 MODEST_CONF_FOLDER_VIEW_KEY);
1430 banner_finish (gpointer data, GObject *object)
1432 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1433 modest_window_mgr_unregister_banner (mgr);
1434 g_object_unref (mgr);
1438 modest_platform_information_banner (GtkWidget *parent,
1439 const gchar *icon_name,
1442 GtkWidget *banner, *banner_parent = NULL;
1443 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1445 if (modest_window_mgr_get_num_windows (mgr) == 0)
1448 if (parent && GTK_IS_WINDOW (parent)) {
1449 /* If the window is the active one then show the
1450 banner on top of this window */
1451 if (gtk_window_is_active (GTK_WINDOW (parent)))
1452 banner_parent = parent;
1453 /* If the window is not the topmost but it's visible
1454 (it's minimized for example) then show the banner
1456 else if (GTK_WIDGET_VISIBLE (parent))
1457 banner_parent = NULL;
1458 /* If the window is hidden (like the main window when
1459 running in the background) then do not show
1466 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1468 modest_window_mgr_register_banner (mgr);
1470 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1474 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1475 const gchar *icon_name,
1481 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1484 banner = hildon_banner_show_information (parent, icon_name, text);
1485 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1489 modest_platform_animation_banner (GtkWidget *parent,
1490 const gchar *animation_name,
1493 GtkWidget *inf_note = NULL;
1495 g_return_val_if_fail (text != NULL, NULL);
1497 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1500 /* If the parent is not visible then do not show */
1501 if (parent && !GTK_WIDGET_VISIBLE (parent))
1504 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1512 TnyAccount *account;
1515 } CheckAccountIdleData;
1517 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1520 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1522 gboolean stop_trying = FALSE;
1523 g_return_val_if_fail (data && data->account, FALSE);
1525 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1526 tny_account_get_connection_status (data->account));
1528 if (data && data->account &&
1529 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1530 * after which the account is likely to be usable, or never likely to be usable soon: */
1531 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1533 data->is_online = TRUE;
1537 /* Give up if we have tried too many times: */
1538 if (data->count_tries >= NUMBER_OF_TRIES) {
1541 /* Wait for another timeout: */
1542 ++(data->count_tries);
1547 /* Allow the function that requested this idle callback to continue: */
1549 g_main_loop_quit (data->loop);
1552 g_object_unref (data->account);
1554 return FALSE; /* Don't call this again. */
1556 return TRUE; /* Call this timeout callback again. */
1560 /* Return TRUE immediately if the account is already online,
1561 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1562 * soon as the account is online, or FALSE if the account does
1563 * not become online in the NUMBER_OF_TRIES seconds.
1564 * This is useful when the D-Bus method was run immediately after
1565 * the application was started (when using D-Bus activation),
1566 * because the account usually takes a short time to go online.
1567 * The return value is maybe not very useful.
1570 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1574 g_return_val_if_fail (account, FALSE);
1576 if (!tny_device_is_online (modest_runtime_get_device())) {
1577 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1581 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1582 * so we avoid wait unnecessarily: */
1583 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1586 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1587 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1588 * we want to avoid. */
1589 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1592 /* This blocks on the result: */
1593 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1594 data->is_online = FALSE;
1595 data->account = account;
1596 g_object_ref (data->account);
1597 data->count_tries = 0;
1599 GMainContext *context = NULL; /* g_main_context_new (); */
1600 data->loop = g_main_loop_new (context, FALSE /* not running */);
1602 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1604 /* This main loop will run until the idle handler has stopped it: */
1605 g_main_loop_run (data->loop);
1607 g_main_loop_unref (data->loop);
1608 /* g_main_context_unref (context); */
1610 is_online = data->is_online;
1611 g_slice_free (CheckAccountIdleData, data);
1619 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1621 /* GTK_RESPONSE_HELP means we need to show the certificate */
1622 if (response_id == GTK_RESPONSE_APPLY) {
1626 /* Do not close the dialog */
1627 g_signal_stop_emission_by_name (dialog, "response");
1629 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1630 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1631 gtk_dialog_run (GTK_DIALOG(note));
1632 gtk_widget_destroy (note);
1638 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1639 const gchar *certificate)
1644 HildonWindowStack *stack;
1646 stack = hildon_window_stack_get_default ();
1647 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1650 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1655 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1658 /* We use GTK_RESPONSE_APPLY because we want the button in the
1659 middle of OK and CANCEL the same as the browser does for
1660 example. With GTK_RESPONSE_HELP the view button is aligned
1661 to the left while the other two to the right */
1662 note = hildon_note_new_confirmation_add_buttons (
1665 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1666 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1667 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1670 g_signal_connect (G_OBJECT(note), "response",
1671 G_CALLBACK(on_cert_dialog_response),
1672 (gpointer) certificate);
1674 response = gtk_dialog_run(GTK_DIALOG(note));
1676 on_destroy_dialog (note);
1679 return response == GTK_RESPONSE_OK;
1683 modest_platform_run_alert_dialog (const gchar* prompt,
1684 gboolean is_question)
1686 ModestWindow *main_win;
1688 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1689 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1690 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1691 return is_question ? FALSE : TRUE;
1694 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1695 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1697 gboolean retval = TRUE;
1699 /* The Tinymail documentation says that we should show Yes and No buttons,
1700 * when it is a question.
1701 * Obviously, we need tinymail to use more specific error codes instead,
1702 * so we know what buttons to show. */
1703 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1705 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1706 GTK_WINDOW (dialog), GTK_WINDOW (main_win));
1708 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1709 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1711 on_destroy_dialog (dialog);
1713 /* Just show the error text and use the default response: */
1714 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1722 GtkWindow *parent_window;
1723 ModestConnectedPerformer callback;
1724 TnyAccount *account;
1731 on_went_online_info_free (OnWentOnlineInfo *info)
1733 /* And if we cleanup, we DO cleanup :-) */
1736 g_object_unref (info->device);
1739 if (info->parent_window)
1740 g_object_unref (info->parent_window);
1742 g_object_unref (info->account);
1744 g_slice_free (OnWentOnlineInfo, info);
1746 /* We're done ... */
1752 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1754 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1756 /* Now it's really time to callback to the caller. If going online didn't succeed,
1757 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1758 * canceled will be set. Etcetera etcetera. */
1760 if (info->callback) {
1761 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1764 /* This is our last call, we must cleanup here if we didn't yet do that */
1765 on_went_online_info_free (info);
1772 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1774 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1775 info->iap = g_strdup (iap_id);
1777 if (canceled || err || !info->account) {
1779 /* If there's a problem or if there's no account (then that's it for us, we callback
1780 * the caller's callback now. He'll have to handle err or canceled, of course.
1781 * We are not really online, as the account is not really online here ... */
1783 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1784 * this info. We don't cleanup err, Tinymail does that! */
1786 if (info->callback) {
1788 /* info->account can be NULL here, this means that the user did not
1789 * provide a nice account instance. We'll assume that the user knows
1790 * what he's doing and is happy with just the device going online.
1792 * We can't do magic, we don't know what account the user wants to
1793 * see going online. So just the device goes online, end of story */
1795 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1798 } else if (info->account) {
1800 /* If there's no problem and if we have an account, we'll put the account
1801 * online too. When done, the callback of bringing the account online
1802 * will callback the caller's callback. This is the most normal case. */
1804 info->device = TNY_DEVICE (g_object_ref (device));
1806 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1807 on_account_went_online, info);
1809 /* The on_account_went_online cb frees up the info, go look if you
1810 * don't believe me! (so we return here) */
1815 /* We cleanup if we are not bringing the account online too */
1816 on_went_online_info_free (info);
1822 modest_platform_connect_and_perform (GtkWindow *parent_window,
1824 TnyAccount *account,
1825 ModestConnectedPerformer callback,
1828 gboolean device_online;
1830 TnyConnectionStatus conn_status;
1831 OnWentOnlineInfo *info;
1833 device = modest_runtime_get_device();
1834 device_online = tny_device_is_online (device);
1836 /* If there is no account check only the device status */
1839 if (device_online) {
1841 /* We promise to instantly perform the callback, so ... */
1843 callback (FALSE, NULL, parent_window, account, user_data);
1848 info = g_slice_new0 (OnWentOnlineInfo);
1851 info->device = NULL;
1852 info->account = NULL;
1855 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1857 info->parent_window = NULL;
1858 info->user_data = user_data;
1859 info->callback = callback;
1861 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1862 force, on_conic_device_went_online,
1865 /* We'll cleanup in on_conic_device_went_online */
1868 /* The other code has no more reason to run. This is all that we can do for the
1869 * caller (he should have given us a nice and clean account instance!). We
1870 * can't do magic, we don't know what account he intends to bring online. So
1871 * we'll just bring the device online (and await his false bug report). */
1877 /* Return if the account is already connected */
1879 conn_status = tny_account_get_connection_status (account);
1880 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1882 /* We promise to instantly perform the callback, so ... */
1884 callback (FALSE, NULL, parent_window, account, user_data);
1890 /* Else, we are in a state that requires that we go online before we
1891 * call the caller's callback. */
1893 info = g_slice_new0 (OnWentOnlineInfo);
1895 info->device = NULL;
1897 info->account = TNY_ACCOUNT (g_object_ref (account));
1900 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1902 info->parent_window = NULL;
1904 /* So we'll put the callback away for later ... */
1906 info->user_data = user_data;
1907 info->callback = callback;
1909 if (!device_online) {
1911 /* If also the device is offline, then we connect both the device
1912 * and the account */
1914 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1915 force, on_conic_device_went_online,
1920 /* If the device is online, we'll just connect the account */
1922 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1923 on_account_went_online, info);
1926 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1927 * in both situations, go look if you don't believe me! */
1933 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1935 TnyFolderStore *folder_store,
1936 ModestConnectedPerformer callback,
1939 TnyAccount *account = NULL;
1941 if (!folder_store) {
1942 /* We promise to instantly perform the callback, so ... */
1944 callback (FALSE, NULL, parent_window, NULL, user_data);
1948 } else if (TNY_IS_FOLDER (folder_store)) {
1949 /* Get the folder's parent account: */
1950 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1951 } else if (TNY_IS_ACCOUNT (folder_store)) {
1952 /* Use the folder store as an account: */
1953 account = TNY_ACCOUNT (g_object_ref (folder_store));
1956 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1957 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1958 /* No need to connect a local account */
1960 callback (FALSE, NULL, parent_window, account, user_data);
1965 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1969 g_object_unref (account);
1973 src_account_connect_performer (gboolean canceled,
1975 GtkWindow *parent_window,
1976 TnyAccount *src_account,
1979 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1981 if (canceled || err) {
1982 /* If there was any error call the user callback */
1983 info->callback (canceled, err, parent_window, src_account, info->data);
1985 /* Connect the destination account */
1986 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1987 TNY_FOLDER_STORE (info->dst_account),
1988 info->callback, info->data);
1991 /* Free the info object */
1992 g_object_unref (info->dst_account);
1993 g_slice_free (DoubleConnectionInfo, info);
1998 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2000 TnyFolderStore *folder_store,
2001 DoubleConnectionInfo *connect_info)
2003 modest_platform_connect_if_remote_and_perform(parent_window,
2006 src_account_connect_performer,
2011 modest_platform_get_account_settings_wizard (void)
2013 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2015 return GTK_WIDGET (dialog);
2019 modest_platform_get_current_connection (void)
2021 TnyDevice *device = NULL;
2022 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2024 device = modest_runtime_get_device ();
2026 if (!tny_device_is_online (device))
2027 return MODEST_CONNECTED_VIA_ANY;
2029 #ifdef MODEST_HAVE_CONIC
2031 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2033 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2034 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2035 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2037 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2038 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2039 !strcmp (bearer_type, "WIMAX")) {
2040 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2042 retval = MODEST_CONNECTED_VIA_ANY;
2045 g_object_unref (iap);
2048 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2049 #endif /* MODEST_HAVE_CONIC */
2056 modest_platform_check_memory_low (ModestWindow *win,
2061 /* are we in low memory state? */
2062 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2064 if (win && lowmem && visuals)
2065 modest_platform_run_information_dialog (
2067 dgettext("ke-recv","memr_ib_operation_disabled"),
2071 g_debug ("%s: low memory reached. disallowing some operations",
2078 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2084 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2087 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2088 GTK_WINDOW (dialog),
2090 gtk_widget_show_all (dialog);
2092 g_signal_connect_swapped (dialog, "response",
2093 G_CALLBACK (gtk_widget_destroy),
2098 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2104 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2107 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2108 GTK_WINDOW (dialog),
2110 gtk_widget_show_all (dialog);
2112 g_signal_connect_swapped (dialog, "response",
2113 G_CALLBACK (gtk_widget_destroy),
2118 modest_platform_get_osso_context (void)
2120 return modest_maemo_utils_get_osso_context ();
2124 _modest_platform_play_email_tone (void)
2126 gchar *active_profile;
2129 gint mail_volume_int;
2131 ca_context *ca_con = NULL;
2132 ca_proplist *pl = NULL;
2134 active_profile = profile_get_profile ();
2135 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2136 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2137 mail_volume_int = profile_parse_int (mail_volume);
2139 if (mail_volume_int > 0) {
2141 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2142 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2146 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2147 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2148 ca_context_destroy(ca_con);
2152 ca_proplist_create(&pl);
2153 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2154 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2156 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2157 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2159 ca_proplist_destroy(pl);
2160 ca_context_destroy(ca_con);
2163 g_free (mail_volume);
2165 g_free (active_profile);
2169 on_move_to_dialog_folder_activated (GtkTreeView *tree_view,
2171 GtkTreeViewColumn *column,
2174 gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2178 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2179 GtkWidget **folder_view)
2181 GtkWidget *dialog, *folder_view_container;
2183 /* Create dialog. We cannot use a touch selector because we
2184 need to use here the folder view widget directly */
2185 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2186 GTK_WINDOW (parent_window),
2187 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2188 GTK_DIALOG_DESTROY_WITH_PARENT,
2189 _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2192 /* Create folder view */
2193 *folder_view = modest_platform_create_folder_view (NULL);
2195 /* Simulate the behaviour of a HildonPickerDialog by emitting
2196 a response when a folder is selected */
2197 g_signal_connect (*folder_view, "row-activated",
2198 G_CALLBACK (on_move_to_dialog_folder_activated),
2201 /* Create pannable and add it to the dialog */
2202 folder_view_container = hildon_pannable_area_new ();
2203 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2204 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2206 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2208 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2209 gtk_widget_show (folder_view_container);
2210 gtk_widget_show (*folder_view);
2216 modest_platform_get_list_to_move (ModestWindow *window)
2218 ModestHeaderView *header_view;
2220 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2222 return modest_header_view_get_selected_headers (header_view);