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-defs.h>
33 #include <modest-platform.h>
34 #include <modest-runtime.h>
35 #include <modest-main-window.h>
36 #include <modest-header-view.h>
37 #include "maemo/modest-maemo-global-settings-dialog.h"
38 #include "modest-widget-memory.h"
39 #include <modest-hildon-includes.h>
40 #include <modest-utils.h>
41 #include <modest-maemo-utils.h>
42 #include <dbus_api/modest-dbus-callbacks.h>
43 #include <maemo/modest-osso-autosave-callbacks.h>
45 #include <tny-maemo-conic-device.h>
46 #include <tny-simple-list.h>
47 #include <tny-folder.h>
48 #include <tny-error.h>
49 #include <tny-merge-folder.h>
50 #include <tny-camel-imap-store-account.h>
51 #include <tny-camel-pop-store-account.h>
52 #include <gtk/gtkicontheme.h>
53 #include <gtk/gtkmenuitem.h>
54 #include <gtk/gtkmain.h>
55 #include <modest-text-utils.h>
56 #include "modest-tny-folder.h"
57 #include "modest-tny-account.h"
59 #include <libgnomevfs/gnome-vfs-mime-utils.h>
60 #include <modest-account-settings-dialog.h>
61 #include <easysetup/modest-easysetup-wizard-dialog.h>
62 #include "modest-hildon-sort-dialog.h"
63 #include <hildon/hildon-sound.h>
65 #include "widgets/modest-details-dialog.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/alarm_event.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_SOUND_FILE "/usr/share/sounds/ui-new_email.wav"
83 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
86 on_modest_conf_update_interval_changed (ModestConf* self,
88 ModestConfEvent event,
89 ModestConfNotificationId id,
92 g_return_if_fail (key);
94 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
95 const guint update_interval_minutes =
96 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
97 modest_platform_set_update_interval (update_interval_minutes);
104 check_required_files (void)
106 FILE *mcc_file = modest_utils_open_mcc_mapping_file ();
109 g_printerr ("modest: check for mcc file failed\n");
115 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
116 access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
117 g_printerr ("modest: cannot find providers data\n");
125 /* the gpointer here is the osso_context. */
127 modest_platform_init (int argc, char *argv[])
129 osso_context_t *osso_context;
131 osso_hw_state_t hw_state = { 0 };
135 if (!check_required_files ()) {
136 g_printerr ("modest: missing required files\n");
140 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
143 g_printerr ("modest: failed to acquire osso context\n");
146 modest_maemo_utils_set_osso_context (osso_context);
148 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
149 g_printerr ("modest: could not get dbus connection\n");
153 /* Add a D-Bus handler to be used when the main osso-rpc
154 * D-Bus handler has not handled something.
155 * We use this for D-Bus methods that need to use more complex types
156 * than osso-rpc supports.
158 if (!dbus_connection_add_filter (con,
159 modest_dbus_req_filter,
163 g_printerr ("modest: Could not add D-Bus filter\n");
167 /* Register our simple D-Bus callbacks, via the osso API: */
168 osso_return_t result = osso_rpc_set_cb_f(osso_context,
172 modest_dbus_req_handler, NULL /* user_data */);
173 if (result != OSSO_OK) {
174 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
178 /* Register hardware event dbus callback: */
179 hw_state.shutdown_ind = TRUE;
180 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
182 /* Register osso auto-save callbacks: */
183 result = osso_application_set_autosave_cb (osso_context,
184 modest_on_osso_application_autosave, NULL /* user_data */);
185 if (result != OSSO_OK) {
186 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
191 /* Make sure that the update interval is changed whenever its gconf key
193 /* CAUTION: we're not using here the
194 modest_conf_listen_to_namespace because we know that there
195 are other parts of Modest listening for this namespace, so
196 we'll receive the notifications anyway. We basically do not
197 use it because there is no easy way to do the
198 modest_conf_forget_namespace */
199 ModestConf *conf = modest_runtime_get_conf ();
200 g_signal_connect (G_OBJECT(conf),
202 G_CALLBACK (on_modest_conf_update_interval_changed),
205 /* only force the setting of the default interval, if there are actually
207 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
209 /* Get the initial update interval from gconf: */
210 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
211 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
212 modest_account_mgr_free_account_names (acc_names);
216 #ifdef MODEST_HAVE_ABOOK
217 /* initialize the addressbook */
218 if (!osso_abook_init (&argc, &argv, osso_context)) {
219 g_printerr ("modest: failed to initialized addressbook\n");
222 #endif /*MODEST_HAVE_ABOOK*/
228 modest_platform_uninit (void)
230 osso_context_t *osso_context =
231 modest_maemo_utils_get_osso_context ();
233 osso_deinitialize (osso_context);
242 modest_platform_get_new_device (void)
244 return TNY_DEVICE (tny_maemo_conic_device_new ());
248 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
249 gchar **effective_mime_type)
251 GString *mime_str = NULL;
252 gchar *icon_name = NULL;
253 gchar **icons, **cursor;
255 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
256 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
258 mime_str = g_string_new (mime_type);
259 g_string_ascii_down (mime_str);
262 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
264 for (cursor = icons; cursor; ++cursor) {
265 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
266 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
267 icon_name = g_strdup ("qgn_list_messagin");
269 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
270 icon_name = g_strdup (*cursor);
276 if (effective_mime_type)
277 *effective_mime_type = g_string_free (mime_str, FALSE);
279 g_string_free (mime_str, TRUE);
286 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
291 g_return_val_if_fail (uri, FALSE);
293 result = hildon_uri_open (uri, action, &err);
295 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
296 uri, action, err && err->message ? err->message : "unknown error");
306 modest_platform_activate_uri (const gchar *uri)
308 HildonURIAction *action;
309 gboolean result = FALSE;
310 GSList *actions, *iter = NULL;
312 g_return_val_if_fail (uri, FALSE);
316 /* don't try to activate file: uri's -- they might confuse the user,
317 * and/or might have security implications */
318 if (!g_str_has_prefix (uri, "file:")) {
320 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
322 for (iter = actions; iter; iter = g_slist_next (iter)) {
323 action = (HildonURIAction*) iter->data;
324 if (action && strcmp (hildon_uri_action_get_service (action),
325 "com.nokia.modest") == 0) {
326 result = checked_hildon_uri_open (uri, action);
331 /* if we could not open it with email, try something else */
333 result = checked_hildon_uri_open (uri, NULL);
337 ModestWindow *parent =
338 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
339 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
340 _("mcen_ib_unsupported_link"));
341 g_debug ("%s: cannot open uri '%s'", __FUNCTION__,uri);
348 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
352 gchar *uri_path = NULL;
354 uri_path = gnome_vfs_get_uri_from_local_path (path);
355 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
358 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
360 result = hildon_mime_open_file (con, uri_path);
362 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
370 } ModestPlatformPopupInfo;
373 delete_uri_popup (GtkWidget *menu,
377 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
379 g_free (popup_info->uri);
380 hildon_uri_free_actions (popup_info->actions);
386 activate_uri_popup_item (GtkMenuItem *menu_item,
390 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
391 const gchar* action_name;
393 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
395 g_printerr ("modest: no action name defined\n");
399 /* special handling for the copy menu item -- copy the uri to the clipboard */
400 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
401 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
402 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
403 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
405 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
406 action_name += strlen ("mailto:");
408 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
409 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
410 return; /* we're done */
413 /* now, the real uri-actions... */
414 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
415 HildonURIAction *action = (HildonURIAction *) node->data;
416 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
417 if (!checked_hildon_uri_open (popup_info->uri, action)) {
418 ModestWindow *parent =
419 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
420 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
421 _("mcen_ib_unsupported_link"));
429 modest_platform_show_uri_popup (const gchar *uri)
431 GSList *actions_list;
436 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
439 GtkWidget *menu = gtk_menu_new ();
440 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
442 /* don't add actions for file: uri's -- they might confuse the user,
443 * and/or might have security implications
444 * we still allow to copy the url though
446 if (!g_str_has_prefix (uri, "file:")) {
449 popup_info->actions = actions_list;
450 popup_info->uri = g_strdup (uri);
452 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
453 GtkWidget *menu_item;
454 const gchar *action_name;
455 const gchar *translation_domain;
456 HildonURIAction *action = (HildonURIAction *) node->data;
457 action_name = hildon_uri_action_get_name (action);
458 translation_domain = hildon_uri_action_get_translation_domain (action);
459 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
460 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
461 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
464 if (hildon_uri_is_default_action (action, NULL)) {
465 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
467 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
469 gtk_widget_show (menu_item);
473 /* always add the copy item */
474 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
475 "uri_link_copy_link_location"));
476 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
477 g_strconcat (URI_ACTION_COPY, uri, NULL),
479 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
480 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
481 gtk_widget_show (menu_item);
484 /* and what to do when the link is deleted */
485 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
486 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
489 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
497 modest_platform_get_icon (const gchar *name, guint icon_size)
500 GdkPixbuf* pixbuf = NULL;
501 GtkIconTheme *current_theme = NULL;
503 g_return_val_if_fail (name, NULL);
505 /* strlen == 0 is not really an error; it just
506 * means the icon is not available
508 if (!name || strlen(name) == 0)
511 current_theme = gtk_icon_theme_get_default ();
512 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
513 GTK_ICON_LOOKUP_NO_SVG,
516 g_warning ("Error loading theme icon '%s': %s\n",
524 modest_platform_get_app_name (void)
526 return _("mcen_ap_name");
530 entry_insert_text (GtkEditable *editable,
539 chars = gtk_editable_get_chars (editable, 0, -1);
540 chars_length = g_utf8_strlen (chars, -1);
543 /* Show WID-INF036 */
544 if (chars_length >= 20) {
545 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
546 _CS("ckdg_ib_maximum_characters_reached"));
548 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
552 tmp = g_strndup (folder_name_forbidden_chars,
553 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
554 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
555 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
560 /* Write the text in the entry if it's valid */
561 g_signal_handlers_block_by_func (editable,
562 (gpointer) entry_insert_text, data);
563 gtk_editable_insert_text (editable, text, length, position);
564 g_signal_handlers_unblock_by_func (editable,
565 (gpointer) entry_insert_text, data);
568 /* Do not allow further processing */
569 g_signal_stop_emission_by_name (editable, "insert_text");
573 entry_changed (GtkEditable *editable,
577 GtkWidget *ok_button;
580 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
581 ok_button = GTK_WIDGET (buttons->next->data);
583 chars = gtk_editable_get_chars (editable, 0, -1);
584 g_return_if_fail (chars != NULL);
587 if (g_utf8_strlen (chars,-1) >= 21)
588 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
589 _CS("ckdg_ib_maximum_characters_reached"));
591 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
594 g_list_free (buttons);
601 on_response (GtkDialog *dialog,
605 GList *child_vbox, *child_hbox;
606 GtkWidget *hbox, *entry;
607 TnyFolderStore *parent;
608 const gchar *new_name;
611 if (response != GTK_RESPONSE_ACCEPT)
615 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
616 hbox = child_vbox->data;
617 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
618 entry = child_hbox->next->data;
620 parent = TNY_FOLDER_STORE (user_data);
621 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
624 /* Look for another folder with the same name */
625 if (modest_tny_folder_has_subfolder_with_name (parent,
632 if (TNY_IS_ACCOUNT (parent) &&
633 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
634 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
643 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
644 NULL, _CS("ckdg_ib_folder_already_exists"));
645 /* Select the text */
646 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
647 gtk_widget_grab_focus (entry);
648 /* Do not close the dialog */
649 g_signal_stop_emission_by_name (dialog, "response");
656 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
657 TnyFolderStore *parent,
658 const gchar *dialog_title,
659 const gchar *label_text,
660 const gchar *suggested_name,
663 GtkWidget *accept_btn = NULL;
664 GtkWidget *dialog, *entry, *label, *hbox;
665 GList *buttons = NULL;
668 /* Ask the user for the folder name */
669 dialog = gtk_dialog_new_with_buttons (dialog_title,
671 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
672 _("mcen_bd_dialog_ok"),
674 _("mcen_bd_dialog_cancel"),
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->next->data);
681 /* Create label and entry */
682 label = gtk_label_new (label_text);
683 /* TODO: check that the suggested name does not exist */
684 /* We set 21 as maximum because we want to show WID-INF036
685 when the user inputs more that 20 */
686 entry = gtk_entry_new_with_max_length (21);
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), GTK_WINDOW (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 *suggested_parent,
745 gchar *suggested_name,
747 TnyFolderStore **parent_folder)
749 gchar *real_suggested_name = NULL, *tmp = NULL;
752 if(suggested_name == NULL)
754 const gchar *default_name = _("mcen_ia_default_folder_name");
758 for(i = 0; i < 100; ++ i) {
759 gboolean exists = FALSE;
761 sprintf(num_str, "%.2u", i);
764 real_suggested_name = g_strdup (default_name);
766 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
768 exists = modest_tny_folder_has_subfolder_with_name (suggested_parent,
775 g_free (real_suggested_name);
778 /* Didn't find a free number */
780 real_suggested_name = g_strdup (default_name);
782 real_suggested_name = suggested_name;
785 tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
786 result = modest_platform_run_folder_name_dialog (parent_window,
788 _("mcen_ti_new_folder"),
794 if (suggested_name == NULL)
795 g_free(real_suggested_name);
797 if (parent_folder != NULL) {
798 *parent_folder = suggested_parent?g_object_ref (suggested_parent): NULL;
805 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
806 TnyFolderStore *parent_folder,
807 const gchar *suggested_name,
810 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
812 return modest_platform_run_folder_name_dialog (parent_window,
814 _HL("ckdg_ti_rename_folder"),
815 _HL("ckdg_fi_rename_name"),
823 on_destroy_dialog (GtkWidget *dialog)
825 /* This could happen when the dialogs get programatically
826 hidden or destroyed (for example when closing the
827 application while a dialog is being shown) */
828 if (!GTK_IS_WIDGET (dialog))
831 gtk_widget_destroy (dialog);
833 if (gtk_events_pending ())
834 gtk_main_iteration ();
838 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
839 const gchar *message)
844 dialog = hildon_note_new_confirmation (parent_window, message);
845 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
846 GTK_WINDOW (dialog), GTK_WINDOW (parent_window));
848 response = gtk_dialog_run (GTK_DIALOG (dialog));
850 on_destroy_dialog (dialog);
856 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
857 const gchar *message,
858 const gchar *button_accept,
859 const gchar *button_cancel)
864 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
865 button_accept, GTK_RESPONSE_ACCEPT,
866 button_cancel, GTK_RESPONSE_CANCEL,
868 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
869 GTK_WINDOW (dialog), GTK_WINDOW (parent_window));
871 response = gtk_dialog_run (GTK_DIALOG (dialog));
873 on_destroy_dialog (dialog);
879 modest_platform_run_information_dialog (GtkWindow *parent_window,
880 const gchar *message,
885 note = hildon_note_new_information (parent_window, message);
887 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
888 GTK_WINDOW (note), GTK_WINDOW (parent_window));
891 gtk_dialog_run (GTK_DIALOG (note));
893 on_destroy_dialog (note);
895 g_signal_connect_swapped (note,
897 G_CALLBACK (on_destroy_dialog),
900 gtk_widget_show_all (note);
904 typedef struct _ConnectAndWaitData {
906 GMainLoop *wait_loop;
907 gboolean has_callback;
909 } ConnectAndWaitData;
913 quit_wait_loop (TnyAccount *account,
914 ConnectAndWaitData *data)
916 /* Set the has_callback to TRUE (means that the callback was
917 executed and wake up every code waiting for cond to be
919 g_mutex_lock (data->mutex);
920 data->has_callback = TRUE;
922 g_main_loop_quit (data->wait_loop);
923 g_mutex_unlock (data->mutex);
927 on_connection_status_changed (TnyAccount *account,
928 TnyConnectionStatus status,
931 TnyConnectionStatus conn_status;
932 ConnectAndWaitData *data;
934 /* Ignore if reconnecting or disconnected */
935 conn_status = tny_account_get_connection_status (account);
936 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
937 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
940 /* Remove the handler */
941 data = (ConnectAndWaitData *) user_data;
942 g_signal_handler_disconnect (account, data->handler);
944 /* Quit from wait loop */
945 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
949 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
954 /* Quit from wait loop */
955 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
959 modest_platform_connect_and_wait (GtkWindow *parent_window,
962 ConnectAndWaitData *data = NULL;
963 gboolean device_online;
965 TnyConnectionStatus conn_status;
966 gboolean user_requested;
968 device = modest_runtime_get_device();
969 device_online = tny_device_is_online (device);
971 /* Whether the connection is user requested or automatically
972 requested, for example via D-Bus */
973 user_requested = (parent_window) ? TRUE : FALSE;
975 /* If there is no account check only the device status */
980 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
981 NULL, user_requested);
984 /* Return if the account is already connected */
985 conn_status = tny_account_get_connection_status (account);
986 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
989 /* Create the helper */
990 data = g_slice_new0 (ConnectAndWaitData);
991 data->mutex = g_mutex_new ();
992 data->has_callback = FALSE;
994 /* Connect the device */
995 if (!device_online) {
996 /* Track account connection status changes */
997 data->handler = g_signal_connect (account, "connection-status-changed",
998 G_CALLBACK (on_connection_status_changed),
1000 /* Try to connect the device */
1001 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1002 NULL, user_requested);
1004 /* If the device connection failed then exit */
1005 if (!device_online && data->handler)
1008 /* Force a reconnection of the account */
1009 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1010 on_tny_camel_account_set_online_cb, data);
1013 /* Wait until the callback is executed */
1014 g_mutex_lock (data->mutex);
1015 if (!data->has_callback) {
1016 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1017 gdk_threads_leave ();
1018 g_mutex_unlock (data->mutex);
1019 g_main_loop_run (data->wait_loop);
1020 g_mutex_lock (data->mutex);
1021 gdk_threads_enter ();
1023 g_mutex_unlock (data->mutex);
1027 if (g_signal_handler_is_connected (account, data->handler))
1028 g_signal_handler_disconnect (account, data->handler);
1029 g_mutex_free (data->mutex);
1030 g_main_loop_unref (data->wait_loop);
1031 g_slice_free (ConnectAndWaitData, data);
1034 conn_status = tny_account_get_connection_status (account);
1035 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1039 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1041 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1042 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1043 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1044 /* This must be a maildir account, which does not require a connection: */
1049 return modest_platform_connect_and_wait (parent_window, account);
1053 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1056 return TRUE; /* Maybe it is something local. */
1058 gboolean result = TRUE;
1059 if (TNY_IS_FOLDER (folder_store)) {
1060 /* Get the folder's parent account: */
1061 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1062 if (account != NULL) {
1063 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1064 g_object_unref (account);
1066 } else if (TNY_IS_ACCOUNT (folder_store)) {
1067 /* Use the folder store as an account: */
1068 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1075 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1079 dialog = modest_hildon_sort_dialog_new (parent_window);
1081 hildon_help_dialog_help_enable (GTK_DIALOG(dialog),
1082 "applications_email_sort",
1083 modest_maemo_utils_get_osso_context());
1090 modest_platform_set_update_interval (guint minutes)
1092 #ifdef MODEST_HAVE_LIBALARM
1094 ModestConf *conf = modest_runtime_get_conf ();
1098 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1100 /* Delete any existing alarm,
1101 * because we will replace it: */
1103 if (alarm_event_del(alarm_cookie) != 1)
1104 g_debug ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1106 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1109 /* 0 means no updates: */
1114 /* Register alarm: */
1116 /* Set the interval in alarm_event_t structure: */
1117 alarm_event_t *event = g_new0(alarm_event_t, 1);
1118 event->alarm_time = minutes * 60; /* seconds */
1120 /* Set recurrence every few minutes: */
1121 event->recurrence = minutes;
1122 event->recurrence_count = -1; /* Means infinite */
1124 /* Specify what should happen when the alarm happens:
1125 * It should call this D-Bus method: */
1127 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1128 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1129 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1130 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1132 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1133 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1134 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1135 * This is why we want to use the Alarm API instead of just g_timeout_add().
1136 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1137 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1139 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION | ALARM_EVENT_CONNECTED;
1141 alarm_cookie = alarm_event_add (event);
1144 alarm_event_free (event);
1146 /* Store the alarm ID in GConf, so we can remove it later:
1147 * This is apparently valid between application instances. */
1148 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1150 if (!alarm_cookie) {
1152 const alarm_error_t alarm_error = alarmd_get_error ();
1153 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1155 /* Give people some clue: */
1156 /* The alarm API should have a function for this: */
1157 if (alarm_error == ALARMD_ERROR_DBUS) {
1158 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1159 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1160 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1161 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1162 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1163 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1164 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1165 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1166 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1167 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1168 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1173 #endif /* MODEST_HAVE_LIBALARM */
1178 modest_platform_push_email_notification(void)
1180 gboolean play_sound;
1181 ModestWindow *main_window;
1182 gboolean screen_on = TRUE, app_in_foreground;
1184 /* Check whether or not we should play a sound */
1185 play_sound = modest_conf_get_bool (modest_runtime_get_conf (),
1186 MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1189 /* Get the screen status */
1190 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1192 screen_on = modest_main_window_screen_is_on (MODEST_MAIN_WINDOW (main_window));
1194 /* Get the window status */
1195 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1197 /* If the screen is on and the app is in the
1198 foreground we don't show anything */
1199 if (!(screen_on && app_in_foreground)) {
1202 hildon_play_system_sound (MODEST_NEW_MAIL_SOUND_FILE);
1204 /* Activate LED. This must be deactivated by
1205 modest_platform_remove_new_mail_notifications */
1206 #ifdef MODEST_HAVE_MCE
1207 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1211 MCE_ACTIVATE_LED_PATTERN,
1213 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1220 modest_platform_on_new_headers_received (GList *URI_list,
1221 gboolean show_visual)
1223 if (g_list_length (URI_list) == 0)
1227 modest_platform_push_email_notification ();
1228 /* We do a return here to avoid indentation with an else */
1232 #ifdef MODEST_HAVE_HILDON_NOTIFY
1233 gboolean play_sound;
1235 /* Check whether or not we should play a sound */
1236 play_sound = modest_conf_get_bool (modest_runtime_get_conf (),
1237 MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1240 HildonNotification *notification;
1242 GSList *notifications_list = NULL;
1244 /* Get previous notifications ids */
1245 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1246 MODEST_CONF_NOTIFICATION_IDS,
1247 MODEST_CONF_VALUE_INT, NULL);
1251 gchar *display_address = NULL;
1252 gboolean first_notification = TRUE;
1254 ModestMsgNotificationData *data;
1256 data = (ModestMsgNotificationData *) iter->data;
1258 display_address = g_strdup (data->from);
1259 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1261 notification = hildon_notification_new (display_address,
1263 "qgn_list_messagin",
1265 g_free (display_address);
1267 /* Add DBus action */
1268 hildon_notification_add_dbus_action(notification,
1271 MODEST_DBUS_SERVICE,
1274 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1275 G_TYPE_STRING, data->uri,
1278 /* Play sound if the user wants. Show the LED
1279 pattern. Show and play just one */
1280 if (G_UNLIKELY (first_notification)) {
1281 first_notification = FALSE;
1283 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1284 "sound-file", MODEST_NEW_MAIL_SOUND_FILE);
1287 /* Set the led pattern */
1288 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1290 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1292 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1295 /* Notify. We need to do this in an idle because this function
1296 could be called from a thread */
1297 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1299 /* Save id in the list */
1300 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1301 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1302 /* We don't listen for the "closed" signal, because we
1303 don't care about if the notification was removed or
1304 not to store the list in gconf */
1306 iter = g_list_next (iter);
1310 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1311 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1313 g_slist_free (notifications_list);
1315 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1319 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1322 #ifdef MODEST_HAVE_MCE
1323 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1327 MCE_DEACTIVATE_LED_PATTERN,
1329 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1335 #ifdef MODEST_HAVE_HILDON_NOTIFY
1336 GSList *notif_list = NULL;
1338 /* Get previous notifications ids */
1339 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1340 MODEST_CONF_NOTIFICATION_IDS,
1341 MODEST_CONF_VALUE_INT, NULL);
1343 while (notif_list) {
1345 NotifyNotification *notif;
1347 /* Nasty HACK to remove the notifications, set the id
1348 of the existing ones and then close them */
1349 notif_id = GPOINTER_TO_INT(notif_list->data);
1350 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1351 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1353 /* Close the notification, note that some ids could be
1354 already invalid, but we don't care because it does
1356 notify_notification_close(notif, NULL);
1357 g_object_unref(notif);
1359 /* Delete the link, it's like going to the next */
1360 notif_list = g_slist_delete_link (notif_list, notif_list);
1364 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1365 notif_list, MODEST_CONF_VALUE_INT, NULL);
1367 g_slist_free (notif_list);
1369 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1375 modest_platform_get_global_settings_dialog ()
1377 return modest_maemo_global_settings_dialog_new ();
1381 modest_platform_show_help (GtkWindow *parent_window,
1382 const gchar *help_id)
1384 osso_return_t result;
1385 g_return_if_fail (help_id);
1387 result = hildon_help_show (modest_maemo_utils_get_osso_context(),
1388 help_id, HILDON_HELP_SHOW_DIALOG);
1390 if (result != OSSO_OK) {
1392 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1393 hildon_banner_show_information (GTK_WIDGET (parent_window),
1401 modest_platform_show_search_messages (GtkWindow *parent_window)
1403 osso_return_t result = OSSO_ERROR;
1405 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1406 "osso_global_search",
1407 "search_email", NULL, DBUS_TYPE_INVALID);
1409 if (result != OSSO_OK) {
1410 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1415 modest_platform_show_addressbook (GtkWindow *parent_window)
1417 osso_return_t result = OSSO_ERROR;
1419 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1421 "top_application", NULL, DBUS_TYPE_INVALID);
1423 if (result != OSSO_OK) {
1424 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1429 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1431 GtkWidget *widget = modest_folder_view_new (query);
1433 /* Show one account by default */
1434 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1435 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1437 /* Restore settings */
1438 modest_widget_memory_restore (modest_runtime_get_conf(),
1440 MODEST_CONF_FOLDER_VIEW_KEY);
1446 banner_finish (gpointer data, GObject *object)
1448 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1449 modest_window_mgr_unregister_banner (mgr);
1450 g_object_unref (mgr);
1454 modest_platform_information_banner (GtkWidget *parent,
1455 const gchar *icon_name,
1458 GtkWidget *banner_parent = NULL;
1459 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1461 if (modest_window_mgr_get_num_windows (mgr) == 0)
1464 if (parent && GTK_IS_WINDOW (parent)) {
1465 /* If the window is the active one then show the
1466 banner on top of this window */
1467 if (gtk_window_is_active (GTK_WINDOW (parent)))
1468 banner_parent = parent;
1469 /* If the window is not the topmost but it's visible
1470 (it's minimized for example) then show the banner
1472 else if (GTK_WIDGET_VISIBLE (parent))
1473 banner_parent = NULL;
1474 /* If the window is hidden (like the main window when
1475 running in the background) then do not show
1481 modest_platform_system_banner (banner_parent, icon_name, text);
1486 modest_platform_system_banner (GtkWidget *parent,
1487 const gchar *icon_name,
1490 GtkWidget *banner = NULL;
1491 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1494 if (parent && GTK_IS_WINDOW (parent)) {
1495 if (!gtk_window_is_active (GTK_WINDOW (parent)))
1499 banner = hildon_banner_show_information (parent, icon_name, text);
1501 modest_window_mgr_register_banner (mgr);
1503 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1507 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1508 const gchar *icon_name,
1514 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1517 banner = hildon_banner_show_information (parent, icon_name, text);
1518 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1522 modest_platform_animation_banner (GtkWidget *parent,
1523 const gchar *animation_name,
1526 GtkWidget *inf_note = NULL;
1528 g_return_val_if_fail (text != NULL, NULL);
1530 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1533 /* If the parent is not visible then do not show */
1534 if (parent && !GTK_WIDGET_VISIBLE (parent))
1537 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1545 TnyAccount *account;
1548 } CheckAccountIdleData;
1550 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1553 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1555 gboolean stop_trying = FALSE;
1556 g_return_val_if_fail (data && data->account, FALSE);
1558 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1559 tny_account_get_connection_status (data->account));
1561 if (data && data->account &&
1562 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1563 * after which the account is likely to be usable, or never likely to be usable soon: */
1564 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1566 data->is_online = TRUE;
1570 /* Give up if we have tried too many times: */
1571 if (data->count_tries >= NUMBER_OF_TRIES) {
1574 /* Wait for another timeout: */
1575 ++(data->count_tries);
1580 /* Allow the function that requested this idle callback to continue: */
1582 g_main_loop_quit (data->loop);
1585 g_object_unref (data->account);
1587 return FALSE; /* Don't call this again. */
1589 return TRUE; /* Call this timeout callback again. */
1593 /* Return TRUE immediately if the account is already online,
1594 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1595 * soon as the account is online, or FALSE if the account does
1596 * not become online in the NUMBER_OF_TRIES seconds.
1597 * This is useful when the D-Bus method was run immediately after
1598 * the application was started (when using D-Bus activation),
1599 * because the account usually takes a short time to go online.
1600 * The return value is maybe not very useful.
1603 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1607 g_return_val_if_fail (account, FALSE);
1609 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1611 if (!tny_device_is_online (modest_runtime_get_device())) {
1612 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1616 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1617 * so we avoid wait unnecessarily: */
1618 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1619 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1623 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1624 __FUNCTION__, tny_account_get_connection_status (account));
1626 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1627 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1628 * we want to avoid. */
1629 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1632 /* This blocks on the result: */
1633 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1634 data->is_online = FALSE;
1635 data->account = account;
1636 g_object_ref (data->account);
1637 data->count_tries = 0;
1639 GMainContext *context = NULL; /* g_main_context_new (); */
1640 data->loop = g_main_loop_new (context, FALSE /* not running */);
1642 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1644 /* This main loop will run until the idle handler has stopped it: */
1645 g_main_loop_run (data->loop);
1647 g_main_loop_unref (data->loop);
1648 /* g_main_context_unref (context); */
1650 is_online = data->is_online;
1651 g_slice_free (CheckAccountIdleData, data);
1659 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1661 /* GTK_RESPONSE_HELP means we need to show the certificate */
1662 if (response_id == GTK_RESPONSE_APPLY) {
1666 /* Do not close the dialog */
1667 g_signal_stop_emission_by_name (dialog, "response");
1669 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1670 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1671 gtk_dialog_run (GTK_DIALOG(note));
1672 gtk_widget_destroy (note);
1678 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1679 const gchar *certificate)
1683 ModestWindow *main_win;
1685 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1686 g_debug ("%s: don't show dialogs if there's no main window; assuming 'Cancel'",
1691 /* don't create it */
1692 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
1693 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1696 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1699 /* We use GTK_RESPONSE_APPLY because we want the button in the
1700 middle of OK and CANCEL the same as the browser does for
1701 example. With GTK_RESPONSE_HELP the view button is aligned
1702 to the left while the other two to the right */
1703 note = hildon_note_new_confirmation_add_buttons (
1704 GTK_WINDOW(main_win),
1706 _("mcen_bd_dialog_ok"), GTK_RESPONSE_OK,
1707 _("mcen_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1708 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1711 g_signal_connect (G_OBJECT(note), "response",
1712 G_CALLBACK(on_cert_dialog_response),
1713 (gpointer) certificate);
1715 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1716 GTK_WINDOW (note), (GtkWindow *) main_win);
1717 response = gtk_dialog_run(GTK_DIALOG(note));
1719 on_destroy_dialog (note);
1722 return response == GTK_RESPONSE_OK;
1726 modest_platform_run_alert_dialog (const gchar* prompt,
1727 gboolean is_question)
1729 ModestWindow *main_win;
1731 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1732 g_debug ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1733 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1734 return is_question ? FALSE : TRUE;
1737 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1738 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1740 gboolean retval = TRUE;
1742 /* The Tinymail documentation says that we should show Yes and No buttons,
1743 * when it is a question.
1744 * Obviously, we need tinymail to use more specific error codes instead,
1745 * so we know what buttons to show. */
1746 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1748 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1749 GTK_WINDOW (dialog), (GtkWindow *) main_win);
1751 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1752 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1754 on_destroy_dialog (dialog);
1756 /* Just show the error text and use the default response: */
1757 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1765 GtkWindow *parent_window;
1766 ModestConnectedPerformer callback;
1767 TnyAccount *account;
1774 on_went_online_info_free (OnWentOnlineInfo *info)
1776 /* And if we cleanup, we DO cleanup :-) */
1779 g_object_unref (info->device);
1782 if (info->parent_window)
1783 g_object_unref (info->parent_window);
1785 g_object_unref (info->account);
1787 g_slice_free (OnWentOnlineInfo, info);
1789 /* We're done ... */
1795 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1797 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1799 /* Now it's really time to callback to the caller. If going online didn't succeed,
1800 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1801 * canceled will be set. Etcetera etcetera. */
1803 if (info->callback) {
1804 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1807 /* This is our last call, we must cleanup here if we didn't yet do that */
1808 on_went_online_info_free (info);
1815 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1817 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1818 info->iap = g_strdup (iap_id);
1820 if (canceled || err || !info->account) {
1822 /* If there's a problem or if there's no account (then that's it for us, we callback
1823 * the caller's callback now. He'll have to handle err or canceled, of course.
1824 * We are not really online, as the account is not really online here ... */
1826 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1827 * this info. We don't cleanup err, Tinymail does that! */
1829 if (info->callback) {
1831 /* info->account can be NULL here, this means that the user did not
1832 * provide a nice account instance. We'll assume that the user knows
1833 * what he's doing and is happy with just the device going online.
1835 * We can't do magic, we don't know what account the user wants to
1836 * see going online. So just the device goes online, end of story */
1838 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1841 } else if (info->account) {
1843 /* If there's no problem and if we have an account, we'll put the account
1844 * online too. When done, the callback of bringing the account online
1845 * will callback the caller's callback. This is the most normal case. */
1847 info->device = TNY_DEVICE (g_object_ref (device));
1849 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1850 on_account_went_online, info);
1852 /* The on_account_went_online cb frees up the info, go look if you
1853 * don't believe me! (so we return here) */
1858 /* We cleanup if we are not bringing the account online too */
1859 on_went_online_info_free (info);
1865 modest_platform_connect_and_perform (GtkWindow *parent_window,
1867 TnyAccount *account,
1868 ModestConnectedPerformer callback,
1871 gboolean device_online;
1873 TnyConnectionStatus conn_status;
1874 OnWentOnlineInfo *info;
1876 device = modest_runtime_get_device();
1877 device_online = tny_device_is_online (device);
1879 /* If there is no account check only the device status */
1882 if (device_online) {
1884 /* We promise to instantly perform the callback, so ... */
1886 callback (FALSE, NULL, parent_window, account, user_data);
1891 info = g_slice_new0 (OnWentOnlineInfo);
1894 info->device = NULL;
1895 info->account = NULL;
1898 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1900 info->parent_window = NULL;
1901 info->user_data = user_data;
1902 info->callback = callback;
1904 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1905 force, on_conic_device_went_online,
1908 /* We'll cleanup in on_conic_device_went_online */
1911 /* The other code has no more reason to run. This is all that we can do for the
1912 * caller (he should have given us a nice and clean account instance!). We
1913 * can't do magic, we don't know what account he intends to bring online. So
1914 * we'll just bring the device online (and await his false bug report). */
1920 /* Return if the account is already connected */
1922 conn_status = tny_account_get_connection_status (account);
1923 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1925 /* We promise to instantly perform the callback, so ... */
1927 callback (FALSE, NULL, parent_window, account, user_data);
1933 /* Else, we are in a state that requires that we go online before we
1934 * call the caller's callback. */
1936 info = g_slice_new0 (OnWentOnlineInfo);
1938 info->device = NULL;
1940 info->account = TNY_ACCOUNT (g_object_ref (account));
1943 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1945 info->parent_window = NULL;
1947 /* So we'll put the callback away for later ... */
1949 info->user_data = user_data;
1950 info->callback = callback;
1952 if (!device_online) {
1954 /* If also the device is offline, then we connect both the device
1955 * and the account */
1957 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1958 force, on_conic_device_went_online,
1963 /* If the device is online, we'll just connect the account */
1965 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1966 on_account_went_online, info);
1969 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1970 * in both situations, go look if you don't believe me! */
1976 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1978 TnyFolderStore *folder_store,
1979 ModestConnectedPerformer callback,
1982 TnyAccount *account = NULL;
1984 if (!folder_store ||
1985 (TNY_IS_MERGE_FOLDER (folder_store) &&
1986 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1988 /* We promise to instantly perform the callback, so ... */
1990 GError *error = NULL;
1991 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1992 "Unable to move or not found folder");
1993 callback (FALSE, error, parent_window, NULL, user_data);
1994 g_error_free (error);
1998 } else if (TNY_IS_FOLDER (folder_store)) {
1999 /* Get the folder's parent account: */
2000 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2001 } else if (TNY_IS_ACCOUNT (folder_store)) {
2002 /* Use the folder store as an account: */
2003 account = TNY_ACCOUNT (g_object_ref (folder_store));
2006 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2007 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
2008 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
2010 /* No need to connect a local account */
2012 callback (FALSE, NULL, parent_window, account, user_data);
2017 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2021 g_object_unref (account);
2025 src_account_connect_performer (gboolean canceled,
2027 GtkWindow *parent_window,
2028 TnyAccount *src_account,
2031 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2033 if (canceled || err) {
2034 /* If there was any error call the user callback */
2035 info->callback (canceled, err, parent_window, src_account, info->data);
2037 /* Connect the destination account */
2038 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2039 TNY_FOLDER_STORE (info->dst_account),
2040 info->callback, info->data);
2043 /* Free the info object */
2044 g_object_unref (info->dst_account);
2045 g_slice_free (DoubleConnectionInfo, info);
2050 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2052 TnyFolderStore *folder_store,
2053 DoubleConnectionInfo *connect_info)
2055 modest_platform_connect_if_remote_and_perform(parent_window,
2058 src_account_connect_performer,
2063 modest_platform_get_account_settings_wizard (void)
2065 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2067 return GTK_WIDGET (dialog);
2071 modest_platform_get_current_connection (void)
2073 TnyDevice *device = NULL;
2074 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2076 device = modest_runtime_get_device ();
2078 if (!tny_device_is_online (device))
2079 return MODEST_CONNECTED_VIA_ANY;
2081 #ifdef MODEST_HAVE_CONIC
2083 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2085 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2086 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2087 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2089 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2090 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2091 !strcmp (bearer_type, "WIMAX")) {
2092 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2094 retval = MODEST_CONNECTED_VIA_ANY;
2097 g_object_unref (iap);
2100 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2101 #endif /* MODEST_HAVE_CONIC */
2106 modest_platform_check_memory_low (ModestWindow *win,
2111 /* are we in low memory state? */
2112 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2114 if (win && lowmem && visuals)
2115 modest_platform_run_information_dialog (
2117 _KR("memr_ib_operation_disabled"),
2121 g_debug ("%s: low memory reached. disallowing some operations",
2128 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2134 dialog = modest_details_dialog_new_with_folder (parent_window, folder);
2137 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2138 GTK_WINDOW (dialog),
2140 gtk_widget_show_all (dialog);
2142 g_signal_connect_swapped (dialog, "response",
2143 G_CALLBACK (gtk_widget_destroy),
2148 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2150 gboolean async_get_size,
2156 dialog = modest_details_dialog_new_with_header (parent_window, header, TRUE);
2159 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2160 GTK_WINDOW (dialog),
2162 gtk_widget_show_all (dialog);
2164 g_signal_connect_swapped (dialog, "response",
2165 G_CALLBACK (gtk_widget_destroy),
2170 modest_platform_get_osso_context (void)
2172 return modest_maemo_utils_get_osso_context ();
2176 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2177 GtkWidget **folder_view)
2179 GtkWidget *dialog, *folder_view_container;
2181 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2182 GTK_WINDOW (parent_window),
2183 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2184 GTK_DIALOG_DESTROY_WITH_PARENT,
2185 _("mcen_bd_dialog_ok"), GTK_RESPONSE_OK,
2186 _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2187 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
2190 /* Create folder view */
2191 *folder_view = modest_platform_create_folder_view (NULL);
2193 /* Create pannable and add it to the dialog */
2194 folder_view_container = gtk_scrolled_window_new (NULL, NULL);
2195 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_view_container),
2196 GTK_POLICY_AUTOMATIC,
2197 GTK_POLICY_AUTOMATIC);
2198 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2199 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2201 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2203 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2204 gtk_widget_show (folder_view_container);
2205 gtk_widget_show (*folder_view);
2212 modest_platform_get_list_to_move (ModestWindow *window)
2214 TnyList *list = NULL;
2216 /* If it's a main window then it could be that we're moving a
2217 folder or a set of messages */
2218 if (MODEST_IS_MAIN_WINDOW (window)) {
2219 ModestHeaderView *header_view = NULL;
2220 ModestFolderView *folder_view = NULL;
2222 folder_view = (ModestFolderView *)
2223 modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (window),
2224 MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
2225 header_view = (ModestHeaderView *)
2226 modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (window),
2227 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2229 /* Get folder or messages to transfer */
2230 if (gtk_widget_is_focus (GTK_WIDGET (folder_view))) {
2231 TnyFolderStore *src_folder;
2233 src_folder = modest_folder_view_get_selected (folder_view);
2235 list = tny_simple_list_new ();
2236 tny_list_prepend (list, G_OBJECT (src_folder));
2237 g_object_unref (src_folder);
2239 } else if (gtk_widget_is_focus (GTK_WIDGET(header_view))) {
2240 list = modest_header_view_get_selected_headers(header_view);
2242 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2243 TnyHeader *header = NULL;
2245 /* We simply return the currently viewed message */
2246 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2248 list = tny_simple_list_new ();
2249 tny_list_prepend (list, G_OBJECT (header));
2250 g_object_unref (header);
2253 g_return_val_if_reached (NULL);