diff options
Diffstat (limited to 'mail')
-rw-r--r-- | mail/Makefile.am | 4 | ||||
-rw-r--r-- | mail/e-mail-folder-utils.c | 142 | ||||
-rw-r--r-- | mail/e-mail-folder-utils.h | 43 | ||||
-rw-r--r-- | mail/e-mail-reader.c | 11 | ||||
-rw-r--r-- | mail/e-mail-session-utils.c | 846 | ||||
-rw-r--r-- | mail/e-mail-session-utils.h | 76 | ||||
-rw-r--r-- | mail/em-composer-utils.c | 1010 | ||||
-rw-r--r-- | mail/em-composer-utils.h | 4 |
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, |