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>
66 #ifdef MODEST_HAVE_MCE
67 #include <mce/dbus-names.h>
68 #endif /*MODEST_HAVE_MCE*/
70 #ifdef MODEST_HAVE_ABOOK
71 #include <libosso-abook/osso-abook.h>
72 #endif /*MODEST_HAVE_ABOOK*/
74 #ifdef MODEST_HAVE_LIBALARM
75 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
76 #endif /*MODEST_HAVE_LIBALARM*/
79 #define HILDON_OSSO_URI_ACTION "uri-action"
80 #define URI_ACTION_COPY "copy:"
81 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
82 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
83 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
85 static void _modest_platform_play_email_tone (void);
89 on_modest_conf_update_interval_changed (ModestConf* self,
91 ModestConfEvent event,
92 ModestConfNotificationId id,
95 g_return_if_fail (key);
97 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
98 const guint update_interval_minutes =
99 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
100 modest_platform_set_update_interval (update_interval_minutes);
107 check_required_files (void)
109 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
111 g_printerr ("modest: check for mcc file failed\n");
116 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
117 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
118 g_printerr ("modest: cannot find providers data\n");
126 /* the gpointer here is the osso_context. */
128 modest_platform_init (int argc, char *argv[])
130 osso_context_t *osso_context;
132 osso_hw_state_t hw_state = { 0 };
136 if (!check_required_files ()) {
137 g_printerr ("modest: missing required files\n");
141 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
144 g_printerr ("modest: failed to acquire osso context\n");
147 modest_maemo_utils_set_osso_context (osso_context);
149 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
150 g_printerr ("modest: could not get dbus connection\n");
154 /* Add a D-Bus handler to be used when the main osso-rpc
155 * D-Bus handler has not handled something.
156 * We use this for D-Bus methods that need to use more complex types
157 * than osso-rpc supports.
159 if (!dbus_connection_add_filter (con,
160 modest_dbus_req_filter,
164 g_printerr ("modest: Could not add D-Bus filter\n");
168 /* Register our simple D-Bus callbacks, via the osso API: */
169 osso_return_t result = osso_rpc_set_cb_f(osso_context,
173 modest_dbus_req_handler, NULL /* user_data */);
174 if (result != OSSO_OK) {
175 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
179 /* Register hardware event dbus callback: */
180 hw_state.shutdown_ind = TRUE;
181 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
183 /* Register osso auto-save callbacks: */
184 result = osso_application_set_autosave_cb (osso_context,
185 modest_on_osso_application_autosave, NULL /* user_data */);
186 if (result != OSSO_OK) {
187 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
192 /* Make sure that the update interval is changed whenever its gconf key
194 /* CAUTION: we're not using here the
195 modest_conf_listen_to_namespace because we know that there
196 are other parts of Modest listening for this namespace, so
197 we'll receive the notifications anyway. We basically do not
198 use it because there is no easy way to do the
199 modest_conf_forget_namespace */
200 ModestConf *conf = modest_runtime_get_conf ();
201 g_signal_connect (G_OBJECT(conf),
203 G_CALLBACK (on_modest_conf_update_interval_changed),
206 /* only force the setting of the default interval, if there are actually
208 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
210 /* Get the initial update interval from gconf: */
211 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
212 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
213 modest_account_mgr_free_account_names (acc_names);
217 #ifdef MODEST_HAVE_ABOOK
218 /* initialize the addressbook */
219 if (!osso_abook_init (&argc, &argv, osso_context)) {
220 g_printerr ("modest: failed to initialized addressbook\n");
223 #endif /*MODEST_HAVE_ABOOK*/
229 modest_platform_uninit (void)
231 osso_context_t *osso_context =
232 modest_maemo_utils_get_osso_context ();
234 osso_deinitialize (osso_context);
243 modest_platform_get_new_device (void)
245 return TNY_DEVICE (tny_maemo_conic_device_new ());
249 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
250 gchar **effective_mime_type)
252 GString *mime_str = NULL;
253 gchar *icon_name = NULL;
254 gchar **icons, **cursor;
256 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
257 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
259 mime_str = g_string_new (mime_type);
260 g_string_ascii_down (mime_str);
263 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
265 for (cursor = icons; cursor; ++cursor) {
266 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
267 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
268 icon_name = g_strdup ("qgn_list_messagin");
270 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
271 icon_name = g_strdup (*cursor);
277 if (effective_mime_type)
278 *effective_mime_type = g_string_free (mime_str, FALSE);
280 g_string_free (mime_str, TRUE);
287 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
292 g_return_val_if_fail (uri, FALSE);
294 result = hildon_uri_open (uri, action, &err);
296 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
297 uri, action, err && err->message ? err->message : "unknown error");
307 modest_platform_activate_uri (const gchar *uri)
309 HildonURIAction *action;
310 gboolean result = FALSE;
311 GSList *actions, *iter = NULL;
313 g_return_val_if_fail (uri, FALSE);
317 /* don't try to activate file: uri's -- they might confuse the user,
318 * and/or might have security implications */
319 if (!g_str_has_prefix (uri, "file:")) {
321 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
323 for (iter = actions; iter; iter = g_slist_next (iter)) {
324 action = (HildonURIAction*) iter->data;
325 if (action && strcmp (hildon_uri_action_get_service (action),
326 "com.nokia.modest") == 0) {
327 result = checked_hildon_uri_open (uri, action);
332 /* if we could not open it with email, try something else */
334 result = checked_hildon_uri_open (uri, NULL);
338 ModestWindow *parent =
339 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
340 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
341 _("mcen_ib_unsupported_link"));
342 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
349 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
353 gchar *uri_path = NULL;
355 uri_path = gnome_vfs_get_uri_from_local_path (path);
356 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
359 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
361 result = hildon_mime_open_file (con, uri_path);
363 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
371 } ModestPlatformPopupInfo;
374 delete_uri_popup (GtkWidget *menu,
378 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
380 g_free (popup_info->uri);
381 hildon_uri_free_actions (popup_info->actions);
387 activate_uri_popup_item (GtkMenuItem *menu_item,
391 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
392 const gchar* action_name;
394 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
396 g_printerr ("modest: no action name defined\n");
400 /* special handling for the copy menu item -- copy the uri to the clipboard */
401 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
402 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
403 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
404 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
406 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
407 action_name += strlen ("mailto:");
409 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
410 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
411 return; /* we're done */
414 /* now, the real uri-actions... */
415 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
416 HildonURIAction *action = (HildonURIAction *) node->data;
417 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
418 if (!checked_hildon_uri_open (popup_info->uri, action)) {
419 ModestWindow *parent =
420 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
421 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
422 _("mcen_ib_unsupported_link"));
430 modest_platform_show_uri_popup (const gchar *uri)
432 GSList *actions_list;
437 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
440 GtkWidget *menu = gtk_menu_new ();
441 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
443 /* don't add actions for file: uri's -- they might confuse the user,
444 * and/or might have security implications
445 * we still allow to copy the url though
447 if (!g_str_has_prefix (uri, "file:")) {
450 popup_info->actions = actions_list;
451 popup_info->uri = g_strdup (uri);
453 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
454 GtkWidget *menu_item;
455 const gchar *action_name;
456 const gchar *translation_domain;
457 HildonURIAction *action = (HildonURIAction *) node->data;
458 action_name = hildon_uri_action_get_name (action);
459 translation_domain = hildon_uri_action_get_translation_domain (action);
460 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
461 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
462 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
465 if (hildon_uri_is_default_action (action, NULL)) {
466 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
468 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
470 gtk_widget_show (menu_item);
474 /* always add the copy item */
475 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
476 "uri_link_copy_link_location"));
477 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
478 g_strconcat (URI_ACTION_COPY, uri, NULL),
480 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
481 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
482 gtk_widget_show (menu_item);
485 /* and what to do when the link is deleted */
486 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
487 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
490 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
498 modest_platform_get_icon (const gchar *name, guint icon_size)
501 GdkPixbuf* pixbuf = NULL;
502 GtkIconTheme *current_theme = NULL;
504 g_return_val_if_fail (name, NULL);
506 /* strlen == 0 is not really an error; it just
507 * means the icon is not available
509 if (!name || strlen(name) == 0)
512 current_theme = gtk_icon_theme_get_default ();
513 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
514 GTK_ICON_LOOKUP_NO_SVG,
517 g_printerr ("modest: error loading theme icon '%s': %s\n",
525 modest_platform_get_app_name (void)
527 return _("mcen_ap_name");
531 entry_insert_text (GtkEditable *editable,
540 chars = gtk_editable_get_chars (editable, 0, -1);
541 chars_length = g_utf8_strlen (chars, -1);
544 /* Show WID-INF036 */
545 if (chars_length >= 20) {
546 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
547 _CS("ckdg_ib_maximum_characters_reached"));
549 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
553 tmp = g_strndup (folder_name_forbidden_chars,
554 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
555 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
556 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
561 /* Write the text in the entry if it's valid */
562 g_signal_handlers_block_by_func (editable,
563 (gpointer) entry_insert_text, data);
564 gtk_editable_insert_text (editable, text, length, position);
565 g_signal_handlers_unblock_by_func (editable,
566 (gpointer) entry_insert_text, data);
569 /* Do not allow further processing */
570 g_signal_stop_emission_by_name (editable, "insert_text");
574 entry_changed (GtkEditable *editable,
578 GtkWidget *ok_button;
581 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
582 ok_button = GTK_WIDGET (buttons->data);
584 chars = gtk_editable_get_chars (editable, 0, -1);
585 g_return_if_fail (chars != NULL);
588 if (g_utf8_strlen (chars,-1) >= 20)
589 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
590 _CS("ckdg_ib_maximum_characters_reached"));
592 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
595 g_list_free (buttons);
602 on_response (GtkDialog *dialog,
606 GList *child_vbox, *child_hbox;
607 GtkWidget *hbox, *entry;
608 TnyFolderStore *parent;
609 const gchar *new_name;
612 if (response != GTK_RESPONSE_ACCEPT)
616 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
617 hbox = child_vbox->data;
618 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
619 entry = child_hbox->next->data;
621 parent = TNY_FOLDER_STORE (user_data);
622 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
625 /* Look for another folder with the same name */
626 if (modest_tny_folder_has_subfolder_with_name (parent,
633 if (TNY_IS_ACCOUNT (parent) &&
634 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
635 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
644 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
645 NULL, _CS("ckdg_ib_folder_already_exists"));
646 /* Select the text */
647 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
648 gtk_widget_grab_focus (entry);
649 /* Do not close the dialog */
650 g_signal_stop_emission_by_name (dialog, "response");
657 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
658 TnyFolderStore *parent,
659 const gchar *dialog_title,
660 const gchar *label_text,
661 const gchar *suggested_name,
664 GtkWidget *accept_btn = NULL;
665 GtkWidget *dialog, *entry, *label, *hbox;
666 GList *buttons = NULL;
669 /* Ask the user for the folder name */
670 dialog = gtk_dialog_new_with_buttons (dialog_title,
672 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
677 /* Add accept button (with unsensitive handler) */
678 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
679 accept_btn = GTK_WIDGET (buttons->data);
680 /* Create label and entry */
681 label = gtk_label_new (label_text);
683 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
684 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
687 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
689 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
690 gtk_entry_set_width_chars (GTK_ENTRY (entry),
691 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
692 g_utf8_strlen (_("mcen_ia_default_folder_name"), -1)));
693 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
695 /* Connect to the response method to avoid closing the dialog
696 when an invalid name is selected*/
697 g_signal_connect (dialog,
699 G_CALLBACK (on_response),
702 /* Track entry changes */
703 g_signal_connect (entry,
705 G_CALLBACK (entry_insert_text),
707 g_signal_connect (entry,
709 G_CALLBACK (entry_changed),
713 /* Some locales like pt_BR need this to get the full window
715 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
717 /* Create the hbox */
718 hbox = gtk_hbox_new (FALSE, 12);
719 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
720 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
722 /* Add hbox to dialog */
723 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
724 hbox, FALSE, FALSE, 0);
725 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
726 GTK_WINDOW (dialog), parent_window);
727 gtk_widget_show_all (GTK_WIDGET(dialog));
729 result = gtk_dialog_run (GTK_DIALOG(dialog));
730 if (result == GTK_RESPONSE_ACCEPT)
731 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
733 gtk_widget_destroy (dialog);
735 while (gtk_events_pending ())
736 gtk_main_iteration ();
742 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
743 TnyFolderStore *parent_folder,
744 gchar *suggested_name,
747 gchar *real_suggested_name = NULL, *tmp = NULL;
750 if(suggested_name == NULL)
752 const gchar *default_name = _("mcen_ia_default_folder_name");
756 for(i = 0; i < 100; ++ i) {
757 gboolean exists = FALSE;
759 sprintf(num_str, "%.2u", i);
762 real_suggested_name = g_strdup (default_name);
764 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
766 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
773 g_free (real_suggested_name);
776 /* Didn't find a free number */
778 real_suggested_name = g_strdup (default_name);
780 real_suggested_name = suggested_name;
783 tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
784 result = modest_platform_run_folder_name_dialog (parent_window,
786 _("mcen_ti_new_folder"),
792 if (suggested_name == NULL)
793 g_free(real_suggested_name);
799 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
800 TnyFolderStore *parent_folder,
801 const gchar *suggested_name,
804 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
806 return modest_platform_run_folder_name_dialog (parent_window,
808 _HL("ckdg_ti_rename_folder"),
809 _HL("ckdg_fi_rename_name"),
817 on_destroy_dialog (GtkWidget *dialog)
819 /* This could happen when the dialogs get programatically
820 hidden or destroyed (for example when closing the
821 application while a dialog is being shown) */
822 if (!GTK_IS_WIDGET (dialog))
825 gtk_widget_destroy (dialog);
827 if (gtk_events_pending ())
828 gtk_main_iteration ();
832 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
833 const gchar *message)
838 dialog = hildon_note_new_confirmation (parent_window, message);
839 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
840 GTK_WINDOW (dialog), parent_window);
842 response = gtk_dialog_run (GTK_DIALOG (dialog));
844 on_destroy_dialog (dialog);
850 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
851 const gchar *message,
852 const gchar *button_accept,
853 const gchar *button_cancel)
858 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
859 button_accept, GTK_RESPONSE_ACCEPT,
860 button_cancel, GTK_RESPONSE_CANCEL,
863 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
864 GTK_WINDOW (dialog), parent_window);
866 response = gtk_dialog_run (GTK_DIALOG (dialog));
868 on_destroy_dialog (dialog);
874 modest_platform_run_information_dialog (GtkWindow *parent_window,
875 const gchar *message,
880 note = hildon_note_new_information (parent_window, message);
882 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
883 GTK_WINDOW (note), parent_window);
886 gtk_dialog_run (GTK_DIALOG (note));
888 on_destroy_dialog (note);
890 g_signal_connect_swapped (note,
892 G_CALLBACK (on_destroy_dialog),
895 gtk_widget_show_all (note);
899 typedef struct _ConnectAndWaitData {
901 GMainLoop *wait_loop;
902 gboolean has_callback;
904 } ConnectAndWaitData;
908 quit_wait_loop (TnyAccount *account,
909 ConnectAndWaitData *data)
911 /* Set the has_callback to TRUE (means that the callback was
912 executed and wake up every code waiting for cond to be
914 g_mutex_lock (data->mutex);
915 data->has_callback = TRUE;
917 g_main_loop_quit (data->wait_loop);
918 g_mutex_unlock (data->mutex);
922 on_connection_status_changed (TnyAccount *account,
923 TnyConnectionStatus status,
926 TnyConnectionStatus conn_status;
927 ConnectAndWaitData *data;
929 /* Ignore if reconnecting or disconnected */
930 conn_status = tny_account_get_connection_status (account);
931 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
932 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
935 /* Remove the handler */
936 data = (ConnectAndWaitData *) user_data;
937 g_signal_handler_disconnect (account, data->handler);
939 /* Quit from wait loop */
940 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
944 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
949 /* Quit from wait loop */
950 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
954 modest_platform_connect_and_wait (GtkWindow *parent_window,
957 ConnectAndWaitData *data = NULL;
958 gboolean device_online;
960 TnyConnectionStatus conn_status;
961 gboolean user_requested;
963 device = modest_runtime_get_device();
964 device_online = tny_device_is_online (device);
966 /* Whether the connection is user requested or automatically
967 requested, for example via D-Bus */
968 user_requested = (parent_window) ? TRUE : FALSE;
970 /* If there is no account check only the device status */
975 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
976 NULL, user_requested);
979 /* Return if the account is already connected */
980 conn_status = tny_account_get_connection_status (account);
981 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
984 /* Create the helper */
985 data = g_slice_new0 (ConnectAndWaitData);
986 data->mutex = g_mutex_new ();
987 data->has_callback = FALSE;
989 /* Connect the device */
990 if (!device_online) {
991 /* Track account connection status changes */
992 data->handler = g_signal_connect (account, "connection-status-changed",
993 G_CALLBACK (on_connection_status_changed),
995 /* Try to connect the device */
996 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
997 NULL, user_requested);
999 /* If the device connection failed then exit */
1000 if (!device_online && data->handler)
1003 /* Force a reconnection of the account */
1004 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1005 on_tny_camel_account_set_online_cb, data);
1008 /* Wait until the callback is executed */
1009 g_mutex_lock (data->mutex);
1010 if (!data->has_callback) {
1011 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1012 gdk_threads_leave ();
1013 g_mutex_unlock (data->mutex);
1014 g_main_loop_run (data->wait_loop);
1015 g_mutex_lock (data->mutex);
1016 gdk_threads_enter ();
1018 g_mutex_unlock (data->mutex);
1022 if (g_signal_handler_is_connected (account, data->handler))
1023 g_signal_handler_disconnect (account, data->handler);
1024 g_mutex_free (data->mutex);
1025 g_main_loop_unref (data->wait_loop);
1026 g_slice_free (ConnectAndWaitData, data);
1029 conn_status = tny_account_get_connection_status (account);
1030 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1034 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1036 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1037 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1038 /* This must be a maildir account, which does not require a connection: */
1043 return modest_platform_connect_and_wait (parent_window, account);
1047 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1050 return TRUE; /* Maybe it is something local. */
1052 gboolean result = TRUE;
1053 if (TNY_IS_FOLDER (folder_store)) {
1054 /* Get the folder's parent account: */
1055 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1056 if (account != NULL) {
1057 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1058 g_object_unref (account);
1060 } else if (TNY_IS_ACCOUNT (folder_store)) {
1061 /* Use the folder store as an account: */
1062 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1069 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1073 dialog = modest_hildon2_sort_dialog_new (parent_window);
1080 modest_platform_set_update_interval (guint minutes)
1082 #ifdef MODEST_HAVE_LIBALARM
1084 ModestConf *conf = modest_runtime_get_conf ();
1088 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1090 /* Delete any existing alarm,
1091 * because we will replace it: */
1093 if (alarmd_event_del(alarm_cookie) != 1)
1094 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1096 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1099 /* 0 means no updates: */
1104 /* Register alarm: */
1106 /* Set the interval in alarm_event_t structure: */
1107 alarm_event_t *event = alarm_event_create ();
1108 alarm_event_add_actions (event, 1);
1109 alarm_action_t *action = alarm_event_get_action (event, 0);
1110 event->alarm_time = minutes * 60; /* seconds */
1112 /* Set recurrence every few minutes: */
1113 event->recur_secs = minutes*60;
1114 event->recur_count = -1; /* Means infinite */
1116 /* Specify what should happen when the alarm happens:
1117 * It should call this D-Bus method: */
1119 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1120 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1121 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1122 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1123 action->flags = ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1125 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1126 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1127 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1128 * This is why we want to use the Alarm API instead of just g_timeout_add().
1129 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1130 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1132 event->flags = ALARM_EVENT_CONNECTED;
1134 alarm_cookie = alarmd_event_add (event);
1137 alarm_event_delete (event);
1139 /* Store the alarm ID in GConf, so we can remove it later:
1140 * This is apparently valid between application instances. */
1141 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1143 if (!alarm_cookie) {
1145 g_debug ("Error setting alarm event. \n");
1149 #endif /* MODEST_HAVE_LIBALARM */
1154 modest_platform_push_email_notification(void)
1156 gboolean screen_on = TRUE, app_in_foreground;
1158 /* Get the window status */
1159 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1161 /* If the screen is on and the app is in the
1162 foreground we don't show anything */
1163 if (!(screen_on && app_in_foreground)) {
1165 _modest_platform_play_email_tone ();
1167 /* Activate LED. This must be deactivated by
1168 modest_platform_remove_new_mail_notifications */
1169 #ifdef MODEST_HAVE_MCE
1170 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1174 MCE_ACTIVATE_LED_PATTERN,
1176 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1183 modest_platform_on_new_headers_received (TnyList *header_list,
1184 gboolean show_visual)
1186 g_return_if_fail (TNY_IS_LIST(header_list));
1188 if (tny_list_get_length(header_list) == 0) {
1189 g_warning ("%s: header list is empty", __FUNCTION__);
1194 modest_platform_push_email_notification ();
1195 /* We do a return here to avoid indentation with an else */
1199 #ifdef MODEST_HAVE_HILDON_NOTIFY
1200 HildonNotification *notification;
1202 GSList *notifications_list = NULL;
1204 /* Get previous notifications ids */
1205 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1206 MODEST_CONF_NOTIFICATION_IDS,
1207 MODEST_CONF_VALUE_INT, NULL);
1209 iter = tny_list_create_iterator (header_list);
1210 while (!tny_iterator_is_done (iter)) {
1211 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1212 const gchar *display_date;
1213 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1214 TnyFolder *folder = tny_header_get_folder (header);
1215 gboolean first_notification = TRUE;
1218 ModestDatetimeFormatter *datetime_formatter;
1220 /* constant string, don't free */
1221 datetime_formatter = modest_datetime_formatter_new ();
1222 display_date = modest_datetime_formatter_display_datetime (datetime_formatter,
1223 tny_header_get_date_received (header));
1224 g_object_unref (datetime_formatter);
1226 display_address = tny_header_dup_from (header);
1227 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1229 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1230 str = tny_header_dup_subject (header);
1231 notification = hildon_notification_new (summary,
1233 "qgn_list_messagin",
1236 /* Create the message URL */
1237 str = tny_header_dup_uid (header);
1238 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1242 hildon_notification_add_dbus_action(notification,
1245 MODEST_DBUS_SERVICE,
1248 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1252 /* Play sound if the user wants. Show the LED
1253 pattern. Show and play just one */
1254 if (G_UNLIKELY (first_notification)) {
1255 gchar *active_profile;
1258 gint mail_volume_int;
1260 first_notification = FALSE;
1262 active_profile = profile_get_profile ();
1263 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1264 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1265 mail_volume_int = profile_parse_int (mail_volume);
1267 if (mail_volume_int > 0)
1268 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1269 "sound-file", mail_tone);
1271 g_free (mail_volume);
1273 g_free (active_profile);
1275 /* Set the led pattern */
1276 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1278 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1280 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1283 /* Notify. We need to do this in an idle because this function
1284 could be called from a thread */
1285 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1287 /* Save id in the list */
1288 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1289 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1290 /* We don't listen for the "closed" signal, because we
1291 don't care about if the notification was removed or
1292 not to store the list in gconf */
1294 /* Free & carry on */
1295 g_free (display_address);
1298 g_object_unref (folder);
1299 g_object_unref (header);
1300 tny_iterator_next (iter);
1302 g_object_unref (iter);
1305 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1306 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1308 g_slist_free (notifications_list);
1310 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1314 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1317 #ifdef MODEST_HAVE_MCE
1318 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1322 MCE_DEACTIVATE_LED_PATTERN,
1324 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1330 #ifdef MODEST_HAVE_HILDON_NOTIFY
1331 GSList *notif_list = NULL;
1333 /* Get previous notifications ids */
1334 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1335 MODEST_CONF_NOTIFICATION_IDS,
1336 MODEST_CONF_VALUE_INT, NULL);
1338 while (notif_list) {
1340 NotifyNotification *notif;
1342 /* Nasty HACK to remove the notifications, set the id
1343 of the existing ones and then close them */
1344 notif_id = GPOINTER_TO_INT(notif_list->data);
1345 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1346 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1348 /* Close the notification, note that some ids could be
1349 already invalid, but we don't care because it does
1351 notify_notification_close(notif, NULL);
1352 g_object_unref(notif);
1354 /* Delete the link, it's like going to the next */
1355 notif_list = g_slist_delete_link (notif_list, notif_list);
1359 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1360 notif_list, MODEST_CONF_VALUE_INT, NULL);
1362 g_slist_free (notif_list);
1364 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1370 modest_platform_get_global_settings_dialog ()
1372 return modest_hildon2_global_settings_dialog_new ();
1376 modest_platform_show_help (GtkWindow *parent_window,
1377 const gchar *help_id)
1383 modest_platform_show_search_messages (GtkWindow *parent_window)
1385 osso_return_t result = OSSO_ERROR;
1387 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1388 "osso_global_search",
1389 "search_email", NULL, DBUS_TYPE_INVALID);
1391 if (result != OSSO_OK) {
1392 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1397 modest_platform_show_addressbook (GtkWindow *parent_window)
1399 osso_return_t result = OSSO_ERROR;
1401 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1403 "top_application", NULL, DBUS_TYPE_INVALID);
1405 if (result != OSSO_OK) {
1406 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1411 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1413 GtkWidget *widget = modest_folder_view_new (query);
1415 /* Show one account by default */
1416 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1417 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1419 /* Restore settings */
1420 modest_widget_memory_restore (modest_runtime_get_conf(),
1422 MODEST_CONF_FOLDER_VIEW_KEY);
1428 banner_finish (gpointer data, GObject *object)
1430 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1431 modest_window_mgr_unregister_banner (mgr);
1432 g_object_unref (mgr);
1436 modest_platform_information_banner (GtkWidget *parent,
1437 const gchar *icon_name,
1440 GtkWidget *banner, *banner_parent = NULL;
1441 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1443 if (modest_window_mgr_get_num_windows (mgr) == 0)
1446 if (parent && GTK_IS_WINDOW (parent)) {
1447 /* If the window is the active one then show the
1448 banner on top of this window */
1449 if (gtk_window_is_active (GTK_WINDOW (parent)))
1450 banner_parent = parent;
1451 /* If the window is not the topmost but it's visible
1452 (it's minimized for example) then show the banner
1454 else if (GTK_WIDGET_VISIBLE (parent))
1455 banner_parent = NULL;
1456 /* If the window is hidden (like the main window when
1457 running in the background) then do not show
1464 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1466 modest_window_mgr_register_banner (mgr);
1468 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1472 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1473 const gchar *icon_name,
1479 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1482 banner = hildon_banner_show_information (parent, icon_name, text);
1483 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1487 modest_platform_animation_banner (GtkWidget *parent,
1488 const gchar *animation_name,
1491 GtkWidget *inf_note = NULL;
1493 g_return_val_if_fail (text != NULL, NULL);
1495 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1498 /* If the parent is not visible then do not show */
1499 if (parent && !GTK_WIDGET_VISIBLE (parent))
1502 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1510 TnyAccount *account;
1513 } CheckAccountIdleData;
1515 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1518 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1520 gboolean stop_trying = FALSE;
1521 g_return_val_if_fail (data && data->account, FALSE);
1523 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1524 tny_account_get_connection_status (data->account));
1526 if (data && data->account &&
1527 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1528 * after which the account is likely to be usable, or never likely to be usable soon: */
1529 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1531 data->is_online = TRUE;
1535 /* Give up if we have tried too many times: */
1536 if (data->count_tries >= NUMBER_OF_TRIES) {
1539 /* Wait for another timeout: */
1540 ++(data->count_tries);
1545 /* Allow the function that requested this idle callback to continue: */
1547 g_main_loop_quit (data->loop);
1550 g_object_unref (data->account);
1552 return FALSE; /* Don't call this again. */
1554 return TRUE; /* Call this timeout callback again. */
1558 /* Return TRUE immediately if the account is already online,
1559 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1560 * soon as the account is online, or FALSE if the account does
1561 * not become online in the NUMBER_OF_TRIES seconds.
1562 * This is useful when the D-Bus method was run immediately after
1563 * the application was started (when using D-Bus activation),
1564 * because the account usually takes a short time to go online.
1565 * The return value is maybe not very useful.
1568 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1572 g_return_val_if_fail (account, FALSE);
1574 if (!tny_device_is_online (modest_runtime_get_device())) {
1575 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1579 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1580 * so we avoid wait unnecessarily: */
1581 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1584 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1585 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1586 * we want to avoid. */
1587 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1590 /* This blocks on the result: */
1591 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1592 data->is_online = FALSE;
1593 data->account = account;
1594 g_object_ref (data->account);
1595 data->count_tries = 0;
1597 GMainContext *context = NULL; /* g_main_context_new (); */
1598 data->loop = g_main_loop_new (context, FALSE /* not running */);
1600 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1602 /* This main loop will run until the idle handler has stopped it: */
1603 g_main_loop_run (data->loop);
1605 g_main_loop_unref (data->loop);
1606 /* g_main_context_unref (context); */
1608 is_online = data->is_online;
1609 g_slice_free (CheckAccountIdleData, data);
1617 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1619 /* GTK_RESPONSE_HELP means we need to show the certificate */
1620 if (response_id == GTK_RESPONSE_APPLY) {
1624 /* Do not close the dialog */
1625 g_signal_stop_emission_by_name (dialog, "response");
1627 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1628 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1629 gtk_dialog_run (GTK_DIALOG(note));
1630 gtk_widget_destroy (note);
1636 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1637 const gchar *certificate)
1643 win = MODEST_WINDOW (hildon_program_peek_window_stack (hildon_program_get_instance ()));
1646 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1651 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1654 /* We use GTK_RESPONSE_APPLY because we want the button in the
1655 middle of OK and CANCEL the same as the browser does for
1656 example. With GTK_RESPONSE_HELP the view button is aligned
1657 to the left while the other two to the right */
1658 note = hildon_note_new_confirmation_add_buttons (
1661 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1662 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1663 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1666 g_signal_connect (G_OBJECT(note), "response",
1667 G_CALLBACK(on_cert_dialog_response),
1668 (gpointer) certificate);
1670 response = gtk_dialog_run(GTK_DIALOG(note));
1672 on_destroy_dialog (note);
1675 return response == GTK_RESPONSE_OK;
1679 modest_platform_run_alert_dialog (const gchar* prompt,
1680 gboolean is_question)
1682 ModestWindow *main_win;
1684 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1685 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1686 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1687 return is_question ? FALSE : TRUE;
1690 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1691 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1693 gboolean retval = TRUE;
1695 /* The Tinymail documentation says that we should show Yes and No buttons,
1696 * when it is a question.
1697 * Obviously, we need tinymail to use more specific error codes instead,
1698 * so we know what buttons to show. */
1699 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1701 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1702 GTK_WINDOW (dialog), GTK_WINDOW (main_win));
1704 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1705 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1707 on_destroy_dialog (dialog);
1709 /* Just show the error text and use the default response: */
1710 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1718 GtkWindow *parent_window;
1719 ModestConnectedPerformer callback;
1720 TnyAccount *account;
1727 on_went_online_info_free (OnWentOnlineInfo *info)
1729 /* And if we cleanup, we DO cleanup :-) */
1732 g_object_unref (info->device);
1735 if (info->parent_window)
1736 g_object_unref (info->parent_window);
1738 g_object_unref (info->account);
1740 g_slice_free (OnWentOnlineInfo, info);
1742 /* We're done ... */
1748 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1750 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1752 /* Now it's really time to callback to the caller. If going online didn't succeed,
1753 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1754 * canceled will be set. Etcetera etcetera. */
1756 if (info->callback) {
1757 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1760 /* This is our last call, we must cleanup here if we didn't yet do that */
1761 on_went_online_info_free (info);
1768 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1770 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1771 info->iap = g_strdup (iap_id);
1773 if (canceled || err || !info->account) {
1775 /* If there's a problem or if there's no account (then that's it for us, we callback
1776 * the caller's callback now. He'll have to handle err or canceled, of course.
1777 * We are not really online, as the account is not really online here ... */
1779 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1780 * this info. We don't cleanup err, Tinymail does that! */
1782 if (info->callback) {
1784 /* info->account can be NULL here, this means that the user did not
1785 * provide a nice account instance. We'll assume that the user knows
1786 * what he's doing and is happy with just the device going online.
1788 * We can't do magic, we don't know what account the user wants to
1789 * see going online. So just the device goes online, end of story */
1791 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1794 } else if (info->account) {
1796 /* If there's no problem and if we have an account, we'll put the account
1797 * online too. When done, the callback of bringing the account online
1798 * will callback the caller's callback. This is the most normal case. */
1800 info->device = TNY_DEVICE (g_object_ref (device));
1802 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1803 on_account_went_online, info);
1805 /* The on_account_went_online cb frees up the info, go look if you
1806 * don't believe me! (so we return here) */
1811 /* We cleanup if we are not bringing the account online too */
1812 on_went_online_info_free (info);
1818 modest_platform_connect_and_perform (GtkWindow *parent_window,
1820 TnyAccount *account,
1821 ModestConnectedPerformer callback,
1824 gboolean device_online;
1826 TnyConnectionStatus conn_status;
1827 OnWentOnlineInfo *info;
1829 device = modest_runtime_get_device();
1830 device_online = tny_device_is_online (device);
1832 /* If there is no account check only the device status */
1835 if (device_online) {
1837 /* We promise to instantly perform the callback, so ... */
1839 callback (FALSE, NULL, parent_window, account, user_data);
1844 info = g_slice_new0 (OnWentOnlineInfo);
1847 info->device = NULL;
1848 info->account = NULL;
1851 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1853 info->parent_window = NULL;
1854 info->user_data = user_data;
1855 info->callback = callback;
1857 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1858 force, on_conic_device_went_online,
1861 /* We'll cleanup in on_conic_device_went_online */
1864 /* The other code has no more reason to run. This is all that we can do for the
1865 * caller (he should have given us a nice and clean account instance!). We
1866 * can't do magic, we don't know what account he intends to bring online. So
1867 * we'll just bring the device online (and await his false bug report). */
1873 /* Return if the account is already connected */
1875 conn_status = tny_account_get_connection_status (account);
1876 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1878 /* We promise to instantly perform the callback, so ... */
1880 callback (FALSE, NULL, parent_window, account, user_data);
1886 /* Else, we are in a state that requires that we go online before we
1887 * call the caller's callback. */
1889 info = g_slice_new0 (OnWentOnlineInfo);
1891 info->device = NULL;
1893 info->account = TNY_ACCOUNT (g_object_ref (account));
1896 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1898 info->parent_window = NULL;
1900 /* So we'll put the callback away for later ... */
1902 info->user_data = user_data;
1903 info->callback = callback;
1905 if (!device_online) {
1907 /* If also the device is offline, then we connect both the device
1908 * and the account */
1910 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1911 force, on_conic_device_went_online,
1916 /* If the device is online, we'll just connect the account */
1918 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1919 on_account_went_online, info);
1922 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1923 * in both situations, go look if you don't believe me! */
1929 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1931 TnyFolderStore *folder_store,
1932 ModestConnectedPerformer callback,
1935 TnyAccount *account = NULL;
1937 if (!folder_store) {
1938 /* We promise to instantly perform the callback, so ... */
1940 callback (FALSE, NULL, parent_window, NULL, user_data);
1944 } else if (TNY_IS_FOLDER (folder_store)) {
1945 /* Get the folder's parent account: */
1946 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1947 } else if (TNY_IS_ACCOUNT (folder_store)) {
1948 /* Use the folder store as an account: */
1949 account = TNY_ACCOUNT (g_object_ref (folder_store));
1952 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1953 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1954 /* No need to connect a local account */
1956 callback (FALSE, NULL, parent_window, account, user_data);
1961 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1965 g_object_unref (account);
1969 src_account_connect_performer (gboolean canceled,
1971 GtkWindow *parent_window,
1972 TnyAccount *src_account,
1975 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1977 if (canceled || err) {
1978 /* If there was any error call the user callback */
1979 info->callback (canceled, err, parent_window, src_account, info->data);
1981 /* Connect the destination account */
1982 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1983 TNY_FOLDER_STORE (info->dst_account),
1984 info->callback, info->data);
1987 /* Free the info object */
1988 g_object_unref (info->dst_account);
1989 g_slice_free (DoubleConnectionInfo, info);
1994 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
1996 TnyFolderStore *folder_store,
1997 DoubleConnectionInfo *connect_info)
1999 modest_platform_connect_if_remote_and_perform(parent_window,
2002 src_account_connect_performer,
2007 modest_platform_get_account_settings_wizard (void)
2009 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2011 return GTK_WIDGET (dialog);
2015 modest_platform_get_current_connection (void)
2017 TnyDevice *device = NULL;
2018 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2020 device = modest_runtime_get_device ();
2022 if (!tny_device_is_online (device))
2023 return MODEST_CONNECTED_VIA_ANY;
2025 #ifdef MODEST_HAVE_CONIC
2027 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2029 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2030 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2031 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2033 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2034 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2035 !strcmp (bearer_type, "WIMAX")) {
2036 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2038 retval = MODEST_CONNECTED_VIA_ANY;
2041 g_object_unref (iap);
2044 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2045 #endif /* MODEST_HAVE_CONIC */
2052 modest_platform_check_memory_low (ModestWindow *win,
2057 /* are we in low memory state? */
2058 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2060 if (win && lowmem && visuals)
2061 modest_platform_run_information_dialog (
2063 dgettext("ke-recv","memr_ib_operation_disabled"),
2067 g_debug ("%s: low memory reached. disallowing some operations",
2074 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2080 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2083 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2084 GTK_WINDOW (dialog),
2086 gtk_widget_show_all (dialog);
2088 g_signal_connect_swapped (dialog, "response",
2089 G_CALLBACK (gtk_widget_destroy),
2094 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2100 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2103 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2104 GTK_WINDOW (dialog),
2106 gtk_widget_show_all (dialog);
2108 g_signal_connect_swapped (dialog, "response",
2109 G_CALLBACK (gtk_widget_destroy),
2114 modest_platform_get_osso_context (void)
2116 return modest_maemo_utils_get_osso_context ();
2120 _modest_platform_play_email_tone (void)
2122 gchar *active_profile;
2125 gint mail_volume_int;
2127 ca_context *ca_con = NULL;
2128 ca_proplist *pl = NULL;
2130 active_profile = profile_get_profile ();
2131 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2132 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2133 mail_volume_int = profile_parse_int (mail_volume);
2135 if (mail_volume_int > 0) {
2137 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2138 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2142 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2143 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2144 ca_context_destroy(ca_con);
2148 ca_proplist_create(&pl);
2149 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2150 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2152 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2153 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2155 ca_proplist_destroy(pl);
2156 ca_context_destroy(ca_con);
2159 g_free (mail_volume);
2161 g_free (active_profile);
2165 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2166 GtkWidget **folder_view_container)
2170 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2171 GTK_WINDOW (parent_window),
2172 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2173 GTK_DIALOG_DESTROY_WITH_PARENT,
2174 _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2177 /* Create pannable and add it to the dialog */
2178 *folder_view_container = hildon_pannable_area_new ();
2179 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), *folder_view_container);
2181 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);