[Evolution-hackers] [PATCH v2] evolution-ews: implement Exchange categories as evolution labels



From: James Bottomley <jbottomley parallels com>

This patch adds evolution labels to an exchange back end via
outlook categories.  The outlook categories perform roughly the
same function and evolution even mirrors their colour scheme.

This patch allows evolution to fill in the labels from the EWS
Category element.  That means that any colour you add to a message via
the categories in outlook (or the outlook web server) automatically
appears in evolution and vice versa.

Signed-off-by: James Bottomley <jbottomley parallels com>

---

I suppose the label mapping is still going to be controversial, but I
don't see how to make it all just work (tm) without that.  I've done
some reasonably extensive testing (and run into several sync issues,
which are now fixed).

James

diff --git a/src/camel/camel-ews-folder.c b/src/camel/camel-ews-folder.c
index 7e20fc2..d71f359 100644
--- a/src/camel/camel-ews-folder.c
+++ b/src/camel/camel-ews-folder.c
@@ -60,7 +60,7 @@ which needs to be better organized via functions */
 
 #define MAX_ATTACHMENT_SIZE 1*1024*1024   /*In bytes*/
 
-#define SUMMARY_ITEM_FLAGS "item:ResponseObjects item:Sensitivity item:Importance"
+#define SUMMARY_ITEM_FLAGS "item:ResponseObjects item:Sensitivity item:Importance item:Categories"
 #define ITEM_PROPS "item:Subject item:DateTimeReceived item:DateTimeSent item:DateTimeCreated item:Size " \
 		   "item:HasAttachments item:InReplyTo"
 #define SUMMARY_ITEM_PROPS ITEM_PROPS " " SUMMARY_ITEM_FLAGS
@@ -638,6 +638,22 @@ msg_update_flags (ESoapMessage *msg, gpointer user_data)
 			e_soap_message_end_element (msg); /* Message */
 			e_soap_message_end_element (msg); /* SetItemField */
 		}
+		/* now update the Categories */
+		e_soap_message_start_element (msg, "SetItemField", NULL, NULL);
+
+		e_soap_message_start_element (msg, "FieldURI", NULL, NULL);
+		e_soap_message_add_attribute (msg, "FieldURI", "item:Categories", NULL, NULL);
+		e_soap_message_end_element (msg);
+
+		e_soap_message_start_element (msg, "Message", NULL, NULL);
+		e_soap_message_start_element (msg, "Categories", NULL, NULL);
+
+		ews_utils_replace_server_user_flags(msg, mi);
+
+		e_soap_message_end_element (msg); /* Categories */
+		e_soap_message_end_element (msg); /* Message */
+		e_soap_message_end_element (msg); /* SetItemField */
+
 		e_ews_message_end_item_change (msg);
 
 		camel_message_info_free (mi);
@@ -698,7 +714,11 @@ ews_synchronize_sync (CamelFolder *folder, gboolean expunge, EVO3(GCancellable *
 		} else if (flags_changed & CAMEL_MESSAGE_DELETED) {
 			deleted_uids = g_slist_prepend (deleted_uids, (gpointer) camel_pstring_strdup (uids->pdata [i]));
 			camel_message_info_free (mi);
-		}
+		} else {
+			/* OK, the change must have been the labels */
+			mi_list = g_slist_append (mi_list, mi);
+			mi_list_len++;
+		}			
 
 		if (mi_list_len == EWS_MAX_FETCH_COUNT) {
 			success = ews_sync_mi_flags (folder, mi_list, cancellable, error);
@@ -1328,7 +1348,7 @@ camel_ews_folder_init (CamelEwsFolder *ews_folder)
 
 	folder->permanent_flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_DELETED |
 		CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN |
-		CAMEL_MESSAGE_FORWARDED;
+		CAMEL_MESSAGE_FORWARDED | CAMEL_MESSAGE_USER;
 
 	folder->folder_flags = CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY | CAMEL_FOLDER_HAS_SEARCH_CAPABILITY;
 
diff --git a/src/camel/camel-ews-utils.c b/src/camel/camel-ews-utils.c
index dbddc52..481ae05 100644
--- a/src/camel/camel-ews-utils.c
+++ b/src/camel/camel-ews-utils.c
@@ -33,6 +33,7 @@
 #include "camel-ews-utils.h"
 #include "ews-esource-utils.h"
 #include "e-ews-compat.h"
+#include "e-ews-message.h"
 
 #define SUBFOLDER_DIR_NAME     "subfolders"
 #define SUBFOLDER_DIR_NAME_LEN 10
@@ -651,6 +652,86 @@ camel_ews_utils_sync_deleted_items (CamelEwsFolder *ews_folder, GSList *items_de
 	g_slist_free (items_deleted);
 }
 
+static const gchar*
+ews_utils_rename_label (const gchar *cat, int from_cat)
+{
+	gint i;
+
+	/* this is a mapping from Exchange/Outlook categories to
+	 * evolution labels based on the standard colours */
+	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 (i = 0; labels[i]; i += 2) {
+		if (from_cat) {
+			if (!g_ascii_strcasecmp (cat, labels[i]))
+				return labels[i + 1];
+		} else {
+			if (!g_ascii_strcasecmp (cat, labels[i + 1]))
+				return labels[i];
+		}
+	}
+	return cat;
+}
+
+void
+ews_utils_replace_server_user_flags (ESoapMessage *msg, CamelEwsMessageInfo *mi)
+{
+	const CamelFlag *flag;
+
+	/* transfer camel flags to become the categories as an XML
+	 * array of strings */
+	for (flag = camel_message_info_user_flags (&mi->info); flag;
+	     flag = flag->next) {
+		const gchar *n = ews_utils_rename_label (flag->name, 0);
+		if (*n == '\0')
+			continue;
+		/* This is a mismatch between evolution flags and
+		 * exchange categories.  Evolution uses a
+		 * receipt-handled flag for message receipts, which we
+		 * don't want showing up in the categories, so
+		 * silently drop it here */
+		if (strcmp (n, "receipt-handled") == 0)
+			continue;
+		e_ews_message_write_string_parameter (msg, "String", NULL, n);
+	}
+}
+
+static void
+ews_utils_merge_server_user_flags (EEwsItem *item, CamelEwsMessageInfo *mi)
+{
+	GSList *list = NULL;
+	const GSList *p;
+	const CamelFlag *flag;
+
+	/* transfer camel flags to a list */
+	for (flag = camel_message_info_user_flags (&mi->info); flag;
+	     flag = flag->next)
+		list = g_slist_append (list, (gchar *)flag->name);
+
+	/* we're transferring from server only, so just dump them */
+	for (p = list; p; p = p->next) {
+		camel_flag_set (&mi->info.user_flags, p->data, 0);
+	}
+	//g_slist_foreach(list, (GFunc)g_free, NULL);
+	g_slist_free(list);
+
+	/* now transfer over all the categories */
+	for (p = e_ews_item_get_categories (item); p; p = p->next) {
+		camel_flag_set (&mi->info.user_flags,
+				ews_utils_rename_label(p->data, 1), 1);
+	}
+}
+
 static gint
 ews_utils_get_server_flags (EEwsItem *item)
 {
@@ -833,8 +914,9 @@ camel_ews_utils_sync_updated_items (CamelEwsFolder *ews_folder, GSList *items_up
 			gint server_flags;
 
 			server_flags = ews_utils_get_server_flags (item);
+			ews_utils_merge_server_user_flags (item, mi);
 			if (camel_ews_update_message_info_flags (folder->summary, (CamelMessageInfo *)mi,
-						server_flags, NULL))
+								 server_flags, NULL))
 				camel_folder_change_info_change_uid (ci, mi->info.uid);
 
 			mi->change_key = g_strdup (id->change_key);
diff --git a/src/camel/camel-ews-utils.h b/src/camel/camel-ews-utils.h
index 2c4d02d..961c9a8 100644
--- a/src/camel/camel-ews-utils.h
+++ b/src/camel/camel-ews-utils.h
@@ -89,6 +89,9 @@ void	camel_ews_utils_sync_created_items	(CamelEwsFolder *ews_folder,
 						 GSList *items_created);
 void	camel_ews_utils_sync_updated_items	(CamelEwsFolder *ews_folder,
 						 GSList *items_updated);
+void	ews_utils_replace_server_user_flags	(ESoapMessage *msg,
+						 CamelEwsMessageInfo *mi);
+
 
 G_END_DECLS
 
diff --git a/src/server/e-ews-item.c b/src/server/e-ews-item.c
index c49376f..e66b314 100644
--- a/src/server/e-ews-item.c
+++ b/src/server/e-ews-item.c
@@ -184,6 +184,12 @@ struct _EEwsItemPrivate {
 
 	EwsId *calendar_item_accept_id;
 
+	/* the evolution labels are implemented as exchange
+	 * Categories.  These appear in the message headers as
+	 * Keywords: and are set and extracted from the EWS server as
+	 * <Categories> which is a string array valued XML element */
+	GSList *categories;
+
 	struct _EEwsContactFields *contact_fields;
 	struct _EEwsTaskFields *task_fields;
 };
@@ -503,6 +509,29 @@ static void parse_extended_property (EEwsItemPrivate *priv, ESoapParameter *para
 	}
 }
 
+static void parse_categories (EEwsItemPrivate *priv, ESoapParameter *param)
+{
+	gchar *value;
+	ESoapParameter *subparam;
+
+	/* release all the old data (if any) */
+	if (priv->categories) {
+		g_slist_foreach (priv->categories, (GFunc) g_free, NULL);
+		g_slist_free (priv->categories);
+		priv->categories = NULL;
+	}
+
+	/* categories are an array of <string> */
+	for (subparam = e_soap_parameter_get_first_child(param);
+	     subparam != NULL;
+	     subparam = e_soap_parameter_get_next_child(subparam)) {
+		value = e_soap_parameter_get_string_value (subparam);
+
+		priv->categories = g_slist_append(priv->categories, value);
+	}
+
+}
+
 static EwsImportance
 parse_importance (ESoapParameter *param)
 {
@@ -882,6 +911,8 @@ e_ews_item_set_from_soap_parameter (EEwsItem *item, ESoapParameter *param)
 			g_free (value);
 		} else if (!g_ascii_strcasecmp (name, "Size")) {
 			priv->size = e_soap_parameter_get_int_value (subparam);
+		} else if (!g_ascii_strcasecmp (name, "Categories")) {
+			parse_categories (priv, subparam);
 		} else if (!g_ascii_strcasecmp (name, "Importance")) {
 			priv->importance = parse_importance (subparam);
 		} else if (!g_ascii_strcasecmp (name, "InReplyTo")) {
@@ -1177,6 +1208,14 @@ e_ews_item_get_from		(EEwsItem *item)
 	return (const EwsMailbox *) item->priv->from;
 }
 
+const GSList *
+e_ews_item_get_categories	(EEwsItem *item)
+{
+	g_return_val_if_fail (E_IS_EWS_ITEM (item), NULL);
+
+	return item->priv->categories;
+}
+
 EwsImportance
 e_ews_item_get_importance	(EEwsItem *item)
 {
diff --git a/src/server/e-ews-item.h b/src/server/e-ews-item.h
index 736aa63..cf3be10 100644
--- a/src/server/e-ews-item.h
+++ b/src/server/e-ews-item.h
@@ -141,6 +141,8 @@ const EwsMailbox *
 		e_ews_item_get_from		(EEwsItem *item);
 EwsImportance
 		e_ews_item_get_importance	(EEwsItem *item);
+const GSList *
+		e_ews_item_get_categories	(EEwsItem *item);
 EwsMailbox *
 		e_ews_item_mailbox_from_soap_param
 						(ESoapParameter *param);




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