aboutsummaryrefslogtreecommitdiffstats
path: root/mail/e-mail-reader-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'mail/e-mail-reader-utils.c')
-rw-r--r--mail/e-mail-reader-utils.c2469
1 files changed, 2469 insertions, 0 deletions
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
new file mode 100644
index 0000000000..acd52950c8
--- /dev/null
+++ b/mail/e-mail-reader-utils.c
@@ -0,0 +1,2469 @@
+/*
+ * e-mail-reader-utils.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* Miscellaneous utility functions used by EMailReader actions. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-reader-utils.h"
+
+#include <glib/gi18n.h>
+#include <libxml/tree.h>
+#include <gtkhtml/gtkhtml.h>
+#include <camel/camel.h>
+
+#include "shell/e-shell-utils.h"
+
+#include "libemail-engine/e-mail-folder-utils.h"
+#include "libemail-engine/e-mail-utils.h"
+#include "libemail-engine/mail-ops.h"
+#include "libemail-engine/mail-tools.h"
+
+#include "em-format/e-mail-parser.h"
+#include "em-format/e-mail-part-utils.h"
+
+#include "composer/e-composer-actions.h"
+
+#include "e-mail-backend.h"
+#include "e-mail-browser.h"
+#include "e-mail-printer.h"
+#include "e-mail-display.h"
+#include "em-composer-utils.h"
+#include "em-utils.h"
+#include "mail-autofilter.h"
+#include "mail-vfolder-ui.h"
+#include "message-list.h"
+
+#define d(x)
+
+typedef struct _AsyncContext AsyncContext;
+
+struct _AsyncContext {
+ EActivity *activity;
+ CamelFolder *folder;
+ CamelMimeMessage *message;
+ EMailPartList *part_list;
+ EMailReader *reader;
+ CamelInternetAddress *address;
+ GPtrArray *uids;
+ gchar *folder_name;
+ gchar *message_uid;
+
+ EMailReplyType reply_type;
+ EMailReplyStyle reply_style;
+ EMailForwardStyle forward_style;
+ GtkPrintOperationAction print_action;
+ const gchar *filter_source;
+ gint filter_type;
+ gboolean replace;
+ gboolean keep_signature;
+};
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+ g_clear_object (&async_context->activity);
+ g_clear_object (&async_context->folder);
+ g_clear_object (&async_context->message);
+ g_clear_object (&async_context->part_list);
+ g_clear_object (&async_context->reader);
+ g_clear_object (&async_context->address);
+
+ if (async_context->uids != NULL)
+ g_ptr_array_unref (async_context->uids);
+
+ g_free (async_context->folder_name);
+ g_free (async_context->message_uid);
+
+ g_slice_free (AsyncContext, async_context);
+}
+
+static gboolean
+mail_reader_is_special_local_folder (const gchar *name)
+{
+ return (strcmp (name, "Drafts") == 0 ||
+ strcmp (name, "Inbox") == 0 ||
+ strcmp (name, "Outbox") == 0 ||
+ strcmp (name, "Sent") == 0 ||
+ strcmp (name, "Templates") == 0);
+}
+
+gboolean
+e_mail_reader_confirm_delete (EMailReader *reader)
+{
+ CamelFolder *folder;
+ CamelStore *parent_store;
+ GtkWidget *check_button;
+ GtkWidget *container;
+ GtkWidget *dialog;
+ GtkWindow *window;
+ GSettings *settings;
+ const gchar *label;
+ gboolean prompt_delete_in_vfolder;
+ gint response = GTK_RESPONSE_OK;
+
+ /* Remind users what deleting from a search folder does. */
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE);
+
+ folder = e_mail_reader_ref_folder (reader);
+ window = e_mail_reader_get_window (reader);
+
+ settings = g_settings_new ("org.gnome.evolution.mail");
+
+ prompt_delete_in_vfolder = g_settings_get_boolean (
+ settings, "prompt-on-delete-in-vfolder");
+
+ parent_store = camel_folder_get_parent_store (folder);
+
+ if (!CAMEL_IS_VEE_STORE (parent_store))
+ goto exit;
+
+ if (!prompt_delete_in_vfolder)
+ goto exit;
+
+ dialog = e_alert_dialog_new_for_args (
+ window, "mail:ask-delete-vfolder-msg",
+ camel_folder_get_full_name (folder), NULL);
+
+ container = e_alert_dialog_get_content_area (E_ALERT_DIALOG (dialog));
+
+ label = _("Do not warn me again");
+ check_button = gtk_check_button_new_with_label (label);
+ gtk_box_pack_start (GTK_BOX (container), check_button, TRUE, TRUE, 6);
+ gtk_widget_show (check_button);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response != GTK_RESPONSE_DELETE_EVENT)
+ g_settings_set_boolean (
+ settings,
+ "prompt-on-delete-in-vfolder",
+ !gtk_toggle_button_get_active (
+ GTK_TOGGLE_BUTTON (check_button)));
+
+ gtk_widget_destroy (dialog);
+
+exit:
+ g_clear_object (&folder);
+
+ return (response == GTK_RESPONSE_OK);
+}
+
+static void
+mail_reader_delete_folder_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder;
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ folder = CAMEL_FOLDER (source_object);
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ e_mail_folder_remove_finish (folder, result, &local_error);
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-delete-folder",
+ camel_folder_get_full_name (folder),
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ }
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_delete_folder (EMailReader *reader,
+ CamelFolder *folder)
+{
+ EMailBackend *backend;
+ EMailSession *session;
+ EShell *shell;
+ EAlertSink *alert_sink;
+ CamelStore *parent_store;
+ CamelProvider *provider;
+ MailFolderCache *folder_cache;
+ GtkWindow *parent = e_shell_get_active_window (NULL);
+ GtkWidget *dialog;
+ gboolean store_is_local;
+ const gchar *display_name;
+ const gchar *full_name;
+ CamelFolderInfoFlags flags = 0;
+ gboolean have_flags;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+ full_name = camel_folder_get_full_name (folder);
+ display_name = camel_folder_get_display_name (folder);
+ parent_store = camel_folder_get_parent_store (folder);
+ provider = camel_service_get_provider (CAMEL_SERVICE (parent_store));
+
+ store_is_local = (provider->flags & CAMEL_PROVIDER_IS_LOCAL) != 0;
+
+ backend = e_mail_reader_get_backend (reader);
+ session = e_mail_backend_get_session (backend);
+
+ alert_sink = e_mail_reader_get_alert_sink (reader);
+ folder_cache = e_mail_session_get_folder_cache (session);
+
+ if (store_is_local &&
+ mail_reader_is_special_local_folder (full_name)) {
+ e_alert_submit (
+ alert_sink, "mail:no-delete-special-folder",
+ display_name, NULL);
+ return;
+ }
+
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
+
+ if (!store_is_local && !e_shell_get_online (shell))
+ {
+ e_alert_submit (
+ alert_sink, "mail:online-operation",
+ display_name, NULL);
+ return;
+ }
+
+ have_flags = mail_folder_cache_get_folder_info_flags (
+ folder_cache, parent_store, full_name, &flags);
+
+ if (have_flags && (flags & CAMEL_FOLDER_SYSTEM)) {
+ e_alert_submit (
+ alert_sink, "mail:no-delete-special-folder",
+ display_name, NULL);
+ return;
+ }
+
+ if (have_flags && (flags & CAMEL_FOLDER_CHILDREN)) {
+ if (CAMEL_IS_VEE_STORE (parent_store))
+ dialog = e_alert_dialog_new_for_args (
+ parent, "mail:ask-delete-vfolder",
+ display_name, NULL);
+ else
+ dialog = e_alert_dialog_new_for_args (
+ parent, "mail:ask-delete-folder",
+ display_name, NULL);
+ } else {
+ if (CAMEL_IS_VEE_STORE (parent_store))
+ dialog = e_alert_dialog_new_for_args (
+ parent, "mail:ask-delete-vfolder-nochild",
+ display_name, NULL);
+ else
+ dialog = e_alert_dialog_new_for_args (
+ parent, "mail:ask-delete-folder-nochild",
+ display_name, NULL);
+ }
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+
+ /* Disable the dialog until the activity finishes. */
+ gtk_widget_set_sensitive (dialog, FALSE);
+
+ /* Destroy the dialog once the activity finishes. */
+ g_object_set_data_full (
+ G_OBJECT (activity), "delete-dialog",
+ dialog, (GDestroyNotify) gtk_widget_destroy);
+
+ e_mail_folder_remove (
+ folder,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_delete_folder_cb,
+ async_context);
+
+ g_object_unref (activity);
+ } else {
+ gtk_widget_destroy (dialog);
+ }
+}
+
+static void
+mail_reader_delete_folder_name_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder;
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ /* XXX The returned CamelFolder is a borrowed reference. */
+ folder = camel_store_get_folder_finish (
+ CAMEL_STORE (source_object), result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((folder != NULL) && (local_error == NULL)) ||
+ ((folder == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-delete-folder",
+ async_context->folder_name,
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ e_mail_reader_delete_folder (async_context->reader, folder);
+ }
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_delete_folder_name (EMailReader *reader,
+ CamelStore *store,
+ const gchar *folder_name)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_STORE (store));
+ g_return_if_fail (folder_name != NULL);
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+ async_context->folder_name = g_strdup (folder_name);
+
+ camel_store_get_folder (
+ store, folder_name,
+ CAMEL_STORE_FOLDER_INFO_FAST,
+ G_PRIORITY_DEFAULT, cancellable,
+ mail_reader_delete_folder_name_cb,
+ async_context);
+
+ g_object_unref (activity);
+}
+
+/* Helper for e_mail_reader_expunge_folder() */
+static void
+mail_reader_expunge_folder_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder;
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ folder = CAMEL_FOLDER (source_object);
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ e_mail_folder_expunge_finish (folder, result, &local_error);
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-expunge-folder",
+ camel_folder_get_display_name (folder),
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ }
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_expunge_folder (EMailReader *reader,
+ CamelFolder *folder)
+{
+ GtkWindow *window;
+ const gchar *display_name;
+ gboolean proceed;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+ window = e_mail_reader_get_window (reader);
+ display_name = camel_folder_get_display_name (folder);
+
+ proceed = em_utils_prompt_user (
+ window, "prompt-on-expunge",
+ "mail:ask-expunge", display_name, NULL);
+
+ if (proceed) {
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+
+ e_mail_folder_expunge (
+ folder,
+ G_PRIORITY_DEFAULT, cancellable,
+ mail_reader_expunge_folder_cb,
+ async_context);
+
+ g_object_unref (activity);
+ }
+}
+
+/* Helper for e_mail_reader_expunge_folder_name() */
+static void
+mail_reader_expunge_folder_name_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder;
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ /* XXX The returned CamelFolder is a borrowed reference. */
+ folder = camel_store_get_folder_finish (
+ CAMEL_STORE (source_object), result, &local_error);
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-expunge-folder",
+ async_context->folder_name,
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ e_mail_reader_expunge_folder (async_context->reader, folder);
+ }
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_expunge_folder_name (EMailReader *reader,
+ CamelStore *store,
+ const gchar *folder_name)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_STORE (store));
+ g_return_if_fail (folder_name != NULL);
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+ async_context->folder_name = g_strdup (folder_name);
+
+ camel_store_get_folder (
+ store, folder_name,
+ CAMEL_STORE_FOLDER_INFO_FAST,
+ G_PRIORITY_DEFAULT, cancellable,
+ mail_reader_expunge_folder_name_cb,
+ async_context);
+
+ g_object_unref (activity);
+}
+
+/* Helper for e_mail_reader_refresh_folder() */
+static void
+mail_reader_refresh_folder_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder;
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ folder = CAMEL_FOLDER (source_object);
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-refresh-folder",
+ camel_folder_get_display_name (folder),
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ }
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_refresh_folder (EMailReader *reader,
+ CamelFolder *folder)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+
+ camel_folder_refresh_info (
+ folder,
+ G_PRIORITY_DEFAULT, cancellable,
+ mail_reader_refresh_folder_cb,
+ async_context);
+
+ g_object_unref (activity);
+}
+
+/* Helper for e_mail_reader_refresh_folder_name() */
+static void
+mail_reader_refresh_folder_name_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder;
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ /* XXX The returned CamelFolder is a borrowed reference. */
+ folder = camel_store_get_folder_finish (
+ CAMEL_STORE (source_object), result, &local_error);
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-refresh-folder",
+ async_context->folder_name,
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ e_mail_reader_refresh_folder (async_context->reader, folder);
+ }
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_refresh_folder_name (EMailReader *reader,
+ CamelStore *store,
+ const gchar *folder_name)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_STORE (store));
+ g_return_if_fail (folder_name != NULL);
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+ async_context->folder_name = g_strdup (folder_name);
+
+ camel_store_get_folder (
+ store, folder_name,
+ CAMEL_STORE_FOLDER_INFO_FAST,
+ G_PRIORITY_DEFAULT, cancellable,
+ mail_reader_refresh_folder_name_cb,
+ async_context);
+
+ g_object_unref (activity);
+}
+
+/* Helper for e_mail_reader_unsubscribe_folder_name() */
+static void
+mail_reader_unsubscribe_folder_name_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ camel_subscribable_unsubscribe_folder_finish (
+ CAMEL_SUBSCRIBABLE (source_object), result, &local_error);
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:folder-unsubscribe",
+ async_context->folder_name,
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ }
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_unsubscribe_folder_name (EMailReader *reader,
+ CamelStore *store,
+ const gchar *folder_name)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_SUBSCRIBABLE (store));
+ g_return_if_fail (folder_name != NULL);
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+ async_context->folder_name = g_strdup (folder_name);
+
+ camel_subscribable_unsubscribe_folder (
+ CAMEL_SUBSCRIBABLE (store), folder_name,
+ G_PRIORITY_DEFAULT, cancellable,
+ mail_reader_unsubscribe_folder_name_cb,
+ async_context);
+
+ g_object_unref (activity);
+}
+
+guint
+e_mail_reader_mark_selected (EMailReader *reader,
+ guint32 mask,
+ guint32 set)
+{
+ CamelFolder *folder;
+ guint ii = 0;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
+
+ folder = e_mail_reader_ref_folder (reader);
+
+ if (folder != NULL) {
+ GPtrArray *uids;
+
+ camel_folder_freeze (folder);
+
+ uids = e_mail_reader_get_selected_uids (reader);
+
+ for (ii = 0; ii < uids->len; ii++)
+ camel_folder_set_message_flags (
+ folder, uids->pdata[ii], mask, set);
+
+ g_ptr_array_unref (uids);
+
+ camel_folder_thaw (folder);
+
+ g_object_unref (folder);
+ }
+
+ return ii;
+}
+
+static void
+copy_tree_state (EMailReader *src_reader,
+ EMailReader *des_reader)
+{
+ GtkWidget *src_mlist, *des_mlist;
+ ETableState *state;
+
+ g_return_if_fail (src_reader != NULL);
+ g_return_if_fail (des_reader != NULL);
+
+ src_mlist = e_mail_reader_get_message_list (src_reader);
+ if (!src_mlist)
+ return;
+
+ des_mlist = e_mail_reader_get_message_list (des_reader);
+ if (!des_mlist)
+ return;
+
+ state = e_tree_get_state_object (E_TREE (src_mlist));
+ e_tree_set_state_object (E_TREE (des_mlist), state);
+ g_object_unref (state);
+
+ message_list_set_search (MESSAGE_LIST (des_mlist), MESSAGE_LIST (src_mlist)->search);
+}
+
+guint
+e_mail_reader_open_selected (EMailReader *reader)
+{
+ EShell *shell;
+ EMailBackend *backend;
+ ESourceRegistry *registry;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *views;
+ GPtrArray *uids;
+ guint ii = 0;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
+
+ backend = e_mail_reader_get_backend (reader);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
+ registry = e_shell_get_registry (shell);
+
+ folder = e_mail_reader_ref_folder (reader);
+ uids = e_mail_reader_get_selected_uids (reader);
+ window = e_mail_reader_get_window (reader);
+
+ if (!em_utils_ask_open_many (window, uids->len))
+ goto exit;
+
+ if (em_utils_folder_is_drafts (registry, folder) ||
+ em_utils_folder_is_outbox (registry, folder) ||
+ em_utils_folder_is_templates (registry, folder)) {
+
+ e_mail_reader_edit_messages (reader, folder, uids, TRUE, TRUE);
+
+ ii = uids->len;
+
+ goto exit;
+ }
+
+ views = g_ptr_array_new ();
+
+ /* For vfolders we need to edit the original, not the vfolder copy. */
+ for (ii = 0; ii < uids->len; ii++) {
+ const gchar *uid = uids->pdata[ii];
+ CamelFolder *real_folder;
+ CamelMessageInfo *info;
+ gchar *real_uid;
+
+ if (!CAMEL_IS_VEE_FOLDER (folder)) {
+ g_ptr_array_add (views, g_strdup (uid));
+ continue;
+ }
+
+ info = camel_folder_get_message_info (folder, uid);
+ if (info == NULL)
+ continue;
+
+ real_folder = camel_vee_folder_get_location (
+ CAMEL_VEE_FOLDER (folder),
+ (CamelVeeMessageInfo *) info, &real_uid);
+
+ if (em_utils_folder_is_drafts (registry, real_folder) ||
+ em_utils_folder_is_outbox (registry, real_folder)) {
+ GPtrArray *edits;
+
+ edits = g_ptr_array_new ();
+ g_ptr_array_add (edits, real_uid);
+ e_mail_reader_edit_messages (
+ reader, real_folder, edits, TRUE, TRUE);
+ g_ptr_array_unref (edits);
+ } else {
+ g_free (real_uid);
+ g_ptr_array_add (views, g_strdup (uid));
+ }
+
+ camel_folder_free_message_info (folder, info);
+ }
+
+ for (ii = 0; ii < views->len; ii++) {
+ const gchar *uid = views->pdata[ii];
+ GtkWidget *browser;
+ MessageList *ml;
+
+ browser = e_mail_browser_new (
+ backend, folder, uid,
+ E_MAIL_FORMATTER_MODE_NORMAL);
+
+ e_mail_reader_set_folder (E_MAIL_READER (browser), folder);
+ e_mail_reader_set_message (E_MAIL_READER (browser), uid);
+
+ ml = MESSAGE_LIST (e_mail_reader_get_message_list (
+ E_MAIL_READER (browser)));
+ message_list_freeze (ml);
+
+ copy_tree_state (reader, E_MAIL_READER (browser));
+ e_mail_reader_set_group_by_threads (
+ E_MAIL_READER (browser),
+ e_mail_reader_get_group_by_threads (reader));
+
+ message_list_thaw (ml);
+ gtk_widget_show (browser);
+ }
+
+ g_ptr_array_foreach (views, (GFunc) g_free, NULL);
+ g_ptr_array_free (views, TRUE);
+
+exit:
+ g_clear_object (&folder);
+ g_ptr_array_unref (uids);
+
+ return ii;
+}
+
+static void
+mail_reader_print_message_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ e_mail_printer_print_finish (
+ E_MAIL_PRINTER (source_object), result, &local_error);
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:printing-failed",
+ local_error->message, NULL);
+ g_error_free (local_error);
+
+ } else {
+ /* Set activity as completed, and keep it displayed for a few
+ * seconds so that user can actually see the the printing was
+ * successfully finished. */
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ }
+
+ async_context_free (async_context);
+}
+
+static void
+mail_reader_print_parse_message_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EMailReader *reader;
+ EMailDisplay *mail_display;
+ EMailFormatter *formatter;
+ EActivity *activity;
+ GCancellable *cancellable;
+ EMailPrinter *printer;
+ EMailPartList *part_list;
+ AsyncContext *async_context;
+
+ reader = E_MAIL_READER (source_object);
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ cancellable = e_activity_get_cancellable (activity);
+
+ part_list = e_mail_reader_parse_message_finish (reader, result);
+
+ printer = e_mail_printer_new (part_list);
+
+ mail_display = e_mail_reader_get_mail_display (reader);
+ formatter = e_mail_display_get_formatter (mail_display);
+
+ e_activity_set_text (activity, _("Printing"));
+
+ e_mail_printer_print (
+ printer,
+ async_context->print_action,
+ formatter,
+ cancellable,
+ mail_reader_print_message_cb,
+ async_context);
+
+ g_object_unref (printer);
+}
+
+static void
+mail_reader_print_get_message_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ CamelMimeMessage *message;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+ cancellable = e_activity_get_cancellable (activity);
+
+ message = camel_folder_get_message_finish (
+ CAMEL_FOLDER (source_object), result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((message != NULL) && (local_error == NULL)) ||
+ ((message == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-retrieve-message",
+ local_error->message, NULL);
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+ }
+
+ e_activity_set_text (activity, "");
+
+ e_mail_reader_parse_message (
+ async_context->reader,
+ async_context->folder,
+ async_context->message_uid,
+ message,
+ cancellable,
+ mail_reader_print_parse_message_cb,
+ async_context);
+
+ g_object_unref (message);
+}
+
+void
+e_mail_reader_print (EMailReader *reader,
+ GtkPrintOperationAction action)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ MessageList *message_list;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ message_list = MESSAGE_LIST (e_mail_reader_get_message_list (reader));
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->folder = e_mail_reader_ref_folder (reader);
+ async_context->reader = g_object_ref (reader);
+ async_context->message_uid = g_strdup (message_list->cursor_uid);
+ async_context->print_action = action;
+
+ camel_folder_get_message (
+ async_context->folder,
+ async_context->message_uid,
+ G_PRIORITY_DEFAULT, cancellable,
+ mail_reader_print_get_message_cb,
+ async_context);
+
+ g_object_unref (activity);
+}
+
+static void
+mail_reader_remove_attachments_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ e_mail_folder_remove_attachments_finish (
+ CAMEL_FOLDER (source_object), result, &local_error);
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "mail:remove-attachments",
+ local_error->message, NULL);
+ g_error_free (local_error);
+ }
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_remove_attachments (EMailReader *reader)
+{
+ EActivity *activity;
+ AsyncContext *async_context;
+ GCancellable *cancellable;
+ CamelFolder *folder;
+ GPtrArray *uids;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ uids = e_mail_reader_get_selected_uids (reader);
+ g_return_if_fail (uids != NULL);
+
+ /* Remove attachments asynchronously. */
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+
+ folder = e_mail_reader_ref_folder (reader);
+
+ e_mail_folder_remove_attachments (
+ folder, uids,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_remove_attachments_cb,
+ async_context);
+
+ g_object_unref (folder);
+
+ g_object_unref (activity);
+
+ g_ptr_array_unref (uids);
+}
+
+static void
+mail_reader_remove_duplicates_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ CamelFolder *folder;
+ GHashTable *duplicates;
+ GtkWindow *parent_window;
+ guint n_duplicates;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ folder = CAMEL_FOLDER (source_object);
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ parent_window = e_mail_reader_get_window (async_context->reader);
+
+ duplicates = e_mail_folder_find_duplicate_messages_finish (
+ folder, result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((duplicates != NULL) && (local_error == NULL)) ||
+ ((duplicates == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "mail:find-duplicate-messages",
+ local_error->message, NULL);
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+ }
+
+ /* Finalize the activity here so we don't leave a message in
+ * the task bar while prompting the user for confirmation. */
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ g_clear_object (&async_context->activity);
+
+ n_duplicates = g_hash_table_size (duplicates);
+
+ if (n_duplicates == 0) {
+ em_utils_prompt_user (
+ parent_window, NULL,
+ "mail:info-no-remove-duplicates",
+ camel_folder_get_display_name (folder), NULL);
+ } else {
+ gchar *confirmation;
+ gboolean proceed;
+
+ confirmation = g_strdup_printf (ngettext (
+ /* Translators: %s is replaced with a folder
+ * name %u with count of duplicate messages. */
+ "Folder '%s' contains %u duplicate message. "
+ "Are you sure you want to delete it?",
+ "Folder '%s' contains %u duplicate messages. "
+ "Are you sure you want to delete them?",
+ n_duplicates),
+ camel_folder_get_display_name (folder),
+ n_duplicates);
+
+ proceed = em_utils_prompt_user (
+ parent_window, NULL,
+ "mail:ask-remove-duplicates",
+ confirmation, NULL);
+
+ if (proceed) {
+ GHashTableIter iter;
+ gpointer key;
+
+ camel_folder_freeze (folder);
+
+ g_hash_table_iter_init (&iter, duplicates);
+
+ /* Mark duplicate messages for deletion. */
+ while (g_hash_table_iter_next (&iter, &key, NULL))
+ camel_folder_delete_message (folder, key);
+
+ camel_folder_thaw (folder);
+ }
+
+ g_free (confirmation);
+ }
+
+ g_hash_table_destroy (duplicates);
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_remove_duplicates (EMailReader *reader)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+ CamelFolder *folder;
+ GPtrArray *uids;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ uids = e_mail_reader_get_selected_uids (reader);
+ g_return_if_fail (uids != NULL);
+
+ /* Find duplicate messages asynchronously. */
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+
+ folder = e_mail_reader_ref_folder (reader);
+
+ e_mail_folder_find_duplicate_messages (
+ folder, uids,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_remove_duplicates_cb,
+ async_context);
+
+ g_object_unref (folder);
+
+ g_object_unref (activity);
+
+ g_ptr_array_unref (uids);
+}
+
+static void
+mail_reader_edit_messages_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder;
+ EShell *shell;
+ EMailBackend *backend;
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ GHashTable *hash_table;
+ GHashTableIter iter;
+ gpointer key, value;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ folder = CAMEL_FOLDER (source_object);
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ hash_table = e_mail_folder_get_multiple_messages_finish (
+ folder, result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((hash_table != NULL) && (local_error == NULL)) ||
+ ((hash_table == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+ goto exit;
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "mail:get-multiple-messages",
+ local_error->message, NULL);
+ g_error_free (local_error);
+ goto exit;
+ }
+
+ backend = e_mail_reader_get_backend (async_context->reader);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
+
+ /* Open each message in its own composer window. */
+
+ g_hash_table_iter_init (&iter, hash_table);
+
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ EMsgComposer *composer;
+ CamelMimeMessage *message;
+ const gchar *message_uid = NULL;
+
+ if (async_context->replace)
+ message_uid = (const gchar *) key;
+
+ message = CAMEL_MIME_MESSAGE (value);
+
+ camel_medium_remove_header (
+ CAMEL_MEDIUM (message), "X-Mailer");
+
+ composer = em_utils_edit_message (
+ shell, folder, message, message_uid,
+ async_context->keep_signature);
+
+ e_mail_reader_composer_created (
+ async_context->reader, composer, message);
+ }
+
+ g_hash_table_unref (hash_table);
+
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+
+exit:
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_edit_messages (EMailReader *reader,
+ CamelFolder *folder,
+ GPtrArray *uids,
+ gboolean replace,
+ gboolean keep_signature)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (uids != NULL);
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+ async_context->replace = replace;
+ async_context->keep_signature = keep_signature;
+
+ e_mail_folder_get_multiple_messages (
+ folder, uids,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_edit_messages_cb,
+ async_context);
+
+ g_object_unref (activity);
+}
+
+static void
+mail_reader_forward_attachment_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder;
+ EMailBackend *backend;
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ CamelMimePart *part;
+ CamelDataWrapper *content;
+ EMsgComposer *composer;
+ gchar *subject = NULL;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ folder = CAMEL_FOLDER (source_object);
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ part = e_mail_folder_build_attachment_finish (
+ folder, result, &subject, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((part != NULL) && (local_error == NULL)) ||
+ ((part == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_warn_if_fail (subject == NULL);
+ g_error_free (local_error);
+ goto exit;
+
+ } else if (local_error != NULL) {
+ g_warn_if_fail (subject == NULL);
+ e_alert_submit (
+ alert_sink,
+ "mail:get-multiple-messages",
+ local_error->message, NULL);
+ g_error_free (local_error);
+ goto exit;
+ }
+
+ backend = e_mail_reader_get_backend (async_context->reader);
+
+ composer = em_utils_forward_attachment (
+ backend, part, subject, folder, async_context->uids);
+
+ content = camel_medium_get_content (CAMEL_MEDIUM (part));
+ if (CAMEL_IS_MIME_MESSAGE (content)) {
+ e_mail_reader_composer_created (
+ async_context->reader, composer,
+ CAMEL_MIME_MESSAGE (content));
+ } else {
+ /* XXX What to do for the multipart/digest case?
+ * Extract the first message from the digest, or
+ * change the argument type to CamelMimePart and
+ * just pass the whole digest through?
+ *
+ * This signal is primarily serving EMailBrowser,
+ * which can only forward one message at a time.
+ * So for the moment it doesn't matter, but still
+ * something to consider. */
+ e_mail_reader_composer_created (
+ async_context->reader, composer, NULL);
+ }
+
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+
+ g_object_unref (part);
+ g_free (subject);
+
+exit:
+ async_context_free (async_context);
+}
+
+static void
+mail_reader_forward_messages_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder;
+ EMailBackend *backend;
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ GHashTable *hash_table;
+ GHashTableIter iter;
+ gpointer key, value;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ folder = CAMEL_FOLDER (source_object);
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ backend = e_mail_reader_get_backend (async_context->reader);
+
+ hash_table = e_mail_folder_get_multiple_messages_finish (
+ folder, result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((hash_table != NULL) && (local_error == NULL)) ||
+ ((hash_table == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+ goto exit;
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "mail:get-multiple-messages",
+ local_error->message, NULL);
+ g_error_free (local_error);
+ goto exit;
+ }
+
+ /* Create a new composer window for each message. */
+
+ g_hash_table_iter_init (&iter, hash_table);
+
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ EMsgComposer *composer;
+ CamelMimeMessage *message;
+ const gchar *message_uid;
+
+ message_uid = (const gchar *) key;
+ message = CAMEL_MIME_MESSAGE (value);
+
+ composer = em_utils_forward_message (
+ backend, message,
+ async_context->forward_style,
+ folder, message_uid);
+
+ e_mail_reader_composer_created (
+ async_context->reader, composer, message);
+ }
+
+ g_hash_table_unref (hash_table);
+
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+
+exit:
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_forward_messages (EMailReader *reader,
+ CamelFolder *folder,
+ GPtrArray *uids,
+ EMailForwardStyle style)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (uids != NULL);
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+ async_context->uids = g_ptr_array_ref (uids);
+ async_context->forward_style = style;
+
+ switch (style) {
+ case E_MAIL_FORWARD_STYLE_ATTACHED:
+ e_mail_folder_build_attachment (
+ folder, uids,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_forward_attachment_cb,
+ async_context);
+ break;
+
+ case E_MAIL_FORWARD_STYLE_INLINE:
+ case E_MAIL_FORWARD_STYLE_QUOTED:
+ e_mail_folder_get_multiple_messages (
+ folder, uids,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_forward_messages_cb,
+ async_context);
+ break;
+
+ default:
+ g_warn_if_reached ();
+ }
+
+ g_object_unref (activity);
+}
+
+/* Helper for e_mail_reader_reply_to_message()
+ * XXX This function belongs in e-html-utils.c */
+static gboolean
+html_contains_nonwhitespace (const gchar *html,
+ gint len)
+{
+ const gchar *cp;
+ gunichar uc = 0;
+
+ if (html == NULL || len <= 0)
+ return FALSE;
+
+ cp = html;
+
+ while (cp != NULL && cp - html < len) {
+ uc = g_utf8_get_char (cp);
+ if (uc == 0)
+ break;
+
+ if (uc == '<') {
+ /* skip until next '>' */
+ uc = g_utf8_get_char (cp);
+ while (uc != 0 && uc != '>' && cp - html < len) {
+ cp = g_utf8_next_char (cp);
+ uc = g_utf8_get_char (cp);
+ }
+ if (uc == 0)
+ break;
+ } else if (uc == '&') {
+ /* sequence '&nbsp;' is a space */
+ if (g_ascii_strncasecmp (cp, "&nbsp;", 6) == 0)
+ cp = cp + 5;
+ else
+ break;
+ } else if (!g_unichar_isspace (uc))
+ break;
+
+ cp = g_utf8_next_char (cp);
+ }
+
+ return cp - html < len - 1 && uc != 0;
+}
+
+static void
+mail_reader_reply_message_parsed (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EShell *shell;
+ EMailBackend *backend;
+ EMailReader *reader = E_MAIL_READER (object);
+ EMailPartList *part_list;
+ EMsgComposer *composer;
+ CamelMimeMessage *message;
+ AsyncContext *async_context;
+
+ async_context = (AsyncContext *) user_data;
+
+ part_list = e_mail_reader_parse_message_finish (reader, result);
+ message = e_mail_part_list_get_message (part_list);
+
+ backend = e_mail_reader_get_backend (async_context->reader);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
+
+ composer = em_utils_reply_to_message (
+ shell, message,
+ async_context->folder,
+ async_context->message_uid,
+ async_context->reply_type,
+ async_context->reply_style,
+ part_list,
+ async_context->address);
+
+ e_mail_reader_composer_created (reader, composer, message);
+
+ g_object_unref (part_list);
+
+ async_context_free (async_context);
+}
+
+static void
+mail_reader_get_message_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ GCancellable *cancellable;
+ CamelMimeMessage *message;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+ cancellable = e_activity_get_cancellable (activity);
+
+ message = camel_folder_get_message_finish (
+ CAMEL_FOLDER (source_object), result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((message != NULL) && (local_error == NULL)) ||
+ ((message == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-retrieve-message",
+ local_error->message, NULL);
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+ }
+
+ e_mail_reader_parse_message (
+ async_context->reader,
+ async_context->folder,
+ async_context->message_uid,
+ message,
+ cancellable,
+ mail_reader_reply_message_parsed,
+ async_context);
+
+ g_object_unref (message);
+}
+
+void
+e_mail_reader_reply_to_message (EMailReader *reader,
+ CamelMimeMessage *src_message,
+ EMailReplyType reply_type)
+{
+ EShell *shell;
+ EMailBackend *backend;
+ EShellBackend *shell_backend;
+ EMailDisplay *display;
+ EMailPartList *part_list = NULL;
+ GtkWidget *message_list;
+ CamelMimeMessage *new_message;
+ CamelInternetAddress *address = NULL;
+ CamelFolder *folder;
+ EMailReplyStyle reply_style;
+ EWebView *web_view;
+ struct _camel_header_raw *header;
+ const gchar *uid;
+ gchar *selection = NULL;
+ gint length;
+ gchar *mail_uri;
+ CamelObjectBag *registry;
+ EMsgComposer *composer;
+ EMailPartValidityFlags validity_pgp_sum = 0;
+ EMailPartValidityFlags validity_smime_sum = 0;
+
+ /* This handles quoting only selected text in the reply. If
+ * nothing is selected or only whitespace is selected, fall
+ * back to the normal em_utils_reply_to_message(). */
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ backend = e_mail_reader_get_backend (reader);
+ display = e_mail_reader_get_mail_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+ reply_style = e_mail_reader_get_reply_style (reader);
+
+ shell_backend = E_SHELL_BACKEND (backend);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ web_view = E_WEB_VIEW (display);
+
+ if (reply_type == E_MAIL_REPLY_TO_RECIPIENT) {
+ const gchar *uri;
+
+ uri = e_web_view_get_selected_uri (web_view);
+
+ if (uri) {
+ CamelURL *curl;
+
+ curl = camel_url_new (uri, NULL);
+
+ if (curl && curl->path && *curl->path) {
+ address = camel_internet_address_new ();
+ if (camel_address_decode (
+ CAMEL_ADDRESS (address),
+ curl->path) < 0) {
+ g_object_unref (address);
+ address = NULL;
+ }
+ }
+
+ if (curl)
+ camel_url_free (curl);
+ }
+ }
+
+ uid = MESSAGE_LIST (message_list)->cursor_uid;
+ g_return_if_fail (uid != NULL);
+
+ folder = e_mail_reader_ref_folder (reader);
+
+ if (!gtk_widget_get_visible (GTK_WIDGET (web_view)))
+ goto whole_message;
+
+ registry = e_mail_part_list_get_registry ();
+ mail_uri = e_mail_part_build_uri (folder, uid, NULL, NULL);
+ part_list = camel_object_bag_get (registry, mail_uri);
+ g_free (mail_uri);
+
+ if (!part_list) {
+ goto whole_message;
+ } else {
+ GQueue queue = G_QUEUE_INIT;
+
+ e_mail_part_list_queue_parts (part_list, NULL, &queue);
+
+ while (!g_queue_is_empty (&queue)) {
+ EMailPart *part = g_queue_pop_head (&queue);
+ GList *head, *link;
+
+ head = g_queue_peek_head_link (&part->validities);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPartValidityPair *vpair = link->data;
+
+ if (vpair == NULL)
+ continue;
+
+ if ((vpair->validity_type & E_MAIL_PART_VALIDITY_PGP) != 0)
+ validity_pgp_sum |= vpair->validity_type;
+ if ((vpair->validity_type & E_MAIL_PART_VALIDITY_SMIME) != 0)
+ validity_smime_sum |= vpair->validity_type;
+ }
+
+ g_object_unref (part);
+ }
+ }
+
+ if (src_message == NULL) {
+ src_message = e_mail_part_list_get_message (part_list);
+ if (src_message != NULL)
+ g_object_ref (src_message);
+
+ g_object_unref (part_list);
+ part_list = NULL;
+
+ g_return_if_fail (src_message != NULL);
+ } else {
+ g_object_unref (part_list);
+ part_list = NULL;
+ }
+
+ if (!e_web_view_is_selection_active (web_view))
+ goto whole_message;
+
+ selection = e_web_view_get_selection_html (web_view);
+ if (selection == NULL || *selection == '\0')
+ goto whole_message;
+
+ length = strlen (selection);
+ if (!html_contains_nonwhitespace (selection, length))
+ goto whole_message;
+
+ new_message = camel_mime_message_new ();
+
+ /* Filter out "content-*" headers. */
+ header = CAMEL_MIME_PART (src_message)->headers;
+ while (header != NULL) {
+ if (g_ascii_strncasecmp (header->name, "content-", 8) != 0)
+ camel_medium_add_header (
+ CAMEL_MEDIUM (new_message),
+ header->name, header->value);
+
+ header = header->next;
+ }
+
+ camel_mime_part_set_encoding (
+ CAMEL_MIME_PART (new_message),
+ CAMEL_TRANSFER_ENCODING_8BIT);
+
+ camel_mime_part_set_content (
+ CAMEL_MIME_PART (new_message),
+ selection, length, "text/html");
+
+ g_object_unref (src_message);
+
+ composer = em_utils_reply_to_message (
+ shell, new_message, folder, uid,
+ reply_type, reply_style, NULL, address);
+ if (validity_pgp_sum != 0 || validity_smime_sum != 0) {
+ GtkToggleAction *action;
+
+ if ((validity_pgp_sum & E_MAIL_PART_VALIDITY_PGP) != 0) {
+ if ((validity_pgp_sum & E_MAIL_PART_VALIDITY_SIGNED) != 0) {
+ action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_SIGN (composer));
+ gtk_toggle_action_set_active (action, TRUE);
+ }
+
+ if ((validity_pgp_sum & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0) {
+ action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_ENCRYPT (composer));
+ gtk_toggle_action_set_active (action, TRUE);
+ }
+ }
+
+ if ((validity_smime_sum & E_MAIL_PART_VALIDITY_SMIME) != 0) {
+ if ((validity_smime_sum & E_MAIL_PART_VALIDITY_SIGNED) != 0) {
+ action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_SIGN (composer));
+ gtk_toggle_action_set_active (action, TRUE);
+ }
+
+ if ((validity_smime_sum & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0) {
+ action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_ENCRYPT (composer));
+ gtk_toggle_action_set_active (action, TRUE);
+ }
+ }
+ }
+
+ e_mail_reader_composer_created (reader, composer, new_message);
+
+ g_object_unref (new_message);
+
+ g_free (selection);
+
+ goto exit;
+
+whole_message:
+ if (src_message == NULL) {
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->folder = g_object_ref (folder);
+ async_context->reader = g_object_ref (reader);
+ async_context->message_uid = g_strdup (uid);
+ async_context->reply_type = reply_type;
+ async_context->reply_style = reply_style;
+
+ if (address != NULL)
+ async_context->address = g_object_ref (address);
+
+ camel_folder_get_message (
+ async_context->folder,
+ async_context->message_uid,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_get_message_ready_cb,
+ async_context);
+
+ g_object_unref (activity);
+
+ } else {
+ composer = em_utils_reply_to_message (
+ shell, src_message, folder, uid,
+ reply_type, reply_style, part_list, address);
+
+ e_mail_reader_composer_created (reader, composer, src_message);
+ }
+
+exit:
+ g_clear_object (&address);
+ g_clear_object (&folder);
+}
+
+static void
+mail_reader_save_messages_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EAlertSink *alert_sink;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ e_mail_folder_save_messages_finish (
+ CAMEL_FOLDER (source_object), result, &local_error);
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ g_error_free (local_error);
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "mail:save-messages",
+ local_error->message, NULL);
+ g_error_free (local_error);
+ }
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_save_messages (EMailReader *reader)
+{
+ EShell *shell;
+ EActivity *activity;
+ EMailBackend *backend;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+ EShellBackend *shell_backend;
+ CamelMessageInfo *info;
+ CamelFolder *folder;
+ GFile *destination;
+ GPtrArray *uids;
+ const gchar *message_uid;
+ const gchar *title;
+ gchar *suggestion = NULL;
+
+ folder = e_mail_reader_ref_folder (reader);
+ backend = e_mail_reader_get_backend (reader);
+
+ uids = e_mail_reader_get_selected_uids (reader);
+ g_return_if_fail (uids != NULL && uids->len > 0);
+
+ if (uids->len > 1) {
+ GtkWidget *message_list;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_sort_uids (MESSAGE_LIST (message_list), uids);
+ }
+
+ message_uid = g_ptr_array_index (uids, 0);
+
+ title = ngettext ("Save Message", "Save Messages", uids->len);
+
+ /* Suggest as a filename the subject of the first message. */
+ info = camel_folder_get_message_info (folder, message_uid);
+ if (info != NULL) {
+ const gchar *subject;
+
+ subject = camel_message_info_subject (info);
+ if (subject != NULL)
+ suggestion = g_strconcat (subject, ".mbox", NULL);
+ camel_folder_free_message_info (folder, info);
+ }
+
+ if (suggestion == NULL) {
+ const gchar *basename;
+
+ /* Translators: This is part of a suggested file name
+ * used when saving a message or multiple messages to
+ * mbox format, when the first message doesn't have a
+ * subject. The extension ".mbox" is appended to the
+ * string; for example "Message.mbox". */
+ basename = ngettext ("Message", "Messages", uids->len);
+ suggestion = g_strconcat (basename, ".mbox", NULL);
+ }
+
+ shell_backend = E_SHELL_BACKEND (backend);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ destination = e_shell_run_save_dialog (
+ shell, title, suggestion,
+ "*.mbox:application/mbox,message/rfc822", NULL, NULL);
+
+ if (destination == NULL)
+ goto exit;
+
+ /* Save messages asynchronously. */
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+
+ e_mail_folder_save_messages (
+ folder, uids,
+ destination,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_save_messages_cb,
+ async_context);
+
+ g_object_unref (activity);
+
+ g_object_unref (destination);
+
+exit:
+ g_clear_object (&folder);
+ g_ptr_array_unref (uids);
+}
+
+void
+e_mail_reader_select_next_message (EMailReader *reader,
+ gboolean or_else_previous)
+{
+ GtkWidget *message_list;
+ gboolean hide_deleted;
+ gboolean success;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ hide_deleted = e_mail_reader_get_hide_deleted (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ success = message_list_select (
+ MESSAGE_LIST (message_list),
+ MESSAGE_LIST_SELECT_NEXT, 0, 0);
+
+ if (!success && (hide_deleted || or_else_previous))
+ message_list_select (
+ MESSAGE_LIST (message_list),
+ MESSAGE_LIST_SELECT_PREVIOUS, 0, 0);
+}
+
+/* Helper for e_mail_reader_create_filter_from_selected() */
+static void
+mail_reader_create_filter_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EMailBackend *backend;
+ EMailSession *session;
+ EAlertSink *alert_sink;
+ CamelMimeMessage *message;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ message = camel_folder_get_message_finish (
+ CAMEL_FOLDER (source_object), result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((message != NULL) && (local_error == NULL)) ||
+ ((message == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-retrieve-message",
+ local_error->message, NULL);
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+ }
+
+ /* Finalize the activity here so we don't leave a message
+ * in the task bar while displaying the filter editor. */
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ g_clear_object (&async_context->activity);
+
+ backend = e_mail_reader_get_backend (async_context->reader);
+ session = e_mail_backend_get_session (backend);
+
+ /* Switch to Incoming filter in case the message contains a Received header */
+ if (g_str_equal (async_context->filter_source, E_FILTER_SOURCE_OUTGOING) &&
+ camel_medium_get_header (CAMEL_MEDIUM (message), "received"))
+ async_context->filter_source = E_FILTER_SOURCE_INCOMING;
+
+ filter_gui_add_from_message (
+ session, message,
+ async_context->filter_source,
+ async_context->filter_type);
+
+ g_object_unref (message);
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_create_filter_from_selected (EMailReader *reader,
+ gint filter_type)
+{
+ EShell *shell;
+ EActivity *activity;
+ EMailBackend *backend;
+ AsyncContext *async_context;
+ GCancellable *cancellable;
+ ESourceRegistry *registry;
+ CamelFolder *folder;
+ GPtrArray *uids;
+ const gchar *filter_source;
+ const gchar *message_uid;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ backend = e_mail_reader_get_backend (reader);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
+ registry = e_shell_get_registry (shell);
+
+ folder = e_mail_reader_ref_folder (reader);
+ g_return_if_fail (folder != NULL);
+
+ if (em_utils_folder_is_sent (registry, folder) ||
+ em_utils_folder_is_outbox (registry, folder))
+ filter_source = E_FILTER_SOURCE_OUTGOING;
+ else
+ filter_source = E_FILTER_SOURCE_INCOMING;
+
+ uids = e_mail_reader_get_selected_uids (reader);
+ g_return_if_fail (uids != NULL && uids->len == 1);
+ message_uid = g_ptr_array_index (uids, 0);
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->reader = g_object_ref (reader);
+ async_context->filter_source = filter_source;
+ async_context->filter_type = filter_type;
+
+ camel_folder_get_message (
+ folder, message_uid,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_create_filter_cb,
+ async_context);
+
+ g_object_unref (activity);
+
+ g_ptr_array_unref (uids);
+
+ g_object_unref (folder);
+}
+
+/* Helper for e_mail_reader_create_vfolder_from_selected() */
+static void
+mail_reader_create_vfolder_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EActivity *activity;
+ EMailBackend *backend;
+ EMailSession *session;
+ EAlertSink *alert_sink;
+ CamelMimeMessage *message;
+ CamelFolder *use_folder;
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = (AsyncContext *) user_data;
+
+ activity = async_context->activity;
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ message = camel_folder_get_message_finish (
+ CAMEL_FOLDER (source_object), result, &local_error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((message != NULL) && (local_error == NULL)) ||
+ ((message == NULL) && (local_error != NULL)));
+
+ if (e_activity_handle_cancellation (activity, local_error)) {
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+
+ } else if (local_error != NULL) {
+ e_alert_submit (
+ alert_sink, "mail:no-retrieve-message",
+ local_error->message, NULL);
+ async_context_free (async_context);
+ g_error_free (local_error);
+ return;
+ }
+
+ /* Finalize the activity here so we don't leave a message
+ * in the task bar while displaying the vfolder editor. */
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ g_clear_object (&async_context->activity);
+
+ backend = e_mail_reader_get_backend (async_context->reader);
+ session = e_mail_backend_get_session (backend);
+
+ use_folder = async_context->folder;
+ if (CAMEL_IS_VEE_FOLDER (use_folder)) {
+ CamelStore *parent_store;
+ CamelVeeFolder *vfolder;
+
+ parent_store = camel_folder_get_parent_store (use_folder);
+ vfolder = CAMEL_VEE_FOLDER (use_folder);
+
+ if (CAMEL_IS_VEE_STORE (parent_store) &&
+ vfolder == camel_vee_store_get_unmatched_folder (CAMEL_VEE_STORE (parent_store))) {
+ /* use source folder instead of the Unmatched folder */
+ use_folder = camel_vee_folder_get_vee_uid_folder (
+ vfolder, async_context->message_uid);
+ }
+ }
+
+ vfolder_gui_add_from_message (
+ session, message,
+ async_context->filter_type,
+ use_folder);
+
+ g_object_unref (message);
+
+ async_context_free (async_context);
+}
+
+void
+e_mail_reader_create_vfolder_from_selected (EMailReader *reader,
+ gint vfolder_type)
+{
+ EActivity *activity;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+ GPtrArray *uids;
+ const gchar *message_uid;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ uids = e_mail_reader_get_selected_uids (reader);
+ g_return_if_fail (uids != NULL && uids->len == 1);
+ message_uid = g_ptr_array_index (uids, 0);
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->folder = e_mail_reader_ref_folder (reader);
+ async_context->reader = g_object_ref (reader);
+ async_context->message_uid = g_strdup (message_uid);
+ async_context->filter_type = vfolder_type;
+
+ camel_folder_get_message (
+ async_context->folder,
+ async_context->message_uid,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ mail_reader_create_vfolder_cb,
+ async_context);
+
+ g_object_unref (activity);
+
+ g_ptr_array_unref (uids);
+}
+
+static void
+mail_reader_parse_message_run (GSimpleAsyncResult *simple,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ EMailReader *reader = E_MAIL_READER (object);
+ CamelObjectBag *registry;
+ EMailPartList *part_list;
+ AsyncContext *async_context;
+ gchar *mail_uri;
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ registry = e_mail_part_list_get_registry ();
+
+ mail_uri = e_mail_part_build_uri (
+ async_context->folder,
+ async_context->message_uid, NULL, NULL);
+
+ part_list = camel_object_bag_reserve (registry, mail_uri);
+ if (part_list == NULL) {
+ EMailBackend *mail_backend;
+ EMailSession *mail_session;
+ EMailParser *parser;
+
+ mail_backend = e_mail_reader_get_backend (reader);
+ mail_session = e_mail_backend_get_session (mail_backend);
+
+ parser = e_mail_parser_new (CAMEL_SESSION (mail_session));
+
+ part_list = e_mail_parser_parse_sync (
+ parser,
+ async_context->folder,
+ async_context->message_uid,
+ async_context->message,
+ cancellable);
+
+ g_object_unref (parser);
+
+ if (part_list == NULL)
+ camel_object_bag_abort (registry, mail_uri);
+ else
+ camel_object_bag_add (registry, mail_uri, part_list);
+ }
+
+ g_free (mail_uri);
+
+ async_context->part_list = part_list;
+}
+
+void
+e_mail_reader_parse_message (EMailReader *reader,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+ EActivity *activity;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (message_uid != NULL);
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+ activity = e_mail_reader_new_activity (reader);
+ e_activity_set_cancellable (activity, cancellable);
+ e_activity_set_text (activity, _("Parsing message"));
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->activity = g_object_ref (activity);
+ async_context->folder = g_object_ref (folder);
+ async_context->message_uid = g_strdup (message_uid);
+ async_context->message = g_object_ref (message);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (reader), callback, user_data,
+ e_mail_reader_parse_message);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ g_simple_async_result_run_in_thread (
+ simple, mail_reader_parse_message_run,
+ G_PRIORITY_DEFAULT, cancellable);
+
+ g_object_unref (simple);
+ g_object_unref (activity);
+}
+
+EMailPartList *
+e_mail_reader_parse_message_finish (EMailReader *reader,
+ GAsyncResult *result)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (reader),
+ e_mail_reader_parse_message), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (async_context->part_list != NULL)
+ g_object_ref (async_context->part_list);
+
+ return async_context->part_list;
+}