[evolution] Drag&drop of multiple messages from message list to composer fails
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] Drag&drop of multiple messages from message list to composer fails
- Date: Thu, 7 Dec 2017 13:36:43 +0000 (UTC)
commit cebbf6fdfcc7eb58aa8db7d3274b2e463058d592
Author: Milan Crha <mcrha redhat com>
Date: Thu Dec 7 14:35:45 2017 +0100
Drag&drop of multiple messages from message list to composer fails
One message works fine, but multiple messages failed due to changed
format of x-uid-list content.
src/mail/em-utils.c | 82 +++++++++--
src/mail/em-utils.h | 14 ++
src/modules/mail/e-mail-attachment-handler.c | 190 +++++++++++---------------
3 files changed, 161 insertions(+), 125 deletions(-)
---
diff --git a/src/mail/em-utils.c b/src/mail/em-utils.c
index 0d6edb4..bab5a9c 100644
--- a/src/mail/em-utils.c
+++ b/src/mail/em-utils.c
@@ -742,22 +742,27 @@ em_utils_selection_set_uidlist (GtkSelectionData *selection_data,
}
/**
- * em_utils_selection_get_uidlist:
- * @data: selection data
+ * em_utils_selection_uidlist_foreach_sync:
+ * @selection_data: a #GtkSelectionData with x-uid-list content
* @session: an #EMailSession
- * @move: do we delete the messages.
+ * @func: a function to call for each UID and its folder
+ * @user_data: user data for @func
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
*
- * Convert a uid list into a copy/move operation.
+ * Calls @func for each folder and UID provided in @selection_data.
*
* Warning: Could take some time to run.
+ *
+ * Since: 3.28
**/
void
-em_utils_selection_get_uidlist (GtkSelectionData *selection_data,
- EMailSession *session,
- CamelFolder *dest,
- gint move,
- GCancellable *cancellable,
- GError **error)
+em_utils_selection_uidlist_foreach_sync (GtkSelectionData *selection_data,
+ EMailSession *session,
+ EMUtilsUIDListFunc func,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
{
/* format: "uri1\0uid1\0uri2\0uid2\0...\0urin\0uidn\0" */
gchar *inptr, *inend;
@@ -768,10 +773,12 @@ em_utils_selection_get_uidlist (GtkSelectionData *selection_data,
GHashTable *uids_by_uri;
GHashTableIter iter;
gpointer key, value;
+ gboolean can_continue = TRUE;
GError *local_error = NULL;
g_return_if_fail (selection_data != NULL);
g_return_if_fail (E_IS_MAIL_SESSION (session));
+ g_return_if_fail (func != NULL);
data = gtk_selection_data_get_data (selection_data);
length = gtk_selection_data_get_length (selection_data);
@@ -823,14 +830,12 @@ em_utils_selection_get_uidlist (GtkSelectionData *selection_data,
const gchar *uri = key;
GPtrArray *uids = value;
- if (!local_error) {
+ if (!local_error && can_continue) {
/* FIXME e_mail_session_uri_to_folder_sync() may block. */
folder = e_mail_session_uri_to_folder_sync (
session, uri, 0, cancellable, &local_error);
if (folder) {
- /* FIXME camel_folder_transfer_messages_to_sync() may block. */
- camel_folder_transfer_messages_to_sync (
- folder, uids, dest, move, NULL, cancellable, &local_error);
+ can_continue = func (folder, uids, user_data, cancellable, &local_error);
g_object_unref (folder);
}
}
@@ -845,6 +850,55 @@ em_utils_selection_get_uidlist (GtkSelectionData *selection_data,
g_propagate_error (error, local_error);
}
+struct UIDListData {
+ CamelFolder *dest;
+ gboolean move;
+};
+
+static gboolean
+uidlist_move_uids_cb (CamelFolder *folder,
+ const GPtrArray *uids,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct UIDListData *uld = user_data;
+
+ g_return_val_if_fail (uld != NULL, FALSE);
+
+ /* FIXME camel_folder_transfer_messages_to_sync() may block. */
+ return camel_folder_transfer_messages_to_sync (
+ folder, (GPtrArray *) uids, uld->dest, uld->move, NULL, cancellable, error);
+}
+
+/**
+ * em_utils_selection_get_uidlist:
+ * @data: selection data
+ * @session: an #EMailSession
+ * @move: do we delete the messages.
+ *
+ * Convert a uid list into a copy/move operation.
+ *
+ * Warning: Could take some time to run.
+ **/
+void
+em_utils_selection_get_uidlist (GtkSelectionData *selection_data,
+ EMailSession *session,
+ CamelFolder *dest,
+ gint move,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct UIDListData uld;
+
+ g_return_if_fail (CAMEL_IS_FOLDER (dest));
+
+ uld.dest = dest;
+ uld.move = move;
+
+ em_utils_selection_uidlist_foreach_sync (selection_data, session, uidlist_move_uids_cb, &uld,
cancellable, error);
+}
+
/**
* em_utils_build_export_basename:
* @folder: a #CamelFolder where the message belongs
diff --git a/src/mail/em-utils.h b/src/mail/em-utils.h
index 6a0787c..d415659 100644
--- a/src/mail/em-utils.h
+++ b/src/mail/em-utils.h
@@ -57,6 +57,20 @@ void em_utils_selection_get_uidlist (GtkSelectionData *data, EMailSession *sessi
void em_utils_selection_set_urilist (GtkSelectionData *data, CamelFolder *folder, GPtrArray *uids);
void em_utils_selection_get_urilist (GtkSelectionData *data, CamelFolder *folder);
+/* Return TRUE to continue, FALSE to stop further processing */
+typedef gboolean (* EMUtilsUIDListFunc) (CamelFolder *folder,
+ const GPtrArray *uids,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error);
+
+void em_utils_selection_uidlist_foreach_sync (GtkSelectionData *selection_data,
+ EMailSession *session,
+ EMUtilsUIDListFunc func,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error);
+
/* FIXME: should this have an override charset? */
gchar * em_utils_message_to_html (CamelSession *session,
CamelMimeMessage *msg,
diff --git a/src/modules/mail/e-mail-attachment-handler.c b/src/modules/mail/e-mail-attachment-handler.c
index e0825e3..a035434 100644
--- a/src/modules/mail/e-mail-attachment-handler.c
+++ b/src/modules/mail/e-mail-attachment-handler.c
@@ -27,6 +27,7 @@
#include "mail/e-mail-backend.h"
#include "mail/e-mail-reader.h"
#include "mail/em-composer-utils.h"
+#include "mail/em-utils.h"
#define E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -533,6 +534,33 @@ exit:
gtk_drag_finish (drag_context, success, FALSE, time);
}
+static gboolean
+gather_x_uid_list_messages_cb (CamelFolder *folder,
+ const GPtrArray *uids,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GSList **pmessages = user_data;
+ guint ii;
+
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+ g_return_val_if_fail (uids != NULL, FALSE);
+ g_return_val_if_fail (pmessages != NULL, FALSE);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ CamelMimeMessage *message;
+
+ message = camel_folder_get_message_sync (folder, uids->pdata[ii], cancellable, error);
+ if (!message)
+ return FALSE;
+
+ *pmessages = g_slist_prepend (*pmessages, message);
+ }
+
+ return TRUE;
+}
+
static void
mail_attachment_handler_x_uid_list (EAttachmentView *view,
GdkDragContext *drag_context,
@@ -546,20 +574,14 @@ mail_attachment_handler_x_uid_list (EAttachmentView *view,
static GdkAtom atom = GDK_NONE;
EMailAttachmentHandlerPrivate *priv;
CamelDataWrapper *wrapper;
- CamelMimeMessage *message;
CamelMultipart *multipart;
CamelMimePart *mime_part;
- CamelFolder *folder = NULL;
EAttachment *attachment;
EAttachmentStore *store;
EMailSession *session;
- GPtrArray *uids;
- const gchar *data;
- const gchar *cp, *end;
+ GSList *messages = NULL, *link;
gchar *description;
gpointer parent;
- gint length;
- guint ii;
GError *local_error = NULL;
if (G_UNLIKELY (atom == GDK_NONE))
@@ -574,124 +596,73 @@ mail_attachment_handler_x_uid_list (EAttachmentView *view,
parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
- uids = g_ptr_array_new ();
-
- data = (const gchar *) gtk_selection_data_get_data (selection_data);
- length = gtk_selection_data_get_length (selection_data);
-
- /* The UID list is delimited by NUL characters.
- * Brilliant. So we can't use g_strsplit(). */
-
- cp = data;
- end = data + length;
-
- while (cp < end) {
- const gchar *start = cp;
-
- while (cp < end && *cp != '\0')
- cp++;
-
- /* Skip the first string. */
- if (start > data)
- g_ptr_array_add (uids, g_strndup (start, cp - start));
-
- cp++;
- }
-
- if (uids->len == 0)
- goto exit;
-
session = e_mail_backend_get_session (priv->backend);
- /* The first string is the folder URI. */
- /* FIXME Not passing a GCancellable here. */
- folder = e_mail_session_uri_to_folder_sync (
- session, data, 0, NULL, &local_error);
- if (folder == NULL)
+ em_utils_selection_uidlist_foreach_sync (selection_data, session,
+ gather_x_uid_list_messages_cb, &messages, NULL, &local_error);
+
+ if (local_error || !messages)
goto exit;
/* Handle one message. */
- if (uids->len == 1) {
- const gchar *message_uid;
-
- message_uid = g_ptr_array_index (uids, 0);
-
- /* FIXME Not passing a GCancellable here. */
- message = camel_folder_get_message_sync (
- folder, message_uid, NULL, &local_error);
- if (message == NULL)
- goto exit;
-
- attachment = e_attachment_new_for_message (message);
+ if (!messages->next) {
+ attachment = e_attachment_new_for_message (messages->data);
e_attachment_store_add_attachment (store, attachment);
e_attachment_load_async (
attachment, (GAsyncReadyCallback)
call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL);
g_object_unref (attachment);
-
- g_object_unref (message);
- goto exit;
- }
-
- /* Build a multipart/digest message out of the UIDs. */
-
- multipart = camel_multipart_new ();
- wrapper = CAMEL_DATA_WRAPPER (multipart);
- camel_data_wrapper_set_mime_type (wrapper, "multipart/digest");
- camel_multipart_set_boundary (multipart, NULL);
-
- for (ii = 0; ii < uids->len; ii++) {
- /* FIXME Not passing a GCancellable here. */
- message = camel_folder_get_message_sync (
- folder, uids->pdata[ii], NULL, &local_error);
- if (message == NULL) {
- g_object_unref (multipart);
- goto exit;
+ } else {
+ gint n_messages = g_slist_length (messages);
+
+ messages = g_slist_reverse (messages);
+
+ /* Build a multipart/digest message out of the UIDs. */
+ multipart = camel_multipart_new ();
+ wrapper = CAMEL_DATA_WRAPPER (multipart);
+ camel_data_wrapper_set_mime_type (wrapper, "multipart/digest");
+ camel_multipart_set_boundary (multipart, NULL);
+
+ for (link = messages; link; link = g_slist_next (link)) {
+ mime_part = camel_mime_part_new ();
+ wrapper = CAMEL_DATA_WRAPPER (link->data);
+ camel_mime_part_set_disposition (mime_part, "inline");
+ camel_medium_set_content (
+ CAMEL_MEDIUM (mime_part), wrapper);
+ camel_mime_part_set_content_type (mime_part, "message/rfc822");
+ camel_multipart_add_part (multipart, mime_part);
+ g_object_unref (mime_part);
}
mime_part = camel_mime_part_new ();
- wrapper = CAMEL_DATA_WRAPPER (message);
- camel_mime_part_set_disposition (mime_part, "inline");
- camel_medium_set_content (
- CAMEL_MEDIUM (mime_part), wrapper);
- camel_mime_part_set_content_type (mime_part, "message/rfc822");
- camel_multipart_add_part (multipart, mime_part);
- g_object_unref (mime_part);
+ wrapper = CAMEL_DATA_WRAPPER (multipart);
+ camel_medium_set_content (CAMEL_MEDIUM (mime_part), wrapper);
+
+ description = g_strdup_printf (
+ ngettext (
+ "%d attached message",
+ "%d attached messages",
+ n_messages),
+ n_messages);
+ camel_mime_part_set_description (mime_part, description);
+ g_free (description);
+
+ attachment = e_attachment_new ();
+ e_attachment_set_mime_part (attachment, mime_part);
+ e_attachment_store_add_attachment (store, attachment);
+ e_attachment_load_async (
+ attachment, (GAsyncReadyCallback)
+ call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL);
+ g_object_unref (attachment);
- g_object_unref (message);
+ g_object_unref (mime_part);
+ g_object_unref (multipart);
}
- mime_part = camel_mime_part_new ();
- wrapper = CAMEL_DATA_WRAPPER (multipart);
- camel_medium_set_content (CAMEL_MEDIUM (mime_part), wrapper);
-
- description = g_strdup_printf (
- ngettext (
- "%d attached message",
- "%d attached messages",
- uids->len),
- uids->len);
- camel_mime_part_set_description (mime_part, description);
- g_free (description);
-
- attachment = e_attachment_new ();
- e_attachment_set_mime_part (attachment, mime_part);
- e_attachment_store_add_attachment (store, attachment);
- e_attachment_load_async (
- attachment, (GAsyncReadyCallback)
- call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL);
- g_object_unref (attachment);
-
- g_object_unref (mime_part);
- g_object_unref (multipart);
-
-exit:
+ exit:
if (local_error != NULL) {
- const gchar *folder_name = data;
-
- if (folder != NULL)
- folder_name = camel_folder_get_display_name (folder);
+ const gchar *folder_name = (const gchar *) gtk_selection_data_get_data (selection_data);
e_alert_run_dialog_for_args (
parent, "mail-composer:attach-nomessages",
@@ -700,10 +671,7 @@ exit:
g_clear_error (&local_error);
}
- if (folder != NULL)
- g_object_unref (folder);
-
- g_ptr_array_free (uids, TRUE);
+ g_slist_free_full (messages, g_object_unref);
g_signal_stop_emission_by_name (view, "drag-data-received");
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]