[evolution-ews/wip/mcrha/office365] Read categories and sync them with mail message labels
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews/wip/mcrha/office365] Read categories and sync them with mail message labels
- Date: Mon, 29 Jun 2020 16:59:39 +0000 (UTC)
commit d96414b4abde8edabc4ff7714ec9125782ab3edf
Author: Milan Crha <mcrha redhat com>
Date: Mon Jun 29 18:59:02 2020 +0200
Read categories and sync them with mail message labels
src/Office365/camel/camel-o365-folder.c | 92 ++++++++
src/Office365/camel/camel-o365-store-summary.c | 159 ++++++++++++++
src/Office365/camel/camel-o365-store-summary.h | 19 ++
src/Office365/camel/camel-o365-store.c | 250 ++++++++++++++++++++++
src/Office365/camel/camel-o365-utils.c | 85 ++++++++
src/Office365/camel/camel-o365-utils.h | 7 +
src/Office365/common/e-o365-connection.c | 46 +++-
src/Office365/common/e-o365-connection.h | 8 +-
src/Office365/common/e-o365-json-utils.c | 63 ++++++
src/Office365/common/e-o365-json-utils.h | 5 +
src/Office365/common/e-oauth2-service-office365.c | 1 +
11 files changed, 733 insertions(+), 2 deletions(-)
---
diff --git a/src/Office365/camel/camel-o365-folder.c b/src/Office365/camel/camel-o365-folder.c
index b51382bc..231fac41 100644
--- a/src/Office365/camel/camel-o365-folder.c
+++ b/src/Office365/camel/camel-o365-folder.c
@@ -27,6 +27,7 @@
#include "camel-o365-folder-summary.h"
#include "camel-o365-store.h"
#include "camel-o365-store-summary.h"
+#include "camel-o365-utils.h"
#include "camel-o365-folder.h"
@@ -544,6 +545,95 @@ o365_folder_get_message_sync (CamelFolder *folder,
return message;
}
+static gboolean
+o365_folder_is_system_user_flag (const gchar *name)
+{
+ if (!name)
+ return FALSE;
+
+ return g_str_equal (name, "receipt-handled") ||
+ g_str_equal (name, "$has-cal");
+}
+
+static gboolean
+o365_folder_merge_server_user_flags (CamelMessageInfo *mi,
+ EO365MailMessage *mail)
+{
+ CamelFolderSummary *summary;
+ JsonArray *categories;
+ GHashTable *current_labels;
+ const CamelNamedFlags *user_flags;
+ guint ii, len;
+ gboolean changed = FALSE;
+
+ summary = camel_message_info_ref_summary (mi);
+ if (summary)
+ camel_folder_summary_lock (summary);
+ camel_message_info_property_lock (mi);
+ camel_message_info_freeze_notifications (mi);
+
+ current_labels = g_hash_table_new (g_str_hash, g_str_equal);
+
+ user_flags = camel_message_info_get_user_flags (mi);
+ len = camel_named_flags_get_length (user_flags);
+
+ /* transfer camel flags to a list */
+ for (ii = 0; ii < len; ii++) {
+ const gchar *name = camel_named_flags_get (user_flags, ii);
+
+ if (!o365_folder_is_system_user_flag (name))
+ g_hash_table_insert (current_labels, (gpointer) name, NULL);
+ }
+
+ categories = e_o365_mail_message_get_categories (mail);
+
+ if (categories) {
+ len = json_array_get_length (categories);
+
+ for (ii = 0; ii < len; ii++) {
+ const gchar *name = json_array_get_string_element (categories, ii);
+
+ name = camel_o365_utils_rename_label (name, TRUE);
+
+ if (name && *name) {
+ gchar *flag;
+
+ flag = camel_o365_utils_encode_category_name (name);
+
+ if (!g_hash_table_remove (current_labels, flag)) {
+ changed = TRUE;
+
+ camel_message_info_set_user_flag (mi, flag, TRUE);
+ }
+
+ g_free (flag);
+ }
+ }
+ }
+
+ /* Those left here are to be removed */
+ if (g_hash_table_size (current_labels)) {
+ GHashTableIter iter;
+ gpointer key;
+
+ changed = TRUE;
+
+ g_hash_table_iter_init (&iter, current_labels);
+
+ while (g_hash_table_iter_next (&iter, &key, NULL)) {
+ camel_message_info_set_user_flag (mi, key, FALSE);
+ }
+ }
+
+ camel_message_info_thaw_notifications (mi);
+ camel_message_info_property_unlock (mi);
+ if (summary)
+ camel_folder_summary_unlock (summary);
+ g_clear_object (&summary);
+
+ return changed;
+}
+
static gboolean
o365_folder_update_message_info (CamelMessageInfo *mi,
EO365MailMessage *mail)
@@ -583,6 +673,8 @@ o365_folder_update_message_info (CamelMessageInfo *mi,
changed = TRUE;
}
+ changed = o365_folder_merge_server_user_flags (mi, mail) || changed;
+
return changed;
}
diff --git a/src/Office365/camel/camel-o365-store-summary.c b/src/Office365/camel/camel-o365-store-summary.c
index 246331f0..b02271bd 100644
--- a/src/Office365/camel/camel-o365-store-summary.c
+++ b/src/Office365/camel/camel-o365-store-summary.c
@@ -22,6 +22,7 @@
#include "camel-o365-store-summary.h"
#define STORE_GROUP_NAME "##storepriv##"
+#define CATEGORIES_KEY "Categories"
#define DATA_VERSION 1
#define LOCK(_summary) g_rec_mutex_lock (&(_summary->priv->property_lock))
@@ -1257,3 +1258,161 @@ camel_o365_store_summary_connect_folder_summary (CamelO365StoreSummary *store_su
g_signal_connect_object (folder_summary, "notify::saved-count", G_CALLBACK
(o365_store_summary_folder_count_notify_cb), store_summary, 0);
g_signal_connect_object (folder_summary, "notify::unread-count", G_CALLBACK
(o365_store_summary_folder_count_notify_cb), store_summary, 0);
}
+
+static gchar *
+camel_o365_category_to_string (const CamelO365Category *cat)
+{
+ gchar *id, *display_name, *color = NULL, *str;
+
+ g_return_val_if_fail (cat != NULL, NULL);
+
+ id = g_uri_escape_string (cat->id, NULL, TRUE);
+ display_name = g_uri_escape_string (cat->display_name, NULL, TRUE);
+
+ if (cat->color)
+ color = g_uri_escape_string (cat->color, NULL, TRUE);
+
+ str = g_strconcat (
+ id ? id : "", "\t",
+ display_name ? display_name : "", "\t",
+ color ? color : "",
+ NULL);
+
+ g_free (id);
+ g_free (display_name);
+ g_free (color);
+
+ return str;
+}
+
+static CamelO365Category *
+camel_o365_category_from_string (const gchar *str)
+{
+ CamelO365Category *cat;
+ gchar **strv, *id, *display_name, *color;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ strv = g_strsplit (str, "\t", -1);
+ if (!strv || !strv[0] || !strv[1]) {
+ g_strfreev (strv);
+ return NULL;
+ }
+
+ id = g_uri_unescape_string (strv[0], NULL);
+ display_name = g_uri_unescape_string (strv[1], NULL);
+ color = (strv[2] && strv[2][0]) ? g_uri_unescape_string (strv[2], NULL) : NULL;
+
+ cat = camel_o365_category_new (id, display_name, color);
+
+ g_free (id);
+ g_free (display_name);
+ g_free (color);
+ g_strfreev (strv);
+
+ return cat;
+}
+
+GHashTable * /* gchar *id ~> CamelO365Category * */
+camel_o365_store_summary_get_categories (CamelO365StoreSummary *store_summary)
+{
+ GHashTable *categories;
+ gchar **strv;
+
+ g_return_val_if_fail (CAMEL_IS_O365_STORE_SUMMARY (store_summary), NULL);
+
+ LOCK (store_summary);
+
+ strv = g_key_file_get_string_list (store_summary->priv->key_file, STORE_GROUP_NAME, CATEGORIES_KEY,
NULL, NULL);
+
+ UNLOCK (store_summary);
+
+ categories = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, camel_o365_category_free);
+
+ if (strv) {
+ gint ii;
+
+ for (ii = 0; strv[ii]; ii++) {
+ CamelO365Category *cat;
+
+ cat = camel_o365_category_from_string (strv[ii]);
+ if (cat)
+ g_hash_table_insert (categories, cat->id, cat);
+ }
+
+ g_strfreev (strv);
+ }
+
+ return categories;
+}
+
+void
+camel_o365_store_summary_set_categories (CamelO365StoreSummary *store_summary,
+ GHashTable *categories) /* gchar *id ~> CamelO365Category * */
+{
+ GPtrArray *array;
+ GHashTableIter iter;
+ gpointer value;
+
+ g_return_if_fail (CAMEL_IS_O365_STORE_SUMMARY (store_summary));
+ g_return_if_fail (categories != NULL);
+
+ array = g_ptr_array_new_full (g_hash_table_size (categories), g_free);
+
+ g_hash_table_iter_init (&iter, categories);
+
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ CamelO365Category *cat = value;
+
+ if (cat) {
+ gchar *str;
+
+ str = camel_o365_category_to_string (cat);
+
+ if (str)
+ g_ptr_array_add (array, str);
+ }
+ }
+
+ LOCK (store_summary);
+
+ g_key_file_set_string_list (store_summary->priv->key_file, STORE_GROUP_NAME, CATEGORIES_KEY,
+ (const gchar * const *) array->pdata, array->len);
+
+ store_summary->priv->dirty = TRUE;
+
+ UNLOCK (store_summary);
+
+ g_ptr_array_free (array, TRUE);
+}
+
+CamelO365Category *
+camel_o365_category_new (const gchar *id,
+ const gchar *display_name,
+ const gchar *color)
+{
+ CamelO365Category *cat;
+
+ g_return_val_if_fail (id != NULL, NULL);
+ g_return_val_if_fail (display_name != NULL, NULL);
+
+ cat = g_slice_new0 (CamelO365Category);
+ cat->id = g_strdup (id);
+ cat->display_name = g_strdup (display_name);
+ cat->color = g_strdup (color);
+
+ return cat;
+}
+
+void
+camel_o365_category_free (gpointer ptr)
+{
+ CamelO365Category *cat = ptr;
+
+ if (cat) {
+ g_free (cat->id);
+ g_free (cat->display_name);
+ g_free (cat->color);
+ g_slice_free (CamelO365Category, cat);
+ }
+}
diff --git a/src/Office365/camel/camel-o365-store-summary.h b/src/Office365/camel/camel-o365-store-summary.h
index 670f739b..c4f3bfb3 100644
--- a/src/Office365/camel/camel-o365-store-summary.h
+++ b/src/Office365/camel/camel-o365-store-summary.h
@@ -175,6 +175,25 @@ CamelFolderInfo *
void camel_o365_store_summary_connect_folder_summary
(CamelO365StoreSummary *store_summary,
CamelFolderSummary *folder_summary);
+
+typedef struct _CamelO365Category {
+ gchar *id;
+ gchar *display_name;
+ gchar *color;
+} CamelO365Category;
+
+GHashTable * camel_o365_store_summary_get_categories /* gchar *id ~> CamelO365Category * */
+ (CamelO365StoreSummary *store_summary);
+void camel_o365_store_summary_set_categories
+ (CamelO365StoreSummary *store_summary,
+ GHashTable *categories); /* gchar *id ~> CamelO365Category *
*/
+
+CamelO365Category *
+ camel_o365_category_new (const gchar *id,
+ const gchar *display_name,
+ const gchar *color);
+void camel_o365_category_free (gpointer ptr); /* CamelO365Category * */
+
G_END_DECLS
#endif /* CAMEL_O365_STORE_SUMMARY_H */
diff --git a/src/Office365/camel/camel-o365-store.c b/src/Office365/camel/camel-o365-store.c
index a648b2fe..ee1474b4 100644
--- a/src/Office365/camel/camel-o365-store.c
+++ b/src/Office365/camel/camel-o365-store.c
@@ -20,6 +20,8 @@
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
+#include <e-util/e-util.h>
+
#include "common/camel-o365-settings.h"
#include "common/e-o365-connection.h"
#include "camel-o365-folder.h"
@@ -259,6 +261,246 @@ o365_store_read_default_folders (CamelO365Store *o365_store,
return success;
}
+static gboolean
+o365_store_equal_label_tag_cb (gconstpointer ptr1,
+ gconstpointer ptr2)
+{
+ const gchar *evo_label_def = ptr1;
+ const gchar *tag = ptr2;
+ const gchar *pos;
+
+ if (!evo_label_def || !tag || !*tag)
+ return FALSE;
+
+ pos = g_strrstr (evo_label_def, tag);
+
+ return pos > evo_label_def && pos[-1] == '|' && !pos[strlen (tag)];
+}
+
+static gboolean
+o365_store_find_in_ptr_array (GPtrArray *haystack,
+ gconstpointer needle,
+ GEqualFunc equal_func,
+ guint *out_index)
+{
+ guint ii;
+
+ if (!haystack)
+ return FALSE;
+
+ if (!equal_func)
+ equal_func = g_direct_equal;
+
+ for (ii = 0; ii < haystack->len; ii++) {
+ if (equal_func (haystack->pdata[ii], needle)) {
+ if (out_index)
+ *out_index = ii;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* Returns whether had been done any changes */
+static gboolean
+o365_store_save_category_changes (GHashTable *old_categories, /* gchar *id ~> CamelO365Category * */
+ GHashTable *new_categories) /* gchar *id ~> CamelO365Category * */
+{
+ GHashTableIter iter;
+ GSettings *settings;
+ GPtrArray *evo_labels; /* gchar * (encoded label definition) */
+ gchar **strv;
+ gint ii;
+ gpointer value;
+ gboolean changed = FALSE;
+
+ if (!old_categories || !new_categories)
+ return new_categories != NULL;
+
+ evo_labels = g_ptr_array_new_full (5, g_free);
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ strv = g_settings_get_strv (settings, "labels");
+
+ for (ii = 0; strv && strv[ii]; ii++) {
+ g_ptr_array_add (evo_labels, g_strdup (strv[ii]));
+ }
+
+ g_strfreev (strv);
+
+ g_hash_table_iter_init (&iter, new_categories);
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ CamelO365Category *new_cat = value, *old_cat;
+ gchar *tag = NULL;
+
+ if (!new_cat)
+ continue;
+
+ old_cat = g_hash_table_lookup (old_categories, new_cat->id);
+ if (old_cat) {
+ if (g_strcmp0 (old_cat->display_name, new_cat->display_name) != 0 ||
+ g_strcmp0 (old_cat->color, new_cat->color) != 0) {
+ /* Old category changed name or color */
+ tag = camel_o365_utils_encode_category_name (new_cat->display_name);
+ }
+ } else {
+ /* This is a new category */
+ tag = camel_o365_utils_encode_category_name (new_cat->display_name);
+ }
+
+ if (tag && *tag) {
+ guint index = (guint) -1;
+ gchar *label_def;
+
+ changed = TRUE;
+
+ /* Sanitize value */
+ for (ii = 0; tag[ii]; ii++) {
+ if (tag[ii] == '|')
+ tag[ii] = '-';
+ }
+
+ if (old_cat && g_strcmp0 (old_cat->display_name, new_cat->display_name) != 0) {
+ gchar *old_tag = camel_o365_utils_encode_category_name
(old_cat->display_name);
+
+ if (old_tag && *old_tag) {
+ if (!o365_store_find_in_ptr_array (evo_labels, old_tag,
o365_store_equal_label_tag_cb, &index))
+ index = (guint) -1;
+ }
+
+ g_free (old_tag);
+ }
+
+ for (ii = 0; new_cat->display_name[ii]; ii++) {
+ if (new_cat->display_name[ii] == '|')
+ new_cat->display_name[ii] = '-';
+ }
+
+ if (index == (guint) -1 &&
+ !o365_store_find_in_ptr_array (evo_labels, tag, o365_store_equal_label_tag_cb,
&index))
+ index = (guint) -1;
+
+ label_def = g_strconcat (new_cat->display_name, "|", new_cat->color ? new_cat->color
: "#FF0000", "|", tag, NULL);
+
+ if (index == (guint) -1 || index >= (gint) evo_labels->len) {
+ g_ptr_array_add (evo_labels, label_def);
+ } else {
+ g_free (evo_labels->pdata[index]);
+ evo_labels->pdata[index] = label_def;
+ }
+ }
+
+ g_hash_table_remove (old_categories, new_cat->id);
+
+ g_free (tag);
+ }
+
+ if (g_hash_table_size (old_categories) > 0) {
+ /* Some categories had been removed */
+ changed = TRUE;
+
+ g_hash_table_iter_init (&iter, old_categories);
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ CamelO365Category *old_cat = value;
+ gchar *old_tag;
+ guint index;
+
+ if (!old_cat)
+ continue;
+
+ old_tag = camel_o365_utils_encode_category_name (old_cat->display_name);
+
+ for (ii = 0; old_tag && old_tag[ii]; ii++) {
+ if (old_tag[ii] == '|')
+ old_tag[ii] = '-';
+ }
+
+ if (old_tag &&
+ o365_store_find_in_ptr_array (evo_labels, old_tag, o365_store_equal_label_tag_cb,
&index))
+ g_ptr_array_remove_index (evo_labels, index);
+
+ g_free (old_tag);
+ }
+ }
+
+ if (changed) {
+ /* NULL-terminated array of strings */
+ g_ptr_array_add (evo_labels, NULL);
+
+ g_settings_set_strv (settings, "labels", (const gchar * const *) evo_labels->pdata);
+ }
+
+ g_ptr_array_free (evo_labels, TRUE);
+ g_object_unref (settings);
+
+ return changed;
+}
+
+static void
+o365_store_get_categories_cb (CamelSession *session,
+ GCancellable *cancellable,
+ gpointer user_data,
+ GError **error)
+{
+ CamelO365Store *o365_store = user_data;
+ EO365Connection *cnc;
+ GSList *categories = NULL;
+
+ g_return_if_fail (CAMEL_IS_O365_STORE (o365_store));
+
+ cnc = camel_o365_store_ref_connection (o365_store);
+
+ if (!cnc)
+ return;
+
+ if (e_o365_connection_get_categories_sync (cnc, NULL, &categories, cancellable, error)) {
+ GHashTable *old_categories, *new_categories;
+ GSList *link;
+
+ new_categories = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
camel_o365_category_free);
+
+ for (link = categories; link; link = g_slist_next (link)) {
+ EO365Category *category = link->data;
+ CamelO365Category *cat;
+ const gchar *id, *display_name, *color;
+
+ if (!category)
+ continue;
+
+ id = e_o365_category_get_id (category);
+ display_name = e_o365_category_get_display_name (category);
+ color = e_o365_category_get_color (category);
+
+ if (!id || !display_name)
+ continue;
+
+ if (display_name != camel_o365_utils_rename_label (display_name, TRUE))
+ continue;
+
+ cat = camel_o365_category_new (id, display_name, color);
+
+ if (cat)
+ g_hash_table_insert (new_categories, cat->id, cat);
+ }
+
+ g_slist_free_full (categories, (GDestroyNotify) json_object_unref);
+
+ old_categories = camel_o365_store_summary_get_categories (o365_store->priv->summary);
+
+ if (o365_store_save_category_changes (old_categories, new_categories)) {
+ camel_o365_store_summary_set_categories (o365_store->priv->summary, new_categories);
+ camel_o365_store_summary_save (o365_store->priv->summary, NULL);
+ }
+
+ g_hash_table_destroy (new_categories);
+ g_hash_table_destroy (old_categories);
+ }
+
+ g_object_unref (cnc);
+}
+
static gboolean
o365_store_connect_sync (CamelService *service,
GCancellable *cancellable,
@@ -293,6 +535,14 @@ o365_store_connect_sync (CamelService *service,
success = camel_session_authenticate_sync (session, service, "Office365", cancellable, error);
+ if (success) {
+ camel_session_submit_job (
+ session, _("Look up Office 365 categories"),
+ o365_store_get_categories_cb,
+ g_object_ref (o365_store),
+ g_object_unref);
+ }
+
g_clear_object (&session);
g_clear_object (&cnc);
} else {
diff --git a/src/Office365/camel/camel-o365-utils.c b/src/Office365/camel/camel-o365-utils.c
index 0d96872f..fa6f11bb 100644
--- a/src/Office365/camel/camel-o365-utils.c
+++ b/src/Office365/camel/camel-o365-utils.c
@@ -91,3 +91,88 @@ camel_o365_utils_new_connection (CamelService *service,
return cnc;
}
+
+/* From Outlook name (which allows spaces) to Evolution name */
+gchar *
+camel_o365_utils_encode_category_name (const gchar *name)
+{
+ if (name && strchr (name, ' ')) {
+ GString *str;
+
+ str = g_string_sized_new (strlen (name) + 16);
+
+ while (*name) {
+ if (*name == '_')
+ g_string_append_c (str, '_');
+
+ g_string_append_c (str, *name == ' ' ? '_' : *name);
+
+ name++;
+ }
+
+ return g_string_free (str, FALSE);
+ }
+
+ return g_strdup (name);
+}
+
+/* From Evolution name to Outlook name (which allows spaces) */
+gchar *
+camel_o365_utils_decode_category_name (const gchar *flag)
+{
+ if (flag && strchr (flag, '_')) {
+ GString *str = g_string_sized_new (strlen (flag));
+
+ while (*flag) {
+ if (*flag == '_') {
+ if (flag[1] == '_') {
+ g_string_append_c (str, '_');
+ flag++;
+ } else {
+ g_string_append_c (str, ' ');
+ }
+ } else {
+ g_string_append_c (str, *flag);
+ }
+
+ flag++;
+ }
+
+ return g_string_free (str, FALSE);
+ }
+
+ return g_strdup (flag);
+}
+
+const gchar *
+camel_o365_utils_rename_label (const gchar *cat,
+ gboolean from_cat)
+{
+ gint ii;
+
+ /* This is a mapping from Outlook categories to
+ * Evolution labels based on the standard colors */
+ const gchar *labels[] = {
+ "Red Category", "$Labelimportant",
+ "Orange Category", "$Labelwork",
+ "Green Category", "$Labelpersonal",
+ "Blue Category", "$Labeltodo",
+ "Purple Category", "$Labellater",
+ NULL, NULL
+ };
+
+ if (!cat || !*cat)
+ return "";
+
+ for (ii = 0; labels[ii]; ii += 2) {
+ if (from_cat) {
+ if (!g_ascii_strcasecmp (cat, labels[ii]))
+ return labels[ii + 1];
+ } else {
+ if (!g_ascii_strcasecmp (cat, labels[ii + 1]))
+ return labels[ii];
+ }
+ }
+
+ return cat;
+}
diff --git a/src/Office365/camel/camel-o365-utils.h b/src/Office365/camel/camel-o365-utils.h
index dfca2254..6c4c507e 100644
--- a/src/Office365/camel/camel-o365-utils.h
+++ b/src/Office365/camel/camel-o365-utils.h
@@ -25,5 +25,12 @@
EO365Connection *
camel_o365_utils_new_connection (CamelService *service,
GCancellable *cancellable);
+gchar * camel_o365_utils_encode_category_name
+ (const gchar *name);
+gchar * camel_o365_utils_decode_category_name
+ (const gchar *flag);
+const gchar * camel_o365_utils_rename_label (const gchar *cat,
+ gboolean from_cat);
+
#endif /* CAMEL_O365_UTILS_H */
diff --git a/src/Office365/common/e-o365-connection.c b/src/Office365/common/e-o365-connection.c
index 31cd7791..d1e95bc3 100644
--- a/src/Office365/common/e-o365-connection.c
+++ b/src/Office365/common/e-o365-connection.c
@@ -2111,6 +2111,50 @@ e_o365_connection_call_gather_into_slist (EO365Connection *cnc,
return TRUE;
}
+/*
https://docs.microsoft.com/en-us/graph/api/outlookuser-list-mastercategories?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_get_categories_sync (EO365Connection *cnc,
+ const gchar *user_override,
+ GSList **out_categories, /* EO365Category * */
+ GCancellable *cancellable,
+ GError **error)
+{
+ EO365ResponseData rd;
+ SoupMessage *message;
+ gchar *uri;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (out_categories != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "outlook",
+ "masterCategories",
+ NULL,
+ NULL);
+
+ message = o365_connection_new_soup_message (SOUP_METHOD_GET, uri, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ memset (&rd, 0, sizeof (EO365ResponseData));
+
+ rd.out_items = out_categories;
+
+ success = o365_connection_send_request_sync (cnc, message, e_o365_read_valued_response_cb, NULL, &rd,
cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
/* https://docs.microsoft.com/en-us/graph/api/user-list-mailfolders?view=graph-rest-1.0&tabs=http */
gboolean
@@ -2118,7 +2162,7 @@ e_o365_connection_list_mail_folders_sync (EO365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use the
account user */
const gchar *from_path, /* path for the folder to read, NULL for
top user folder */
const gchar *select, /* properties to select, nullable */
- GSList **out_folders, /* JsonObject * - the returned mailFolder
objects */
+ GSList **out_folders, /* EO365MailFolder * - the returned
mailFolder objects */
GCancellable *cancellable,
GError **error)
{
diff --git a/src/Office365/common/e-o365-connection.h b/src/Office365/common/e-o365-connection.h
index 4335190e..ee7ea81a 100644
--- a/src/Office365/common/e-o365-connection.h
+++ b/src/Office365/common/e-o365-connection.h
@@ -159,12 +159,18 @@ gboolean e_o365_connection_call_gather_into_slist
gpointer user_data, /* expects GSList **, aka pointer to a
GSList *, where it copies the 'results' */
GCancellable *cancellable,
GError **error);
+gboolean e_o365_connection_get_categories_sync
+ (EO365Connection *cnc,
+ const gchar *user_override,
+ GSList **out_categories, /* EO365Category * */
+ GCancellable *cancellable,
+ GError **error);
gboolean e_o365_connection_list_mail_folders_sync
(EO365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use
the account user */
const gchar *from_path, /* path for the folder to read, NULL
for top user folder */
const gchar *select, /* properties to select, nullable */
- GSList **out_folders, /* JsonObject * - the returned
mailFolder objects */
+ GSList **out_folders, /* EO365MailFolder * - the returned
mailFolder objects */
GCancellable *cancellable,
GError **error);
gboolean e_o365_connection_get_mail_folders_delta_sync
diff --git a/src/Office365/common/e-o365-json-utils.c b/src/Office365/common/e-o365-json-utils.c
index 7e86ea52..9b50c3f7 100644
--- a/src/Office365/common/e-o365-json-utils.c
+++ b/src/Office365/common/e-o365-json-utils.c
@@ -190,6 +190,69 @@ e_o365_delta_is_removed_object (JsonObject *object)
return json_object_has_member (object, "@removed");
}
+/* https://docs.microsoft.com/en-us/graph/api/resources/outlookcategory?view=graph-rest-1.0 */
+
+const gchar *
+e_o365_category_get_display_name (EO365Category *category)
+{
+ return e_o365_json_get_string_member (category, "displayName", NULL);
+}
+
+const gchar *
+e_o365_category_get_id (EO365Category *category)
+{
+ return e_o365_json_get_string_member (category, "id", NULL);
+}
+
+const gchar *
+e_o365_category_get_color (EO365Category *category)
+{
+ const gchar *colors_array[] = {
+ "#ff1a36", /* Red */
+ "#ff8c00", /* Orange */
+ "#f4b10b", /* Peach */
+ "#fff100", /* Yellow */
+ "#009e48", /* Green */
+ "#00b294", /* Teal */
+ "#89933f", /* Olive */
+ "#00bcf2", /* Blue */
+ "#8e69df", /* Purple */
+ "#f30092", /* Maroon */
+ "#6c7e9a", /* Steel */
+ "#425066", /* DarkSteel */
+ "#969696", /* Gray */
+ "#525552", /* DarkGray */
+ "#282828", /* Black */
+ "#a00023", /* DarkRed */
+ "#c45502", /* DarkOrange */
+ "#af7000", /* DarkPeach */
+ "#b59b02", /* DarkYellow */
+ "#176002", /* DarkGreen */
+ "#00725c", /* DarkTeal */
+ "#5c6022", /* DarkOlive */
+ "#036393", /* DarkBlue */
+ "#422f8e", /* DarkPurple */
+ "#960269" /* DarkMaroon */
+ };
+ const gchar *color_str;
+ gchar *enptr = NULL;
+ gint color_index;
+
+ color_str = e_o365_json_get_string_member (category, "color", NULL);
+
+ if (!color_str ||
+ g_ascii_strcasecmp (color_str, "None") == 0 ||
+ g_ascii_strncasecmp (color_str, "preset", 6) != 0)
+ return NULL;
+
+ color_index = (gint) g_ascii_strtoll (color_str + 6, &enptr, 10);
+
+ if (enptr != color_str && color_index >= 0 && color_index < G_N_ELEMENTS (colors_array))
+ return colors_array[color_index];
+
+ return NULL;
+}
+
/* https://docs.microsoft.com/en-us/graph/api/resources/mailfolder?view=graph-rest-1.0 */
const gchar *
diff --git a/src/Office365/common/e-o365-json-utils.h b/src/Office365/common/e-o365-json-utils.h
index 1f480853..fb562900 100644
--- a/src/Office365/common/e-o365-json-utils.h
+++ b/src/Office365/common/e-o365-json-utils.h
@@ -54,6 +54,7 @@ typedef enum _EO365ItemBodyContentTypeType {
} EO365ItemBodyContentTypeType;
/* Just for better readability */
+#define EO365Category JsonObject
#define EO365DateTimeWithZone JsonObject
#define EO365FollowupFlag JsonObject
#define EO365InternetMessageHeader JsonObject
@@ -87,6 +88,10 @@ time_t e_o365_get_date_time_offset_member (JsonObject *object,
gboolean e_o365_delta_is_removed_object (JsonObject *object);
+const gchar * e_o365_category_get_display_name (EO365Category *category);
+const gchar * e_o365_category_get_id (EO365Category *category);
+const gchar * e_o365_category_get_color (EO365Category *category);
+
const gchar * e_o365_mail_folder_get_display_name (EO365MailFolder *folder);
const gchar * e_o365_mail_folder_get_id (EO365MailFolder *folder);
const gchar * e_o365_mail_folder_get_parent_folder_id (EO365MailFolder *folder);
diff --git a/src/Office365/common/e-oauth2-service-office365.c
b/src/Office365/common/e-oauth2-service-office365.c
index aaf28744..57a05dc9 100644
--- a/src/Office365/common/e-oauth2-service-office365.c
+++ b/src/Office365/common/e-oauth2-service-office365.c
@@ -38,6 +38,7 @@
"Mail.ReadWrite.Shared " \
"Mail.Send " \
"Mail.Send.Shared " \
+ "MailboxSettings.Read " \
"Notes.Create " \
"Notes.ReadWrite.All " \
"offline_access " \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]