From 4e793fea55d9b308cec82a723f874a85d5cc1e52 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Fri, 9 Nov 2007 01:23:12 +0100
Subject: [PATCH] Started implementation of comparator execution support.

---
 src/lib-sieve/ext-envelope.c                  |  2 +-
 src/lib-sieve/ext-fileinto.c                  |  2 +-
 src/lib-sieve/ext-reject.c                    |  2 +-
 src/lib-sieve/plugins/vacation/ext-vacation.c |  2 +-
 src/lib-sieve/sieve-binary.c                  | 10 +-
 src/lib-sieve/sieve-binary.h                  |  4 +-
 src/lib-sieve/sieve-code.c                    |  5 +-
 src/lib-sieve/sieve-comparators.c             | 94 +++++++++++++++++--
 src/lib-sieve/sieve-comparators.h             | 17 +++-
 src/lib-sieve/sieve-extensions.h              |  7 +-
 src/lib-sieve/sieve-interpreter.c             | 73 ++++++++++++--
 src/lib-sieve/sieve-interpreter.h             | 23 +++--
 12 files changed, 199 insertions(+), 42 deletions(-)

diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index c918d2cb0..fae863efe 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -25,7 +25,7 @@ static bool tst_envelope_generate
 const struct sieve_opcode envelope_opcode =
 	{ ext_envelope_opcode_dump, NULL };
 const struct sieve_extension envelope_extension = 
-	{ "envelope", ext_envelope_validator_load, NULL, &envelope_opcode, NULL };
+	{ "envelope", ext_envelope_validator_load, NULL, NULL, &envelope_opcode, NULL };
 
 static const struct sieve_command envelope_test = 
 	{ "envelope", SCT_TEST, tst_envelope_registered, tst_envelope_validate, tst_envelope_generate, NULL };
diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c
index f7a0cd40a..fcb23480e 100644
--- a/src/lib-sieve/ext-fileinto.c
+++ b/src/lib-sieve/ext-fileinto.c
@@ -22,7 +22,7 @@ const struct sieve_opcode fileinto_opcode =
 	{ ext_fileinto_opcode_dump, ext_fileinto_opcode_execute };
 
 const struct sieve_extension fileinto_extension = 
-	{ "fileinto", ext_fileinto_validator_load, NULL, &fileinto_opcode, NULL	};
+	{ "fileinto", ext_fileinto_validator_load, NULL, NULL, &fileinto_opcode, NULL	};
 static const struct sieve_command fileinto_command = 
 	{ "fileinto", SCT_COMMAND, NULL, cmd_fileinto_validate, cmd_fileinto_generate, NULL };
 
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index 6784e977b..de5dd7c8a 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -22,7 +22,7 @@ struct sieve_opcode reject_opcode =
 	{ ext_reject_opcode_dump, NULL };
 	
 struct sieve_extension reject_extension = 
-	{ "reject", ext_reject_validator_load, ext_reject_generator_load, &reject_opcode, NULL };
+	{ "reject", ext_reject_validator_load, ext_reject_generator_load, NULL, &reject_opcode, NULL };
 
 static const struct sieve_command reject_command = 
 	{ "reject", SCT_COMMAND, NULL, cmd_reject_validate, cmd_reject_generate, NULL };
diff --git a/src/lib-sieve/plugins/vacation/ext-vacation.c b/src/lib-sieve/plugins/vacation/ext-vacation.c
index 50e0a4ecb..da710b1b7 100644
--- a/src/lib-sieve/plugins/vacation/ext-vacation.c
+++ b/src/lib-sieve/plugins/vacation/ext-vacation.c
@@ -23,7 +23,7 @@ static bool cmd_vacation_generate(struct sieve_generator *generator,	struct siev
 const struct sieve_opcode vacation_opcode = 
 	{ ext_vacation_opcode_dump, NULL };
 const struct sieve_extension vacation_extension = 
-	{ "vacation", ext_vacation_validator_load, NULL, &vacation_opcode, NULL};
+	{ "vacation", ext_vacation_validator_load, NULL, NULL, &vacation_opcode, NULL};
 static const struct sieve_command vacation_command = 
 	{ "vacation", SCT_COMMAND, cmd_vacation_registered, cmd_vacation_validate, cmd_vacation_generate, NULL };
 
diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c
index 411b961f3..1097e8227 100644
--- a/src/lib-sieve/sieve-binary.c
+++ b/src/lib-sieve/sieve-binary.c
@@ -68,7 +68,7 @@ void sieve_binary_commit(struct sieve_binary *binary)
 
 /* Extension handling */
 
-static unsigned int sieve_binary_link_extension(struct sieve_binary *binary, const struct sieve_extension *extension) 
+static int sieve_binary_link_extension(struct sieve_binary *binary, const struct sieve_extension *extension) 
 {
 	array_append(&(binary->extensions), &extension, 1);
 	
@@ -87,7 +87,7 @@ const struct sieve_extension *sieve_binary_get_extension(struct sieve_binary *bi
 	return NULL;
 }
 
-unsigned int sieve_binary_register_extension
+int sieve_binary_register_extension
 	(struct sieve_binary *sbin, const struct sieve_extension *extension) 
 {
 	struct sieve_extension_registration *reg;
@@ -101,15 +101,15 @@ unsigned int sieve_binary_register_extension
 	return reg->opcode;
 }
 
-unsigned int sieve_binary_get_extension_index		
+int sieve_binary_get_extension_index		
 	(struct sieve_binary *sbin, const struct sieve_extension *extension) 
 {
   struct sieve_extension_registration *reg = 
     (struct sieve_extension_registration *) hash_lookup(sbin->extension_index, extension);
 
 	if ( reg == NULL )
-		return sieve_binary_register_extension(sbin, extension);
-    
+		return -1;
+		    
   return reg->opcode;
 }
 
diff --git a/src/lib-sieve/sieve-binary.h b/src/lib-sieve/sieve-binary.h
index 7b2c7688c..7ddbc6c70 100644
--- a/src/lib-sieve/sieve-binary.h
+++ b/src/lib-sieve/sieve-binary.h
@@ -18,11 +18,11 @@ void sieve_binary_commit(struct sieve_binary *binary);
  * Extension handling 
  */
 
-unsigned int sieve_binary_register_extension
+int sieve_binary_register_extension
 	(struct sieve_binary *sbin, const struct sieve_extension *extension);
 const struct sieve_extension *sieve_binary_get_extension
 	(struct sieve_binary *binary, unsigned int index); 
-unsigned int sieve_binary_get_extension_index		
+int sieve_binary_get_extension_index		
 	(struct sieve_binary *sbin, const struct sieve_extension *extension); 
 
 /* 
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index 77ff46d32..3d727e01d 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -188,10 +188,13 @@ const struct sieve_operand stringlist_operand =
 	
 /* Core operands */
 
+extern struct sieve_operand comparator_operand;
+
 const struct sieve_operand *sieve_operands[] = {
 	&number_operand,
 	&string_operand,
-	&stringlist_operand
+	&stringlist_operand,
+	&comparator_operand
 }; 
 
 const unsigned int sieve_operand_count =
diff --git a/src/lib-sieve/sieve-comparators.c b/src/lib-sieve/sieve-comparators.c
index cb339969d..09623c04b 100644
--- a/src/lib-sieve/sieve-comparators.c
+++ b/src/lib-sieve/sieve-comparators.c
@@ -1,9 +1,11 @@
 #include "lib.h"
 #include "compat.h"
 
+#include "sieve-code.h"
 #include "sieve-binary.h"
 #include "sieve-validator.h"
 #include "sieve-generator.h"
+#include "sieve-interpreter.h"
 
 #include "sieve-comparators.h"
 
@@ -12,10 +14,25 @@
 /* 
  * Predeclarations 
  */
+ 
+static struct sieve_interpreter_registry *cmp_registry = NULL;
+
+static void opr_comparator_emit
+	(struct sieve_binary *sbin, unsigned int code);
+static void opr_comparator_emit_ext
+	(struct sieve_binary *sbin, const struct sieve_extension *ext);
+
 
 static int cmp_i_octet_compare(const void *val1, size_t val1_size, const void *val2, size_t val2_size);
 static int cmp_i_ascii_casemap_compare(const void *val1, size_t val1_size, const void *val2, size_t val2_size);
 
+/*
+ * Comparator operand
+ */
+ 
+struct sieve_operand_class comparator_class = { "comparator", NULL };
+struct sieve_operand comparator_operand = { "comparator", &comparator_class };
+
 /* 
  * Comparator tag 
  */
@@ -68,20 +85,70 @@ static bool tag_comparator_validate
 	return TRUE;
 }
 
+/* Code generation */
+
 static void opr_comparator_emit
-	(struct sieve_generator *generator, struct sieve_comparator *cmp)
+	(struct sieve_binary *sbin, unsigned int code)
 { 
-	struct sieve_binary *sbin = sieve_generator_get_binary(generator);
-
 	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_COMPARATOR);
-	(void) sieve_binary_emit_byte(sbin, (unsigned char) cmp->code);
+	(void) sieve_binary_emit_byte(sbin, code);
+}
+
+static void opr_comparator_emit_ext
+	(struct sieve_binary *sbin, const struct sieve_extension *ext)
+{ 
+	unsigned char cmp_code = SIEVE_COMPARATOR_CUSTOM + 
+		sieve_binary_get_extension_index(sbin, ext);
+	
+	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_COMPARATOR);	
+	(void) sieve_binary_emit_byte(sbin, cmp_code);
+}
+
+const struct sieve_comparator *sieve_opr_comparator_read
+  (struct sieve_binary *sbin, sieve_size_t *address)
+{
+	unsigned int cmp_code;
+	const struct sieve_operand *operand = sieve_operand_read(sbin, address);
+	
+	if ( operand == NULL || operand->class != &comparator_class ) 
+		return NULL;
+	
+	if ( sieve_binary_read_byte(sbin, address, &cmp_code) ) {
+		if ( cmp_code < SIEVE_COMPARATOR_CUSTOM ) {
+			if ( cmp_code < sieve_core_comparators_count )
+				return sieve_core_comparators[cmp_code];
+			else
+				return NULL;
+		} else {
+		  const struct sieve_extension *ext = 
+		  	sieve_binary_get_extension(sbin, cmp_code - SIEVE_COMPARATOR_CUSTOM);
+		  
+		  if ( ext != NULL )
+		  	return (const struct sieve_comparator *) 
+		  		sieve_interpreter_registry_get(cmp_registry, ext);	
+		  else
+		  	return NULL;
+		}
+	}		
+		
+	return NULL;
 }
 
 static bool tag_comparator_generate
 	(struct sieve_generator *generator, struct sieve_ast_argument **arg, 
 	struct sieve_command_context *cmd ATTR_UNUSED)
 {
-	opr_comparator_emit(generator, (struct sieve_comparator *) (*arg)->context);
+	struct sieve_binary *sbin = sieve_generator_get_binary(generator);
+	struct sieve_comparator *cmp = (struct sieve_comparator *) (*arg)->context;
+	
+	if ( cmp->extension == NULL ) {
+		if ( cmp->code < SIEVE_COMPARATOR_CUSTOM )
+			opr_comparator_emit(sbin, cmp->code);
+		else
+			return FALSE;
+	} else {
+		opr_comparator_emit_ext(sbin, cmp->extension);
+	} 
 		
 	*arg = sieve_ast_argument_next(*arg);
 	
@@ -93,14 +160,16 @@ static bool tag_comparator_generate
  */
 
 const struct sieve_comparator i_octet_comparator = {
-	SCI_I_OCTET,
 	"i;octet",
+	SIEVE_COMPARATOR_I_OCTET,
+	NULL,
 	cmp_i_octet_compare
 };
 
 const struct sieve_comparator i_ascii_casemap_comparator = {
-	SCI_I_ASCII_CASEMAP,
 	"i;ascii-casemap",
+	SIEVE_COMPARATOR_I_ASCII_CASEMAP,
+	NULL,
 	cmp_i_ascii_casemap_compare
 };
 
@@ -157,3 +226,14 @@ static int cmp_i_ascii_casemap_compare(const void *val1, size_t val1_size, const
 		
 	return result;
 }
+
+/* 
+ * Registry 
+ */
+ 
+void sieve_comparators_init_registry(struct sieve_interpreter *interp) 
+{
+	cmp_registry = sieve_interpreter_registry_init(interp, "comparators");
+}
+
+
diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h
index db804dde2..5fd8976b6 100644
--- a/src/lib-sieve/sieve-comparators.h
+++ b/src/lib-sieve/sieve-comparators.h
@@ -2,16 +2,17 @@
 #define __SIEVE_COMPARATORS_H
 
 enum sieve_comparator_code {
-	SCI_I_OCTET,
-	SCI_I_ASCII_CASEMAP,
-	
-	SCI_CUSTOM
+	SIEVE_COMPARATOR_I_OCTET,
+	SIEVE_COMPARATOR_I_ASCII_CASEMAP,
+	SIEVE_COMPARATOR_CUSTOM
 };
 
 struct sieve_comparator {
-	enum sieve_comparator_code code;
 	const char *identifier;
 	
+	enum sieve_comparator_code code;
+	const struct sieve_extension *extension;
+	
 	/* Equality, ordering, prefix and substring match */
 	
 	/* ( output similar to strncmp ) */
@@ -23,5 +24,11 @@ extern const struct sieve_argument comparator_tag;
 extern const struct sieve_comparator *sieve_core_comparators[];
 extern const unsigned int sieve_core_comparators_count;
 
+const struct sieve_comparator *sieve_opr_comparator_read
+  (struct sieve_binary *sbin, sieve_size_t *address);
+
+void sieve_comparators_init_registry(struct sieve_interpreter *interp);
+
+
 
 #endif /* __SIEVE_COMPARATORS_H */
diff --git a/src/lib-sieve/sieve-extensions.h b/src/lib-sieve/sieve-extensions.h
index e0c71c717..343b2efc7 100644
--- a/src/lib-sieve/sieve-extensions.h
+++ b/src/lib-sieve/sieve-extensions.h
@@ -1,5 +1,5 @@
-#ifndef __SIEVE_EXTENSIONS_H__
-#define __SIEVE_EXTENSIONS_H__
+#ifndef __SIEVE_EXTENSIONS_H
+#define __SIEVE_EXTENSIONS_H
 
 #include "lib.h"
 #include "sieve-common.h"
@@ -9,6 +9,7 @@ struct sieve_extension {
 	
 	bool (*validator_load)(struct sieve_validator *validator);
 	bool (*generator_load)(struct sieve_generator *generator);
+	bool (*interpreter_load)(struct sieve_interpreter *interpreter);
 
 	const struct sieve_opcode *opcode;
 	const struct sieve_operand *operand;
@@ -16,4 +17,4 @@ struct sieve_extension {
 
 const struct sieve_extension *sieve_extension_acquire(const char *extension);
 
-#endif /* __SIEVE_EXTENSIONS_H__ */
+#endif /* __SIEVE_EXTENSIONS_H */
diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index 4429c7e07..1ba3a74f7 100644
--- a/src/lib-sieve/sieve-interpreter.c
+++ b/src/lib-sieve/sieve-interpreter.c
@@ -4,6 +4,7 @@
 #include "lib.h"
 #include "mempool.h"
 #include "array.h"
+#include "hash.h"
 #include "mail-storage.h"
 
 #include "sieve-commands-private.h"
@@ -18,6 +19,9 @@ struct sieve_interpreter {
 	
 	struct sieve_binary *binary;
 		
+	/* Object registries */
+	struct hash_table *registries; 
+		
 	/* Execution status */
 	sieve_size_t pc; 
 	bool test_result;
@@ -30,19 +34,24 @@ struct sieve_interpreter {
 struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *binary) 
 {
 	pool_t pool;
-	struct sieve_interpreter *interpreter;
+	struct sieve_interpreter *interp;
 	
 	pool = pool_alloconly_create("sieve_interpreter", 4096);	
-	interpreter = p_new(pool, struct sieve_interpreter, 1);
-	interpreter->pool = pool;
+	interp = p_new(pool, struct sieve_interpreter, 1);
+	interp->pool = pool;
 	
-	interpreter->binary = binary;
+	interp->binary = binary;
 	sieve_binary_ref(binary);
 	sieve_binary_commit(binary);
 	
-	interpreter->pc = 0;
+	interp->pc = 0;
+
+	interp->registries = hash_create(pool, pool, 0, NULL, NULL);
 	
-	return interpreter;
+	/* Init core functionalities */
+	sieve_comparators_init_registry(interp);
+	
+	return interp;
 }
 
 void sieve_interpreter_free(struct sieve_interpreter *interpreter) 
@@ -51,6 +60,58 @@ void sieve_interpreter_free(struct sieve_interpreter *interpreter)
 	pool_unref(&(interpreter->pool));
 }
 
+/* Object registry */
+
+struct sieve_interpreter_registry {
+	struct sieve_interpreter *interpreter;
+	const char *name;
+	ARRAY_DEFINE(registered, void);
+};
+
+struct sieve_interpreter_registry *
+	sieve_interpreter_registry_init(struct sieve_interpreter *interp, const char *name)
+{
+	struct sieve_interpreter_registry *reg = (struct sieve_interpreter_registry *) 
+		hash_lookup(interp->registries, name);
+	
+	if ( reg == NULL ) {
+		reg = p_new(interp->pool, struct sieve_interpreter_registry, 1);
+		reg->interpreter = interp;
+		reg->name = name;
+		array_create(&reg->registered, interp->pool, sizeof(void *), 5);
+		
+		hash_insert(interp->registries, (void *) name, (void *) reg);
+	}
+
+	return reg;
+}
+
+const void *sieve_interpreter_registry_get
+	(struct sieve_interpreter_registry *reg, const struct sieve_extension *ext)
+{
+	const void *result;
+	int index = sieve_binary_get_extension_index(reg->interpreter->binary, ext);
+	
+	if  ( index < 0 || index > (int) array_count(&reg->registered) )
+		return NULL;
+	
+	result = array_idx(&reg->registered, (unsigned int) index);		
+	
+	return result;
+}
+
+void  sieve_interpreter_registry_set
+	(struct sieve_interpreter_registry *reg, const struct sieve_extension *ext, const void *obj)
+{
+	int index = sieve_binary_get_extension_index(reg->interpreter->binary, ext);
+	
+	if  ( index < 0 || index > (int) array_count(&reg->registered) )
+		return;
+	
+	array_idx_set(&reg->registered, (unsigned int) index, obj);		
+}
+
+
 /* Accessing runtinme environment */
 
 inline struct mail *sieve_interpreter_get_mail(struct sieve_interpreter *interpreter) 
diff --git a/src/lib-sieve/sieve-interpreter.h b/src/lib-sieve/sieve-interpreter.h
index 73f1171a4..031583349 100644
--- a/src/lib-sieve/sieve-interpreter.h
+++ b/src/lib-sieve/sieve-interpreter.h
@@ -2,12 +2,12 @@
 #define __SIEVE_INTERPRETER_H__
 
 #include "lib.h"
+#include "array.h"
 #include "buffer.h"
 #include "mail-storage.h"
 
 #include "sieve-binary.h"
-
-struct sieve_coded_stringlist;
+#include "sieve-code.h"
 
 struct sieve_interpreter;
 
@@ -29,17 +29,22 @@ inline bool sieve_interpreter_get_test_result
 inline struct sieve_binary *sieve_interpreter_get_binary
 	(struct sieve_interpreter *interp);
 
+/* Object registry */
+
+struct sieve_interpreter_registry;
+
+struct sieve_interpreter_registry *
+	sieve_interpreter_registry_init(struct sieve_interpreter *interp, const char *name);
+const void *sieve_interpreter_registry_get
+	(struct sieve_interpreter_registry *reg, const struct sieve_extension *ext);
+void  sieve_interpreter_registry_set
+	(struct sieve_interpreter_registry *reg, const struct sieve_extension *ext, const void *obj);
+	
 /* Opcodes and operands */
 
 bool sieve_interpreter_read_offset_operand
 	(struct sieve_interpreter *interpreter, int *offset);
-bool sieve_interpreter_read_number_operand
-  (struct sieve_interpreter *interpreter, sieve_size_t *number);
-bool sieve_interpreter_read_string_operand
-  (struct sieve_interpreter *interpreter, string_t **str);
-struct sieve_coded_stringlist *sieve_interpreter_read_stringlist_operand
-	(struct sieve_interpreter *interpreter);
-	
+
 /* Stringlist Utility */
 
 bool sieve_stringlist_match
-- 
GitLab