aboutsummaryrefslogtreecommitdiffstats
path: root/mail
diff options
context:
space:
mode:
Diffstat (limited to 'mail')
-rw-r--r--mail/Makefile.am4
-rw-r--r--mail/e-mail-folder-utils.c142
-rw-r--r--mail/e-mail-folder-utils.h43
-rw-r--r--mail/e-mail-reader.c11
-rw-r--r--mail/e-mail-session-utils.c846
-rw-r--r--mail/e-mail-session-utils.h76
-rw-r--r--mail/em-composer-utils.c1010
-rw-r--r--mail/em-composer-utils.h4
8 files changed, 1661 insertions, 475 deletions
diff --git a/mail/Makefile.am b/mail/Makefile.am
index f30de3eea9..6b1615ec91 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -45,6 +45,7 @@ mailinclude_HEADERS = \
e-mail-backend.h \
e-mail-browser.h \
e-mail-display.h \
+ e-mail-folder-utils.h \
e-mail-label-action.h \
e-mail-label-dialog.h \
e-mail-label-list-store.h \
@@ -55,6 +56,7 @@ mailinclude_HEADERS = \
e-mail-reader.h \
e-mail-reader-utils.h \
e-mail-session.h \
+ e-mail-session-utils.h \
e-mail-sidebar.h \
e-mail-store.h \
e-mail-tag-editor.h \
@@ -114,6 +116,7 @@ libevolution_mail_la_SOURCES = \
e-mail-backend.c \
e-mail-browser.c \
e-mail-display.c \
+ e-mail-folder-utils.c \
e-mail-label-action.c \
e-mail-label-dialog.c \
e-mail-label-list-store.c \
@@ -124,6 +127,7 @@ libevolution_mail_la_SOURCES = \
e-mail-reader.c \
e-mail-reader-utils.c \
e-mail-session.c \
+ e-mail-session-utils.c \
e-mail-sidebar.c \
e-mail-store.c \
e-mail-tag-editor.c \
diff --git a/mail/e-mail-folder-utils.c b/mail/e-mail-folder-utils.c
new file mode 100644
index 0000000000..7186589849
--- /dev/null
+++ b/mail/e-mail-folder-utils.c
@@ -0,0 +1,142 @@
+/*
+ * e-mail-folder-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-folder-utils.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+/* X-Mailer header value */
+#define X_MAILER ("Evolution " VERSION SUB_VERSION " " VERSION_COMMENT)
+
+typedef struct _AsyncContext AsyncContext;
+
+struct _AsyncContext {
+ GCancellable *cancellable;
+ gchar *message_uid;
+};
+
+static void
+async_context_free (AsyncContext *context)
+{
+ if (context->cancellable != NULL)
+ g_object_unref (context->cancellable);
+
+ g_free (context->message_uid);
+
+ g_slice_free (AsyncContext, context);
+}
+
+static void
+mail_folder_append_message_ready (CamelFolder *folder,
+ GAsyncResult *result,
+ GSimpleAsyncResult *simple)
+{
+ AsyncContext *context;
+ GError *error = NULL;
+
+ context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ camel_folder_append_message_finish (
+ folder, result, &context->message_uid, &error);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ }
+
+ camel_operation_pop_message (context->cancellable);
+
+ g_simple_async_result_complete (simple);
+
+ g_object_unref (simple);
+}
+
+void
+e_mail_folder_append_message (CamelFolder *folder,
+ CamelMimeMessage *message,
+ CamelMessageInfo *info,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *context;
+ CamelMedium *medium;
+
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+ medium = CAMEL_MEDIUM (message);
+
+ context = g_slice_new0 (AsyncContext);
+
+ if (G_IS_CANCELLABLE (cancellable))
+ context->cancellable = g_object_ref (cancellable);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (folder), callback, user_data,
+ e_mail_folder_append_message);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, context, (GDestroyNotify) async_context_free);
+
+ camel_operation_push_message (
+ context->cancellable,
+ _("Saving message to folder '%s'"),
+ camel_folder_get_full_name (folder));
+
+ if (camel_medium_get_header (medium, "X-Mailer") == NULL)
+ camel_medium_set_header (medium, "X-Mailer", X_MAILER);
+
+ camel_mime_message_set_date (message, CAMEL_MESSAGE_DATE_CURRENT, 0);
+
+ camel_folder_append_message (
+ folder, message, info, io_priority,
+ context->cancellable, (GAsyncReadyCallback)
+ mail_folder_append_message_ready, simple);
+}
+
+gboolean
+e_mail_folder_append_message_finish (CamelFolder *folder,
+ GAsyncResult *result,
+ gchar **appended_uid,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *context;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (folder),
+ e_mail_folder_append_message), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ if (appended_uid != NULL) {
+ *appended_uid = context->message_uid;
+ context->message_uid = NULL;
+ }
+
+ return TRUE;
+}
diff --git a/mail/e-mail-folder-utils.h b/mail/e-mail-folder-utils.h
new file mode 100644
index 0000000000..c5d3fefe13
--- /dev/null
+++ b/mail/e-mail-folder-utils.h
@@ -0,0 +1,43 @@
+/*
+ * e-mail-folder-utils.h
+ *
+ * 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/>
+ *
+ */
+
+#ifndef E_MAIL_FOLDER_UTILS_H
+#define E_MAIL_FOLDER_UTILS_H
+
+/* CamelFolder wrappers with Evolution-specific policies. */
+
+#include <camel/camel.h>
+
+G_BEGIN_DECLS
+
+void e_mail_folder_append_message (CamelFolder *folder,
+ CamelMimeMessage *message,
+ CamelMessageInfo *info,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_mail_folder_append_message_finish
+ (CamelFolder *folder,
+ GAsyncResult *result,
+ gchar **appended_uid,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_MAIL_FOLDER_UTILS_H */
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 0e28d06c88..184cc757df 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -462,9 +462,12 @@ check_close_browser_reader (EMailReader *reader)
GtkWindow *parent;
gint response;
EShell *shell;
+ EMailBackend *backend;
EShellBackend *shell_backend;
- shell_backend = e_mail_reader_get_shell_backend (reader);
+ backend = e_mail_reader_get_backend (reader);
+
+ shell_backend = E_SHELL_BACKEND (backend);
shell = e_shell_backend_get_shell (shell_backend);
parent = e_shell_get_active_window (shell);
@@ -714,16 +717,20 @@ action_mail_message_edit_cb (GtkAction *action,
EMailBackend *backend;
EShellBackend *shell_backend;
CamelFolder *folder;
+ const gchar *folder_uri;
GPtrArray *uids;
+ gboolean replace;
backend = e_mail_reader_get_backend (reader);
folder = e_mail_reader_get_folder (reader);
+ folder_uri = e_mail_reader_get_folder_uri (reader);
uids = e_mail_reader_get_selected_uids (reader);
shell_backend = E_SHELL_BACKEND (backend);
shell = e_shell_backend_get_shell (shell_backend);
- em_utils_edit_messages (shell, folder, uids, FALSE);
+ replace = em_utils_folder_is_drafts (folder, folder_uri);
+ em_utils_edit_messages (shell, folder, uids, replace);
}
static void
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);
+}
diff --git a/mail/e-mail-session-utils.h b/mail/e-mail-session-utils.h
new file mode 100644
index 0000000000..fcbc2636f7
--- /dev/null
+++ b/mail/e-mail-session-utils.h
@@ -0,0 +1,76 @@
+/*
+ * e-mail-session-utils.h
+ *
+ * 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/>
+ *
+ */
+
+#ifndef E_MAIL_SESSION_UTILS_H
+#define E_MAIL_SESSION_UTILS_H
+
+/* High-level operations with Evolution-specific policies. */
+
+#include <mail/e-mail-session.h>
+
+G_BEGIN_DECLS
+
+gboolean e_mail_session_handle_draft_headers_sync
+ (EMailSession *session,
+ CamelMimeMessage *message,
+ GCancellable *cancellable,
+ GError **error);
+void e_mail_session_handle_draft_headers
+ (EMailSession *session,
+ CamelMimeMessage *message,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_mail_session_handle_draft_headers_finish
+ (EMailSession *session,
+ GAsyncResult *result,
+ GError **error);
+gboolean e_mail_session_handle_source_headers_sync
+ (EMailSession *session,
+ CamelMimeMessage *message,
+ GCancellable *cancellable,
+ GError **error);
+void e_mail_session_handle_source_headers
+ (EMailSession *session,
+ CamelMimeMessage *message,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_mail_session_handle_source_headers_finish
+ (EMailSession *session,
+ GAsyncResult *result,
+ GError **error);
+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);
+gboolean e_mail_session_send_to_finish (EMailSession *session,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SESSION_UTILS_H */
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index 11143124e0..316046eecd 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -44,8 +44,10 @@
#include "shell/e-shell.h"
+#include "e-mail-folder-utils.h"
#include "e-mail-local.h"
#include "e-mail-session.h"
+#include "e-mail-session-utils.h"
#include "em-utils.h"
#include "em-composer-utils.h"
#include "composer/e-msg-composer.h"
@@ -69,97 +71,32 @@
#define GCONF_KEY_TEMPLATE_PLACEHOLDERS "/apps/evolution/mail/template_placeholders"
-static void em_utils_composer_send_cb (EMsgComposer *composer);
-static void em_utils_composer_save_draft_cb (EMsgComposer *composer);
+typedef struct _AsyncContext AsyncContext;
-struct emcs_t {
- guint ref_count;
-
- CamelFolder *drafts_folder;
- gchar *drafts_uid;
-
- CamelFolder *folder;
- guint32 flags, set;
- gchar *uid;
+struct _AsyncContext {
+ CamelMimeMessage *message;
+ EMsgComposer *composer;
+ EActivity *activity;
+ gchar *folder_uri;
+ gchar *message_uid;
};
-static struct emcs_t *
-emcs_new (void)
-{
- struct emcs_t *emcs;
-
- emcs = g_new0 (struct emcs_t, 1);
- emcs->ref_count = 1;
-
- return emcs;
-}
-
-static void
-emcs_set_drafts_info (struct emcs_t *emcs,
- CamelFolder *drafts_folder,
- const gchar *drafts_uid)
-{
- g_return_if_fail (emcs != NULL);
- g_return_if_fail (drafts_folder != NULL);
- g_return_if_fail (drafts_uid != NULL);
-
- if (emcs->drafts_folder != NULL)
- g_object_unref (emcs->drafts_folder);
- g_free (emcs->drafts_uid);
-
- g_object_ref (drafts_folder);
- emcs->drafts_folder = drafts_folder;
- emcs->drafts_uid = g_strdup (drafts_uid);
-}
-
-static void
-emcs_set_folder_info (struct emcs_t *emcs,
- CamelFolder *folder,
- const gchar *uid,
- guint32 flags,
- guint32 set)
-{
- g_return_if_fail (emcs != NULL);
- g_return_if_fail (folder != NULL);
- g_return_if_fail (uid != NULL);
-
- if (emcs->folder != NULL)
- g_object_unref (emcs->folder);
- g_free (emcs->uid);
-
- g_object_ref (folder);
- emcs->folder = folder;
- emcs->uid = g_strdup (uid);
- emcs->flags = flags;
- emcs->set = set;
-}
-
static void
-free_emcs (struct emcs_t *emcs)
+async_context_free (AsyncContext *context)
{
- if (emcs->drafts_folder != NULL)
- g_object_unref (emcs->drafts_folder);
- g_free (emcs->drafts_uid);
+ if (context->message != NULL)
+ g_object_unref (context->message);
- if (emcs->folder != NULL)
- g_object_unref (emcs->folder);
- g_free (emcs->uid);
+ if (context->composer != NULL)
+ g_object_unref (context->composer);
- g_free (emcs);
-}
+ if (context->activity != NULL)
+ g_object_unref (context->activity);
-static void
-emcs_ref (struct emcs_t *emcs)
-{
- emcs->ref_count++;
-}
+ g_free (context->folder_uri);
+ g_free (context->message_uid);
-static void
-emcs_unref (struct emcs_t *emcs)
-{
- emcs->ref_count--;
- if (emcs->ref_count == 0)
- free_emcs (emcs);
+ g_slice_free (AsyncContext, context);
}
static gboolean
@@ -211,69 +148,6 @@ ask_confirm_for_only_bcc (EMsgComposer *composer, gboolean hidden_list_case)
hidden_list_case?"mail:ask-send-only-bcc-contact":"mail:ask-send-only-bcc", NULL);
}
-struct _send_data {
- struct emcs_t *emcs;
- EMsgComposer *composer;
- gboolean send;
-};
-
-static void
-composer_send_queued_cb (CamelFolder *folder, CamelMimeMessage *msg, CamelMessageInfo *info,
- gint queued, const gchar *appended_uid, gpointer data)
-{
- CamelSession *session;
- struct emcs_t *emcs;
- struct _send_data *send = data;
-
- emcs = send->emcs;
-
- session = e_msg_composer_get_session (send->composer);
-
- if (queued) {
- if (emcs && emcs->drafts_folder) {
- /* delete the old draft message */
- camel_folder_set_message_flags (
- emcs->drafts_folder, emcs->drafts_uid,
- CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
- CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
- g_object_unref (emcs->drafts_folder);
- emcs->drafts_folder = NULL;
- g_free (emcs->drafts_uid);
- emcs->drafts_uid = NULL;
- }
-
- if (emcs && emcs->folder) {
- /* set any replied flags etc */
- camel_folder_set_message_flags (
- emcs->folder, emcs->uid,
- emcs->flags, emcs->set);
- camel_folder_set_message_user_flag (
- emcs->folder, emcs->uid,
- "receipt-handled", TRUE);
- g_object_unref (emcs->folder);
- emcs->folder = NULL;
- g_free (emcs->uid);
- emcs->uid = NULL;
- }
-
- gtk_widget_destroy (GTK_WIDGET (send->composer));
-
- if (send->send && camel_session_get_online (session)) {
- /* queue a message send */
- mail_send (E_MAIL_SESSION (session));
- }
- } else
- gtk_widget_show (GTK_WIDGET (send->composer));
-
- camel_message_info_free (info);
-
- if (send->emcs)
- emcs_unref (send->emcs);
-
- g_object_unref (send->composer);
- g_free (send);
-}
-
static gboolean
is_group_definition (const gchar *str)
{
@@ -286,106 +160,101 @@ is_group_definition (const gchar *str)
return colon > str && strchr (str, ';') > colon;
}
-static CamelMimeMessage *
-composer_get_message (EMsgComposer *composer, gboolean save_html_object_data)
+static gboolean
+composer_presend_check_recipients (EMsgComposer *composer)
{
- CamelMimeMessage *message = NULL;
- EDestination **recipients, **recipients_bcc;
- gboolean html_mode, send_html, confirm_html;
+ EDestination **recipients;
+ EDestination **recipients_bcc;
CamelInternetAddress *cia;
- gint hidden = 0, shown = 0;
- gint num = 0, num_bcc = 0, num_post = 0;
- const gchar *subject;
- GConfClient *gconf;
- EAccount *account;
- gint i;
- EMEvent *eme;
- EMEventTargetComposer *target;
EComposerHeaderTable *table;
EComposerHeader *post_to_header;
GString *invalid_addrs = NULL;
- GError *error = NULL;
-
- gconf = mail_config_get_gconf_client ();
- table = e_msg_composer_get_header_table (composer);
+ gboolean check_passed = FALSE;
+ gint hidden = 0;
+ gint shown = 0;
+ gint num = 0;
+ gint num_bcc = 0;
+ gint num_post = 0;
+ gint ii;
- /* We should do all of the validity checks based on the composer, and not on
- the created message, as extra interaction may occur when we get the message
- (e.g. to get a passphrase to sign a message) */
+ /* We should do all of the validity checks based on the composer,
+ * and not on the created message, as extra interaction may occur
+ * when we get the message (e.g. passphrase to sign a message). */
- /* get the message recipients */
+ table = e_msg_composer_get_header_table (composer);
recipients = e_composer_header_table_get_destinations (table);
cia = camel_internet_address_new ();
- /* see which ones are visible/present, etc */
- if (recipients) {
- for (i = 0; recipients[i] != NULL; i++) {
- const gchar *addr = e_destination_get_address (recipients[i]);
-
- if (addr && addr[0]) {
- gint len, j;
-
- camel_address_decode ((CamelAddress *) cia, addr);
- len = camel_address_length ((CamelAddress *) cia);
-
- if (len > 0) {
- if (!e_destination_is_evolution_list (recipients[i])) {
- for (j = 0; j < len; j++) {
- const gchar *name = NULL, *eml = NULL;
-
- if (!camel_internet_address_get (cia, j, &name, &eml) ||
- !eml ||
- strchr (eml, '@') <= eml) {
- if (!invalid_addrs)
- invalid_addrs = g_string_new ("");
- else
- g_string_append (invalid_addrs, ", ");
-
- if (name)
- g_string_append (invalid_addrs, name);
- if (eml) {
- g_string_append (invalid_addrs, name ? " <" : "");
- g_string_append (invalid_addrs, eml);
- g_string_append (invalid_addrs, name ? ">" : "");
- }
- }
- }
- }
+ /* See which ones are visible, present, etc. */
+ for (ii = 0; recipients != NULL && recipients[ii] != NULL; ii++) {
+ const gchar *addr;
+ gint len, j;
- camel_address_remove ((CamelAddress *) cia, -1);
- num++;
- if (e_destination_is_evolution_list (recipients[i])
- && !e_destination_list_show_addresses (recipients[i])) {
- hidden++;
- } else {
- shown++;
+ addr = e_destination_get_address (recipients[ii]);
+ if (addr == NULL || *addr == '\0')
+ continue;
+
+ camel_address_decode (CAMEL_ADDRESS (cia), addr);
+ len = camel_address_length (CAMEL_ADDRESS (cia));
+
+ if (len > 0) {
+ if (!e_destination_is_evolution_list (recipients[ii])) {
+ for (j = 0; j < len; j++) {
+ const gchar *name = NULL, *eml = NULL;
+
+ if (!camel_internet_address_get (cia, j, &name, &eml) ||
+ !eml ||
+ strchr (eml, '@') <= eml) {
+ if (!invalid_addrs)
+ invalid_addrs = g_string_new ("");
+ else
+ g_string_append (invalid_addrs, ", ");
+
+ if (name)
+ g_string_append (invalid_addrs, name);
+ if (eml) {
+ g_string_append (invalid_addrs, name ? " <" : "");
+ g_string_append (invalid_addrs, eml);
+ g_string_append (invalid_addrs, name ? ">" : "");
+ }
}
- } else if (is_group_definition (addr)) {
- /* like an address, it will not claim on only-bcc */
- shown++;
- num++;
- } else if (!invalid_addrs) {
- invalid_addrs = g_string_new (addr);
- } else {
- g_string_append (invalid_addrs, ", ");
- g_string_append (invalid_addrs, addr);
}
}
+
+ camel_address_remove (CAMEL_ADDRESS (cia), -1);
+ num++;
+ if (e_destination_is_evolution_list (recipients[ii])
+ && !e_destination_list_show_addresses (recipients[ii])) {
+ hidden++;
+ } else {
+ shown++;
+ }
+ } else if (is_group_definition (addr)) {
+ /* like an address, it will not claim on only-bcc */
+ shown++;
+ num++;
+ } else if (!invalid_addrs) {
+ invalid_addrs = g_string_new (addr);
+ } else {
+ g_string_append (invalid_addrs, ", ");
+ g_string_append (invalid_addrs, addr);
}
}
recipients_bcc = e_composer_header_table_get_destinations_bcc (table);
if (recipients_bcc) {
- for (i = 0; recipients_bcc[i] != NULL; i++) {
- const gchar *addr = e_destination_get_address (recipients_bcc[i]);
-
- if (addr && addr[0]) {
- camel_address_decode ((CamelAddress *) cia, addr);
- if (camel_address_length ((CamelAddress *) cia) > 0) {
- camel_address_remove ((CamelAddress *) cia, -1);
- num_bcc++;
- }
+ for (ii = 0; recipients_bcc[ii] != NULL; ii++) {
+ const gchar *addr;
+
+ addr = e_destination_get_address (recipients_bcc[ii]);
+ if (addr == NULL || *addr == '\0')
+ continue;
+
+ camel_address_decode (CAMEL_ADDRESS (cia), addr);
+ if (camel_address_length (CAMEL_ADDRESS (cia)) > 0) {
+ camel_address_remove (CAMEL_ADDRESS (cia), -1);
+ num_bcc++;
}
}
@@ -394,24 +263,32 @@ composer_get_message (EMsgComposer *composer, gboolean save_html_object_data)
g_object_unref (cia);
- post_to_header = e_composer_header_table_get_header (table, E_COMPOSER_HEADER_POST_TO);
+ post_to_header = e_composer_header_table_get_header (
+ table, E_COMPOSER_HEADER_POST_TO);
if (e_composer_header_get_visible (post_to_header)) {
GList *postlist;
postlist = e_composer_header_table_get_post_to (table);
num_post = g_list_length (postlist);
- g_list_foreach (postlist, (GFunc)g_free, NULL);
+ g_list_foreach (postlist, (GFunc) g_free, NULL);
g_list_free (postlist);
}
/* I'm sensing a lack of love, er, I mean recipients. */
if (num == 0 && num_post == 0) {
- e_alert_run_dialog_for_args ((GtkWindow *)composer, "mail:send-no-recipients", NULL);
+ e_alert_submit (
+ GTK_WIDGET (composer),
+ "mail:send-no-recipients", NULL);
goto finished;
}
if (invalid_addrs) {
- if (e_alert_run_dialog_for_args ((GtkWindow *)composer, strstr (invalid_addrs->str, ", ") ? "mail:ask-send-invalid-recip-multi" : "mail:ask-send-invalid-recip-one", invalid_addrs->str, NULL) == GTK_RESPONSE_CANCEL) {
+ if (e_alert_run_dialog_for_args (
+ GTK_WINDOW (composer),
+ strstr (invalid_addrs->str, ", ") ?
+ "mail:ask-send-invalid-recip-multi" :
+ "mail:ask-send-invalid-recip-one",
+ invalid_addrs->str, NULL) == GTK_RESPONSE_CANCEL) {
g_string_free (invalid_addrs, TRUE);
goto finished;
}
@@ -425,154 +302,277 @@ composer_get_message (EMsgComposer *composer, gboolean save_html_object_data)
goto finished;
}
- html_mode = gtkhtml_editor_get_html_mode (GTKHTML_EDITOR (composer));
- send_html = gconf_client_get_bool (gconf, "/apps/evolution/mail/composer/send_html", NULL);
- confirm_html = gconf_client_get_bool (gconf, "/apps/evolution/mail/prompts/unwanted_html", NULL);
+ check_passed = TRUE;
- /* Only show this warning if our default is to send html. If it isn't, we've
- manually switched into html mode in the composer and (presumably) had a good
- reason for doing this. */
- if (html_mode && send_html && confirm_html) {
+finished:
+ if (recipients != NULL)
+ e_destination_freev (recipients);
- gboolean html_problem = FALSE;
+ return check_passed;
+}
- if (recipients) {
- for (i = 0; recipients[i] != NULL && !html_problem; i++) {
- if (!e_destination_get_html_mail_pref (recipients[i]))
- html_problem = TRUE;
- }
- }
+static gboolean
+composer_presend_check_account (EMsgComposer *composer)
+{
+ EComposerHeaderTable *table;
+ EAccount *account;
+ gboolean check_passed;
- if (html_problem) {
- html_problem = !ask_confirm_for_unwanted_html_mail (composer, recipients);
- if (html_problem)
- goto finished;
- }
- }
+ table = e_msg_composer_get_header_table (composer);
+ account = e_composer_header_table_get_account (table);
+ check_passed = (account != NULL && account->enabled);
- /* Check for no subject */
- subject = e_composer_header_table_get_subject (table);
- if (subject == NULL || subject[0] == '\0') {
- if (!ask_confirm_for_empty_subject (composer))
- goto finished;
+ if (!check_passed)
+ e_alert_submit (
+ GTK_WIDGET (composer),
+ "mail:send-no-account-enabled", NULL);
+
+ return check_passed;
+}
+
+static gboolean
+composer_presend_check_downloads (EMsgComposer *composer)
+{
+ EAttachmentView *view;
+ EAttachmentStore *store;
+ gboolean check_passed = TRUE;
+
+ view = e_msg_composer_get_attachment_view (composer);
+ store = e_attachment_view_get_store (view);
+
+ if (e_attachment_store_get_num_loading (store) > 0) {
+ if (!em_utils_prompt_user (GTK_WINDOW (composer), NULL,
+ "mail-composer:ask-send-message-pending-download", NULL))
+ check_passed = FALSE;
}
+ return check_passed;
+}
+
+static gboolean
+composer_presend_check_plugins (EMsgComposer *composer)
+{
+ EMEvent *eme;
+ EMEventTargetComposer *target;
+ gpointer data;
+
/** @Event: composer.presendchecks
* @Title: Composer PreSend Checks
* @Target: EMEventTargetMessage
*
- * composer.presendchecks is emitted during pre-checks for the message just before sending.
- * Since the e-plugin framework doesn't provide a way to return a value from the plugin,
- * use 'presend_check_status' to set whether the check passed / failed.
+ * composer.presendchecks is emitted during pre-checks for the
+ * message just before sending. Since the e-plugin framework
+ * doesn't provide a way to return a value from the plugin,
+ * use 'presend_check_status' to set whether the check passed.
*/
eme = em_event_peek ();
target = em_event_target_new_composer (eme, composer, 0);
- g_object_set_data (G_OBJECT (composer), "presend_check_status", GINT_TO_POINTER(0));
- e_event_emit((EEvent *)eme, "composer.presendchecks", (EEventTarget *)target);
+ e_event_emit (
+ (EEvent *) eme, "composer.presendchecks",
+ (EEventTarget *) target);
- if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (composer), "presend_check_status")))
- goto finished;
+ /* A non-NULL value for this key means the check failed. */
+ data = g_object_get_data (G_OBJECT (composer), "presend_check_status");
- /* actually get the message now, this will sign/encrypt etc */
- message = e_msg_composer_get_message (
- composer, save_html_object_data, NULL, &error);
+ return (data == NULL);
+}
+
+static gboolean
+composer_presend_check_subject (EMsgComposer *composer)
+{
+ EComposerHeaderTable *table;
+ const gchar *subject;
+ gboolean check_passed = TRUE;
+
+ table = e_msg_composer_get_header_table (composer);
+ subject = e_composer_header_table_get_subject (table);
+
+ if (subject == NULL || subject[0] == '\0') {
+ if (!ask_confirm_for_empty_subject (composer))
+ check_passed = FALSE;
+ }
+
+ return check_passed;
+}
+
+static gboolean
+composer_presend_check_unwanted_html (EMsgComposer *composer)
+{
+ EDestination **recipients;
+ EComposerHeaderTable *table;
+ GConfClient *client;
+ gboolean check_passed = TRUE;
+ gboolean html_mode;
+ gboolean send_html;
+ gboolean confirm_html;
+ gint ii;
+
+ client = gconf_client_get_default ();
+
+ table = e_msg_composer_get_header_table (composer);
+ recipients = e_composer_header_table_get_destinations (table);
+ html_mode = gtkhtml_editor_get_html_mode (GTKHTML_EDITOR (composer));
+
+ send_html = gconf_client_get_bool (
+ client, "/apps/evolution/mail/composer/send_html", NULL);
+ confirm_html = gconf_client_get_bool (
+ client, "/apps/evolution/mail/prompts/unwanted_html", NULL);
+
+ /* Only show this warning if our default is to send html. If it
+ * isn't, we've manually switched into html mode in the composer
+ * and (presumably) had a good reason for doing this. */
+ if (html_mode && send_html && confirm_html && recipients != NULL) {
+ gboolean html_problem = FALSE;
+
+ for (ii = 0; recipients[ii] != NULL; ii++) {
+ if (!e_destination_get_html_mail_pref (recipients[ii]))
+ html_problem = TRUE;
+ break;
+ }
+
+ if (html_problem) {
+ if (!ask_confirm_for_unwanted_html_mail (
+ composer, recipients))
+ check_passed = FALSE;
+ }
+ }
+
+ if (recipients != NULL)
+ e_destination_freev (recipients);
+
+ g_object_unref (client);
+
+ return check_passed;
+}
+
+static void
+composer_send_completed (EMailSession *session,
+ GAsyncResult *result,
+ AsyncContext *context)
+{
+ GError *error = NULL;
+
+ e_mail_session_send_to_finish (session, result, &error);
/* Ignore cancellations. */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- g_warn_if_fail (message == NULL);
g_error_free (error);
- goto finished;
+ goto exit;
}
if (error != NULL) {
- g_warn_if_fail (message == NULL);
- e_alert_run_dialog_for_args (
- GTK_WINDOW (composer),
- "mail-composer:no-build-message",
+ e_alert_submit (
+ GTK_WIDGET (context->composer),
+ "mail-composer:send-error",
error->message, NULL);
g_error_free (error);
- goto finished;
- }
-
- g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
-
- /* Add info about the sending account */
- account = e_composer_header_table_get_account (table);
-
- if (account) {
- /* FIXME: Why isn't this crap just in e_msg_composer_get_message? */
- camel_medium_set_header (CAMEL_MEDIUM (message), "X-Evolution-Account", account->uid);
- camel_medium_set_header (CAMEL_MEDIUM (message), "X-Evolution-Transport", account->transport->url);
- camel_medium_set_header (CAMEL_MEDIUM (message), "X-Evolution-Fcc", account->sent_folder_uri);
- if (account->id->organization && *account->id->organization) {
- gchar *org;
-
- org = camel_header_encode_string ((const guchar *)account->id->organization);
- camel_medium_set_header (CAMEL_MEDIUM (message), "Organization", org);
- g_free (org);
- }
+ goto exit;
}
- finished:
+ e_activity_complete (context->activity);
- if (recipients)
- e_destination_freev (recipients);
+ /* Wait for the EActivity's completion message to
+ * time out and then destroy the composer window. */
+ g_object_weak_ref (
+ G_OBJECT (context->activity), (GWeakNotify)
+ gtk_widget_destroy, context->composer);
- return message;
+exit:
+ async_context_free (context);
}
static void
-em_utils_composer_send_cb (EMsgComposer *composer)
+composer_send_appended (CamelFolder *outbox_folder,
+ GAsyncResult *result,
+ AsyncContext *context)
{
- EComposerHeaderTable *table;
- CamelMimeMessage *message;
- CamelMessageInfo *info;
- struct _send_data *send;
- CamelFolder *folder;
- EAccount *account;
+ CamelSession *session;
+ GCancellable *cancellable;
+ gchar *message_uid = NULL;
+ GError *error = NULL;
- table = e_msg_composer_get_header_table (composer);
- account = e_composer_header_table_get_account (table);
- if (!account || !account->enabled) {
- e_alert_run_dialog_for_args (
- GTK_WINDOW (composer),
- "mail:send-no-account-enabled", NULL);
+ e_mail_folder_append_message_finish (
+ outbox_folder, result, &message_uid, &error);
+
+ /* Ignore cancellations. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warn_if_fail (message_uid == NULL);
+ async_context_free (context);
+ g_error_free (error);
return;
}
- if ((message = composer_get_message (composer, FALSE)) == NULL)
+ if (error != NULL) {
+ g_warn_if_fail (message_uid == NULL);
+ e_alert_submit (
+ GTK_WIDGET (context->composer),
+ "mail-composer:append-to-outbox-error",
+ error->message, NULL);
+ g_warning ("%s", error->message);
+ async_context_free (context);
+ g_error_free (error);
return;
+ }
- folder = e_mail_local_get_folder (E_MAIL_FOLDER_OUTBOX);
- g_object_ref (folder);
+ session = e_msg_composer_get_session (context->composer);
+ cancellable = e_activity_get_cancellable (context->activity);
- /* mail the message */
- e_msg_composer_set_mail_sent (composer, TRUE);
- info = camel_message_info_new (NULL);
+ /* If we're online, go ahead and send the message now. */
+ if (camel_session_get_online (session))
+ e_mail_session_send_to (
+ E_MAIL_SESSION (session),
+ outbox_folder, message_uid, NULL,
+ G_PRIORITY_DEFAULT, cancellable, NULL, NULL,
+ (GAsyncReadyCallback) composer_send_completed,
+ context);
- camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0);
+ /* If we're offline, writing the message to the Outbox
+ * folder is as much as we can do. Tell the user. */
+ else {
+ g_object_unref (context->activity);
+ context->activity = NULL;
- send = g_malloc (sizeof (*send));
- send->emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- if (send->emcs)
- emcs_ref (send->emcs);
- send->send = TRUE;
- send->composer = g_object_ref (composer);
- gtk_widget_hide (GTK_WIDGET (composer));
+ e_alert_run_dialog_for_args (
+ GTK_WINDOW (context->composer),
+ "mail-composer:saved-to-outbox", NULL);
- mail_append_mail (
- folder, message, info, composer_send_queued_cb, send);
+ gtk_widget_destroy (GTK_WIDGET (context->composer));
+ async_context_free (context);
+ }
- g_object_unref (folder);
- g_object_unref (message);
+ g_free (message_uid);
}
-struct _save_draft_info {
- struct emcs_t *emcs;
- EMsgComposer *composer;
+static void
+em_utils_composer_send_cb (EMsgComposer *composer,
+ CamelMimeMessage *message,
+ EActivity *activity)
+{
+ AsyncContext *context;
+ CamelFolder *outbox_folder;
CamelMessageInfo *info;
-};
+ GCancellable *cancellable;
+
+ context = g_slice_new0 (AsyncContext);
+ context->message = g_object_ref (message);
+ context->composer = g_object_ref (composer);
+ context->activity = g_object_ref (activity);
+
+ cancellable = e_activity_get_cancellable (activity);
+ outbox_folder = e_mail_local_get_folder (E_MAIL_FOLDER_OUTBOX);
+
+ info = camel_message_info_new (NULL);
+ camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0);
+
+ e_mail_folder_append_message (
+ outbox_folder, message, info,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) composer_send_appended,
+ context);
+
+ camel_message_info_free (info);
+}
static void
composer_set_no_change (EMsgComposer *composer)
@@ -588,172 +588,211 @@ composer_set_no_change (EMsgComposer *composer)
}
static void
-save_draft_done (CamelFolder *folder, CamelMimeMessage *msg, CamelMessageInfo *info, gint ok,
- const gchar *appended_uid, gpointer user_data)
+composer_save_draft_complete (EMailSession *session,
+ GAsyncResult *result,
+ AsyncContext *context)
{
- struct _save_draft_info *sdi = user_data;
- struct emcs_t *emcs;
+ GError *error = NULL;
- if (!ok)
- goto done;
+ /* We don't really care if this failed. If something other than
+ * cancellation happened, emit a runtime warning so the error is
+ * not completely lost. */
- if ((emcs = sdi->emcs) == NULL)
- emcs = emcs_new ();
+ e_mail_session_handle_draft_headers_finish (session, result, &error);
- if (emcs->drafts_folder) {
- /* delete the original draft message */
- camel_folder_set_message_flags (
- emcs->drafts_folder, emcs->drafts_uid,
- CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
- CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
- g_object_unref (emcs->drafts_folder);
- emcs->drafts_folder = NULL;
- g_free (emcs->drafts_uid);
- emcs->drafts_uid = NULL;
- }
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_error_free (error);
- if (emcs->folder) {
- /* set the replied flags etc */
- camel_folder_set_message_flags (
- emcs->folder, emcs->uid,
- emcs->flags, emcs->set);
- g_object_unref (emcs->folder);
- emcs->folder = NULL;
- g_free (emcs->uid);
- emcs->uid = NULL;
+ else if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
}
- if (appended_uid) {
- g_object_ref (folder);
- emcs->drafts_folder = folder;
- emcs->drafts_uid = g_strdup (appended_uid);
- }
+ /* Encode the draft message we just saved into the EMsgComposer
+ * as X-Evolution-Draft headers. The message will be marked for
+ * deletion if the user saves a newer draft message or sends the
+ * composed message. */
+ e_msg_composer_set_draft_headers (
+ context->composer, context->folder_uri,
+ context->message_uid);
- if (e_msg_composer_is_exiting (sdi->composer))
- gtk_widget_destroy (GTK_WIDGET (sdi->composer));
+ e_activity_complete (context->activity);
- done:
- g_object_unref (sdi->composer);
- if (sdi->emcs)
- emcs_unref (sdi->emcs);
- camel_message_info_free (info);
- g_free (sdi);
+ async_context_free (context);
}
static void
-save_draft_folder (gchar *uri, CamelFolder *folder, gpointer data)
+composer_save_draft_cleanup (CamelFolder *drafts_folder,
+ GAsyncResult *result,
+ AsyncContext *context)
{
- CamelFolder **save = data;
+ CamelSession *session;
+ GCancellable *cancellable;
+ GError *error = NULL;
+
+ e_mail_folder_append_message_finish (
+ drafts_folder, result, &context->message_uid, &error);
+
+ /* Ignore cancellations. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warn_if_fail (context->message_uid == NULL);
+ async_context_free (context);
+ g_error_free (error);
+ return;
+ }
- if (folder) {
- *save = folder;
- g_object_ref (folder);
+ if (error != NULL) {
+ g_warn_if_fail (context->message_uid == NULL);
+ e_alert_submit (
+ GTK_WIDGET (context->composer),
+ "mail-composer:save-draft-error",
+ error->message, NULL);
+ async_context_free (context);
+ g_error_free (error);
+ return;
}
+
+ session = e_msg_composer_get_session (context->composer);
+ cancellable = e_activity_get_cancellable (context->activity);
+
+ /* Mark the previously saved draft message for deletion.
+ * Note: This is just a nice-to-have; ignore failures. */
+ e_mail_session_handle_draft_headers (
+ E_MAIL_SESSION (session), context->message,
+ G_PRIORITY_DEFAULT, cancellable, (GAsyncReadyCallback)
+ composer_save_draft_complete, context);
}
static void
-em_utils_composer_save_draft_cb (EMsgComposer *composer)
+composer_save_draft_append_mail (AsyncContext *context,
+ CamelFolder *drafts_folder)
{
CamelFolder *local_drafts_folder;
- EComposerHeaderTable *table;
- struct _save_draft_info *sdi;
- const gchar *local_drafts_folder_uri;
- CamelFolder *folder = NULL;
- CamelMimeMessage *msg;
+ GCancellable *cancellable;
CamelMessageInfo *info;
- CamelSession *session;
- EAccount *account;
- GError *error = NULL;
-
- /* need to get stuff from the composer here, since it could
- * get destroyed while we're in mail_msg_wait() a little lower
- * down, waiting for the folder to open */
-
- session = e_msg_composer_get_session (composer);
local_drafts_folder =
e_mail_local_get_folder (E_MAIL_FOLDER_DRAFTS);
- local_drafts_folder_uri =
- e_mail_local_get_folder_uri (E_MAIL_FOLDER_DRAFTS);
- msg = e_msg_composer_get_message_draft (composer, NULL, &error);
+ if (drafts_folder == NULL)
+ drafts_folder = g_object_ref (local_drafts_folder);
+
+ cancellable = e_activity_get_cancellable (context->activity);
+
+ info = camel_message_info_new (NULL);
+
+ camel_message_info_set_flags (
+ info, CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_SEEN, ~0);
+
+ e_mail_folder_append_message (
+ drafts_folder, context->message,
+ info, G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) composer_save_draft_cleanup,
+ context);
+
+ camel_message_info_free (info);
+
+ g_object_unref (drafts_folder);
+}
+
+static void
+composer_save_draft_got_folder (EMailSession *session,
+ GAsyncResult *result,
+ AsyncContext *context)
+{
+ CamelFolder *drafts_folder;
+ GError *error = NULL;
+
+ drafts_folder = e_mail_session_uri_to_folder_finish (
+ session, result, &error);
/* Ignore cancellations. */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- g_warn_if_fail (msg == NULL);
+ g_warn_if_fail (drafts_folder == NULL);
+ async_context_free (context);
g_error_free (error);
return;
}
if (error != NULL) {
- g_warn_if_fail (msg == NULL);
- e_alert_run_dialog_for_args (
- GTK_WINDOW (composer),
- "mail-composer:no-build-message",
- error->message, NULL);
+ gint response;
+
+ g_warn_if_fail (drafts_folder == NULL);
+
+ /* XXX Not showing the error message in the dialog? */
g_error_free (error);
- return;
+
+ /* If we can't retrieve the Drafts folder for the
+ * selected account, ask the user if he wants to
+ * save to the local Drafts folder instead. */
+ response = e_alert_run_dialog_for_args (
+ GTK_WINDOW (context->composer),
+ "mail:ask-default-drafts", NULL);
+ if (response != GTK_RESPONSE_YES) {
+ async_context_free (context);
+ return;
+ }
}
- g_return_if_fail (CAMEL_IS_MIME_MESSAGE (msg));
+ composer_save_draft_append_mail (context, drafts_folder);
+}
+
+static void
+em_utils_composer_save_draft_cb (EMsgComposer *composer,
+ CamelMimeMessage *message,
+ EActivity *activity)
+{
+ AsyncContext *context;
+ EComposerHeaderTable *table;
+ const gchar *drafts_folder_uri = NULL;
+ const gchar *local_drafts_folder_uri;
+ CamelSession *session;
+ EAccount *account;
+
+ context = g_slice_new0 (AsyncContext);
+ context->message = g_object_ref (message);
+ context->composer = g_object_ref (composer);
+ context->activity = g_object_ref (activity);
+
+ session = e_msg_composer_get_session (composer);
+
+ local_drafts_folder_uri =
+ e_mail_local_get_folder_uri (E_MAIL_FOLDER_DRAFTS);
table = e_msg_composer_get_header_table (composer);
account = e_composer_header_table_get_account (table);
- sdi = g_malloc (sizeof (struct _save_draft_info));
- sdi->composer = g_object_ref (composer);
- sdi->emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- if (sdi->emcs)
- emcs_ref (sdi->emcs);
+ if (account != NULL && account->enabled)
+ drafts_folder_uri = account->drafts_folder_uri;
- if (account && account->drafts_folder_uri &&
- strcmp (account->drafts_folder_uri, local_drafts_folder_uri) != 0) {
- gint id;
+ if (g_strcmp0 (drafts_folder_uri, local_drafts_folder_uri) == 0)
+ drafts_folder_uri = NULL;
- id = mail_get_folder (
- E_MAIL_SESSION (session),
- account->drafts_folder_uri, 0,
- save_draft_folder, &folder,
- mail_msg_unordered_push);
- mail_msg_wait (id);
-
- if (!folder || !account->enabled) {
- if (e_alert_run_dialog_for_args ((GtkWindow *)composer, "mail:ask-default-drafts", NULL) != GTK_RESPONSE_YES) {
- g_object_unref (composer);
- g_object_unref (msg);
- if (sdi->emcs)
- emcs_unref (sdi->emcs);
- g_free (sdi);
- return;
- }
-
- folder = local_drafts_folder;
- g_object_ref (local_drafts_folder);
- }
+ if (drafts_folder_uri == NULL) {
+ composer_save_draft_append_mail (context, NULL);
+ context->folder_uri = g_strdup (local_drafts_folder_uri);
} else {
- folder = local_drafts_folder;
- g_object_ref (folder);
- }
-
- info = camel_message_info_new (NULL);
+ GCancellable *cancellable;
- camel_message_info_set_flags (
- info, CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_SEEN, ~0);
+ cancellable = e_activity_get_cancellable (activity);
+ context->folder_uri = g_strdup (drafts_folder_uri);
- mail_append_mail (folder, msg, info, save_draft_done, sdi);
- g_object_unref (folder);
- g_object_unref (msg);
+ e_mail_session_uri_to_folder (
+ E_MAIL_SESSION (session),
+ drafts_folder_uri, 0, G_PRIORITY_DEFAULT,
+ cancellable, (GAsyncReadyCallback)
+ composer_save_draft_got_folder, context);
+ }
}
static void
em_utils_composer_print_cb (EMsgComposer *composer,
- GtkPrintOperationAction action)
+ GtkPrintOperationAction action,
+ CamelMimeMessage *message,
+ EActivity *activity)
{
- CamelMimeMessage *message;
EMFormatHTMLPrint *efhp;
- message = e_msg_composer_get_message_print (composer, 1, NULL);
-
efhp = em_format_html_print_new (NULL, action);
em_format_html_print_raw_message (efhp, message);
g_object_unref (efhp);
@@ -998,14 +1037,14 @@ traverse_parts (GSList *clues, CamelMimeMessage *message, CamelDataWrapper *cont
static GtkWidget *
edit_message (EShell *shell,
+ CamelFolder *folder,
CamelMimeMessage *message,
- CamelFolder *drafts,
- const gchar *uid)
+ const gchar *message_uid)
{
EMsgComposer *composer;
/* Template specific code follows. */
- if (em_utils_folder_is_templates (drafts, NULL) == TRUE) {
+ if (em_utils_folder_is_templates (folder, NULL)) {
GConfClient *gconf;
GSList *clue_list = NULL;
@@ -1022,11 +1061,14 @@ edit_message (EShell *shell,
composer = e_msg_composer_new_with_message (shell, message, NULL);
- if (em_utils_folder_is_drafts (drafts, NULL)) {
- struct emcs_t *emcs;
+ if (message_uid != NULL) {
+ const gchar *folder_uri;
+
+ folder_uri = camel_folder_get_uri (folder);
- emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- emcs_set_drafts_info (emcs, drafts, uid);
+ if (em_utils_folder_is_drafts (folder, folder_uri))
+ e_msg_composer_set_draft_headers (
+ composer, folder_uri, message_uid);
}
composer_set_no_change (composer);
@@ -1039,21 +1081,22 @@ edit_message (EShell *shell,
/**
* em_utils_edit_message:
* @shell: an #EShell
- * @message: message to edit
- * @folder: used to recognize the templates folder
+ * @folder: a #CamelFolder
+ * @message: a #CamelMimeMessage
*
* Opens a composer filled in with the headers/mime-parts/etc of
* @message.
**/
GtkWidget *
em_utils_edit_message (EShell *shell,
- CamelMimeMessage *message,
- CamelFolder *folder)
+ CamelFolder *folder,
+ CamelMimeMessage *message)
{
g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
- return edit_message (shell, message, folder, NULL);
+ return edit_message (shell, folder, message, NULL);
}
static void
@@ -1071,7 +1114,7 @@ edit_messages_replace (CamelFolder *folder,
for (ii = 0; ii < msgs->len; ii++) {
camel_medium_remove_header (
CAMEL_MEDIUM (msgs->pdata[ii]), "X-Mailer");
- edit_message (shell, msgs->pdata[ii], folder, uids->pdata[ii]);
+ edit_message (shell, folder, msgs->pdata[ii], uids->pdata[ii]);
}
g_object_unref (shell);
@@ -1092,7 +1135,7 @@ edit_messages_no_replace (CamelFolder *folder,
for (ii = 0; ii < msgs->len; ii++) {
camel_medium_remove_header (
CAMEL_MEDIUM (msgs->pdata[ii]), "X-Mailer");
- edit_message (shell, msgs->pdata[ii], NULL, NULL);
+ edit_message (shell, NULL, msgs->pdata[ii], NULL);
}
g_object_unref (shell);
@@ -1300,6 +1343,7 @@ forward_non_attached (EShell *shell,
{
CamelMimeMessage *message;
EMsgComposer *composer = NULL;
+ const gchar *folder_uri;
gchar *subject, *text;
gint i;
guint32 flags;
@@ -1307,6 +1351,8 @@ forward_non_attached (EShell *shell,
if (messages->len == 0)
return NULL;
+ folder_uri = camel_folder_get_uri (folder);
+
flags = EM_FORMAT_QUOTE_HEADERS | EM_FORMAT_QUOTE_KEEP_SIG;
if (style == MAIL_CONFIG_FORWARD_QUOTED)
flags |= EM_FORMAT_QUOTE_CITE;
@@ -1329,12 +1375,11 @@ forward_non_attached (EShell *shell,
e_msg_composer_set_body_text (composer, text, len);
- if (uids && uids->pdata[i]) {
- struct emcs_t *emcs;
-
- emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- emcs_set_folder_info (emcs, folder, uids->pdata[i], CAMEL_MESSAGE_FORWARDED, CAMEL_MESSAGE_FORWARDED);
- }
+ if (uids && uids->pdata[i])
+ e_msg_composer_set_source_headers (
+ composer, folder_uri,
+ uids->pdata[i],
+ CAMEL_MESSAGE_FORWARDED);
emu_update_composers_security (composer, validity_found);
composer_set_no_change (composer);
@@ -2533,7 +2578,6 @@ em_utils_reply_to_message (EShell *shell,
EMsgComposer *composer;
EAccount *account;
guint32 flags;
- struct emcs_t *emcs;
g_return_val_if_fail (E_IS_SHELL (shell), NULL);
@@ -2599,8 +2643,15 @@ em_utils_reply_to_message (EShell *shell,
composer_set_body (composer, message, source);
g_object_unref (message);
- emcs = g_object_get_data (G_OBJECT (composer), "emcs");
- emcs_set_folder_info (emcs, folder, uid, flags, flags);
+
+ if (folder != NULL) {
+ const gchar *folder_uri;
+
+ folder_uri = camel_folder_get_uri (folder);
+
+ e_msg_composer_set_source_headers (
+ composer, folder_uri, uid, flags);
+ }
composer_set_no_change (composer);
@@ -2679,7 +2730,6 @@ em_configure_new_composer (EMsgComposer *composer)
EComposerHeaderTable *table;
EComposerHeaderType header_type;
EComposerHeader *header;
- struct emcs_t *emcs;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
@@ -2687,11 +2737,29 @@ em_configure_new_composer (EMsgComposer *composer)
table = e_msg_composer_get_header_table (composer);
header = e_composer_header_table_get_header (table, header_type);
- emcs = emcs_new ();
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_recipients), NULL);
- g_object_set_data_full (
- G_OBJECT (composer), "emcs", emcs,
- (GDestroyNotify) emcs_unref);
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_account), NULL);
+
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_downloads), NULL);
+
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_plugins), NULL);
+
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_subject), NULL);
+
+ g_signal_connect (
+ composer, "presend",
+ G_CALLBACK (composer_presend_check_unwanted_html), NULL);
g_signal_connect (
composer, "send",
diff --git a/mail/em-composer-utils.h b/mail/em-composer-utils.h
index fa991863f6..81e8cf1eb0 100644
--- a/mail/em-composer-utils.h
+++ b/mail/em-composer-utils.h
@@ -37,8 +37,8 @@ EMsgComposer * em_utils_compose_new_message_with_mailto
const gchar *url,
const gchar *from_uri);
GtkWidget * em_utils_edit_message (EShell *shell,
- CamelMimeMessage *message,
- CamelFolder *folder);
+ CamelFolder *folder,
+ CamelMimeMessage *message);
void em_utils_edit_messages (EShell *shell,
CamelFolder *folder,
GPtrArray *uids,