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.
This commit is contained in:
Milan Crha
2017-12-07 14:35:45 +01:00
parent 0086baed2c
commit cebbf6fdfc
3 changed files with 158 additions and 122 deletions

View File

@ -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

View File

@ -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,

View File

@ -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);
} else {
gint n_messages = g_slist_length (messages);
g_object_unref (message);
goto exit;
}
messages = g_slist_reverse (messages);
/* Build a multipart/digest message out of the UIDs. */
/* 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);
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;
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);
g_object_unref (message);
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 (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");
}