[evolution-mapi] Implement SExp parser for contacts backend



commit c20420c6536bde58f772a212217c01add71fc3f1
Author: Milan Crha <mcrha redhat com>
Date:   Tue Nov 29 18:15:31 2011 +0100

    Implement SExp parser for contacts backend

 configure.ac                                   |   19 +-
 src/addressbook/e-book-backend-mapi-contacts.c |  140 +--------
 src/addressbook/e-book-backend-mapi.c          |  412 +++++++++++++++++++++++-
 src/addressbook/e-book-backend-mapi.h          |    4 +
 src/libexchangemapi/e-mapi-connection.c        |   12 +-
 5 files changed, 445 insertions(+), 142 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index d39b93d..0ceac14 100644
--- a/configure.ac
+++ b/configure.ac
@@ -134,7 +134,7 @@ AC_SUBST(LIBMAPI_CFLAGS)
 AC_SUBST(LIBMAPI_LIBS)
 
 dnl ****************************
-dnl Check for struct StringArrayW_r function
+dnl Check for struct StringArrayW_r availability
 dnl ****************************
 AC_MSG_CHECKING([libmapi struct StringArrayW_r])
 save_cflags=$CFLAGS; CFLAGS=$LIBMAPI_CFLAGS
@@ -151,7 +151,7 @@ LIBS=$save_libs
 AC_MSG_RESULT([$ac_cv_have_saw])
 
 dnl ****************************
-dnl Check for struct mapi_SLPSTRArrayW function
+dnl Check for struct mapi_SLPSTRArrayW availability
 dnl ****************************
 AC_MSG_CHECKING([libmapi struct mapi_SLPSTRArrayW])
 save_cflags=$CFLAGS; CFLAGS=$LIBMAPI_CFLAGS
@@ -168,6 +168,21 @@ LIBS=$save_libs
 AC_MSG_RESULT([$ac_cv_have_msaw])
 
 dnl ****************************
+dnl Check for struct mapi_SNotRestriction availability
+dnl see http://tracker.openchange.org/issues/377
+dnl ****************************
+AC_MSG_CHECKING([libmapi struct mapi_SNotRestriction])
+save_cflags=$CFLAGS; CFLAGS=$LIBMAPI_CFLAGS
+save_libs=$LIBS; LIBS="$LIBMAPI_LIBS"
+AC_LINK_IFELSE([AC_LANG_PROGRAM(
+	[[#include <libmapi/libmapi.h>]],
+	[[struct mapi_SNotRestriction snot; snot.res->rt = RES_NOT]])],
+	[AC_DEFINE(HAVE_RES_NOT_SUPPORTED, 1, [libmapi supports RES_NOT restrictions]) ac_cv_have_rns=yes],[ac_cv_have_rns=no])
+CFLAGS=$save_cflags
+LIBS=$save_libs
+AC_MSG_RESULT([$ac_cv_have_rns])
+
+dnl ****************************
 dnl Expose version information
 dnl ****************************
 API_VERSION=$EDS_PACKAGE
diff --git a/src/addressbook/e-book-backend-mapi-contacts.c b/src/addressbook/e-book-backend-mapi-contacts.c
index 4f0df9e..076763d 100644
--- a/src/addressbook/e-book-backend-mapi-contacts.c
+++ b/src/addressbook/e-book-backend-mapi-contacts.c
@@ -57,7 +57,7 @@ struct _EBookBackendMAPIContactsPrivate
 };
 
 static gboolean
-build_restriction_emails_contains (EMapiConnection *conn,
+build_restriction_from_sexp_query (EMapiConnection *conn,
 				   mapi_id_t fid,
 				   TALLOC_CTX *mem_ctx,
 				   struct mapi_SRestriction **restrictions,
@@ -65,135 +65,15 @@ build_restriction_emails_contains (EMapiConnection *conn,
 				   GCancellable *cancellable,
 				   GError **perror)
 {
-	struct mapi_SRestriction *restriction;
-	const gchar *query = user_data;
-	gchar *email = NULL, *to_free, *tmp, *tmp1;
-
-	g_return_val_if_fail (query != NULL, FALSE);
-
-	/* This currently supports "email foo bar soo" */
-	to_free = strdup (query);
-
-	tmp = strstr (to_free, "email");
-	if (tmp ) {
-		tmp = strchr (tmp, '\"');
-		if (tmp && ++tmp) {
-			tmp = strchr (tmp, '\"');
-			if (tmp && ++tmp) {
-				tmp1 = tmp;
-				tmp1 = strchr (tmp1, '\"');
-				if (tmp1) {
-					*tmp1 = 0;
-					email = tmp;
-				}
-			}
-		}
-	}
-
-	if (email == NULL || !strchr (email, '@')) {
-		g_free (to_free);
-		return FALSE;
-	}
-
-	if (!restrictions) {
-		g_free (to_free);
-		return TRUE;
-	}
-
-	restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
-	g_return_val_if_fail (restriction != NULL, FALSE);
+	const gchar *sexp_query = user_data;
 
-	restriction->rt = RES_PROPERTY;
-	restriction->res.resProperty.relop = RES_PROPERTY;
-	restriction->res.resProperty.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL */
-	restriction->res.resProperty.lpProp.ulPropTag = PROP_TAG(PT_UNICODE, 0x801f); /* EMAIL*/
-	restriction->res.resProperty.lpProp.value.lpszA = talloc_strdup (mem_ctx, email);
+	g_return_val_if_fail (sexp_query != NULL, FALSE);
 
-	*restrictions = restriction;
-
-	g_free (to_free);
+	*restrictions = mapi_book_utils_sexp_to_restriction (mem_ctx, sexp_query);
 
 	return TRUE;
 }
 
-#if 0
-static gboolean
-build_multiple_restriction_emails_contains (EMapiConnection *conn, mapi_id_t fid, struct mapi_SRestriction *res,
-					    struct mapi_SRestriction_or *or_res,
-					    const gchar *query, gchar **to_free)
-{
-	gchar *email=NULL, *tmp, *tmp1;
-	//Number of restriction to apply
-	guint res_count = 6;
-
-	g_return_val_if_fail (to_free != NULL, FALSE);
-
-	/* This currently supports "email foo bar soo" */
-	*to_free = strdup (query);
-
-	tmp = strstr (*to_free, "email");
-	if (tmp ) {
-		tmp = strchr (tmp, '\"');
-		if (tmp && ++tmp) {
-			tmp = strchr (tmp, '\"');
-			if (tmp && ++tmp) {
-				tmp1 = tmp;
-				tmp1 = strchr (tmp1, '\"');
-				if (tmp1) {
-					*tmp1 = 0;
-					email = tmp;
-				}
-			}
-		}
-	}
-
-	if (email==NULL || !strchr (email, '@')) {
-		g_free (*to_free);
-		*to_free = NULL;
-
-		return FALSE;
-	}
-
-	or_res[0].rt = RES_CONTENT;
-	or_res[0].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[0].res.resContent.ulPropTag = PR_EMS_AB_MANAGER_T_UNICODE;
-	or_res[0].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[1].rt = RES_CONTENT;
-	or_res[1].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[1].res.resContent.ulPropTag = PR_DISPLAY_NAME_UNICODE;
-	or_res[1].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[2].rt = RES_CONTENT;
-	or_res[2].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[2].res.resContent.ulPropTag = PR_GIVEN_NAME_UNICODE;
-	or_res[2].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[3].rt = RES_CONTENT;
-	or_res[3].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[3].res.resContent.ulPropTag = e_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail1OriginalDisplayName, NULL, NULL);
-	or_res[3].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[4].rt = RES_CONTENT;
-	or_res[4].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[4].res.resContent.ulPropTag = e_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail2OriginalDisplayName, NULL, NULL);
-	or_res[4].res.resContent.lpProp.value.lpszA = email;
-
-	or_res[5].rt = RES_CONTENT;
-	or_res[5].res.resContent.fuzzy = FL_FULLSTRING | FL_IGNORECASE;
-	or_res[5].res.resContent.ulPropTag = e_mapi_connection_resolve_named_prop (conn, fid, PidLidEmail3OriginalDisplayName, NULL, NULL);
-	or_res[5].res.resContent.lpProp.value.lpszA = email;
-
-	res = g_new0 (struct mapi_SRestriction, 1);
-
-	res->rt = RES_OR;
-	res->res.resOr.cRes = res_count;
-	res->res.resOr.res = or_res;
-
-	return TRUE;
-}
-#endif
-
 static uint32_t
 string_to_bin (TALLOC_CTX *mem_ctx, const gchar *str, uint8_t **lpb)
 {
@@ -1069,7 +949,7 @@ ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellabl
 	EBookBackendMAPIContactsPrivate *priv;
 	EMapiConnection *conn;
 	GError *mapi_error = NULL;
-	gboolean get_all, status;
+	gboolean status;
 	mapi_object_t obj_folder;
 	GSList *mids = NULL;
 	struct TransferContactsData tcd = { 0 };
@@ -1110,14 +990,6 @@ ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellabl
 	tcd.ebma = ebma;
 	tcd.cards = vCards;
 
-	get_all = g_ascii_strcasecmp (query, "(contains \"x-evolution-any-field\" \"\")") == 0;
-	if (!get_all && !build_restriction_emails_contains (NULL, 0, NULL, NULL, (gpointer) query, NULL, NULL)) {
-		e_book_backend_mapi_unlock_connection (ebma);
-		/* g_propagate_error (error, EDB_ERROR (OTHER_ERROR)); */
-
-		return;
-	}
-
 	if (priv->is_public_folder)
 		status = e_mapi_connection_open_public_folder (conn, priv->fid, &obj_folder, cancellable, &mapi_error);
 	else
@@ -1125,7 +997,7 @@ ebbm_contacts_get_contact_list (EBookBackendMAPI *ebma, GCancellable *cancellabl
 
 	if (status) {
 		status = e_mapi_connection_list_objects (conn, &obj_folder,
-							 get_all ? NULL : build_restriction_emails_contains, (gpointer) query,
+							 build_restriction_from_sexp_query, (gpointer) query,
 							 gather_contact_mids_cb, &mids,
 							 cancellable, &mapi_error);
 
diff --git a/src/addressbook/e-book-backend-mapi.c b/src/addressbook/e-book-backend-mapi.c
index e5324aa..bf28e95 100644
--- a/src/addressbook/e-book-backend-mapi.c
+++ b/src/addressbook/e-book-backend-mapi.c
@@ -34,6 +34,7 @@
 
 #include <libebook/e-contact.h>
 #include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-sexp.h>
 #include <camel/camel.h>
 
 #include <e-mapi-operation-queue.h>
@@ -75,8 +76,8 @@ struct _EBookBackendMAPIPrivate
 
 static const struct field_element_mapping {
 		EContactField field_id;
-		gint element_type;
-		gint mapi_id;
+		uint32_t element_type;
+		uint32_t mapi_id;
 		gint contact_type;
 	} mappings [] = {
 
@@ -1965,3 +1966,410 @@ mapi_book_utils_timet_to_string (time_t tt)
 
 	return g_time_val_to_iso8601 (&tv);
 }
+
+struct EMapiSExpParserData
+{
+	TALLOC_CTX *mem_ctx;
+	/* parser results in ints, indexes to res_parts */
+	GPtrArray *res_parts;
+};
+
+static ESExpResult *
+term_eval_and (struct _ESExp *f,
+	       gint argc,
+	       struct _ESExpResult **argv,
+	       gpointer user_data)
+{
+	struct EMapiSExpParserData *esp = user_data;
+	ESExpResult *r;
+	gint ii, jj, valid = 0;
+
+	r = e_sexp_result_new (f, ESEXP_RES_INT);
+	r->value.number = -1;
+
+	for (ii = 0; ii < argc; ii++) {
+		if (argv[ii]->type == ESEXP_RES_INT &&
+		    argv[ii]->value.number >= 0 && 
+		    argv[ii]->value.number < esp->res_parts->len) {
+			jj = argv[ii]->value.number;
+			valid++;
+		}
+	}
+
+	if (valid == 1) {
+		r->value.number = jj;
+	} else if (valid > 0) {
+		struct mapi_SRestriction *res = talloc_zero (esp->mem_ctx, struct mapi_SRestriction);
+		g_return_val_if_fail (res != NULL, NULL);
+
+		res->rt = RES_AND;
+		res->res.resAnd.cRes = valid;
+		res->res.resAnd.res = talloc_zero_array (esp->mem_ctx, struct mapi_SRestriction_and, res->res.resAnd.cRes + 1);
+
+		jj = 0;
+
+		for (ii = 0; ii < argc; ii++) {
+			if (argv[ii]->type == ESEXP_RES_INT &&
+			    argv[ii]->value.number >= 0 && 
+			    argv[ii]->value.number < esp->res_parts->len) {
+				struct mapi_SRestriction *subres = g_ptr_array_index (esp->res_parts, argv[ii]->value.number);
+
+				res->res.resAnd.res[jj].rt = subres->rt;
+				res->res.resAnd.res[jj].res = subres->res;
+
+				jj++;
+			}
+		}
+
+		g_ptr_array_add (esp->res_parts, res);
+		r->value.number = esp->res_parts->len - 1;
+	}
+
+	return r;
+}
+
+static ESExpResult *
+term_eval_or (struct _ESExp *f,
+	      gint argc,
+	      struct _ESExpResult **argv,
+	      gpointer user_data)
+{
+	struct EMapiSExpParserData *esp = user_data;
+	ESExpResult *r;
+	gint ii, jj = -1, valid = 0;
+
+	r = e_sexp_result_new (f, ESEXP_RES_INT);
+	r->value.number = -1;
+
+	for (ii = 0; ii < argc; ii++) {
+		if (argv[ii]->type == ESEXP_RES_INT &&
+		    argv[ii]->value.number >= 0 && 
+		    argv[ii]->value.number < esp->res_parts->len) {
+			jj = argv[ii]->value.number;
+			valid++;
+		    }
+	}
+
+	if (valid == 1) {
+		r->value.number = jj;
+	} else if (valid > 0) {
+		struct mapi_SRestriction *res = talloc_zero (esp->mem_ctx, struct mapi_SRestriction);
+		g_return_val_if_fail (res != NULL, NULL);
+
+		res->rt = RES_OR;
+		res->res.resOr.cRes = valid;
+		res->res.resOr.res = talloc_zero_array (esp->mem_ctx, struct mapi_SRestriction_or, res->res.resOr.cRes + 1);
+
+		jj = 0;
+
+		for (ii = 0; ii < argc; ii++) {
+			if (argv[ii]->type == ESEXP_RES_INT &&
+			    argv[ii]->value.number >= 0 && 
+			    argv[ii]->value.number < esp->res_parts->len) {
+				struct mapi_SRestriction *subres = g_ptr_array_index (esp->res_parts, argv[ii]->value.number);
+
+				res->res.resOr.res[jj].rt = subres->rt;
+				res->res.resOr.res[jj].res = subres->res;
+
+				jj++;
+			}
+		}
+
+		g_ptr_array_add (esp->res_parts, res);
+		r->value.number = esp->res_parts->len - 1;
+	}
+
+	return r;
+}
+
+static ESExpResult *
+term_eval_not (struct _ESExp *f,
+	       gint argc,
+	       struct _ESExpResult **argv,
+	       gpointer user_data)
+{
+	struct EMapiSExpParserData *esp = user_data;
+	ESExpResult *r;
+
+	r = e_sexp_result_new (f, ESEXP_RES_INT);
+	r->value.number = -1;
+
+	#ifdef HAVE_RES_NOT_SUPPORTED
+	if (argc == 1 && argv[0]->type == ESEXP_RES_INT) {
+		gint idx = argv[0]->value.number;
+
+		if (idx >= 0 && idx < esp->res_parts->len) {
+			struct mapi_SRestriction *res = talloc_zero (esp->mem_ctx, struct mapi_SRestriction);
+			g_return_val_if_fail (res != NULL, NULL);
+
+			res->rt = RES_NOT;
+			res->res.resNot.res = g_ptr_array_index (esp->res_parts, idx);
+
+			g_ptr_array_add (esp->res_parts, res);
+			r->value.number = esp->res_parts->len - 1;
+		}
+	}
+	#endif
+
+	return r;
+}
+
+static uint32_t
+get_proptag_from_field_name (const gchar *field_name, gboolean is_contact_field)
+{
+	EContactField cfid;
+	gint ii;
+
+	if (is_contact_field)
+		cfid = e_contact_field_id (field_name);
+	else
+		cfid = e_contact_field_id_from_vcard (field_name);
+
+	for (ii = 0; ii < G_N_ELEMENTS (mappings); ii++) {
+		if (mappings[ii].field_id == cfid) {
+			return mappings[ii].mapi_id;
+		}
+	}
+
+	return MAPI_E_RESERVED;
+}
+
+static ESExpResult *
+func_eval_text_compare (struct _ESExp *f,
+			gint argc,
+			struct _ESExpResult **argv,
+			gpointer user_data,
+			uint32_t fuzzy)
+{
+	struct EMapiSExpParserData *esp = user_data;
+	ESExpResult *r;
+
+	r = e_sexp_result_new (f, ESEXP_RES_INT);
+	r->value.number = -1;
+
+	if (argc == 2
+	    && argv[0]->type == ESEXP_RES_STRING
+	    && argv[1]->type == ESEXP_RES_STRING) {
+		const gchar *propname = argv[0]->value.string;
+		const gchar *propvalue = argv[1]->value.string;
+
+		if (propname && propvalue && g_ascii_strcasecmp (propname, "x-evolution-any-field") != 0) {
+			uint32_t proptag = get_proptag_from_field_name (propname, TRUE);
+
+			if (proptag != MAPI_E_RESERVED && ((proptag & 0xFFFF) == PT_UNICODE || (proptag & 0xFFFF) == PT_STRING8)) {
+				struct mapi_SRestriction *res = talloc_zero (esp->mem_ctx, struct mapi_SRestriction);
+				g_return_val_if_fail (res != NULL, NULL);
+
+				res->rt = RES_CONTENT;
+				res->res.resContent.fuzzy = fuzzy | FL_IGNORECASE;
+				res->res.resContent.ulPropTag = proptag;
+				res->res.resContent.lpProp.ulPropTag = proptag;
+				res->res.resContent.lpProp.value.lpszW = talloc_strdup (esp->mem_ctx, propvalue);
+
+				g_ptr_array_add (esp->res_parts, res);
+				r->value.number = esp->res_parts->len - 1;
+			} else if (g_ascii_strcasecmp (propname, "email") == 0) {
+				struct mapi_SRestriction *res = talloc_zero (esp->mem_ctx, struct mapi_SRestriction);
+				g_return_val_if_fail (res != NULL, NULL);
+
+				res->rt = RES_OR;
+				res->res.resOr.cRes = 3;
+				res->res.resOr.res = talloc_zero_array (esp->mem_ctx, struct mapi_SRestriction_or, res->res.resOr.cRes + 1);
+
+				proptag = get_proptag_from_field_name ("email_1", TRUE);
+				res->res.resOr.res[0].rt = RES_CONTENT;
+				res->res.resOr.res[0].res.resContent.fuzzy = fuzzy | FL_IGNORECASE;
+				res->res.resOr.res[0].res.resContent.ulPropTag = proptag;
+				res->res.resOr.res[0].res.resContent.lpProp.ulPropTag = proptag;
+				res->res.resOr.res[0].res.resContent.lpProp.value.lpszW = talloc_strdup (esp->mem_ctx, propvalue);
+
+				proptag = get_proptag_from_field_name ("email_2", TRUE);
+				res->res.resOr.res[1].rt = RES_CONTENT;
+				res->res.resOr.res[1].res.resContent.fuzzy = fuzzy | FL_IGNORECASE;
+				res->res.resOr.res[1].res.resContent.ulPropTag = proptag;
+				res->res.resOr.res[1].res.resContent.lpProp.ulPropTag = proptag;
+				res->res.resOr.res[1].res.resContent.lpProp.value.lpszW = talloc_strdup (esp->mem_ctx, propvalue);
+
+				proptag = get_proptag_from_field_name ("email_3", TRUE);
+				res->res.resOr.res[2].rt = RES_CONTENT;
+				res->res.resOr.res[2].res.resContent.fuzzy = fuzzy | FL_IGNORECASE;
+				res->res.resOr.res[2].res.resContent.ulPropTag = proptag;
+				res->res.resOr.res[2].res.resContent.lpProp.ulPropTag = proptag;
+				res->res.resOr.res[2].res.resContent.lpProp.value.lpszW = talloc_strdup (esp->mem_ctx, propvalue);
+
+				g_ptr_array_add (esp->res_parts, res);
+				r->value.number = esp->res_parts->len - 1;
+			}
+		}
+	}
+
+	return r;
+}
+
+static ESExpResult *
+func_eval_contains (struct _ESExp *f,
+		    gint argc,
+		    struct _ESExpResult **argv,
+		    gpointer user_data)
+{
+	return func_eval_text_compare (f, argc, argv, user_data, FL_SUBSTRING);
+}
+
+static ESExpResult *
+func_eval_is (struct _ESExp *f,
+	      gint argc,
+	      struct _ESExpResult **argv,
+	      gpointer user_data)
+{
+	return func_eval_text_compare (f, argc, argv, user_data, FL_FULLSTRING);
+}
+static ESExpResult *
+func_eval_beginswith (struct _ESExp *f,
+		      gint argc,
+		      struct _ESExpResult **argv,
+		      gpointer user_data)
+{
+	return func_eval_text_compare (f, argc, argv, user_data, FL_PREFIX);
+}
+static ESExpResult *
+func_eval_endswith (struct _ESExp *f,
+		    gint argc,
+		    struct _ESExpResult **argv,
+		    gpointer user_data)
+{
+	/* no suffix, thus at least substring is used */
+	return func_eval_text_compare (f, argc, argv, user_data, FL_SUBSTRING);
+}
+
+static ESExpResult *
+func_eval_field_exists (struct _ESExp *f,
+			gint argc,
+			struct _ESExpResult **argv,
+			gpointer user_data,
+			gboolean is_contact_field)
+{
+	struct EMapiSExpParserData *esp = user_data;
+	ESExpResult *r;
+
+	r = e_sexp_result_new (f, ESEXP_RES_INT);
+	r->value.number = -1;
+
+	if (argc == 1 && argv[0]->type == ESEXP_RES_STRING) {
+		const gchar *propname = argv[0]->value.string;
+		uint32_t proptag = get_proptag_from_field_name (propname, is_contact_field);
+
+		if (proptag != MAPI_E_RESERVED) {
+			struct mapi_SRestriction *res = talloc_zero (esp->mem_ctx, struct mapi_SRestriction);
+			g_return_val_if_fail (res != NULL, NULL);
+
+			res->rt = RES_EXIST;
+			res->res.resExist.ulPropTag = proptag;
+
+			g_ptr_array_add (esp->res_parts, res);
+			r->value.number = esp->res_parts->len - 1;
+		} else if (g_ascii_strcasecmp (propname, "email") == 0) {
+			struct mapi_SRestriction *res = talloc_zero (esp->mem_ctx, struct mapi_SRestriction);
+			g_return_val_if_fail (res != NULL, NULL);
+
+			res->rt = RES_OR;
+			res->res.resOr.cRes = 3;
+			res->res.resOr.res = talloc_zero_array (esp->mem_ctx, struct mapi_SRestriction_or, res->res.resOr.cRes + 1);
+
+			res->res.resOr.res[0].rt = RES_EXIST;
+			res->res.resOr.res[0].res.resExist.ulPropTag = get_proptag_from_field_name ("email_1", TRUE);
+
+			res->res.resOr.res[1].rt = RES_EXIST;
+			res->res.resOr.res[1].res.resExist.ulPropTag = get_proptag_from_field_name ("email_2", TRUE);
+
+			res->res.resOr.res[2].rt = RES_EXIST;
+			res->res.resOr.res[2].res.resExist.ulPropTag = get_proptag_from_field_name ("email_3", TRUE);
+
+			g_ptr_array_add (esp->res_parts, res);
+			r->value.number = esp->res_parts->len - 1;
+		}
+	}
+
+	return r;
+}
+
+static ESExpResult *
+func_eval_exists (struct _ESExp *f,
+		  gint argc,
+		  struct _ESExpResult **argv,
+		  gpointer user_data)
+{
+	return func_eval_field_exists (f, argc, argv, user_data, TRUE);
+}
+
+static ESExpResult *
+func_eval_exists_vcard (struct _ESExp *f,
+			gint argc,
+			struct _ESExpResult **argv,
+			gpointer user_data)
+{
+	return func_eval_field_exists (f, argc, argv, user_data, FALSE);
+}
+
+struct mapi_SRestriction *
+mapi_book_utils_sexp_to_restriction (TALLOC_CTX *mem_ctx, const gchar *sexp_query)
+{
+	/* 'builtin' functions */
+	static const struct {
+		const gchar *name;
+		ESExpFunc *func;
+		gint type;		/* set to 1 if a function can perform shortcut evaluation, or
+					   doesn't execute everything, 0 otherwise */
+	} check_symbols[] = {
+		{ "and", 		term_eval_and,		0 },
+		{ "or", 		term_eval_or,		0 },
+		{ "not", 		term_eval_not,		0 },
+
+		{ "contains",		func_eval_contains,	0 },
+		{ "is",			func_eval_is,		0 },
+		{ "beginswith",		func_eval_beginswith,	0 },
+		{ "endswith",		func_eval_endswith,	0 },
+		{ "exists",		func_eval_exists,	0 },
+		{ "exists_vcard",	func_eval_exists_vcard,	0 }
+	};
+
+	gint i;
+	ESExp *sexp;
+	ESExpResult *r;
+	struct EMapiSExpParserData esp;
+	struct mapi_SRestriction *restriction;
+
+	g_return_val_if_fail (sexp_query != NULL, NULL);
+
+	esp.mem_ctx = mem_ctx;
+	sexp = e_sexp_new ();
+
+	for (i = 0; i < G_N_ELEMENTS (check_symbols); i++) {
+		if (check_symbols[i].type == 1) {
+			e_sexp_add_ifunction (sexp, 0, check_symbols[i].name,
+					      (ESExpIFunc *) check_symbols[i].func, &esp);
+		} else {
+			e_sexp_add_function (sexp, 0, check_symbols[i].name,
+					     check_symbols[i].func, &esp);
+		}
+	}
+
+	e_sexp_input_text (sexp, sexp_query, strlen (sexp_query));
+	if (e_sexp_parse (sexp) == -1) {
+		e_sexp_unref (sexp);
+		return NULL;
+	}
+
+	esp.res_parts = g_ptr_array_new ();
+	r = e_sexp_eval (sexp);
+
+	restriction = NULL;
+	if (r && r->type == ESEXP_RES_INT && r->value.number >= 0 && r->value.number < esp.res_parts->len)
+		restriction = g_ptr_array_index (esp.res_parts, r->value.number);
+
+	e_sexp_result_free (sexp, r);
+
+	e_sexp_unref (sexp);
+	g_ptr_array_free (esp.res_parts, TRUE);
+
+	return restriction;
+}
diff --git a/src/addressbook/e-book-backend-mapi.h b/src/addressbook/e-book-backend-mapi.h
index 5a65f95..4e84bcb 100644
--- a/src/addressbook/e-book-backend-mapi.h
+++ b/src/addressbook/e-book-backend-mapi.h
@@ -149,6 +149,10 @@ EContact *mapi_book_utils_contact_from_props (EMapiConnection *conn, mapi_id_t f
    free returned pointer with g_free() */
 gchar *mapi_book_utils_timet_to_string (time_t tt);
 
+/* converts sexp_query into mapi_SRestriction, which is completely
+   allocated on the given mem_ctx */
+struct mapi_SRestriction *mapi_book_utils_sexp_to_restriction (TALLOC_CTX *mem_ctx, const gchar *sexp_query);
+
 G_END_DECLS
 
 #endif /* __E_BOOK_BACKEND_MAPI_H__ */
diff --git a/src/libexchangemapi/e-mapi-connection.c b/src/libexchangemapi/e-mapi-connection.c
index 4688091..30285cc 100644
--- a/src/libexchangemapi/e-mapi-connection.c
+++ b/src/libexchangemapi/e-mapi-connection.c
@@ -1980,9 +1980,11 @@ gather_mapi_SRestriction_named_ids (struct mapi_SRestriction *restriction,
 			gather_mapi_SRestriction_named_ids ((struct mapi_SRestriction *) &(restriction->res.resOr.res[i]), named_ids_list, named_ids_len);
 		}
 		break;
-	/*case RES_NOT:
+	#ifdef HAVE_RES_NOT_SUPPORTED
+	case RES_NOT:
 		gather_mapi_SRestriction_named_ids ((struct mapi_SRestriction *) restriction->res.resNot.res, named_ids_list, named_ids_len);
-		break;*/
+		break;
+	#endif
 	case RES_CONTENT:
 		maybe_add_named_id_tag (restriction->res.resContent.ulPropTag, named_ids_list, named_ids_len);
 		maybe_add_named_id_tag (restriction->res.resContent.lpProp.ulPropTag, named_ids_list, named_ids_len);
@@ -2048,9 +2050,11 @@ replace_mapi_SRestriction_named_ids (struct mapi_SRestriction *restriction,
 			replace_mapi_SRestriction_named_ids ((struct mapi_SRestriction *) &(restriction->res.resOr.res[i]), named_ids_list, named_ids_len);
 		}
 		break;
-	/*case RES_NOT:
+	#ifdef HAVE_RES_NOT_SUPPORTED
+	case RES_NOT:
 		replace_mapi_SRestriction_named_ids (restriction->res.resNot.res, named_ids_list, named_ids_len);
-		break;*/
+		break;
+	#endif
 	case RES_CONTENT:
 		maybe_replace_named_id_tag (&restriction->res.resContent.ulPropTag, named_ids_list, named_ids_len);
 		maybe_replace_named_id_tag (&restriction->res.resContent.lpProp.ulPropTag, named_ids_list, named_ids_len);



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