From a5b4c2c54c338ddacdf13b0dd49c1ca29f6eccdd Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sun, 23 Mar 2008 16:03:02 +0100
Subject: [PATCH] Relational: split match-type implementation into separate
 file.

---
 src/lib-sieve/plugins/relational/Makefile.am  |   7 +-
 .../relational/ext-relational-common.c        | 126 +++++++
 .../relational/ext-relational-common.h        |  70 ++++
 .../plugins/relational/ext-relational.c       | 312 ++----------------
 src/lib-sieve/plugins/relational/mcht-count.c | 116 +++++++
 src/lib-sieve/plugins/relational/mcht-value.c |  81 +++++
 6 files changed, 421 insertions(+), 291 deletions(-)
 create mode 100644 src/lib-sieve/plugins/relational/ext-relational-common.c
 create mode 100644 src/lib-sieve/plugins/relational/ext-relational-common.h
 create mode 100644 src/lib-sieve/plugins/relational/mcht-count.c
 create mode 100644 src/lib-sieve/plugins/relational/mcht-value.c

diff --git a/src/lib-sieve/plugins/relational/Makefile.am b/src/lib-sieve/plugins/relational/Makefile.am
index a883602c2..d5ae35bab 100644
--- a/src/lib-sieve/plugins/relational/Makefile.am
+++ b/src/lib-sieve/plugins/relational/Makefile.am
@@ -8,5 +8,10 @@ AM_CPPFLAGS = \
 	-I$(dovecot_incdir)/src/lib-storage 
 
 libsieve_ext_relational_la_SOURCES = \
-	ext-relational.c
+	ext-relational-common.c \
+	mcht-value.c \
+	mcht-count.c \
+	ext-relational.c 
 
+noinst_HEADER = \
+	ext-relational-common.h
diff --git a/src/lib-sieve/plugins/relational/ext-relational-common.c b/src/lib-sieve/plugins/relational/ext-relational-common.c
new file mode 100644
index 000000000..549c90318
--- /dev/null
+++ b/src/lib-sieve/plugins/relational/ext-relational-common.c
@@ -0,0 +1,126 @@
+/* Syntax:
+ *   MATCH-TYPE =/ COUNT / VALUE
+ *   COUNT = ":count" relational-match
+ *   VALUE = ":value" relational-match
+ *   relational-match = DQUOTE ( "gt" / "ge" / "lt"
+ *                             / "le" / "eq" / "ne" ) DQUOTE
+ */ 
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ast.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-relational-common.h"
+
+/* 
+ * Validation 
+ */
+
+bool mcht_relational_validate
+(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
+	struct sieve_match_type_context *ctx)
+{	
+	enum relational_match rel_match = REL_MATCH_INVALID;
+	const char *rel_match_id;
+
+	/* Check syntax:
+	 *   relational-match = DQUOTE ( "gt" / "ge" / "lt"	
+ 	 *                             / "le" / "eq" / "ne" ) DQUOTE
+ 	 *
+	 * So, actually this must be a constant string and it is implemented as such 
+	 */
+	 
+	/* Did we get a string in the first place ? */ 
+	if ( (*arg)->type != SAAT_STRING ) {
+		sieve_command_validate_error(validator, ctx->command_ctx, 
+			"the :%s match-type requires a constant string argument being "
+			"one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", "
+			"but %s was found", 
+			ctx->match_type->identifier, sieve_ast_argument_name(*arg));
+		return FALSE;
+	}
+	
+	/* Check the relational match id */
+	
+	rel_match_id = sieve_ast_argument_strc(*arg);
+	switch ( rel_match_id[0] ) {
+	/* "gt" or "ge" */
+	case 'g':
+		switch ( rel_match_id[1] ) {
+		case 't': 
+			rel_match = REL_MATCH_GREATER; 
+			break;
+		case 'e': 
+			rel_match = REL_MATCH_GREATER_EQUAL; 
+			break;
+		default: 
+			rel_match = REL_MATCH_INVALID;
+		}
+		break;
+	/* "lt" or "le" */
+	case 'l':
+		switch ( rel_match_id[1] ) {
+		case 't': 
+			rel_match = REL_MATCH_LESS; 
+			break;
+		case 'e': 
+			rel_match = REL_MATCH_LESS_EQUAL; 
+			break;
+		default: 
+			rel_match = REL_MATCH_INVALID;
+		}
+		break;
+	/* "eq" */
+	case 'e':
+		if ( rel_match_id[1] == 'q' )
+			rel_match = REL_MATCH_EQUAL;
+		else	
+			rel_match = REL_MATCH_INVALID;
+			
+		break;
+	/* "ne" */
+	case 'n':
+		if ( rel_match_id[1] == 'e' )
+			rel_match = REL_MATCH_NOT_EQUAL;
+		else	
+			rel_match = REL_MATCH_INVALID;
+		break;
+	/* invalid */
+	default:
+		rel_match = REL_MATCH_INVALID;
+	}
+	
+	if ( rel_match >= REL_MATCH_INVALID ) {
+		sieve_command_validate_error(validator, ctx->command_ctx, 
+			"the :%s match-type requires a constant string argument being "
+			"one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", "
+			"but \"%s\" was found", 
+			ctx->match_type->identifier, rel_match_id);
+		return FALSE;
+	}
+	
+	/* Delete argument */
+	*arg = sieve_ast_arguments_detach(*arg, 1);
+
+	/* Not used just yet */
+	ctx->ctx_data = (void *) rel_match;
+
+	/* Override the actual match type with a parameter-specific one */
+	ctx->match_type = rel_match_types
+		[REL_MATCH_INDEX(ctx->match_type->code, rel_match)];
+
+	return TRUE;
+}
+
+
diff --git a/src/lib-sieve/plugins/relational/ext-relational-common.h b/src/lib-sieve/plugins/relational/ext-relational-common.h
new file mode 100644
index 000000000..aa759cf6d
--- /dev/null
+++ b/src/lib-sieve/plugins/relational/ext-relational-common.h
@@ -0,0 +1,70 @@
+#ifndef __EXT_RELATIONAL_COMMON_H
+#define __EXT_RELATIONAL_COMMON_H
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+/* 
+ * Types 
+ */
+
+enum ext_relational_match_type {
+	RELATIONAL_VALUE,
+	RELATIONAL_COUNT
+};
+
+enum relational_match {
+	REL_MATCH_GREATER,
+	REL_MATCH_GREATER_EQUAL,
+	REL_MATCH_LESS,
+	REL_MATCH_LESS_EQUAL,
+	REL_MATCH_EQUAL,
+	REL_MATCH_NOT_EQUAL,
+	REL_MATCH_INVALID
+};
+
+#define REL_MATCH_INDEX(type, match) \
+	(type * REL_MATCH_INVALID + match)
+#define REL_MATCH_TYPE(index) \
+	(index / REL_MATCH_INVALID)
+#define REL_MATCH(index) \
+	(index % REL_MATCH_INVALID)
+
+/* 
+ * Extension definitions 
+ */
+
+int ext_relational_my_id;
+
+extern const struct sieve_extension relational_extension;
+extern const struct sieve_match_type_extension relational_match_extension;
+
+bool mcht_relational_validate
+	(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
+		struct sieve_match_type_context *ctx);
+bool mcht_value_match
+    (struct sieve_match_context *mctx, const char *val, size_t val_size,
+        const char *key, size_t key_size, int key_index);
+
+extern const struct sieve_match_type value_match_type;
+extern const struct sieve_match_type count_match_type;
+
+extern const struct sieve_match_type rel_match_count_gt;
+extern const struct sieve_match_type rel_match_count_ge;
+extern const struct sieve_match_type rel_match_count_lt;
+extern const struct sieve_match_type rel_match_count_le;
+extern const struct sieve_match_type rel_match_count_eq;
+extern const struct sieve_match_type rel_match_count_ne;
+
+extern const struct sieve_match_type rel_match_value_gt;
+extern const struct sieve_match_type rel_match_value_ge;
+extern const struct sieve_match_type rel_match_value_lt;
+extern const struct sieve_match_type rel_match_value_le;
+extern const struct sieve_match_type rel_match_value_eq;
+extern const struct sieve_match_type rel_match_value_ne;
+
+extern const struct sieve_match_type *rel_match_types[];
+
+#endif
diff --git a/src/lib-sieve/plugins/relational/ext-relational.c b/src/lib-sieve/plugins/relational/ext-relational.c
index 1a886ef2f..bca852268 100644
--- a/src/lib-sieve/plugins/relational/ext-relational.c
+++ b/src/lib-sieve/plugins/relational/ext-relational.c
@@ -8,14 +8,6 @@
  * 
  */
 
-/* Syntax:
- *   MATCH-TYPE =/ COUNT / VALUE
- *   COUNT = ":count" relational-match
- *   VALUE = ":value" relational-match
- *   relational-match = DQUOTE ( "gt" / "ge" / "lt"
- *                             / "le" / "eq" / "ne" ) DQUOTE
- */ 
-
 #include "lib.h"
 #include "str.h"
 
@@ -31,40 +23,27 @@
 #include "sieve-generator.h"
 #include "sieve-interpreter.h"
 
-/* Forward declarations */
+#include "ext-relational-common.h"
+
+/* 
+ * Forward declarations 
+ */
 
 static bool ext_relational_load(int ext_id);
 static bool ext_relational_validator_load(struct sieve_validator *validator);
 static bool ext_relational_binary_load(struct sieve_binary *sbin);
 
-/* Types */
+/* Extension definitions */
 
-enum ext_relational_match_type {
-	RELATIONAL_VALUE,
-	RELATIONAL_COUNT
-};
+int ext_relational_my_id;
 
-enum relational_match {
-	REL_MATCH_GREATER,
-	REL_MATCH_GREATER_EQUAL,
-	REL_MATCH_LESS,
-	REL_MATCH_LESS_EQUAL,
-	REL_MATCH_EQUAL,
-	REL_MATCH_NOT_EQUAL,
-	REL_MATCH_INVALID
+const struct sieve_match_type *rel_match_types[] = {
+    &rel_match_value_gt, &rel_match_value_ge, &rel_match_value_lt,
+    &rel_match_value_le, &rel_match_value_eq, &rel_match_value_ne,
+    &rel_match_count_gt, &rel_match_count_ge, &rel_match_count_lt,
+    &rel_match_count_le, &rel_match_count_eq, &rel_match_count_ne
 };
 
-#define REL_MATCH_INDEX(type, match) \
-	(type * REL_MATCH_INVALID + match)
-#define REL_MATCH_TYPE(index) \
-	(index / REL_MATCH_INVALID)
-#define REL_MATCH(index) \
-	(index % REL_MATCH_INVALID)
-
-/* Extension definitions */
-
-static int ext_my_id;
-
 const struct sieve_extension relational_extension = { 
 	"relational", 
 	ext_relational_load,
@@ -78,285 +57,38 @@ const struct sieve_extension relational_extension = {
 
 static bool ext_relational_load(int ext_id)
 {
-	ext_my_id = ext_id;
+	ext_relational_my_id = ext_id;
 
 	return TRUE;
 }
 
-/* Validation */
-
-static const struct sieve_match_type *rel_match_types[];
-
-static bool mtch_relational_validate
-	(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
-		struct sieve_match_type_context *ctx)
-{	
-	enum relational_match rel_match = REL_MATCH_INVALID;
-	const char *rel_match_id;
-
-	/* Check syntax:
-	 *   relational-match = DQUOTE ( "gt" / "ge" / "lt"	
- 	 *                             / "le" / "eq" / "ne" ) DQUOTE
- 	 *
-	 * So, actually this must be a constant string and it is implemented as such 
-	 */
-	 
-	/* Did we get a string in the first place ? */ 
-	if ( (*arg)->type != SAAT_STRING ) {
-		sieve_command_validate_error(validator, ctx->command_ctx, 
-			"the :%s match-type requires a constant string argument being "
-			"one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", "
-			"but %s was found", 
-			ctx->match_type->identifier, sieve_ast_argument_name(*arg));
-		return FALSE;
-	}
-	
-	/* Check the relational match id */
-	
-	rel_match_id = sieve_ast_argument_strc(*arg);
-	switch ( rel_match_id[0] ) {
-	/* "gt" or "ge" */
-	case 'g':
-		switch ( rel_match_id[1] ) {
-		case 't': 
-			rel_match = REL_MATCH_GREATER; 
-			break;
-		case 'e': 
-			rel_match = REL_MATCH_GREATER_EQUAL; 
-			break;
-		default: 
-			rel_match = REL_MATCH_INVALID;
-		}
-		break;
-	/* "lt" or "le" */
-	case 'l':
-		switch ( rel_match_id[1] ) {
-		case 't': 
-			rel_match = REL_MATCH_LESS; 
-			break;
-		case 'e': 
-			rel_match = REL_MATCH_LESS_EQUAL; 
-			break;
-		default: 
-			rel_match = REL_MATCH_INVALID;
-		}
-		break;
-	/* "eq" */
-	case 'e':
-		if ( rel_match_id[1] == 'q' )
-			rel_match = REL_MATCH_EQUAL;
-		else	
-			rel_match = REL_MATCH_INVALID;
-			
-		break;
-	/* "ne" */
-	case 'n':
-		if ( rel_match_id[1] == 'e' )
-			rel_match = REL_MATCH_NOT_EQUAL;
-		else	
-			rel_match = REL_MATCH_INVALID;
-		break;
-	/* invalid */
-	default:
-		rel_match = REL_MATCH_INVALID;
-	}
-	
-	if ( rel_match >= REL_MATCH_INVALID ) {
-		sieve_command_validate_error(validator, ctx->command_ctx, 
-			"the :%s match-type requires a constant string argument being "
-			"one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", "
-			"but \"%s\" was found", 
-			ctx->match_type->identifier, rel_match_id);
-		return FALSE;
-	}
-	
-	/* Delete argument */
-	*arg = sieve_ast_arguments_detach(*arg, 1);
-
-	/* Not used just yet */
-	ctx->ctx_data = (void *) rel_match;
-
-	/* Override the actual match type with a parameter-specific one */
-	ctx->match_type = rel_match_types
-		[REL_MATCH_INDEX(ctx->match_type->code, rel_match)];
-
-	return TRUE;
-}
-
-/* Actual extension implementation */
-
-static bool mtch_value_match
-(struct sieve_match_context *mctx, const char *val, size_t val_size, 
-	const char *key, size_t key_size, int key_index ATTR_UNUSED)
-{
-	const struct sieve_match_type *mtch = mctx->match_type;
-	unsigned int rel_match = REL_MATCH(mtch->code);	
-	int cmp_result = mctx->comparator->
-		compare(mctx->comparator, val, val_size, key, key_size);
-
-	switch ( rel_match ) {
-	case REL_MATCH_GREATER:
-		return ( cmp_result > 0 );
-	case REL_MATCH_GREATER_EQUAL:
-		return ( cmp_result >= 0 );
-	case REL_MATCH_LESS:
-		return ( cmp_result < 0 );
-	case REL_MATCH_LESS_EQUAL:
-		return ( cmp_result <= 0 );
-	case REL_MATCH_EQUAL:
-		return ( cmp_result == 0 );
-	case REL_MATCH_NOT_EQUAL:
-		return ( cmp_result != 0 );
-	case REL_MATCH_INVALID:
- 	default:
-		break;
-	}	
-	
-	return FALSE;
-}
-
-static void mtch_count_match_init(struct sieve_match_context *mctx)
-{
-	mctx->data = (void *) 0;
-}
-
-static bool mtch_count_match
-(struct sieve_match_context *mctx, 
-	const char *val ATTR_UNUSED, size_t val_size ATTR_UNUSED, 
-	const char *key ATTR_UNUSED, size_t key_size ATTR_UNUSED,
-	 int key_index) 
-{
-	unsigned int val_count = (unsigned int) mctx->data;
-
-	/* Count values */
-	if ( key_index == -1 ) {
-		val_count++;
-		mctx->data = (void *) val_count;	
-	}
-
-	return FALSE;
-}
-
-static bool mtch_count_match_deinit(struct sieve_match_context *mctx)
-{
-	unsigned int val_count = (unsigned int) mctx->data;
-	int key_index;
-	string_t *key_item;
-    sieve_coded_stringlist_reset(mctx->key_list);
-
-	string_t *value = t_str_new(20);
-	str_printfa(value, "%d", val_count);
-	
-    /* Match to all key values */
-    key_index = 0;
-    key_item = NULL;
-    while ( sieve_coded_stringlist_next_item(mctx->key_list, &key_item) &&
-        key_item != NULL )
-    {
-        if ( mtch_value_match
-			(mctx, str_c(value), str_len(value), str_c(key_item), 
-			str_len(key_item), key_index) )
-            return TRUE;
-
-        key_index++;
-    }
-
-	return FALSE;
-}
-
-/* Extension access structures */
-
-extern const struct sieve_match_type_extension relational_match_extension;
-
-/* Parameter-independent match type objects, only used during validation */
-
-const struct sieve_match_type value_match_type = {
-	"value", TRUE,
-	&relational_match_extension,
-	RELATIONAL_VALUE,
-	mtch_relational_validate,
-	NULL, NULL, NULL, NULL
-};
-
-const struct sieve_match_type count_match_type = {
-	"count", FALSE,
-	&relational_match_extension,
-	RELATIONAL_COUNT,
-	mtch_relational_validate,
-	NULL, NULL, NULL, NULL
-};
-
-/* Per-parameter match type objects, used for generation/interpretation 
- * FIXME: This is fast, but kinda hideous.. however, otherwise context data 
- * would have to be passed along with the match type objects everywhere.. also
- * not such a great idea. This needs more thought
- */
-
-#define VALUE_MATCH_TYPE(name, rel_match)                   \
-const struct sieve_match_type rel_match_value_ ## name = {  \
-	"value-" #name, TRUE,                                   \
-	&relational_match_extension,                            \
-	REL_MATCH_INDEX(RELATIONAL_VALUE, rel_match),           \
-	NULL, NULL, NULL,                                       \
-	mtch_value_match,                                       \
-	NULL                                                    \
-}
-
-#define COUNT_MATCH_TYPE(name, rel_match)                   \
-const struct sieve_match_type rel_match_count_ ## name = {  \
-	"count-" #name, FALSE,                                  \
-	&relational_match_extension,                            \
-	REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match),           \
-	NULL, NULL,                                             \
-	mtch_count_match_init,                                  \
-	mtch_count_match,                                       \
-	mtch_count_match_deinit                                 \
-}
-	
-VALUE_MATCH_TYPE(gt, REL_MATCH_GREATER);
-VALUE_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL); 
-VALUE_MATCH_TYPE(lt, REL_MATCH_LESS);
-VALUE_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL); 
-VALUE_MATCH_TYPE(eq, REL_MATCH_EQUAL);
-VALUE_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);
-
-COUNT_MATCH_TYPE(gt, REL_MATCH_GREATER);
-COUNT_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL);
-COUNT_MATCH_TYPE(lt, REL_MATCH_LESS);
-COUNT_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL);
-COUNT_MATCH_TYPE(eq, REL_MATCH_EQUAL);
-COUNT_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);
-
-static const struct sieve_match_type *rel_match_types[] = { 
-	&rel_match_value_gt, &rel_match_value_ge, &rel_match_value_lt, 
-	&rel_match_value_le, &rel_match_value_eq, &rel_match_value_ne,
-	&rel_match_count_gt, &rel_match_count_ge, &rel_match_count_lt, 
-	&rel_match_count_le, &rel_match_count_eq, &rel_match_count_ne 
-};
- 
 const struct sieve_match_type_extension relational_match_extension = { 
 	&relational_extension,
 	SIEVE_EXT_DEFINE_MATCH_TYPES(rel_match_types) 
 };
 
-/* Load extension into validator */
+/* 
+ * Load extension into validator 
+ */
 
 static bool ext_relational_validator_load(struct sieve_validator *validator)
 {
 	sieve_match_type_register
-		(validator, &value_match_type, ext_my_id); 
+		(validator, &value_match_type, ext_relational_my_id); 
 	sieve_match_type_register
-		(validator, &count_match_type, ext_my_id); 
+		(validator, &count_match_type, ext_relational_my_id); 
 
 	return TRUE;
 }
 
-/* Load extension into binary */
+/* 
+ * Load extension into binary 
+ */
 
 static bool ext_relational_binary_load(struct sieve_binary *sbin)
 {
 	sieve_match_type_extension_set
-		(sbin, ext_my_id, &relational_match_extension);
+		(sbin, ext_relational_my_id, &relational_match_extension);
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/plugins/relational/mcht-count.c b/src/lib-sieve/plugins/relational/mcht-count.c
new file mode 100644
index 000000000..771cbf547
--- /dev/null
+++ b/src/lib-sieve/plugins/relational/mcht-count.c
@@ -0,0 +1,116 @@
+/* Match-type ':count' 
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ast.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-relational-common.h"
+
+/* 
+ * Forward declarations
+ */
+
+static void mcht_count_match_init(struct sieve_match_context *mctx);
+static bool mcht_count_match
+	(struct sieve_match_context *mctx, const char *val, size_t val_size, 
+		const char *key, size_t key_size, int key_index);
+static bool mcht_count_match_deinit(struct sieve_match_context *mctx);
+
+/* 
+ * Match-type objects
+ */
+
+const struct sieve_match_type count_match_type = {
+	"count", FALSE,
+	&relational_match_extension,
+	RELATIONAL_COUNT,
+	mcht_relational_validate,
+	NULL, NULL, NULL, NULL
+};
+
+#define COUNT_MATCH_TYPE(name, rel_match)                   \
+const struct sieve_match_type rel_match_count_ ## name = {  \
+	"count-" #name, FALSE,                                  \
+	&relational_match_extension,                            \
+	REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match),           \
+	NULL, NULL,                                             \
+	mcht_count_match_init,                                  \
+	mcht_count_match,                                       \
+	mcht_count_match_deinit                                 \
+}
+	
+COUNT_MATCH_TYPE(gt, REL_MATCH_GREATER);
+COUNT_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL);
+COUNT_MATCH_TYPE(lt, REL_MATCH_LESS);
+COUNT_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL);
+COUNT_MATCH_TYPE(eq, REL_MATCH_EQUAL);
+COUNT_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);
+
+/* 
+ * Match-type implementation 
+ */
+
+static void mcht_count_match_init(struct sieve_match_context *mctx)
+{
+	mctx->data = (void *) 0;
+}
+
+static bool mcht_count_match
+(struct sieve_match_context *mctx, 
+	const char *val ATTR_UNUSED, size_t val_size ATTR_UNUSED, 
+	const char *key ATTR_UNUSED, size_t key_size ATTR_UNUSED,
+	 int key_index) 
+{
+	unsigned int val_count = (unsigned int) mctx->data;
+
+	/* Count values */
+	if ( key_index == -1 ) {
+		val_count++;
+		mctx->data = (void *) val_count;	
+	}
+
+	return FALSE;
+}
+
+static bool mcht_count_match_deinit(struct sieve_match_context *mctx)
+{
+	unsigned int val_count = (unsigned int) mctx->data;
+	int key_index;
+	string_t *key_item;
+    sieve_coded_stringlist_reset(mctx->key_list);
+
+	string_t *value = t_str_new(20);
+	str_printfa(value, "%d", val_count);
+	
+    /* Match to all key values */
+    key_index = 0;
+    key_item = NULL;
+    while ( sieve_coded_stringlist_next_item(mctx->key_list, &key_item) &&
+        key_item != NULL )
+    {
+        if ( mcht_value_match
+			(mctx, str_c(value), str_len(value), str_c(key_item), 
+			str_len(key_item), key_index) )
+            return TRUE;
+
+        key_index++;
+    }
+
+	return FALSE;
+}
+
+
+
+
diff --git a/src/lib-sieve/plugins/relational/mcht-value.c b/src/lib-sieve/plugins/relational/mcht-value.c
new file mode 100644
index 000000000..1838d337c
--- /dev/null
+++ b/src/lib-sieve/plugins/relational/mcht-value.c
@@ -0,0 +1,81 @@
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ast.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-relational-common.h"
+
+/*
+ * Match-type objects
+ */
+
+const struct sieve_match_type value_match_type = {
+	"value", TRUE,
+	&relational_match_extension,
+	RELATIONAL_VALUE,
+	mcht_relational_validate,
+	NULL, NULL, NULL, NULL
+};
+
+#define VALUE_MATCH_TYPE(name, rel_match)                   \
+const struct sieve_match_type rel_match_value_ ## name = {  \
+	"value-" #name, TRUE,                                   \
+	&relational_match_extension,                            \
+	REL_MATCH_INDEX(RELATIONAL_VALUE, rel_match),           \
+	NULL, NULL, NULL,                                       \
+	mcht_value_match,                                       \
+	NULL                                                    \
+}
+
+VALUE_MATCH_TYPE(gt, REL_MATCH_GREATER);
+VALUE_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL); 
+VALUE_MATCH_TYPE(lt, REL_MATCH_LESS);
+VALUE_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL); 
+VALUE_MATCH_TYPE(eq, REL_MATCH_EQUAL);
+VALUE_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);
+
+/* 
+ * Match-type implementation 
+ */
+
+bool mcht_value_match
+(struct sieve_match_context *mctx, const char *val, size_t val_size, 
+	const char *key, size_t key_size, int key_index ATTR_UNUSED)
+{
+	const struct sieve_match_type *mtch = mctx->match_type;
+	unsigned int rel_match = REL_MATCH(mtch->code);	
+	int cmp_result = mctx->comparator->
+		compare(mctx->comparator, val, val_size, key, key_size);
+
+	switch ( rel_match ) {
+	case REL_MATCH_GREATER:
+		return ( cmp_result > 0 );
+	case REL_MATCH_GREATER_EQUAL:
+		return ( cmp_result >= 0 );
+	case REL_MATCH_LESS:
+		return ( cmp_result < 0 );
+	case REL_MATCH_LESS_EQUAL:
+		return ( cmp_result <= 0 );
+	case REL_MATCH_EQUAL:
+		return ( cmp_result == 0 );
+	case REL_MATCH_NOT_EQUAL:
+		return ( cmp_result != 0 );
+	case REL_MATCH_INVALID:
+ 	default:
+		break;
+	}	
+	
+	return FALSE;
+}
+
+
-- 
GitLab