[evolution-ews/wip/mcrha/office365] Implement create mail folder



commit 63e34a3f7d27859bbedcc6f7d796ac7753d909a6
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jun 24 22:36:00 2020 +0200

    Implement create mail folder

 src/Office365/camel/camel-o365-store-summary.c |  46 +++++++++
 src/Office365/camel/camel-o365-store-summary.h |   2 +
 src/Office365/camel/camel-o365-store.c         | 125 +++++++++++++++++++++++-
 src/Office365/common/e-o365-connection.c       | 127 +++++++++++++++++++++----
 src/Office365/common/e-o365-connection.h       |   8 ++
 5 files changed, 289 insertions(+), 19 deletions(-)
---
diff --git a/src/Office365/camel/camel-o365-store-summary.c b/src/Office365/camel/camel-o365-store-summary.c
index 163d3a43..619f01ac 100644
--- a/src/Office365/camel/camel-o365-store-summary.c
+++ b/src/Office365/camel/camel-o365-store-summary.c
@@ -466,6 +466,24 @@ camel_o365_store_summary_has_folder (CamelO365StoreSummary *store_summary,
        return has;
 }
 
+gboolean
+camel_o365_store_summary_has_full_name (CamelO365StoreSummary *store_summary,
+                                       const gchar *full_name)
+{
+       gboolean has;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE_SUMMARY (store_summary), FALSE);
+       g_return_val_if_fail (full_name != NULL, FALSE);
+
+       LOCK (store_summary);
+
+       has = g_hash_table_contains (store_summary->priv->full_name_id_hash, full_name);
+
+       UNLOCK (store_summary);
+
+       return has;
+}
+
 void
 camel_o365_store_summary_remove_folder (CamelO365StoreSummary *store_summary,
                                        const gchar *id)
@@ -852,6 +870,34 @@ camel_o365_store_summary_set_folder_display_name (CamelO365StoreSummary *store_s
 
                                g_slist_free_full (rpd.removed, id_full_name_data_free);
                                g_free (new_full_name);
+                       } else {
+                               gchar *parent_id, *encoded_folder_name, *id_copy, *new_full_name = NULL;
+
+                               encoded_folder_name = o365_store_summary_encode_folder_name (display_name);
+
+                               parent_id = camel_o365_store_summary_dup_folder_parent_id (store_summary, id);
+
+                               if (parent_id && *parent_id) {
+                                       const gchar *parent_full_name;
+
+                                       parent_full_name = g_hash_table_lookup 
(store_summary->priv->id_full_name_hash, parent_id);
+
+                                       if (parent_full_name && *parent_full_name)
+                                               new_full_name = g_strconcat (parent_full_name, "/", 
encoded_folder_name, NULL);
+                               }
+
+                               if (!new_full_name) {
+                                       new_full_name = encoded_folder_name;
+                                       encoded_folder_name = NULL;
+                               }
+
+                               g_free (encoded_folder_name);
+                               g_free (parent_id);
+
+                               id_copy = g_strdup (id);
+
+                               g_hash_table_insert (store_summary->priv->id_full_name_hash, id_copy, 
new_full_name);
+                               g_hash_table_insert (store_summary->priv->full_name_id_hash, new_full_name, 
id_copy);
                        }
                }
        }
diff --git a/src/Office365/camel/camel-o365-store-summary.h b/src/Office365/camel/camel-o365-store-summary.h
index a83783e9..670f739b 100644
--- a/src/Office365/camel/camel-o365-store-summary.h
+++ b/src/Office365/camel/camel-o365-store-summary.h
@@ -73,6 +73,8 @@ void          camel_o365_store_summary_set_delta_link (CamelO365StoreSummary *store_summ
 gchar *                camel_o365_store_summary_dup_delta_link (CamelO365StoreSummary *store_summary);
 gboolean       camel_o365_store_summary_has_folder     (CamelO365StoreSummary *store_summary,
                                                         const gchar *id);
+gboolean       camel_o365_store_summary_has_full_name  (CamelO365StoreSummary *store_summary,
+                                                        const gchar *full_name);
 void           camel_o365_store_summary_remove_folder  (CamelO365StoreSummary *store_summary,
                                                         const gchar *id);
 void           camel_o365_store_summary_set_folder     (CamelO365StoreSummary *store_summary,
diff --git a/src/Office365/camel/camel-o365-store.c b/src/Office365/camel/camel-o365-store.c
index 4771eec4..adf925f8 100644
--- a/src/Office365/camel/camel-o365-store.c
+++ b/src/Office365/camel/camel-o365-store.c
@@ -415,6 +415,100 @@ o365_store_save_summary_locked (CamelO365StoreSummary *summary,
        g_clear_error (&error);
 }
 
+static CamelFolderInfo *
+o365_store_create_folder_sync (CamelStore *store,
+                              const gchar *parent_name,
+                              const gchar *folder_name,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+       CamelO365Store *o365_store;
+       EO365MailFolder *mail_folder = NULL;
+       gchar *fid = NULL;
+       gchar *full_name;
+       EO365Connection *cnc;
+       CamelFolderInfo *fi = NULL;
+       guint32 flags;
+       gboolean success;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_O365_STORE (store), NULL);
+
+       o365_store = CAMEL_O365_STORE (store);
+
+       if (parent_name && *parent_name)
+               full_name = g_strdup_printf ("%s/%s", parent_name, folder_name);
+       else
+               full_name = g_strdup (folder_name);
+
+       fid = camel_o365_store_summary_dup_folder_id_for_full_name (o365_store->priv->summary, full_name);
+
+       if (fid) {
+               g_free (fid);
+               g_set_error (
+                       error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                       _("Cannot create folder “%s”, folder already exists"),
+                       full_name);
+               g_free (full_name);
+               return NULL;
+       }
+
+       g_free (full_name);
+
+       /* Get Parent folder ID */
+       if (parent_name && parent_name[0]) {
+               fid = camel_o365_store_summary_dup_folder_id_for_full_name (o365_store->priv->summary, 
parent_name);
+
+               if (!fid) {
+                       g_set_error (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                               _("Parent folder “%s” does not exist"),
+                               parent_name);
+                       return NULL;
+               }
+       }
+
+       if (!camel_o365_store_ensure_connected (o365_store, &cnc, cancellable, error)) {
+               g_free (fid);
+
+               return NULL;
+       }
+
+       success = e_o365_connection_create_mail_folder_sync (cnc, NULL, fid, folder_name, &mail_folder, 
cancellable, &local_error);
+
+       g_object_unref (cnc);
+       g_free (fid);
+
+       if (!success) {
+               camel_o365_store_maybe_disconnect (o365_store, local_error);
+               g_propagate_error (error, local_error);
+
+               return NULL;
+       }
+
+       flags = e_o365_mail_folder_get_child_folder_count (mail_folder) ? CAMEL_STORE_INFO_FOLDER_CHILDREN : 
CAMEL_STORE_INFO_FOLDER_NOCHILDREN;
+
+       camel_o365_store_summary_set_folder (o365_store->priv->summary, TRUE,
+               e_o365_mail_folder_get_id (mail_folder),
+               e_o365_mail_folder_get_parent_folder_id (mail_folder),
+               e_o365_mail_folder_get_display_name (mail_folder),
+               e_o365_mail_folder_get_total_item_count (mail_folder),
+               e_o365_mail_folder_get_unread_item_count (mail_folder),
+               flags, E_O365_FOLDER_KIND_MAIL, FALSE, FALSE);
+
+       fi = camel_o365_store_summary_build_folder_info_for_id (o365_store->priv->summary, 
e_o365_mail_folder_get_id (mail_folder));
+
+       camel_store_folder_created (store, fi);
+       camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (o365_store), fi);
+
+       json_object_unref (mail_folder);
+
+       LOCK (o365_store);
+       o365_store_save_summary_locked (o365_store->priv->summary, G_STRFUNC);
+       UNLOCK (o365_store);
+
+       return fi;
+}
+
 typedef struct _FolderRenamedData {
        gchar *id;
        gchar *old_name;
@@ -845,6 +939,33 @@ o365_store_can_refresh_folder (CamelStore *store,
        return CAMEL_STORE_CLASS (camel_o365_store_parent_class)->can_refresh_folder (store, info, error);
 }
 
+static gboolean
+o365_store_folder_is_subscribed (CamelSubscribable *subscribable,
+                                const gchar *folder_name)
+{
+       CamelO365Store *o365_store = CAMEL_O365_STORE (subscribable);
+
+       return camel_o365_store_summary_has_full_name (o365_store->priv->summary, folder_name);
+}
+
+static gboolean
+o365_store_subscribe_folder_sync (CamelSubscribable *subscribable,
+                                 const gchar *folder_name,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       return TRUE;
+}
+
+static gboolean
+o365_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
+                                   const gchar *folder_name,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+       return TRUE;
+}
+
 static void
 o365_store_set_property (GObject *object,
                         guint property_id,
@@ -956,8 +1077,8 @@ camel_o365_store_class_init (CamelO365StoreClass *class)
 
        store_class = CAMEL_STORE_CLASS (class);
        store_class->get_folder_sync = o365_store_get_folder_sync;
-#if 0
        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
@@ -979,11 +1100,9 @@ camel_o365_store_initable_init (GInitableIface *iface)
 static void
 camel_o365_subscribable_init (CamelSubscribableInterface *iface)
 {
-#if 0
        iface->folder_is_subscribed = o365_store_folder_is_subscribed;
        iface->subscribe_folder_sync = o365_store_subscribe_folder_sync;
        iface->unsubscribe_folder_sync = o365_store_unsubscribe_folder_sync;
-#endif
 }
 
 static void
diff --git a/src/Office365/common/e-o365-connection.c b/src/Office365/common/e-o365-connection.c
index e1855790..6df4ba51 100644
--- a/src/Office365/common/e-o365-connection.c
+++ b/src/Office365/common/e-o365-connection.c
@@ -1407,6 +1407,31 @@ e_o365_read_valued_response_cb (EO365Connection *cnc,
        return can_continue;
 }
 
+static gboolean
+e_o365_read_json_object_response_cb (EO365Connection *cnc,
+                                    SoupMessage *message,
+                                    GInputStream *input_stream,
+                                    JsonNode *node,
+                                    gpointer user_data,
+                                    gchar **out_next_link,
+                                    GCancellable *cancellable,
+                                    GError **error)
+{
+       JsonObject **out_json_object = user_data;
+       JsonObject *object;
+
+       g_return_val_if_fail (out_json_object != NULL, FALSE);
+       g_return_val_if_fail (out_next_link != NULL, FALSE);
+       g_return_val_if_fail (JSON_NODE_HOLDS_OBJECT (node), FALSE);
+
+       object = json_node_get_object (node);
+       g_return_val_if_fail (object != NULL, FALSE);
+
+       *out_json_object = json_object_ref (object);
+
+       return TRUE;
+}
+
 gboolean
 e_o365_connection_get_ssl_error_details (EO365Connection *cnc,
                                         gchar **out_certificate_pem,
@@ -1660,6 +1685,34 @@ e_o365_connection_construct_uri (EO365Connection *cnc,
        return g_string_free (uri, FALSE);
 }
 
+static void
+e_o365_connection_set_json_body (SoupMessage *message,
+                                JsonBuilder *builder)
+{
+       JsonGenerator *generator;
+       JsonNode *node;
+       gchar *data;
+       gsize data_length = 0;
+
+       g_return_if_fail (SOUP_IS_MESSAGE (message));
+       g_return_if_fail (builder != NULL);
+
+       node = json_builder_get_root (builder);
+
+       generator = json_generator_new ();
+       json_generator_set_root (generator, node);
+
+       data = json_generator_to_data (generator, &data_length);
+
+       soup_message_headers_append (message->request_headers, "Content-Type", "application/json");
+
+       if (data)
+               soup_message_body_append_take (message->request_body, (guchar *) data, data_length);
+
+       g_object_unref (generator);
+       json_node_unref (node);
+}
+
 static void
 e_o365_fill_message_headers_cb (JsonObject *object,
                                const gchar *member_name,
@@ -1772,11 +1825,8 @@ e_o365_connection_batch_request_internal_sync (EO365Connection *cnc,
 {
        SoupMessage *message;
        JsonBuilder *builder;
-       JsonGenerator *generator;
-       JsonNode *node;
        gboolean success;
-       gchar *uri, buff[128], *data;
-       gsize data_length = 0;
+       gchar *uri, buff[128];
        guint ii;
 
        g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
@@ -1888,22 +1938,11 @@ e_o365_connection_batch_request_internal_sync (EO365Connection *cnc,
        json_builder_end_array (builder);
        json_builder_end_object (builder);
 
-       node = json_builder_get_root (builder);
-
-       generator = json_generator_new ();
-       json_generator_set_root (generator, node);
-
-       data = json_generator_to_data (generator, &data_length);
+       e_o365_connection_set_json_body (message, builder);
 
-       soup_message_headers_append (message->request_headers, "Content-Type", "application/json");
        soup_message_headers_append (message->request_headers, "Accept", "application/json");
 
-       if (data)
-               soup_message_body_append_take (message->request_body, (guchar *) data, data_length);
-
-       json_node_unref (node);
        g_object_unref (builder);
-       g_object_unref (generator);
 
        success = o365_connection_send_request_sync (cnc, message, e_o365_read_batch_response_cb, NULL, 
requests, cancellable, error);
 
@@ -2145,6 +2184,62 @@ e_o365_connection_get_mail_folders_delta_sync (EO365Connection *cnc,
        return success;
 }
 
+/* https://docs.microsoft.com/en-us/graph/api/user-post-mailfolders?view=graph-rest-1.0&tabs=http
+   https://docs.microsoft.com/en-us/graph/api/mailfolder-post-childfolders?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_create_mail_folder_sync (EO365Connection *cnc,
+                                          const gchar *user_override, /* for which user, NULL to use the 
account user */
+                                          const gchar *parent_folder_id, /* NULL for the folder root */
+                                          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 (display_name != NULL, FALSE);
+       g_return_val_if_fail (out_mail_folder != NULL, FALSE);
+
+       uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+               "mailFolders",
+               parent_folder_id,
+               parent_folder_id ? "childFolders" : NULL,
+               NULL);
+
+       message = soup_message_new (SOUP_METHOD_POST, uri);
+
+       if (!message) {
+               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: “%s”"), uri);
+               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/message-delta?view=graph-rest-1.0&tabs=http */
 
 gboolean
diff --git a/src/Office365/common/e-o365-connection.h b/src/Office365/common/e-o365-connection.h
index 9854e02f..cc1de355 100644
--- a/src/Office365/common/e-o365-connection.h
+++ b/src/Office365/common/e-o365-connection.h
@@ -178,6 +178,14 @@ gboolean   e_o365_connection_get_mail_folders_delta_sync
                                                 gchar **out_delta_link,
                                                 GCancellable *cancellable,
                                                 GError **error);
+gboolean       e_o365_connection_create_mail_folder_sync
+                                               (EO365Connection *cnc,
+                                                const gchar *user_override, /* for which user, NULL to use 
the account user */
+                                                const gchar *parent_folder_id, /* NULL for the folder root */
+                                                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 */


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