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 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1230 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1231 str = tny_header_dup_subject (header);
1232 notification = hildon_notification_new (summary,
1234 "qgn_list_messagin",
1237 /* Create the message URL */
1238 str = tny_header_dup_uid (header);
1239 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1243 hildon_notification_add_dbus_action(notification,
1246 MODEST_DBUS_SERVICE,
1249 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1253 /* Play sound if the user wants. Show the LED
1254 pattern. Show and play just one */
1255 if (G_UNLIKELY (first_notification)) {
1256 gchar *active_profile;
1259 gint mail_volume_int;
1261 first_notification = FALSE;
1263 active_profile = profile_get_profile ();
1264 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1265 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1266 mail_volume_int = profile_parse_int (mail_volume);
1268 if (mail_volume_int > 0)
1269 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1270 "sound-file", mail_tone);
1272 g_free (mail_volume);
1274 g_free (active_profile);
1276 /* Set the led pattern */
1277 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1279 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1281 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1284 /* Notify. We need to do this in an idle because this function
1285 could be called from a thread */
1286 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1288 /* Save id in the list */
1289 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1290 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1291 /* We don't listen for the "closed" signal, because we
1292 don't care about if the notification was removed or
1293 not to store the list in gconf */
1295 /* Free & carry on */
1296 g_free (display_address);
1299 g_object_unref (folder);
1300 g_object_unref (header);
1301 tny_iterator_next (iter);
1303 g_object_unref (iter);
1306 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1307 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1309 g_slist_free (notifications_list);
1311 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1315 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1318 #ifdef MODEST_HAVE_MCE
1319 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1323 MCE_DEACTIVATE_LED_PATTERN,
1325 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1331 #ifdef MODEST_HAVE_HILDON_NOTIFY
1332 GSList *notif_list = NULL;
1334 /* Get previous notifications ids */
1335 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1336 MODEST_CONF_NOTIFICATION_IDS,
1337 MODEST_CONF_VALUE_INT, NULL);
1339 while (notif_list) {
1341 NotifyNotification *notif;
1343 /* Nasty HACK to remove the notifications, set the id
1344 of the existing ones and then close them */
1345 notif_id = GPOINTER_TO_INT(notif_list->data);
1346 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1347 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1349 /* Close the notification, note that some ids could be
1350 already invalid, but we don't care because it does
1352 notify_notification_close(notif, NULL);
1353 g_object_unref(notif);
1355 /* Delete the link, it's like going to the next */
1356 notif_list = g_slist_delete_link (notif_list, notif_list);
1360 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1361 notif_list, MODEST_CONF_VALUE_INT, NULL);
1363 g_slist_free (notif_list);
1365 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1371 modest_platform_get_global_settings_dialog ()
1373 return modest_hildon2_global_settings_dialog_new ();
1377 modest_platform_show_help (GtkWindow *parent_window,
1378 const gchar *help_id)
1384 modest_platform_show_search_messages (GtkWindow *parent_window)
1386 osso_return_t result = OSSO_ERROR;
1388 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1389 "osso_global_search",
1390 "search_email", NULL, DBUS_TYPE_INVALID);
1392 if (result != OSSO_OK) {
1393 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1398 modest_platform_show_addressbook (GtkWindow *parent_window)
1400 osso_return_t result = OSSO_ERROR;
1402 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1404 "top_application", NULL, DBUS_TYPE_INVALID);
1406 if (result != OSSO_OK) {
1407 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1412 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1414 GtkWidget *widget = modest_folder_view_new (query);
1416 /* Show one account by default */
1417 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1418 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1420 /* Restore settings */
1421 modest_widget_memory_restore (modest_runtime_get_conf(),
1423 MODEST_CONF_FOLDER_VIEW_KEY);
1429 banner_finish (gpointer data, GObject *object)
1431 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1432 modest_window_mgr_unregister_banner (mgr);
1433 g_object_unref (mgr);
1437 modest_platform_information_banner (GtkWidget *parent,
1438 const gchar *icon_name,
1441 GtkWidget *banner, *banner_parent = NULL;
1442 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1444 if (modest_window_mgr_get_num_windows (mgr) == 0)
1447 if (parent && GTK_IS_WINDOW (parent)) {
1448 /* If the window is the active one then show the
1449 banner on top of this window */
1450 if (gtk_window_is_active (GTK_WINDOW (parent)))
1451 banner_parent = parent;
1452 /* If the window is not the topmost but it's visible
1453 (it's minimized for example) then show the banner
1455 else if (GTK_WIDGET_VISIBLE (parent))
1456 banner_parent = NULL;
1457 /* If the window is hidden (like the main window when
1458 running in the background) then do not show
1465 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1467 modest_window_mgr_register_banner (mgr);
1469 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1473 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1474 const gchar *icon_name,
1480 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1483 banner = hildon_banner_show_information (parent, icon_name, text);
1484 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1488 modest_platform_animation_banner (GtkWidget *parent,
1489 const gchar *animation_name,
1492 GtkWidget *inf_note = NULL;
1494 g_return_val_if_fail (text != NULL, NULL);
1496 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1499 /* If the parent is not visible then do not show */
1500 if (parent && !GTK_WIDGET_VISIBLE (parent))
1503 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1511 TnyAccount *account;
1514 } CheckAccountIdleData;
1516 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1519 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1521 gboolean stop_trying = FALSE;
1522 g_return_val_if_fail (data && data->account, FALSE);
1524 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1525 tny_account_get_connection_status (data->account));
1527 if (data && data->account &&
1528 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1529 * after which the account is likely to be usable, or never likely to be usable soon: */
1530 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1532 data->is_online = TRUE;
1536 /* Give up if we have tried too many times: */
1537 if (data->count_tries >= NUMBER_OF_TRIES) {
1540 /* Wait for another timeout: */
1541 ++(data->count_tries);
1546 /* Allow the function that requested this idle callback to continue: */
1548 g_main_loop_quit (data->loop);
1551 g_object_unref (data->account);
1553 return FALSE; /* Don't call this again. */
1555 return TRUE; /* Call this timeout callback again. */
1559 /* Return TRUE immediately if the account is already online,
1560 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1561 * soon as the account is online, or FALSE if the account does
1562 * not become online in the NUMBER_OF_TRIES seconds.
1563 * This is useful when the D-Bus method was run immediately after
1564 * the application was started (when using D-Bus activation),
1565 * because the account usually takes a short time to go online.
1566 * The return value is maybe not very useful.
1569 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1573 g_return_val_if_fail (account, FALSE);
1575 if (!tny_device_is_online (modest_runtime_get_device())) {
1576 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1580 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1581 * so we avoid wait unnecessarily: */
1582 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1585 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1586 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1587 * we want to avoid. */
1588 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1591 /* This blocks on the result: */
1592 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1593 data->is_online = FALSE;
1594 data->account = account;
1595 g_object_ref (data->account);
1596 data->count_tries = 0;
1598 GMainContext *context = NULL; /* g_main_context_new (); */
1599 data->loop = g_main_loop_new (context, FALSE /* not running */);
1601 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1603 /* This main loop will run until the idle handler has stopped it: */
1604 g_main_loop_run (data->loop);
1606 g_main_loop_unref (data->loop);
1607 /* g_main_context_unref (context); */
1609 is_online = data->is_online;
1610 g_slice_free (CheckAccountIdleData, data);
1618 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1620 /* GTK_RESPONSE_HELP means we need to show the certificate */
1621 if (response_id == GTK_RESPONSE_APPLY) {
1625 /* Do not close the dialog */
1626 g_signal_stop_emission_by_name (dialog, "response");
1628 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1629 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1630 gtk_dialog_run (GTK_DIALOG(note));
1631 gtk_widget_destroy (note);
1637 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1638 const gchar *certificate)
1643 HildonWindowStack *stack;
1645 stack = hildon_window_stack_get_default ();
1646 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1649 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1654 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1657 /* We use GTK_RESPONSE_APPLY because we want the button in the
1658 middle of OK and CANCEL the same as the browser does for
1659 example. With GTK_RESPONSE_HELP the view button is aligned
1660 to the left while the other two to the right */
1661 note = hildon_note_new_confirmation_add_buttons (
1664 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1665 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1666 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1669 g_signal_connect (G_OBJECT(note), "response",
1670 G_CALLBACK(on_cert_dialog_response),
1671 (gpointer) certificate);
1673 response = gtk_dialog_run(GTK_DIALOG(note));
1675 on_destroy_dialog (note);
1678 return response == GTK_RESPONSE_OK;
1682 modest_platform_run_alert_dialog (const gchar* prompt,
1683 gboolean is_question)
1685 ModestWindow *main_win;
1687 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1688 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1689 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1690 return is_question ? FALSE : TRUE;
1693 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1694 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1696 gboolean retval = TRUE;
1698 /* The Tinymail documentation says that we should show Yes and No buttons,
1699 * when it is a question.
1700 * Obviously, we need tinymail to use more specific error codes instead,
1701 * so we know what buttons to show. */
1702 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1704 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1705 GTK_WINDOW (dialog), GTK_WINDOW (main_win));
1707 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1708 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1710 on_destroy_dialog (dialog);
1712 /* Just show the error text and use the default response: */
1713 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1721 GtkWindow *parent_window;
1722 ModestConnectedPerformer callback;
1723 TnyAccount *account;
1730 on_went_online_info_free (OnWentOnlineInfo *info)
1732 /* And if we cleanup, we DO cleanup :-) */
1735 g_object_unref (info->device);
1738 if (info->parent_window)
1739 g_object_unref (info->parent_window);
1741 g_object_unref (info->account);
1743 g_slice_free (OnWentOnlineInfo, info);
1745 /* We're done ... */
1751 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1753 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1755 /* Now it's really time to callback to the caller. If going online didn't succeed,
1756 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1757 * canceled will be set. Etcetera etcetera. */
1759 if (info->callback) {
1760 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1763 /* This is our last call, we must cleanup here if we didn't yet do that */
1764 on_went_online_info_free (info);
1771 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1773 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1774 info->iap = g_strdup (iap_id);
1776 if (canceled || err || !info->account) {
1778 /* If there's a problem or if there's no account (then that's it for us, we callback
1779 * the caller's callback now. He'll have to handle err or canceled, of course.
1780 * We are not really online, as the account is not really online here ... */
1782 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1783 * this info. We don't cleanup err, Tinymail does that! */
1785 if (info->callback) {
1787 /* info->account can be NULL here, this means that the user did not
1788 * provide a nice account instance. We'll assume that the user knows
1789 * what he's doing and is happy with just the device going online.
1791 * We can't do magic, we don't know what account the user wants to
1792 * see going online. So just the device goes online, end of story */
1794 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1797 } else if (info->account) {
1799 /* If there's no problem and if we have an account, we'll put the account
1800 * online too. When done, the callback of bringing the account online
1801 * will callback the caller's callback. This is the most normal case. */
1803 info->device = TNY_DEVICE (g_object_ref (device));
1805 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1806 on_account_went_online, info);
1808 /* The on_account_went_online cb frees up the info, go look if you
1809 * don't believe me! (so we return here) */
1814 /* We cleanup if we are not bringing the account online too */
1815 on_went_online_info_free (info);
1821 modest_platform_connect_and_perform (GtkWindow *parent_window,
1823 TnyAccount *account,
1824 ModestConnectedPerformer callback,
1827 gboolean device_online;
1829 TnyConnectionStatus conn_status;
1830 OnWentOnlineInfo *info;
1832 device = modest_runtime_get_device();
1833 device_online = tny_device_is_online (device);
1835 /* If there is no account check only the device status */
1838 if (device_online) {
1840 /* We promise to instantly perform the callback, so ... */
1842 callback (FALSE, NULL, parent_window, account, user_data);
1847 info = g_slice_new0 (OnWentOnlineInfo);
1850 info->device = NULL;
1851 info->account = NULL;
1854 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1856 info->parent_window = NULL;
1857 info->user_data = user_data;
1858 info->callback = callback;
1860 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1861 force, on_conic_device_went_online,
1864 /* We'll cleanup in on_conic_device_went_online */
1867 /* The other code has no more reason to run. This is all that we can do for the
1868 * caller (he should have given us a nice and clean account instance!). We
1869 * can't do magic, we don't know what account he intends to bring online. So
1870 * we'll just bring the device online (and await his false bug report). */
1876 /* Return if the account is already connected */
1878 conn_status = tny_account_get_connection_status (account);
1879 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1881 /* We promise to instantly perform the callback, so ... */
1883 callback (FALSE, NULL, parent_window, account, user_data);
1889 /* Else, we are in a state that requires that we go online before we
1890 * call the caller's callback. */
1892 info = g_slice_new0 (OnWentOnlineInfo);
1894 info->device = NULL;
1896 info->account = TNY_ACCOUNT (g_object_ref (account));
1899 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1901 info->parent_window = NULL;
1903 /* So we'll put the callback away for later ... */
1905 info->user_data = user_data;
1906 info->callback = callback;
1908 if (!device_online) {
1910 /* If also the device is offline, then we connect both the device
1911 * and the account */
1913 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1914 force, on_conic_device_went_online,
1919 /* If the device is online, we'll just connect the account */
1921 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1922 on_account_went_online, info);
1925 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1926 * in both situations, go look if you don't believe me! */
1932 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1934 TnyFolderStore *folder_store,
1935 ModestConnectedPerformer callback,
1938 TnyAccount *account = NULL;
1940 if (!folder_store) {
1941 /* We promise to instantly perform the callback, so ... */
1943 callback (FALSE, NULL, parent_window, NULL, user_data);
1947 } else if (TNY_IS_FOLDER (folder_store)) {
1948 /* Get the folder's parent account: */
1949 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1950 } else if (TNY_IS_ACCOUNT (folder_store)) {
1951 /* Use the folder store as an account: */
1952 account = TNY_ACCOUNT (g_object_ref (folder_store));
1955 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1956 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1957 /* No need to connect a local account */
1959 callback (FALSE, NULL, parent_window, account, user_data);
1964 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1968 g_object_unref (account);
1972 src_account_connect_performer (gboolean canceled,
1974 GtkWindow *parent_window,
1975 TnyAccount *src_account,
1978 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1980 if (canceled || err) {
1981 /* If there was any error call the user callback */
1982 info->callback (canceled, err, parent_window, src_account, info->data);
1984 /* Connect the destination account */
1985 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1986 TNY_FOLDER_STORE (info->dst_account),
1987 info->callback, info->data);
1990 /* Free the info object */
1991 g_object_unref (info->dst_account);
1992 g_slice_free (DoubleConnectionInfo, info);
1997 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
1999 TnyFolderStore *folder_store,
2000 DoubleConnectionInfo *connect_info)
2002 modest_platform_connect_if_remote_and_perform(parent_window,
2005 src_account_connect_performer,
2010 modest_platform_get_account_settings_wizard (void)
2012 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2014 return GTK_WIDGET (dialog);
2018 modest_platform_get_current_connection (void)
2020 TnyDevice *device = NULL;
2021 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2023 device = modest_runtime_get_device ();
2025 if (!tny_device_is_online (device))
2026 return MODEST_CONNECTED_VIA_ANY;
2028 #ifdef MODEST_HAVE_CONIC
2030 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2032 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2033 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2034 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2036 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2037 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2038 !strcmp (bearer_type, "WIMAX")) {
2039 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2041 retval = MODEST_CONNECTED_VIA_ANY;
2044 g_object_unref (iap);
2047 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2048 #endif /* MODEST_HAVE_CONIC */
2055 modest_platform_check_memory_low (ModestWindow *win,
2060 /* are we in low memory state? */
2061 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2063 if (win && lowmem && visuals)
2064 modest_platform_run_information_dialog (
2066 dgettext("ke-recv","memr_ib_operation_disabled"),
2070 g_debug ("%s: low memory reached. disallowing some operations",
2077 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2083 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2086 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2087 GTK_WINDOW (dialog),
2089 gtk_widget_show_all (dialog);
2091 g_signal_connect_swapped (dialog, "response",
2092 G_CALLBACK (gtk_widget_destroy),
2097 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2103 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2106 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2107 GTK_WINDOW (dialog),
2109 gtk_widget_show_all (dialog);
2111 g_signal_connect_swapped (dialog, "response",
2112 G_CALLBACK (gtk_widget_destroy),
2117 modest_platform_get_osso_context (void)
2119 return modest_maemo_utils_get_osso_context ();
2123 _modest_platform_play_email_tone (void)
2125 gchar *active_profile;
2128 gint mail_volume_int;
2130 ca_context *ca_con = NULL;
2131 ca_proplist *pl = NULL;
2133 active_profile = profile_get_profile ();
2134 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2135 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2136 mail_volume_int = profile_parse_int (mail_volume);
2138 if (mail_volume_int > 0) {
2140 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2141 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2145 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2146 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2147 ca_context_destroy(ca_con);
2151 ca_proplist_create(&pl);
2152 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2153 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2155 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2156 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2158 ca_proplist_destroy(pl);
2159 ca_context_destroy(ca_con);
2162 g_free (mail_volume);
2164 g_free (active_profile);
2168 on_move_to_dialog_folder_activated (GtkTreeView *tree_view,
2170 GtkTreeViewColumn *column,
2173 gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2177 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2178 GtkWidget **folder_view)
2180 GtkWidget *dialog, *folder_view_container;
2182 /* Create dialog. We cannot use a touch selector because we
2183 need to use here the folder view widget directly */
2184 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2185 GTK_WINDOW (parent_window),
2186 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2187 GTK_DIALOG_DESTROY_WITH_PARENT,
2188 _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2191 /* Create folder view */
2192 *folder_view = modest_platform_create_folder_view (NULL);
2194 /* Simulate the behaviour of a HildonPickerDialog by emitting
2195 a response when a folder is selected */
2196 g_signal_connect (*folder_view, "row-activated",
2197 G_CALLBACK (on_move_to_dialog_folder_activated),
2200 /* Create pannable and add it to the dialog */
2201 folder_view_container = hildon_pannable_area_new ();
2202 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2203 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2205 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2207 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2208 gtk_widget_show (folder_view_container);
2209 gtk_widget_show (*folder_view);
2215 modest_platform_get_list_to_move (ModestWindow *window)
2217 ModestHeaderView *header_view;
2219 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2221 return modest_header_view_get_selected_headers (header_view);