[evolution/gnome-3-26] Drag&drop of multiple messages from message list to composer fails



commit e7d4bb14f767d3c0f8d11d3053bdd60422250f48
Author: Milan Crha <mcrha redhat com>
Date:   Thu Dec 7 14:38:57 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 3c37e43..ba2ff30 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.26.3
  **/
 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]