aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail/e-mail-folder-utils.c242
-rw-r--r--mail/e-mail-folder-utils.h18
-rw-r--r--mail/e-mail-reader-utils.c111
-rw-r--r--mail/e-mail-reader-utils.h1
-rw-r--r--mail/e-mail-reader.c65
-rw-r--r--mail/mail-ops.c169
-rw-r--r--mail/mail-ops.h5
-rw-r--r--mail/mail.error.xml5
8 files changed, 378 insertions, 238 deletions
diff --git a/mail/e-mail-folder-utils.c b/mail/e-mail-folder-utils.c
index 10546c15d5..f244260bf5 100644
--- a/mail/e-mail-folder-utils.c
+++ b/mail/e-mail-folder-utils.c
@@ -34,6 +34,7 @@ struct _AsyncContext {
CamelMimePart *part;
GHashTable *hash_table;
GPtrArray *ptr_array;
+ GFile *destination;
gchar *fwd_subject;
gchar *message_uid;
};
@@ -56,6 +57,9 @@ async_context_free (AsyncContext *context)
if (context->ptr_array != NULL)
g_ptr_array_unref (context->ptr_array);
+ if (context->destination != NULL)
+ g_object_unref (context->destination);
+
g_free (context->fwd_subject);
g_free (context->message_uid);
@@ -884,6 +888,244 @@ e_mail_folder_remove_attachments_finish (CamelFolder *folder,
return !g_simple_async_result_propagate_error (simple, error);
}
+static void
+mail_folder_save_messages_thread (GSimpleAsyncResult *simple,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ AsyncContext *context;
+ GError *error = NULL;
+
+ context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ e_mail_folder_save_messages_sync (
+ CAMEL_FOLDER (object), context->ptr_array,
+ context->destination, cancellable, &error);
+
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ }
+}
+
+/* Helper for e_mail_folder_save_messages_sync() */
+static void
+mail_folder_save_prepare_part (CamelMimePart *mime_part)
+{
+ CamelDataWrapper *content;
+
+ content = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+
+ if (content == NULL)
+ return;
+
+ if (CAMEL_IS_MULTIPART (content)) {
+ guint n_parts, ii;
+
+ n_parts = camel_multipart_get_number (
+ CAMEL_MULTIPART (content));
+ for (ii = 0; ii < n_parts; ii++) {
+ mime_part = camel_multipart_get_part (
+ CAMEL_MULTIPART (content), ii);
+ mail_folder_save_prepare_part (mime_part);
+ }
+
+ } else if (CAMEL_IS_MIME_MESSAGE (content)) {
+ mail_folder_save_prepare_part (CAMEL_MIME_PART (content));
+
+ } else {
+ CamelContentType *type;
+
+ /* Save textual parts as 8-bit, not encoded. */
+ type = camel_data_wrapper_get_mime_type_field (content);
+ if (camel_content_type_is (type, "text", "*"))
+ camel_mime_part_set_encoding (
+ mime_part, CAMEL_TRANSFER_ENCODING_8BIT);
+ }
+}
+
+gboolean
+e_mail_folder_save_messages_sync (CamelFolder *folder,
+ GPtrArray *message_uids,
+ GFile *destination,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GFileOutputStream *file_output_stream;
+ GByteArray *byte_array;
+ CamelMimeFilter *filter;
+ CamelStream *base_stream;
+ CamelStream *stream;
+ gboolean success = TRUE;
+ guint ii;
+
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+ g_return_val_if_fail (message_uids != NULL, FALSE);
+ g_return_val_if_fail (G_IS_FILE (destination), FALSE);
+
+ /* Need at least one message UID to save. */
+ g_return_val_if_fail (message_uids->len > 0, FALSE);
+
+ camel_operation_push_message (
+ cancellable, ngettext (
+ "Saving %d message",
+ "Saving %d messages",
+ message_uids->len),
+ message_uids->len);
+
+ file_output_stream = g_file_replace (
+ destination, NULL, FALSE,
+ G_FILE_CREATE_PRIVATE |
+ G_FILE_CREATE_REPLACE_DESTINATION,
+ cancellable, error);
+
+ if (file_output_stream == NULL) {
+ camel_operation_pop_message (cancellable);
+ return FALSE;
+ }
+
+ /* CamelStreamMem takes ownership of the GByteArray. */
+ byte_array = g_byte_array_new ();
+ filter = camel_mime_filter_from_new ();
+ base_stream = camel_stream_mem_new_with_byte_array (byte_array);
+ stream = camel_stream_filter_new (base_stream);
+ camel_stream_filter_add (CAMEL_STREAM_FILTER (stream), filter);
+ g_object_unref (base_stream);
+ g_object_unref (filter);
+
+ for (ii = 0; ii < message_uids->len; ii++) {
+ CamelMimeMessage *message;
+ const gchar *uid;
+ gchar *from_line;
+ gint percent;
+ gint retval;
+
+ uid = g_ptr_array_index (message_uids, ii);
+
+ message = camel_folder_get_message_sync (
+ folder, uid, cancellable, error);
+ if (message == NULL) {
+ success = FALSE;
+ goto exit;
+ }
+
+ mail_folder_save_prepare_part (CAMEL_MIME_PART (message));
+
+ from_line = camel_mime_message_build_mbox_from (message);
+ g_return_val_if_fail (from_line != NULL, FALSE);
+
+ success = g_output_stream_write_all (
+ G_OUTPUT_STREAM (file_output_stream),
+ from_line, strlen (from_line), NULL,
+ cancellable, error);
+
+ g_free (from_line);
+
+ if (!success) {
+ g_object_unref (message);
+ goto exit;
+ }
+
+ retval = camel_data_wrapper_write_to_stream_sync (
+ CAMEL_DATA_WRAPPER (message),
+ stream, cancellable, error);
+
+ if (retval == -1) {
+ g_object_unref (message);
+ goto exit;
+ }
+
+ g_byte_array_append (byte_array, (guint8 *) "\n", 1);
+
+ success = g_output_stream_write_all (
+ G_OUTPUT_STREAM (file_output_stream),
+ byte_array->data, byte_array->len,
+ NULL, cancellable, error);
+
+ if (!success) {
+ g_object_unref (message);
+ goto exit;
+ }
+
+ percent = ((ii + 1) * 100) / message_uids->len;
+ camel_operation_progress (cancellable, percent);
+
+ /* Flush the buffer for the next message.
+ * For memory streams this never fails. */
+ camel_stream_reset (stream, NULL);
+
+ g_object_unref (message);
+ }
+
+exit:
+ g_object_unref (file_output_stream);
+ g_object_unref (stream);
+
+ camel_operation_pop_message (cancellable);
+
+ if (!success) {
+ /* Try deleting the destination file. */
+ g_file_delete (destination, NULL, NULL);
+ }
+
+ return success;
+}
+
+void
+e_mail_folder_save_messages (CamelFolder *folder,
+ GPtrArray *message_uids,
+ GFile *destination,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *context;
+
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (message_uids != NULL);
+ g_return_if_fail (G_IS_FILE (destination));
+
+ /* Need at least one message UID to save. */
+ g_return_if_fail (message_uids->len > 0);
+
+ context = g_slice_new0 (AsyncContext);
+ context->ptr_array = g_ptr_array_ref (message_uids);
+ context->destination = g_object_ref (destination);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (folder), callback, user_data,
+ e_mail_folder_save_messages);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, context, (GDestroyNotify) async_context_free);
+
+ g_simple_async_result_run_in_thread (
+ simple, mail_folder_save_messages_thread,
+ io_priority, cancellable);
+
+ g_object_unref (simple);
+}
+
+gboolean
+e_mail_folder_save_messages_finish (CamelFolder *folder,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (folder),
+ e_mail_folder_save_messages), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
+}
+
/**
* e_mail_folder_uri_build:
* @store: a #CamelStore
diff --git a/mail/e-mail-folder-utils.h b/mail/e-mail-folder-utils.h
index f526c3273b..5b178f4a90 100644
--- a/mail/e-mail-folder-utils.h
+++ b/mail/e-mail-folder-utils.h
@@ -114,6 +114,24 @@ gboolean e_mail_folder_remove_attachments_finish
GAsyncResult *result,
GError **error);
+gboolean e_mail_folder_save_messages_sync
+ (CamelFolder *folder,
+ GPtrArray *message_uids,
+ GFile *destination,
+ GCancellable *cancellable,
+ GError **error);
+void e_mail_folder_save_messages (CamelFolder *folder,
+ GPtrArray *message_uids,
+ GFile *destination,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_mail_folder_save_messages_finish
+ (CamelFolder *folder,
+ GAsyncResult *result,
+ GError **error);
+
gchar * e_mail_folder_uri_build (CamelStore *store,
const gchar *folder_name);
gboolean e_mail_folder_uri_parse (CamelSession *session,
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index 281acbbe52..8e88d7d31a 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -31,6 +31,7 @@
#include "e-util/e-alert-dialog.h"
#include "filter/e-filter-rule.h"
#include "misc/e-web-view.h"
+#include "shell/e-shell-utils.h"
#include "mail/e-mail-backend.h"
#include "mail/e-mail-browser.h"
@@ -753,6 +754,116 @@ whole_message:
reply_type, reply_style, EM_FORMAT (formatter));
}
+static void
+mail_reader_save_messages_cb (CamelFolder *folder,
+ GAsyncResult *result,
+ AsyncContext *context)
+{
+ EAlertSink *alert_sink;
+ GError *error = NULL;
+
+ alert_sink = e_mail_reader_get_alert_sink (context->reader);
+
+ e_mail_folder_save_messages_finish (folder, result, &error);
+
+ if (e_activity_handle_cancellation (context->activity, error)) {
+ g_error_free (error);
+
+ } else if (error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "mail:save-messages",
+ error->message, NULL);
+ g_error_free (error);
+ }
+
+ async_context_free (context);
+}
+
+void
+e_mail_reader_save_messages (EMailReader *reader)
+{
+ EShell *shell;
+ EActivity *activity;
+ AsyncContext *context;
+ EMailBackend *backend;
+ GCancellable *cancellable;
+ EShellBackend *shell_backend;
+ CamelMessageInfo *info;
+ CamelFolder *folder;
+ GFile *destination;
+ GPtrArray *uids;
+ const gchar *message_uid;
+ const gchar *title;
+ gchar *suggestion = NULL;
+
+ folder = e_mail_reader_get_folder (reader);
+ backend = e_mail_reader_get_backend (reader);
+
+ uids = e_mail_reader_get_selected_uids (reader);
+ g_return_if_fail (uids != NULL && uids->len > 0);
+ message_uid = g_ptr_array_index (uids, 0);
+
+ /* XXX Either e_mail_reader_get_selected_uids()
+ * or MessageList should do this itself. */
+ g_ptr_array_set_free_func (uids, (GDestroyNotify) g_free);
+
+ title = ngettext ("Save Message", "Save Messages", uids->len);
+
+ /* Suggest as a filename the subject of the first message. */
+ info = camel_folder_get_message_info (folder, message_uid);
+ if (info != NULL) {
+ const gchar *subject;
+
+ subject = camel_message_info_subject (info);
+ if (subject != NULL)
+ suggestion = g_strconcat (subject, ".mbox", NULL);
+ camel_folder_free_message_info (folder, info);
+ }
+
+ if (suggestion == NULL) {
+ const gchar *basename;
+
+ /* Translators: This is part of a suggested file name
+ * used when saving a message or multiple messages to
+ * mbox format, when the first message doesn't have a
+ * subject. The extension ".mbox" is appended to the
+ * string; for example "Message.mbox". */
+ basename = ngettext ("Message", "Messages", uids->len);
+ suggestion = g_strconcat (basename, ".mbox", NULL);
+ }
+
+ shell_backend = E_SHELL_BACKEND (backend);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ destination = e_shell_run_save_dialog (
+ shell, title, suggestion,
+ "*.mbox:application/mbox,message/rfc822", NULL, NULL);
+
+ if (destination == NULL) {
+ g_ptr_array_unref (uids);
+ return;
+ }
+
+ /* Save messages asynchronously. */
+
+ activity = e_mail_reader_new_activity (reader);
+ cancellable = e_activity_get_cancellable (activity);
+
+ context = g_slice_new0 (AsyncContext);
+ context->activity = activity;
+ context->reader = g_object_ref (reader);
+
+ e_mail_folder_save_messages (
+ folder, uids,
+ destination, G_PRIORITY_DEFAULT,
+ cancellable, (GAsyncReadyCallback)
+ mail_reader_save_messages_cb, context);
+
+ g_object_unref (destination);
+ g_ptr_array_unref (uids);
+}
+
void
e_mail_reader_select_next_message (EMailReader *reader,
gboolean or_else_previous)
diff --git a/mail/e-mail-reader-utils.h b/mail/e-mail-reader-utils.h
index b574f03bfe..b59ff3c8b7 100644
--- a/mail/e-mail-reader-utils.h
+++ b/mail/e-mail-reader-utils.h
@@ -53,6 +53,7 @@ void e_mail_reader_remove_duplicates (EMailReader *reader);
void e_mail_reader_reply_to_message (EMailReader *reader,
CamelMimeMessage *message,
EMailReplyType reply_type);
+void e_mail_reader_save_messages (EMailReader *reader);
void e_mail_reader_select_next_message
(EMailReader *reader,
gboolean or_else_previous);
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 0a6cb06848..27096c4a03 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -1502,70 +1502,7 @@ static void
action_mail_save_as_cb (GtkAction *action,
EMailReader *reader)
{
- EShell *shell;
- EMailBackend *backend;
- EShellBackend *shell_backend;
- CamelMessageInfo *info;
- CamelFolder *folder;
- GPtrArray *uids;
- GFile *file;
- const gchar *message_uid;
- const gchar *title;
- gchar *suggestion = NULL;
- gchar *uri;
-
- folder = e_mail_reader_get_folder (reader);
- backend = e_mail_reader_get_backend (reader);
-
- uids = e_mail_reader_get_selected_uids (reader);
- g_return_if_fail (uids != NULL && uids->len == 1);
- message_uid = g_ptr_array_index (uids, 0);
-
- title = ngettext ("Save Message", "Save Messages", uids->len);
-
- /* Suggest as a filename the subject of the first message. */
- info = camel_folder_get_message_info (folder, message_uid);
- if (info != NULL) {
- const gchar *subject = camel_message_info_subject (info);
-
- if (subject)
- suggestion = g_strconcat (subject, ".mbox", NULL);
- camel_folder_free_message_info (folder, info);
- }
-
- if (!suggestion) {
- const gchar *basename;
-
- /* Translators: This is a part of a suggested file name
- * used when saving a message or multiple messages to an
- * mbox format, when the first message doesn't have a
- * Subject. The extension ".mbox" is appended to this
- * string, thus it will be something like "Message.mbox"
- * at the end. */
- basename = ngettext ("Message", "Messages", uids->len);
- suggestion = g_strconcat (basename, ".mbox", NULL);
- }
-
- shell_backend = E_SHELL_BACKEND (backend);
- shell = e_shell_backend_get_shell (shell_backend);
-
- file = e_shell_run_save_dialog (
- shell, title, suggestion,
- "*.mbox:application/mbox,message/rfc822", NULL, NULL);
-
- if (file == NULL) {
- em_utils_uids_free (uids);
- return;
- }
-
- uri = g_file_get_uri (file);
-
- /* This eats the UID array, so do not free it. */
- mail_save_messages (folder, uids, uri, NULL, NULL);
-
- g_free (uri);
-
- g_object_unref (file);
+ e_mail_reader_save_messages (reader);
}
static void
diff --git a/mail/mail-ops.c b/mail/mail-ops.c
index 1438805321..ad86c772d6 100644
--- a/mail/mail-ops.c
+++ b/mail/mail-ops.c
@@ -1725,175 +1725,6 @@ mail_empty_trash (EMailSession *session,
mail_msg_slow_ordered_push (m);
}
-/* ** SAVE MESSAGES ******************************************************* */
-
-struct _save_messages_msg {
- MailMsg base;
-
- CamelFolder *folder;
- GPtrArray *uids;
- gchar *path;
- void (*done)(CamelFolder *folder, GPtrArray *uids, gchar *path, gpointer data);
- gpointer data;
-};
-
-static gchar *
-save_messages_desc (struct _save_messages_msg *m)
-{
- return g_strdup_printf(ngettext("Saving %d message",
- "Saving %d messages", m->uids->len),
- m->uids->len);
-}
-
-static void
-save_prepare_part (CamelMimePart *mime_part)
-{
- CamelDataWrapper *wrapper;
- gint parts, i;
-
- wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
- if (!wrapper)
- return;
-
- if (CAMEL_IS_MULTIPART (wrapper)) {
- parts = camel_multipart_get_number (CAMEL_MULTIPART (wrapper));
- for (i = 0; i < parts; i++) {
- CamelMimePart *part = camel_multipart_get_part (CAMEL_MULTIPART (wrapper), i);
-
- save_prepare_part (part);
- }
- } else {
- if (CAMEL_IS_MIME_MESSAGE (wrapper)) {
- /* prepare the message parts' subparts */
- save_prepare_part (CAMEL_MIME_PART (wrapper));
- } else {
- CamelContentType *type;
-
- /* We want to save textual parts as 8bit instead of encoded */
- type = camel_data_wrapper_get_mime_type_field (wrapper);
- if (camel_content_type_is (type, "text", "*"))
- camel_mime_part_set_encoding (mime_part, CAMEL_TRANSFER_ENCODING_8BIT);
- }
- }
-}
-
-static void
-save_messages_exec (struct _save_messages_msg *m,
- GCancellable *cancellable,
- GError **error)
-{
- CamelStream *filtered_stream;
- CamelMimeFilter *from_filter;
- CamelStream *stream;
- gint i;
- gchar *from, *path;
-
- if (strstr (m->path, "://"))
- path = m->path;
- else
- path = g_filename_to_uri (m->path, NULL, NULL);
-
- stream = camel_stream_vfs_new_with_uri (path, CAMEL_STREAM_VFS_CREATE);
- from_filter = camel_mime_filter_from_new ();
- filtered_stream = camel_stream_filter_new (stream);
- camel_stream_filter_add (
- CAMEL_STREAM_FILTER (filtered_stream), from_filter);
- g_object_unref (from_filter);
-
- if (path != m->path)
- g_free (path);
-
- for (i=0; i<m->uids->len; i++) {
- CamelMimeMessage *message;
- gint pc = ((i+1) * 100) / m->uids->len;
-
- message = camel_folder_get_message_sync (
- m->folder, m->uids->pdata[i],
- cancellable, error);
- camel_operation_progress (cancellable, pc);
- if (message == NULL)
- break;
-
- save_prepare_part (CAMEL_MIME_PART (message));
-
- /* we need to flush after each stream write since we are writing to the same fd */
- from = camel_mime_message_build_mbox_from (message);
- if (camel_stream_write_string (
- stream, from,
- cancellable, error) == -1
- || camel_stream_flush (
- stream, cancellable, error) == -1
- || camel_data_wrapper_write_to_stream_sync (
- (CamelDataWrapper *) message,
- (CamelStream *) filtered_stream,
- cancellable, error) == -1
- || camel_stream_flush (
- (CamelStream *) filtered_stream,
- cancellable, error) == -1
- || camel_stream_write_string (
- stream, "\n",
- cancellable, error) == -1
- || camel_stream_flush (stream,
- cancellable, error) == -1) {
- g_prefix_error (
- error, _("Error saving messages to: %s:\n"),
- m->path);
- g_free (from);
- g_object_unref ((CamelObject *) message);
- break;
- }
- g_free (from);
- g_object_unref (message);
- }
-
- g_object_unref (filtered_stream);
- g_object_unref (stream);
-}
-
-static void
-save_messages_done (struct _save_messages_msg *m)
-{
- if (m->done)
- m->done (m->folder, m->uids, m->path, m->data);
-}
-
-static void
-save_messages_free (struct _save_messages_msg *m)
-{
- em_utils_uids_free (m->uids);
- g_object_unref (m->folder);
- g_free (m->path);
-}
-
-static MailMsgInfo save_messages_info = {
- sizeof (struct _save_messages_msg),
- (MailMsgDescFunc) save_messages_desc,
- (MailMsgExecFunc) save_messages_exec,
- (MailMsgDoneFunc) save_messages_done,
- (MailMsgFreeFunc) save_messages_free
-};
-
-gint
-mail_save_messages (CamelFolder *folder, GPtrArray *uids, const gchar *path,
- void (*done) (CamelFolder *folder, GPtrArray *uids, gchar *path, gpointer data), gpointer data)
-{
- struct _save_messages_msg *m;
- gint id;
-
- m = mail_msg_new (&save_messages_info);
- m->folder = folder;
- g_object_ref (folder);
- m->uids = uids;
- m->path = g_strdup (path);
- m->data = data;
- m->done = done;
-
- id = m->base.seq;
- mail_msg_unordered_push (m);
-
- return id;
-}
-
/* ** Execute Shell Command ***************************************************** */
void
diff --git a/mail/mail-ops.h b/mail/mail-ops.h
index 2d18b1a24f..520cae61ce 100644
--- a/mail/mail-ops.h
+++ b/mail/mail-ops.h
@@ -77,11 +77,6 @@ void mail_xfer_folder (const gchar *src_uri, const gchar *dest_uri, gboolean rem
CamelFolder *folder, gpointer data),
gpointer data);
-/* save messages */
-gint mail_save_messages (CamelFolder *folder, GPtrArray *uids, const gchar *path,
- void (*done) (CamelFolder *folder, GPtrArray *uids, gchar *path, gpointer data),
- gpointer data);
-
/* yeah so this is messy, but it does a lot, maybe i can consolidate all user_data's to be the one */
void mail_send_queue (EMailSession *session,
CamelFolder *queue,
diff --git a/mail/mail.error.xml b/mail/mail.error.xml
index 82767fca18..0fa46c726c 100644
--- a/mail/mail.error.xml
+++ b/mail/mail.error.xml
@@ -530,5 +530,10 @@ An mbox account will be created to preserve the old mbox folders. You can delete
<_secondary>The reported error was &quot;{0}&quot;.</_secondary>
</error>
+ <error id="save-messages" type="error">
+ <_primary>Failed to save messages to disk.</_primary>
+ <_secondary>The reported error was &quot;{0}&quot;.</_secondary>
+ </error>
+
</error-list>