[evolution-ews/wip/mcrha/office365] Implement rename and delete of mail folders



commit d4931e8faf6067fdaed9f6c0b711d8ec0bdb5a95
Author: Milan Crha <mcrha redhat com>
Date:   Thu Jun 25 16:02:11 2020 +0200

    Implement rename and delete of mail folders

 src/Office365/camel/camel-o365-store-summary.c     |   8 +-
 src/Office365/camel/camel-o365-store.c             | 339 ++++++++++++++++++++-
 src/Office365/common/e-o365-connection.c           | 216 ++++++++++++-
 src/Office365/common/e-o365-connection.h           |  23 ++
 src/Office365/common/e-o365-json-utils.h           |  14 +-
 .../evolution/e-mail-config-o365-backend.c         |  63 ----
 6 files changed, 564 insertions(+), 99 deletions(-)
---
diff --git a/src/Office365/camel/camel-o365-store-summary.c b/src/Office365/camel/camel-o365-store-summary.c
index 619f01ac..246331f0 100644
--- a/src/Office365/camel/camel-o365-store-summary.c
+++ b/src/Office365/camel/camel-o365-store-summary.c
@@ -840,7 +840,7 @@ camel_o365_store_summary_set_folder_display_name (CamelO365StoreSummary *store_s
                                rpd.prefix_len = strlen (old_full_name);
                                rpd.removed = NULL;
 
-                               g_hash_table_foreach_remove (store_summary->priv->id_full_name_hash, 
o365_remove_prefixed_cb, &rpd);
+                               g_hash_table_foreach_steal (store_summary->priv->id_full_name_hash, 
o365_remove_prefixed_cb, &rpd);
 
                                new_full_name = o365_store_summary_build_new_full_name (old_full_name, 
display_name);
                                diff = strlen (new_full_name) - rpd.prefix_len;
@@ -1162,10 +1162,10 @@ o365_store_summary_gather_folder_infos (gpointer key,
        g_return_if_fail (gid != NULL);
 
        if (!gid->prefix_len || (g_str_has_prefix (full_name, gid->prefix) &&
-           full_name[gid->prefix_len] == '/')) {
+           (full_name[gid->prefix_len] == '/' || !full_name[gid->prefix_len]))) {
                const gchar *without_prefix = full_name + gid->prefix_len + (gid->prefix_len > 0 ? 1 : 0);
 
-               if (gid->recursive || !strchr (without_prefix, '/')) {
+               if (gid->recursive || !*without_prefix) {
                        CamelFolderInfo *info;
 
                        info = camel_o365_store_summary_build_folder_info_for_id (gid->store_summary, id);
@@ -1201,7 +1201,7 @@ camel_o365_store_summary_build_folder_info (CamelO365StoreSummary *store_summary
 
        g_hash_table_foreach (store_summary->priv->id_full_name_hash, o365_store_summary_gather_folder_infos, 
&gid);
 
-       info = camel_folder_info_build (gid.folder_infos, NULL, '/', TRUE);
+       info = camel_folder_info_build (gid.folder_infos, top, '/', TRUE);
 
        UNLOCK (store_summary);
 
diff --git a/src/Office365/camel/camel-o365-store.c b/src/Office365/camel/camel-o365-store.c
index adf925f8..a648b2fe 100644
--- a/src/Office365/camel/camel-o365-store.c
+++ b/src/Office365/camel/camel-o365-store.c
@@ -404,8 +404,8 @@ o365_store_get_folder_sync (CamelStore *store,
 }
 
 static void
-o365_store_save_summary_locked (CamelO365StoreSummary *summary,
-                               const gchar *where)
+o365_store_save_summary (CamelO365StoreSummary *summary,
+                        const gchar *where)
 {
        GError *error = NULL;
 
@@ -502,13 +502,336 @@ o365_store_create_folder_sync (CamelStore *store,
 
        json_object_unref (mail_folder);
 
-       LOCK (o365_store);
-       o365_store_save_summary_locked (o365_store->priv->summary, G_STRFUNC);
-       UNLOCK (o365_store);
+       o365_store_save_summary (o365_store->priv->summary, G_STRFUNC);
 
        return fi;
 }
 
+static void
+o365_store_notify_created_recursive (CamelStore *store,
+                                    CamelFolderInfo *folder_info)
+{
+       while (folder_info) {
+               camel_store_folder_created (store, folder_info);
+               camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (store), folder_info);
+
+               if (folder_info->child)
+                       o365_store_notify_created_recursive (store, folder_info->child);
+
+               folder_info = folder_info->next;
+       }
+}
+
+static gboolean
+o365_store_move_mail_folder (CamelO365Store *o365_store,
+                            EO365Connection *cnc,
+                            const gchar *folder_id,
+                            const gchar *des_folder_id,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       EO365MailFolder *moved_mail_folder = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE (o365_store), FALSE);
+       g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+       g_return_val_if_fail (folder_id != NULL, FALSE);
+       g_return_val_if_fail (des_folder_id != NULL, FALSE);
+       g_return_val_if_fail (g_strcmp0 (folder_id, des_folder_id) != 0, FALSE);
+
+       success = e_o365_connection_copy_move_mail_folder_sync (cnc, NULL, folder_id, des_folder_id, FALSE, 
&moved_mail_folder, cancellable, error);
+
+       if (success && moved_mail_folder) {
+               CamelFolderInfo *fi;
+               gchar *new_full_name;
+
+               fi = camel_o365_store_summary_build_folder_info_for_id (o365_store->priv->summary, folder_id);
+
+               camel_o365_store_summary_set_folder_parent_id (o365_store->priv->summary, folder_id, 
e_o365_mail_folder_get_parent_folder_id (moved_mail_folder));
+               camel_o365_store_summary_rebuild_hashes (o365_store->priv->summary);
+
+               camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (o365_store), fi);
+               camel_store_folder_deleted (CAMEL_STORE (o365_store), fi);
+
+               camel_folder_info_free (fi);
+
+               new_full_name = camel_o365_store_summary_dup_folder_full_name (o365_store->priv->summary, 
folder_id);
+               g_warn_if_fail (new_full_name != NULL);
+
+               fi = camel_o365_store_summary_build_folder_info (o365_store->priv->summary, new_full_name, 
TRUE);
+
+               o365_store_notify_created_recursive (CAMEL_STORE (o365_store), fi);
+
+               json_object_unref (moved_mail_folder);
+               camel_folder_info_free (fi);
+               g_free (new_full_name);
+       }
+
+       return success;
+}
+
+static void
+o365_store_delete_folders_from_summary_recursive (CamelO365Store *o365_store,
+                                                 CamelFolderInfo *fi,
+                                                 gboolean send_signals)
+{
+       CamelStore *store = send_signals ? CAMEL_STORE (o365_store) : NULL;
+       CamelSubscribable *subscribable = send_signals ? CAMEL_SUBSCRIBABLE (o365_store) : NULL;
+
+       while (fi) {
+               gchar *folder_id;
+
+               if (fi->child)
+                       o365_store_delete_folders_from_summary_recursive (o365_store, fi->child, 
send_signals);
+
+               folder_id = camel_o365_store_summary_dup_folder_id_for_full_name (o365_store->priv->summary, 
fi->full_name);
+               if (folder_id) {
+                       camel_o365_store_summary_remove_folder (o365_store->priv->summary, folder_id);
+                       g_free (folder_id);
+               }
+
+               if (send_signals) {
+                       camel_subscribable_folder_unsubscribed (subscribable, fi);
+                       camel_store_folder_deleted (store, fi);
+               }
+
+               fi = fi->next;
+       }
+}
+
+static gboolean
+o365_store_delete_folder_sync (CamelStore *store,
+                              const gchar *folder_name,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+       CamelO365Store *o365_store;
+       CamelFolderInfo *folder_info;
+       EO365Connection *cnc = NULL;
+       gchar *folder_id;
+       gchar *trash_folder_id;
+       gchar *trash_full_name;
+       gboolean success;
+       gboolean is_under_trash_folder, claim_unsubscribe = TRUE;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE (store), FALSE);
+
+       o365_store = CAMEL_O365_STORE (store);
+
+       folder_info = camel_store_get_folder_info_sync (store, folder_name,
+               CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
+               cancellable, &local_error);
+
+       if (!folder_info) {
+               if (local_error)
+                       g_propagate_error (error, local_error);
+
+               return FALSE;
+       }
+
+       folder_id = camel_o365_store_summary_dup_folder_id_for_full_name (o365_store->priv->summary, 
folder_name);
+
+       if (!folder_id) {
+               camel_folder_info_free (folder_info);
+
+               g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Folder does not exist"));
+
+               return FALSE;
+       }
+
+       trash_folder_id = camel_o365_store_summary_dup_folder_id_for_type (o365_store->priv->summary, 
CAMEL_FOLDER_TYPE_TRASH);
+       trash_full_name = camel_o365_store_summary_dup_folder_full_name (o365_store->priv->summary, 
trash_folder_id);
+
+       if (!trash_full_name) {
+               camel_folder_info_free (folder_info);
+               g_free (trash_folder_id);
+               g_free (folder_id);
+
+               g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot find “Deleted Items” 
folder"));
+
+               return FALSE;
+       }
+
+       is_under_trash_folder = g_str_has_prefix (folder_name, trash_full_name);
+
+       if (is_under_trash_folder) {
+               gint len = strlen (trash_full_name);
+
+               is_under_trash_folder = len > 0 && (trash_full_name[len - 1] == '/' || folder_name[len] == 
'/');
+       }
+
+       g_free (trash_full_name);
+
+       if (!camel_o365_store_ensure_connected (o365_store, &cnc, cancellable, error)) {
+               camel_folder_info_free (folder_info);
+               g_free (trash_folder_id);
+               g_free (folder_id);
+
+               return FALSE;
+       }
+
+       if (camel_o365_store_summary_get_folder_is_foreign (o365_store->priv->summary, folder_id) ||
+           camel_o365_store_summary_get_folder_is_public (o365_store->priv->summary, folder_id)) {
+               /* do not delete foreign or public folders,
+                * only remove them from the local cache */
+               success = TRUE;
+       } else if (is_under_trash_folder) {
+               success = e_o365_connection_delete_mail_folder_sync (cnc, NULL, folder_id, cancellable, 
&local_error);
+       } else {
+               success = o365_store_move_mail_folder (o365_store, cnc, folder_id, "deleteditems", 
cancellable, &local_error);
+               claim_unsubscribe = FALSE;
+       }
+
+       g_clear_object (&cnc);
+
+       if (!success) {
+               camel_folder_info_free (folder_info);
+               g_free (trash_folder_id);
+               g_free (folder_id);
+
+               camel_o365_store_maybe_disconnect (o365_store, local_error);
+               g_propagate_error (error, local_error);
+
+               return FALSE;
+       }
+
+       if (is_under_trash_folder)
+               o365_store_delete_folders_from_summary_recursive (o365_store, folder_info, FALSE);
+
+       if (claim_unsubscribe) {
+               camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (o365_store), folder_info);
+               camel_store_folder_deleted (store, folder_info);
+       }
+
+       camel_folder_info_free (folder_info);
+
+       o365_store_save_summary (o365_store->priv->summary, G_STRFUNC);
+
+       g_free (trash_folder_id);
+       g_free (folder_id);
+
+       return TRUE;
+}
+
+static gboolean
+o365_store_rename_folder_sync (CamelStore *store,
+                              const gchar *old_name,
+                              const gchar *new_name,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+       CamelO365Store *o365_store;
+       EO365Connection *cnc;
+       const gchar *old_slash, *new_slash;
+       gint parent_len;
+       gchar *folder_id;
+       gboolean success = TRUE;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE (store), FALSE);
+
+       if (!g_strcmp0 (old_name, new_name))
+               return TRUE;
+
+       o365_store = CAMEL_O365_STORE (store);
+       folder_id = camel_o365_store_summary_dup_folder_id_for_full_name (o365_store->priv->summary, 
old_name);
+
+       if (!folder_id) {
+               g_set_error (error, CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER,
+                       _("Folder “%s” does not exist"), old_name);
+
+               return FALSE;
+       }
+
+       if (!camel_o365_store_ensure_connected (o365_store, &cnc, cancellable, error)) {
+               g_free (folder_id);
+               return FALSE;
+       }
+
+       old_slash = g_strrstr (old_name, "/");
+       new_slash = g_strrstr (new_name, "/");
+
+       if (old_slash)
+               old_slash++;
+       else
+               old_slash = old_name;
+
+       if (new_slash)
+               new_slash++;
+       else
+               new_slash = new_name;
+
+       parent_len = old_slash - old_name;
+
+       /* First move the folder, if needed */
+       if (new_slash - new_name != parent_len ||
+           strncmp (old_name, new_name, parent_len)) {
+               gchar *new_parent_id;
+
+               if (new_slash - new_name > 0) {
+                       gchar *new_parent;
+
+                       new_parent = g_strndup (new_name, new_slash - new_name - 1);
+                       new_parent_id = camel_o365_store_summary_dup_folder_id_for_full_name 
(o365_store->priv->summary, new_parent);
+
+                       if (!new_parent_id) {
+                               g_set_error (error, CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER,
+                                       _("Folder “%s” does not exist"), new_parent);
+
+                               g_free (new_parent);
+                               g_free (folder_id);
+
+                               return FALSE;
+                       }
+
+                       g_free (new_parent);
+               } else {
+                       new_parent_id = NULL;
+               }
+
+               success = o365_store_move_mail_folder (o365_store, cnc, folder_id, new_parent_id ? 
new_parent_id : "msgfolderroot", cancellable, &local_error);
+
+               g_free (new_parent_id);
+       }
+
+       /* Then rename the folder, if needed */
+       if (success && g_strcmp0 (old_slash, new_slash) != 0) {
+               EO365MailFolder *mail_folder = NULL;
+
+               success = e_o365_connection_rename_mail_folder_sync (cnc, NULL, folder_id, new_slash, 
&mail_folder, cancellable, &local_error);
+
+               if (mail_folder) {
+                       camel_o365_store_summary_set_folder_display_name (o365_store->priv->summary, 
folder_id,
+                               e_o365_mail_folder_get_display_name (mail_folder), TRUE);
+
+                       json_object_unref (mail_folder);
+               }
+       }
+
+       if (success) {
+               CamelFolderInfo *fi;
+
+               fi = camel_o365_store_summary_build_folder_info_for_id (o365_store->priv->summary, folder_id);
+
+               if (fi) {
+                       camel_store_folder_renamed (store, old_name, fi);
+                       camel_folder_info_free (fi);
+               }
+       }
+
+       o365_store_save_summary (o365_store->priv->summary, G_STRFUNC);
+
+       if (!success && local_error) {
+               camel_o365_store_maybe_disconnect (o365_store, local_error);
+               g_propagate_error (error, local_error);
+       }
+
+       g_free (folder_id);
+
+       return success;
+}
+
 typedef struct _FolderRenamedData {
        gchar *id;
        gchar *old_name;
@@ -667,7 +990,7 @@ o365_get_folder_info_sync (CamelStore *store,
                                        LOCK (o365_store);
 
                                        camel_o365_store_summary_set_delta_link (o365_store->priv->summary, 
new_delta_link);
-                                       o365_store_save_summary_locked (o365_store->priv->summary, G_STRFUNC);
+                                       o365_store_save_summary (o365_store->priv->summary, G_STRFUNC);
 
                                        fdd.added_ids = g_slist_reverse (fdd.added_ids);
                                        fdd.renamed_data = g_slist_reverse (fdd.renamed_data);
@@ -1015,7 +1338,7 @@ o365_store_dispose (GObject *object)
        LOCK (o365_store);
 
        if (o365_store->priv->summary) {
-               o365_store_save_summary_locked (o365_store->priv->summary, G_STRFUNC);
+               o365_store_save_summary (o365_store->priv->summary, G_STRFUNC);
                g_clear_object (&o365_store->priv->summary);
        }
 
@@ -1078,10 +1401,8 @@ camel_o365_store_class_init (CamelO365StoreClass *class)
        store_class = CAMEL_STORE_CLASS (class);
        store_class->get_folder_sync = o365_store_get_folder_sync;
        store_class->create_folder_sync = o365_store_create_folder_sync;
-#if 0
        store_class->delete_folder_sync = o365_store_delete_folder_sync;
        store_class->rename_folder_sync = o365_store_rename_folder_sync;
-#endif
        store_class->get_folder_info_sync = o365_get_folder_info_sync;
        store_class->initial_setup_sync = o365_store_initial_setup_sync;
        store_class->get_trash_folder_sync = o365_store_get_trash_folder_sync;
diff --git a/src/Office365/common/e-o365-connection.c b/src/Office365/common/e-o365-connection.c
index 6df4ba51..31cd7791 100644
--- a/src/Office365/common/e-o365-connection.c
+++ b/src/Office365/common/e-o365-connection.c
@@ -1335,6 +1335,29 @@ o365_connection_send_request_sync (EO365Connection *cnc,
        return success;
 }
 
+static gboolean
+e_o365_read_no_response_cb (EO365Connection *cnc,
+                           SoupMessage *message,
+                           GInputStream *raw_data_stream,
+                           gpointer user_data,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+       /* This is used when no response is expected from the server.
+          Read the data stream only if debugging is on, in case
+          the server returns anything interesting. */
+
+       if (o365_log_enabled ()) {
+               gchar buffer[4096];
+
+               while (g_input_stream_read (raw_data_stream, buffer, sizeof (buffer), cancellable, error) > 
0) {
+                       /* Do nothing, just read it, thus it's shown in the debug output */
+               }
+       }
+
+       return TRUE;
+}
+
 typedef struct _EO365ResponseData {
        EO365ConnectionJsonFunc json_func;
        gpointer func_user_data;
@@ -1432,6 +1455,28 @@ e_o365_read_json_object_response_cb (EO365Connection *cnc,
        return TRUE;
 }
 
+static SoupMessage *
+o365_connection_new_soup_message (const gchar *method,
+                                 const gchar *uri,
+                                 GError **error)
+{
+       SoupMessage *message;
+
+       g_return_val_if_fail (method != NULL, NULL);
+       g_return_val_if_fail (uri != NULL, NULL);
+
+       message = soup_message_new (method, uri);
+
+       if (message) {
+               soup_message_headers_append (message->request_headers, "Connection", "Keep-Alive");
+               soup_message_headers_append (message->request_headers, "User-Agent", "Evolution-O365/" 
VERSION);
+       } else {
+               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: “%s”"), uri);
+       }
+
+       return message;
+}
+
 gboolean
 e_o365_connection_get_ssl_error_details (EO365Connection *cnc,
                                         gchar **out_certificate_pem,
@@ -1480,10 +1525,9 @@ e_o365_connection_authenticate_sync (EO365Connection *cnc,
                "$top", "1",
                NULL);
 
-       message = soup_message_new (SOUP_METHOD_GET, uri);
+       message = o365_connection_new_soup_message (SOUP_METHOD_GET, uri, error);
 
        if (!message) {
-               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: “%s”"), uri);
                g_free (uri);
 
                return FALSE;
@@ -1837,10 +1881,9 @@ e_o365_connection_batch_request_internal_sync (EO365Connection *cnc,
        uri = e_o365_connection_construct_uri (cnc, FALSE, NULL, api_version, "",
                "$batch", NULL, NULL, NULL);
 
-       message = soup_message_new (SOUP_METHOD_POST, uri);
+       message = o365_connection_new_soup_message (SOUP_METHOD_POST, uri, error);
 
        if (!message) {
-               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: “%s”"), uri);
                g_free (uri);
 
                return FALSE;
@@ -2094,10 +2137,9 @@ e_o365_connection_list_mail_folders_sync (EO365Connection *cnc,
                "$select", select,
                NULL);
 
-       message = soup_message_new (SOUP_METHOD_GET, uri);
+       message = o365_connection_new_soup_message (SOUP_METHOD_GET, uri, error);
 
        if (!message) {
-               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: “%s”"), uri);
                g_free (uri);
 
                return FALSE;
@@ -2137,7 +2179,7 @@ e_o365_connection_get_mail_folders_delta_sync (EO365Connection *cnc,
        g_return_val_if_fail (func != NULL, FALSE);
 
        if (delta_link)
-               message = soup_message_new (SOUP_METHOD_GET, delta_link);
+               message = o365_connection_new_soup_message (SOUP_METHOD_GET, delta_link, NULL);
 
        if (!message) {
                gchar *uri;
@@ -2149,10 +2191,9 @@ e_o365_connection_get_mail_folders_delta_sync (EO365Connection *cnc,
                        "$select", select,
                        NULL);
 
-               message = soup_message_new (SOUP_METHOD_GET, uri);
+               message = o365_connection_new_soup_message (SOUP_METHOD_GET, uri, error);
 
                if (!message) {
-                       g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: “%s”"), 
uri);
                        g_free (uri);
 
                        return FALSE;
@@ -2211,10 +2252,155 @@ e_o365_connection_create_mail_folder_sync (EO365Connection *cnc,
                parent_folder_id ? "childFolders" : NULL,
                NULL);
 
-       message = soup_message_new (SOUP_METHOD_POST, uri);
+       message = o365_connection_new_soup_message (SOUP_METHOD_POST, uri, error);
+
+       if (!message) {
+               g_free (uri);
+
+               return FALSE;
+       }
+
+       g_free (uri);
+
+       builder = json_builder_new_immutable ();
+
+       json_builder_begin_object (builder);
+       json_builder_set_member_name (builder, "displayName");
+       json_builder_add_string_value (builder, display_name);
+       json_builder_end_object (builder);
+
+       e_o365_connection_set_json_body (message, builder);
+
+       g_object_unref (builder);
+
+       success = o365_connection_send_request_sync (cnc, message, e_o365_read_json_object_response_cb, NULL, 
out_mail_folder, cancellable, error);
+
+       g_clear_object (&message);
+
+       return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/mailfolder-delete?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_delete_mail_folder_sync (EO365Connection *cnc,
+                                          const gchar *user_override, /* for which user, NULL to use the 
account user */
+                                          const gchar *folder_id,
+                                          GCancellable *cancellable,
+                                          GError **error)
+{
+       SoupMessage *message = NULL;
+       gboolean success;
+       gchar *uri;
+
+       g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+       g_return_val_if_fail (folder_id != NULL, FALSE);
+
+       uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+               "mailFolders", folder_id, NULL, NULL);
+
+       message = o365_connection_new_soup_message (SOUP_METHOD_DELETE, uri, error);
+
+       if (!message) {
+               g_free (uri);
+
+               return FALSE;
+       }
+
+       g_free (uri);
+
+       success = o365_connection_send_request_sync (cnc, message, NULL, e_o365_read_no_response_cb, NULL, 
cancellable, error);
+
+       g_clear_object (&message);
+
+       return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/mailfolder-copy?view=graph-rest-1.0&tabs=http
+   https://docs.microsoft.com/en-us/graph/api/mailfolder-move?view=graph-rest-1.0&tabs=http
+ */
+gboolean
+e_o365_connection_copy_move_mail_folder_sync (EO365Connection *cnc,
+                                             const gchar *user_override, /* for which user, NULL to use the 
account user */
+                                             const gchar *src_folder_id,
+                                             const gchar *des_folder_id,
+                                             gboolean do_copy,
+                                             EO365MailFolder **out_mail_folder,
+                                             GCancellable *cancellable,
+                                             GError **error)
+{
+       SoupMessage *message = NULL;
+       JsonBuilder *builder;
+       gboolean success;
+       gchar *uri;
+
+       g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+       g_return_val_if_fail (src_folder_id != NULL, FALSE);
+       g_return_val_if_fail (des_folder_id != NULL, FALSE);
+
+       uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+               "mailFolders",
+               src_folder_id,
+               do_copy ? "copy" : "move",
+               NULL);
+
+       message = o365_connection_new_soup_message (SOUP_METHOD_POST, uri, error);
+
+       if (!message) {
+               g_free (uri);
+
+               return FALSE;
+       }
+
+       g_free (uri);
+
+       builder = json_builder_new_immutable ();
+
+       json_builder_begin_object (builder);
+       json_builder_set_member_name (builder, "destinationId");
+       json_builder_add_string_value (builder, des_folder_id);
+       json_builder_end_object (builder);
+
+       e_o365_connection_set_json_body (message, builder);
+
+       g_object_unref (builder);
+
+       success = o365_connection_send_request_sync (cnc, message, e_o365_read_json_object_response_cb, NULL, 
out_mail_folder, cancellable, error);
+
+       g_clear_object (&message);
+
+       return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/mailfolder-update?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_rename_mail_folder_sync (EO365Connection *cnc,
+                                          const gchar *user_override, /* for which user, NULL to use the 
account user */
+                                          const gchar *folder_id,
+                                          const gchar *display_name,
+                                          EO365MailFolder **out_mail_folder,
+                                          GCancellable *cancellable,
+                                          GError **error)
+{
+       SoupMessage *message = NULL;
+       JsonBuilder *builder;
+       gboolean success;
+       gchar *uri;
+
+       g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+       g_return_val_if_fail (folder_id != NULL, FALSE);
+       g_return_val_if_fail (display_name != NULL, FALSE);
+
+       uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+               "mailFolders",
+               folder_id,
+               NULL,
+               NULL);
+
+       message = o365_connection_new_soup_message ("PATCH", uri, error);
 
        if (!message) {
-               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: “%s”"), uri);
                g_free (uri);
 
                return FALSE;
@@ -2265,7 +2451,7 @@ e_o365_connection_get_mail_messages_delta_sync (EO365Connection *cnc,
        g_return_val_if_fail (func != NULL, FALSE);
 
        if (delta_link)
-               message = soup_message_new (SOUP_METHOD_GET, delta_link);
+               message = o365_connection_new_soup_message (SOUP_METHOD_GET, delta_link, NULL);
 
        if (!message) {
                gchar *uri;
@@ -2278,10 +2464,9 @@ e_o365_connection_get_mail_messages_delta_sync (EO365Connection *cnc,
                        "$select", select,
                        NULL);
 
-               message = soup_message_new (SOUP_METHOD_GET, uri);
+               message = o365_connection_new_soup_message (SOUP_METHOD_GET, uri, error);
 
                if (!message) {
-                       g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: “%s”"), 
uri);
                        g_free (uri);
 
                        return FALSE;
@@ -2342,10 +2527,9 @@ e_o365_connection_get_mail_message_sync (EO365Connection *cnc,
                "", "$value",
                NULL);
 
-       message = soup_message_new (SOUP_METHOD_GET, uri);
+       message = o365_connection_new_soup_message (SOUP_METHOD_GET, uri, error);
 
        if (!message) {
-               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: “%s”"), uri);
                g_free (uri);
 
                return FALSE;
diff --git a/src/Office365/common/e-o365-connection.h b/src/Office365/common/e-o365-connection.h
index cc1de355..4335190e 100644
--- a/src/Office365/common/e-o365-connection.h
+++ b/src/Office365/common/e-o365-connection.h
@@ -186,6 +186,29 @@ gboolean   e_o365_connection_create_mail_folder_sync
                                                 EO365MailFolder **out_mail_folder,
                                                 GCancellable *cancellable,
                                                 GError **error);
+gboolean       e_o365_connection_delete_mail_folder_sync
+                                               (EO365Connection *cnc,
+                                                const gchar *user_override, /* for which user, NULL to use 
the account user */
+                                                const gchar *folder_id,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       e_o365_connection_copy_move_mail_folder_sync
+                                               (EO365Connection *cnc,
+                                                const gchar *user_override, /* for which user, NULL to use 
the account user */
+                                                const gchar *src_folder_id,
+                                                const gchar *des_folder_id,
+                                                gboolean do_copy,
+                                                EO365MailFolder **out_mail_folder,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       e_o365_connection_rename_mail_folder_sync
+                                               (EO365Connection *cnc,
+                                                const gchar *user_override, /* for which user, NULL to use 
the account user */
+                                                const gchar *folder_id,
+                                                const gchar *display_name,
+                                                EO365MailFolder **out_mail_folder,
+                                                GCancellable *cancellable,
+                                                GError **error);
 gboolean       e_o365_connection_get_mail_messages_delta_sync
                                                (EO365Connection *cnc,
                                                 const gchar *user_override, /* for which user, NULL to use 
the account user */
diff --git a/src/Office365/common/e-o365-json-utils.h b/src/Office365/common/e-o365-json-utils.h
index 12aeecc4..1f480853 100644
--- a/src/Office365/common/e-o365-json-utils.h
+++ b/src/Office365/common/e-o365-json-utils.h
@@ -54,13 +54,13 @@ typedef enum _EO365ItemBodyContentTypeType {
 } EO365ItemBodyContentTypeType;
 
 /* Just for better readability */
-#define EO365MailFolder JsonObject
-#define EO365Recipient JsonObject
-#define EO365DateTimeWithZone JsonObject
-#define EO365FollowupFlag JsonObject
-#define EO365InternetMessageHeader JsonObject
-#define EO365ItemBody JsonObject
-#define EO365MailMessage JsonObject
+#define EO365DateTimeWithZone          JsonObject
+#define EO365FollowupFlag              JsonObject
+#define EO365InternetMessageHeader     JsonObject
+#define EO365ItemBody                  JsonObject
+#define EO365MailFolder                        JsonObject
+#define EO365MailMessage               JsonObject
+#define EO365Recipient                 JsonObject
 
 JsonArray *    e_o365_json_get_array_member            (JsonObject *object,
                                                         const gchar *member_name);
diff --git a/src/Office365/evolution/e-mail-config-o365-backend.c 
b/src/Office365/evolution/e-mail-config-o365-backend.c
index e0e76b6d..5045758f 100644
--- a/src/Office365/evolution/e-mail-config-o365-backend.c
+++ b/src/Office365/evolution/e-mail-config-o365-backend.c
@@ -83,63 +83,6 @@ mail_config_o365_backend_set_oauth2_tooltip (GtkWidget *widget,
        g_free (when_value_filled);
 }
 
-static void
-test_clicked_cb (GtkButton *button,
-                EMailConfigServiceBackend *backend)
-{
-       CamelSettings *settings;
-       ESource *source;
-       EO365Connection *cnc;
-       GSList *folders = NULL, *link;
-       gboolean success;
-       static gchar *delta_link = NULL;
-       gchar *new_delta_link = NULL;
-       GError *error = NULL;
-
-       settings = e_mail_config_service_backend_get_settings (backend);
-       source = e_mail_config_service_backend_get_collection (backend);
-
-       cnc = e_o365_connection_new (source, CAMEL_O365_SETTINGS (settings));
-       g_return_if_fail (cnc != NULL);
-
-       //success = e_o365_connection_list_mail_folders_sync (cnc, NULL, NULL, NULL, &folders, NULL, &error);
-       success = e_o365_connection_get_mail_folders_delta_sync (cnc, NULL, NULL, delta_link, 0, 
e_o365_connection_call_gather_into_slist, &folders, &new_delta_link, NULL, &error);
-
-       if (success) {
-               g_free (delta_link);
-               delta_link = new_delta_link;
-       }
-
-       if (!success) {
-               printf ("%s: failed with error: %s\n", __FUNCTION__, error ? error->message : "none");
-       } else {
-               if (error) {
-                       printf ("%s: succeeded, but has set error: '%s'\n", __FUNCTION__, error->message);
-               }
-
-               printf ("%s: returned %d objects:\n", __FUNCTION__, g_slist_length (folders));
-
-               for (link = folders; link; link = g_slist_next (link)) {
-                       JsonObject *folder = link->data;
-
-                       if (e_o365_delta_is_removed_object (folder))
-                               printf ("   %p: removed folder id:'%s'\n", folder, e_o365_mail_folder_get_id 
(folder));
-                       else
-                               printf ("   %p: '%s' childCount:%d total:%d unread:%d id:'%s' parent:'%s'\n", 
folder,
-                                       e_o365_mail_folder_get_display_name (folder),
-                                       e_o365_mail_folder_get_child_folder_count (folder),
-                                       e_o365_mail_folder_get_total_item_count (folder),
-                                       e_o365_mail_folder_get_unread_item_count (folder),
-                                       e_o365_mail_folder_get_id (folder),
-                                       e_o365_mail_folder_get_parent_folder_id (folder));
-               }
-       }
-
-       g_slist_free_full (folders, (GDestroyNotify) json_object_unref);
-       g_clear_error (&error);
-       g_clear_object (&cnc);
-}
-
 static void
 mail_config_o365_backend_insert_widgets (EMailConfigServiceBackend *backend,
                                         GtkBox *parent)
@@ -403,12 +346,6 @@ mail_config_o365_backend_insert_widgets (EMailConfigServiceBackend *backend,
        e_source_authentication_set_host (auth_extension, "graph.microsoft.com");
        e_source_authentication_set_port (auth_extension, 442);
        e_source_authentication_set_method (auth_extension, "Office365");
-
-       /* The following is for easier debugging only */                        
-       widget = gtk_button_new_with_mnemonic ("_Test");
-       g_signal_connect (widget, "clicked", G_CALLBACK (test_clicked_cb), o365_backend);
-       gtk_widget_show (widget);
-       gtk_box_pack_start (GTK_BOX (parent), widget, FALSE, FALSE, 0);
 }
 
 static void


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