1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
32 #include <modest-platform.h>
33 #include <modest-runtime.h>
34 #include <modest-main-window.h>
35 #include <modest-header-view.h>
36 #include "modest-hildon2-global-settings-dialog.h"
37 #include "modest-widget-memory.h"
38 #include <modest-hildon-includes.h>
39 #include <modest-maemo-utils.h>
40 #include <dbus_api/modest-dbus-callbacks.h>
41 #include <modest-osso-autosave-callbacks.h>
43 #include <tny-maemo-conic-device.h>
44 #include <tny-simple-list.h>
45 #include <tny-folder.h>
46 #include <gtk/gtkicontheme.h>
47 #include <gtk/gtkmenuitem.h>
48 #include <gtk/gtkmain.h>
49 #include <modest-text-utils.h>
50 #include "modest-tny-folder.h"
51 #include "modest-tny-account.h"
53 #include <libgnomevfs/gnome-vfs-mime-utils.h>
54 #include <modest-account-settings-dialog.h>
55 #include <modest-easysetup-wizard-dialog.h>
56 #include "modest-hildon2-sort-dialog.h"
57 #include <hildon/hildon-sound.h>
59 #include "hildon2/modest-hildon2-details-dialog.h"
60 #include "hildon2/modest-hildon2-window-mgr.h"
61 #include <keys_nokia.h>
62 #include <libprofile.h>
64 #include <modest-datetime-formatter.h>
65 #include "modest-header-window.h"
66 #include <modest-folder-window.h>
67 #include <modest-account-mgr.h>
68 #include <modest-account-mgr-helpers.h>
69 #include <modest-ui-constants.h>
70 #include <modest-selector-picker.h>
71 #include <modest-icon-names.h>
73 #ifdef MODEST_HAVE_MCE
74 #include <mce/dbus-names.h>
75 #endif /*MODEST_HAVE_MCE*/
77 #ifdef MODEST_HAVE_ABOOK
78 #include <libosso-abook/osso-abook.h>
79 #endif /*MODEST_HAVE_ABOOK*/
81 #ifdef MODEST_HAVE_LIBALARM
82 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
83 #endif /*MODEST_HAVE_LIBALARM*/
86 #define HILDON_OSSO_URI_ACTION "uri-action"
87 #define URI_ACTION_COPY "copy:"
88 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
89 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
90 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
92 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
93 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
95 static void _modest_platform_play_email_tone (void);
99 on_modest_conf_update_interval_changed (ModestConf* self,
101 ModestConfEvent event,
102 ModestConfNotificationId id,
105 g_return_if_fail (key);
107 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
108 const guint update_interval_minutes =
109 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
110 modest_platform_set_update_interval (update_interval_minutes);
117 check_required_files (void)
119 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
121 g_printerr ("modest: check for mcc file failed\n");
126 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
127 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
128 g_printerr ("modest: cannot find providers data\n");
136 /* the gpointer here is the osso_context. */
138 modest_platform_init (int argc, char *argv[])
140 osso_context_t *osso_context;
142 osso_hw_state_t hw_state = { 0 };
146 if (!check_required_files ()) {
147 g_printerr ("modest: missing required files\n");
151 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
154 g_printerr ("modest: failed to acquire osso context\n");
157 modest_maemo_utils_set_osso_context (osso_context);
159 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
160 g_printerr ("modest: could not get dbus connection\n");
164 /* Add a D-Bus handler to be used when the main osso-rpc
165 * D-Bus handler has not handled something.
166 * We use this for D-Bus methods that need to use more complex types
167 * than osso-rpc supports.
169 if (!dbus_connection_add_filter (con,
170 modest_dbus_req_filter,
174 g_printerr ("modest: Could not add D-Bus filter\n");
178 /* Register our simple D-Bus callbacks, via the osso API: */
179 osso_return_t result = osso_rpc_set_cb_f(osso_context,
183 modest_dbus_req_handler, NULL /* user_data */);
184 if (result != OSSO_OK) {
185 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
189 /* Register hardware event dbus callback: */
190 hw_state.shutdown_ind = TRUE;
191 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
193 /* Register osso auto-save callbacks: */
194 result = osso_application_set_autosave_cb (osso_context,
195 modest_on_osso_application_autosave, NULL /* user_data */);
196 if (result != OSSO_OK) {
197 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
202 /* Make sure that the update interval is changed whenever its gconf key
204 /* CAUTION: we're not using here the
205 modest_conf_listen_to_namespace because we know that there
206 are other parts of Modest listening for this namespace, so
207 we'll receive the notifications anyway. We basically do not
208 use it because there is no easy way to do the
209 modest_conf_forget_namespace */
210 ModestConf *conf = modest_runtime_get_conf ();
211 g_signal_connect (G_OBJECT(conf),
213 G_CALLBACK (on_modest_conf_update_interval_changed),
216 /* only force the setting of the default interval, if there are actually
218 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
220 /* Get the initial update interval from gconf: */
221 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
222 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
223 modest_account_mgr_free_account_names (acc_names);
227 #ifdef MODEST_HAVE_ABOOK
228 /* initialize the addressbook */
229 if (!osso_abook_init (&argc, &argv, osso_context)) {
230 g_printerr ("modest: failed to initialized addressbook\n");
233 #endif /*MODEST_HAVE_ABOOK*/
239 modest_platform_uninit (void)
241 osso_context_t *osso_context =
242 modest_maemo_utils_get_osso_context ();
244 osso_deinitialize (osso_context);
253 modest_platform_get_new_device (void)
255 return TNY_DEVICE (tny_maemo_conic_device_new ());
259 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
260 gchar **effective_mime_type)
262 GString *mime_str = NULL;
263 gchar *icon_name = NULL;
264 gchar **icons, **cursor;
266 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
267 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
269 mime_str = g_string_new (mime_type);
270 g_string_ascii_down (mime_str);
273 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
275 for (cursor = icons; cursor; ++cursor) {
276 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
277 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
278 icon_name = g_strdup ("qgn_list_messagin");
280 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
281 icon_name = g_strdup (*cursor);
287 if (effective_mime_type)
288 *effective_mime_type = g_string_free (mime_str, FALSE);
290 g_string_free (mime_str, TRUE);
297 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
302 g_return_val_if_fail (uri, FALSE);
304 result = hildon_uri_open (uri, action, &err);
306 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
307 uri, action, err && err->message ? err->message : "unknown error");
317 modest_platform_activate_uri (const gchar *uri)
319 HildonURIAction *action;
320 gboolean result = FALSE;
321 GSList *actions, *iter = NULL;
323 g_return_val_if_fail (uri, FALSE);
327 /* don't try to activate file: uri's -- they might confuse the user,
328 * and/or might have security implications */
329 if (!g_str_has_prefix (uri, "file:")) {
331 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
333 for (iter = actions; iter; iter = g_slist_next (iter)) {
334 action = (HildonURIAction*) iter->data;
335 if (action && strcmp (hildon_uri_action_get_service (action),
336 "com.nokia.modest") == 0) {
337 result = checked_hildon_uri_open (uri, action);
342 /* if we could not open it with email, try something else */
344 result = checked_hildon_uri_open (uri, NULL);
348 ModestWindow *parent =
349 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
350 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
351 _("mcen_ib_unsupported_link"));
352 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
359 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
363 gchar *uri_path = NULL;
365 uri_path = gnome_vfs_get_uri_from_local_path (path);
366 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
369 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
371 result = hildon_mime_open_file (con, uri_path);
373 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
381 } ModestPlatformPopupInfo;
384 delete_uri_popup (GtkWidget *menu,
388 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
390 g_free (popup_info->uri);
391 hildon_uri_free_actions (popup_info->actions);
397 activate_uri_popup_item (GtkMenuItem *menu_item,
401 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
402 const gchar* action_name;
404 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
406 g_printerr ("modest: no action name defined\n");
410 /* special handling for the copy menu item -- copy the uri to the clipboard */
411 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
412 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
413 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
414 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
416 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
417 action_name += strlen ("mailto:");
419 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
420 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
421 return; /* we're done */
424 /* now, the real uri-actions... */
425 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
426 HildonURIAction *action = (HildonURIAction *) node->data;
427 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
428 if (!checked_hildon_uri_open (popup_info->uri, action)) {
429 ModestWindow *parent =
430 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
431 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
432 _("mcen_ib_unsupported_link"));
440 modest_platform_show_uri_popup (const gchar *uri)
442 GSList *actions_list;
447 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
450 GtkWidget *menu = gtk_menu_new ();
451 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
453 /* don't add actions for file: uri's -- they might confuse the user,
454 * and/or might have security implications
455 * we still allow to copy the url though
457 if (!g_str_has_prefix (uri, "file:")) {
460 popup_info->actions = actions_list;
461 popup_info->uri = g_strdup (uri);
463 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
464 GtkWidget *menu_item;
465 const gchar *action_name;
466 const gchar *translation_domain;
467 HildonURIAction *action = (HildonURIAction *) node->data;
468 action_name = hildon_uri_action_get_name (action);
469 translation_domain = hildon_uri_action_get_translation_domain (action);
470 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
471 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
472 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
475 if (hildon_uri_is_default_action (action, NULL)) {
476 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
478 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
480 gtk_widget_show (menu_item);
484 /* always add the copy item */
485 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
486 "uri_link_copy_link_location"));
487 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
488 g_strconcat (URI_ACTION_COPY, uri, NULL),
490 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
491 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
492 gtk_widget_show (menu_item);
495 /* and what to do when the link is deleted */
496 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
497 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
500 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
508 modest_platform_get_icon (const gchar *name, guint icon_size)
511 GdkPixbuf* pixbuf = NULL;
512 GtkIconTheme *current_theme = NULL;
514 g_return_val_if_fail (name, NULL);
516 /* strlen == 0 is not really an error; it just
517 * means the icon is not available
519 if (!name || strlen(name) == 0)
522 current_theme = gtk_icon_theme_get_default ();
523 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
524 GTK_ICON_LOOKUP_NO_SVG,
527 g_printerr ("modest: error loading theme icon '%s': %s\n",
535 modest_platform_get_app_name (void)
537 return _("mcen_ap_name");
541 entry_insert_text (GtkEditable *editable,
550 chars = gtk_editable_get_chars (editable, 0, -1);
551 chars_length = g_utf8_strlen (chars, -1);
554 /* Show WID-INF036 */
555 if (chars_length >= 20) {
556 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
557 _CS("ckdg_ib_maximum_characters_reached"));
559 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
563 tmp = g_strndup (folder_name_forbidden_chars,
564 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
565 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
566 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
571 /* Write the text in the entry if it's valid */
572 g_signal_handlers_block_by_func (editable,
573 (gpointer) entry_insert_text, data);
574 gtk_editable_insert_text (editable, text, length, position);
575 g_signal_handlers_unblock_by_func (editable,
576 (gpointer) entry_insert_text, data);
579 /* Do not allow further processing */
580 g_signal_stop_emission_by_name (editable, "insert_text");
584 entry_changed (GtkEditable *editable,
588 GtkWidget *ok_button;
591 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
592 ok_button = GTK_WIDGET (buttons->data);
594 chars = gtk_editable_get_chars (editable, 0, -1);
595 g_return_if_fail (chars != NULL);
598 if (g_utf8_strlen (chars,-1) >= 20)
599 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
600 _CS("ckdg_ib_maximum_characters_reached"));
602 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
605 g_list_free (buttons);
612 on_response (GtkDialog *dialog,
616 GtkWidget *entry, *picker;
617 TnyFolderStore *parent;
618 const gchar *new_name;
621 if (response != GTK_RESPONSE_ACCEPT)
625 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
626 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
628 parent = TNY_FOLDER_STORE (user_data);
629 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
632 if (picker != NULL) {
633 const gchar *active_id;
635 active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (picker));
636 parent = TNY_FOLDER_STORE (
637 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
639 TNY_ACCOUNT_TYPE_STORE));
641 g_object_ref (parent);
643 /* Look for another folder with the same name */
644 if (modest_tny_folder_has_subfolder_with_name (parent,
651 if (TNY_IS_ACCOUNT (parent) &&
652 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
653 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
662 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
663 NULL, _CS("ckdg_ib_folder_already_exists"));
664 /* Select the text */
665 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
666 gtk_widget_grab_focus (entry);
667 /* Do not close the dialog */
668 g_signal_stop_emission_by_name (dialog, "response");
671 g_object_unref (parent);
675 order_by_acc_name (gconstpointer a,
678 ModestPair *pair_a, *pair_b;
680 pair_a = (ModestPair *) a;
681 pair_b = (ModestPair *) b;
683 if (pair_a->second && pair_b->second) {
684 gint compare = g_utf8_collate ((gchar *) pair_a->second,
685 (gchar *) pair_b->second);
688 else if (compare < 0)
697 static ModestPairList *
698 get_folders_accounts_list (void)
701 GSList *cursor, *account_names;
702 ModestAccountMgr *account_mgr;
705 account_mgr = modest_runtime_get_account_mgr ();
707 cursor = account_names = modest_account_mgr_account_names (account_mgr, TRUE /*only enabled*/);
710 ModestAccountSettings *settings;
711 ModestServerAccountSettings *store_settings;
713 account_name = (gchar*)cursor->data;
715 settings = modest_account_mgr_load_account_settings (account_mgr, account_name);
717 g_printerr ("modest: failed to get account data for %s\n", account_name);
720 store_settings = modest_account_settings_get_store_settings (settings);
722 /* don't display accounts not able to show folders */
723 if (modest_server_account_settings_get_account_name (store_settings) != NULL) {
724 ModestProtocolType protocol_type;
726 protocol_type = modest_server_account_settings_get_protocol (store_settings);
727 /* we cannot create folders on accounts without folders */
728 if (modest_protocol_registry_protocol_type_has_tag (modest_runtime_get_protocol_registry (),
730 MODEST_PROTOCOL_REGISTRY_STORE_HAS_FOLDERS)) {
731 if (modest_account_settings_get_enabled (settings)) {
733 pair = modest_pair_new (
734 g_strdup (account_name),
735 g_strdup (modest_account_settings_get_display_name (settings)),
737 list = g_slist_insert_sorted (list, pair, order_by_acc_name);
742 g_object_unref (store_settings);
743 g_object_unref (settings);
744 cursor = cursor->next;
747 /* Create also entries for local account and mmc */
748 pair = modest_pair_new (g_strdup (MODEST_LOCAL_FOLDERS_ACCOUNT_ID),
749 g_strdup (MODEST_LOCAL_FOLDERS_DEFAULT_DISPLAY_NAME),
751 list = g_slist_insert_sorted (list, pair, order_by_acc_name);
753 /* TODO: add mmc account */
755 return (ModestPairList *) g_slist_reverse (list);
761 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
762 TnyFolderStore *suggested_parent,
763 const gchar *dialog_title,
764 const gchar *label_text,
765 const gchar *suggested_name,
767 gboolean show_parent,
769 TnyFolderStore **parent)
771 GtkWidget *accept_btn = NULL;
772 GtkWidget *dialog, *entry, *label_entry, *label_location, *hbox;
773 GtkWidget *account_picker;
774 GList *buttons = NULL;
776 GSList *accounts_list;
777 GtkSizeGroup *sizegroup;
779 /* Ask the user for the folder name */
780 dialog = gtk_dialog_new_with_buttons (dialog_title,
782 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
787 /* Add accept button (with unsensitive handler) */
788 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
789 accept_btn = GTK_WIDGET (buttons->data);
791 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
794 label_entry = gtk_label_new (label_text);
795 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
796 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
798 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
799 gtk_size_group_add_widget (sizegroup, label_entry);
802 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
804 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
805 gtk_entry_set_width_chars (GTK_ENTRY (entry),
806 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
807 g_utf8_strlen (_("mcen_ia_default_folder_name"), -1)));
808 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
814 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
816 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
817 gtk_size_group_add_widget (sizegroup, label_location);
819 accounts_list = get_folders_accounts_list ();
820 account_picker = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
821 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
824 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL,
825 MODEST_ICON_SIZE_SMALL);
826 hildon_button_set_image (HILDON_BUTTON (account_picker),
827 gtk_image_new_from_pixbuf (pixbuf));
828 hildon_button_set_alignment (HILDON_BUTTON (account_picker), 0.0, 0.5, 1.0, 1.0);
831 g_object_unref (sizegroup);
833 /* Connect to the response method to avoid closing the dialog
834 when an invalid name is selected*/
835 g_signal_connect (dialog,
837 G_CALLBACK (on_response),
841 /* Track entry changes */
842 g_signal_connect (entry,
844 G_CALLBACK (entry_insert_text),
846 g_signal_connect (entry,
848 G_CALLBACK (entry_changed),
853 /* Some locales like pt_BR need this to get the full window
855 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
857 /* Create the hbox */
859 hbox = gtk_hbox_new (FALSE, 12);
860 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
861 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
863 /* Add hbox to dialog */
864 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
865 hbox, FALSE, FALSE, 0);
866 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
870 hbox = gtk_hbox_new (FALSE, 12);
871 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
872 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
874 /* Add hbox to dialog */
875 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
876 hbox, FALSE, FALSE, 0);
877 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
879 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
880 GTK_WINDOW (dialog), parent_window);
881 gtk_widget_show_all (GTK_WIDGET(dialog));
883 result = gtk_dialog_run (GTK_DIALOG(dialog));
884 if (result == GTK_RESPONSE_ACCEPT) {
886 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
888 const gchar *active_id;
890 active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (account_picker));
891 *parent = TNY_FOLDER_STORE (
892 modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
894 TNY_ACCOUNT_TYPE_STORE));
898 gtk_widget_destroy (dialog);
901 modest_pair_list_free (accounts_list);
904 while (gtk_events_pending ())
905 gtk_main_iteration ();
911 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
912 TnyFolderStore *suggested_folder,
913 gchar *suggested_name,
915 TnyFolderStore **parent_folder)
917 gchar *real_suggested_name = NULL, *tmp = NULL;
920 if(suggested_name == NULL)
922 const gchar *default_name = _("mcen_ia_default_folder_name");
926 for(i = 0; i < 100; ++ i) {
927 gboolean exists = FALSE;
929 sprintf(num_str, "%.2u", i);
932 real_suggested_name = g_strdup (default_name);
934 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
936 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
943 g_free (real_suggested_name);
946 /* Didn't find a free number */
948 real_suggested_name = g_strdup (default_name);
950 real_suggested_name = suggested_name;
953 tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
954 result = modest_platform_run_folder_common_dialog (parent_window,
956 _("mcen_ti_new_folder"),
965 if (suggested_name == NULL)
966 g_free(real_suggested_name);
972 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
973 TnyFolderStore *parent_folder,
974 const gchar *suggested_name,
977 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
979 return modest_platform_run_folder_common_dialog (parent_window,
981 _HL("ckdg_ti_rename_folder"),
982 _HL("ckdg_fi_rename_name"),
993 on_destroy_dialog (GtkWidget *dialog)
995 /* This could happen when the dialogs get programatically
996 hidden or destroyed (for example when closing the
997 application while a dialog is being shown) */
998 if (!GTK_IS_WIDGET (dialog))
1001 gtk_widget_destroy (dialog);
1003 if (gtk_events_pending ())
1004 gtk_main_iteration ();
1008 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1009 const gchar *message)
1014 dialog = hildon_note_new_confirmation (parent_window, message);
1015 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1016 GTK_WINDOW (dialog), parent_window);
1018 response = gtk_dialog_run (GTK_DIALOG (dialog));
1020 on_destroy_dialog (dialog);
1026 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1027 const gchar *message,
1028 const gchar *button_accept,
1029 const gchar *button_cancel)
1034 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1035 button_accept, GTK_RESPONSE_ACCEPT,
1036 button_cancel, GTK_RESPONSE_CANCEL,
1039 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1040 GTK_WINDOW (dialog), parent_window);
1042 response = gtk_dialog_run (GTK_DIALOG (dialog));
1044 on_destroy_dialog (dialog);
1050 modest_platform_run_information_dialog (GtkWindow *parent_window,
1051 const gchar *message,
1056 note = hildon_note_new_information (parent_window, message);
1058 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1059 GTK_WINDOW (note), parent_window);
1062 gtk_dialog_run (GTK_DIALOG (note));
1064 on_destroy_dialog (note);
1066 g_signal_connect_swapped (note,
1068 G_CALLBACK (on_destroy_dialog),
1071 gtk_widget_show_all (note);
1075 typedef struct _ConnectAndWaitData {
1077 GMainLoop *wait_loop;
1078 gboolean has_callback;
1080 } ConnectAndWaitData;
1084 quit_wait_loop (TnyAccount *account,
1085 ConnectAndWaitData *data)
1087 /* Set the has_callback to TRUE (means that the callback was
1088 executed and wake up every code waiting for cond to be
1090 g_mutex_lock (data->mutex);
1091 data->has_callback = TRUE;
1092 if (data->wait_loop)
1093 g_main_loop_quit (data->wait_loop);
1094 g_mutex_unlock (data->mutex);
1098 on_connection_status_changed (TnyAccount *account,
1099 TnyConnectionStatus status,
1102 TnyConnectionStatus conn_status;
1103 ConnectAndWaitData *data;
1105 /* Ignore if reconnecting or disconnected */
1106 conn_status = tny_account_get_connection_status (account);
1107 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1108 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1111 /* Remove the handler */
1112 data = (ConnectAndWaitData *) user_data;
1113 g_signal_handler_disconnect (account, data->handler);
1115 /* Quit from wait loop */
1116 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1120 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1125 /* Quit from wait loop */
1126 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1130 modest_platform_connect_and_wait (GtkWindow *parent_window,
1131 TnyAccount *account)
1133 ConnectAndWaitData *data = NULL;
1134 gboolean device_online;
1136 TnyConnectionStatus conn_status;
1137 gboolean user_requested;
1139 device = modest_runtime_get_device();
1140 device_online = tny_device_is_online (device);
1142 /* Whether the connection is user requested or automatically
1143 requested, for example via D-Bus */
1144 user_requested = (parent_window) ? TRUE : FALSE;
1146 /* If there is no account check only the device status */
1151 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1152 NULL, user_requested);
1155 /* Return if the account is already connected */
1156 conn_status = tny_account_get_connection_status (account);
1157 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1160 /* Create the helper */
1161 data = g_slice_new0 (ConnectAndWaitData);
1162 data->mutex = g_mutex_new ();
1163 data->has_callback = FALSE;
1165 /* Connect the device */
1166 if (!device_online) {
1167 /* Track account connection status changes */
1168 data->handler = g_signal_connect (account, "connection-status-changed",
1169 G_CALLBACK (on_connection_status_changed),
1171 /* Try to connect the device */
1172 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1173 NULL, user_requested);
1175 /* If the device connection failed then exit */
1176 if (!device_online && data->handler)
1179 /* Force a reconnection of the account */
1180 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1181 on_tny_camel_account_set_online_cb, data);
1184 /* Wait until the callback is executed */
1185 g_mutex_lock (data->mutex);
1186 if (!data->has_callback) {
1187 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1188 gdk_threads_leave ();
1189 g_mutex_unlock (data->mutex);
1190 g_main_loop_run (data->wait_loop);
1191 g_mutex_lock (data->mutex);
1192 gdk_threads_enter ();
1194 g_mutex_unlock (data->mutex);
1198 if (g_signal_handler_is_connected (account, data->handler))
1199 g_signal_handler_disconnect (account, data->handler);
1200 g_mutex_free (data->mutex);
1201 g_main_loop_unref (data->wait_loop);
1202 g_slice_free (ConnectAndWaitData, data);
1205 conn_status = tny_account_get_connection_status (account);
1206 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1210 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1212 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1213 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1214 /* This must be a maildir account, which does not require a connection: */
1219 return modest_platform_connect_and_wait (parent_window, account);
1223 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1226 return TRUE; /* Maybe it is something local. */
1228 gboolean result = TRUE;
1229 if (TNY_IS_FOLDER (folder_store)) {
1230 /* Get the folder's parent account: */
1231 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1232 if (account != NULL) {
1233 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1234 g_object_unref (account);
1236 } else if (TNY_IS_ACCOUNT (folder_store)) {
1237 /* Use the folder store as an account: */
1238 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1245 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1249 dialog = modest_hildon2_sort_dialog_new (parent_window);
1256 modest_platform_set_update_interval (guint minutes)
1258 #ifdef MODEST_HAVE_LIBALARM
1260 ModestConf *conf = modest_runtime_get_conf ();
1264 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1266 /* Delete any existing alarm,
1267 * because we will replace it: */
1269 if (alarmd_event_del(alarm_cookie) != 1)
1270 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1272 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1275 /* 0 means no updates: */
1280 /* Register alarm: */
1282 /* Set the interval in alarm_event_t structure: */
1283 alarm_event_t *event = alarm_event_create ();
1284 alarm_event_add_actions (event, 1);
1285 alarm_action_t *action = alarm_event_get_action (event, 0);
1286 event->alarm_time = minutes * 60; /* seconds */
1288 /* Set recurrence every few minutes: */
1289 event->recur_secs = minutes*60;
1290 event->recur_count = -1; /* Means infinite */
1292 /* Specify what should happen when the alarm happens:
1293 * It should call this D-Bus method: */
1295 action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1296 action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1297 action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1298 action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1299 action->flags = ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1301 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1302 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1303 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1304 * This is why we want to use the Alarm API instead of just g_timeout_add().
1305 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1306 * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1308 event->flags = ALARM_EVENT_CONNECTED;
1310 alarm_cookie = alarmd_event_add (event);
1313 alarm_event_delete (event);
1315 /* Store the alarm ID in GConf, so we can remove it later:
1316 * This is apparently valid between application instances. */
1317 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1319 if (!alarm_cookie) {
1321 g_debug ("Error setting alarm event. \n");
1325 #endif /* MODEST_HAVE_LIBALARM */
1330 modest_platform_push_email_notification(void)
1332 gboolean screen_on = TRUE, app_in_foreground;
1334 /* Get the window status */
1335 app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1337 /* If the screen is on and the app is in the
1338 foreground we don't show anything */
1339 if (!(screen_on && app_in_foreground)) {
1341 _modest_platform_play_email_tone ();
1343 /* Activate LED. This must be deactivated by
1344 modest_platform_remove_new_mail_notifications */
1345 #ifdef MODEST_HAVE_MCE
1346 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1350 MCE_ACTIVATE_LED_PATTERN,
1352 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1359 modest_platform_on_new_headers_received (TnyList *header_list,
1360 gboolean show_visual)
1362 g_return_if_fail (TNY_IS_LIST(header_list));
1364 if (tny_list_get_length(header_list) == 0) {
1365 g_warning ("%s: header list is empty", __FUNCTION__);
1370 modest_platform_push_email_notification ();
1371 /* We do a return here to avoid indentation with an else */
1375 #ifdef MODEST_HAVE_HILDON_NOTIFY
1376 HildonNotification *notification;
1378 GSList *notifications_list = NULL;
1380 /* Get previous notifications ids */
1381 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1382 MODEST_CONF_NOTIFICATION_IDS,
1383 MODEST_CONF_VALUE_INT, NULL);
1385 iter = tny_list_create_iterator (header_list);
1386 while (!tny_iterator_is_done (iter)) {
1387 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1388 const gchar *display_date;
1389 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1390 TnyFolder *folder = tny_header_get_folder (header);
1391 gboolean first_notification = TRUE;
1394 ModestDatetimeFormatter *datetime_formatter;
1396 /* constant string, don't free */
1397 datetime_formatter = modest_datetime_formatter_new ();
1398 display_date = modest_datetime_formatter_display_datetime (datetime_formatter,
1399 tny_header_get_date_received (header));
1400 g_object_unref (datetime_formatter);
1402 display_address = tny_header_dup_from (header);
1403 /* string is changed in-place */
1404 modest_text_utils_get_display_address (display_address);
1406 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1407 str = tny_header_dup_subject (header);
1408 notification = hildon_notification_new (summary,
1410 "qgn_list_messagin",
1413 /* Create the message URL */
1414 str = tny_header_dup_uid (header);
1415 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1419 hildon_notification_add_dbus_action(notification,
1422 MODEST_DBUS_SERVICE,
1425 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1429 /* Play sound if the user wants. Show the LED
1430 pattern. Show and play just one */
1431 if (G_UNLIKELY (first_notification)) {
1432 gchar *active_profile;
1435 gint mail_volume_int;
1437 first_notification = FALSE;
1439 active_profile = profile_get_profile ();
1440 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1441 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1442 mail_volume_int = profile_parse_int (mail_volume);
1444 if (mail_volume_int > 0)
1445 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1446 "sound-file", mail_tone);
1448 g_free (mail_volume);
1450 g_free (active_profile);
1452 /* Set the led pattern */
1453 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1455 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1457 MODEST_NEW_MAIL_LIGHTING_PATTERN);
1460 /* Notify. We need to do this in an idle because this function
1461 could be called from a thread */
1462 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1464 /* Save id in the list */
1465 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1466 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1467 /* We don't listen for the "closed" signal, because we
1468 don't care about if the notification was removed or
1469 not to store the list in gconf */
1471 /* Free & carry on */
1472 g_free (display_address);
1475 g_object_unref (folder);
1476 g_object_unref (header);
1477 tny_iterator_next (iter);
1479 g_object_unref (iter);
1482 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1483 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1485 g_slist_free (notifications_list);
1487 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1491 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1494 #ifdef MODEST_HAVE_MCE
1495 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1499 MCE_DEACTIVATE_LED_PATTERN,
1501 DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1507 #ifdef MODEST_HAVE_HILDON_NOTIFY
1508 GSList *notif_list = NULL;
1510 /* Get previous notifications ids */
1511 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1512 MODEST_CONF_NOTIFICATION_IDS,
1513 MODEST_CONF_VALUE_INT, NULL);
1515 while (notif_list) {
1517 NotifyNotification *notif;
1519 /* Nasty HACK to remove the notifications, set the id
1520 of the existing ones and then close them */
1521 notif_id = GPOINTER_TO_INT(notif_list->data);
1522 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1523 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1525 /* Close the notification, note that some ids could be
1526 already invalid, but we don't care because it does
1528 notify_notification_close(notif, NULL);
1529 g_object_unref(notif);
1531 /* Delete the link, it's like going to the next */
1532 notif_list = g_slist_delete_link (notif_list, notif_list);
1536 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1537 notif_list, MODEST_CONF_VALUE_INT, NULL);
1539 g_slist_free (notif_list);
1541 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1547 modest_platform_get_global_settings_dialog ()
1549 return modest_hildon2_global_settings_dialog_new ();
1553 modest_platform_show_help (GtkWindow *parent_window,
1554 const gchar *help_id)
1560 modest_platform_show_search_messages (GtkWindow *parent_window)
1562 osso_return_t result = OSSO_ERROR;
1564 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1565 "osso_global_search",
1566 "search_email", NULL, DBUS_TYPE_INVALID);
1568 if (result != OSSO_OK) {
1569 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1574 modest_platform_show_addressbook (GtkWindow *parent_window)
1576 osso_return_t result = OSSO_ERROR;
1578 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1580 "top_application", NULL, DBUS_TYPE_INVALID);
1582 if (result != OSSO_OK) {
1583 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1588 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1590 GtkWidget *widget = modest_folder_view_new (query);
1592 /* Show one account by default */
1593 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1594 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1596 /* Restore settings */
1597 modest_widget_memory_restore (modest_runtime_get_conf(),
1599 MODEST_CONF_FOLDER_VIEW_KEY);
1605 banner_finish (gpointer data, GObject *object)
1607 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1608 modest_window_mgr_unregister_banner (mgr);
1609 g_object_unref (mgr);
1613 modest_platform_information_banner (GtkWidget *parent,
1614 const gchar *icon_name,
1617 GtkWidget *banner, *banner_parent = NULL;
1618 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1620 if (modest_window_mgr_get_num_windows (mgr) == 0)
1623 if (parent && GTK_IS_WINDOW (parent)) {
1624 /* If the window is the active one then show the
1625 banner on top of this window */
1626 if (gtk_window_is_active (GTK_WINDOW (parent)))
1627 banner_parent = parent;
1628 /* If the window is not the topmost but it's visible
1629 (it's minimized for example) then show the banner
1631 else if (GTK_WIDGET_VISIBLE (parent))
1632 banner_parent = NULL;
1633 /* If the window is hidden (like the main window when
1634 running in the background) then do not show
1641 banner = hildon_banner_show_information (banner_parent, icon_name, text);
1643 modest_window_mgr_register_banner (mgr);
1645 g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1649 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1650 const gchar *icon_name,
1656 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1659 banner = hildon_banner_show_information (parent, icon_name, text);
1660 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1664 modest_platform_animation_banner (GtkWidget *parent,
1665 const gchar *animation_name,
1668 GtkWidget *inf_note = NULL;
1670 g_return_val_if_fail (text != NULL, NULL);
1672 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1675 /* If the parent is not visible then do not show */
1676 if (parent && !GTK_WIDGET_VISIBLE (parent))
1679 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1687 TnyAccount *account;
1690 } CheckAccountIdleData;
1692 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1695 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1697 gboolean stop_trying = FALSE;
1698 g_return_val_if_fail (data && data->account, FALSE);
1700 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1701 tny_account_get_connection_status (data->account));
1703 if (data && data->account &&
1704 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1705 * after which the account is likely to be usable, or never likely to be usable soon: */
1706 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1708 data->is_online = TRUE;
1712 /* Give up if we have tried too many times: */
1713 if (data->count_tries >= NUMBER_OF_TRIES) {
1716 /* Wait for another timeout: */
1717 ++(data->count_tries);
1722 /* Allow the function that requested this idle callback to continue: */
1724 g_main_loop_quit (data->loop);
1727 g_object_unref (data->account);
1729 return FALSE; /* Don't call this again. */
1731 return TRUE; /* Call this timeout callback again. */
1735 /* Return TRUE immediately if the account is already online,
1736 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1737 * soon as the account is online, or FALSE if the account does
1738 * not become online in the NUMBER_OF_TRIES seconds.
1739 * This is useful when the D-Bus method was run immediately after
1740 * the application was started (when using D-Bus activation),
1741 * because the account usually takes a short time to go online.
1742 * The return value is maybe not very useful.
1745 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1749 g_return_val_if_fail (account, FALSE);
1751 if (!tny_device_is_online (modest_runtime_get_device())) {
1752 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1756 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1757 * so we avoid wait unnecessarily: */
1758 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1761 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1762 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1763 * we want to avoid. */
1764 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1767 /* This blocks on the result: */
1768 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1769 data->is_online = FALSE;
1770 data->account = account;
1771 g_object_ref (data->account);
1772 data->count_tries = 0;
1774 GMainContext *context = NULL; /* g_main_context_new (); */
1775 data->loop = g_main_loop_new (context, FALSE /* not running */);
1777 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1779 /* This main loop will run until the idle handler has stopped it: */
1780 g_main_loop_run (data->loop);
1782 g_main_loop_unref (data->loop);
1783 /* g_main_context_unref (context); */
1785 is_online = data->is_online;
1786 g_slice_free (CheckAccountIdleData, data);
1794 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1796 /* GTK_RESPONSE_HELP means we need to show the certificate */
1797 if (response_id == GTK_RESPONSE_APPLY) {
1801 /* Do not close the dialog */
1802 g_signal_stop_emission_by_name (dialog, "response");
1804 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1805 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1806 gtk_dialog_run (GTK_DIALOG(note));
1807 gtk_widget_destroy (note);
1813 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1814 const gchar *certificate)
1819 HildonWindowStack *stack;
1821 stack = hildon_window_stack_get_default ();
1822 win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1825 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1830 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1833 /* We use GTK_RESPONSE_APPLY because we want the button in the
1834 middle of OK and CANCEL the same as the browser does for
1835 example. With GTK_RESPONSE_HELP the view button is aligned
1836 to the left while the other two to the right */
1837 note = hildon_note_new_confirmation_add_buttons (
1840 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1841 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1842 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1845 g_signal_connect (G_OBJECT(note), "response",
1846 G_CALLBACK(on_cert_dialog_response),
1847 (gpointer) certificate);
1849 response = gtk_dialog_run(GTK_DIALOG(note));
1851 on_destroy_dialog (note);
1854 return response == GTK_RESPONSE_OK;
1858 modest_platform_run_alert_dialog (const gchar* prompt,
1859 gboolean is_question)
1861 ModestWindow *main_win;
1863 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1864 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1865 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1866 return is_question ? FALSE : TRUE;
1869 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1870 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1872 gboolean retval = TRUE;
1874 /* The Tinymail documentation says that we should show Yes and No buttons,
1875 * when it is a question.
1876 * Obviously, we need tinymail to use more specific error codes instead,
1877 * so we know what buttons to show. */
1878 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1880 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1881 GTK_WINDOW (dialog), GTK_WINDOW (main_win));
1883 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1884 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1886 on_destroy_dialog (dialog);
1888 /* Just show the error text and use the default response: */
1889 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1897 GtkWindow *parent_window;
1898 ModestConnectedPerformer callback;
1899 TnyAccount *account;
1906 on_went_online_info_free (OnWentOnlineInfo *info)
1908 /* And if we cleanup, we DO cleanup :-) */
1911 g_object_unref (info->device);
1914 if (info->parent_window)
1915 g_object_unref (info->parent_window);
1917 g_object_unref (info->account);
1919 g_slice_free (OnWentOnlineInfo, info);
1921 /* We're done ... */
1927 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1929 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1931 /* Now it's really time to callback to the caller. If going online didn't succeed,
1932 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1933 * canceled will be set. Etcetera etcetera. */
1935 if (info->callback) {
1936 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1939 /* This is our last call, we must cleanup here if we didn't yet do that */
1940 on_went_online_info_free (info);
1947 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1949 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1950 info->iap = g_strdup (iap_id);
1952 if (canceled || err || !info->account) {
1954 /* If there's a problem or if there's no account (then that's it for us, we callback
1955 * the caller's callback now. He'll have to handle err or canceled, of course.
1956 * We are not really online, as the account is not really online here ... */
1958 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1959 * this info. We don't cleanup err, Tinymail does that! */
1961 if (info->callback) {
1963 /* info->account can be NULL here, this means that the user did not
1964 * provide a nice account instance. We'll assume that the user knows
1965 * what he's doing and is happy with just the device going online.
1967 * We can't do magic, we don't know what account the user wants to
1968 * see going online. So just the device goes online, end of story */
1970 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1973 } else if (info->account) {
1975 /* If there's no problem and if we have an account, we'll put the account
1976 * online too. When done, the callback of bringing the account online
1977 * will callback the caller's callback. This is the most normal case. */
1979 info->device = TNY_DEVICE (g_object_ref (device));
1981 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1982 on_account_went_online, info);
1984 /* The on_account_went_online cb frees up the info, go look if you
1985 * don't believe me! (so we return here) */
1990 /* We cleanup if we are not bringing the account online too */
1991 on_went_online_info_free (info);
1997 modest_platform_connect_and_perform (GtkWindow *parent_window,
1999 TnyAccount *account,
2000 ModestConnectedPerformer callback,
2003 gboolean device_online;
2005 TnyConnectionStatus conn_status;
2006 OnWentOnlineInfo *info;
2008 device = modest_runtime_get_device();
2009 device_online = tny_device_is_online (device);
2011 /* If there is no account check only the device status */
2014 if (device_online) {
2016 /* We promise to instantly perform the callback, so ... */
2018 callback (FALSE, NULL, parent_window, account, user_data);
2023 info = g_slice_new0 (OnWentOnlineInfo);
2026 info->device = NULL;
2027 info->account = NULL;
2030 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2032 info->parent_window = NULL;
2033 info->user_data = user_data;
2034 info->callback = callback;
2036 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2037 force, on_conic_device_went_online,
2040 /* We'll cleanup in on_conic_device_went_online */
2043 /* The other code has no more reason to run. This is all that we can do for the
2044 * caller (he should have given us a nice and clean account instance!). We
2045 * can't do magic, we don't know what account he intends to bring online. So
2046 * we'll just bring the device online (and await his false bug report). */
2052 /* Return if the account is already connected */
2054 conn_status = tny_account_get_connection_status (account);
2055 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2057 /* We promise to instantly perform the callback, so ... */
2059 callback (FALSE, NULL, parent_window, account, user_data);
2065 /* Else, we are in a state that requires that we go online before we
2066 * call the caller's callback. */
2068 info = g_slice_new0 (OnWentOnlineInfo);
2070 info->device = NULL;
2072 info->account = TNY_ACCOUNT (g_object_ref (account));
2075 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2077 info->parent_window = NULL;
2079 /* So we'll put the callback away for later ... */
2081 info->user_data = user_data;
2082 info->callback = callback;
2084 if (!device_online) {
2086 /* If also the device is offline, then we connect both the device
2087 * and the account */
2089 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2090 force, on_conic_device_went_online,
2095 /* If the device is online, we'll just connect the account */
2097 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
2098 on_account_went_online, info);
2101 /* The info gets freed by on_account_went_online or on_conic_device_went_online
2102 * in both situations, go look if you don't believe me! */
2108 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2110 TnyFolderStore *folder_store,
2111 ModestConnectedPerformer callback,
2114 TnyAccount *account = NULL;
2116 if (!folder_store) {
2117 /* We promise to instantly perform the callback, so ... */
2119 callback (FALSE, NULL, parent_window, NULL, user_data);
2123 } else if (TNY_IS_FOLDER (folder_store)) {
2124 /* Get the folder's parent account: */
2125 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2126 } else if (TNY_IS_ACCOUNT (folder_store)) {
2127 /* Use the folder store as an account: */
2128 account = TNY_ACCOUNT (g_object_ref (folder_store));
2131 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2132 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2133 /* No need to connect a local account */
2135 callback (FALSE, NULL, parent_window, account, user_data);
2140 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2144 g_object_unref (account);
2148 src_account_connect_performer (gboolean canceled,
2150 GtkWindow *parent_window,
2151 TnyAccount *src_account,
2154 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2156 if (canceled || err) {
2157 /* If there was any error call the user callback */
2158 info->callback (canceled, err, parent_window, src_account, info->data);
2160 /* Connect the destination account */
2161 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
2162 TNY_FOLDER_STORE (info->dst_account),
2163 info->callback, info->data);
2166 /* Free the info object */
2167 g_object_unref (info->dst_account);
2168 g_slice_free (DoubleConnectionInfo, info);
2173 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
2175 TnyFolderStore *folder_store,
2176 DoubleConnectionInfo *connect_info)
2178 modest_platform_connect_if_remote_and_perform(parent_window,
2181 src_account_connect_performer,
2186 modest_platform_get_account_settings_wizard (void)
2188 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2190 return GTK_WIDGET (dialog);
2194 modest_platform_get_current_connection (void)
2196 TnyDevice *device = NULL;
2197 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2199 device = modest_runtime_get_device ();
2201 if (!tny_device_is_online (device))
2202 return MODEST_CONNECTED_VIA_ANY;
2204 #ifdef MODEST_HAVE_CONIC
2206 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2208 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2209 TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2210 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2212 if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2213 !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2214 !strcmp (bearer_type, "WIMAX")) {
2215 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2217 retval = MODEST_CONNECTED_VIA_ANY;
2220 g_object_unref (iap);
2223 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
2224 #endif /* MODEST_HAVE_CONIC */
2231 modest_platform_check_memory_low (ModestWindow *win,
2236 /* are we in low memory state? */
2237 lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2239 if (win && lowmem && visuals)
2240 modest_platform_run_information_dialog (
2242 dgettext("ke-recv","memr_ib_operation_disabled"),
2246 g_debug ("%s: low memory reached. disallowing some operations",
2253 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2259 dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2262 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2263 GTK_WINDOW (dialog),
2265 gtk_widget_show_all (dialog);
2267 g_signal_connect_swapped (dialog, "response",
2268 G_CALLBACK (gtk_widget_destroy),
2273 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2279 dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2282 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2283 GTK_WINDOW (dialog),
2285 gtk_widget_show_all (dialog);
2287 g_signal_connect_swapped (dialog, "response",
2288 G_CALLBACK (gtk_widget_destroy),
2293 modest_platform_get_osso_context (void)
2295 return modest_maemo_utils_get_osso_context ();
2299 _modest_platform_play_email_tone (void)
2301 gchar *active_profile;
2304 gint mail_volume_int;
2306 ca_context *ca_con = NULL;
2307 ca_proplist *pl = NULL;
2309 active_profile = profile_get_profile ();
2310 mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2311 mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2312 mail_volume_int = profile_parse_int (mail_volume);
2314 if (mail_volume_int > 0) {
2316 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2317 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2321 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2322 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2323 ca_context_destroy(ca_con);
2327 ca_proplist_create(&pl);
2328 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2329 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2331 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2332 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2334 ca_proplist_destroy(pl);
2335 ca_context_destroy(ca_con);
2338 g_free (mail_volume);
2340 g_free (active_profile);
2344 on_move_to_dialog_folder_activated (GtkTreeView *tree_view,
2346 GtkTreeViewColumn *column,
2349 gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2353 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2354 GtkWidget **folder_view)
2356 GtkWidget *dialog, *folder_view_container;
2358 /* Create dialog. We cannot use a touch selector because we
2359 need to use here the folder view widget directly */
2360 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2361 GTK_WINDOW (parent_window),
2362 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2363 GTK_DIALOG_DESTROY_WITH_PARENT,
2364 _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2367 /* Create folder view */
2368 *folder_view = modest_platform_create_folder_view (NULL);
2370 /* Simulate the behaviour of a HildonPickerDialog by emitting
2371 a response when a folder is selected */
2372 g_signal_connect (*folder_view, "row-activated",
2373 G_CALLBACK (on_move_to_dialog_folder_activated),
2376 /* Create pannable and add it to the dialog */
2377 folder_view_container = hildon_pannable_area_new ();
2378 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2379 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2381 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2383 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2384 gtk_widget_show (folder_view_container);
2385 gtk_widget_show (*folder_view);
2391 modest_platform_get_list_to_move (ModestWindow *window)
2393 if (MODEST_IS_HEADER_WINDOW (window)) {
2394 ModestHeaderView *header_view;
2396 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2398 return modest_header_view_get_selected_headers (header_view);
2399 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2400 ModestFolderView *folder_view;
2401 TnyFolderStore *selected_folder;
2404 list = TNY_LIST (tny_simple_list_new ());
2405 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2406 selected_folder = modest_folder_view_get_selected (folder_view);
2407 if (selected_folder) {
2408 tny_list_prepend (list, G_OBJECT (selected_folder));
2409 g_object_unref (selected_folder);