[evolution-ews] I#24 - Sync CategoryList with mail Labels
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews] I#24 - Sync CategoryList with mail Labels
- Date: Wed, 24 Oct 2018 15:42:50 +0000 (UTC)
commit e984c384fa712e0c1dfef4e776b1366569547c32
Author: Milan Crha <mcrha redhat com>
Date: Wed Oct 24 17:43:29 2018 +0200
I#24 - Sync CategoryList with mail Labels
Closes https://gitlab.gnome.org/GNOME/evolution-ews/issues/24
src/camel/camel-ews-store-summary.c | 157 +++++++++++++++
src/camel/camel-ews-store-summary.h | 17 ++
src/camel/camel-ews-store.c | 54 +++++
src/camel/camel-ews-utils.c | 388 ++++++++++++++++++++++++++++++++----
src/camel/camel-ews-utils.h | 5 +-
src/server/e-ews-connection.c | 243 +++++++++++++++++++++-
src/server/e-ews-connection.h | 32 +++
src/server/e-soap-response.c | 26 +++
src/server/e-soap-response.h | 2 +
9 files changed, 873 insertions(+), 51 deletions(-)
---
diff --git a/src/camel/camel-ews-store-summary.c b/src/camel/camel-ews-store-summary.c
index 22511996..43ca0326 100644
--- a/src/camel/camel-ews-store-summary.c
+++ b/src/camel/camel-ews-store-summary.c
@@ -31,6 +31,7 @@
#define S_UNLOCK(x) (g_rec_mutex_unlock(&(x)->priv->s_lock))
#define STORE_GROUP_NAME "##storepriv"
+#define CATEGORIES_KEY "Categories"
#define CURRENT_SUMMARY_VERSION 3
struct _CamelEwsStoreSummaryPrivate {
@@ -1047,3 +1048,159 @@ camel_ews_store_summary_has_folder (CamelEwsStoreSummary *ews_summary,
return ret;
}
+
+static gchar *
+camel_ews_category_to_string (const CamelEwsCategory *cat)
+{
+ gchar *guid, *name, *color_def = NULL, *str;
+
+ g_return_val_if_fail (cat != NULL, NULL);
+
+ guid = g_uri_escape_string (cat->guid, NULL, TRUE);
+ name = g_uri_escape_string (cat->name, NULL, TRUE);
+
+ if (cat->color_def)
+ color_def = g_uri_escape_string (cat->color_def, NULL, TRUE);
+
+ str = g_strconcat (
+ guid ? guid : "", "\t",
+ name ? name : "", "\t",
+ color_def ? color_def : "",
+ NULL);
+
+ g_free (guid);
+ g_free (name);
+ g_free (color_def);
+
+ return str;
+}
+
+static CamelEwsCategory *
+camel_ews_category_from_string (const gchar *str)
+{
+ CamelEwsCategory *cat;
+ gchar **strv, *guid, *name, *color_def;
+
+ 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;
+ }
+
+ guid = g_uri_unescape_string (strv[0], NULL);
+ name = g_uri_unescape_string (strv[1], NULL);
+ color_def = (strv[2] && strv[2][0]) ? g_uri_unescape_string (strv[2], NULL) : NULL;
+
+ cat = camel_ews_category_new (guid, name, color_def);
+
+ g_free (guid);
+ g_free (name);
+ g_free (color_def);
+ g_strfreev (strv);
+
+ return cat;
+}
+
+GHashTable * /* gchar *guid ~> CamelEwsCategory * */
+camel_ews_store_summary_get_categories (CamelEwsStoreSummary *ews_summary)
+{
+ GHashTable *categories;
+ gchar **strv;
+ g_return_val_if_fail (CAMEL_IS_EWS_STORE_SUMMARY (ews_summary), NULL);
+
+ S_LOCK (ews_summary);
+
+ strv = g_key_file_get_string_list (ews_summary->priv->key_file, STORE_GROUP_NAME, CATEGORIES_KEY,
NULL, NULL);
+
+ S_UNLOCK (ews_summary);
+
+ categories = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, camel_ews_category_free);
+
+ if (strv) {
+ gint ii;
+
+ for (ii = 0; strv[ii]; ii++) {
+ CamelEwsCategory *cat;
+
+ cat = camel_ews_category_from_string (strv[ii]);
+ if (cat)
+ g_hash_table_insert (categories, cat->guid, cat);
+ }
+
+ g_strfreev (strv);
+ }
+
+ return categories;
+}
+
+void
+camel_ews_store_summary_set_categories (CamelEwsStoreSummary *ews_summary,
+ GHashTable *categories) /* gchar *guid ~> CamelEwsCategory * */
+{
+ GPtrArray *array;
+ GHashTableIter iter;
+ gpointer value;
+
+ g_return_if_fail (CAMEL_IS_EWS_STORE_SUMMARY (ews_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)) {
+ CamelEwsCategory *cat = value;
+
+ if (cat) {
+ gchar *str;
+
+ str = camel_ews_category_to_string (cat);
+
+ if (str)
+ g_ptr_array_add (array, str);
+ }
+ }
+
+ S_LOCK (ews_summary);
+
+ g_key_file_set_string_list (ews_summary->priv->key_file, STORE_GROUP_NAME, CATEGORIES_KEY,
+ (const gchar * const *) array->pdata, array->len);
+
+ ews_summary->priv->dirty = TRUE;
+
+ S_UNLOCK (ews_summary);
+
+ g_ptr_array_free (array, TRUE);
+}
+
+CamelEwsCategory *
+camel_ews_category_new (const gchar *guid,
+ const gchar *name,
+ const gchar *color_def)
+{
+ CamelEwsCategory *cat;
+
+ g_return_val_if_fail (guid != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ cat = g_new0 (CamelEwsCategory, 1);
+ cat->guid = g_strdup (guid);
+ cat->name = g_strdup (name);
+ cat->color_def = g_strdup (color_def);
+
+ return cat;
+}
+
+void
+camel_ews_category_free (gpointer ptr)
+{
+ CamelEwsCategory *cat = ptr;
+
+ if (cat) {
+ g_free (cat->guid);
+ g_free (cat->name);
+ g_free (cat->color_def);
+ g_free (cat);
+ }
+}
diff --git a/src/camel/camel-ews-store-summary.h b/src/camel/camel-ews-store-summary.h
index 0ae13e32..1c6723cc 100644
--- a/src/camel/camel-ews-store-summary.h
+++ b/src/camel/camel-ews-store-summary.h
@@ -50,6 +50,12 @@
G_BEGIN_DECLS
+typedef struct _CamelEwsCategory {
+ gchar *guid;
+ gchar *name;
+ gchar *color_def;
+} CamelEwsCategory;
+
typedef struct _CamelEwsStoreSummary CamelEwsStoreSummary;
typedef struct _CamelEwsStoreSummaryClass CamelEwsStoreSummaryClass;
typedef struct _CamelEwsStoreSummaryPrivate CamelEwsStoreSummaryPrivate;
@@ -215,6 +221,17 @@ gchar * camel_ews_store_summary_get_folder_id_from_folder_type
gboolean camel_ews_store_summary_has_folder
(CamelEwsStoreSummary *ews_summary,
const gchar *id);
+GHashTable * camel_ews_store_summary_get_categories /* gchar *guid ~> CamelEwsCategory * */
+ (CamelEwsStoreSummary *ews_summary);
+void camel_ews_store_summary_set_categories
+ (CamelEwsStoreSummary *ews_summary,
+ GHashTable *categories); /* gchar *guid ~> CamelEwsCategory
* */
+
+CamelEwsCategory *
+ camel_ews_category_new (const gchar *guid,
+ const gchar *name,
+ const gchar *color_def);
+void camel_ews_category_free (gpointer ptr); /* CamelEwsCategory * */
G_END_DECLS
diff --git a/src/camel/camel-ews-store.c b/src/camel/camel-ews-store.c
index ba97df0b..aee2580e 100644
--- a/src/camel/camel-ews-store.c
+++ b/src/camel/camel-ews-store.c
@@ -673,6 +673,43 @@ ews_update_has_ooo_set (CamelSession *session,
g_clear_object (&oof_settings);
}
+static void
+ews_exchange_server_categories_cb (CamelSession *session,
+ GCancellable *cancellable,
+ gpointer user_data,
+ GError **error)
+{
+ CamelEwsStore *ews_store = user_data;
+ EEwsConnection *cnc;
+ EwsFolderId fid = { 0 };
+ gchar *properties = NULL;
+ GError *local_error = NULL;
+
+ cnc = camel_ews_store_ref_connection (ews_store);
+ if (!cnc)
+ return;
+
+ fid.id = (gchar *) "calendar";
+ fid.is_distinguished_id = TRUE;
+
+ if (e_ews_connection_get_user_configuration_sync (cnc, G_PRIORITY_DEFAULT, &fid, "CategoryList",
+ E_EWS_USER_CONFIGURATION_PROPERTIES_XMLDATA, &properties, cancellable, &local_error) &&
properties) {
+ guchar *data;
+ gsize data_len = 0;
+
+ data = g_base64_decode (properties, &data_len);
+
+ if (data && data_len > 0)
+ camel_ews_utils_merge_category_list (ews_store, data, data_len);
+
+ g_free (data);
+ }
+
+ g_clear_error (&local_error);
+ g_clear_object (&cnc);
+ g_free (properties);
+}
+
struct ScheduleUpdateData
{
GCancellable *cancellable;
@@ -1252,6 +1289,12 @@ ews_connect_sync (CamelService *service,
g_object_ref (ews_store),
g_object_unref);
+ camel_session_submit_job (
+ session, _("Look up Exchange server categories"),
+ ews_exchange_server_categories_cb,
+ g_object_ref (ews_store),
+ g_object_unref);
+
if (!priv->updates_cancellable)
priv->updates_cancellable = g_cancellable_new ();
@@ -2371,6 +2414,17 @@ ews_get_folder_info_sync (CamelStore *store,
ews_store = (CamelEwsStore *) store;
priv = ews_store->priv;
+ if ((flags & CAMEL_STORE_FOLDER_INFO_REFRESH) != 0 &&
+ camel_offline_store_get_online (CAMEL_OFFLINE_STORE (ews_store))) {
+ CamelSession *session;
+
+ session = camel_service_ref_session (CAMEL_SERVICE (ews_store));
+ if (session) {
+ ews_exchange_server_categories_cb (session, cancellable, ews_store, NULL);
+ g_object_unref (session);
+ }
+ }
+
if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0) {
gboolean includes_last_folder = TRUE;
GSList *folders = NULL, *to_check = NULL;
diff --git a/src/camel/camel-ews-utils.c b/src/camel/camel-ews-utils.c
index bf03a3af..4368b184 100644
--- a/src/camel/camel-ews-utils.c
+++ b/src/camel/camel-ews-utils.c
@@ -29,6 +29,7 @@
#include <glib/gstdio.h>
#include <libemail-engine/libemail-engine.h>
+#include <e-util/e-util.h>
#include "server/camel-ews-settings.h"
#include "server/e-ews-camel-common.h"
@@ -386,6 +387,43 @@ camel_ews_utils_sync_deleted_items (CamelEwsFolder *ews_folder,
g_slist_free (items_deleted);
}
+static const gchar *
+ews_utils_outlook_color_index_to_color_def (gint color_index)
+{
+ 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 */
+ };
+
+ if (color_index >= 0 && color_index < G_N_ELEMENTS (colors_array))
+ return colors_array[color_index];
+
+ return NULL;
+}
+
static const gchar *
ews_utils_rename_label (const gchar *cat,
gboolean from_cat)
@@ -428,6 +466,58 @@ ews_utils_is_system_user_flag (const gchar *name)
g_str_equal (name, "$has-cal");
}
+/* From Exchange name (which allows spaces) to evolution-name */
+static gchar *
+camel_ews_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 Exchange name (which allows spaces) */
+static gchar *
+camel_ews_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);
+}
+
/* free with g_slist_free_full (flags, g_free);
the lists' members are values for the String xml element. */
GSList *
@@ -447,6 +537,7 @@ ews_utils_gather_server_user_flags (ESoapMessage *msg,
* array of strings */
for (ii = 0; ii < len; ii++) {
const gchar *n = ews_utils_rename_label (camel_named_flags_get (user_flags, ii), FALSE);
+
if (*n == '\0')
continue;
@@ -455,26 +546,7 @@ ews_utils_gather_server_user_flags (ESoapMessage *msg,
if (ews_utils_is_system_user_flag (n))
continue;
- if (strchr (n, '_')) {
- GString *str = g_string_sized_new (strlen (n));
-
- while (*n) {
- if (*n == '_') {
- if (n[1] == '_')
- g_string_append_c (str, '_');
- else
- g_string_append_c (str, ' ');
- } else {
- g_string_append_c (str, *n);
- }
-
- n++;
- }
-
- out_user_flags = g_slist_prepend (out_user_flags, g_string_free (str, FALSE));
- } else {
- out_user_flags = g_slist_prepend (out_user_flags, g_strdup (n));
- }
+ out_user_flags = g_slist_prepend (out_user_flags, camel_ews_utils_decode_category_name (n));
}
camel_message_info_property_unlock (mi);
@@ -518,33 +590,17 @@ ews_utils_merge_server_user_flags (EEwsItem *item,
/* now transfer over all the categories */
for (p = e_ews_item_get_categories (item); p; p = p->next) {
- const gchar *flag = ews_utils_rename_label (p->data, 1);
- gchar *underscored = NULL;
+ const gchar *name = ews_utils_rename_label (p->data, 1);
+ gchar *flag;
- if (!flag || !*flag)
+ if (!name || !*name)
continue;
- if (strchr (flag, ' ')) {
- GString *str;
-
- str = g_string_sized_new (strlen (flag) + 16);
-
- while (*flag) {
- if (*flag == '_')
- g_string_append_c (str, '_');
-
- g_string_append_c (str, *flag == ' ' ? '_' : *flag);
-
- flag++;
- }
-
- underscored = g_string_free (str, FALSE);
- flag = underscored;
- }
+ flag = camel_ews_utils_encode_category_name (name);
camel_message_info_set_user_flag (mi, flag, TRUE);
- g_free (underscored);
+ g_free (flag);
}
camel_message_info_thaw_notifications (mi);
@@ -1402,3 +1458,253 @@ camel_ews_utils_ref_corresponding_source (CamelService *service,
return source;
}
+
+static gboolean
+ews_util_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)];
+}
+
+/* Returns whether had been done any changes */
+static gboolean
+ews_utils_save_category_changes (GHashTable *old_categories, /* gchar *guid ~> CamelEwsCategory * */
+ GHashTable *new_categories) /* gchar *guid ~> CamelEwsCategory * */
+{
+ 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)) {
+ CamelEwsCategory *new_cat = value, *old_cat;
+ gchar *tag = NULL;
+
+ if (!new_cat)
+ continue;
+
+ old_cat = g_hash_table_lookup (old_categories, new_cat->guid);
+ if (old_cat) {
+ if (g_strcmp0 (old_cat->name, new_cat->name) != 0 ||
+ g_strcmp0 (old_cat->color_def, new_cat->color_def) != 0) {
+ /* Old category changed name or color */
+ tag = camel_ews_utils_encode_category_name (new_cat->name);
+ }
+ } else {
+ /* This is a new category */
+ tag = camel_ews_utils_encode_category_name (new_cat->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->name, new_cat->name) != 0) {
+ gchar *old_tag = camel_ews_utils_encode_category_name (old_cat->name);
+
+ if (old_tag && *old_tag) {
+ if (!g_ptr_array_find_with_equal_func (evo_labels, old_tag,
ews_util_equal_label_tag_cb, &index))
+ index = (guint) -1;
+ }
+
+ g_free (old_tag);
+ }
+
+ for (ii = 0; new_cat->name[ii]; ii++) {
+ if (new_cat->name[ii] == '|')
+ new_cat->name[ii] = '-';
+ }
+
+ if (index == (guint) -1 &&
+ !g_ptr_array_find_with_equal_func (evo_labels, tag, ews_util_equal_label_tag_cb,
&index))
+ index = (guint) -1;
+
+ label_def = g_strconcat (new_cat->name, "|", new_cat->color_def ? new_cat->color_def
: "#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->guid);
+
+ 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)) {
+ CamelEwsCategory *old_cat = value;
+ gchar *old_tag;
+ guint index;
+
+ if (!old_cat)
+ continue;
+
+ old_tag = camel_ews_utils_encode_category_name (old_cat->name);
+
+ for (ii = 0; old_tag && old_tag[ii]; ii++) {
+ if (old_tag[ii] == '|')
+ old_tag[ii] = '-';
+ }
+
+ if (old_tag &&
+ g_ptr_array_find_with_equal_func (evo_labels, old_tag,
ews_util_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;
+}
+
+void
+camel_ews_utils_merge_category_list (CamelEwsStore *ews_store,
+ const guchar *xml_data,
+ gsize xml_data_len)
+{
+ xmlDocPtr doc;
+ xmlXPathContextPtr xpath_ctx;
+
+ g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store));
+ g_return_if_fail (xml_data != NULL);
+
+ doc = e_xml_parse_data (xml_data, xml_data_len);
+ if (!doc)
+ return;
+
+ xpath_ctx = e_xml_new_xpath_context_with_namespaces (doc, "C", "CategoryList.xsd", NULL);
+
+ if (xpath_ctx) {
+ xmlXPathObjectPtr xpath_obj_categories;
+
+ xpath_obj_categories = e_xml_xpath_eval (xpath_ctx, "%s", "/C:categories/C:category");
+
+ if (xpath_obj_categories) {
+ GHashTable *old_categories, *new_categories;
+ gint response_index, response_length;
+
+ new_categories = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
camel_ews_category_free);
+
+ response_length = xmlXPathNodeSetGetLength (xpath_obj_categories->nodesetval);
+
+ for (response_index = 0; response_index < response_length; response_index++) {
+ xmlXPathObjectPtr xpath_obj_category;
+
+ xpath_obj_category = e_xml_xpath_eval (xpath_ctx,
+ "/C:categories/C:category[%d]",
+ response_index + 1);
+
+ if (xpath_obj_category) {
+ gchar *name;
+
+ name = e_xml_xpath_eval_as_string (xpath_ctx,
"/C:categories/C:category[%d]/@name", response_index + 1);
+
+ if (name && ews_utils_rename_label (name, 1) == name) {
+ const gchar *color_def = NULL;
+ gchar *color, *guid;
+ gint color_index = -1;
+
+ color = e_xml_xpath_eval_as_string (xpath_ctx,
"/C:categories/C:category[%d]/@color", response_index + 1);
+ if (color) {
+ gchar *endptr = NULL;
+
+ color_index = (gint) g_ascii_strtoll (color, &endptr,
10);
+
+ if (endptr == color)
+ color_index = -1;
+ }
+
+ g_free (color);
+
+ if (color_index >= 0)
+ color_def =
ews_utils_outlook_color_index_to_color_def (color_index);
+
+ guid = e_xml_xpath_eval_as_string (xpath_ctx,
"/C:categories/C:category[%d]/@guid", response_index + 1);
+
+ if (guid && *guid) {
+ CamelEwsCategory *cat;
+
+ cat = camel_ews_category_new (guid, name, color_def);
+ if (cat)
+ g_hash_table_insert (new_categories,
cat->guid, cat);
+ }
+
+ g_free (guid);
+ }
+
+ g_free (name);
+ xmlXPathFreeObject (xpath_obj_category);
+ }
+ }
+
+ xmlXPathFreeObject (xpath_obj_categories);
+
+ old_categories = camel_ews_store_summary_get_categories (ews_store->summary);
+
+ if (ews_utils_save_category_changes (old_categories, new_categories)) {
+ camel_ews_store_summary_set_categories (ews_store->summary, new_categories);
+ camel_ews_store_summary_save (ews_store->summary, NULL);
+ }
+
+ g_hash_table_destroy (new_categories);
+ g_hash_table_destroy (old_categories);
+ }
+ }
+
+ if (xpath_ctx)
+ xmlXPathFreeContext (xpath_ctx);
+ xmlFreeDoc (doc);
+}
diff --git a/src/camel/camel-ews-utils.h b/src/camel/camel-ews-utils.h
index 3e6ee0ac..6a7a9a8a 100644
--- a/src/camel/camel-ews-utils.h
+++ b/src/camel/camel-ews-utils.h
@@ -100,7 +100,10 @@ CamelMessageInfo * /* (transfer full) */
GCancellable *cancellable);
gboolean camel_ews_utils_folder_is_drafts_folder
(CamelEwsFolder *ews_folder);
-
+void camel_ews_utils_merge_category_list
+ (CamelEwsStore *ews_store,
+ const guchar *xml_data,
+ gsize xml_data_len);
G_END_DECLS
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index 257e2a68..46315e2f 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -152,7 +152,7 @@ struct _EwsAsyncData {
EwsDelegateDeliver deliver_to;
EEwsFolderType folder_type;
EEwsConnection *cnc;
- gchar *user_photo; /* base64-encoded, as GetUserPhoto result */
+ gchar *custom_data; /* Can be re-used by operations, will be freed with g_free() */
};
struct _EwsNode {
@@ -197,7 +197,7 @@ ews_connection_error_quark (void)
static void
async_data_free (EwsAsyncData *async_data)
{
- g_free (async_data->user_photo);
+ g_free (async_data->custom_data);
g_free (async_data);
}
@@ -10789,10 +10789,10 @@ get_user_photo_response_cb (ESoapResponse *response,
return;
}
- async_data->user_photo = e_soap_parameter_get_string_value (param);
- if (async_data->user_photo && !*async_data->user_photo) {
- g_free (async_data->user_photo);
- async_data->user_photo = NULL;
+ async_data->custom_data = e_soap_parameter_get_string_value (param);
+ if (async_data->custom_data && !*async_data->custom_data) {
+ g_free (async_data->custom_data);
+ async_data->custom_data = NULL;
}
}
@@ -10877,11 +10877,11 @@ e_ews_connection_get_user_photo_finish (EEwsConnection *cnc,
if (g_simple_async_result_propagate_error (simple, error))
return FALSE;
- if (!async_data->user_photo)
+ if (!async_data->custom_data)
return FALSE;
- *out_picture_data = async_data->user_photo;
- async_data->user_photo = NULL;
+ *out_picture_data = async_data->custom_data;
+ async_data->custom_data = NULL;
return TRUE;
}
@@ -10914,3 +10914,228 @@ e_ews_connection_get_user_photo_sync (EEwsConnection *cnc,
return success;
}
+
+static void
+get_user_configuration_response_cb (ESoapResponse *response,
+ GSimpleAsyncResult *simple)
+{
+ EwsAsyncData *async_data;
+ ESoapParameter *param, *subparam;
+ GError *error = NULL;
+
+ async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ param = e_soap_response_get_first_parameter_by_name (response, "ResponseMessages", &error);
+
+ if (param) {
+ param = e_soap_parameter_get_first_child_by_name (param,
"GetUserConfigurationResponseMessage");
+ if (!param) {
+ g_set_error (&error,
+ SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED,
+ "Missing <%s> in SOAP response", "GetUserConfigurationResponseMessage");
+ }
+ }
+
+ if (param) {
+ param = e_soap_parameter_get_first_child_by_name (param, "UserConfiguration");
+ if (!param) {
+ g_set_error (&error,
+ SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED,
+ "Missing <%s> in SOAP response", "UserConfiguration");
+ }
+ }
+
+ /* Sanity check */
+ g_return_if_fail (
+ (param != NULL && error == NULL) ||
+ (param == NULL && error != NULL));
+
+ if (error != NULL) {
+ g_simple_async_result_take_error (simple, error);
+ return;
+ }
+
+ subparam = e_soap_parameter_get_first_child_by_name (param, "ItemId");
+ if (subparam) {
+ gchar *id, *changekey;
+
+ id = e_soap_parameter_get_property (subparam, "Id");
+ changekey = e_soap_parameter_get_property (subparam, "ChangeKey");
+
+ /* Encoded as: Id + "\n" + ChangeKey */
+ async_data->custom_data = g_strconcat (id ? id : "", "\n", changekey, NULL);
+
+ g_free (changekey);
+ g_free (id);
+ }
+
+ if (!subparam) {
+ subparam = e_soap_parameter_get_first_child_by_name (param, "Dictionary");
+ if (subparam)
+ async_data->custom_data = e_soap_response_dump_parameter (response, subparam);
+ }
+
+ if (!subparam) {
+ subparam = e_soap_parameter_get_first_child_by_name (param, "XmlData");
+ if (subparam) {
+ async_data->custom_data = e_soap_parameter_get_string_value (subparam);
+ }
+ }
+
+ if (!subparam) {
+ subparam = e_soap_parameter_get_first_child_by_name (param, "BinaryData");
+ if (subparam) {
+ async_data->custom_data = e_soap_parameter_get_string_value (subparam);
+ }
+ }
+
+ if (async_data->custom_data && !*async_data->custom_data) {
+ g_free (async_data->custom_data);
+ async_data->custom_data = NULL;
+ }
+}
+
+void
+e_ews_connection_get_user_configuration (EEwsConnection *cnc,
+ gint pri,
+ const EwsFolderId *fid,
+ const gchar *config_name,
+ EEwsUserConfigurationProperties props,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ESoapMessage *msg;
+ GSimpleAsyncResult *simple;
+ EwsAsyncData *async_data;
+ EwsFolderId local_fid;
+
+ g_return_if_fail (cnc != NULL);
+ g_return_if_fail (cnc->priv != NULL);
+ g_return_if_fail (fid != NULL);
+ g_return_if_fail (config_name != NULL);
+
+ simple = g_simple_async_result_new (G_OBJECT (cnc), callback, user_data,
e_ews_connection_get_user_configuration);
+ async_data = g_new0 (EwsAsyncData, 1);
+ g_simple_async_result_set_op_res_gpointer (simple, async_data, (GDestroyNotify) async_data_free);
+
+ /* EWS server version earlier than 2010 doesn't support it. */
+ if (!e_ews_connection_satisfies_server_version (cnc, E_EWS_EXCHANGE_2010)) {
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ local_fid = *fid;
+ local_fid.change_key = NULL;
+
+ msg = e_ews_message_new_with_header (
+ cnc->priv->settings,
+ cnc->priv->uri,
+ cnc->priv->impersonate_user,
+ "GetUserConfiguration",
+ NULL,
+ NULL,
+ cnc->priv->version,
+ E_EWS_EXCHANGE_2010,
+ FALSE,
+ TRUE);
+
+ e_soap_message_start_element (msg, "UserConfigurationName", "messages", NULL);
+ e_soap_message_add_attribute (msg, "Name", config_name, NULL, NULL);
+
+ e_ews_folder_id_append_to_msg (msg, cnc->priv->email, &local_fid);
+
+ e_soap_message_end_element (msg); /* UserConfigurationName */
+
+ e_soap_message_start_element (msg, "UserConfigurationProperties", "messages", NULL);
+
+ switch (props) {
+ case E_EWS_USER_CONFIGURATION_PROPERTIES_ID:
+ e_soap_message_write_string (msg, "Id");
+ break;
+ case E_EWS_USER_CONFIGURATION_PROPERTIES_DICTIONARY:
+ e_soap_message_write_string (msg, "Dictionary");
+ break;
+ case E_EWS_USER_CONFIGURATION_PROPERTIES_XMLDATA:
+ e_soap_message_write_string (msg, "XmlData");
+ break;
+ case E_EWS_USER_CONFIGURATION_PROPERTIES_BINARYDATA:
+ e_soap_message_write_string (msg, "BinaryData");
+ break;
+ /* case E_EWS_USER_CONFIGURATION_PROPERTIES_ALL:
+ e_soap_message_write_string (msg, "All");
+ break; */
+ default:
+ e_soap_message_write_string (msg, "Unknown");
+ break;
+ }
+
+ e_soap_message_end_element (msg); /* UserConfigurationProperties */
+
+ e_ews_message_write_footer (msg);
+
+ e_ews_connection_queue_request (cnc, msg, get_user_configuration_response_cb, pri, cancellable,
simple);
+
+ g_object_unref (simple);
+}
+
+gboolean
+e_ews_connection_get_user_configuration_finish (EEwsConnection *cnc,
+ GAsyncResult *result,
+ gchar **out_properties,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ EwsAsyncData *async_data;
+
+ g_return_val_if_fail (cnc != NULL, FALSE);
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (result, G_OBJECT (cnc),
e_ews_connection_get_user_configuration),
+ FALSE);
+ g_return_val_if_fail (out_properties != NULL, FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ if (!async_data->custom_data)
+ return FALSE;
+
+ *out_properties = async_data->custom_data;
+ async_data->custom_data = NULL;
+
+ return TRUE;
+}
+
+gboolean
+e_ews_connection_get_user_configuration_sync (EEwsConnection *cnc,
+ gint pri,
+ const EwsFolderId *fid,
+ const gchar *config_name,
+ EEwsUserConfigurationProperties props,
+ gchar **out_properties,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (cnc != NULL, FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_ews_connection_get_user_configuration (
+ cnc, pri, fid, config_name, props, cancellable, e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_ews_connection_get_user_configuration_finish (cnc, result, out_properties, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
diff --git a/src/server/e-ews-connection.h b/src/server/e-ews-connection.h
index fa8edc93..b483a4b4 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -133,6 +133,15 @@ typedef enum {
E_EWS_SIZE_REQUESTED_648X648 = 648
} EEwsSizeRequested;
+typedef enum {
+ E_EWS_USER_CONFIGURATION_PROPERTIES_UNKNOWN = -1,
+ E_EWS_USER_CONFIGURATION_PROPERTIES_ID,
+ E_EWS_USER_CONFIGURATION_PROPERTIES_DICTIONARY,
+ E_EWS_USER_CONFIGURATION_PROPERTIES_XMLDATA,
+ E_EWS_USER_CONFIGURATION_PROPERTIES_BINARYDATA /*,
+ E_EWS_USER_CONFIGURATION_PROPERTIES_ALL - skip it, be specific */
+} EEwsUserConfigurationProperties;
+
typedef struct {
gchar *id;
gchar *dn;
@@ -1372,6 +1381,29 @@ gboolean e_ews_connection_get_user_photo_sync
gchar **out_picture_data, /* base64-encoded */
GCancellable *cancellable,
GError **error);
+void e_ews_connection_get_user_configuration
+ (EEwsConnection *cnc,
+ gint pri,
+ const EwsFolderId *fid,
+ const gchar *config_name,
+ EEwsUserConfigurationProperties props,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_ews_connection_get_user_configuration_finish
+ (EEwsConnection *cnc,
+ GAsyncResult *result,
+ gchar **out_properties,
+ GError **error);
+gboolean e_ews_connection_get_user_configuration_sync
+ (EEwsConnection *cnc,
+ gint pri,
+ const EwsFolderId *fid,
+ const gchar *config_name,
+ EEwsUserConfigurationProperties props,
+ gchar **out_properties,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/src/server/e-soap-response.c b/src/server/e-soap-response.c
index 29b9e227..6cc57ca1 100644
--- a/src/server/e-soap-response.c
+++ b/src/server/e-soap-response.c
@@ -685,3 +685,29 @@ e_soap_response_dump_response (ESoapResponse *response,
return ret;
}
+
+gchar *
+e_soap_response_dump_parameter (ESoapResponse *response,
+ ESoapParameter *param)
+{
+ xmlBuffer *buffer;
+ gint len;
+ gchar *data;
+
+ g_return_val_if_fail (E_IS_SOAP_RESPONSE (response), NULL);
+ g_return_val_if_fail (param != NULL, NULL);
+
+ buffer = xmlBufferCreate ();
+ len = xmlNodeDump (buffer, response->priv->xmldoc, param, 0, 0);
+
+ if (len <= 0) {
+ xmlBufferFree (buffer);
+ return NULL;
+ }
+
+ data = g_strndup ((const gchar *) buffer->content, len);
+
+ xmlBufferFree (buffer);
+
+ return data;
+}
diff --git a/src/server/e-soap-response.h b/src/server/e-soap-response.h
index 11843797..25ce77be 100644
--- a/src/server/e-soap-response.h
+++ b/src/server/e-soap-response.h
@@ -101,6 +101,8 @@ ESoapParameter *
const gchar *name);
gint e_soap_response_dump_response (ESoapResponse *response,
FILE *buffer);
+gchar * e_soap_response_dump_parameter (ESoapResponse *response,
+ ESoapParameter *param);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]