Blame SOURCES/evolution-ews-3.28.5-sync-category-list.patch

acc9f3
diff -up evolution-ews-3.28.5/src/camel/camel-ews-store.c.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-store.c
acc9f3
--- evolution-ews-3.28.5/src/camel/camel-ews-store.c.sync-category-list	2019-10-24 09:39:08.336278207 +0200
acc9f3
+++ evolution-ews-3.28.5/src/camel/camel-ews-store.c	2019-10-24 09:39:08.341278207 +0200
acc9f3
@@ -673,6 +673,43 @@ ews_update_has_ooo_set (CamelSession *se
acc9f3
 	g_clear_object (&oof_settings);
acc9f3
 }
acc9f3
 
acc9f3
+static void
acc9f3
+ews_exchange_server_categories_cb (CamelSession *session,
acc9f3
+				   GCancellable *cancellable,
acc9f3
+				   gpointer user_data,
acc9f3
+				   GError **error)
acc9f3
+{
acc9f3
+	CamelEwsStore *ews_store = user_data;
acc9f3
+	EEwsConnection *cnc;
acc9f3
+	EwsFolderId fid = { 0 };
acc9f3
+	gchar *properties = NULL;
acc9f3
+	GError *local_error = NULL;
acc9f3
+
acc9f3
+	cnc = camel_ews_store_ref_connection (ews_store);
acc9f3
+	if (!cnc)
acc9f3
+		return;
acc9f3
+
acc9f3
+	fid.id = (gchar *) "calendar";
acc9f3
+	fid.is_distinguished_id = TRUE;
acc9f3
+
acc9f3
+	if (e_ews_connection_get_user_configuration_sync (cnc, G_PRIORITY_DEFAULT, &fid, "CategoryList",
acc9f3
+		E_EWS_USER_CONFIGURATION_PROPERTIES_XMLDATA, &properties, cancellable, &local_error) && properties) {
acc9f3
+		guchar *data;
acc9f3
+		gsize data_len = 0;
acc9f3
+
acc9f3
+		data = g_base64_decode (properties, &data_len);
acc9f3
+
acc9f3
+		if (data && data_len > 0)
acc9f3
+			camel_ews_utils_merge_category_list (ews_store, data, data_len);
acc9f3
+
acc9f3
+		g_free (data);
acc9f3
+	}
acc9f3
+
acc9f3
+	g_clear_error (&local_error);
acc9f3
+	g_clear_object (&cnc);
acc9f3
+	g_free (properties);
acc9f3
+}
acc9f3
+
acc9f3
 struct ScheduleUpdateData
acc9f3
 {
acc9f3
 	GCancellable *cancellable;
acc9f3
@@ -1252,6 +1289,12 @@ ews_connect_sync (CamelService *service,
acc9f3
 				g_object_ref (ews_store),
acc9f3
 				g_object_unref);
acc9f3
 
acc9f3
+		camel_session_submit_job (
acc9f3
+			session, _("Look up Exchange server categories"),
acc9f3
+			ews_exchange_server_categories_cb,
acc9f3
+			g_object_ref (ews_store),
acc9f3
+			g_object_unref);
acc9f3
+
acc9f3
 		if (!priv->updates_cancellable)
acc9f3
 			priv->updates_cancellable = g_cancellable_new ();
acc9f3
 
acc9f3
@@ -2377,6 +2420,17 @@ ews_get_folder_info_sync (CamelStore *st
acc9f3
 	ews_store = (CamelEwsStore *) store;
acc9f3
 	priv = ews_store->priv;
acc9f3
 
acc9f3
+	if ((flags & CAMEL_STORE_FOLDER_INFO_REFRESH) != 0 &&
acc9f3
+	    camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store))) {
acc9f3
+		CamelSession *session;
acc9f3
+
acc9f3
+		session = camel_service_ref_session (CAMEL_SERVICE (ews_store));
acc9f3
+		if (session) {
acc9f3
+			ews_exchange_server_categories_cb (session, cancellable, ews_store, NULL);
acc9f3
+			g_object_unref (session);
acc9f3
+		}
acc9f3
+	}
acc9f3
+
acc9f3
 	if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0) {
acc9f3
 		gboolean includes_last_folder = TRUE;
acc9f3
 		GSList *folders = NULL, *to_check = NULL;
acc9f3
diff -up evolution-ews-3.28.5/src/camel/camel-ews-store-summary.c.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-store-summary.c
acc9f3
--- evolution-ews-3.28.5/src/camel/camel-ews-store-summary.c.sync-category-list	2018-07-30 16:01:00.000000000 +0200
acc9f3
+++ evolution-ews-3.28.5/src/camel/camel-ews-store-summary.c	2019-10-24 09:39:08.341278207 +0200
acc9f3
@@ -31,6 +31,7 @@
acc9f3
 #define S_UNLOCK(x) (g_rec_mutex_unlock(&(x)->priv->s_lock))
acc9f3
 
acc9f3
 #define STORE_GROUP_NAME "##storepriv"
acc9f3
+#define CATEGORIES_KEY "Categories"
acc9f3
 #define CURRENT_SUMMARY_VERSION 3
acc9f3
 
acc9f3
 struct _CamelEwsStoreSummaryPrivate {
acc9f3
@@ -1047,3 +1048,159 @@ camel_ews_store_summary_has_folder (Came
acc9f3
 
acc9f3
 	return ret;
acc9f3
 }
acc9f3
+
acc9f3
+static gchar *
acc9f3
+camel_ews_category_to_string (const CamelEwsCategory *cat)
acc9f3
+{
acc9f3
+	gchar *guid, *name, *color_def = NULL, *str;
acc9f3
+
acc9f3
+	g_return_val_if_fail (cat != NULL, NULL);
acc9f3
+
acc9f3
+	guid = g_uri_escape_string (cat->guid, NULL, TRUE);
acc9f3
+	name = g_uri_escape_string (cat->name, NULL, TRUE);
acc9f3
+
acc9f3
+	if (cat->color_def)
acc9f3
+		color_def = g_uri_escape_string (cat->color_def, NULL, TRUE);
acc9f3
+
acc9f3
+	str = g_strconcat (
acc9f3
+		guid ? guid : "", "\t",
acc9f3
+		name ? name : "", "\t",
acc9f3
+		color_def ? color_def : "",
acc9f3
+		NULL);
acc9f3
+
acc9f3
+	g_free (guid);
acc9f3
+	g_free (name);
acc9f3
+	g_free (color_def);
acc9f3
+
acc9f3
+	return str;
acc9f3
+}
acc9f3
+
acc9f3
+static CamelEwsCategory *
acc9f3
+camel_ews_category_from_string (const gchar *str)
acc9f3
+{
acc9f3
+	CamelEwsCategory *cat;
acc9f3
+	gchar **strv, *guid, *name, *color_def;
acc9f3
+
acc9f3
+	g_return_val_if_fail (str != NULL, NULL);
acc9f3
+
acc9f3
+	strv = g_strsplit (str, "\t", -1);
acc9f3
+	if (!strv || !strv[0] || !strv[1]) {
acc9f3
+		g_strfreev (strv);
acc9f3
+		return NULL;
acc9f3
+	}
acc9f3
+
acc9f3
+	guid = g_uri_unescape_string (strv[0], NULL);
acc9f3
+	name = g_uri_unescape_string (strv[1], NULL);
acc9f3
+	color_def = (strv[2] && strv[2][0]) ? g_uri_unescape_string (strv[2], NULL) : NULL;
acc9f3
+
acc9f3
+	cat = camel_ews_category_new (guid, name, color_def);
acc9f3
+
acc9f3
+	g_free (guid);
acc9f3
+	g_free (name);
acc9f3
+	g_free (color_def);
acc9f3
+	g_strfreev (strv);
acc9f3
+
acc9f3
+	return cat;
acc9f3
+}
acc9f3
+
acc9f3
+GHashTable * /* gchar *guid ~> CamelEwsCategory * */
acc9f3
+camel_ews_store_summary_get_categories (CamelEwsStoreSummary *ews_summary)
acc9f3
+{
acc9f3
+	GHashTable *categories;
acc9f3
+	gchar **strv;
acc9f3
+	g_return_val_if_fail (CAMEL_IS_EWS_STORE_SUMMARY (ews_summary), NULL);
acc9f3
+
acc9f3
+	S_LOCK (ews_summary);
acc9f3
+
acc9f3
+	strv = g_key_file_get_string_list (ews_summary->priv->key_file, STORE_GROUP_NAME, CATEGORIES_KEY, NULL, NULL);
acc9f3
+
acc9f3
+	S_UNLOCK (ews_summary);
acc9f3
+
acc9f3
+	categories = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, camel_ews_category_free);
acc9f3
+
acc9f3
+	if (strv) {
acc9f3
+		gint ii;
acc9f3
+
acc9f3
+		for (ii = 0; strv[ii]; ii++) {
acc9f3
+			CamelEwsCategory *cat;
acc9f3
+
acc9f3
+			cat = camel_ews_category_from_string (strv[ii]);
acc9f3
+			if (cat)
acc9f3
+				g_hash_table_insert (categories, cat->guid, cat);
acc9f3
+		}
acc9f3
+
acc9f3
+		g_strfreev (strv);
acc9f3
+	}
acc9f3
+
acc9f3
+	return categories;
acc9f3
+}
acc9f3
+
acc9f3
+void
acc9f3
+camel_ews_store_summary_set_categories (CamelEwsStoreSummary *ews_summary,
acc9f3
+					GHashTable *categories) /* gchar *guid ~> CamelEwsCategory * */
acc9f3
+{
acc9f3
+	GPtrArray *array;
acc9f3
+	GHashTableIter iter;
acc9f3
+	gpointer value;
acc9f3
+
acc9f3
+	g_return_if_fail (CAMEL_IS_EWS_STORE_SUMMARY (ews_summary));
acc9f3
+	g_return_if_fail (categories != NULL);
acc9f3
+
acc9f3
+	array = g_ptr_array_new_full (g_hash_table_size (categories), g_free);
acc9f3
+
acc9f3
+	g_hash_table_iter_init (&iter, categories);
acc9f3
+	while (g_hash_table_iter_next (&iter, NULL, &value)) {
acc9f3
+		CamelEwsCategory *cat = value;
acc9f3
+
acc9f3
+		if (cat) {
acc9f3
+			gchar *str;
acc9f3
+
acc9f3
+			str = camel_ews_category_to_string (cat);
acc9f3
+
acc9f3
+			if (str)
acc9f3
+				g_ptr_array_add (array, str);
acc9f3
+		}
acc9f3
+	}
acc9f3
+
acc9f3
+	S_LOCK (ews_summary);
acc9f3
+
acc9f3
+	g_key_file_set_string_list (ews_summary->priv->key_file, STORE_GROUP_NAME, CATEGORIES_KEY,
acc9f3
+		(const gchar * const *) array->pdata, array->len);
acc9f3
+
acc9f3
+	ews_summary->priv->dirty = TRUE;
acc9f3
+
acc9f3
+	S_UNLOCK (ews_summary);
acc9f3
+
acc9f3
+	g_ptr_array_free (array, TRUE);
acc9f3
+}
acc9f3
+
acc9f3
+CamelEwsCategory *
acc9f3
+camel_ews_category_new (const gchar *guid,
acc9f3
+			const gchar *name,
acc9f3
+			const gchar *color_def)
acc9f3
+{
acc9f3
+	CamelEwsCategory *cat;
acc9f3
+
acc9f3
+	g_return_val_if_fail (guid != NULL, NULL);
acc9f3
+	g_return_val_if_fail (name != NULL, NULL);
acc9f3
+
acc9f3
+	cat = g_new0 (CamelEwsCategory, 1);
acc9f3
+	cat->guid = g_strdup (guid);
acc9f3
+	cat->name = g_strdup (name);
acc9f3
+	cat->color_def = g_strdup (color_def);
acc9f3
+
acc9f3
+	return cat;
acc9f3
+}
acc9f3
+
acc9f3
+void
acc9f3
+camel_ews_category_free (gpointer ptr)
acc9f3
+{
acc9f3
+	CamelEwsCategory *cat = ptr;
acc9f3
+
acc9f3
+	if (cat) {
acc9f3
+		g_free (cat->guid);
acc9f3
+		g_free (cat->name);
acc9f3
+		g_free (cat->color_def);
acc9f3
+		g_free (cat);
acc9f3
+	}
acc9f3
+}
acc9f3
diff -up evolution-ews-3.28.5/src/camel/camel-ews-store-summary.h.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-store-summary.h
acc9f3
--- evolution-ews-3.28.5/src/camel/camel-ews-store-summary.h.sync-category-list	2018-07-30 16:01:00.000000000 +0200
acc9f3
+++ evolution-ews-3.28.5/src/camel/camel-ews-store-summary.h	2019-10-24 09:39:08.341278207 +0200
acc9f3
@@ -50,6 +50,12 @@
acc9f3
 
acc9f3
 G_BEGIN_DECLS
acc9f3
 
acc9f3
+typedef struct _CamelEwsCategory {
acc9f3
+	gchar *guid;
acc9f3
+	gchar *name;
acc9f3
+	gchar *color_def;
acc9f3
+} CamelEwsCategory;
acc9f3
+
acc9f3
 typedef struct _CamelEwsStoreSummary CamelEwsStoreSummary;
acc9f3
 typedef struct _CamelEwsStoreSummaryClass CamelEwsStoreSummaryClass;
acc9f3
 typedef struct _CamelEwsStoreSummaryPrivate CamelEwsStoreSummaryPrivate;
acc9f3
@@ -215,6 +221,17 @@ gchar *		camel_ews_store_summary_get_fol
acc9f3
 gboolean	camel_ews_store_summary_has_folder
acc9f3
 						(CamelEwsStoreSummary *ews_summary,
acc9f3
 						 const gchar *id);
acc9f3
+GHashTable *	camel_ews_store_summary_get_categories /* gchar *guid ~> CamelEwsCategory * */
acc9f3
+						(CamelEwsStoreSummary *ews_summary);
acc9f3
+void		camel_ews_store_summary_set_categories
acc9f3
+						(CamelEwsStoreSummary *ews_summary,
acc9f3
+						 GHashTable *categories); /* gchar *guid ~> CamelEwsCategory * */
acc9f3
+
acc9f3
+CamelEwsCategory *
acc9f3
+		camel_ews_category_new		(const gchar *guid,
acc9f3
+						 const gchar *name,
acc9f3
+						 const gchar *color_def);
acc9f3
+void		camel_ews_category_free		(gpointer ptr); /* CamelEwsCategory * */
acc9f3
 
acc9f3
 G_END_DECLS
acc9f3
 
acc9f3
diff -up evolution-ews-3.28.5/src/camel/camel-ews-utils.c.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-utils.c
acc9f3
--- evolution-ews-3.28.5/src/camel/camel-ews-utils.c.sync-category-list	2018-07-30 16:01:00.000000000 +0200
acc9f3
+++ evolution-ews-3.28.5/src/camel/camel-ews-utils.c	2019-10-24 09:39:08.341278207 +0200
acc9f3
@@ -29,6 +29,7 @@
acc9f3
 #include <glib/gstdio.h>
acc9f3
 
acc9f3
 #include <libemail-engine/libemail-engine.h>
acc9f3
+#include <e-util/e-util.h>
acc9f3
 
acc9f3
 #include "server/camel-ews-settings.h"
acc9f3
 #include "server/e-ews-camel-common.h"
acc9f3
@@ -381,6 +382,43 @@ camel_ews_utils_sync_deleted_items (Came
acc9f3
 }
acc9f3
 
acc9f3
 static const gchar *
acc9f3
+ews_utils_outlook_color_index_to_color_def (gint color_index)
acc9f3
+{
acc9f3
+	const gchar *colors_array[] = {
acc9f3
+		"#ff1a36", /* Red */
acc9f3
+		"#ff8c00", /* Orange */
acc9f3
+		"#f4b10b", /* Peach */
acc9f3
+		"#fff100", /* Yellow */
acc9f3
+		"#009e48", /* Green */
acc9f3
+		"#00b294", /* Teal */
acc9f3
+		"#89933f", /* Olive */
acc9f3
+		"#00bcf2", /* Blue */
acc9f3
+		"#8e69df", /* Purple */
acc9f3
+		"#f30092", /* Maroon */
acc9f3
+		"#6c7e9a", /* Steel */
acc9f3
+		"#425066", /* DarkSteel */
acc9f3
+		"#969696", /* Gray */
acc9f3
+		"#525552", /* DarkGray */
acc9f3
+		"#282828", /* Black */
acc9f3
+		"#a00023", /* DarkRed */
acc9f3
+		"#c45502", /* DarkOrange */
acc9f3
+		"#af7000", /* DarkPeach */
acc9f3
+		"#b59b02", /* DarkYellow */
acc9f3
+		"#176002", /* DarkGreen */
acc9f3
+		"#00725c", /* DarkTeal */
acc9f3
+		"#5c6022", /* DarkOlive */
acc9f3
+		"#036393", /* DarkBlue */
acc9f3
+		"#422f8e", /* DarkPurple */
acc9f3
+		"#960269"  /* DarkMaroon */
acc9f3
+	};
acc9f3
+
acc9f3
+	if (color_index >= 0 && color_index < G_N_ELEMENTS (colors_array))
acc9f3
+		return colors_array[color_index];
acc9f3
+
acc9f3
+	return NULL;
acc9f3
+}
acc9f3
+
acc9f3
+static const gchar *
acc9f3
 ews_utils_rename_label (const gchar *cat,
acc9f3
                         gboolean from_cat)
acc9f3
 {
acc9f3
@@ -422,6 +460,58 @@ ews_utils_is_system_user_flag (const gch
acc9f3
 		g_str_equal (name, "$has-cal");
acc9f3
 }
acc9f3
 
acc9f3
+/* From Exchange name (which allows spaces) to evolution-name */
acc9f3
+static gchar *
acc9f3
+camel_ews_utils_encode_category_name (const gchar *name)
acc9f3
+{
acc9f3
+	if (name && strchr (name, ' ')) {
acc9f3
+		GString *str;
acc9f3
+
acc9f3
+		str = g_string_sized_new (strlen (name) + 16);
acc9f3
+
acc9f3
+		while (*name) {
acc9f3
+			if (*name == '_')
acc9f3
+				g_string_append_c (str, '_');
acc9f3
+
acc9f3
+			g_string_append_c (str, *name == ' ' ? '_' : *name);
acc9f3
+
acc9f3
+			name++;
acc9f3
+		}
acc9f3
+
acc9f3
+		return g_string_free (str, FALSE);
acc9f3
+	}
acc9f3
+
acc9f3
+	return g_strdup (name);
acc9f3
+}
acc9f3
+
acc9f3
+/* From evolution-name to Exchange name (which allows spaces) */
acc9f3
+static gchar *
acc9f3
+camel_ews_utils_decode_category_name (const gchar *flag)
acc9f3
+{
acc9f3
+	if (flag && strchr (flag, '_')) {
acc9f3
+		GString *str = g_string_sized_new (strlen (flag));
acc9f3
+
acc9f3
+		while (*flag) {
acc9f3
+			if (*flag == '_') {
acc9f3
+				if (flag[1] == '_') {
acc9f3
+					g_string_append_c (str, '_');
acc9f3
+					flag++;
acc9f3
+				} else {
acc9f3
+					g_string_append_c (str, ' ');
acc9f3
+				}
acc9f3
+			} else {
acc9f3
+				g_string_append_c (str, *flag);
acc9f3
+			}
acc9f3
+
acc9f3
+			flag++;
acc9f3
+		}
acc9f3
+
acc9f3
+		return g_string_free (str, FALSE);
acc9f3
+	}
acc9f3
+
acc9f3
+	return g_strdup (flag);
acc9f3
+}
acc9f3
+
acc9f3
 /* free with g_slist_free_full (flags, g_free);
acc9f3
    the lists' members are values for the String xml element. */
acc9f3
 GSList *
acc9f3
@@ -441,6 +531,7 @@ ews_utils_gather_server_user_flags (ESoa
acc9f3
 	 * array of strings */
acc9f3
 	for (ii = 0; ii < len; ii++) {
acc9f3
 		const gchar *n = ews_utils_rename_label (camel_named_flags_get (user_flags, ii), FALSE);
acc9f3
+
acc9f3
 		if (*n == '\0')
acc9f3
 			continue;
acc9f3
 
acc9f3
@@ -449,26 +540,7 @@ ews_utils_gather_server_user_flags (ESoa
acc9f3
 		if (ews_utils_is_system_user_flag (n))
acc9f3
 			continue;
acc9f3
 
acc9f3
-		if (strchr (n, '_')) {
acc9f3
-			GString *str = g_string_sized_new (strlen (n));
acc9f3
-
acc9f3
-			while (*n) {
acc9f3
-				if (*n == '_') {
acc9f3
-					if (n[1] == '_')
acc9f3
-						g_string_append_c (str, '_');
acc9f3
-					else
acc9f3
-						g_string_append_c (str, ' ');
acc9f3
-				} else {
acc9f3
-					g_string_append_c (str, *n);
acc9f3
-				}
acc9f3
-
acc9f3
-				n++;
acc9f3
-			}
acc9f3
-
acc9f3
-			out_user_flags = g_slist_prepend (out_user_flags, g_string_free (str, FALSE));
acc9f3
-		} else {
acc9f3
-			out_user_flags = g_slist_prepend (out_user_flags, g_strdup (n));
acc9f3
-		}
acc9f3
+		out_user_flags = g_slist_prepend (out_user_flags, camel_ews_utils_decode_category_name (n));
acc9f3
 	}
acc9f3
 
acc9f3
 	camel_message_info_property_unlock (mi);
acc9f3
@@ -512,33 +584,17 @@ ews_utils_merge_server_user_flags (EEwsI
acc9f3
 
acc9f3
 	/* now transfer over all the categories */
acc9f3
 	for (p = e_ews_item_get_categories (item); p; p = p->next) {
acc9f3
-		const gchar *flag = ews_utils_rename_label (p->data, 1);
acc9f3
-		gchar *underscored = NULL;
acc9f3
+		const gchar *name = ews_utils_rename_label (p->data, 1);
acc9f3
+		gchar *flag;
acc9f3
 
acc9f3
-		if (!flag || !*flag)
acc9f3
+		if (!name || !*name)
acc9f3
 			continue;
acc9f3
 
acc9f3
-		if (strchr (flag, ' ')) {
acc9f3
-			GString *str;
acc9f3
-
acc9f3
-			str = g_string_sized_new (strlen (flag) + 16);
acc9f3
-
acc9f3
-			while (*flag) {
acc9f3
-				if (*flag == '_')
acc9f3
-					g_string_append_c (str, '_');
acc9f3
-
acc9f3
-				g_string_append_c (str, *flag == ' ' ? '_' : *flag);
acc9f3
-
acc9f3
-				flag++;
acc9f3
-			}
acc9f3
-
acc9f3
-			underscored = g_string_free (str, FALSE);
acc9f3
-			flag = underscored;
acc9f3
-		}
acc9f3
+		flag = camel_ews_utils_encode_category_name (name);
acc9f3
 
acc9f3
 		camel_message_info_set_user_flag (mi, flag, TRUE);
acc9f3
 
acc9f3
-		g_free (underscored);
acc9f3
+		g_free (flag);
acc9f3
 	}
acc9f3
 
acc9f3
 	camel_message_info_thaw_notifications (mi);
acc9f3
@@ -1281,3 +1337,279 @@ camel_ews_utils_ref_corresponding_source
acc9f3
 
acc9f3
 	return source;
acc9f3
 }
acc9f3
+
acc9f3
+static gboolean
acc9f3
+ews_util_equal_label_tag_cb (gconstpointer ptr1,
acc9f3
+			     gconstpointer ptr2)
acc9f3
+{
acc9f3
+	const gchar *evo_label_def = ptr1;
acc9f3
+	const gchar *tag = ptr2;
acc9f3
+	const gchar *pos;
acc9f3
+
acc9f3
+	if (!evo_label_def || !tag || !*tag)
acc9f3
+		return FALSE;
acc9f3
+
acc9f3
+	pos = g_strrstr (evo_label_def, tag);
acc9f3
+
acc9f3
+	return pos > evo_label_def && pos[-1] == '|' && !pos[strlen (tag)];
acc9f3
+}
acc9f3
+
acc9f3
+static gboolean
acc9f3
+ews_utils_find_in_ptr_array (GPtrArray *haystack,
acc9f3
+			     gconstpointer needle,
acc9f3
+			     GEqualFunc equal_func,
acc9f3
+			     guint *out_index)
acc9f3
+{
acc9f3
+	guint ii;
acc9f3
+
acc9f3
+	if (!haystack)
acc9f3
+		return FALSE;
acc9f3
+
acc9f3
+	if (!equal_func)
acc9f3
+		equal_func = g_direct_equal;
acc9f3
+
acc9f3
+	for (ii = 0; ii < haystack->len; ii++) {
acc9f3
+		if (equal_func (haystack->pdata[ii], needle)) {
acc9f3
+			if (out_index)
acc9f3
+				*out_index = ii;
acc9f3
+
acc9f3
+			return TRUE;
acc9f3
+		}
acc9f3
+	}
acc9f3
+
acc9f3
+	return FALSE;
acc9f3
+}
acc9f3
+
acc9f3
+/* Returns whether had been done any changes */
acc9f3
+static gboolean
acc9f3
+ews_utils_save_category_changes (GHashTable *old_categories, /* gchar *guid ~> CamelEwsCategory * */
acc9f3
+				 GHashTable *new_categories) /* gchar *guid ~> CamelEwsCategory * */
acc9f3
+{
acc9f3
+	GHashTableIter iter;
acc9f3
+	GSettings *settings;
acc9f3
+	GPtrArray *evo_labels; /* gchar * (encoded label definition) */
acc9f3
+	gchar **strv;
acc9f3
+	gint ii;
acc9f3
+	gpointer value;
acc9f3
+	gboolean changed = FALSE;
acc9f3
+
acc9f3
+	if (!old_categories || !new_categories)
acc9f3
+		return new_categories != NULL;
acc9f3
+
acc9f3
+	evo_labels = g_ptr_array_new_full (5, g_free);
acc9f3
+
acc9f3
+	settings = e_util_ref_settings ("org.gnome.evolution.mail");
acc9f3
+	strv = g_settings_get_strv (settings, "labels");
acc9f3
+
acc9f3
+	for (ii = 0; strv && strv[ii]; ii++) {
acc9f3
+		g_ptr_array_add (evo_labels, g_strdup (strv[ii]));
acc9f3
+	}
acc9f3
+
acc9f3
+	g_strfreev (strv);
acc9f3
+
acc9f3
+	g_hash_table_iter_init (&iter, new_categories);
acc9f3
+	while (g_hash_table_iter_next (&iter, NULL, &value)) {
acc9f3
+		CamelEwsCategory *new_cat = value, *old_cat;
acc9f3
+		gchar *tag = NULL;
acc9f3
+
acc9f3
+		if (!new_cat)
acc9f3
+			continue;
acc9f3
+
acc9f3
+		old_cat = g_hash_table_lookup (old_categories, new_cat->guid);
acc9f3
+		if (old_cat) {
acc9f3
+			if (g_strcmp0 (old_cat->name, new_cat->name) != 0 ||
acc9f3
+			    g_strcmp0 (old_cat->color_def, new_cat->color_def) != 0) {
acc9f3
+				/* Old category changed name or color */
acc9f3
+				tag = camel_ews_utils_encode_category_name (new_cat->name);
acc9f3
+			}
acc9f3
+		} else {
acc9f3
+			/* This is a new category */
acc9f3
+			tag = camel_ews_utils_encode_category_name (new_cat->name);
acc9f3
+		}
acc9f3
+
acc9f3
+		if (tag && *tag) {
acc9f3
+			guint index = (guint) -1;
acc9f3
+			gchar *label_def;
acc9f3
+
acc9f3
+			changed = TRUE;
acc9f3
+
acc9f3
+			/* Sanitize value */
acc9f3
+			for (ii = 0; tag[ii]; ii++) {
acc9f3
+				if (tag[ii] == '|')
acc9f3
+					tag[ii] = '-';
acc9f3
+			}
acc9f3
+
acc9f3
+			if (old_cat && g_strcmp0 (old_cat->name, new_cat->name) != 0) {
acc9f3
+				gchar *old_tag = camel_ews_utils_encode_category_name (old_cat->name);
acc9f3
+
acc9f3
+				if (old_tag && *old_tag) {
acc9f3
+					if (!ews_utils_find_in_ptr_array (evo_labels, old_tag, ews_util_equal_label_tag_cb, &index))
acc9f3
+						index = (guint) -1;
acc9f3
+				}
acc9f3
+
acc9f3
+				g_free (old_tag);
acc9f3
+			}
acc9f3
+
acc9f3
+			for (ii = 0; new_cat->name[ii]; ii++) {
acc9f3
+				if (new_cat->name[ii] == '|')
acc9f3
+					new_cat->name[ii] = '-';
acc9f3
+			}
acc9f3
+
acc9f3
+			if (index == (guint) -1 &&
acc9f3
+			    !ews_utils_find_in_ptr_array (evo_labels, tag, ews_util_equal_label_tag_cb, &index))
acc9f3
+				index = (guint) -1;
acc9f3
+
acc9f3
+			label_def = g_strconcat (new_cat->name, "|", new_cat->color_def ? new_cat->color_def : "#FF0000", "|", tag, NULL);
acc9f3
+
acc9f3
+			if (index == (guint) -1 || index >= (gint) evo_labels->len) {
acc9f3
+				g_ptr_array_add (evo_labels, label_def);
acc9f3
+			} else {
acc9f3
+				g_free (evo_labels->pdata[index]);
acc9f3
+				evo_labels->pdata[index] = label_def;
acc9f3
+			}
acc9f3
+		}
acc9f3
+
acc9f3
+		g_hash_table_remove (old_categories, new_cat->guid);
acc9f3
+
acc9f3
+		g_free (tag);
acc9f3
+	}
acc9f3
+
acc9f3
+	if (g_hash_table_size (old_categories) > 0) {
acc9f3
+		/* Some categories had been removed */
acc9f3
+		changed = TRUE;
acc9f3
+
acc9f3
+		g_hash_table_iter_init (&iter, old_categories);
acc9f3
+		while (g_hash_table_iter_next (&iter, NULL, &value)) {
acc9f3
+			CamelEwsCategory *old_cat = value;
acc9f3
+			gchar *old_tag;
acc9f3
+			guint index;
acc9f3
+
acc9f3
+			if (!old_cat)
acc9f3
+				continue;
acc9f3
+
acc9f3
+			old_tag = camel_ews_utils_encode_category_name (old_cat->name);
acc9f3
+
acc9f3
+			for (ii = 0; old_tag && old_tag[ii]; ii++) {
acc9f3
+				if (old_tag[ii] == '|')
acc9f3
+					old_tag[ii] = '-';
acc9f3
+			}
acc9f3
+
acc9f3
+			if (old_tag &&
acc9f3
+			    ews_utils_find_in_ptr_array (evo_labels, old_tag, ews_util_equal_label_tag_cb, &index))
acc9f3
+				g_ptr_array_remove_index (evo_labels, index);
acc9f3
+
acc9f3
+			g_free (old_tag);
acc9f3
+		}
acc9f3
+	}
acc9f3
+
acc9f3
+	if (changed) {
acc9f3
+		/* NULL-terminated array of strings */
acc9f3
+		g_ptr_array_add (evo_labels, NULL);
acc9f3
+
acc9f3
+		g_settings_set_strv (settings, "labels", (const gchar * const *) evo_labels->pdata);
acc9f3
+	}
acc9f3
+
acc9f3
+	g_ptr_array_free (evo_labels, TRUE);
acc9f3
+	g_object_unref (settings);
acc9f3
+
acc9f3
+	return changed;
acc9f3
+}
acc9f3
+
acc9f3
+void
acc9f3
+camel_ews_utils_merge_category_list (CamelEwsStore *ews_store,
acc9f3
+				     const guchar *xml_data,
acc9f3
+				     gsize xml_data_len)
acc9f3
+{
acc9f3
+	xmlDocPtr doc;
acc9f3
+	xmlXPathContextPtr xpath_ctx;
acc9f3
+
acc9f3
+	g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store));
acc9f3
+	g_return_if_fail (xml_data != NULL);
acc9f3
+
acc9f3
+	doc = e_xml_parse_data (xml_data, xml_data_len);
acc9f3
+	if (!doc)
acc9f3
+		return;
acc9f3
+
acc9f3
+	xpath_ctx = e_xml_new_xpath_context_with_namespaces (doc, "C", "CategoryList.xsd", NULL);
acc9f3
+
acc9f3
+	if (xpath_ctx) {
acc9f3
+		xmlXPathObjectPtr xpath_obj_categories;
acc9f3
+
acc9f3
+		xpath_obj_categories = e_xml_xpath_eval (xpath_ctx, "%s", "/C:categories/C:category");
acc9f3
+
acc9f3
+		if (xpath_obj_categories) {
acc9f3
+			GHashTable *old_categories, *new_categories;
acc9f3
+			gint response_index, response_length;
acc9f3
+
acc9f3
+			new_categories = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, camel_ews_category_free);
acc9f3
+
acc9f3
+			response_length = xmlXPathNodeSetGetLength (xpath_obj_categories->nodesetval);
acc9f3
+
acc9f3
+			for (response_index = 0; response_index < response_length; response_index++) {
acc9f3
+				xmlXPathObjectPtr xpath_obj_category;
acc9f3
+
acc9f3
+				xpath_obj_category = e_xml_xpath_eval (xpath_ctx,
acc9f3
+					"/C:categories/C:category[%d]",
acc9f3
+					response_index + 1);
acc9f3
+
acc9f3
+				if (xpath_obj_category) {
acc9f3
+					gchar *name;
acc9f3
+
acc9f3
+					name = e_xml_xpath_eval_as_string (xpath_ctx, "/C:categories/C:category[%d]/@name", response_index + 1);
acc9f3
+
acc9f3
+					if (name && ews_utils_rename_label (name, 1) == name) {
acc9f3
+						const gchar *color_def = NULL;
acc9f3
+						gchar *color, *guid;
acc9f3
+						gint color_index = -1;
acc9f3
+
acc9f3
+						color = e_xml_xpath_eval_as_string (xpath_ctx, "/C:categories/C:category[%d]/@color", response_index + 1);
acc9f3
+						if (color) {
acc9f3
+							gchar *endptr = NULL;
acc9f3
+
acc9f3
+							color_index = (gint) g_ascii_strtoll (color, &endptr, 10);
acc9f3
+
acc9f3
+							if (endptr == color)
acc9f3
+								color_index = -1;
acc9f3
+						}
acc9f3
+
acc9f3
+						g_free (color);
acc9f3
+
acc9f3
+						if (color_index >= 0)
acc9f3
+							color_def = ews_utils_outlook_color_index_to_color_def (color_index);
acc9f3
+
acc9f3
+						guid = e_xml_xpath_eval_as_string (xpath_ctx, "/C:categories/C:category[%d]/@guid", response_index + 1);
acc9f3
+
acc9f3
+						if (guid && *guid) {
acc9f3
+							CamelEwsCategory *cat;
acc9f3
+
acc9f3
+							cat = camel_ews_category_new (guid, name, color_def);
acc9f3
+							if (cat)
acc9f3
+								g_hash_table_insert (new_categories, cat->guid, cat);
acc9f3
+						}
acc9f3
+
acc9f3
+						g_free (guid);
acc9f3
+					}
acc9f3
+
acc9f3
+					g_free (name);
acc9f3
+					xmlXPathFreeObject (xpath_obj_category);
acc9f3
+				}
acc9f3
+			}
acc9f3
+
acc9f3
+			xmlXPathFreeObject (xpath_obj_categories);
acc9f3
+
acc9f3
+			old_categories = camel_ews_store_summary_get_categories (ews_store->summary);
acc9f3
+
acc9f3
+			if (ews_utils_save_category_changes (old_categories, new_categories)) {
acc9f3
+				camel_ews_store_summary_set_categories (ews_store->summary, new_categories);
acc9f3
+				camel_ews_store_summary_save (ews_store->summary, NULL);
acc9f3
+			}
acc9f3
+
acc9f3
+			g_hash_table_destroy (new_categories);
acc9f3
+			g_hash_table_destroy (old_categories);
acc9f3
+		}
acc9f3
+	}
acc9f3
+
acc9f3
+	if (xpath_ctx)
acc9f3
+		xmlXPathFreeContext (xpath_ctx);
acc9f3
+	xmlFreeDoc (doc);
acc9f3
+}
acc9f3
diff -up evolution-ews-3.28.5/src/camel/camel-ews-utils.h.sync-category-list evolution-ews-3.28.5/src/camel/camel-ews-utils.h
acc9f3
--- evolution-ews-3.28.5/src/camel/camel-ews-utils.h.sync-category-list	2018-07-30 16:01:00.000000000 +0200
acc9f3
+++ evolution-ews-3.28.5/src/camel/camel-ews-utils.h	2019-10-24 09:39:08.341278207 +0200
acc9f3
@@ -94,6 +94,10 @@ CamelMessageInfo * /* (transfer full) */
acc9f3
 						 EEwsConnection *cnc,
acc9f3
 						 EEwsItem *item,
acc9f3
 						 GCancellable *cancellable);
acc9f3
+void		camel_ews_utils_merge_category_list
acc9f3
+						(CamelEwsStore *ews_store,
acc9f3
+						 const guchar *xml_data,
acc9f3
+						 gsize xml_data_len);
acc9f3
 
acc9f3
 G_END_DECLS
acc9f3
 
acc9f3
diff -up evolution-ews-3.28.5/src/server/e-ews-connection.c.sync-category-list evolution-ews-3.28.5/src/server/e-ews-connection.c
acc9f3
--- evolution-ews-3.28.5/src/server/e-ews-connection.c.sync-category-list	2019-10-24 09:39:08.339278207 +0200
acc9f3
+++ evolution-ews-3.28.5/src/server/e-ews-connection.c	2019-10-24 09:46:14.667272312 +0200
acc9f3
@@ -155,7 +155,7 @@ struct _EwsAsyncData {
acc9f3
 	EwsDelegateDeliver deliver_to;
acc9f3
 	EEwsFolderType folder_type;
acc9f3
 	EEwsConnection *cnc;
acc9f3
-	gchar *user_photo; /* base64-encoded, as GetUserPhoto result */
acc9f3
+	gchar *custom_data; /* Can be re-used by operations, will be freed with g_free() */
acc9f3
 };
acc9f3
 
acc9f3
 struct _EwsNode {
acc9f3
@@ -200,7 +200,7 @@ ews_connection_error_quark (void)
acc9f3
 static void
acc9f3
 async_data_free (EwsAsyncData *async_data)
acc9f3
 {
acc9f3
-	g_free (async_data->user_photo);
acc9f3
+	g_free (async_data->custom_data);
acc9f3
 	g_free (async_data);
acc9f3
 }
acc9f3
 
acc9f3
@@ -10830,10 +10830,10 @@ get_user_photo_response_cb (ESoapRespons
acc9f3
 		return;
acc9f3
 	}
acc9f3
 
acc9f3
-	async_data->user_photo = e_soap_parameter_get_string_value (param);
acc9f3
-	if (async_data->user_photo && !*async_data->user_photo) {
acc9f3
-		g_free (async_data->user_photo);
acc9f3
-		async_data->user_photo = NULL;
acc9f3
+	async_data->custom_data = e_soap_parameter_get_string_value (param);
acc9f3
+	if (async_data->custom_data && !*async_data->custom_data) {
acc9f3
+		g_free (async_data->custom_data);
acc9f3
+		async_data->custom_data = NULL;
acc9f3
 	}
acc9f3
 }
acc9f3
 
acc9f3
@@ -10918,11 +10918,11 @@ e_ews_connection_get_user_photo_finish (
acc9f3
 	if (g_simple_async_result_propagate_error (simple, error))
acc9f3
 		return FALSE;
acc9f3
 
acc9f3
-	if (!async_data->user_photo)
acc9f3
+	if (!async_data->custom_data)
acc9f3
 		return FALSE;
acc9f3
 
acc9f3
-	*out_picture_data = async_data->user_photo;
acc9f3
-	async_data->user_photo = NULL;
acc9f3
+	*out_picture_data = async_data->custom_data;
acc9f3
+	async_data->custom_data = NULL;
acc9f3
 
acc9f3
 	return TRUE;
acc9f3
 }
acc9f3
@@ -10953,5 +10953,256 @@ e_ews_connection_get_user_photo_sync (EE
acc9f3
 
acc9f3
 	e_async_closure_free (closure);
acc9f3
 
acc9f3
+	return success;
acc9f3
+}
acc9f3
+
acc9f3
+static void
acc9f3
+get_user_configuration_response_cb (ESoapResponse *response,
acc9f3
+				    GSimpleAsyncResult *simple)
acc9f3
+{
acc9f3
+	EwsAsyncData *async_data;
acc9f3
+	ESoapParameter *param, *subparam;
acc9f3
+	GError *error = NULL;
acc9f3
+
acc9f3
+	async_data = g_simple_async_result_get_op_res_gpointer (simple);
acc9f3
+
acc9f3
+	param = e_soap_response_get_first_parameter_by_name (response, "ResponseMessages", &error);
acc9f3
+
acc9f3
+	if (param) {
acc9f3
+		param = e_soap_parameter_get_first_child_by_name (param, "GetUserConfigurationResponseMessage");
acc9f3
+		if (!param) {
acc9f3
+			g_set_error (&error,
acc9f3
+				SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED,
acc9f3
+				"Missing <%s> in SOAP response", "GetUserConfigurationResponseMessage");
acc9f3
+		}
acc9f3
+	}
acc9f3
+
acc9f3
+	if (param) {
acc9f3
+		param = e_soap_parameter_get_first_child_by_name (param, "UserConfiguration");
acc9f3
+		if (!param) {
acc9f3
+			g_set_error (&error,
acc9f3
+				SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED,
acc9f3
+				"Missing <%s> in SOAP response", "UserConfiguration");
acc9f3
+		}
acc9f3
+	}
acc9f3
+
acc9f3
+	/* Sanity check */
acc9f3
+	g_return_if_fail (
acc9f3
+		(param != NULL && error == NULL) ||
acc9f3
+		(param == NULL && error != NULL));
acc9f3
+
acc9f3
+	if (error != NULL) {
acc9f3
+		g_simple_async_result_take_error (simple, error);
acc9f3
+		return;
acc9f3
+	}
acc9f3
+
acc9f3
+	subparam = e_soap_parameter_get_first_child_by_name (param, "ItemId");
acc9f3
+	if (subparam) {
acc9f3
+		gchar *id, *changekey;
acc9f3
+
acc9f3
+		id = e_soap_parameter_get_property (subparam, "Id");
acc9f3
+		changekey = e_soap_parameter_get_property (subparam, "ChangeKey");
acc9f3
+
acc9f3
+		/* Encoded as: Id + "\n" + ChangeKey */
acc9f3
+		async_data->custom_data = g_strconcat (id ? id : "", "\n", changekey, NULL);
acc9f3
+
acc9f3
+		g_free (changekey);
acc9f3
+		g_free (id);
acc9f3
+	}
acc9f3
+
acc9f3
+	if (!subparam) {
acc9f3
+		subparam = e_soap_parameter_get_first_child_by_name (param, "Dictionary");
acc9f3
+		if (subparam)
acc9f3
+			async_data->custom_data = e_soap_response_dump_parameter (response, subparam);
acc9f3
+	}
acc9f3
+
acc9f3
+	if (!subparam) {
acc9f3
+		subparam = e_soap_parameter_get_first_child_by_name (param, "XmlData");
acc9f3
+		if (subparam) {
acc9f3
+			async_data->custom_data = e_soap_parameter_get_string_value (subparam);
acc9f3
+		}
acc9f3
+	}
acc9f3
+
acc9f3
+	if (!subparam) {
acc9f3
+		subparam = e_soap_parameter_get_first_child_by_name (param, "BinaryData");
acc9f3
+		if (subparam) {
acc9f3
+			async_data->custom_data = e_soap_parameter_get_string_value (subparam);
acc9f3
+		}
acc9f3
+	}
acc9f3
+
acc9f3
+	if (async_data->custom_data && !*async_data->custom_data) {
acc9f3
+		g_free (async_data->custom_data);
acc9f3
+		async_data->custom_data = NULL;
acc9f3
+	}
acc9f3
+}
acc9f3
+
acc9f3
+static void
acc9f3
+e_ews_folder_id_append_to_msg (ESoapMessage *msg,
acc9f3
+			       const gchar *email,
acc9f3
+			       const EwsFolderId *fid)
acc9f3
+{
acc9f3
+	g_return_if_fail (msg != NULL);
acc9f3
+	g_return_if_fail (fid != NULL);
acc9f3
+
acc9f3
+	if (fid->is_distinguished_id)
acc9f3
+		e_soap_message_start_element (msg, "DistinguishedFolderId", NULL, NULL);
acc9f3
+	else
acc9f3
+		e_soap_message_start_element (msg, "FolderId", NULL, NULL);
acc9f3
+
acc9f3
+	e_soap_message_add_attribute (msg, "Id", fid->id, NULL, NULL);
acc9f3
+	if (fid->change_key)
acc9f3
+		e_soap_message_add_attribute (msg, "ChangeKey", fid->change_key, NULL, NULL);
acc9f3
+
acc9f3
+	if (fid->is_distinguished_id && email) {
acc9f3
+		e_soap_message_start_element (msg, "Mailbox", NULL, NULL);
acc9f3
+		e_ews_message_write_string_parameter (msg, "EmailAddress", NULL, email);
acc9f3
+		e_soap_message_end_element (msg);
acc9f3
+	}
acc9f3
+
acc9f3
+	e_soap_message_end_element (msg);
acc9f3
+}
acc9f3
+
acc9f3
+void
acc9f3
+e_ews_connection_get_user_configuration (EEwsConnection *cnc,
acc9f3
+					 gint pri,
acc9f3
+					 const EwsFolderId *fid,
acc9f3
+					 const gchar *config_name,
acc9f3
+					 EEwsUserConfigurationProperties props,
acc9f3
+					 GCancellable *cancellable,
acc9f3
+					 GAsyncReadyCallback callback,
acc9f3
+					 gpointer user_data)
acc9f3
+{
acc9f3
+	ESoapMessage *msg;
acc9f3
+	GSimpleAsyncResult *simple;
acc9f3
+	EwsAsyncData *async_data;
acc9f3
+	EwsFolderId local_fid;
acc9f3
+
acc9f3
+	g_return_if_fail (cnc != NULL);
acc9f3
+	g_return_if_fail (cnc->priv != NULL);
acc9f3
+	g_return_if_fail (fid != NULL);
acc9f3
+	g_return_if_fail (config_name != NULL);
acc9f3
+
acc9f3
+	simple = g_simple_async_result_new (G_OBJECT (cnc), callback, user_data, e_ews_connection_get_user_configuration);
acc9f3
+	async_data = g_new0 (EwsAsyncData, 1);
acc9f3
+	g_simple_async_result_set_op_res_gpointer (simple, async_data, (GDestroyNotify) async_data_free);
acc9f3
+
acc9f3
+	/* EWS server version earlier than 2010 doesn't support it. */
acc9f3
+	if (!e_ews_connection_satisfies_server_version (cnc, E_EWS_EXCHANGE_2010)) {
acc9f3
+		g_simple_async_result_complete_in_idle (simple);
acc9f3
+		g_object_unref (simple);
acc9f3
+		return;
acc9f3
+	}
acc9f3
+
acc9f3
+	local_fid = *fid;
acc9f3
+	local_fid.change_key = NULL;
acc9f3
+
acc9f3
+	msg = e_ews_message_new_with_header (
acc9f3
+		cnc->priv->settings,
acc9f3
+		cnc->priv->uri,
acc9f3
+		cnc->priv->impersonate_user,
acc9f3
+		"GetUserConfiguration",
acc9f3
+		NULL,
acc9f3
+		NULL,
acc9f3
+		cnc->priv->version,
acc9f3
+		E_EWS_EXCHANGE_2010,
acc9f3
+		FALSE,
acc9f3
+		TRUE);
acc9f3
+
acc9f3
+	e_soap_message_start_element (msg, "UserConfigurationName", "messages", NULL);
acc9f3
+	e_soap_message_add_attribute (msg, "Name", config_name, NULL, NULL);
acc9f3
+
acc9f3
+	e_ews_folder_id_append_to_msg (msg, cnc->priv->email, &local_fid);
acc9f3
+
acc9f3
+	e_soap_message_end_element (msg); /* UserConfigurationName */
acc9f3
+
acc9f3
+	e_soap_message_start_element (msg, "UserConfigurationProperties", "messages", NULL);
acc9f3
+
acc9f3
+	switch (props) {
acc9f3
+	case E_EWS_USER_CONFIGURATION_PROPERTIES_ID:
acc9f3
+		e_soap_message_write_string (msg, "Id");
acc9f3
+		break;
acc9f3
+	case E_EWS_USER_CONFIGURATION_PROPERTIES_DICTIONARY:
acc9f3
+		e_soap_message_write_string (msg, "Dictionary");
acc9f3
+		break;
acc9f3
+	case E_EWS_USER_CONFIGURATION_PROPERTIES_XMLDATA:
acc9f3
+		e_soap_message_write_string (msg, "XmlData");
acc9f3
+		break;
acc9f3
+	case E_EWS_USER_CONFIGURATION_PROPERTIES_BINARYDATA:
acc9f3
+		e_soap_message_write_string (msg, "BinaryData");
acc9f3
+		break;
acc9f3
+	/* case E_EWS_USER_CONFIGURATION_PROPERTIES_ALL:
acc9f3
+		e_soap_message_write_string (msg, "All");
acc9f3
+		break; */
acc9f3
+	default:
acc9f3
+		e_soap_message_write_string (msg, "Unknown");
acc9f3
+		break;
acc9f3
+	}
acc9f3
+
acc9f3
+	e_soap_message_end_element (msg); /* UserConfigurationProperties */
acc9f3
+
acc9f3
+	e_ews_message_write_footer (msg);
acc9f3
+
acc9f3
+	e_ews_connection_queue_request (cnc, msg, get_user_configuration_response_cb, pri, cancellable, simple);
acc9f3
+
acc9f3
+	g_object_unref (simple);
acc9f3
+}
acc9f3
+
acc9f3
+gboolean
acc9f3
+e_ews_connection_get_user_configuration_finish (EEwsConnection *cnc,
acc9f3
+						GAsyncResult *result,
acc9f3
+						gchar **out_properties,
acc9f3
+						GError **error)
acc9f3
+{
acc9f3
+	GSimpleAsyncResult *simple;
acc9f3
+	EwsAsyncData *async_data;
acc9f3
+
acc9f3
+	g_return_val_if_fail (cnc != NULL, FALSE);
acc9f3
+	g_return_val_if_fail (
acc9f3
+		g_simple_async_result_is_valid (result, G_OBJECT (cnc), e_ews_connection_get_user_configuration),
acc9f3
+		FALSE);
acc9f3
+	g_return_val_if_fail (out_properties != NULL, FALSE);
acc9f3
+
acc9f3
+	simple = G_SIMPLE_ASYNC_RESULT (result);
acc9f3
+	async_data = g_simple_async_result_get_op_res_gpointer (simple);
acc9f3
+
acc9f3
+	if (g_simple_async_result_propagate_error (simple, error))
acc9f3
+		return FALSE;
acc9f3
+
acc9f3
+	if (!async_data->custom_data)
acc9f3
+		return FALSE;
acc9f3
+
acc9f3
+	*out_properties = async_data->custom_data;
acc9f3
+	async_data->custom_data = NULL;
acc9f3
+
acc9f3
+	return TRUE;
acc9f3
+}
acc9f3
+
acc9f3
+gboolean
acc9f3
+e_ews_connection_get_user_configuration_sync (EEwsConnection *cnc,
acc9f3
+					      gint pri,
acc9f3
+					      const EwsFolderId *fid,
acc9f3
+					      const gchar *config_name,
acc9f3
+					      EEwsUserConfigurationProperties props,
acc9f3
+					      gchar **out_properties,
acc9f3
+					      GCancellable *cancellable,
acc9f3
+					      GError **error)
acc9f3
+{
acc9f3
+	EAsyncClosure *closure;
acc9f3
+	GAsyncResult *result;
acc9f3
+	gboolean success;
acc9f3
+
acc9f3
+	g_return_val_if_fail (cnc != NULL, FALSE);
acc9f3
+
acc9f3
+	closure = e_async_closure_new ();
acc9f3
+
acc9f3
+	e_ews_connection_get_user_configuration (
acc9f3
+		cnc, pri, fid, config_name, props, cancellable, e_async_closure_callback, closure);
acc9f3
+
acc9f3
+	result = e_async_closure_wait (closure);
acc9f3
+
acc9f3
+	success = e_ews_connection_get_user_configuration_finish (cnc, result, out_properties, error);
acc9f3
+
acc9f3
+	e_async_closure_free (closure);
acc9f3
+
acc9f3
 	return success;
acc9f3
 }
acc9f3
diff -up evolution-ews-3.28.5/src/server/e-ews-connection.h.sync-category-list evolution-ews-3.28.5/src/server/e-ews-connection.h
acc9f3
--- evolution-ews-3.28.5/src/server/e-ews-connection.h.sync-category-list	2019-10-24 09:39:08.339278207 +0200
acc9f3
+++ evolution-ews-3.28.5/src/server/e-ews-connection.h	2019-10-24 09:39:08.342278207 +0200
acc9f3
@@ -132,6 +132,15 @@ typedef enum {
acc9f3
 	E_EWS_SIZE_REQUESTED_648X648 = 648
acc9f3
 } EEwsSizeRequested;
acc9f3
 
acc9f3
+typedef enum {
acc9f3
+	E_EWS_USER_CONFIGURATION_PROPERTIES_UNKNOWN = -1,
acc9f3
+	E_EWS_USER_CONFIGURATION_PROPERTIES_ID,
acc9f3
+	E_EWS_USER_CONFIGURATION_PROPERTIES_DICTIONARY,
acc9f3
+	E_EWS_USER_CONFIGURATION_PROPERTIES_XMLDATA,
acc9f3
+	E_EWS_USER_CONFIGURATION_PROPERTIES_BINARYDATA /*,
acc9f3
+	E_EWS_USER_CONFIGURATION_PROPERTIES_ALL - skip it, be specific */
acc9f3
+} EEwsUserConfigurationProperties;
acc9f3
+
acc9f3
 typedef struct {
acc9f3
 	gchar *id;
acc9f3
 	gchar *dn;
acc9f3
@@ -1377,6 +1386,29 @@ gboolean	e_ews_connection_get_user_photo
acc9f3
 						 gchar **out_picture_data, /* base64-encoded */
acc9f3
 						 GCancellable *cancellable,
acc9f3
 						 GError **error);
acc9f3
+void		e_ews_connection_get_user_configuration
acc9f3
+						(EEwsConnection *cnc,
acc9f3
+						 gint pri,
acc9f3
+						 const EwsFolderId *fid,
acc9f3
+						 const gchar *config_name,
acc9f3
+						 EEwsUserConfigurationProperties props,
acc9f3
+						 GCancellable *cancellable,
acc9f3
+						 GAsyncReadyCallback callback,
acc9f3
+						 gpointer user_data);
acc9f3
+gboolean	e_ews_connection_get_user_configuration_finish
acc9f3
+						(EEwsConnection *cnc,
acc9f3
+						 GAsyncResult *result,
acc9f3
+						 gchar **out_properties,
acc9f3
+						 GError **error);
acc9f3
+gboolean	e_ews_connection_get_user_configuration_sync
acc9f3
+						(EEwsConnection *cnc,
acc9f3
+						 gint pri,
acc9f3
+						 const EwsFolderId *fid,
acc9f3
+						 const gchar *config_name,
acc9f3
+						 EEwsUserConfigurationProperties props,
acc9f3
+						 gchar **out_properties,
acc9f3
+						 GCancellable *cancellable,
acc9f3
+						 GError **error);
acc9f3
 
acc9f3
 G_END_DECLS
acc9f3
 
acc9f3
diff -up evolution-ews-3.28.5/src/server/e-soap-response.c.sync-category-list evolution-ews-3.28.5/src/server/e-soap-response.c
acc9f3
--- evolution-ews-3.28.5/src/server/e-soap-response.c.sync-category-list	2018-07-30 16:01:00.000000000 +0200
acc9f3
+++ evolution-ews-3.28.5/src/server/e-soap-response.c	2019-10-24 09:39:08.342278207 +0200
acc9f3
@@ -685,3 +685,29 @@ e_soap_response_dump_response (ESoapResp
acc9f3
 
acc9f3
 	return ret;
acc9f3
 }
acc9f3
+
acc9f3
+gchar *
acc9f3
+e_soap_response_dump_parameter (ESoapResponse *response,
acc9f3
+				ESoapParameter *param)
acc9f3
+{
acc9f3
+	xmlBuffer *buffer;
acc9f3
+	gint len;
acc9f3
+	gchar *data;
acc9f3
+
acc9f3
+	g_return_val_if_fail (E_IS_SOAP_RESPONSE (response), NULL);
acc9f3
+	g_return_val_if_fail (param != NULL, NULL);
acc9f3
+
acc9f3
+	buffer = xmlBufferCreate ();
acc9f3
+	len = xmlNodeDump (buffer, response->priv->xmldoc, param, 0, 0);
acc9f3
+
acc9f3
+	if (len <= 0) {
acc9f3
+		xmlBufferFree (buffer);
acc9f3
+		return NULL;
acc9f3
+	}
acc9f3
+
acc9f3
+	data = g_strndup ((const gchar *) buffer->content, len);
acc9f3
+
acc9f3
+	xmlBufferFree (buffer);
acc9f3
+
acc9f3
+	return data;
acc9f3
+}
acc9f3
diff -up evolution-ews-3.28.5/src/server/e-soap-response.h.sync-category-list evolution-ews-3.28.5/src/server/e-soap-response.h
acc9f3
--- evolution-ews-3.28.5/src/server/e-soap-response.h.sync-category-list	2018-07-30 16:01:00.000000000 +0200
acc9f3
+++ evolution-ews-3.28.5/src/server/e-soap-response.h	2019-10-24 09:39:08.343278207 +0200
acc9f3
@@ -101,6 +101,8 @@ ESoapParameter *
acc9f3
 						 const gchar *name);
acc9f3
 gint		e_soap_response_dump_response	(ESoapResponse *response,
acc9f3
 						 FILE *buffer);
acc9f3
+gchar *		e_soap_response_dump_parameter	(ESoapResponse *response,
acc9f3
+						 ESoapParameter *param);
acc9f3
 
acc9f3
 G_END_DECLS
acc9f3