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_run_sort_dialog (GtkWindow *parent_window,
1186 ModestSortDialogType type)
1188 GtkWidget *dialog = NULL;
1191 dialog = hildon_sort_dialog_new (parent_window);
1192 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1193 GTK_WINDOW (dialog));
1195 hildon_help_dialog_help_enable (GTK_DIALOG(dialog),
1196 "applications_email_sort",
1197 modest_maemo_utils_get_osso_context());
1199 /* Fill sort keys */
1201 case MODEST_SORT_HEADERS:
1202 launch_sort_headers_dialog (parent_window,
1203 HILDON_SORT_DIALOG(dialog));
1208 on_destroy_dialog (GTK_DIALOG(dialog));
1213 modest_platform_set_update_interval (guint minutes)
1215 #ifdef MODEST_HAVE_LIBALARM
1217 ModestConf *conf = modest_runtime_get_conf ();
1221 cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1223 /* Delete any existing alarm,
1224 * because we will replace it: */
1226 if (alarm_event_del(alarm_cookie) != 1)
1227 g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1229 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1232 /* 0 means no updates: */
1237 /* Register alarm: */
1239 /* Set the interval in alarm_event_t structure: */
1240 alarm_event_t *event = g_new0(alarm_event_t, 1);
1241 event->alarm_time = minutes * 60; /* seconds */
1243 /* Set recurrence every few minutes: */
1244 event->recurrence = minutes;
1245 event->recurrence_count = -1; /* Means infinite */
1247 /* Specify what should happen when the alarm happens:
1248 * It should call this D-Bus method: */
1250 event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1251 event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1252 event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1253 event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1255 /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if
1256 * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1257 * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails
1258 * This is why we want to use the Alarm API instead of just g_timeout_add().
1259 * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1261 event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1263 alarm_cookie = alarm_event_add (event);
1266 alarm_event_free (event);
1268 /* Store the alarm ID in GConf, so we can remove it later:
1269 * This is apparently valid between application instances. */
1270 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1272 if (!alarm_cookie) {
1274 const alarm_error_t alarm_error = alarmd_get_error ();
1275 g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1277 /* Give people some clue: */
1278 /* The alarm API should have a function for this: */
1279 if (alarm_error == ALARMD_ERROR_DBUS) {
1280 g_debug (" ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1281 } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1282 g_debug (" ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1283 } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1284 g_debug (" ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1285 } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1286 g_debug (" ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1287 } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1288 g_debug (" ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1289 } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1290 g_debug (" ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1295 #endif /* MODEST_HAVE_LIBALARM */
1300 modest_platform_on_new_headers_received (TnyList *header_list)
1302 #ifdef MODEST_HAVE_HILDON_NOTIFY
1303 HildonNotification *notification;
1305 GSList *notifications_list = NULL;
1307 /* Get previous notifications ids */
1308 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1309 MODEST_CONF_NOTIFICATION_IDS,
1310 MODEST_CONF_VALUE_INT, NULL);
1312 iter = tny_list_create_iterator (header_list);
1313 while (!tny_iterator_is_done (iter)) {
1314 gchar *url = NULL, *display_address = NULL, *summary = NULL;
1315 const gchar *display_date;
1316 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1317 TnyFolder *folder = tny_header_get_folder (header);
1318 gboolean first_notification = TRUE;
1321 /* constant string, don't free */
1322 display_date = modest_text_utils_get_display_date (tny_header_get_date_received (header));
1324 display_address = g_strdup(tny_header_get_from (header));
1325 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1327 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1328 notification = hildon_notification_new (summary,
1329 tny_header_get_subject (header),
1330 "qgn_list_messagin",
1332 /* Create the message URL */
1333 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder),
1334 tny_header_get_uid (header));
1336 hildon_notification_add_dbus_action(notification,
1339 MODEST_DBUS_SERVICE,
1342 MODEST_DBUS_METHOD_OPEN_MESSAGE,
1346 /* Play sound if the user wants. Show the LED
1347 pattern. Show and play just one */
1348 if (G_UNLIKELY (first_notification)) {
1349 first_notification = FALSE;
1350 if (modest_conf_get_bool (modest_runtime_get_conf (),
1351 MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1353 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1354 "sound-file", "/usr/share/sounds/ui-new_email.wav");
1357 /* Set the led pattern */
1358 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1360 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1362 "PatternCommunicationEmail");
1365 /* Notify. We need to do this in an idle because this function
1366 could be called from a thread */
1367 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1369 /* Save id in the list */
1370 g_object_get(G_OBJECT(notification), "id", ¬if_id, NULL);
1371 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1372 /* We don't listen for the "closed" signal, because we
1373 don't care about if the notification was removed or
1374 not to store the list in gconf */
1376 /* Free & carry on */
1377 g_free (display_address);
1380 g_object_unref (folder);
1381 g_object_unref (header);
1382 tny_iterator_next (iter);
1384 g_object_unref (iter);
1387 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1388 notifications_list, MODEST_CONF_VALUE_INT, NULL);
1390 g_slist_free (notifications_list);
1392 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1396 modest_platform_remove_new_mail_notifications (void)
1398 #ifdef MODEST_HAVE_HILDON_NOTIFY
1399 GSList *notif_list = NULL;
1401 /* Get previous notifications ids */
1402 notif_list = modest_conf_get_list (modest_runtime_get_conf (),
1403 MODEST_CONF_NOTIFICATION_IDS,
1404 MODEST_CONF_VALUE_INT, NULL);
1406 while (notif_list) {
1408 NotifyNotification *notif;
1410 /* Nasty HACK to remove the notifications, set the id
1411 of the existing ones and then close them */
1412 notif_id = GPOINTER_TO_INT(notif_list->data);
1413 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1414 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1416 /* Close the notification, note that some ids could be
1417 already invalid, but we don't care because it does
1419 notify_notification_close(notif, NULL);
1420 g_object_unref(notif);
1422 /* Delete the link, it's like going to the next */
1423 notif_list = g_slist_delete_link (notif_list, notif_list);
1427 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1428 notif_list, MODEST_CONF_VALUE_INT, NULL);
1430 g_slist_free (notif_list);
1432 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1438 modest_platform_get_global_settings_dialog ()
1440 return modest_maemo_global_settings_dialog_new ();
1444 modest_platform_show_help (GtkWindow *parent_window,
1445 const gchar *help_id)
1447 osso_return_t result;
1448 g_return_if_fail (help_id);
1450 result = hildon_help_show (modest_maemo_utils_get_osso_context(),
1451 help_id, HILDON_HELP_SHOW_DIALOG);
1453 if (result != OSSO_OK) {
1455 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id);
1456 hildon_banner_show_information (GTK_WIDGET (parent_window),
1464 modest_platform_show_search_messages (GtkWindow *parent_window)
1466 osso_return_t result = OSSO_ERROR;
1468 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1469 "osso_global_search",
1470 "search_email", NULL, DBUS_TYPE_INVALID);
1472 if (result != OSSO_OK) {
1473 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1478 modest_platform_show_addressbook (GtkWindow *parent_window)
1480 osso_return_t result = OSSO_ERROR;
1482 result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1484 "top_application", NULL, DBUS_TYPE_INVALID);
1486 if (result != OSSO_OK) {
1487 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1492 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1494 GtkWidget *widget = modest_folder_view_new (query);
1496 /* Show one account by default */
1497 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1498 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1501 /* Restore settings */
1502 modest_widget_memory_restore (modest_runtime_get_conf(),
1504 MODEST_CONF_FOLDER_VIEW_KEY);
1510 modest_platform_information_banner (GtkWidget *parent,
1511 const gchar *icon_name,
1514 hildon_banner_show_information (parent, icon_name, text);
1518 modest_platform_animation_banner (GtkWidget *parent,
1519 const gchar *animation_name,
1522 GtkWidget *inf_note = NULL;
1524 g_return_val_if_fail (text != NULL, NULL);
1526 inf_note = hildon_banner_show_animation (parent, animation_name, text);
1534 TnyAccount *account;
1537 } CheckAccountIdleData;
1539 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1542 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1544 gboolean stop_trying = FALSE;
1545 g_return_val_if_fail (data && data->account, FALSE);
1547 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1548 tny_account_get_connection_status (data->account));
1550 if (data && data->account &&
1551 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1552 * after which the account is likely to be usable, or never likely to be usable soon: */
1553 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1555 data->is_online = TRUE;
1559 /* Give up if we have tried too many times: */
1560 if (data->count_tries >= NUMBER_OF_TRIES) {
1563 /* Wait for another timeout: */
1564 ++(data->count_tries);
1569 /* Allow the function that requested this idle callback to continue: */
1571 g_main_loop_quit (data->loop);
1574 g_object_unref (data->account);
1576 return FALSE; /* Don't call this again. */
1578 return TRUE; /* Call this timeout callback again. */
1582 /* Return TRUE immediately if the account is already online,
1583 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1584 * soon as the account is online, or FALSE if the account does
1585 * not become online in the NUMBER_OF_TRIES seconds.
1586 * This is useful when the D-Bus method was run immediately after
1587 * the application was started (when using D-Bus activation),
1588 * because the account usually takes a short time to go online.
1589 * The return value is maybe not very useful.
1592 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1594 g_return_val_if_fail (account, FALSE);
1596 printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1598 if (!tny_device_is_online (modest_runtime_get_device())) {
1599 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1603 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1604 * so we avoid wait unnecessarily: */
1605 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1606 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1610 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1611 __FUNCTION__, tny_account_get_connection_status (account));
1613 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1614 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1615 * we want to avoid. */
1616 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1619 /* This blocks on the result: */
1620 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1621 data->is_online = FALSE;
1622 data->account = account;
1623 g_object_ref (data->account);
1624 data->count_tries = 0;
1626 GMainContext *context = NULL; /* g_main_context_new (); */
1627 data->loop = g_main_loop_new (context, FALSE /* not running */);
1629 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1631 /* This main loop will run until the idle handler has stopped it: */
1632 g_main_loop_run (data->loop);
1634 g_main_loop_unref (data->loop);
1635 /* g_main_context_unref (context); */
1637 g_slice_free (CheckAccountIdleData, data);
1639 return data->is_online;
1645 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1647 /* GTK_RESPONSE_HELP means we need to show the certificate */
1648 if (response_id == GTK_RESPONSE_HELP) {
1652 /* Do not close the dialog */
1653 g_signal_stop_emission_by_name (dialog, "response");
1655 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1656 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1657 gtk_dialog_run (GTK_DIALOG(note));
1658 gtk_widget_destroy (note);
1664 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1665 const gchar *certificate)
1669 ModestWindow *main_win;
1671 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1672 g_warning ("%s: don't show dialogs if there's no main window; assuming 'Cancel'",
1677 /* don't create it */
1678 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
1679 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1682 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1685 note = hildon_note_new_confirmation_add_buttons (
1686 GTK_WINDOW(main_win),
1688 _("mcen_bd_dialog_ok"), GTK_RESPONSE_OK,
1689 _("mcen_bd_view"), GTK_RESPONSE_HELP, /* abusing this... */
1690 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1693 g_signal_connect (G_OBJECT(note), "response",
1694 G_CALLBACK(on_cert_dialog_response),
1695 (gpointer) certificate);
1697 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1699 response = gtk_dialog_run(GTK_DIALOG(note));
1701 on_destroy_dialog (GTK_DIALOG(note));
1704 return response == GTK_RESPONSE_OK;
1708 modest_platform_run_alert_dialog (const gchar* prompt,
1709 gboolean is_question)
1711 ModestWindow *main_win;
1713 if (!modest_window_mgr_main_window_exists (modest_runtime_get_window_mgr())) {
1714 g_warning ("%s:\n'%s'\ndon't show dialogs if there's no main window;"
1715 " assuming 'Cancel' for questions, 'Ok' otherwise", prompt, __FUNCTION__);
1716 return is_question ? FALSE : TRUE;
1719 main_win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1720 g_return_val_if_fail (main_win, FALSE); /* should not happen */
1722 gboolean retval = TRUE;
1724 /* The Tinymail documentation says that we should show Yes and No buttons,
1725 * when it is a question.
1726 * Obviously, we need tinymail to use more specific error codes instead,
1727 * so we know what buttons to show. */
1728 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_win),
1730 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1731 GTK_WINDOW (dialog));
1733 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1734 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1736 on_destroy_dialog (GTK_DIALOG(dialog));
1738 /* Just show the error text and use the default response: */
1739 modest_platform_run_information_dialog (GTK_WINDOW (main_win),
1747 GtkWindow *parent_window;
1748 ModestConnectedPerformer callback;
1749 TnyAccount *account;
1756 on_went_online_info_free (OnWentOnlineInfo *info)
1758 /* And if we cleanup, we DO cleanup :-) */
1761 g_object_unref (info->device);
1764 if (info->parent_window)
1765 g_object_unref (info->parent_window);
1767 g_object_unref (info->account);
1769 g_slice_free (OnWentOnlineInfo, info);
1771 /* We're done ... */
1777 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1779 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1781 /* Now it's really time to callback to the caller. If going online didn't succeed,
1782 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1783 * canceled will be set. Etcetera etcetera. */
1785 if (info->callback) {
1786 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1789 /* This is our last call, we must cleanup here if we didn't yet do that */
1790 on_went_online_info_free (info);
1797 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1799 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1800 info->iap = g_strdup (iap_id);
1802 if (canceled || err || !info->account) {
1804 /* If there's a problem or if there's no account (then that's it for us, we callback
1805 * the caller's callback now. He'll have to handle err or canceled, of course.
1806 * We are not really online, as the account is not really online here ... */
1808 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
1809 * this info. We don't cleanup err, Tinymail does that! */
1811 if (info->callback) {
1813 /* info->account can be NULL here, this means that the user did not
1814 * provide a nice account instance. We'll assume that the user knows
1815 * what he's doing and is happy with just the device going online.
1817 * We can't do magic, we don't know what account the user wants to
1818 * see going online. So just the device goes online, end of story */
1820 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1823 } else if (info->account) {
1825 /* If there's no problem and if we have an account, we'll put the account
1826 * online too. When done, the callback of bringing the account online
1827 * will callback the caller's callback. This is the most normal case. */
1829 info->device = TNY_DEVICE (g_object_ref (device));
1831 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
1832 on_account_went_online, info);
1834 /* The on_account_went_online cb frees up the info, go look if you
1835 * don't believe me! (so we return here) */
1840 /* We cleanup if we are not bringing the account online too */
1841 on_went_online_info_free (info);
1847 modest_platform_connect_and_perform (GtkWindow *parent_window,
1848 TnyAccount *account,
1849 ModestConnectedPerformer callback,
1852 gboolean device_online;
1854 TnyConnectionStatus conn_status;
1855 OnWentOnlineInfo *info;
1856 gboolean user_requested;
1858 device = modest_runtime_get_device();
1859 device_online = tny_device_is_online (device);
1861 /* Whether the connection is user requested or automatically
1862 requested, for example via D-Bus */
1863 user_requested = (parent_window) ? TRUE : FALSE;
1865 /* If there is no account check only the device status */
1868 if (device_online) {
1870 /* We promise to instantly perform the callback, so ... */
1872 callback (FALSE, NULL, parent_window, account, user_data);
1877 info = g_slice_new0 (OnWentOnlineInfo);
1880 info->device = NULL;
1881 info->account = NULL;
1884 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1886 info->parent_window = NULL;
1887 info->user_data = user_data;
1888 info->callback = callback;
1890 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1891 user_requested, on_conic_device_went_online,
1894 /* We'll cleanup in on_conic_device_went_online */
1897 /* The other code has no more reason to run. This is all that we can do for the
1898 * caller (he should have given us a nice and clean account instance!). We
1899 * can't do magic, we don't know what account he intends to bring online. So
1900 * we'll just bring the device online (and await his false bug report). */
1906 /* Return if the account is already connected */
1908 conn_status = tny_account_get_connection_status (account);
1909 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1911 /* We promise to instantly perform the callback, so ... */
1913 callback (FALSE, NULL, parent_window, account, user_data);
1919 /* Else, we are in a state that requires that we go online before we
1920 * call the caller's callback. */
1922 info = g_slice_new0 (OnWentOnlineInfo);
1924 info->device = NULL;
1926 info->account = TNY_ACCOUNT (g_object_ref (account));
1929 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1931 info->parent_window = NULL;
1933 /* So we'll put the callback away for later ... */
1935 info->user_data = user_data;
1936 info->callback = callback;
1938 if (!device_online) {
1940 /* If also the device is offline, then we connect both the device
1941 * and the account */
1943 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
1944 user_requested, on_conic_device_went_online,
1949 /* If the device is online, we'll just connect the account */
1951 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1952 on_account_went_online, info);
1955 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1956 * in both situations, go look if you don't believe me! */
1962 modest_platform_connect_and_perform_if_network_account (GtkWindow *parent_window,
1963 TnyAccount *account,
1964 ModestConnectedPerformer callback,
1967 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1968 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1969 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1971 /* This IS a local account like a maildir account, which does not require
1972 * a connection. (original comment had a vague assumption in its language
1973 * usage. There's no assuming needed, this IS what it IS: a local account), */
1975 /* We promise to instantly perform the callback, so ... */
1977 callback (FALSE, NULL, parent_window, account, user_data);
1984 modest_platform_connect_and_perform (parent_window, account, callback, user_data);
1990 modest_platform_connect_and_perform_if_network_folderstore (GtkWindow *parent_window,
1991 TnyFolderStore *folder_store,
1992 ModestConnectedPerformer callback,
1995 if (!folder_store) {
1997 /* We promise to instantly perform the callback, so ... */
1999 callback (FALSE, NULL, parent_window, NULL, user_data);
2003 /* Original comment: Maybe it is something local. */
2004 /* PVH's comment: maybe we should KNOW this in stead of assuming? */
2008 if (TNY_IS_FOLDER (folder_store)) {
2009 /* Get the folder's parent account: */
2010 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
2011 if (account != NULL) {
2012 modest_platform_connect_and_perform_if_network_account (NULL, account, callback, user_data);
2013 g_object_unref (account);
2015 } else if (TNY_IS_ACCOUNT (folder_store)) {
2016 /* Use the folder store as an account: */
2017 modest_platform_connect_and_perform_if_network_account (NULL, TNY_ACCOUNT (folder_store), callback, user_data);