diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2010-10-06 22:55:27 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2010-10-13 01:59:00 +0800 |
commit | 4118d671d44b71592f0e91abb63f2468baaa9318 (patch) | |
tree | e70f787f68034a16df1c59f75c8869618b02146b /mail | |
parent | a06e4484b8df804124b5bcf88d94dec5acfba270 (diff) | |
download | gsoc2013-evolution-4118d671d44b71592f0e91abb63f2468baaa9318.tar gsoc2013-evolution-4118d671d44b71592f0e91abb63f2468baaa9318.tar.gz gsoc2013-evolution-4118d671d44b71592f0e91abb63f2468baaa9318.tar.bz2 gsoc2013-evolution-4118d671d44b71592f0e91abb63f2468baaa9318.tar.lz gsoc2013-evolution-4118d671d44b71592f0e91abb63f2468baaa9318.tar.xz gsoc2013-evolution-4118d671d44b71592f0e91abb63f2468baaa9318.tar.zst gsoc2013-evolution-4118d671d44b71592f0e91abb63f2468baaa9318.zip |
Composer: Show cancellable operations and errors inline.
'Send' and 'Save Draft' are now asynchronous and run outside of
Evolution's MailMsg infrastructure.
Add an EActivityBar to the composer window so these asynchronous
operations can be tracked and cancelled even in the absense of a main
window. Also add an EAlertBar to the composer window so error messages
can be shown directly in the window.
Instead of calling e_alert_dialog_run_for_args(), call e_alert_submit()
and pass the EMsgComposer as the widget argument. The EMsgComposer will
decide whether to show an EAlertDialog or use the EAlertBar, depending
on the GtkMessageType of the alert.
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, |