[evolution-ews] Microsoft365: Implement raw MIME message upload
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews] Microsoft365: Implement raw MIME message upload
- Date: Wed, 5 Oct 2022 07:55:21 +0000 (UTC)
commit 394a1097e026f2d27fb3ad478a448281a6dcba12
Author: Milan Crha <mcrha redhat com>
Date: Wed Oct 5 09:51:50 2022 +0200
Microsoft365: Implement raw MIME message upload
The message is still marked as draft (isDraft flag) on the server.
There does not seem to be a way to unset it. There also does not work
upload to the specified folder, the server errors out, thus the code
uploads to the Drafts folder and then moves the message to the specified
folder. Maybe that plays its role with the isDraft flag as well.
src/Microsoft365/camel/camel-m365-folder.c | 28 ------------
src/Microsoft365/camel/camel-m365-utils.c | 54 +++++++++--------------
src/Microsoft365/common/e-m365-connection.c | 67 +++++++++++++++++++++++++++++
src/Microsoft365/common/e-m365-connection.h | 8 ++++
4 files changed, 95 insertions(+), 62 deletions(-)
---
diff --git a/src/Microsoft365/camel/camel-m365-folder.c b/src/Microsoft365/camel/camel-m365-folder.c
index 14a97604..8ff8ca52 100644
--- a/src/Microsoft365/camel/camel-m365-folder.c
+++ b/src/Microsoft365/camel/camel-m365-folder.c
@@ -574,29 +574,6 @@ m365_folder_append_message_sync (CamelFolder *folder,
GCancellable *cancellable,
GError **error)
{
- /* Cannot put existing messages from other providers, because:
- 1) those are always set as drafts
- 2) the set sentDateTime property is not respected
- 3) internetMessageHeaders is limited to 5! headers only:
- {
- "error": {
- "code": "InvalidInternetMessageHeaderCollection",
- "message": "Maximum number of headers in one message should be less than or equal to
5.",
- "innerError": {
- "date": "2020-07-01T10:03:34",
- "request-id": "a46da0ea-8933-43c6-932d-7c751f226516"
- }
- }
- }
- 4) there are likely to be more limitations on the graph API, not spotted yet.
-
- There is opened a feture request, which may eventually fix this, but it's currently not done yet
(as of 2020-07-01):
-
https://microsoftgraph.uservoice.com/forums/920506-microsoft-graph-feature-requests/suggestions/35049175-put-edit-mime-email-content-with-microsoft-graph
-
- Thus just error out for now.
- */
-
-#ifdef ENABLE_MAINTAINER_MODE /* Only for easier testing */
CamelStore *parent_store;
CamelM365Store *m365_store;
EM365Connection *cnc = NULL;
@@ -628,11 +605,6 @@ m365_folder_append_message_sync (CamelFolder *folder,
g_propagate_error (error, local_error);
return success;
-#else
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- _("Cannot add messages into a Microsoft 365 account from another account. Only messages from
the same account can be moved/copied between the Microsoft 365 folders."));
- return FALSE;
-#endif
}
static gboolean
diff --git a/src/Microsoft365/camel/camel-m365-utils.c b/src/Microsoft365/camel/camel-m365-utils.c
index ebe17e82..46e72cad 100644
--- a/src/Microsoft365/camel/camel-m365-utils.c
+++ b/src/Microsoft365/camel/camel-m365-utils.c
@@ -934,56 +934,42 @@ camel_m365_utils_create_message_sync (EM365Connection *cnc,
GError **error)
{
EM365MailMessage *appended_message = NULL;
- GSList *attachments = NULL;
- JsonBuilder *builder;
gboolean success;
g_return_val_if_fail (E_IS_M365_CONNECTION (cnc), FALSE);
g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
- builder = json_builder_new_immutable ();
-
- e_m365_json_begin_object_member (builder, NULL);
-
- if (!camel_m365_utils_fill_message_object_sync (builder, message, info, NULL, NULL, FALSE,
&attachments, cancellable, error)) {
- g_slist_free_full (attachments, g_object_unref);
- g_object_unref (builder);
-
- return FALSE;
- }
-
- e_m365_json_end_object_member (builder);
-
- success = e_m365_connection_create_mail_message_sync (cnc, NULL, folder_id, builder,
&appended_message, cancellable, error);
+ /* Cannot upload message directly to the folder_id, because the server returns:
+ {"error":{"code":"UnableToDeserializePostBody","message":"were unable to deserialize "}}
+ thus upload to the Drafts folder and then move the message to the right place. */
+ success = e_m365_connection_upload_mail_message_sync (cnc, NULL, NULL, message, &appended_message,
cancellable, error);
g_warn_if_fail ((success && appended_message) || (!success && !appended_message));
- g_object_unref (builder);
-
if (success && appended_message) {
- GSList *link;
- const gchar *message_id;
-
- message_id = e_m365_mail_message_get_id (appended_message);
-
- if (out_appended_id)
- *out_appended_id = g_strdup (message_id);
-
- for (link = attachments; link && success; link = g_slist_next (link)) {
- CamelDataWrapper *dw = link->data;
+ GSList src_ids = { 0, }, *des_ids = NULL;
+ const gchar *id;
- builder = json_builder_new_immutable ();
+ id = e_m365_mail_message_get_id (appended_message);
+ g_warn_if_fail (id != NULL);
- m365_utils_add_attachment_object (builder, dw, cancellable);
+ src_ids.next = NULL;
+ src_ids.data = (gpointer) id;
- success = e_m365_connection_add_mail_message_attachment_sync (cnc, NULL, message_id,
builder, NULL, cancellable, error);
+ /* Sadly, the isDraft flag cannot be unset, thus every uploaded message
+ is a draft for the server, which is quite bad */
+ if (e_m365_connection_copy_move_mail_messages_sync (cnc, NULL, &src_ids, folder_id, FALSE,
&des_ids, cancellable, error)) {
+ if (des_ids) {
+ if (out_appended_id)
+ *out_appended_id = g_strdup ((const gchar *) des_ids->data);
- g_object_unref (builder);
+ g_slist_free_full (des_ids, (GDestroyNotify) camel_pstring_free);
+ } else {
+ g_warning ("Moved message to '%s', but did not return new message id",
folder_id);
+ }
}
}
- g_slist_free_full (attachments, g_object_unref);
-
if (appended_message)
json_object_unref (appended_message);
diff --git a/src/Microsoft365/common/e-m365-connection.c b/src/Microsoft365/common/e-m365-connection.c
index cb7c6093..fc5e7083 100644
--- a/src/Microsoft365/common/e-m365-connection.c
+++ b/src/Microsoft365/common/e-m365-connection.c
@@ -2511,6 +2511,73 @@ e_m365_connection_create_mail_message_sync (EM365Connection *cnc,
return success;
}
+gboolean
+e_m365_connection_upload_mail_message_sync (EM365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *folder_id, /* if NULL, then goes to the Drafts
folder */
+ CamelMimeMessage *mime_message,
+ EM365MailMessage **out_created_message, /* free with
json_object_unref() */
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message;
+ GInputStream *input_stream;
+ CamelStream *mem_stream, *filter_stream;
+ CamelMimeFilter *base64_filter;
+ GByteArray *byte_array;
+ gboolean success;
+ gchar *uri;
+
+ g_return_val_if_fail (E_IS_M365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (mime_message), FALSE);
+ g_return_val_if_fail (out_created_message != NULL, FALSE);
+
+ uri = e_m365_connection_construct_uri (cnc, TRUE, user_override, E_M365_API_V1_0, NULL,
+ folder_id ? "mailFolders" : "messages",
+ folder_id,
+ folder_id ? "messages" : NULL,
+ NULL);
+
+ message = m365_connection_new_soup_message (SOUP_METHOD_POST, uri, CSM_DEFAULT, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ mem_stream = camel_stream_mem_new ();
+ filter_stream = camel_stream_filter_new (mem_stream);
+ base64_filter = camel_mime_filter_basic_new (CAMEL_MIME_FILTER_BASIC_BASE64_ENC);
+ camel_stream_filter_add (CAMEL_STREAM_FILTER (filter_stream), base64_filter);
+ g_clear_object (&base64_filter);
+
+ if (camel_data_wrapper_write_to_stream_sync (CAMEL_DATA_WRAPPER (mime_message), filter_stream,
cancellable, error) == -1) {
+ g_clear_object (&filter_stream);
+ g_clear_object (&mem_stream);
+ g_clear_object (&message);
+
+ return FALSE;
+ }
+
+ byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (mem_stream));
+
+ input_stream = g_memory_input_stream_new_from_data (byte_array->data, byte_array->len, NULL);
+
+ e_soup_session_util_set_message_request_body (message, "text/plain", input_stream, byte_array->len);
+
+ success = m365_connection_send_request_sync (cnc, message, e_m365_read_json_object_response_cb, NULL,
out_created_message, cancellable, error);
+
+ g_clear_object (&input_stream);
+ g_clear_object (&filter_stream);
+ g_clear_object (&mem_stream);
+ g_clear_object (&message);
+
+ return success;
+}
+
/* https://docs.microsoft.com/en-us/graph/api/message-post-attachments?view=graph-rest-1.0&tabs=http */
gboolean
diff --git a/src/Microsoft365/common/e-m365-connection.h b/src/Microsoft365/common/e-m365-connection.h
index 33fb831c..8ee1c2b0 100644
--- a/src/Microsoft365/common/e-m365-connection.h
+++ b/src/Microsoft365/common/e-m365-connection.h
@@ -247,6 +247,14 @@ gboolean e_m365_connection_create_mail_message_sync
EM365MailMessage **out_created_message, /* free with
json_object_unref() */
GCancellable *cancellable,
GError **error);
+gboolean e_m365_connection_upload_mail_message_sync
+ (EM365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *folder_id, /* if NULL, then goes to the Drafts
folder */
+ CamelMimeMessage *mime_message,
+ EM365MailMessage **out_created_message, /* free with
json_object_unref() */
+ GCancellable *cancellable,
+ GError **error);
gboolean e_m365_connection_add_mail_message_attachment_sync
(EM365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use
the account user */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]