aboutsummaryrefslogtreecommitdiffstats
path: root/mail/e-mail-session-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'mail/e-mail-session-utils.c')
-rw-r--r--mail/e-mail-session-utils.c846
1 files changed, 846 insertions, 0 deletions
diff --git a/mail/e-mail-session-utils.c b/mail/e-mail-session-utils.c
new file mode 100644
index 0000000000..e9cdd83914
--- /dev/null
+++ b/mail/e-mail-session-utils.c
@@ -0,0 +1,846 @@
+/*
+ * e-mail-session-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/>
+ *
+ */
+
+#include "e-mail-session-utils.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <mail/mail-tools.h>
+#include <mail/e-mail-local.h>
+#include <e-util/e-account-utils.h>
+#include <filter/e-filter-rule.h>
+
+/* X-Mailer header value */
+#define X_MAILER ("Evolution " VERSION SUB_VERSION " " VERSION_COMMENT)
+
+typedef struct _AsyncContext AsyncContext;
+
+struct _AsyncContext {
+ CamelFolder *sent_folder;
+ CamelFolder *outbox_folder;
+
+ CamelMimeMessage *message;
+ CamelMessageInfo *info;
+
+ CamelAddress *from;
+ CamelAddress *recipients;
+
+ CamelFilterDriver *driver;
+
+ GCancellable *cancellable;
+ gint io_priority;
+
+ /* X-Evolution headers */
+ struct _camel_header_raw *xev;
+
+ GPtrArray *post_to_uris;
+
+ gchar *destination;
+ gchar *message_uid;
+ gchar *transport_uri;
+ gchar *sent_folder_uri;
+};
+
+static void
+async_context_free (AsyncContext *context)
+{
+ if (context->sent_folder != NULL)
+ g_object_unref (context->sent_folder);
+
+ if (context->outbox_folder != NULL)
+ g_object_unref (context->outbox_folder);
+
+ if (context->message != NULL)
+ g_object_unref (context->message);
+
+ if (context->info != NULL)
+ camel_message_info_free (context->info);
+
+ if (context->from != NULL)
+ g_object_unref (context->from);
+
+ if (context->recipients != NULL)
+ g_object_unref (context->recipients);
+
+ if (context->driver != NULL)
+ g_object_unref (context->driver);
+
+ if (context->cancellable != NULL) {
+ camel_operation_pop_message (context->cancellable);
+ g_object_unref (context->cancellable);
+ }
+
+ if (context->xev != NULL)
+ camel_header_raw_clear (&context->xev);
+
+ if (context->post_to_uris != NULL) {
+ g_ptr_array_foreach (
+ context->post_to_uris, (GFunc) g_free, NULL);
+ g_ptr_array_free (context->post_to_uris, TRUE);
+ }
+
+ g_free (context->destination);
+ g_free (context->message_uid);
+ g_free (context->transport_uri);
+ g_free (context->sent_folder_uri);
+
+ g_slice_free (AsyncContext, context);
+}
+
+static void
+mail_session_handle_draft_headers_thread (GSimpleAsyncResult *simple,
+ EMailSession *session,
+ GCancellable *cancellable)
+{
+ AsyncContext *context;
+ GError *error = NULL;
+
+ context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ e_mail_session_handle_draft_headers_sync (
+ session, context->message, cancellable, &error);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ }
+}
+
+gboolean
+e_mail_session_handle_draft_headers_sync (EMailSession *session,
+ CamelMimeMessage *message,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelFolder *folder;
+ CamelMedium *medium;
+ const gchar *folder_uri;
+ const gchar *message_uid;
+ const gchar *header_name;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
+
+ medium = CAMEL_MEDIUM (message);
+
+ header_name = "X-Evolution-Draft-Folder";
+ folder_uri = camel_medium_get_header (medium, header_name);
+
+ header_name = "X-Evolution-Draft-Message";
+ message_uid = camel_medium_get_header (medium, header_name);
+
+ /* Don't report errors about missing X-Evolution-Draft
+ * headers. These headers are optional, so their absence
+ * is handled by doing nothing. */
+ if (folder_uri == NULL || message_uid == NULL)
+ return TRUE;
+
+ folder = e_mail_session_uri_to_folder_sync (
+ session, folder_uri, 0, cancellable, error);
+
+ if (folder == NULL)
+ return FALSE;
+
+ camel_folder_set_message_flags (
+ folder, message_uid,
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
+
+ success = camel_folder_synchronize_message_sync (
+ folder, message_uid, cancellable, error);
+
+ g_object_unref (folder);
+
+ return success;
+}
+
+void
+e_mail_session_handle_draft_headers (EMailSession *session,
+ CamelMimeMessage *message,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *context;
+
+ g_return_if_fail (E_IS_MAIL_SESSION (session));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+ context = g_slice_new0 (AsyncContext);
+ context->message = g_object_ref (message);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (session), callback, user_data,
+ e_mail_session_handle_draft_headers);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, context, (GDestroyNotify) async_context_free);
+
+ g_simple_async_result_run_in_thread (
+ simple, (GSimpleAsyncThreadFunc)
+ mail_session_handle_draft_headers_thread,
+ io_priority, cancellable);
+
+ g_object_unref (simple);
+}
+
+gboolean
+e_mail_session_handle_draft_headers_finish (EMailSession *session,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (session),
+ e_mail_session_handle_draft_headers), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+mail_session_handle_source_headers_thread (GSimpleAsyncResult *simple,
+ EMailSession *session,
+ GCancellable *cancellable)
+{
+ AsyncContext *context;
+ GError *error = NULL;
+
+ context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ e_mail_session_handle_source_headers_sync (
+ session, context->message, cancellable, &error);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ }
+}
+
+gboolean
+e_mail_session_handle_source_headers_sync (EMailSession *session,
+ CamelMimeMessage *message,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelFolder *folder;
+ CamelMedium *medium;
+ CamelMessageFlags flags = 0;
+ const gchar *folder_uri;
+ const gchar *message_uid;
+ const gchar *flag_string;
+ const gchar *header_name;
+ gboolean success;
+ guint length, ii;
+ gchar **tokens;
+ gchar *string;
+
+ g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
+
+ medium = CAMEL_MEDIUM (message);
+
+ header_name = "X-Evolution-Source-Folder";
+ folder_uri = camel_medium_get_header (medium, header_name);
+
+ header_name = "X-Evolution-Source-Message";
+ message_uid = camel_medium_get_header (medium, header_name);
+
+ header_name = "X-Evolution-Source-Flags";
+ flag_string = camel_medium_get_header (medium, header_name);
+
+ /* Don't report errors about missing X-Evolution-Source
+ * headers. These headers are optional, so their absence
+ * is handled by doing nothing. */
+ if (folder_uri == NULL || message_uid == NULL || flag_string == NULL)
+ return TRUE;
+
+ /* Convert the flag string to CamelMessageFlags. */
+
+ string = g_strstrip (g_strdup (flag_string));
+ tokens = g_strsplit (string, " ", 0);
+ g_free (string);
+
+ /* If tokens is NULL, a length of 0 will skip the loop. */
+ length = (tokens != NULL) ? g_strv_length (tokens) : 0;
+
+ for (ii = 0; ii < length; ii++) {
+ /* Note: We're only checking for flags known to
+ * be used in X-Evolution-Source-Flags headers.
+ * Add more as needed. */
+ if (g_strcmp0 (tokens[ii], "ANSWERED") == 0)
+ flags |= CAMEL_MESSAGE_ANSWERED;
+ else if (g_strcmp0 (tokens[ii], "ANSWERED_ALL") == 0)
+ flags |= CAMEL_MESSAGE_ANSWERED_ALL;
+ else if (g_strcmp0 (tokens[ii], "FORWARDED") == 0)
+ flags |= CAMEL_MESSAGE_FORWARDED;
+ else if (g_strcmp0 (tokens[ii], "SEEN") == 0)
+ flags |= CAMEL_MESSAGE_SEEN;
+ else
+ g_warning (
+ "Unknown flag '%s' in %s",
+ tokens[ii], header_name);
+ }
+
+ g_strfreev (tokens);
+
+ folder = e_mail_session_uri_to_folder_sync (
+ session, folder_uri, 0, cancellable, error);
+
+ if (folder == NULL)
+ return FALSE;
+
+ camel_folder_set_message_flags (
+ folder, message_uid, flags, flags);
+
+ success = camel_folder_synchronize_message_sync (
+ folder, message_uid, cancellable, error);
+
+ g_object_unref (folder);
+
+ return success;
+}
+
+void
+e_mail_session_handle_source_headers (EMailSession *session,
+ CamelMimeMessage *message,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *context;
+
+ g_return_if_fail (E_IS_MAIL_SESSION (session));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+ context = g_slice_new0 (AsyncContext);
+ context->message = g_object_ref (message);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (session), callback, user_data,
+ e_mail_session_handle_source_headers);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, context, (GDestroyNotify) async_context_free);
+
+ g_simple_async_result_run_in_thread (
+ simple, (GSimpleAsyncThreadFunc)
+ mail_session_handle_source_headers_thread,
+ io_priority, cancellable);
+
+ g_object_unref (simple);
+}
+
+gboolean
+e_mail_session_handle_source_headers_finish (EMailSession *session,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (session),
+ e_mail_session_handle_draft_headers), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+mail_session_send_to_thread (GSimpleAsyncResult *simple,
+ EMailSession *session,
+ GCancellable *cancellable)
+{
+ AsyncContext *context;
+ CamelFolder *local_sent_folder;
+ GString *error_messages;
+ gboolean copy_to_sent = TRUE;
+ guint ii;
+ GError *error = NULL;
+
+ context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ /* Send the message to all recipients. */
+ if (camel_address_length (context->recipients) > 0) {
+ CamelTransport *transport;
+ CamelProviderFlags flags;
+
+ /* XXX This API does not allow for cancellation. */
+ transport = camel_session_get_transport (
+ CAMEL_SESSION (session),
+ context->transport_uri, &error);
+
+ if (error != NULL) {
+ g_warn_if_fail (transport == NULL);
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ return;
+ }
+
+ g_return_if_fail (CAMEL_IS_TRANSPORT (transport));
+
+ flags = CAMEL_SERVICE (transport)->provider->flags;
+ if (flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)
+ copy_to_sent = FALSE;
+
+ camel_transport_send_to_sync (
+ transport, context->message,
+ context->from, context->recipients,
+ cancellable, &error);
+
+ g_object_unref (transport);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ return;
+ }
+ }
+
+ /* Post the message to requested folders. */
+ for (ii = 0; ii < context->post_to_uris->len; ii++) {
+ CamelFolder *folder;
+ const gchar *folder_uri;
+
+ folder_uri = g_ptr_array_index (context->post_to_uris, ii);
+
+ folder = e_mail_session_uri_to_folder_sync (
+ session, folder_uri, 0, cancellable, &error);
+
+ if (error != NULL) {
+ g_warn_if_fail (folder == NULL);
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ return;
+ }
+
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+ camel_folder_append_message_sync (
+ folder, context->message, context->info,
+ NULL, cancellable, &error);
+
+ g_object_unref (folder);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ return;
+ }
+ }
+
+ /*** Post Processing ***/
+
+ /* This accumulates error messages during post-processing. */
+ error_messages = g_string_sized_new (256);
+
+ mail_tool_restore_xevolution_headers (context->message, context->xev);
+
+ /* Run filters on the outgoing message. */
+ if (context->driver != NULL) {
+ camel_filter_driver_filter_message (
+ context->driver, context->message, context->info,
+ NULL, NULL, NULL, "", cancellable, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ goto exit;
+
+ if (error != NULL) {
+ g_string_append_printf (
+ error_messages,
+ _("Failed to apply outgoing filters: %s"),
+ error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ if (!copy_to_sent)
+ goto cleanup;
+
+ /* Append the sent message to a Sent folder. */
+
+ local_sent_folder = e_mail_local_get_folder (E_MAIL_FOLDER_SENT);
+
+ /* Try to extract a CamelFolder from the Sent folder URI. */
+ if (context->sent_folder_uri != NULL) {
+ context->sent_folder = e_mail_session_uri_to_folder_sync (
+ session, context->sent_folder_uri, 0,
+ cancellable, &error);
+ if (error != NULL) {
+ g_warn_if_fail (context->sent_folder == NULL);
+ if (error_messages->len > 0)
+ g_string_append (error_messages, "\n\n");
+ g_string_append_printf (
+ error_messages,
+ _("Failed to append to %s: %s\n"
+ "Appending to local 'Sent' folder instead."),
+ context->sent_folder_uri, error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ /* Fall back to the local Sent folder. */
+ if (context->sent_folder == NULL)
+ context->sent_folder = g_object_ref (local_sent_folder);
+
+ /* Append the message. */
+ camel_folder_append_message_sync (
+ context->sent_folder, context->message,
+ context->info, NULL, cancellable, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ goto exit;
+
+ if (error == NULL)
+ goto cleanup;
+
+ /* If appending to a remote Sent folder failed,
+ * try appending to the local Sent folder. */
+ if (context->sent_folder != local_sent_folder) {
+ const gchar *description;
+
+ description = camel_folder_get_description (
+ context->sent_folder);
+
+ if (error_messages->len > 0)
+ g_string_append (error_messages, "\n\n");
+ g_string_append_printf (
+ error_messages,
+ _("Failed to append to %s: %s\n"
+ "Appending to local 'Sent' folder instead."),
+ description, error->message);
+ g_clear_error (&error);
+
+ camel_folder_append_message_sync (
+ local_sent_folder, context->message,
+ context->info, NULL, cancellable, &error);
+ }
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ goto exit;
+
+ /* We can't even append to the local Sent folder?
+ * In that case just leave the message in Outbox. */
+ if (error != NULL) {
+ if (error_messages->len > 0)
+ g_string_append (error_messages, "\n\n");
+ g_string_append_printf (
+ error_messages,
+ _("Failed to append to local 'Sent' folder: %s"),
+ error->message);
+ g_clear_error (&error);
+ goto exit;
+ }
+
+cleanup:
+
+ /* The send operation was successful; ignore cleanup errors. */
+
+ /* Mark the Outbox message for deletion. */
+ camel_folder_set_message_flags (
+ context->outbox_folder, context->message_uid,
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN, ~0);
+
+ /* Synchronize the Outbox folder. */
+ camel_folder_synchronize_sync (
+ context->outbox_folder, FALSE, cancellable, &error);
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ /* Mark the draft message for deletion, if present. */
+ e_mail_session_handle_draft_headers_sync (
+ session, context->message, cancellable, &error);
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ /* Set flags on the original source message, if present.
+ * Source message refers to the message being forwarded
+ * or replied to. */
+ e_mail_session_handle_source_headers_sync (
+ session, context->message, cancellable, &error);
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+exit:
+
+ /* If we were cancelled, disregard any other errors. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+
+ /* Stuff the accumulated error messages in a GError. */
+ } else if (error_messages->len > 0) {
+ g_simple_async_result_set_error (
+ simple, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+ "%s", error_messages->str);
+ }
+
+ /* Synchronize the Sent folder. */
+ if (context->sent_folder != NULL)
+ camel_folder_synchronize_sync (
+ context->sent_folder, FALSE, cancellable, NULL);
+
+ g_string_free (error_messages, TRUE);
+}
+
+static void
+mail_session_send_to_prepare (CamelFolder *outbox_folder,
+ GAsyncResult *result,
+ GSimpleAsyncResult *simple)
+{
+ AsyncContext *context;
+ CamelAddress *from;
+ CamelAddress *recipients;
+ CamelMedium *medium;
+ CamelMessageInfo *info;
+ CamelMimeMessage *message;
+ EAccount *account = NULL;
+ GPtrArray *post_to_uris;
+ struct _camel_header_raw *xev;
+ struct _camel_header_raw *header;
+ const gchar *string;
+ const gchar *resent_from;
+ gchar *transport_uri = NULL;
+ gchar *sent_folder_uri = NULL;
+ GError *error = NULL;
+
+ context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ message = camel_folder_get_message_finish (
+ outbox_folder, result, &error);
+
+ if (error != NULL) {
+ g_warn_if_fail (message == NULL);
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ g_error_free (error);
+ return;
+ }
+
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+ medium = CAMEL_MEDIUM (message);
+
+ camel_medium_set_header (medium, "X-Mailer", X_MAILER);
+
+ xev = mail_tool_remove_xevolution_headers (message);
+
+ /* Extract directives from X-Evolution headers. */
+
+ string = camel_header_raw_find (&xev, "X-Evolution-Account", NULL);
+ if (string != NULL) {
+ gchar *account_uid;
+
+ account_uid = g_strstrip (g_strdup (string));
+ account = e_get_account_by_uid (account_uid);
+ g_free (account_uid);
+ }
+
+ if (account != NULL) {
+ if (account->transport != NULL)
+ transport_uri = g_strdup (account->transport->url);
+ sent_folder_uri = g_strdup (account->sent_folder_uri);
+ }
+
+ string = camel_header_raw_find (&xev, "X-Evolution-Transport", NULL);
+ if (transport_uri == NULL && string != NULL)
+ transport_uri = g_strstrip (g_strdup (string));
+
+ string = camel_header_raw_find (&xev, "X-Evolution-Fcc", NULL);
+ if (sent_folder_uri == NULL && string != NULL)
+ sent_folder_uri = g_strstrip (g_strdup (string));
+
+ if (transport_uri == NULL)
+ transport_uri = g_strdup (context->destination);
+
+ post_to_uris = g_ptr_array_new ();
+ for (header = xev; header != NULL; header = header->next) {
+ gchar *folder_uri;
+
+ if (g_strcmp0 (header->name, "X-Evolution-PostTo") != 0)
+ continue;
+
+ folder_uri = g_strstrip (g_strdup (header->name));
+ g_ptr_array_add (post_to_uris, folder_uri);
+ }
+
+ /* Collect sender and recipients from headers. */
+
+ from = (CamelAddress *) camel_internet_address_new ();
+ recipients = (CamelAddress *) camel_internet_address_new ();
+ resent_from = camel_medium_get_header (medium, "Resent-From");
+
+ if (resent_from != NULL) {
+ const CamelInternetAddress *addr;
+ const gchar *type;
+
+ camel_address_decode (from, resent_from);
+
+ type = CAMEL_RECIPIENT_TYPE_RESENT_TO;
+ addr = camel_mime_message_get_recipients (message, type);
+ camel_address_cat (recipients, CAMEL_ADDRESS (addr));
+
+ type = CAMEL_RECIPIENT_TYPE_RESENT_CC;
+ addr = camel_mime_message_get_recipients (message, type);
+ camel_address_cat (recipients, CAMEL_ADDRESS (addr));
+
+ type = CAMEL_RECIPIENT_TYPE_RESENT_BCC;
+ addr = camel_mime_message_get_recipients (message, type);
+ camel_address_cat (recipients, CAMEL_ADDRESS (addr));
+
+ } else {
+ const CamelInternetAddress *addr;
+ const gchar *type;
+
+ addr = camel_mime_message_get_from (message);
+ camel_address_copy (from, CAMEL_ADDRESS (addr));
+
+ type = CAMEL_RECIPIENT_TYPE_TO;
+ addr = camel_mime_message_get_recipients (message, type);
+ camel_address_cat (recipients, CAMEL_ADDRESS (addr));
+
+ type = CAMEL_RECIPIENT_TYPE_CC;
+ addr = camel_mime_message_get_recipients (message, type);
+ camel_address_cat (recipients, CAMEL_ADDRESS (addr));
+
+ type = CAMEL_RECIPIENT_TYPE_BCC;
+ addr = camel_mime_message_get_recipients (message, type);
+ camel_address_cat (recipients, CAMEL_ADDRESS (addr));
+ }
+
+ /* Miscellaneous preparations. */
+
+ info = camel_message_info_new (NULL);
+ camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0);
+
+ /* The rest of the processing happens in a thread. */
+
+ context->from = from;
+ context->recipients = recipients;
+ context->message = g_object_ref (message);
+ context->info = info;
+ context->xev = xev;
+ context->post_to_uris = post_to_uris;
+ context->transport_uri = transport_uri;
+ context->sent_folder_uri = sent_folder_uri;
+
+ g_simple_async_result_run_in_thread (
+ simple, (GSimpleAsyncThreadFunc)
+ mail_session_send_to_thread,
+ context->io_priority,
+ context->cancellable);
+
+ g_object_unref (simple);
+}
+
+void
+e_mail_session_send_to (EMailSession *session,
+ CamelFolder *outbox_folder,
+ const gchar *message_uid,
+ const gchar *destination,
+ gint io_priority,
+ GCancellable *cancellable,
+ CamelFilterGetFolderFunc get_folder_func,
+ gpointer get_folder_data,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *context;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_MAIL_SESSION (session));
+ g_return_if_fail (CAMEL_IS_FOLDER (outbox_folder));
+ g_return_if_fail (message_uid != NULL);
+
+ context = g_slice_new0 (AsyncContext);
+ context->outbox_folder = g_object_ref (outbox_folder);
+ context->message_uid = g_strdup (message_uid);
+ context->destination = g_strdup (destination);
+ context->io_priority = io_priority;
+
+ if (G_IS_CANCELLABLE (cancellable))
+ context->cancellable = g_object_ref (cancellable);
+
+ /* More convenient to do this here than in the prepare function.
+ * Failure here emits a runtime warning but is non-fatal. */
+ context->driver = camel_session_get_filter_driver (
+ CAMEL_SESSION (session), E_FILTER_SOURCE_OUTGOING, &error);
+ if (context->driver != NULL)
+ camel_filter_driver_set_folder_func (
+ context->driver, get_folder_func, get_folder_data);
+ if (error != NULL) {
+ g_warn_if_fail (context->driver == NULL);
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (session), callback,
+ user_data, e_mail_session_send_to);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, context, (GDestroyNotify) async_context_free);
+
+ /* This gets popped in async_context_free(). */
+ camel_operation_push_message (
+ context->cancellable, _("Sending message"));
+
+ camel_folder_get_message (
+ outbox_folder, message_uid, io_priority,
+ context->cancellable, (GAsyncReadyCallback)
+ mail_session_send_to_prepare, simple);
+}
+
+gboolean
+e_mail_session_send_to_finish (EMailSession *session,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (session),
+ e_mail_session_send_to), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
+}