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>
57 #ifdef MODEST_HAVE_ABOOK
58 #include <libosso-abook/osso-abook.h>
59 #endif /*MODEST_HAVE_ABOOK*/
61 #ifdef MODEST_HAVE_LIBALARM
62 #include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
63 #endif /*MODEST_HAVE_LIBALARM*/
66 #define HILDON_OSSO_URI_ACTION "uri-action"
67 #define URI_ACTION_COPY "copy:"
70 on_modest_conf_update_interval_changed (ModestConf* self,
72 ModestConfEvent event,
73 ModestConfNotificationId id,
76 g_return_if_fail (key);
78 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
79 const guint update_interval_minutes =
80 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
81 modest_platform_set_update_interval (update_interval_minutes);
88 check_required_files (void)
90 FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
92 g_printerr ("modest: check for mcc file failed\n");
97 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
98 access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
99 g_printerr ("modest: cannot find providers data\n");
107 /* the gpointer here is the osso_context. */
109 modest_platform_init (int argc, char *argv[])
111 osso_context_t *osso_context;
113 osso_hw_state_t hw_state = { 0 };
117 if (!check_required_files ()) {
118 g_printerr ("modest: missing required files\n");
122 osso_context = osso_initialize(PACKAGE,PACKAGE_VERSION,
125 g_printerr ("modest: failed to acquire osso context\n");
128 modest_maemo_utils_set_osso_context (osso_context);
130 if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
131 g_printerr ("modest: could not get dbus connection\n");
135 /* Add a D-Bus handler to be used when the main osso-rpc
136 * D-Bus handler has not handled something.
137 * We use this for D-Bus methods that need to use more complex types
138 * than osso-rpc supports.
140 if (!dbus_connection_add_filter (con,
141 modest_dbus_req_filter,
145 g_printerr ("modest: Could not add D-Bus filter\n");
149 /* Register our simple D-Bus callbacks, via the osso API: */
150 osso_return_t result = osso_rpc_set_cb_f(osso_context,
154 modest_dbus_req_handler, NULL /* user_data */);
155 if (result != OSSO_OK) {
156 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
160 /* Register hardware event dbus callback: */
161 hw_state.shutdown_ind = TRUE;
162 osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
164 /* Register osso auto-save callbacks: */
165 result = osso_application_set_autosave_cb (osso_context,
166 modest_on_osso_application_autosave, NULL /* user_data */);
167 if (result != OSSO_OK) {
168 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
173 /* Make sure that the update interval is changed whenever its gconf key
175 /* CAUTION: we're not using here the
176 modest_conf_listen_to_namespace because we know that there
177 are other parts of Modest listening for this namespace, so
178 we'll receive the notifications anyway. We basically do not
179 use it because there is no easy way to do the
180 modest_conf_forget_namespace */
181 ModestConf *conf = modest_runtime_get_conf ();
182 g_signal_connect (G_OBJECT(conf),
184 G_CALLBACK (on_modest_conf_update_interval_changed),
187 /* only force the setting of the default interval, if there are actually
189 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
191 /* Get the initial update interval from gconf: */
192 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
193 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
194 modest_account_mgr_free_account_names (acc_names);
198 #ifdef MODEST_HAVE_ABOOK
199 /* initialize the addressbook */
200 if (!osso_abook_init (&argc, &argv, osso_context)) {
201 g_printerr ("modest: failed to initialized addressbook\n");
204 #endif /*MODEST_HAVE_ABOOK*/
210 modest_platform_uninit (void)
212 osso_context_t *osso_context =
213 modest_maemo_utils_get_osso_context ();
215 osso_deinitialize (osso_context);
224 modest_platform_get_new_device (void)
226 return TNY_DEVICE (tny_maemo_conic_device_new ());
230 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
231 gchar **effective_mime_type)
233 GString *mime_str = NULL;
234 gchar *icon_name = NULL;
235 gchar **icons, **cursor;
237 if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream"))
238 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
240 mime_str = g_string_new (mime_type);
241 g_string_ascii_down (mime_str);
244 icons = hildon_mime_get_icon_names (mime_str->str, NULL);
245 for (cursor = icons; cursor; ++cursor) {
246 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
247 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
248 icon_name = g_strdup ("qgn_list_messagin");
250 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
251 icon_name = g_strdup (*cursor);
257 if (effective_mime_type)
258 *effective_mime_type = g_string_free (mime_str, FALSE);
260 g_string_free (mime_str, TRUE);
267 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
272 g_return_val_if_fail (uri, FALSE);
274 result = hildon_uri_open (uri, action, &err);
276 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
277 uri, action, err && err->message ? err->message : "unknown error");
287 modest_platform_activate_uri (const gchar *uri)
289 HildonURIAction *action;
290 gboolean result = FALSE;
291 GSList *actions, *iter = NULL;
293 g_return_val_if_fail (uri, FALSE);
297 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
299 for (iter = actions; iter; iter = g_slist_next (iter)) {
300 action = (HildonURIAction*) iter->data;
301 if (action && strcmp (hildon_uri_action_get_service (action),
302 "com.nokia.modest") == 0) {
303 result = checked_hildon_uri_open (uri, action);
308 /* if we could not open it with email, try something else */
310 result = checked_hildon_uri_open (uri, NULL);
313 ModestWindow *parent =
314 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
315 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
316 _("mcen_ib_unsupported_link"));
323 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
327 gchar *uri_path = NULL;
329 uri_path = g_strconcat ("file://", path, NULL);
330 con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
333 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
335 result = hildon_mime_open_file (con, uri_path);
337 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
345 } ModestPlatformPopupInfo;
348 delete_uri_popup (GtkWidget *menu,
352 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
354 g_free (popup_info->uri);
355 hildon_uri_free_actions (popup_info->actions);
361 activate_uri_popup_item (GtkMenuItem *menu_item,
365 ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
366 const gchar* action_name;
368 action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
370 g_printerr ("modest: no action name defined\n");
374 /* special handling for the copy menu item -- copy the uri to the clipboard */
375 /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
376 if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
377 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
378 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
380 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
381 action_name += strlen ("mailto:");
383 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
384 return; /* we're done */
387 /* now, the real uri-actions... */
388 for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
389 HildonURIAction *action = (HildonURIAction *) node->data;
390 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
391 if (!checked_hildon_uri_open (popup_info->uri, action)) {
392 ModestWindow *parent =
393 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
394 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
395 _("mcen_ib_unsupported_link"));
403 modest_platform_show_uri_popup (const gchar *uri)
405 GSList *actions_list;
410 actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
411 if (actions_list != NULL) {
413 GtkWidget *menu = gtk_menu_new ();
414 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
416 popup_info->actions = actions_list;
417 popup_info->uri = g_strdup (uri);
419 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
420 GtkWidget *menu_item;
421 const gchar *action_name;
422 const gchar *translation_domain;
423 HildonURIAction *action = (HildonURIAction *) node->data;
424 action_name = hildon_uri_action_get_name (action);
425 translation_domain = hildon_uri_action_get_translation_domain (action);
426 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
427 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name); /* hack */
428 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
431 if (hildon_uri_is_default_action (action, NULL)) {
432 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
434 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
436 gtk_widget_show (menu_item);
439 /* always add the copy item */
440 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
441 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
442 g_strconcat (URI_ACTION_COPY, uri, NULL),
444 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
445 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
446 gtk_widget_show (menu_item);
449 /* and what to do when the link is deleted */
450 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
451 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
454 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
462 modest_platform_get_icon (const gchar *name)
465 GdkPixbuf* pixbuf = NULL;
466 GtkIconTheme *current_theme = NULL;
468 g_return_val_if_fail (name, NULL);
470 /* strlen == 0 is not really an error; it just
471 * means the icon is not available
473 if (!name || strlen(name) == 0)
476 #if 0 /* do we still need this? */
477 if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
478 pixbuf = gdk_pixbuf_new_from_file (name, &err);
480 g_printerr ("modest: error loading icon '%s': %s\n",
488 current_theme = gtk_icon_theme_get_default ();
489 pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
490 GTK_ICON_LOOKUP_NO_SVG,
493 g_printerr ("modest: error loading theme icon '%s': %s\n",
501 modest_platform_get_app_name (void)
503 return _("mcen_ap_name");
507 entry_insert_text (GtkEditable *editable,
516 chars = gtk_editable_get_chars (editable, 0, -1);
517 chars_length = g_utf8_strlen (chars, -1);
519 /* Show WID-INF036 */
520 if (chars_length >= 20) {
521 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
522 _CS("ckdg_ib_maximum_characters_reached"));
524 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
528 tmp = g_strndup (folder_name_forbidden_chars,
529 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
530 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
531 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (data)),
536 /* Write the text in the entry if it's valid */
537 g_signal_handlers_block_by_func (editable,
538 (gpointer) entry_insert_text, data);
539 gtk_editable_insert_text (editable, text, length, position);
540 g_signal_handlers_unblock_by_func (editable,
541 (gpointer) entry_insert_text, data);
544 /* Do not allow further processing */
545 g_signal_stop_emission_by_name (editable, "insert_text");
549 entry_changed (GtkEditable *editable,
553 GtkWidget *ok_button;
556 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
557 ok_button = GTK_WIDGET (buttons->next->data);
559 chars = gtk_editable_get_chars (editable, 0, -1);
560 g_return_if_fail (chars != NULL);
563 if (g_utf8_strlen (chars,-1) >= 21)
564 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
565 _CS("ckdg_ib_maximum_characters_reached"));
567 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
570 g_list_free (buttons);
575 checked_hildon_sort_dialog_add_sort_key (HildonSortDialog *dialog, const gchar* key, guint max)
579 g_return_val_if_fail (dialog && HILDON_IS_SORT_DIALOG(dialog), 0);
580 g_return_val_if_fail (key, 0);
582 sort_key = hildon_sort_dialog_add_sort_key (dialog, key);
583 if (sort_key < 0 || sort_key >= max) {
584 g_warning ("%s: out of range (%d) for %s", __FUNCTION__, sort_key, key);
587 return (guint)sort_key;
592 launch_sort_headers_dialog (GtkWindow *parent_window,
593 HildonSortDialog *dialog)
595 ModestHeaderView *header_view = NULL;
597 GtkSortType sort_type;
599 gint default_key = 0;
601 gboolean outgoing = FALSE;
602 gint current_sort_colid = -1;
603 GtkSortType current_sort_type;
604 gint attachments_sort_id;
605 gint priority_sort_id;
606 GtkTreeSortable *sortable;
608 /* Get header window */
609 if (MODEST_IS_MAIN_WINDOW (parent_window)) {
610 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
611 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
616 /* Add sorting keys */
617 cols = modest_header_view_get_columns (header_view);
620 #define SORT_ID_NUM 6
621 int sort_model_ids[SORT_ID_NUM];
622 int sort_ids[SORT_ID_NUM];
624 outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
625 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
627 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"),
630 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
631 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
633 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
634 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
637 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"),
640 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
641 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
643 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
644 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
646 default_key = sort_key;
648 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"),
650 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
652 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
654 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
656 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"),
658 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
659 sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
660 attachments_sort_id = sort_key;
662 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"),
664 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
665 sort_ids[sort_key] = 0;
667 sort_key = checked_hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"),
669 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
670 sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY_MASK;
671 priority_sort_id = sort_key;
673 sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model
674 (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
676 if (!gtk_tree_sortable_get_sort_column_id (sortable,
677 ¤t_sort_colid, ¤t_sort_type)) {
678 hildon_sort_dialog_set_sort_key (dialog, default_key);
679 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
681 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
682 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
683 gpointer flags_sort_type_pointer;
684 flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
685 if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY_MASK)
686 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
688 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
690 gint current_sort_keyid = 0;
691 while (current_sort_keyid < 6) {
692 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
695 current_sort_keyid++;
697 hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
701 result = gtk_dialog_run (GTK_DIALOG (dialog));
702 if (result == GTK_RESPONSE_OK) {
703 sort_key = hildon_sort_dialog_get_sort_key (dialog);
704 if (sort_key < 0 || sort_key > SORT_ID_NUM -1) {
705 g_warning ("%s: out of range (%d)", __FUNCTION__, sort_key);
709 sort_type = hildon_sort_dialog_get_sort_order (dialog);
710 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
711 g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
712 GINT_TO_POINTER (sort_ids[sort_key]));
713 /* This is a hack to make it resort rows always when flag fields are
714 * selected. If we do not do this, changing sort field from priority to
715 * attachments does not work */
716 modest_header_view_sort_by_column_id (header_view, 0, sort_type);
718 gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data),
719 sort_model_ids[sort_key]);
722 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
723 gtk_tree_sortable_sort_column_changed (sortable);
726 modest_widget_memory_save (modest_runtime_get_conf (),
727 G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
736 on_response (GtkDialog *dialog,
740 GList *child_vbox, *child_hbox;
741 GtkWidget *hbox, *entry;
742 TnyFolderStore *parent;
743 const gchar *new_name;
746 if (response != GTK_RESPONSE_ACCEPT)
750 child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
751 hbox = child_vbox->data;
752 child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
753 entry = child_hbox->next->data;
755 parent = TNY_FOLDER_STORE (user_data);
756 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
759 /* Look for another folder with the same name */
760 if (modest_tny_folder_has_subfolder_with_name (parent,
767 if (TNY_IS_ACCOUNT (parent) &&
768 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
769 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
778 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)),
779 NULL, _CS("ckdg_ib_folder_already_exists"));
780 /* Select the text */
781 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
782 gtk_widget_grab_focus (entry);
783 /* Do not close the dialog */
784 g_signal_stop_emission_by_name (dialog, "response");
791 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
792 TnyFolderStore *parent,
793 const gchar *dialog_title,
794 const gchar *label_text,
795 const gchar *suggested_name,
798 GtkWidget *accept_btn = NULL;
799 GtkWidget *dialog, *entry, *label, *hbox;
800 GList *buttons = NULL;
803 /* Ask the user for the folder name */
804 dialog = gtk_dialog_new_with_buttons (dialog_title,
806 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
807 _("mcen_bd_dialog_ok"),
809 _("mcen_bd_dialog_cancel"),
813 /* Add accept button (with unsensitive handler) */
814 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
815 accept_btn = GTK_WIDGET (buttons->next->data);
816 /* Create label and entry */
817 label = gtk_label_new (label_text);
818 /* TODO: check that the suggested name does not exist */
819 /* We set 21 as maximum because we want to show WID-INF036
820 when the user inputs more that 20 */
821 entry = gtk_entry_new_with_max_length (21);
823 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
825 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
826 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
828 /* Connect to the response method to avoid closing the dialog
829 when an invalid name is selected*/
830 g_signal_connect (dialog,
832 G_CALLBACK (on_response),
835 /* Track entry changes */
836 g_signal_connect (entry,
838 G_CALLBACK (entry_insert_text),
840 g_signal_connect (entry,
842 G_CALLBACK (entry_changed),
845 /* Create the hbox */
846 hbox = gtk_hbox_new (FALSE, 12);
847 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
848 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
850 /* Add hbox to dialog */
851 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
852 hbox, FALSE, FALSE, 0);
854 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
855 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
857 result = gtk_dialog_run (GTK_DIALOG(dialog));
858 if (result == GTK_RESPONSE_ACCEPT)
859 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
861 gtk_widget_destroy (dialog);
863 while (gtk_events_pending ())
864 gtk_main_iteration ();
870 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
871 TnyFolderStore *parent_folder,
872 gchar *suggested_name,
875 gchar *real_suggested_name = NULL;
878 if(suggested_name == NULL)
880 const gchar *default_name = _("mcen_ia_default_folder_name");
884 for(i = 0; i < 100; ++ i) {
885 gboolean exists = FALSE;
887 sprintf(num_str, "%.2u", i);
890 real_suggested_name = g_strdup (default_name);
892 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
894 exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
901 g_free (real_suggested_name);
904 /* Didn't find a free number */
906 real_suggested_name = g_strdup (default_name);
908 real_suggested_name = suggested_name;
911 result = modest_platform_run_folder_name_dialog (parent_window,
913 _("mcen_ti_new_folder"),
914 _("mcen_fi_new_folder_name"),
917 if (suggested_name == NULL)
918 g_free(real_suggested_name);
924 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
925 TnyFolderStore *parent_folder,
926 const gchar *suggested_name,
929 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
931 return modest_platform_run_folder_name_dialog (parent_window,
933 _HL("ckdg_ti_rename_folder"),
934 _HL("ckdg_fi_rename_name"),
942 on_destroy_dialog (GtkDialog *dialog)
944 gtk_widget_destroy (GTK_WIDGET(dialog));
945 if (gtk_events_pending ())
946 gtk_main_iteration ();
950 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
951 const gchar *message)
956 dialog = hildon_note_new_confirmation (parent_window, message);
957 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
958 GTK_WINDOW (dialog));
960 response = gtk_dialog_run (GTK_DIALOG (dialog));
962 on_destroy_dialog (GTK_DIALOG(dialog));
964 while (gtk_events_pending ())
965 gtk_main_iteration ();
971 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
972 const gchar *message)
977 dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
978 _("mcen_bd_yes"), GTK_RESPONSE_YES,
979 _("mcen_bd_no"), GTK_RESPONSE_NO,
981 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
982 response = gtk_dialog_run (GTK_DIALOG (dialog));
984 on_destroy_dialog (GTK_DIALOG(dialog));
986 while (gtk_events_pending ())
987 gtk_main_iteration ();
995 modest_platform_run_information_dialog (GtkWindow *parent_window,
996 const gchar *message)
1000 note = hildon_note_new_information (parent_window, message);
1001 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1004 g_signal_connect_swapped (note,
1006 G_CALLBACK (on_destroy_dialog),
1009 gtk_widget_show_all (note);
1014 typedef struct _ConnectAndWaitData {
1016 GMainLoop *wait_loop;
1017 gboolean has_callback;
1019 } ConnectAndWaitData;
1023 quit_wait_loop (TnyAccount *account,
1024 ConnectAndWaitData *data)
1026 /* Set the has_callback to TRUE (means that the callback was
1027 executed and wake up every code waiting for cond to be
1029 g_mutex_lock (data->mutex);
1030 data->has_callback = TRUE;
1031 if (data->wait_loop)
1032 g_main_loop_quit (data->wait_loop);
1033 g_mutex_unlock (data->mutex);
1037 on_connection_status_changed (TnyAccount *account,
1038 TnyConnectionStatus status,
1041 TnyConnectionStatus conn_status;
1042 ConnectAndWaitData *data;
1044 /* Ignore if reconnecting or disconnected */
1045 conn_status = tny_account_get_connection_status (account);
1046 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1047 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1050 /* Remove the handler */
1051 data = (ConnectAndWaitData *) user_data;
1052 g_signal_handler_disconnect (account, data->handler);
1054 /* Quit from wait loop */
1055 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1059 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1064 /* Quit from wait loop */
1065 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1069 modest_platform_connect_and_wait (GtkWindow *parent_window,
1070 TnyAccount *account)
1072 ConnectAndWaitData *data = NULL;
1073 gboolean device_online;
1075 TnyConnectionStatus conn_status;
1076 gboolean user_requested;
1078 device = modest_runtime_get_device();
1079 device_online = tny_device_is_online (device);
1081 /* Whether the connection is user requested or automatically
1082 requested, for example via D-Bus */
1083 user_requested = (parent_window) ? TRUE : FALSE;
1085 /* If there is no account check only the device status */
1090 return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1091 NULL, user_requested);
1094 /* Return if the account is already connected */
1095 conn_status = tny_account_get_connection_status (account);
1096 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1099 /* Create the helper */
1100 data = g_slice_new0 (ConnectAndWaitData);
1101 data->mutex = g_mutex_new ();
1102 data->has_callback = FALSE;
1104 /* Connect the device */
1105 if (!device_online) {
1106 /* Track account connection status changes */
1107 data->handler = g_signal_connect (account, "connection-status-changed",
1108 G_CALLBACK (on_connection_status_changed),
1110 /* Try to connect the device */
1111 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device),
1112 NULL, user_requested);
1114 /* If the device connection failed then exit */
1115 if (!device_online && data->handler)
1118 /* Force a reconnection of the account */
1119 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1120 on_tny_camel_account_set_online_cb, data);
1123 /* Wait until the callback is executed */
1124 g_mutex_lock (data->mutex);
1125 if (!data->has_callback) {
1126 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1127 gdk_threads_leave ();
1128 g_mutex_unlock (data->mutex);
1129 g_main_loop_run (data->wait_loop);
1130 g_mutex_lock (data->mutex);
1131 gdk_threads_enter ();
1133 g_mutex_unlock (data->mutex);
1137 if (g_signal_handler_is_connected (account, data->handler))
1138 g_signal_handler_disconnect (account, data->handler);
1139 g_mutex_free (data->mutex);
1140 g_main_loop_unref (data->wait_loop);
1141 g_slice_free (ConnectAndWaitData, data);
1144 conn_status = tny_account_get_connection_status (account);
1145 return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1149 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1151 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1152 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1153 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1154 /* This must be a maildir account, which does not require a connection: */
1159 return modest_platform_connect_and_wait (parent_window, account);
1163 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1166 return TRUE; /* Maybe it is something local. */
1168 gboolean result = TRUE;
1169 if (TNY_IS_FOLDER (folder_store)) {
1170 /* Get the folder's parent account: */
1171 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1172 if (account != NULL) {
1173 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1174 g_object_unref (account);
1176 } else if (TNY_IS_ACCOUNT (folder_store)) {
1177 /* Use the folder store as an account: */
1178 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1185 modest_platform_is_network_folderstore (TnyFolderStore *folder_store)
1187 TnyAccount *account = NULL;
1188 gboolean result = TRUE;
1190 g_return_val_if_fail(TNY_IS_FOLDER_STORE(folder_store), FALSE);
1192 if (TNY_IS_FOLDER (folder_store)) {
1193 /* Get the folder's parent account: */
1194 account = tny_folder_get_account(TNY_FOLDER(folder_store));
1195 } else if (TNY_IS_ACCOUNT (folder_store)) {
1196 account = TNY_ACCOUNT(folder_store);
1197 g_object_ref(account);
1200 if (account != NULL) {
1201 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1202 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1203 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1204 /* This must be a maildir account, which does
1205 * not require a connection: */
1209 g_object_unref (account);
1218 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1219 ModestSortDialogType type)
1221 GtkWidget *dialog = NULL;
1224 dialog = hildon_sort_dialog_new (parent_window);
1225 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1226 GTK_WINDOW (dialog));
1228 hildon_help_dialog_help_enable (GTK_DIALOG(dialog),
1229 "applications_email_sort",
1230 modest_maemo_utils_get_osso_context());
1232 /* Fill sort keys */
1234 case MODEST_SORT_HEADERS:
1235 launch_sort_headers_dialog (parent_window,
1236 HILDON_SORT_DIALOG(dialog));
1241 on_destroy_dialog (GTK_DIALOG(dialog));
1246 modest_platform_set_update_interval (guint minutes)
1248 #ifdef MODEST_HAVE_LIBALARM
1250 ModestConf *conf = modest_runtime_get_conf ();
1254 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1256 /* Delete any existing alarm,
1257 * because we will replace it: */
1259 if (alarm_event_del(alarm_cookie) != 1)
1260 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1262 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1265 /* 0 means no updates: */
1270 /* Register alarm: */
1272 /* Set the interval in alarm_event_t structure: */
1273 alarm_event_t *event = g_new0(alarm_event_t, 1);
1274 event->alarm_time = minutes * 60; /* seconds */
1276 /* Set recurrence every few minutes: */
1277 event->recurrence = minutes;
1278 event->recurrence_count = -1; /* Means infinite */
1280 /* Specify what should happen when the alarm happens:
1281 * It should call this D-Bus method: */
1283 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1284 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1285 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1286 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1288 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1289 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1290 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1291 * This is why we want to use the Alarm API instead of just g_timeout_add().
1292 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1294 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1296 alarm_cookie = alarm_event_add (event);
1299 alarm_event_free (event);
1301 /* Store the alarm ID in GConf, so we can remove it later:
1302 * This is apparently valid between application instances. */
1303 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1305 if (!alarm_cookie) {
1307 const alarm_error_t alarm_error = alarmd_get_error ();
1308 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1310 /* Give people some clue: */
1311 /* The alarm API should have a function for this: */
1312 if (alarm_error == ALARMD_ERROR_DBUS) {
1313 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1314 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1315 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1316 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1317 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1318 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1319 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1320 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1321 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1322 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1323 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1328 #endif /* MODEST_HAVE_LIBALARM */
1333 modest_platform_on_new_headers_received (TnyList *header_list)
1335 #ifdef MODEST_HAVE_HILDON_NOTIFY
1336 HildonNotification *notification;
1338 GSList *notifications_list = NULL;
1340 /* Get previous notifications ids */
1341 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1342 MODEST_CONF_NOTIFICATION_IDS,
1343 MODEST_CONF_VALUE_INT, NULL);
1345 iter = tny_list_create_iterator (header_list);
1346 while (!tny_iterator_is_done (iter)) {
1347 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1348 const gchar *display_date;
1349 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1350 TnyFolder *folder = tny_header_get_folder (header);
1351 gboolean first_notification = TRUE;
1354 /* constant string, don't free */
1355 display_date = modest_text_utils_get_display_date (tny_header_get_date_received (header));
1357 display_address = g_strdup(tny_header_get_from (header));
1358 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1360 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1361 notification = hildon_notification_new (summary,
1362 tny_header_get_subject (header),
1363 "qgn_list_messagin",
1365 /* Create the message URL */
1366 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1367 tny_header_get_uid (header));
1369 hildon_notification_add_dbus_action(notification,
1372 MODEST_DBUS_SERVICE,
1375 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1379 /* Play sound if the user wants. Show the LED
1380 pattern. Show and play just one */
1381 if (G_UNLIKELY (first_notification)) {
1382 first_notification = FALSE;
1383 if (modest_conf_get_bool (modest_runtime_get_conf (),
1384 MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1386 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1387 "sound-file", "/usr/share/sounds/ui-new_email.wav");
1390 /* Set the led pattern */
1391 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1393 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1395 "PatternCommunicationEmail");
1398 /* Notify. We need to do this in an idle because this function
1399 could be called from a thread */
1400 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1402 /* Save id in the list */
1403 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1404 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1405 /* We don't listen for the "closed" signal, because we
1406 don't care about if the notification was removed or
1407 not to store the list in gconf */
1409 /* Free & carry on */
1410 g_free (display_address);
1413 g_object_unref (folder);
1414 g_object_unref (header);
1415 tny_iterator_next (iter);
1417 g_object_unref (iter);
1420 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1421 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1423 g_slist_free (notifications_list);
1425 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1429 modest_platform_remove_new_mail_notifications (void)
1431 #ifdef MODEST_HAVE_HILDON_NOTIFY
1432 GSList *notif_list = NULL;
1434 /* Get previous notifications ids */
1435 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1436 MODEST_CONF_NOTIFICATION_IDS,
1437 MODEST_CONF_VALUE_INT, NULL);
1439 while (notif_list) {
1441 NotifyNotification *notif;
1443 /* Nasty HACK to remove the notifications, set the id
1444 of the existing ones and then close them */
1445 notif_id = GPOINTER_TO_INT(notif_list->data);
1446 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1447 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1449 /* Close the notification, note that some ids could be
1450 already invalid, but we don't care because it does
1452 notify_notification_close(notif, NULL);
1453 g_object_unref(notif);
1455 /* Delete the link, it's like going to the next */
1456 notif_list = g_slist_delete_link (notif_list, notif_list);
1460 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1461 notif_list, MODEST_CONF_VALUE_INT, NULL);
1463 g_slist_free (notif_list);
1465 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1471 modest_platform_get_global_settings_dialog ()
1473 return modest_maemo_global_settings_dialog_new ();
1477 modest_platform_show_help (GtkWindow *parent_window,
1478 const gchar *help_id)
1480 osso_return_t result;
1481 g_return_if_fail (help_id);
1483 result = hildon_help_show (modest_maemo_utils_get_osso_context(),
1484 help_id, HILDON_HELP_SHOW_DIALOG);
1486 if (result != OSSO_OK) {
1488 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1489 hildon_banner_show_information (GTK_WIDGET (parent_window),
1497 modest_platform_show_search_messages (GtkWindow *parent_window)
1499 osso_return_t result = OSSO_ERROR;
1501 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1502 "osso_global_search",
1503 "search_email", NULL, DBUS_TYPE_INVALID);
1505 if (result != OSSO_OK) {
1506 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1511 modest_platform_show_addressbook (GtkWindow *parent_window)
1513 osso_return_t result = OSSO_ERROR;
1515 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1517 "top_application", NULL, DBUS_TYPE_INVALID);
1519 if (result != OSSO_OK) {
1520 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1525 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1527 GtkWidget *widget = modest_folder_view_new (query);
1529 /* Show one account by default */
1530 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1531 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1534 /* Restore settings */
1535 modest_widget_memory_restore (modest_runtime_get_conf(),
1537 MODEST_CONF_FOLDER_VIEW_KEY);
1543 modest_platform_information_banner (GtkWidget *parent,
1544 const gchar *icon_name,
1547 hildon_banner_show_information (parent, icon_name, text);
1551 modest_platform_animation_banner (GtkWidget *parent,
1552 const gchar *animation_name,
1555 GtkWidget *inf_note = NULL;
1557 g_return_val_if_fail (text != NULL, NULL);
1559 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1567 TnyAccount *account;
1570 } CheckAccountIdleData;
1572 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1575 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1577 gboolean stop_trying = FALSE;
1578 g_return_val_if_fail (data && data->account, FALSE);
1580 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1581 tny_account_get_connection_status (data->account));
1583 if (data && data->account &&
1584 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1585 * after which the account is likely to be usable, or never likely to be usable soon: */
1586 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1588 data->is_online = TRUE;
1592 /* Give up if we have tried too many times: */
1593 if (data->count_tries >= NUMBER_OF_TRIES) {
1596 /* Wait for another timeout: */
1597 ++(data->count_tries);
1602 /* Allow the function that requested this idle callback to continue: */
1604 g_main_loop_quit (data->loop);
1607 g_object_unref (data->account);
1609 return FALSE; /* Don't call this again. */
1611 return TRUE; /* Call this timeout callback again. */
1615 /* Return TRUE immediately if the account is already online,
1616 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1617 * soon as the account is online, or FALSE if the account does
1618 * not become online in the NUMBER_OF_TRIES seconds.
1619 * This is useful when the D-Bus method was run immediately after
1620 * the application was started (when using D-Bus activation),
1621 * because the account usually takes a short time to go online.
1622 * The return value is maybe not very useful.
1625 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1627 g_return_val_if_fail (account, FALSE);
1629 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1631 if (!tny_device_is_online (modest_runtime_get_device())) {
1632 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1636 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1637 * so we avoid wait unnecessarily: */
1638 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1639 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1643 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1644 __FUNCTION__, tny_account_get_connection_status (account));
1646 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1647 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1648 * we want to avoid. */
1649 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1652 /* This blocks on the result: */
1653 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1654 data->is_online = FALSE;
1655 data->account = account;
1656 g_object_ref (data->account);
1657 data->count_tries = 0;
1659 GMainContext *context = NULL; /* g_main_context_new (); */
1660 data->loop = g_main_loop_new (context, FALSE /* not running */);
1662 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1664 /* This main loop will run until the idle handler has stopped it: */
1665 g_main_loop_run (data->loop);
1667 g_main_loop_unref (data->loop);
1668 /* g_main_context_unref (context); */
1670 g_slice_free (CheckAccountIdleData, data);
1672 return data->is_online;
1678 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1680 /* GTK_RESPONSE_HELP means we need to show the certificate */
1681 if (response_id == GTK_RESPONSE_HELP) {
1685 /* Do not close the dialog */
1686 g_signal_stop_emission_by_name (dialog, "response");
1688 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1689 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1690 gtk_dialog_run (GTK_DIALOG(note));
1691 gtk_widget_destroy (note);
1697 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1698 const gchar *certificate)
1702 ModestWindow *main_win;
1704 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1705 g_warning ("%s: don't show dialogs if there's no main window; assuming 'Cancel'",
1710 /* don't create it */
1711 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
1712 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1715 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1718 note = hildon_note_new_confirmation_add_buttons (
1719 GTK_WINDOW(main_win),
1721 _("mcen_bd_dialog_ok"), GTK_RESPONSE_OK,
1722 _("mcen_bd_view"), GTK_RESPONSE_HELP, /* abusing this... */
1723 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1726 g_signal_connect (G_OBJECT(note), "response",
1727 G_CALLBACK(on_cert_dialog_response),
1728 (gpointer) certificate);
1730 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1732 response = gtk_dialog_run(GTK_DIALOG(note));
1734 on_destroy_dialog (GTK_DIALOG(note));
1737 return response == GTK_RESPONSE_OK;
1741 modest_platform_run_alert_dialog (const gchar* prompt,
1742 gboolean is_question)
1744 ModestWindow *main_win;
1746 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1747 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1748 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1749 return is_question ? FALSE : TRUE;
1752 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1753 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1755 gboolean retval = TRUE;
1757 /* The Tinymail documentation says that we should show Yes and No buttons,
1758 * when it is a question.
1759 * Obviously, we need tinymail to use more specific error codes instead,
1760 * so we know what buttons to show. */
1761 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1763 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1764 GTK_WINDOW (dialog));
1766 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1767 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1769 on_destroy_dialog (GTK_DIALOG(dialog));
1771 /* Just show the error text and use the default response: */
1772 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1780 GtkWindow *parent_window;
1781 ModestConnectedPerformer callback;
1782 TnyAccount *account;
1789 on_went_online_info_free (OnWentOnlineInfo *info)
1791 /* And if we cleanup, we DO cleanup :-) */
1794 g_object_unref (info->device);
1797 if (info->parent_window)
1798 g_object_unref (info->parent_window);
1800 g_object_unref (info->account);
1802 g_slice_free (OnWentOnlineInfo, info);
1804 /* We're done ... */
1810 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1812 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1814 /* Now it's really time to callback to the caller. If going online didn't succeed,
1815 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1816 * canceled will be set. Etcetera etcetera. */
1818 if (info->callback) {
1819 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1822 /* This is our last call, we must cleanup here if we didn't yet do that */
1823 on_went_online_info_free (info);
1830 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1832 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1833 info->iap = g_strdup (iap_id);
1835 if (canceled || err || !info->account) {
1837 /* If there's a problem or if there's no account (then that's it for us, we callback
1838 * the caller's callback now. He'll have to handle err or canceled, of course.
1839 * We are not really online, as the account is not really online here ... */
1841 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1842 * this info. We don't cleanup err, Tinymail does that! */
1844 if (info->callback) {
1846 /* info->account can be NULL here, this means that the user did not
1847 * provide a nice account instance. We'll assume that the user knows
1848 * what he's doing and is happy with just the device going online.
1850 * We can't do magic, we don't know what account the user wants to
1851 * see going online. So just the device goes online, end of story */
1853 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1856 } else if (info->account) {
1858 /* If there's no problem and if we have an account, we'll put the account
1859 * online too. When done, the callback of bringing the account online
1860 * will callback the caller's callback. This is the most normal case. */
1862 info->device = TNY_DEVICE (g_object_ref (device));
1864 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1865 on_account_went_online, info);
1867 /* The on_account_went_online cb frees up the info, go look if you
1868 * don't believe me! (so we return here) */
1873 /* We cleanup if we are not bringing the account online too */
1874 on_went_online_info_free (info);
1880 modest_platform_connect_and_perform (GtkWindow *parent_window,
1881 TnyAccount *account,
1882 ModestConnectedPerformer callback,
1885 gboolean device_online;
1887 TnyConnectionStatus conn_status;
1888 OnWentOnlineInfo *info;
1889 gboolean user_requested;
1891 device = modest_runtime_get_device();
1892 device_online = tny_device_is_online (device);
1894 /* Whether the connection is user requested or automatically
1895 requested, for example via D-Bus */
1896 user_requested = (parent_window) ? TRUE : FALSE;
1898 /* If there is no account check only the device status */
1901 if (device_online) {
1903 /* We promise to instantly perform the callback, so ... */
1905 callback (FALSE, NULL, parent_window, account, user_data);
1910 info = g_slice_new0 (OnWentOnlineInfo);
1913 info->device = NULL;
1914 info->account = NULL;
1917 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1919 info->parent_window = NULL;
1920 info->user_data = user_data;
1921 info->callback = callback;
1923 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1924 user_requested, on_conic_device_went_online,
1927 /* We'll cleanup in on_conic_device_went_online */
1930 /* The other code has no more reason to run. This is all that we can do for the
1931 * caller (he should have given us a nice and clean account instance!). We
1932 * can't do magic, we don't know what account he intends to bring online. So
1933 * we'll just bring the device online (and await his false bug report). */
1939 /* Return if the account is already connected */
1941 conn_status = tny_account_get_connection_status (account);
1942 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1944 /* We promise to instantly perform the callback, so ... */
1946 callback (FALSE, NULL, parent_window, account, user_data);
1952 /* Else, we are in a state that requires that we go online before we
1953 * call the caller's callback. */
1955 info = g_slice_new0 (OnWentOnlineInfo);
1957 info->device = NULL;
1959 info->account = TNY_ACCOUNT (g_object_ref (account));
1962 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1964 info->parent_window = NULL;
1966 /* So we'll put the callback away for later ... */
1968 info->user_data = user_data;
1969 info->callback = callback;
1971 if (!device_online) {
1973 /* If also the device is offline, then we connect both the device
1974 * and the account */
1976 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1977 user_requested, on_conic_device_went_online,
1982 /* If the device is online, we'll just connect the account */
1984 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1985 on_account_went_online, info);
1988 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1989 * in both situations, go look if you don't believe me! */
1995 modest_platform_connect_and_perform_if_network_account (GtkWindow *parent_window,
1996 TnyAccount *account,
1997 ModestConnectedPerformer callback,
2000 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2001 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
2002 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
2004 /* This IS a local account like a maildir account, which does not require
2005 * a connection. (original comment had a vague assumption in its language
2006 * usage. There's no assuming needed, this IS what it IS: a local account), */
2008 /* We promise to instantly perform the callback, so ... */
2010 callback (FALSE, NULL, parent_window, account, user_data);
2017 modest_platform_connect_and_perform (parent_window, account, callback, user_data);
2023 modest_platform_connect_and_perform_if_network_folderstore (GtkWindow *parent_window,
2024 TnyFolderStore *folder_store,
2025 ModestConnectedPerformer callback,
2028 if (!folder_store) {
2030 /* We promise to instantly perform the callback, so ... */
2032 callback (FALSE, NULL, parent_window, NULL, user_data);
2036 /* Original comment: Maybe it is something local. */
2037 /* PVH's comment: maybe we should KNOW this in stead of assuming? */
2041 if (TNY_IS_FOLDER (folder_store)) {
2042 /* Get the folder's parent account: */
2043 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
2044 if (account != NULL) {
2045 modest_platform_connect_and_perform_if_network_account (NULL, account, callback, user_data);
2046 g_object_unref (account);
2048 } else if (TNY_IS_ACCOUNT (folder_store)) {
2049 /* Use the folder store as an account: */
2050 modest_platform_connect_and_perform_if_network_account (NULL, TNY_ACCOUNT (folder_store), callback, user_data);