[evolution-ews] I#90 - Handle share folder invitation mails



commit a2d3cdf803cde27069ccffc6d19a585543c14ff1
Author: Milan Crha <mcrha redhat com>
Date:   Tue Sep 29 14:07:48 2020 +0200

    I#90 - Handle share folder invitation mails
    
    Closes https://gitlab.gnome.org/GNOME/evolution-ews/-/issues/90

 src/EWS/common/e-ews-connection.c                  | 167 ++++++++++++++
 src/EWS/common/e-ews-connection.h                  |  23 ++
 src/EWS/evolution/CMakeLists.txt                   |   8 +
 src/EWS/evolution/e-ews-subscribe-foreign-folder.c | 242 ++++++++++++---------
 src/EWS/evolution/e-ews-subscribe-foreign-folder.h |  33 ++-
 .../e-mail-formatter-ews-sharing-metadata.c        | 223 +++++++++++++++++++
 .../e-mail-formatter-ews-sharing-metadata.h        |  18 ++
 .../evolution/e-mail-parser-ews-multipart-mixed.c  | 103 +++++++++
 .../evolution/e-mail-parser-ews-multipart-mixed.h  |  18 ++
 .../evolution/e-mail-parser-ews-sharing-metadata.c | 123 +++++++++++
 .../evolution/e-mail-parser-ews-sharing-metadata.h |  23 ++
 .../evolution/e-mail-part-ews-sharing-metadata.c   | 233 ++++++++++++++++++++
 .../evolution/e-mail-part-ews-sharing-metadata.h   |  54 +++++
 src/EWS/evolution/module-ews-configuration.c       |   8 +
 .../evolution/module-ews-configuration.error.xml   |  10 +
 15 files changed, 1178 insertions(+), 108 deletions(-)
---
diff --git a/src/EWS/common/e-ews-connection.c b/src/EWS/common/e-ews-connection.c
index 1d318068..464e2ad7 100644
--- a/src/EWS/common/e-ews-connection.c
+++ b/src/EWS/common/e-ews-connection.c
@@ -11771,3 +11771,170 @@ e_ews_connection_get_user_configuration_sync (EEwsConnection *cnc,
 
        return success;
 }
+
+static void
+convert_id_response_cb (ESoapResponse *response,
+                       GSimpleAsyncResult *simple)
+{
+       EwsAsyncData *async_data;
+       ESoapParameter *param;
+       GError *error = NULL;
+
+       async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+       param = e_soap_response_get_first_parameter_by_name (response, "ResponseMessages", &error);
+
+       if (param) {
+               param = e_soap_parameter_get_first_child_by_name (param, "ConvertIdResponseMessage");
+               if (!param) {
+                       g_set_error (&error,
+                               SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED,
+                               "Missing <%s> in SOAP response", "ConvertIdResponseMessage");
+               }
+       }
+
+       if (param) {
+               param = e_soap_parameter_get_first_child_by_name (param, "AlternateId");
+               if (!param) {
+                       g_set_error (&error,
+                               SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED,
+                               "Missing <%s> in SOAP response", "AlternateId");
+               }
+       }
+
+       /* Sanity check */
+       g_return_if_fail (
+               (param != NULL && error == NULL) ||
+               (param == NULL && error != NULL));
+
+       if (error != NULL) {
+               g_simple_async_result_take_error (simple, error);
+               return;
+       }
+
+       async_data->custom_data = e_soap_parameter_get_property (param, "Id");
+}
+
+void
+e_ews_connection_convert_id (EEwsConnection *cnc,
+                            gint pri,
+                            const gchar *email,
+                            const gchar *folder_id,
+                            const gchar *from_format,
+                            const gchar *to_format,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
+{
+       ESoapMessage *msg;
+       GSimpleAsyncResult *simple;
+       EwsAsyncData *async_data;
+
+       g_return_if_fail (cnc != NULL);
+       g_return_if_fail (cnc->priv != NULL);
+       g_return_if_fail (email != NULL);
+       g_return_if_fail (folder_id != NULL);
+       g_return_if_fail (from_format != NULL);
+       g_return_if_fail (to_format != NULL);
+
+       simple = g_simple_async_result_new (G_OBJECT (cnc), callback, user_data, e_ews_connection_convert_id);
+       async_data = g_slice_new0 (EwsAsyncData);
+       g_simple_async_result_set_op_res_gpointer (simple, async_data, (GDestroyNotify) async_data_free);
+
+       /* EWS server version earlier than 2007 SP1 doesn't support it. */
+       if (!e_ews_connection_satisfies_server_version (cnc, E_EWS_EXCHANGE_2007_SP1)) {
+               g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR, "%s", _("Requires at least 
Microsoft Exchange 2007 SP1 server"));
+               g_simple_async_result_complete_in_idle (simple);
+               g_object_unref (simple);
+               return;
+       }
+
+       msg = e_ews_message_new_with_header (
+               cnc->priv->settings,
+               cnc->priv->uri,
+               cnc->priv->impersonate_user,
+               "ConvertId",
+               "DestinationFormat",
+               to_format,
+               cnc->priv->version,
+               E_EWS_EXCHANGE_2007_SP1,
+               FALSE,
+               TRUE);
+
+       e_soap_message_start_element (msg, "SourceIds", "messages", NULL);
+       e_soap_message_start_element (msg, "AlternateId", NULL, NULL);
+
+       e_soap_message_add_attribute (msg, "Id", folder_id, NULL, NULL);
+       e_soap_message_add_attribute (msg, "Format", from_format, NULL, NULL);
+       e_soap_message_add_attribute (msg, "Mailbox", email, NULL, NULL);
+
+       e_soap_message_end_element (msg); /* AlternateId */
+       e_soap_message_end_element (msg); /* SourceIds */
+
+       e_ews_message_write_footer (msg);
+
+       e_ews_connection_queue_request (cnc, msg, convert_id_response_cb, pri, cancellable, simple);
+
+       g_object_unref (simple);
+}
+
+gboolean
+e_ews_connection_convert_id_finish (EEwsConnection *cnc,
+                                   GAsyncResult *result,
+                                   gchar **out_converted_id,
+                                   GError **error)
+{
+       GSimpleAsyncResult *simple;
+       EwsAsyncData *async_data;
+
+       g_return_val_if_fail (cnc != NULL, FALSE);
+       g_return_val_if_fail (
+               g_simple_async_result_is_valid (result, G_OBJECT (cnc), e_ews_connection_convert_id),
+               FALSE);
+       g_return_val_if_fail (out_converted_id != NULL, FALSE);
+
+       simple = G_SIMPLE_ASYNC_RESULT (result);
+       async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+       if (g_simple_async_result_propagate_error (simple, error))
+               return FALSE;
+
+       if (!async_data->custom_data)
+               return FALSE;
+
+       *out_converted_id = async_data->custom_data;
+       async_data->custom_data = NULL;
+
+       return TRUE;
+}
+
+gboolean
+e_ews_connection_convert_id_sync (EEwsConnection *cnc,
+                                 gint pri,
+                                 const gchar *email,
+                                 const gchar *folder_id,
+                                 const gchar *from_format,
+                                 const gchar *to_format,
+                                 gchar **out_converted_id,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       EAsyncClosure *closure;
+       GAsyncResult *result;
+       gboolean success;
+
+       g_return_val_if_fail (cnc != NULL, FALSE);
+
+       closure = e_async_closure_new ();
+
+       e_ews_connection_convert_id (
+               cnc, pri, email, folder_id, from_format, to_format, cancellable, e_async_closure_callback, 
closure);
+
+       result = e_async_closure_wait (closure);
+
+       success = e_ews_connection_convert_id_finish (cnc, result, out_converted_id, error);
+
+       e_async_closure_free (closure);
+
+       return success;
+}
diff --git a/src/EWS/common/e-ews-connection.h b/src/EWS/common/e-ews-connection.h
index 3ad44bea..3e2b2785 100644
--- a/src/EWS/common/e-ews-connection.h
+++ b/src/EWS/common/e-ews-connection.h
@@ -1398,6 +1398,29 @@ gboolean e_ews_connection_get_user_configuration_sync
                                                 gchar **out_properties,
                                                 GCancellable *cancellable,
                                                 GError **error);
+void           e_ews_connection_convert_id     (EEwsConnection *cnc,
+                                                gint pri,
+                                                const gchar *email,
+                                                const gchar *folder_id,
+                                                const gchar *from_format,
+                                                const gchar *to_format,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_ews_connection_convert_id_finish
+                                               (EEwsConnection *cnc,
+                                                GAsyncResult *result,
+                                                gchar **out_converted_id,
+                                                GError **error);
+gboolean       e_ews_connection_convert_id_sync(EEwsConnection *cnc,
+                                                gint pri,
+                                                const gchar *email,
+                                                const gchar *folder_id,
+                                                const gchar *from_format,
+                                                const gchar *to_format,
+                                                gchar **out_converted_id,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
 G_END_DECLS
 
diff --git a/src/EWS/evolution/CMakeLists.txt b/src/EWS/evolution/CMakeLists.txt
index 76779bb9..70f65bde 100644
--- a/src/EWS/evolution/CMakeLists.txt
+++ b/src/EWS/evolution/CMakeLists.txt
@@ -27,6 +27,14 @@ set(sources
        e-mail-config-ews-offline-options.h
        e-mail-config-ews-ooo-page.c
        e-mail-config-ews-ooo-page.h
+       e-mail-formatter-ews-sharing-metadata.c
+       e-mail-formatter-ews-sharing-metadata.h
+       e-mail-parser-ews-multipart-mixed.c
+       e-mail-parser-ews-multipart-mixed.h
+       e-mail-parser-ews-sharing-metadata.c
+       e-mail-parser-ews-sharing-metadata.h
+       e-mail-part-ews-sharing-metadata.c
+       e-mail-part-ews-sharing-metadata.h
        e-ews-config-lookup.c
        e-ews-config-lookup.h
        e-ews-config-ui-extension.c
diff --git a/src/EWS/evolution/e-ews-subscribe-foreign-folder.c 
b/src/EWS/evolution/e-ews-subscribe-foreign-folder.c
index 5204d54e..09c3ae13 100644
--- a/src/EWS/evolution/e-ews-subscribe-foreign-folder.c
+++ b/src/EWS/evolution/e-ews-subscribe-foreign-folder.c
@@ -271,62 +271,11 @@ check_foreign_folder_thread (GObject *with_object,
                cffd->user_displayname = cffd->email;
                cffd->email = g_strdup (cffd->direct_email);
        } else {
-               GSList *mailboxes = NULL;
-               EwsMailbox *mailbox = NULL;
-               gboolean includes_last_item = FALSE;
-
-               if (!e_ews_connection_resolve_names_sync (conn, G_PRIORITY_DEFAULT,
-                       cffd->email, EWS_SEARCH_AD, NULL, FALSE,
-                       &mailboxes, NULL, &includes_last_item,
-                       cancellable, &local_error)) {
-                       if (g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_NAMERESOLUTIONNORESULTS) ||
-                           g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_NAMERESOLUTIONNOMAILBOX)) {
-                               g_clear_error (&local_error);
-                               mailboxes = NULL;
-                       } else {
-                               if (local_error)
-                                       g_propagate_error (perror, local_error);
-                               g_object_unref (conn);
-                               return;
-                       }
-               }
-
-               if (mailboxes) {
-                       /* is there only one result? */
-                       if (!mailboxes->next) {
-                               mailbox = mailboxes->data;
-                       } else {
-                               GSList *iter;
-
-                               for (iter = mailboxes; iter; iter = iter->next) {
-                                       EwsMailbox *mb = iter->data;
-
-                                       if (!mb)
-                                               continue;
-
-                                       if (mb->name && g_utf8_collate (mb->name, cffd->email) == 0) {
-                                               mailbox = mb;
-                                               break;
-                                       }
-                               }
-                       }
-
-                       if (mailbox) {
-                               g_free (cffd->user_displayname);
-                               cffd->user_displayname = g_strdup (mailbox->name);
-                               g_free (cffd->email);
-                               cffd->email = g_strdup (mailbox->email);
-                       }
+               gchar *display_name = NULL, *email_address = NULL;
 
-                       g_slist_free_full (mailboxes, (GDestroyNotify) e_ews_mailbox_free);
-
-                       if (!mailbox) {
-                               g_set_error (
-                                       perror, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_ITEMNOTFOUND,
-                                       _("User name “%s” is ambiguous, specify it more precisely, please"), 
cffd->email);
-                               g_object_unref (conn);
-                               return;
-                       }
+               if (!e_ews_subscribe_foreign_folder_resolve_name_sync (conn, cffd->email, &display_name, 
&email_address, cancellable, perror)) {
+                       g_object_unref (conn);
+                       return;
                }
        }
 
@@ -418,14 +367,6 @@ check_foreign_folder_idle (GObject *with_object,
                            GError **perror)
 {
        struct EEwsCheckForeignFolderData *cffd = user_data;
-       gchar *folder_name;
-       const gchar *base_username, *base_foldername;
-       CamelSettings *settings;
-       CamelEwsSettings *ews_settings;
-       CamelEwsStore *ews_store;
-       ESourceRegistry *registry = NULL;
-       CamelSession *session;
-       EEwsFolderType folder_type;
 
        g_return_if_fail (with_object != NULL);
        g_return_if_fail (CAMEL_IS_EWS_STORE (with_object));
@@ -435,51 +376,13 @@ check_foreign_folder_idle (GObject *with_object,
        if (!cffd->folder)
                return;
 
-       folder_type = e_ews_folder_get_folder_type (cffd->folder);
-       base_username = cffd->user_displayname ? cffd->user_displayname : cffd->email;
-       base_foldername = e_ews_folder_get_name (cffd->folder) ? e_ews_folder_get_name (cffd->folder) : 
cffd->orig_foldername;
-
-       /* Translators: This is used to name foreign folder.
-        * The first '%s' is replaced with user name to whom the folder belongs,
-        * the second '%s' is replaced with folder name.
-        * Example result: "John Smith — Calendar"
-       */
-       folder_name = g_strdup_printf (C_("ForeignFolder", "%s — %s"), base_username, base_foldername);
-       if (folder_type != E_EWS_FOLDER_TYPE_MAILBOX)
-               e_ews_folder_set_name (cffd->folder, folder_name);
-
-       ews_store = CAMEL_EWS_STORE (with_object);
-       settings = camel_service_ref_settings (CAMEL_SERVICE (ews_store));
-       ews_settings = CAMEL_EWS_SETTINGS (settings);
-       session = camel_service_ref_session (CAMEL_SERVICE (ews_store));
-       if (E_IS_MAIL_SESSION (session))
-               registry = e_mail_session_get_registry (E_MAIL_SESSION (session));
-
-       if ((folder_type == E_EWS_FOLDER_TYPE_MAILBOX &&
-            !add_foreign_folder_to_camel (ews_store,
-               cffd->email,
-               cffd->folder,
-               cffd->include_subfolders,
-               base_username,
-               base_foldername,
-               perror)) ||
-           (folder_type != E_EWS_FOLDER_TYPE_MAILBOX && !e_ews_folder_utils_add_as_esource (registry,
-               camel_ews_settings_get_hosturl (ews_settings),
-               camel_network_settings_get_user (CAMEL_NETWORK_SETTINGS (ews_settings)),
-               cffd->folder,
-               (cffd->include_subfolders ? E_EWS_ESOURCE_FLAG_INCLUDE_SUBFOLDERS : 0) | 
E_EWS_ESOURCE_FLAG_OFFLINE_SYNC,
-               0,
-               cancellable,
-               perror))
-       ) {
+       if (!e_ews_subscrive_foreign_folder_subscribe_sync (CAMEL_EWS_STORE (with_object),
+               cffd->folder, cffd->user_displayname, cffd->email, cffd->orig_foldername,
+               cffd->include_subfolders, cancellable, perror)) {
                /* to not destroy the dialog on error */
                g_object_unref (cffd->folder);
                cffd->folder = NULL;
        }
-
-       g_free (folder_name);
-       g_object_unref (session);
-       g_object_unref (settings);
 }
 
 static gpointer
@@ -875,3 +778,134 @@ e_ews_subscribe_foreign_folder (GtkWindow *parent,
        gtk_widget_show_all (content);
        gtk_widget_show (GTK_WIDGET (dialog));
 }
+
+gboolean
+e_ews_subscribe_foreign_folder_resolve_name_sync (EEwsConnection *cnc,
+                                                 const gchar *name,
+                                                 gchar **out_display_name,
+                                                 gchar **out_email_address,
+                                                 GCancellable *cancellable,
+                                                 GError **error)
+{
+       GSList *mailboxes = NULL;
+       EwsMailbox *mailbox = NULL;
+       gboolean includes_last_item = FALSE;
+       GError *local_error = NULL;
+
+       if (!e_ews_connection_resolve_names_sync (cnc, G_PRIORITY_DEFAULT,
+               name, EWS_SEARCH_AD, NULL, FALSE,
+               &mailboxes, NULL, &includes_last_item,
+               cancellable, &local_error)) {
+               if (g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_NAMERESOLUTIONNORESULTS) ||
+                   g_error_matches (local_error, EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_NAMERESOLUTIONNOMAILBOX)) {
+                       g_clear_error (&local_error);
+                       mailboxes = NULL;
+               } else {
+                       if (local_error)
+                               g_propagate_error (error, local_error);
+                       return FALSE;
+               }
+       }
+
+       if (mailboxes) {
+               /* is there only one result? */
+               if (!mailboxes->next) {
+                       mailbox = mailboxes->data;
+               } else {
+                       GSList *iter;
+
+                       for (iter = mailboxes; iter; iter = iter->next) {
+                               EwsMailbox *mb = iter->data;
+
+                               if (!mb)
+                                       continue;
+
+                               if (mb->name && g_utf8_collate (mb->name, name) == 0) {
+                                       mailbox = mb;
+                                       break;
+                               }
+                       }
+               }
+
+               if (mailbox) {
+                       if (out_display_name)
+                               *out_display_name = g_strdup (mailbox->name);
+
+                       if (out_email_address)
+                               *out_email_address = g_strdup (mailbox->email);
+               }
+
+               g_slist_free_full (mailboxes, (GDestroyNotify) e_ews_mailbox_free);
+
+               if (!mailbox) {
+                       g_set_error (
+                               error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_ITEMNOTFOUND,
+                               _("User name “%s” is ambiguous, specify it more precisely, please"), name);
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+gboolean
+e_ews_subscrive_foreign_folder_subscribe_sync (CamelEwsStore *ews_store,
+                                              EEwsFolder *folder,
+                                              const gchar *user_display_name,
+                                              const gchar *user_email,
+                                              const gchar *fallback_folder_name,
+                                              gboolean include_subfolders,
+                                              GCancellable *cancellable,
+                                              GError **error)
+{
+       gchar *folder_name;
+       const gchar *base_username, *base_foldername;
+       CamelSettings *settings;
+       CamelEwsSettings *ews_settings;
+       ESourceRegistry *registry = NULL;
+       CamelSession *session;
+       EEwsFolderType folder_type;
+       gboolean success;
+
+       folder_type = e_ews_folder_get_folder_type (folder);
+       base_username = user_display_name ? user_display_name : user_email;
+       base_foldername = e_ews_folder_get_name (folder) ? e_ews_folder_get_name (folder) : 
fallback_folder_name;
+
+       /* Translators: This is used to name foreign folder.
+        * The first '%s' is replaced with user name to whom the folder belongs,
+        * the second '%s' is replaced with folder name.
+        * Example result: "John Smith — Calendar"
+       */
+       folder_name = g_strdup_printf (C_("ForeignFolder", "%s — %s"), base_username, base_foldername);
+       if (folder_type != E_EWS_FOLDER_TYPE_MAILBOX)
+               e_ews_folder_set_name (folder, folder_name);
+
+       settings = camel_service_ref_settings (CAMEL_SERVICE (ews_store));
+       ews_settings = CAMEL_EWS_SETTINGS (settings);
+       session = camel_service_ref_session (CAMEL_SERVICE (ews_store));
+       if (E_IS_MAIL_SESSION (session))
+               registry = e_mail_session_get_registry (E_MAIL_SESSION (session));
+
+       success = (folder_type == E_EWS_FOLDER_TYPE_MAILBOX &&
+            !add_foreign_folder_to_camel (ews_store,
+               user_email,
+               folder,
+               include_subfolders,
+               base_username,
+               base_foldername,
+               error)) ||
+           (folder_type != E_EWS_FOLDER_TYPE_MAILBOX && !e_ews_folder_utils_add_as_esource (registry,
+               camel_ews_settings_get_hosturl (ews_settings),
+               camel_network_settings_get_user (CAMEL_NETWORK_SETTINGS (ews_settings)),
+               folder,
+               (include_subfolders ? E_EWS_ESOURCE_FLAG_INCLUDE_SUBFOLDERS : 0) | 
E_EWS_ESOURCE_FLAG_OFFLINE_SYNC,
+               0,
+               cancellable,
+               error));
+
+       g_free (folder_name);
+       g_object_unref (session);
+       g_object_unref (settings);
+
+       return success;
+}
diff --git a/src/EWS/evolution/e-ews-subscribe-foreign-folder.h 
b/src/EWS/evolution/e-ews-subscribe-foreign-folder.h
index 9d3e31d7..526601da 100644
--- a/src/EWS/evolution/e-ews-subscribe-foreign-folder.h
+++ b/src/EWS/evolution/e-ews-subscribe-foreign-folder.h
@@ -9,9 +9,34 @@
 
 #include <e-util/e-util.h>
 
-void   e_ews_subscribe_foreign_folder  (GtkWindow *parent,
-                                        CamelSession *session,
-                                        CamelStore *store,
-                                        EClientCache *client_cache);
+#include "camel/camel-ews-store.h"
+#include "common/e-ews-connection.h"
+#include "common/e-ews-folder.h"
+
+G_BEGIN_DECLS
+
+void           e_ews_subscribe_foreign_folder  (GtkWindow *parent,
+                                                CamelSession *session,
+                                                CamelStore *store,
+                                                EClientCache *client_cache);
+
+gboolean       e_ews_subscribe_foreign_folder_resolve_name_sync
+                                               (EEwsConnection *cnc,
+                                                const gchar *name,
+                                                gchar **out_display_name,
+                                                gchar **out_email_address,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+gboolean       e_ews_subscrive_foreign_folder_subscribe_sync
+                                               (CamelEwsStore *ews_store,
+                                                EEwsFolder *folder,
+                                                const gchar *user_display_name,
+                                                const gchar *user_email,
+                                                const gchar *fallback_folder_name,
+                                                gboolean include_subfolders,
+                                                GCancellable *cancellable,
+                                                GError **error);
+G_END_DECLS
 
 #endif /* E_EWS_SUBSCRIBE_FOREIGN_FOLDER_H */
diff --git a/src/EWS/evolution/e-mail-formatter-ews-sharing-metadata.c 
b/src/EWS/evolution/e-mail-formatter-ews-sharing-metadata.c
new file mode 100644
index 00000000..c998030f
--- /dev/null
+++ b/src/EWS/evolution/e-mail-formatter-ews-sharing-metadata.c
@@ -0,0 +1,223 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * SPDX-FileCopyrightText: (C) 2020 Red Hat (www.redhat.com)
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "evolution-ews-config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/libedataserver.h>
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-part-utils.h>
+
+#include "e-mail-part-ews-sharing-metadata.h"
+#include "e-mail-formatter-ews-sharing-metadata.h"
+
+typedef EMailFormatterExtension EMailFormatterEwsSharingMetadata;
+typedef EMailFormatterExtensionClass EMailFormatterEwsSharingMetadataClass;
+
+GType e_mail_formatter_ews_sharing_metadata_get_type (void);
+
+G_DEFINE_DYNAMIC_TYPE (EMailFormatterEwsSharingMetadata, e_mail_formatter_ews_sharing_metadata, 
E_TYPE_MAIL_FORMATTER_EXTENSION)
+
+static const gchar *formatter_mime_types[] = {
+       "application/x-sharing-metadata-xml",
+       NULL
+};
+
+static gboolean
+emf_ews_sharing_metadata (const gchar *xml_str,
+                         gchar **out_datatype,
+                         gchar **out_initiator_name,
+                         gchar **out_initiator_email,
+                         gchar **out_folder_entry_id)
+{
+       xmlDoc *xml;
+       xmlXPathContext *xpath;
+
+       if (!xml_str || !*xml_str)
+               return FALSE;
+
+       xml = e_xml_parse_data (xml_str, strlen (xml_str));
+
+       if (!xml)
+               return FALSE;
+
+       xpath = e_xml_new_xpath_context_with_namespaces (xml,
+               "s", "http://schemas.microsoft.com/sharing/2008";,
+               "e", "http://schemas.microsoft.com/exchange/sharing/2008";,
+               NULL);
+
+       *out_datatype = e_xml_xpath_eval_as_string (xpath, "/s:SharingMessage/s:DataType");
+       *out_initiator_name = e_xml_xpath_eval_as_string (xpath, "/s:SharingMessage/s:Initiator/s:Name");
+       *out_initiator_email = e_xml_xpath_eval_as_string (xpath, 
"/s:SharingMessage/s:Initiator/s:SmtpAddress");
+       *out_folder_entry_id = e_xml_xpath_eval_as_string (xpath, 
"/s:SharingMessage/s:Invitation/s:Providers/s:Provider/e:FolderId");
+
+       xmlXPathFreeContext (xpath);
+       xmlFreeDoc (xml);
+
+       return *out_datatype && **out_datatype &&
+               *out_initiator_name && **out_initiator_name &&
+               *out_initiator_email && **out_initiator_email &&
+               *out_folder_entry_id && **out_folder_entry_id;
+}
+
+static gboolean
+emf_ews_sharing_metadata_format (EMailFormatterExtension *extension,
+                                EMailFormatter *formatter,
+                                EMailFormatterContext *context,
+                                EMailPart *part,
+                                GOutputStream *stream,
+                                GCancellable *cancellable)
+{
+       EMailPartEwsSharingMetadata *sharing_part;
+       gboolean handled = TRUE;
+       GString *buffer = NULL;
+
+       if (!E_IS_MAIL_PART_EWS_SHARING_METADATA (part))
+               return FALSE;
+
+       sharing_part = E_MAIL_PART_EWS_SHARING_METADATA (part);
+
+       if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING ||
+           context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+               gchar *datatype = NULL, *initiator_name = NULL, *initiator_email = NULL, *folder_entry_id = 
NULL;
+
+               if (emf_ews_sharing_metadata (sharing_part->xml, &datatype, &initiator_name, 
&initiator_email, &folder_entry_id)) {
+                       ENamedParameters *params;
+                       gchar *params_str, *info;
+
+                       params = e_named_parameters_new ();
+
+                       e_named_parameters_set (params, "email", initiator_email);
+                       e_named_parameters_set (params, "folder_id", folder_entry_id);
+
+                       params_str = e_named_parameters_to_string (params);
+
+                       e_named_parameters_free (params);
+
+                       buffer = g_string_sized_new (2048);
+
+                       g_string_append (buffer, e_mail_formatter_get_sub_html_header (formatter));
+                       /* No need for body margins within <iframe> */
+                       g_string_append (buffer, "<style>body{ margin: 0; }</style>");
+
+                       if (g_strcmp0 (datatype, "calendar") == 0) {
+                               /* Translators: the first %s is replaced with a user name, the second %s is 
replaced with an email address of that user */
+                               info = g_strdup_printf (_("%s (%s) has invited you to view his or her 
Microsoft Exchange calendar."), initiator_name, initiator_email);
+                       } else {
+                               /* Translators: the first %s is replaced with a user name, the second %s is 
replaced with an email address of that user */
+                               info = g_strdup_printf (_("%s (%s) has invited you to view his or her 
Microsoft Exchange folder."), initiator_name, initiator_email);
+                       }
+
+                       e_util_markup_append_escaped (buffer,
+                               "<div class=\"part-container -e-web-view-background-color 
-e-web-view-text-color\" style=\"border: none; padding: 8px; margin: 0;\">%s<br>"
+                               "<br>"
+                               "%s<br>"
+                               "<br>"
+                               "<button type=\"button\" class=\"ews-sharing-metadata-btn\" 
id=\"ews-sharing-metadata-btn\" value=\"%s\">%s</button></div></body></html>",
+                               info,
+                               _("Click the Subscribe button to add it to Evolution."),
+                               params_str,
+                               _("Subscribe"));
+
+                       g_free (params_str);
+                       g_free (info);
+               } else {
+                       CamelMimePart *err_part;
+                       EMailPart *mail_part;
+                       const gchar *msg, *mime_type = "application/vnd.evolution.error";
+
+                       msg = _("Failed to extract sharing information from provided data.");
+
+                       err_part = camel_mime_part_new ();
+                       camel_mime_part_set_content (err_part, msg, strlen (msg), mime_type);
+
+                       mail_part = e_mail_part_new (err_part, e_mail_part_get_id (part));
+
+                       handled = e_mail_formatter_format_as (formatter, context, mail_part, stream, 
mime_type, cancellable);
+
+                       g_object_unref (mail_part);
+                       g_object_unref (err_part);
+               }
+
+               g_free (datatype);
+               g_free (initiator_name);
+               g_free (initiator_email);
+               g_free (folder_entry_id);
+       } else {
+               const gchar *default_charset, *charset;
+               gchar *uri;
+
+               default_charset = e_mail_formatter_get_default_charset (formatter);
+               charset = e_mail_formatter_get_charset (formatter);
+
+               if (!default_charset)
+                       default_charset = "";
+               if (!charset)
+                       charset = "";
+
+               uri = e_mail_part_build_uri (
+                       e_mail_part_list_get_folder (context->part_list),
+                       e_mail_part_list_get_message_uid (context->part_list),
+                       "part_id", G_TYPE_STRING, e_mail_part_get_id (part),
+                       "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+                       "formatter_default_charset", G_TYPE_STRING, default_charset,
+                       "formatter_charset", G_TYPE_STRING, charset,
+                       NULL);
+
+               buffer = g_string_sized_new (256);
+
+               g_string_append_printf (buffer,
+                       "<div class=\"part-container-nostyle\" >"
+                       "<iframe width=\"100%%\" height=\"10\""
+                       " id=\"%s\" name=\"%s\" "
+                       " frameborder=\"0\" src=\"%s\" "
+                       " class=\"-e-mail-formatter-frame-color %s"
+                       " -e-web-view-text-color\" >"
+                       "</iframe>"
+                       "</div>",
+                       e_mail_part_get_id (part),
+                       e_mail_part_get_id (part),
+                       uri,
+                       e_mail_part_get_frame_security_style (part));
+
+               g_free (uri);
+       }
+
+       if (buffer) {
+               g_output_stream_write_all (stream, buffer->str, buffer->len, NULL, cancellable, NULL);
+
+               g_string_free (buffer, TRUE);
+       }
+
+       return handled;
+}
+
+static void
+e_mail_formatter_ews_sharing_metadata_class_init (EMailFormatterExtensionClass *klass)
+{
+       klass->display_name = _("EWS Sharing Metadata");
+       klass->description = _("Display part as EWS sharing metadata");
+       klass->mime_types = formatter_mime_types;
+       klass->format = emf_ews_sharing_metadata_format;
+}
+
+static void
+e_mail_formatter_ews_sharing_metadata_class_finalize (EMailFormatterExtensionClass *klass)
+{
+}
+
+static void
+e_mail_formatter_ews_sharing_metadata_init (EMailFormatterExtension *extension)
+{
+}
+
+void
+e_mail_formatter_ews_sharing_metadata_type_register (GTypeModule *type_module)
+{
+       e_mail_formatter_ews_sharing_metadata_register_type (type_module);
+}
diff --git a/src/EWS/evolution/e-mail-formatter-ews-sharing-metadata.h 
b/src/EWS/evolution/e-mail-formatter-ews-sharing-metadata.h
new file mode 100644
index 00000000..d28f49c7
--- /dev/null
+++ b/src/EWS/evolution/e-mail-formatter-ews-sharing-metadata.h
@@ -0,0 +1,18 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * SPDX-FileCopyrightText: (C) 2020 Red Hat (www.redhat.com)
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef E_MAIL_FORMATTER_EWS_SHARING_METADATA_H
+#define E_MAIL_FORMATTER_EWS_SHARING_METADATA_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void e_mail_formatter_ews_sharing_metadata_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_MAIL_FORMATTER_EWS_SHARING_METADATA_H */
diff --git a/src/EWS/evolution/e-mail-parser-ews-multipart-mixed.c 
b/src/EWS/evolution/e-mail-parser-ews-multipart-mixed.c
new file mode 100644
index 00000000..c8b587f9
--- /dev/null
+++ b/src/EWS/evolution/e-mail-parser-ews-multipart-mixed.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * SPDX-FileCopyrightText: (C) 2020 Red Hat (www.redhat.com)
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "evolution-ews-config.h"
+
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-parser-extension.h>
+
+#include "e-mail-parser-ews-sharing-metadata.h"
+#include "e-mail-parser-ews-multipart-mixed.h"
+
+typedef EMailParserExtension EMailParserEwsMultipartMixed;
+typedef EMailParserExtensionClass EMailParserEwsMultipartMixedClass;
+
+GType e_mail_parser_ews_multipart_mixed_get_type (void);
+
+G_DEFINE_DYNAMIC_TYPE (EMailParserEwsMultipartMixed, e_mail_parser_ews_multipart_mixed, 
E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+       "multipart/mixed",
+       NULL
+};
+
+static gboolean
+emp_ews_mp_mixed_parse (EMailParserExtension *extension,
+                       EMailParser *parser,
+                       CamelMimePart *part,
+                       GString *part_id,
+                       GCancellable *cancellable,
+                       GQueue *out_mail_parts)
+{
+       CamelMultipart *mp;
+       gboolean handled = FALSE;
+
+       /* Allow this only in an EWS folder, because the EWS connection is needed */
+       if (!e_mail_parser_ews_sharing_metadata_is_ews_folder (parser, cancellable))
+               return FALSE;
+
+       mp = (CamelMultipart *) camel_medium_get_content (CAMEL_MEDIUM (part));
+
+       if (CAMEL_IS_MULTIPART (mp)) {
+               CamelMimePart *sharing_subpart = NULL;
+               gint ii, nparts, ntexts = 0, nsharings = 0;
+
+               nparts = camel_multipart_get_number (mp);
+
+               for (ii = 0; ii < nparts; ii++) {
+                       CamelMimePart *subpart;
+                       CamelContentType *ct;
+
+                       subpart = camel_multipart_get_part (mp, ii);
+                       ct = camel_mime_part_get_content_type (subpart);
+
+                       if (ct && (camel_content_type_is (ct, "text", "plain") || camel_content_type_is (ct, 
"text", "html"))) {
+                               ntexts++;
+                       } else if (ct && camel_content_type_is (ct, "application", "x-sharing-metadata-xml")) 
{
+                               sharing_subpart = subpart;
+                               nsharings++;
+                       }
+               }
+
+               /* Hide the text parts only if there is only a single sharing subpart */
+               if (nsharings == 1 && nsharings + ntexts == nparts) {
+                       gint len;
+
+                       len = part_id->len;
+
+                       g_string_append_printf (part_id, ".mixed.ews-sharing");
+                       handled = e_mail_parser_parse_part (parser, sharing_subpart, part_id, cancellable, 
out_mail_parts);
+                       g_string_truncate (part_id, len);
+               }
+       }
+
+       return handled;
+}
+
+static void
+e_mail_parser_ews_multipart_mixed_class_init (EMailParserExtensionClass *klass)
+{
+       klass->mime_types = parser_mime_types;
+       klass->priority = G_PRIORITY_LOW - 1;
+       klass->flags = E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
+       klass->parse = emp_ews_mp_mixed_parse;
+}
+
+static void
+e_mail_parser_ews_multipart_mixed_class_finalize (EMailParserExtensionClass *klass)
+{
+}
+
+static void
+e_mail_parser_ews_multipart_mixed_init (EMailParserExtension *extension)
+{
+}
+
+void
+e_mail_parser_ews_multipart_mixed_type_register (GTypeModule *type_module)
+{
+       e_mail_parser_ews_multipart_mixed_register_type (type_module);
+}
diff --git a/src/EWS/evolution/e-mail-parser-ews-multipart-mixed.h 
b/src/EWS/evolution/e-mail-parser-ews-multipart-mixed.h
new file mode 100644
index 00000000..4be321ad
--- /dev/null
+++ b/src/EWS/evolution/e-mail-parser-ews-multipart-mixed.h
@@ -0,0 +1,18 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * SPDX-FileCopyrightText: (C) 2020 Red Hat (www.redhat.com)
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef E_MAIL_PARSER_EWS_MULTIPART_MIXED_H
+#define E_MAIL_PARSER_EWS_MULTIPART_MIXED_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void e_mail_parser_ews_multipart_mixed_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PARSER_EWS_MULTIPART_MIXED_H */
diff --git a/src/EWS/evolution/e-mail-parser-ews-sharing-metadata.c 
b/src/EWS/evolution/e-mail-parser-ews-sharing-metadata.c
new file mode 100644
index 00000000..99217b87
--- /dev/null
+++ b/src/EWS/evolution/e-mail-parser-ews-sharing-metadata.c
@@ -0,0 +1,123 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * SPDX-FileCopyrightText: (C) 2020 Red Hat (www.redhat.com)
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "evolution-ews-config.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-part.h>
+
+#include "camel/camel-ews-folder.h"
+#include "e-mail-part-ews-sharing-metadata.h"
+
+#include "e-mail-parser-ews-sharing-metadata.h"
+
+typedef EMailParserExtension EMailParserEwsSharingMetadata;
+typedef EMailParserExtensionClass EMailParserEwsSharingMetadataClass;
+
+GType e_mail_parser_ews_sharing_metadata_get_type (void);
+
+G_DEFINE_DYNAMIC_TYPE (EMailParserEwsSharingMetadata, e_mail_parser_ews_sharing_metadata, 
E_TYPE_MAIL_PARSER_EXTENSION)
+
+static const gchar *parser_mime_types[] = {
+       "application/x-sharing-metadata-xml",
+       NULL
+};
+
+static gboolean
+emp_ews_sharing_metadata_parse (EMailParserExtension *extension,
+                               EMailParser *parser,
+                               CamelMimePart *part,
+                               GString *part_id,
+                               GCancellable *cancellable,
+                               GQueue *out_mail_parts)
+{
+       EMailPart *mail_part;
+       CamelDataWrapper *content;
+       CamelStream *stream;
+       GByteArray *byte_array;
+       gchar *xml;
+       gint len;
+
+       /* Allow this only in an EWS folder, because the EWS connection is needed */
+       if (!e_mail_parser_ews_sharing_metadata_is_ews_folder (parser, cancellable))
+               return FALSE;
+
+       /* This is non-gui thread. Download the part for using in the main thread */
+       content = camel_medium_get_content ((CamelMedium *) part);
+
+       byte_array = g_byte_array_new ();
+       stream = camel_stream_mem_new_with_byte_array (byte_array);
+       camel_data_wrapper_decode_to_stream_sync (content, stream, NULL, NULL);
+
+       if (byte_array->len == 0)
+               xml = NULL;
+       else
+               xml = g_strndup ((const gchar *) byte_array->data, byte_array->len);
+
+       g_object_unref (stream);
+
+       if (!xml)
+               return FALSE;
+
+       len = part_id->len;
+       g_string_append_printf (part_id, ".ews-sharing-xml");
+
+       mail_part = e_mail_part_ews_sharing_metadata_new (part, part_id->str);
+       mail_part->force_inline = TRUE;
+       e_mail_part_set_mime_type (mail_part, parser_mime_types[0]);
+       E_MAIL_PART_EWS_SHARING_METADATA (mail_part)->xml = xml;
+
+       g_queue_push_tail (out_mail_parts, mail_part);
+
+       g_string_truncate (part_id, len);
+
+       return TRUE;
+}
+
+static void
+e_mail_parser_ews_sharing_metadata_class_init (EMailParserExtensionClass *klass)
+{
+       klass->mime_types = parser_mime_types;
+       klass->flags = E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION;
+       klass->parse = emp_ews_sharing_metadata_parse;
+}
+
+static void
+e_mail_parser_ews_sharing_metadata_class_finalize (EMailParserExtensionClass *klass)
+{
+}
+
+static void
+e_mail_parser_ews_sharing_metadata_init (EMailParserExtension *sharind_metadata)
+{
+}
+
+void
+e_mail_parser_ews_sharing_metadata_type_register (GTypeModule *type_module)
+{
+       e_mail_parser_ews_sharing_metadata_register_type (type_module);
+}
+
+gboolean
+e_mail_parser_ews_sharing_metadata_is_ews_folder (EMailParser *parser,
+                                                 GCancellable *operation)
+{
+       EMailPartList *part_list;
+       CamelFolder *folder;
+       gboolean is_ews_folder;
+
+       part_list = e_mail_parser_ref_part_list_for_operation (parser, operation);
+
+       if (!part_list)
+               return FALSE;
+
+       folder = e_mail_part_list_get_folder (part_list);
+       is_ews_folder = CAMEL_IS_EWS_FOLDER (folder);
+
+       g_object_unref (part_list);
+
+       return is_ews_folder;
+}
diff --git a/src/EWS/evolution/e-mail-parser-ews-sharing-metadata.h 
b/src/EWS/evolution/e-mail-parser-ews-sharing-metadata.h
new file mode 100644
index 00000000..586b57fa
--- /dev/null
+++ b/src/EWS/evolution/e-mail-parser-ews-sharing-metadata.h
@@ -0,0 +1,23 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * SPDX-FileCopyrightText: (C) 2020 Red Hat (www.redhat.com)
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef E_MAIL_PARSER_EWS_SHARING_METADATA_H
+#define E_MAIL_PARSER_EWS_SHARING_METADATA_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include <em-format/e-mail-parser.h>
+
+G_BEGIN_DECLS
+
+void           e_mail_parser_ews_sharing_metadata_type_register (GTypeModule *type_module);
+gboolean       e_mail_parser_ews_sharing_metadata_is_ews_folder (EMailParser *parser,
+                                                                 GCancellable *operation);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PARSER_EWS_SHARING_METADATA_H */
diff --git a/src/EWS/evolution/e-mail-part-ews-sharing-metadata.c 
b/src/EWS/evolution/e-mail-part-ews-sharing-metadata.c
new file mode 100644
index 00000000..19b03de1
--- /dev/null
+++ b/src/EWS/evolution/e-mail-part-ews-sharing-metadata.c
@@ -0,0 +1,233 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * SPDX-FileCopyrightText: (C) 2020 Red Hat (www.redhat.com)
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "evolution-ews-config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+#include <mail/e-mail-display.h>
+#include <shell/e-shell-window.h>
+
+#include "camel/camel-ews-folder.h"
+#include "camel/camel-ews-store.h"
+
+#include "e-ews-subscribe-foreign-folder.h"
+
+#include "e-mail-part-ews-sharing-metadata.h"
+
+G_DEFINE_DYNAMIC_TYPE (EMailPartEwsSharingMetadata, e_mail_part_ews_sharing_metadata, E_TYPE_MAIL_PART)
+
+typedef struct _SubscribeData {
+       CamelEwsStore *ews_store;
+       EEwsConnection *cnc;
+       ENamedParameters *params;
+} SubscribeData;
+
+static void
+subscribe_data_free (gpointer ptr)
+{
+       SubscribeData *sd = ptr;
+
+       if (sd) {
+               g_clear_object (&sd->ews_store);
+               g_clear_object (&sd->cnc);
+               e_named_parameters_free (sd->params);
+               g_slice_free (SubscribeData, sd);
+       }
+}
+
+static void
+ews_sharing_metadata_subscribe_thread (EAlertSinkThreadJobData *job_data,
+                                      gpointer user_data,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+       SubscribeData *sd = user_data;
+       EwsFolderId fid;
+       EEwsFolder *folder = NULL;
+       const gchar *email;
+       gchar *folder_id = NULL;
+       gchar *display_name = NULL;
+       GError *local_error = NULL;
+
+       g_return_if_fail (sd != NULL);
+
+       if (!sd->cnc) {
+               g_set_error_literal (error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
+                       _("Cannot subscribe EWS folders in offline mode"));
+               return;
+       }
+
+       email = e_named_parameters_get (sd->params, "email");
+
+       if (!e_ews_connection_convert_id_sync (sd->cnc, G_PRIORITY_DEFAULT, email,
+               e_named_parameters_get (sd->params, "folder_id"),
+               "HexEntryId", "EwsId", &folder_id, cancellable, error)) {
+               return;
+       }
+
+       fid.id = folder_id;
+       fid.change_key = NULL;
+       fid.is_distinguished_id = FALSE;
+
+       if (e_ews_connection_get_folder_info_sync (sd->cnc, G_PRIORITY_DEFAULT, email, &fid, &folder, 
cancellable, &local_error)) {
+               if (e_ews_folder_get_folder_type (folder) == E_EWS_FOLDER_TYPE_UNKNOWN) {
+                       local_error = g_error_new_literal (EWS_CONNECTION_ERROR, 
EWS_CONNECTION_ERROR_FOLDERNOTFOUND,
+                               _("Cannot add folder, cannot determine folder’s type"));
+               } else {
+                       e_ews_folder_set_foreign (folder, TRUE);
+
+                       if (!e_ews_subscribe_foreign_folder_resolve_name_sync (sd->cnc, email, &display_name, 
NULL, cancellable, NULL))
+                               display_name = NULL;
+
+                       e_ews_subscrive_foreign_folder_subscribe_sync (sd->ews_store, folder,
+                               display_name, email, _("Folder"), FALSE, cancellable, &local_error);
+               }
+       } else if (!local_error ||
+                  g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_ITEMNOTFOUND) ||
+                  g_error_matches (local_error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_FOLDERNOTFOUND)) {
+               g_clear_error (&local_error);
+               local_error = g_error_new (
+                       EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_FOLDERNOTFOUND,
+                       _("Folder “%s” not found. Either it does not exist or you do not have permission to 
access it."),
+                       e_named_parameters_get (sd->params, "folder_id"));
+       }
+
+       if (local_error) {
+               g_propagate_error (error, local_error);
+       } else {
+               e_alert_sink_thread_job_set_alert_ident (job_data, "ews:folder-subscribe-info");
+               e_alert_sink_thread_job_set_alert_arg_0 (job_data, display_name ? display_name : email);
+
+               /* Create a fake error, to give a feedback about successful subscribe of the folder */
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "");
+       }
+
+       g_clear_object (&folder);
+       g_free (display_name);
+       g_free (folder_id);
+}
+
+static void
+ews_sharing_metadata_btn_clicked_cb (EWebView *web_view,
+                                    const gchar *iframe_id,
+                                    const gchar *element_id,
+                                    const gchar *element_class,
+                                    const gchar *element_value,
+                                    const GtkAllocation *element_position,
+                                    gpointer user_data)
+{
+       EMailPartList *part_list;
+       EAlertSink *alert_sink = NULL;
+       EActivity *activity;
+       CamelFolder *folder;
+       CamelStore *store;
+       GtkWidget *widget;
+       SubscribeData *sd;
+
+       if (!element_value || !*element_value || !E_IS_MAIL_DISPLAY (web_view))
+               return;
+
+       part_list = e_mail_display_get_part_list (E_MAIL_DISPLAY (web_view));
+       folder = part_list ? e_mail_part_list_get_folder (part_list) : NULL;
+
+       if (!CAMEL_IS_EWS_FOLDER (folder))
+               return;
+
+       store = camel_folder_get_parent_store (folder);
+
+       if (!CAMEL_IS_EWS_STORE (store))
+               return;
+
+       widget = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
+
+       if (E_IS_SHELL_WINDOW (widget))
+               alert_sink = E_ALERT_SINK (widget);
+
+       if (!alert_sink)
+               alert_sink = E_ALERT_SINK (web_view);
+
+       sd = g_slice_new (SubscribeData);
+       sd->ews_store = g_object_ref (store);
+       sd->cnc = camel_ews_store_ref_connection (CAMEL_EWS_STORE (store));
+       sd->params = e_named_parameters_new_string (element_value);
+
+       activity = e_alert_sink_submit_thread_job (alert_sink,
+               _("Subscribing EWS folder…"), "ews:folder-subscribe-error", NULL,
+               ews_sharing_metadata_subscribe_thread, sd, subscribe_data_free);
+
+       g_clear_object (&activity);
+}
+
+static void
+mail_part_ews_sharing_metadata_content_loaded (EMailPart *part,
+                                              EWebView *web_view,
+                                              const gchar *iframe_id)
+{
+       g_return_if_fail (E_IS_MAIL_PART_EWS_SHARING_METADATA (part));
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       if (g_strcmp0 ((iframe_id && *iframe_id) ? iframe_id : NULL, e_mail_part_get_id (part)) != 0)
+               return;
+
+       e_web_view_register_element_clicked (web_view, "ews-sharing-metadata-btn",
+               ews_sharing_metadata_btn_clicked_cb, NULL);
+}
+
+static void
+mail_part_ews_sharing_metadata_finalize (GObject *object)
+{
+       EMailPartEwsSharingMetadata *part = E_MAIL_PART_EWS_SHARING_METADATA (object);
+
+       g_clear_pointer (&part->xml, g_free);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_mail_part_ews_sharing_metadata_parent_class)->finalize (object);
+}
+
+static void
+e_mail_part_ews_sharing_metadata_class_init (EMailPartEwsSharingMetadataClass *klass)
+{
+       GObjectClass *object_class;
+       EMailPartClass *mail_part_class;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->finalize = mail_part_ews_sharing_metadata_finalize;
+
+       mail_part_class = E_MAIL_PART_CLASS (klass);
+       mail_part_class->content_loaded = mail_part_ews_sharing_metadata_content_loaded;
+}
+
+static void
+e_mail_part_ews_sharing_metadata_class_finalize (EMailPartEwsSharingMetadataClass *klass)
+{
+}
+
+static void
+e_mail_part_ews_sharing_metadata_init (EMailPartEwsSharingMetadata *part)
+{
+}
+
+void
+e_mail_part_ews_sharing_metadata_type_register (GTypeModule *type_module)
+{
+       /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+        *     function, so we have to wrap it with a public function in
+        *     order to register types from a separate compilation unit. */
+       e_mail_part_ews_sharing_metadata_register_type (type_module);
+}
+
+EMailPart *
+e_mail_part_ews_sharing_metadata_new (CamelMimePart *mime_part,
+                      const gchar *id)
+{
+       g_return_val_if_fail (id != NULL, NULL);
+
+       return g_object_new (
+               E_TYPE_MAIL_PART_EWS_SHARING_METADATA,
+               "id", id, "mime-part", mime_part, NULL);
+}
diff --git a/src/EWS/evolution/e-mail-part-ews-sharing-metadata.h 
b/src/EWS/evolution/e-mail-part-ews-sharing-metadata.h
new file mode 100644
index 00000000..c62a7abf
--- /dev/null
+++ b/src/EWS/evolution/e-mail-part-ews-sharing-metadata.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * SPDX-FileCopyrightText: (C) 2020 Red Hat (www.redhat.com)
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef E_MAIL_PART_EWS_SHARING_METADATA_H
+#define E_MAIL_PART_EWS_SHARING_METADATA_H
+
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_EWS_SHARING_METADATA \
+       (e_mail_part_ews_sharing_metadata_get_type ())
+#define E_MAIL_PART_EWS_SHARING_METADATA(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_PART_EWS_SHARING_METADATA, EMailPartEwsSharingMetadata))
+#define E_MAIL_PART_EWS_SHARING_METADATA_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_PART_EWS_SHARING_METADATA, EMailPartEwsSharingMetadataClass))
+#define E_IS_MAIL_PART_EWS_SHARING_METADATA(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_PART_EWS_SHARING_METADATA))
+#define E_IS_MAIL_PART_EWS_SHARING_METADATA_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_PART_EWS_SHARING_METADATA))
+#define E_MAIL_PART_EWS_SHARING_METADATA_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_PART_EWS_SHARING_METADATA, EMailPartEwsSharingMetadataClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartEwsSharingMetadata EMailPartEwsSharingMetadata;
+typedef struct _EMailPartEwsSharingMetadataClass EMailPartEwsSharingMetadataClass;
+typedef struct _EMailPartEwsSharingMetadataPrivate EMailPartEwsSharingMetadataPrivate;
+
+struct _EMailPartEwsSharingMetadata {
+       EMailPart parent;
+
+       gchar *xml;
+};
+
+struct _EMailPartEwsSharingMetadataClass {
+       EMailPartClass parent_class;
+};
+
+GType          e_mail_part_ews_sharing_metadata_get_type       (void) G_GNUC_CONST;
+void           e_mail_part_ews_sharing_metadata_type_register  (GTypeModule *type_module);
+EMailPart *    e_mail_part_ews_sharing_metadata_new            (CamelMimePart *mime_part,
+                                                                const gchar *id);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_EWS_SHARING_METADATA_H */
diff --git a/src/EWS/evolution/module-ews-configuration.c b/src/EWS/evolution/module-ews-configuration.c
index 978e7cb3..747fc8db 100644
--- a/src/EWS/evolution/module-ews-configuration.c
+++ b/src/EWS/evolution/module-ews-configuration.c
@@ -19,6 +19,10 @@
 #include "e-mail-config-ews-offline-options.h"
 #include "e-mail-config-ews-ooo-page.h"
 #include "e-mail-config-ews-folder-sizes-page.h"
+#include "e-mail-formatter-ews-sharing-metadata.h"
+#include "e-mail-parser-ews-multipart-mixed.h"
+#include "e-mail-parser-ews-sharing-metadata.h"
+#include "e-mail-part-ews-sharing-metadata.h"
 #include "e-ews-ooo-notificator.h"
 #include "e-ews-config-lookup.h"
 #include "e-ews-photo-source.h"
@@ -49,6 +53,10 @@ e_module_load (GTypeModule *type_module)
        e_mail_config_ews_delegates_page_type_register (type_module);
        e_mail_config_ews_ooo_page_type_register (type_module);
        e_mail_config_ews_folder_sizes_page_type_register (type_module);
+       e_mail_formatter_ews_sharing_metadata_type_register (type_module);
+       e_mail_parser_ews_multipart_mixed_type_register (type_module);
+       e_mail_parser_ews_sharing_metadata_type_register (type_module);
+       e_mail_part_ews_sharing_metadata_type_register (type_module);
        e_ews_config_lookup_type_register (type_module);
        e_ews_config_ui_extension_type_register (type_module);
        e_ews_ooo_notificator_type_register (type_module);
diff --git a/src/EWS/evolution/module-ews-configuration.error.xml 
b/src/EWS/evolution/module-ews-configuration.error.xml
index 33a01288..3d915ac1 100644
--- a/src/EWS/evolution/module-ews-configuration.error.xml
+++ b/src/EWS/evolution/module-ews-configuration.error.xml
@@ -25,4 +25,14 @@
     <_primary>Your Exchange account “{0}” has the status set as “Out of Office”.</_primary>
   </error>
 
+  <error type="error" id="folder-subscribe-error">
+    <_primary>Failed to subscribe user folder.</_primary>
+    <_secondary>The reported error was “{0}”.</_secondary>
+  </error>
+
+  <error type="info" id="folder-subscribe-info">
+    <_primary>Folder had been subscribed.</_primary>
+    <_secondary>Folder of user “{0}” had been subscribed successfully.</_secondary>
+  </error>
+
 </error-list>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]