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 "maemo/modest-maemo-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 <maemo/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 <tny-camel-imap-store-account.h>
47 #include <tny-camel-pop-store-account.h>
48 #include <gtk/gtkicontheme.h>
49 #include <gtk/gtkmenuitem.h>
50 #include <gtk/gtkmain.h>
51 #include <modest-text-utils.h>
52 #include "modest-tny-folder.h"
53 #include "modest-tny-account.h"
55 #include <libgnomevfs/gnome-vfs-mime-utils.h>
56 #include <modest-account-settings-dialog.h>
57 #include <maemo/easysetup/modest-easysetup-wizard.h>
59 #ifdef MODEST_HAVE_ABOOK
60 #include <libosso-abook/osso-abook.h>
61 #endif /*MODEST_HAVE_ABOOK*/
63 #ifdef MODEST_HAVE_LIBALARM
64 #include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
65 #endif /*MODEST_HAVE_LIBALARM*/
68 #define HILDON_OSSO_URI_ACTION "uri-action"
69 #define URI_ACTION_COPY "copy:"
72 on_modest_conf_update_interval_changed (ModestConf* self,
74 ModestConfEvent event,
75 ModestConfNotificationId id,
78 g_return_if_fail (key);
80 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
81 const guint update_interval_minutes =
82 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
83 modest_platform_set_update_interval (update_interval_minutes);
90 check_required_files (void)
92 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
94 g_printerr ("modest: check for mcc file failed\n");
99 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
100 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
101 g_printerr ("modest: cannot find providers data\n");
109 /* the gpointer here is the osso_context. */
111 modest_platform_init (int argc, char *argv[])
113 osso_context_t *osso_context;
115 osso_hw_state_t hw_state = { 0 };
119 if (!check_required_files ()) {
120 g_printerr ("modest: missing required files\n");
124 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
127 g_printerr ("modest: failed to acquire osso context\n");
130 modest_maemo_utils_set_osso_context (osso_context);
132 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
133 g_printerr ("modest: could not get dbus connection\n");
137 /* Add a D-Bus handler to be used when the main osso-rpc
138 * D-Bus handler has not handled something.
139 * We use this for D-Bus methods that need to use more complex types
140 * than osso-rpc supports.
142 if (!dbus_connection_add_filter (con,
143 modest_dbus_req_filter,
147 g_printerr ("modest: Could not add D-Bus filter\n");
151 /* Register our simple D-Bus callbacks, via the osso API: */
152 osso_return_t result = osso_rpc_set_cb_f(osso_context,
156 modest_dbus_req_handler, NULL /* user_data */);
157 if (result != OSSO_OK) {
158 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
162 /* Register hardware event dbus callback: */
163 hw_state.shutdown_ind = TRUE;
164 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
166 /* Register osso auto-save callbacks: */
167 result = osso_application_set_autosave_cb (osso_context,
168 modest_on_osso_application_autosave, NULL /* user_data */);
169 if (result != OSSO_OK) {
170 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
175 /* Make sure that the update interval is changed whenever its gconf key
177 /* CAUTION: we're not using here the
178 modest_conf_listen_to_namespace because we know that there
179 are other parts of Modest listening for this namespace, so
180 we'll receive the notifications anyway. We basically do not
181 use it because there is no easy way to do the
182 modest_conf_forget_namespace */
183 ModestConf *conf = modest_runtime_get_conf ();
184 g_signal_connect (G_OBJECT(conf),
186 G_CALLBACK (on_modest_conf_update_interval_changed),
189 /* only force the setting of the default interval, if there are actually
191 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
193 /* Get the initial update interval from gconf: */
194 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
195 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
196 modest_account_mgr_free_account_names (acc_names);
200 #ifdef MODEST_HAVE_ABOOK
201 /* initialize the addressbook */
202 if (!osso_abook_init (&argc, &argv, osso_context)) {
203 g_printerr ("modest: failed to initialized addressbook\n");
206 #endif /*MODEST_HAVE_ABOOK*/
212 modest_platform_uninit (void)
214 osso_context_t *osso_context =
215 modest_maemo_utils_get_osso_context ();
217 osso_deinitialize (osso_context);
226 modest_platform_get_new_device (void)
228 return TNY_DEVICE (tny_maemo_conic_device_new ());
232 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
233 gchar **effective_mime_type)
235 GString *mime_str = NULL;
236 gchar *icon_name = NULL;
237 gchar **icons, **cursor;
239 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
240 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
242 mime_str = g_string_new (mime_type);
243 g_string_ascii_down (mime_str);
246 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
248 for (cursor = icons; cursor; ++cursor) {
249 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
250 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
251 icon_name = g_strdup ("qgn_list_messagin");
253 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
254 icon_name = g_strdup (*cursor);
260 if (effective_mime_type)
261 *effective_mime_type = g_string_free (mime_str, FALSE);
263 g_string_free (mime_str, TRUE);
270 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
275 g_return_val_if_fail (uri, FALSE);
277 result = hildon_uri_open (uri, action, &err);
279 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
280 uri, action, err && err->message ? err->message : "unknown error");
290 modest_platform_activate_uri (const gchar *uri)
292 HildonURIAction *action;
293 gboolean result = FALSE;
294 GSList *actions, *iter = NULL;
296 g_return_val_if_fail (uri, FALSE);
300 /* don't try to activate file: uri's -- they might confuse the user,
301 * and/or might have security implications */
302 if (!g_str_has_prefix (uri, "file:")) {
304 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
306 for (iter = actions; iter; iter = g_slist_next (iter)) {
307 action = (HildonURIAction*) iter->data;
308 if (action && strcmp (hildon_uri_action_get_service (action),
309 "com.nokia.modest") == 0) {
310 result = checked_hildon_uri_open (uri, action);
315 /* if we could not open it with email, try something else */
317 result = checked_hildon_uri_open (uri, NULL);
321 ModestWindow *parent =
322 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
323 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
324 _("mcen_ib_unsupported_link"));
325 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
332 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
336 gchar *uri_path = NULL;
338 uri_path = g_strconcat ("file://", path, NULL);
339 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
342 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
344 result = hildon_mime_open_file (con, uri_path);
346 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
354 } ModestPlatformPopupInfo;
357 delete_uri_popup (GtkWidget *menu,
361 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
363 g_free (popup_info->uri);
364 hildon_uri_free_actions (popup_info->actions);
370 activate_uri_popup_item (GtkMenuItem *menu_item,
374 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
375 const gchar* action_name;
377 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
379 g_printerr ("modest: no action name defined\n");
383 /* special handling for the copy menu item -- copy the uri to the clipboard */
384 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
385 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
386 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
387 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
389 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
390 action_name += strlen ("mailto:");
392 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
393 return; /* we're done */
396 /* now, the real uri-actions... */
397 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
398 HildonURIAction *action = (HildonURIAction *) node->data;
399 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
400 if (!checked_hildon_uri_open (popup_info->uri, action)) {
401 ModestWindow *parent =
402 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
403 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
404 _("mcen_ib_unsupported_link"));
412 modest_platform_show_uri_popup (const gchar *uri)
414 GSList *actions_list;
419 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
422 GtkWidget *menu = gtk_menu_new ();
423 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
425 /* don't add actions for file: uri's -- they might confuse the user,
426 * and/or might have security implications
427 * we still allow to copy the url though
429 if (!g_str_has_prefix (uri, "file:")) {
432 popup_info->actions = actions_list;
433 popup_info->uri = g_strdup (uri);
435 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
436 GtkWidget *menu_item;
437 const gchar *action_name;
438 const gchar *translation_domain;
439 HildonURIAction *action = (HildonURIAction *) node->data;
440 action_name = hildon_uri_action_get_name (action);
441 translation_domain = hildon_uri_action_get_translation_domain (action);
442 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
443 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
444 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
447 if (hildon_uri_is_default_action (action, NULL)) {
448 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
450 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
452 gtk_widget_show (menu_item);
456 /* always add the copy item */
457 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri",
458 "uri_link_copy_link_location"));
459 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
460 g_strconcat (URI_ACTION_COPY, uri, NULL),
462 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
463 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
464 gtk_widget_show (menu_item);
467 /* and what to do when the link is deleted */
468 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
469 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
472 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
480 modest_platform_get_icon (const gchar *name, guint icon_size)
483 GdkPixbuf* pixbuf = NULL;
484 GtkIconTheme *current_theme = NULL;
486 g_return_val_if_fail (name, NULL);
488 /* strlen == 0 is not really an error; it just
489 * means the icon is not available
491 if (!name || strlen(name) == 0)
494 current_theme = gtk_icon_theme_get_default ();
495 pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
496 GTK_ICON_LOOKUP_NO_SVG,
499 g_printerr ("modest: error loading theme icon '%s': %s\n",
507 modest_platform_get_app_name (void)
509 return _("mcen_ap_name");
513 entry_insert_text (GtkEditable *editable,
522 chars = gtk_editable_get_chars (editable, 0, -1);
523 chars_length = g_utf8_strlen (chars, -1);
525 /* Show WID-INF036 */
526 if (chars_length >= 20) {
527 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
528 _CS("ckdg_ib_maximum_characters_reached"));
530 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
534 tmp = g_strndup (folder_name_forbidden_chars,
535 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
536 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
537 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
542 /* Write the text in the entry if it's valid */
543 g_signal_handlers_block_by_func (editable,
544 (gpointer) entry_insert_text, data);
545 gtk_editable_insert_text (editable, text, length, position);
546 g_signal_handlers_unblock_by_func (editable,
547 (gpointer) entry_insert_text, data);
550 /* Do not allow further processing */
551 g_signal_stop_emission_by_name (editable, "insert_text");
555 entry_changed (GtkEditable *editable,
559 GtkWidget *ok_button;
562 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
563 ok_button = GTK_WIDGET (buttons->next->data);
565 chars = gtk_editable_get_chars (editable, 0, -1);
566 g_return_if_fail (chars != NULL);
569 if (g_utf8_strlen (chars,-1) >= 21)
570 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
571 _CS("ckdg_ib_maximum_characters_reached"));
573 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
576 g_list_free (buttons);
581 checked_hildon_sort_dialog_add_sort_key (HildonSortDialog *dialog, const gchar* key, guint max)
585 g_return_val_if_fail (dialog && HILDON_IS_SORT_DIALOG(dialog), 0);
586 g_return_val_if_fail (key, 0);
588 sort_key = hildon_sort_dialog_add_sort_key (dialog, key);
589 if (sort_key < 0 || sort_key >= max) {
590 g_warning ("%s: out of range (%d) for %s", __FUNCTION__, sort_key, key);
593 return (guint)sort_key;
598 launch_sort_headers_dialog (GtkWindow *parent_window,
599 HildonSortDialog *dialog)
601 ModestHeaderView *header_view = NULL;
603 GtkSortType sort_type;
605 gint default_key = 0;
607 gboolean outgoing = FALSE;
608 gint current_sort_colid = -1;
609 GtkSortType current_sort_type;
610 gint attachments_sort_id;
611 gint priority_sort_id;
612 GtkTreeSortable *sortable;
614 /* Get header window */
615 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
616 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
617 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
622 /* Add sorting keys */
623 cols = modest_header_view_get_columns (header_view);
626 #define SORT_ID_NUM 6
627 int sort_model_ids[SORT_ID_NUM];
628 int sort_ids[SORT_ID_NUM];
630 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
631 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
633 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"),
636 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
637 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
639 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
640 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
643 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"),
646 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
647 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
649 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
650 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
652 default_key = sort_key;
654 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"),
656 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
658 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
660 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
662 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"),
664 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
665 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
666 attachments_sort_id = sort_key;
668 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"),
670 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
671 sort_ids[sort_key] = 0;
673 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"),
675 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
676 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY_MASK;
677 priority_sort_id = sort_key;
679 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model
680 (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
682 if (!gtk_tree_sortable_get_sort_column_id (sortable,
683 ¤t_sort_colid, ¤t_sort_type)) {
684 hildon_sort_dialog_set_sort_key (dialog, default_key);
685 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
687 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
688 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
689 gpointer flags_sort_type_pointer;
690 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
691 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY_MASK)
692 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
694 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
696 gint current_sort_keyid = 0;
697 while (current_sort_keyid < 6) {
698 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
701 current_sort_keyid++;
703 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
707 result = gtk_dialog_run (GTK_DIALOG (dialog));
708 if (result == GTK_RESPONSE_OK) {
709 sort_key = hildon_sort_dialog_get_sort_key (dialog);
710 if (sort_key < 0 || sort_key > SORT_ID_NUM -1) {
711 g_warning ("%s: out of range (%d)", __FUNCTION__, sort_key);
715 sort_type = hildon_sort_dialog_get_sort_order (dialog);
716 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
717 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
718 GINT_TO_POINTER (sort_ids[sort_key]));
719 /* This is a hack to make it resort rows always when flag fields are
720 * selected. If we do not do this, changing sort field from priority to
721 * attachments does not work */
722 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
724 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
725 sort_model_ids[sort_key]);
728 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
729 gtk_tree_sortable_sort_column_changed (sortable);
732 modest_widget_memory_save (modest_runtime_get_conf (),
733 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
742 on_response (GtkDialog *dialog,
746 GList *child_vbox, *child_hbox;
747 GtkWidget *hbox, *entry;
748 TnyFolderStore *parent;
749 const gchar *new_name;
752 if (response != GTK_RESPONSE_ACCEPT)
756 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
757 hbox = child_vbox->data;
758 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
759 entry = child_hbox->next->data;
761 parent = TNY_FOLDER_STORE (user_data);
762 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
765 /* Look for another folder with the same name */
766 if (modest_tny_folder_has_subfolder_with_name (parent,
773 if (TNY_IS_ACCOUNT (parent) &&
774 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
775 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
784 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
785 NULL, _CS("ckdg_ib_folder_already_exists"));
786 /* Select the text */
787 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
788 gtk_widget_grab_focus (entry);
789 /* Do not close the dialog */
790 g_signal_stop_emission_by_name (dialog, "response");
797 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
798 TnyFolderStore *parent,
799 const gchar *dialog_title,
800 const gchar *label_text,
801 const gchar *suggested_name,
804 GtkWidget *accept_btn = NULL;
805 GtkWidget *dialog, *entry, *label, *hbox;
806 GList *buttons = NULL;
809 /* Ask the user for the folder name */
810 dialog = gtk_dialog_new_with_buttons (dialog_title,
812 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
813 _("mcen_bd_dialog_ok"),
815 _("mcen_bd_dialog_cancel"),
819 /* Add accept button (with unsensitive handler) */
820 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
821 accept_btn = GTK_WIDGET (buttons->next->data);
822 /* Create label and entry */
823 label = gtk_label_new (label_text);
824 /* TODO: check that the suggested name does not exist */
825 /* We set 21 as maximum because we want to show WID-INF036
826 when the user inputs more that 20 */
827 entry = gtk_entry_new_with_max_length (21);
829 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
831 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
832 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
834 /* Connect to the response method to avoid closing the dialog
835 when an invalid name is selected*/
836 g_signal_connect (dialog,
838 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),
851 /* Create the hbox */
852 hbox = gtk_hbox_new (FALSE, 12);
853 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
854 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
856 /* Add hbox to dialog */
857 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
858 hbox, FALSE, FALSE, 0);
860 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
861 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
863 result = gtk_dialog_run (GTK_DIALOG(dialog));
864 if (result == GTK_RESPONSE_ACCEPT)
865 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
867 gtk_widget_destroy (dialog);
869 while (gtk_events_pending ())
870 gtk_main_iteration ();
876 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
877 TnyFolderStore *parent_folder,
878 gchar *suggested_name,
881 gchar *real_suggested_name = NULL;
884 if(suggested_name == NULL)
886 const gchar *default_name = _("mcen_ia_default_folder_name");
890 for(i = 0; i < 100; ++ i) {
891 gboolean exists = FALSE;
893 sprintf(num_str, "%.2u", i);
896 real_suggested_name = g_strdup (default_name);
898 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
900 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
907 g_free (real_suggested_name);
910 /* Didn't find a free number */
912 real_suggested_name = g_strdup (default_name);
914 real_suggested_name = suggested_name;
917 result = modest_platform_run_folder_name_dialog (parent_window,
919 _("mcen_ti_new_folder"),
920 _("mcen_fi_new_folder_name"),
923 if (suggested_name == NULL)
924 g_free(real_suggested_name);
930 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
931 TnyFolderStore *parent_folder,
932 const gchar *suggested_name,
935 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
937 return modest_platform_run_folder_name_dialog (parent_window,
939 _HL("ckdg_ti_rename_folder"),
940 _HL("ckdg_fi_rename_name"),
948 on_destroy_dialog (GtkDialog *dialog)
950 gtk_widget_destroy (GTK_WIDGET(dialog));
951 if (gtk_events_pending ())
952 gtk_main_iteration ();
956 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
957 const gchar *message)
962 dialog = hildon_note_new_confirmation (parent_window, message);
963 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
964 GTK_WINDOW (dialog));
966 response = gtk_dialog_run (GTK_DIALOG (dialog));
968 on_destroy_dialog (GTK_DIALOG(dialog));
970 while (gtk_events_pending ())
971 gtk_main_iteration ();
977 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
978 const gchar *message,
979 const gchar *button_accept,
980 const gchar *button_cancel)
985 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
986 button_accept, GTK_RESPONSE_ACCEPT,
987 button_cancel, GTK_RESPONSE_CANCEL,
989 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
990 GTK_WINDOW (dialog));
992 response = gtk_dialog_run (GTK_DIALOG (dialog));
994 on_destroy_dialog (GTK_DIALOG(dialog));
996 while (gtk_events_pending ())
997 gtk_main_iteration ();
1003 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
1004 const gchar *message)
1009 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1010 _("mcen_bd_yes"), GTK_RESPONSE_YES,
1011 _("mcen_bd_no"), GTK_RESPONSE_NO,
1013 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
1014 response = gtk_dialog_run (GTK_DIALOG (dialog));
1016 on_destroy_dialog (GTK_DIALOG(dialog));
1018 while (gtk_events_pending ())
1019 gtk_main_iteration ();
1027 modest_platform_run_information_dialog (GtkWindow *parent_window,
1028 const gchar *message)
1032 note = hildon_note_new_information (parent_window, message);
1033 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1036 g_signal_connect_swapped (note,
1038 G_CALLBACK (on_destroy_dialog),
1041 gtk_widget_show_all (note);
1046 typedef struct _ConnectAndWaitData {
1048 GMainLoop *wait_loop;
1049 gboolean has_callback;
1051 } ConnectAndWaitData;
1055 quit_wait_loop (TnyAccount *account,
1056 ConnectAndWaitData *data)
1058 /* Set the has_callback to TRUE (means that the callback was
1059 executed and wake up every code waiting for cond to be
1061 g_mutex_lock (data->mutex);
1062 data->has_callback = TRUE;
1063 if (data->wait_loop)
1064 g_main_loop_quit (data->wait_loop);
1065 g_mutex_unlock (data->mutex);
1069 on_connection_status_changed (TnyAccount *account,
1070 TnyConnectionStatus status,
1073 TnyConnectionStatus conn_status;
1074 ConnectAndWaitData *data;
1076 /* Ignore if reconnecting or disconnected */
1077 conn_status = tny_account_get_connection_status (account);
1078 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1079 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1082 /* Remove the handler */
1083 data = (ConnectAndWaitData *) user_data;
1084 g_signal_handler_disconnect (account, data->handler);
1086 /* Quit from wait loop */
1087 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1091 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1096 /* Quit from wait loop */
1097 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1101 modest_platform_connect_and_wait (GtkWindow *parent_window,
1102 TnyAccount *account)
1104 ConnectAndWaitData *data = NULL;
1105 gboolean device_online;
1107 TnyConnectionStatus conn_status;
1108 gboolean user_requested;
1110 device = modest_runtime_get_device();
1111 device_online = tny_device_is_online (device);
1113 /* Whether the connection is user requested or automatically
1114 requested, for example via D-Bus */
1115 user_requested = (parent_window) ? TRUE : FALSE;
1117 /* If there is no account check only the device status */
1122 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1123 NULL, user_requested);
1126 /* Return if the account is already connected */
1127 conn_status = tny_account_get_connection_status (account);
1128 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1131 /* Create the helper */
1132 data = g_slice_new0 (ConnectAndWaitData);
1133 data->mutex = g_mutex_new ();
1134 data->has_callback = FALSE;
1136 /* Connect the device */
1137 if (!device_online) {
1138 /* Track account connection status changes */
1139 data->handler = g_signal_connect (account, "connection-status-changed",
1140 G_CALLBACK (on_connection_status_changed),
1142 /* Try to connect the device */
1143 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1144 NULL, user_requested);
1146 /* If the device connection failed then exit */
1147 if (!device_online && data->handler)
1150 /* Force a reconnection of the account */
1151 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1152 on_tny_camel_account_set_online_cb, data);
1155 /* Wait until the callback is executed */
1156 g_mutex_lock (data->mutex);
1157 if (!data->has_callback) {
1158 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1159 gdk_threads_leave ();
1160 g_mutex_unlock (data->mutex);
1161 g_main_loop_run (data->wait_loop);
1162 g_mutex_lock (data->mutex);
1163 gdk_threads_enter ();
1165 g_mutex_unlock (data->mutex);
1169 if (g_signal_handler_is_connected (account, data->handler))
1170 g_signal_handler_disconnect (account, data->handler);
1171 g_mutex_free (data->mutex);
1172 g_main_loop_unref (data->wait_loop);
1173 g_slice_free (ConnectAndWaitData, data);
1176 conn_status = tny_account_get_connection_status (account);
1177 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1181 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1183 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1184 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1185 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1186 /* This must be a maildir account, which does not require a connection: */
1191 return modest_platform_connect_and_wait (parent_window, account);
1195 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1198 return TRUE; /* Maybe it is something local. */
1200 gboolean result = TRUE;
1201 if (TNY_IS_FOLDER (folder_store)) {
1202 /* Get the folder's parent account: */
1203 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1204 if (account != NULL) {
1205 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1206 g_object_unref (account);
1208 } else if (TNY_IS_ACCOUNT (folder_store)) {
1209 /* Use the folder store as an account: */
1210 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1217 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1218 ModestSortDialogType type)
1220 GtkWidget *dialog = NULL;
1223 dialog = hildon_sort_dialog_new (parent_window);
1224 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1225 GTK_WINDOW (dialog));
1227 hildon_help_dialog_help_enable (GTK_DIALOG(dialog),
1228 "applications_email_sort",
1229 modest_maemo_utils_get_osso_context());
1231 /* Fill sort keys */
1233 case MODEST_SORT_HEADERS:
1234 launch_sort_headers_dialog (parent_window,
1235 HILDON_SORT_DIALOG(dialog));
1240 on_destroy_dialog (GTK_DIALOG(dialog));
1245 modest_platform_set_update_interval (guint minutes)
1247 #ifdef MODEST_HAVE_LIBALARM
1249 ModestConf *conf = modest_runtime_get_conf ();
1253 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1255 /* Delete any existing alarm,
1256 * because we will replace it: */
1258 if (alarm_event_del(alarm_cookie) != 1)
1259 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1261 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1264 /* 0 means no updates: */
1269 /* Register alarm: */
1271 /* Set the interval in alarm_event_t structure: */
1272 alarm_event_t *event = g_new0(alarm_event_t, 1);
1273 event->alarm_time = minutes * 60; /* seconds */
1275 /* Set recurrence every few minutes: */
1276 event->recurrence = minutes;
1277 event->recurrence_count = -1; /* Means infinite */
1279 /* Specify what should happen when the alarm happens:
1280 * It should call this D-Bus method: */
1282 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1283 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1284 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1285 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1287 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1288 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1289 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1290 * This is why we want to use the Alarm API instead of just g_timeout_add().
1291 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1293 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1295 alarm_cookie = alarm_event_add (event);
1298 alarm_event_free (event);
1300 /* Store the alarm ID in GConf, so we can remove it later:
1301 * This is apparently valid between application instances. */
1302 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1304 if (!alarm_cookie) {
1306 const alarm_error_t alarm_error = alarmd_get_error ();
1307 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1309 /* Give people some clue: */
1310 /* The alarm API should have a function for this: */
1311 if (alarm_error == ALARMD_ERROR_DBUS) {
1312 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1313 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1314 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1315 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1316 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1317 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1318 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1319 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1320 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1321 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1322 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1327 #endif /* MODEST_HAVE_LIBALARM */
1332 modest_platform_on_new_headers_received (TnyList *header_list)
1334 #ifdef MODEST_HAVE_HILDON_NOTIFY
1335 HildonNotification *notification;
1337 GSList *notifications_list = NULL;
1339 /* Get previous notifications ids */
1340 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1341 MODEST_CONF_NOTIFICATION_IDS,
1342 MODEST_CONF_VALUE_INT, NULL);
1344 iter = tny_list_create_iterator (header_list);
1345 while (!tny_iterator_is_done (iter)) {
1346 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1347 const gchar *display_date;
1348 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1349 TnyFolder *folder = tny_header_get_folder (header);
1350 gboolean first_notification = TRUE;
1353 /* constant string, don't free */
1354 display_date = modest_text_utils_get_display_date (tny_header_get_date_received (header));
1356 display_address = g_strdup(tny_header_get_from (header));
1357 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1359 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1360 notification = hildon_notification_new (summary,
1361 tny_header_get_subject (header),
1362 "qgn_list_messagin",
1364 /* Create the message URL */
1365 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1366 tny_header_get_uid (header));
1368 hildon_notification_add_dbus_action(notification,
1371 MODEST_DBUS_SERVICE,
1374 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1378 /* Play sound if the user wants. Show the LED
1379 pattern. Show and play just one */
1380 if (G_UNLIKELY (first_notification)) {
1381 first_notification = FALSE;
1382 if (modest_conf_get_bool (modest_runtime_get_conf (),
1383 MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1385 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1386 "sound-file", "/usr/share/sounds/ui-new_email.wav");
1389 /* Set the led pattern */
1390 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1392 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1394 "PatternCommunicationEmail");
1397 /* Notify. We need to do this in an idle because this function
1398 could be called from a thread */
1399 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1401 /* Save id in the list */
1402 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1403 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1404 /* We don't listen for the "closed" signal, because we
1405 don't care about if the notification was removed or
1406 not to store the list in gconf */
1408 /* Free & carry on */
1409 g_free (display_address);
1412 g_object_unref (folder);
1413 g_object_unref (header);
1414 tny_iterator_next (iter);
1416 g_object_unref (iter);
1419 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1420 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1422 g_slist_free (notifications_list);
1424 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1428 modest_platform_remove_new_mail_notifications (void)
1430 #ifdef MODEST_HAVE_HILDON_NOTIFY
1431 GSList *notif_list = NULL;
1433 /* Get previous notifications ids */
1434 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1435 MODEST_CONF_NOTIFICATION_IDS,
1436 MODEST_CONF_VALUE_INT, NULL);
1438 while (notif_list) {
1440 NotifyNotification *notif;
1442 /* Nasty HACK to remove the notifications, set the id
1443 of the existing ones and then close them */
1444 notif_id = GPOINTER_TO_INT(notif_list->data);
1445 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1446 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1448 /* Close the notification, note that some ids could be
1449 already invalid, but we don't care because it does
1451 notify_notification_close(notif, NULL);
1452 g_object_unref(notif);
1454 /* Delete the link, it's like going to the next */
1455 notif_list = g_slist_delete_link (notif_list, notif_list);
1459 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1460 notif_list, MODEST_CONF_VALUE_INT, NULL);
1462 g_slist_free (notif_list);
1464 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1470 modest_platform_get_global_settings_dialog ()
1472 return modest_maemo_global_settings_dialog_new ();
1476 modest_platform_show_help (GtkWindow *parent_window,
1477 const gchar *help_id)
1479 osso_return_t result;
1480 g_return_if_fail (help_id);
1482 result = hildon_help_show (modest_maemo_utils_get_osso_context(),
1483 help_id, HILDON_HELP_SHOW_DIALOG);
1485 if (result != OSSO_OK) {
1487 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1488 hildon_banner_show_information (GTK_WIDGET (parent_window),
1496 modest_platform_show_search_messages (GtkWindow *parent_window)
1498 osso_return_t result = OSSO_ERROR;
1500 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1501 "osso_global_search",
1502 "search_email", NULL, DBUS_TYPE_INVALID);
1504 if (result != OSSO_OK) {
1505 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1510 modest_platform_show_addressbook (GtkWindow *parent_window)
1512 osso_return_t result = OSSO_ERROR;
1514 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1516 "top_application", NULL, DBUS_TYPE_INVALID);
1518 if (result != OSSO_OK) {
1519 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1524 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1526 GtkWidget *widget = modest_folder_view_new (query);
1528 /* Show one account by default */
1529 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1530 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1533 /* Restore settings */
1534 modest_widget_memory_restore (modest_runtime_get_conf(),
1536 MODEST_CONF_FOLDER_VIEW_KEY);
1542 modest_platform_information_banner (GtkWidget *parent,
1543 const gchar *icon_name,
1546 hildon_banner_show_information (parent, icon_name, text);
1550 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1551 const gchar *icon_name,
1556 banner = hildon_banner_show_information (parent, icon_name, text);
1557 hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1561 modest_platform_animation_banner (GtkWidget *parent,
1562 const gchar *animation_name,
1565 GtkWidget *inf_note = NULL;
1567 g_return_val_if_fail (text != NULL, NULL);
1569 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1577 TnyAccount *account;
1580 } CheckAccountIdleData;
1582 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1585 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1587 gboolean stop_trying = FALSE;
1588 g_return_val_if_fail (data && data->account, FALSE);
1590 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1591 tny_account_get_connection_status (data->account));
1593 if (data && data->account &&
1594 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1595 * after which the account is likely to be usable, or never likely to be usable soon: */
1596 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1598 data->is_online = TRUE;
1602 /* Give up if we have tried too many times: */
1603 if (data->count_tries >= NUMBER_OF_TRIES) {
1606 /* Wait for another timeout: */
1607 ++(data->count_tries);
1612 /* Allow the function that requested this idle callback to continue: */
1614 g_main_loop_quit (data->loop);
1617 g_object_unref (data->account);
1619 return FALSE; /* Don't call this again. */
1621 return TRUE; /* Call this timeout callback again. */
1625 /* Return TRUE immediately if the account is already online,
1626 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1627 * soon as the account is online, or FALSE if the account does
1628 * not become online in the NUMBER_OF_TRIES seconds.
1629 * This is useful when the D-Bus method was run immediately after
1630 * the application was started (when using D-Bus activation),
1631 * because the account usually takes a short time to go online.
1632 * The return value is maybe not very useful.
1635 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1637 g_return_val_if_fail (account, FALSE);
1639 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1641 if (!tny_device_is_online (modest_runtime_get_device())) {
1642 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1646 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1647 * so we avoid wait unnecessarily: */
1648 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1649 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1653 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1654 __FUNCTION__, tny_account_get_connection_status (account));
1656 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1657 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1658 * we want to avoid. */
1659 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1662 /* This blocks on the result: */
1663 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1664 data->is_online = FALSE;
1665 data->account = account;
1666 g_object_ref (data->account);
1667 data->count_tries = 0;
1669 GMainContext *context = NULL; /* g_main_context_new (); */
1670 data->loop = g_main_loop_new (context, FALSE /* not running */);
1672 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1674 /* This main loop will run until the idle handler has stopped it: */
1675 g_main_loop_run (data->loop);
1677 g_main_loop_unref (data->loop);
1678 /* g_main_context_unref (context); */
1680 g_slice_free (CheckAccountIdleData, data);
1682 return data->is_online;
1688 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1690 /* GTK_RESPONSE_HELP means we need to show the certificate */
1691 if (response_id == GTK_RESPONSE_HELP) {
1695 /* Do not close the dialog */
1696 g_signal_stop_emission_by_name (dialog, "response");
1698 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1699 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1700 gtk_dialog_run (GTK_DIALOG(note));
1701 gtk_widget_destroy (note);
1707 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1708 const gchar *certificate)
1712 ModestWindow *main_win;
1714 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1715 g_warning ("%s: don't show dialogs if there's no main window; assuming 'Cancel'",
1720 /* don't create it */
1721 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
1722 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1725 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1728 note = hildon_note_new_confirmation_add_buttons (
1729 GTK_WINDOW(main_win),
1731 _("mcen_bd_dialog_ok"), GTK_RESPONSE_OK,
1732 _("mcen_bd_view"), GTK_RESPONSE_HELP, /* abusing this... */
1733 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1736 g_signal_connect (G_OBJECT(note), "response",
1737 G_CALLBACK(on_cert_dialog_response),
1738 (gpointer) certificate);
1740 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1742 response = gtk_dialog_run(GTK_DIALOG(note));
1744 on_destroy_dialog (GTK_DIALOG(note));
1747 return response == GTK_RESPONSE_OK;
1751 modest_platform_run_alert_dialog (const gchar* prompt,
1752 gboolean is_question)
1754 ModestWindow *main_win;
1756 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1757 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1758 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1759 return is_question ? FALSE : TRUE;
1762 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1763 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1765 gboolean retval = TRUE;
1767 /* The Tinymail documentation says that we should show Yes and No buttons,
1768 * when it is a question.
1769 * Obviously, we need tinymail to use more specific error codes instead,
1770 * so we know what buttons to show. */
1771 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1773 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1774 GTK_WINDOW (dialog));
1776 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1777 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1779 on_destroy_dialog (GTK_DIALOG(dialog));
1781 /* Just show the error text and use the default response: */
1782 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1790 GtkWindow *parent_window;
1791 ModestConnectedPerformer callback;
1792 TnyAccount *account;
1799 on_went_online_info_free (OnWentOnlineInfo *info)
1801 /* And if we cleanup, we DO cleanup :-) */
1804 g_object_unref (info->device);
1807 if (info->parent_window)
1808 g_object_unref (info->parent_window);
1810 g_object_unref (info->account);
1812 g_slice_free (OnWentOnlineInfo, info);
1814 /* We're done ... */
1820 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1822 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1824 /* Now it's really time to callback to the caller. If going online didn't succeed,
1825 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1826 * canceled will be set. Etcetera etcetera. */
1828 if (info->callback) {
1829 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1832 /* This is our last call, we must cleanup here if we didn't yet do that */
1833 on_went_online_info_free (info);
1840 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1842 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1843 info->iap = g_strdup (iap_id);
1845 if (canceled || err || !info->account) {
1847 /* If there's a problem or if there's no account (then that's it for us, we callback
1848 * the caller's callback now. He'll have to handle err or canceled, of course.
1849 * We are not really online, as the account is not really online here ... */
1851 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1852 * this info. We don't cleanup err, Tinymail does that! */
1854 if (info->callback) {
1856 /* info->account can be NULL here, this means that the user did not
1857 * provide a nice account instance. We'll assume that the user knows
1858 * what he's doing and is happy with just the device going online.
1860 * We can't do magic, we don't know what account the user wants to
1861 * see going online. So just the device goes online, end of story */
1863 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1866 } else if (info->account) {
1868 /* If there's no problem and if we have an account, we'll put the account
1869 * online too. When done, the callback of bringing the account online
1870 * will callback the caller's callback. This is the most normal case. */
1872 info->device = TNY_DEVICE (g_object_ref (device));
1874 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1875 on_account_went_online, info);
1877 /* The on_account_went_online cb frees up the info, go look if you
1878 * don't believe me! (so we return here) */
1883 /* We cleanup if we are not bringing the account online too */
1884 on_went_online_info_free (info);
1890 modest_platform_connect_and_perform (GtkWindow *parent_window,
1891 TnyAccount *account,
1892 ModestConnectedPerformer callback,
1895 gboolean device_online;
1897 TnyConnectionStatus conn_status;
1898 OnWentOnlineInfo *info;
1899 gboolean user_requested;
1901 device = modest_runtime_get_device();
1902 device_online = tny_device_is_online (device);
1904 /* Whether the connection is user requested or automatically
1905 requested, for example via D-Bus */
1906 user_requested = (parent_window) ? TRUE : FALSE;
1908 /* If there is no account check only the device status */
1911 if (device_online) {
1913 /* We promise to instantly perform the callback, so ... */
1915 callback (FALSE, NULL, parent_window, account, user_data);
1920 info = g_slice_new0 (OnWentOnlineInfo);
1923 info->device = NULL;
1924 info->account = NULL;
1927 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1929 info->parent_window = NULL;
1930 info->user_data = user_data;
1931 info->callback = callback;
1933 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1934 user_requested, on_conic_device_went_online,
1937 /* We'll cleanup in on_conic_device_went_online */
1940 /* The other code has no more reason to run. This is all that we can do for the
1941 * caller (he should have given us a nice and clean account instance!). We
1942 * can't do magic, we don't know what account he intends to bring online. So
1943 * we'll just bring the device online (and await his false bug report). */
1949 /* Return if the account is already connected */
1951 conn_status = tny_account_get_connection_status (account);
1952 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1954 /* We promise to instantly perform the callback, so ... */
1956 callback (FALSE, NULL, parent_window, account, user_data);
1962 /* Else, we are in a state that requires that we go online before we
1963 * call the caller's callback. */
1965 info = g_slice_new0 (OnWentOnlineInfo);
1967 info->device = NULL;
1969 info->account = TNY_ACCOUNT (g_object_ref (account));
1972 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1974 info->parent_window = NULL;
1976 /* So we'll put the callback away for later ... */
1978 info->user_data = user_data;
1979 info->callback = callback;
1981 if (!device_online) {
1983 /* If also the device is offline, then we connect both the device
1984 * and the account */
1986 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1987 user_requested, on_conic_device_went_online,
1992 /* If the device is online, we'll just connect the account */
1994 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1995 on_account_went_online, info);
1998 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1999 * in both situations, go look if you don't believe me! */
2005 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
2006 TnyFolderStore *folder_store,
2007 ModestConnectedPerformer callback,
2010 TnyAccount *account = NULL;
2012 if (!folder_store) {
2013 /* We promise to instantly perform the callback, so ... */
2015 callback (FALSE, NULL, parent_window, NULL, user_data);
2019 /* Original comment: Maybe it is something local. */
2020 /* PVH's comment: maybe we should KNOW this in stead of assuming? */
2022 } else if (TNY_IS_FOLDER (folder_store)) {
2023 /* Get the folder's parent account: */
2024 account = tny_folder_get_account(TNY_FOLDER (folder_store));
2025 } else if (TNY_IS_ACCOUNT (folder_store)) {
2026 /* Use the folder store as an account: */
2027 account = TNY_ACCOUNT (folder_store);
2030 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2031 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
2032 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
2034 /* This IS a local account like a maildir account, which does not require
2035 * a connection. (original comment had a vague assumption in its language
2036 * usage. There's no assuming needed, this IS what it IS: a local account), */
2038 /* We promise to instantly perform the callback, so ... */
2040 callback (FALSE, NULL, parent_window, account, user_data);
2047 modest_platform_connect_and_perform (parent_window, account, callback, user_data);
2053 modest_platform_get_account_settings_dialog (ModestAccountSettings *settings)
2055 ModestAccountSettingsDialog *dialog = modest_account_settings_dialog_new ();
2057 modest_account_settings_dialog_set_account (dialog, settings);
2058 return GTK_WIDGET (dialog);
2062 modest_platform_get_account_settings_wizard ()
2064 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2066 return GTK_WIDGET (dialog);