From e25f3bafe65f9ada1b8e50915e42baaffa22b362 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sun, 11 Nov 2007 17:19:01 +0100
Subject: [PATCH] Added support for optional operators to the byte code
 implementation.

---
 sieve/tests/comparator.sieve                  |  4 +
 src/lib-sieve/ext-envelope.c                  | 34 ++++++++-
 src/lib-sieve/plugins/vacation/ext-vacation.c | 21 +++--
 src/lib-sieve/sieve-ast.c                     |  2 +
 src/lib-sieve/sieve-ast.h                     |  1 +
 src/lib-sieve/sieve-code.c                    | 39 ++++++++--
 src/lib-sieve/sieve-code.h                    |  7 ++
 src/lib-sieve/sieve-comparators.c             | 17 ++++-
 src/lib-sieve/sieve-comparators.h             |  6 ++
 src/lib-sieve/sieve-generator.c               | 30 ++++++++
 src/lib-sieve/sieve-validator.c               | 76 +++++++++++++------
 src/lib-sieve/sieve-validator.h               | 11 ++-
 src/lib-sieve/tst-address.c                   | 54 ++++++++++++-
 src/lib-sieve/tst-header.c                    | 48 +++++++++++-
 src/lib-sieve/tst-size.c                      |  4 +-
 15 files changed, 305 insertions(+), 49 deletions(-)

diff --git a/sieve/tests/comparator.sieve b/sieve/tests/comparator.sieve
index 12de98223..291276ab2 100644
--- a/sieve/tests/comparator.sieve
+++ b/sieve/tests/comparator.sieve
@@ -1,5 +1,9 @@
 if header :is :comparator "i;ascii-casemap" "from" "STEPHAN@drunksnipers.com" {
 	discard;
+
+	if address :is :comparator "i;octet" :domain "from" "drunksnipers.com" {
+		keep;
+	}
 	stop;
 }
 
diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index fae863efe..268ad1154 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -30,13 +30,22 @@ const struct sieve_extension envelope_extension =
 static const struct sieve_command envelope_test = 
 	{ "envelope", SCT_TEST, tst_envelope_registered, tst_envelope_validate, tst_envelope_generate, NULL };
 
+/* Optional arguments */
+
+enum tst_envelope_optional {
+	OPT_END,
+	OPT_COMPARATOR,
+	OPT_ADDRESS_PART,
+	OPT_MATCH_TYPE
+};
+
 /* Command Registration */
 static bool tst_envelope_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
 {
 	/* The order of these is not significant */
-	sieve_validator_link_comparator_tag(validator, cmd_reg);
-	sieve_validator_link_address_part_tags(validator, cmd_reg);
-	sieve_validator_link_match_type_tags(validator, cmd_reg);
+	sieve_validator_link_comparator_tag(validator, cmd_reg, OPT_COMPARATOR);
+	sieve_validator_link_address_part_tags(validator, cmd_reg, OPT_ADDRESS_PART);
+	sieve_validator_link_match_type_tags(validator, cmd_reg, OPT_MATCH_TYPE);
 	
 	return TRUE;
 }
@@ -111,8 +120,27 @@ static bool ext_envelope_opcode_dump
 	(struct sieve_interpreter *interp ATTR_UNUSED, 
 	struct sieve_binary *sbin, sieve_size_t *address)
 {
+	unsigned opt_code;
+
 	printf("ENVELOPE\n");
 
+	/* Handle any optional arguments */
+    if ( sieve_operand_optional_present(sbin, address) ) {
+        while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
+            switch ( opt_code ) {
+            case OPT_COMPARATOR:
+                sieve_opr_comparator_dump(sbin, address);
+                break;
+            case OPT_MATCH_TYPE:
+                break;
+			case OPT_ADDRESS_PART:
+				break;
+            default:
+                return FALSE;
+            }
+        }
+    }
+
 	return
 		sieve_opr_stringlist_dump(sbin, address) &&
 		sieve_opr_stringlist_dump(sbin, address);
diff --git a/src/lib-sieve/plugins/vacation/ext-vacation.c b/src/lib-sieve/plugins/vacation/ext-vacation.c
index da710b1b7..7d9d39dd1 100644
--- a/src/lib-sieve/plugins/vacation/ext-vacation.c
+++ b/src/lib-sieve/plugins/vacation/ext-vacation.c
@@ -183,14 +183,23 @@ static const struct sieve_argument vacation_mime_tag =
 static const struct sieve_argument vacation_handle_tag = 
 	{ "handle", cmd_vacation_validate_handle_tag, NULL };
 
+enum cmd_vacation_optional {
+	OPT_DAYS,
+	OPT_SUBJECT,
+	OPT_FROM,
+	OPT_ADDRESS,
+	OPT_MIME,
+	OPT_HANDLE
+};
+
 static bool cmd_vacation_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
 {
-	sieve_validator_register_tag(validator, cmd_reg, &vacation_days_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &vacation_subject_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &vacation_from_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &vacation_addresses_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &vacation_mime_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &vacation_handle_tag); 	
+	sieve_validator_register_tag(validator, cmd_reg, &vacation_days_tag, OPT_DAYS); 	
+	sieve_validator_register_tag(validator, cmd_reg, &vacation_subject_tag, OPT_SUBJECT); 	
+	sieve_validator_register_tag(validator, cmd_reg, &vacation_from_tag, OPT_FROM); 	
+	sieve_validator_register_tag(validator, cmd_reg, &vacation_addresses_tag, OPT_ADDRESS); 	
+	sieve_validator_register_tag(validator, cmd_reg, &vacation_mime_tag, OPT_MIME); 	
+	sieve_validator_register_tag(validator, cmd_reg, &vacation_handle_tag, OPT_HANDLE); 	
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c
index 3b45748df..b66658ac7 100644
--- a/src/lib-sieve/sieve-ast.c
+++ b/src/lib-sieve/sieve-ast.c
@@ -149,7 +149,9 @@ static struct sieve_ast_argument *sieve_ast_argument_create
 	
 	arg->source_line = source_line;
 	arg->context = NULL;
+	
 	arg->argument = NULL;
+	arg->arg_id_code = 0;
 			
 	return arg;
 }
diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h
index 1288e8d44..1d97da134 100644
--- a/src/lib-sieve/sieve-ast.h
+++ b/src/lib-sieve/sieve-ast.h
@@ -83,6 +83,7 @@ struct sieve_ast_argument {
 
 	/* Argument associated with this ast element  */
 	const struct sieve_argument *argument;
+	unsigned int arg_id_code;
 
 	/* Context data associated with this ast element */
 	void *context;
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index 3d727e01d..9e2efba0e 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -122,6 +122,34 @@ const struct sieve_operand *sieve_operand_read
 	return NULL;
 }
 
+bool sieve_operand_optional_present(struct sieve_binary *sbin, sieve_size_t *address)
+{	
+	sieve_size_t tmp_addr = *address;
+	unsigned int op = -1;
+	
+	if ( sieve_binary_read_byte(sbin, &tmp_addr, &op) && (op == SIEVE_OPERAND_OPTIONAL) ) {
+		*address = tmp_addr;
+		return TRUE;
+	}
+	
+	return FALSE;
+}
+
+unsigned int sieve_operand_optional_read(struct sieve_binary *sbin, sieve_size_t *address)
+{
+	unsigned int id = -1;
+	
+	if ( sieve_binary_read_byte(sbin, address, &id) ) {
+		/* No more optionals */
+		if ( id == 0 ) 
+			return 0;
+			
+		return id;
+	}
+	
+	return -1;
+}
+
 /* 
  * Operand definitions
  */
@@ -140,7 +168,7 @@ const struct sieve_operand_class number_class =
 	{ "number", &number_interface };
 	
 const struct sieve_operand number_operand = 
-	{ "number", &number_class };
+	{ "@number", &number_class, TRUE };
 
 /* String */
 
@@ -157,7 +185,7 @@ const struct sieve_operand_class string_class =
 	{ "string", &string_interface };
 	
 const struct sieve_operand string_operand = 
-	{ "string", &string_class };
+	{ "@string", &string_class, TRUE };
 	
 
 /* String List */
@@ -184,13 +212,14 @@ const struct sieve_operand_class stringlist_class =
 	{ "string-list", &stringlist_interface };
 
 const struct sieve_operand stringlist_operand = 
-	{ "string-list", &stringlist_class };
+	{ "@string-list", &stringlist_class, TRUE };
 	
 /* Core operands */
 
 extern struct sieve_operand comparator_operand;
 
 const struct sieve_operand *sieve_operands[] = {
+	NULL, /* SIEVE_OPERAND_OPTIONAL */
 	&number_operand,
 	&string_operand,
 	&stringlist_operand,
@@ -499,8 +528,8 @@ static struct sieve_coded_stringlist *opr_stringlist_read
 	end = pc + end_offset;
 
 	if ( !sieve_binary_read_integer(sbin, address, &length) ) 
-  	return NULL;
-
+  	return NULL;	
+  	
 	strlist = sieve_coded_stringlist_create(sbin, *address, length, end); 
 
   /* Skip over the string list for now */
diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h
index 3259ebd55..e8a50bea4 100644
--- a/src/lib-sieve/sieve-code.h
+++ b/src/lib-sieve/sieve-code.h
@@ -30,6 +30,8 @@ struct sieve_operand {
 	const char *name;
 	
 	const struct sieve_operand_class *class;
+
+	unsigned int positional:1;
 };
 
 struct sieve_opr_number_interface {
@@ -54,6 +56,7 @@ struct sieve_opr_stringlist_interface {
 };
 
 enum sieve_core_operand {
+	SIEVE_OPERAND_OPTIONAL,
   SIEVE_OPERAND_NUMBER,
   SIEVE_OPERAND_STRING,
   SIEVE_OPERAND_STRING_LIST,
@@ -70,6 +73,10 @@ inline sieve_size_t sieve_operand_emit_code
 const struct sieve_operand *sieve_operand_read
 	(struct sieve_binary *sbin, sieve_size_t *address);
 
+bool sieve_operand_optional_present(struct sieve_binary *sbin, sieve_size_t *address);
+unsigned int sieve_operand_optional_read
+	(struct sieve_binary *sbin, sieve_size_t *address);
+
 void sieve_opr_number_emit(struct sieve_binary *sbin, sieve_size_t number);
 bool sieve_opr_number_dump(struct sieve_binary *sbin, sieve_size_t *address); 
 bool sieve_opr_number_read
diff --git a/src/lib-sieve/sieve-comparators.c b/src/lib-sieve/sieve-comparators.c
index 09623c04b..fd93cb72e 100644
--- a/src/lib-sieve/sieve-comparators.c
+++ b/src/lib-sieve/sieve-comparators.c
@@ -1,3 +1,5 @@
+#include <stdio.h>
+
 #include "lib.h"
 #include "compat.h"
 
@@ -31,7 +33,7 @@ static int cmp_i_ascii_casemap_compare(const void *val1, size_t val1_size, const
  */
  
 struct sieve_operand_class comparator_class = { "comparator", NULL };
-struct sieve_operand comparator_operand = { "comparator", &comparator_class };
+struct sieve_operand comparator_operand = { "comparator", &comparator_class, FALSE };
 
 /* 
  * Comparator tag 
@@ -134,6 +136,19 @@ const struct sieve_comparator *sieve_opr_comparator_read
 	return NULL;
 }
 
+bool sieve_opr_comparator_dump(struct sieve_binary *sbin, sieve_size_t *address)
+{
+	sieve_size_t pc = *address;
+	const struct sieve_comparator *cmp = sieve_opr_comparator_read(sbin, address);
+	
+	if ( cmp == NULL )
+		return FALSE;
+		
+	printf("%08x:   CMP: %s\n", pc, cmp->identifier);
+	
+	return TRUE;
+}
+
 static bool tag_comparator_generate
 	(struct sieve_generator *generator, struct sieve_ast_argument **arg, 
 	struct sieve_command_context *cmd ATTR_UNUSED)
diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h
index 5fd8976b6..77da4c23c 100644
--- a/src/lib-sieve/sieve-comparators.h
+++ b/src/lib-sieve/sieve-comparators.h
@@ -21,11 +21,17 @@ struct sieve_comparator {
 
 extern const struct sieve_argument comparator_tag;
 
+
+const struct sieve_comparator i_octet_comparator;
+const struct sieve_comparator i_ascii_casemap_comparator;
+
 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);
+bool sieve_opr_comparator_dump
+	(struct sieve_binary *sbin, sieve_size_t *address);
 
 void sieve_comparators_init_registry(struct sieve_interpreter *interp);
 
diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c
index e8dc10b0f..e23f5606c 100644
--- a/src/lib-sieve/sieve-generator.c
+++ b/src/lib-sieve/sieve-generator.c
@@ -103,12 +103,42 @@ inline sieve_size_t sieve_generator_emit_opcode_ext
 bool sieve_generate_arguments(struct sieve_generator *generator, 
 	struct sieve_command_context *cmd, struct sieve_ast_argument **last_arg)
 {
+	enum { ARG_START, ARG_OPTIONAL, ARG_POSITIONAL } state = ARG_START;
 	struct sieve_ast_argument *arg = sieve_ast_argument_first(cmd->ast_node);
 	
 	/* Parse all arguments with assigned generator function */
+	
 	while ( arg != NULL && arg->argument != NULL) {
 		const struct sieve_argument *argument = arg->argument;
 		
+		switch ( state ) {
+		case ARG_START: 
+			if ( arg->arg_id_code == 0 )
+				state = ARG_POSITIONAL;
+			else {
+				/* Mark start of optional operands with 0 operand identifier */
+				sieve_binary_emit_byte(generator->binary, SIEVE_OPERAND_OPTIONAL);
+				
+				/* Emit argument id for optional operand */
+				sieve_binary_emit_byte(generator->binary, arg->arg_id_code);
+
+				state = ARG_OPTIONAL;
+			}
+			break;
+		case ARG_OPTIONAL: 
+			if ( arg->arg_id_code == 0 )
+				state = ARG_POSITIONAL;
+			
+			/* Emit argument id for optional operand (0 marks the end of the optionals) */
+			sieve_binary_emit_byte(generator->binary, arg->arg_id_code);
+
+			break;
+		case ARG_POSITIONAL:
+			if ( arg->arg_id_code != 0 )
+				return FALSE;
+			break;
+		}
+		
 		/* Call the generation function for the argument */ 
 		if ( argument->generate != NULL ) { 
 			if ( !argument->generate(generator, &arg, cmd) ) 
diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c
index 51e8ef50f..26f6ac524 100644
--- a/src/lib-sieve/sieve-validator.c
+++ b/src/lib-sieve/sieve-validator.c
@@ -163,7 +163,13 @@ static const struct sieve_command *
   return ( record == NULL ? NULL : record->command );
 }
 
-/* Per-command tag registry */
+/* Per-command tag/argument registry */
+
+struct sieve_tag_registration {
+	const struct sieve_argument *tag;
+	
+	unsigned int id_code;
+};
 
 static bool _unknown_tag_validate
 	(struct sieve_validator *validator ATTR_UNUSED, 
@@ -176,36 +182,54 @@ static bool _unknown_tag_validate
 
 static const struct sieve_argument _unknown_tag = { "", _unknown_tag_validate, NULL };
 
-void sieve_validator_register_tag
+static void _sieve_validator_register_tag
 	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, 
-	const struct sieve_argument *tag) 
+	const struct sieve_argument *tag, const char *identifier, unsigned int id_code) 
 {
+	struct sieve_tag_registration *reg;
+	
+	reg = p_new(validator->pool, struct sieve_tag_registration, 1);
+	reg->tag = tag;
+	reg->id_code = id_code;
+	
 	if ( cmd_reg->tags == NULL ) {
 		cmd_reg->tags = hash_create
 			(validator->pool, validator->pool, 0, str_hash, (hash_cmp_callback_t *)strcmp);
 	}
 	
-	hash_insert(cmd_reg->tags, (void *) tag->identifier, (void *) tag);
+	hash_insert(cmd_reg->tags, (void *) identifier, (void *) reg);
+}
+
+void sieve_validator_register_tag
+	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, 
+	const struct sieve_argument *tag, unsigned int id_code) 
+{
+	_sieve_validator_register_tag(validator, cmd_reg, tag, tag->identifier, id_code);
 }
 
 static void sieve_validator_register_unknown_tag
 	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, 
 	const char *tag) 
 {
-	if ( cmd_reg->tags == NULL ) {
-		cmd_reg->tags = hash_create
-			(validator->pool, validator->pool, 0, str_hash, (hash_cmp_callback_t *)strcmp);
-	}
-	
-	hash_insert(cmd_reg->tags, (void *) tag, (void *) &_unknown_tag);
+	_sieve_validator_register_tag(validator, cmd_reg, &_unknown_tag, tag, 0);
 }
 
 static const struct sieve_argument *sieve_validator_find_tag
-	(struct sieve_command_registration *cmd_reg, const char *tag) 
+	(struct sieve_command_registration *cmd_reg, const char *tag, unsigned int *id_code) 
 {
+	const struct sieve_tag_registration *reg;
+	
+	*id_code = 0;
+	
 	if ( cmd_reg->tags == NULL ) return NULL;
 	
-  return (struct sieve_argument *) hash_lookup(cmd_reg->tags, tag);
+	reg = (const struct sieve_tag_registration *) hash_lookup(cmd_reg->tags, tag);
+	
+	if ( reg == NULL )return NULL;
+	
+	*id_code = reg->id_code;
+	
+  return reg->tag; 
 }
 
 /* Extension support */
@@ -257,9 +281,10 @@ static void sieve_validator_register_core_comparators(struct sieve_validator *va
 /* Comparator validation */
 
 void sieve_validator_link_comparator_tag
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
+	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,	
+		unsigned int id_code) 
 {
-	sieve_validator_register_tag(validator, cmd_reg, &comparator_tag); 	
+	sieve_validator_register_tag(validator, cmd_reg, &comparator_tag, id_code); 	
 }
 
 /* Match type validation */
@@ -287,11 +312,12 @@ static const struct sieve_argument match_matches_tag =
 	{ "matches", sieve_validate_match_type_tag, NULL };
 
 void sieve_validator_link_match_type_tags
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
+	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,
+		unsigned int id_code) 
 {
-	sieve_validator_register_tag(validator, cmd_reg, &match_is_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &match_contains_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &match_matches_tag); 	
+	sieve_validator_register_tag(validator, cmd_reg, &match_is_tag, id_code); 	
+	sieve_validator_register_tag(validator, cmd_reg, &match_contains_tag, id_code); 	
+	sieve_validator_register_tag(validator, cmd_reg, &match_matches_tag, id_code); 	
 }
 
 /* Address part validation */
@@ -319,11 +345,12 @@ static const struct sieve_argument address_all_tag =
 	{ "all", sieve_validate_address_part_tag, NULL };
 
 void sieve_validator_link_address_part_tags
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
+	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,
+		unsigned int id_code) 
 {
-	sieve_validator_register_tag(validator, cmd_reg, &address_localpart_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &address_domain_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &address_all_tag); 	
+	sieve_validator_register_tag(validator, cmd_reg, &address_localpart_tag, id_code); 	
+	sieve_validator_register_tag(validator, cmd_reg, &address_domain_tag, id_code); 	
+	sieve_validator_register_tag(validator, cmd_reg, &address_all_tag, id_code); 	
 }
 
 /* Tag Validation API */
@@ -361,7 +388,9 @@ bool sieve_validate_command_arguments
 	
 	/* Parse tagged and optional arguments */
 	while ( sieve_ast_argument_type(arg) == SAAT_TAG ) {
-		const struct sieve_argument *tag = sieve_validator_find_tag(cmd_reg, sieve_ast_argument_tag(arg));
+		unsigned int id_code;
+		const struct sieve_argument *tag = 
+			sieve_validator_find_tag(cmd_reg, sieve_ast_argument_tag(arg), &id_code);
 		
 		if ( tag == NULL ) {
 			sieve_command_validate_error(validator, cmd, 
@@ -377,6 +406,7 @@ bool sieve_validate_command_arguments
 		
 		/* Assign the tagged argument type to the ast for later reference (in generator) */
 		arg->argument = tag;
+		arg->arg_id_code = id_code;
 		
 		/* Call the validation function for the tag (if present)
 		 *   Fail if the validation fails.
diff --git a/src/lib-sieve/sieve-validator.h b/src/lib-sieve/sieve-validator.h
index e3aaf3b80..8103faaf3 100644
--- a/src/lib-sieve/sieve-validator.h
+++ b/src/lib-sieve/sieve-validator.h
@@ -29,7 +29,7 @@ void sieve_validator_register_command
 /* Argument registration */
 void sieve_validator_register_tag
 	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, 
-	const struct sieve_argument *argument);
+	const struct sieve_argument *argument, unsigned int id_code);
 	
 /* Comparator registration */
 void sieve_validator_register_comparator
@@ -39,11 +39,14 @@ const struct sieve_comparator *sieve_validator_find_comparator
 
 /* Special test arguments */
 void sieve_validator_link_comparator_tag
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg); 
+	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,
+		unsigned int id_code); 
 void sieve_validator_link_match_type_tags
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg); 
+	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,
+		unsigned int id_code); 
 void sieve_validator_link_address_part_tags
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg); 
+	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,
+		unsigned int id_code); 
 
 /* Argument validation */
 bool sieve_validate_command_arguments
diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c
index 1f0b7cb39..6432abfb0 100644
--- a/src/lib-sieve/tst-address.c
+++ b/src/lib-sieve/tst-address.c
@@ -16,14 +16,23 @@ static bool tst_address_opcode_execute
 const struct sieve_opcode tst_address_opcode = 
 	{ tst_address_opcode_dump, tst_address_opcode_execute };
 
+/* Optional arguments */
+
+enum tst_address_optional {
+	OPT_END,
+	OPT_COMPARATOR,
+	OPT_ADDRESS_PART,
+	OPT_MATCH_TYPE
+};
+
 /* Test registration */
 
 bool tst_address_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
 {
 	/* The order of these is not significant */
-	sieve_validator_link_comparator_tag(validator, cmd_reg);
-	sieve_validator_link_address_part_tags(validator, cmd_reg);
-	sieve_validator_link_match_type_tags(validator, cmd_reg);
+	sieve_validator_link_comparator_tag(validator, cmd_reg, OPT_COMPARATOR );
+	sieve_validator_link_address_part_tags(validator, cmd_reg, OPT_ADDRESS_PART);
+	sieve_validator_link_match_type_tags(validator, cmd_reg, OPT_MATCH_TYPE);
 
 	return TRUE;
 }
@@ -85,8 +94,27 @@ static bool tst_address_opcode_dump
 	(struct sieve_interpreter *interp ATTR_UNUSED, 
 	struct sieve_binary *sbin, sieve_size_t *address)
 {
+	unsigned int opt_code;
+
 	printf("ADDRESS\n");
 
+	/* Handle any optional arguments */
+    if ( sieve_operand_optional_present(sbin, address) ) {
+        while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
+            switch ( opt_code ) {
+            case OPT_COMPARATOR:
+                sieve_opr_comparator_dump(sbin, address);
+                break;
+            case OPT_MATCH_TYPE:
+                break;
+			case OPT_ADDRESS_PART:
+				break;			
+            default:
+                return FALSE;
+            }
+        }
+    }
+
 	return
 		sieve_opr_stringlist_dump(sbin, address) &&
 		sieve_opr_stringlist_dump(sbin, address);
@@ -98,6 +126,9 @@ static bool tst_address_opcode_execute
 	(struct sieve_interpreter *interp, struct sieve_binary *sbin, sieve_size_t *address)
 {
 	struct mail *mail = sieve_interpreter_get_mail(interp);
+	
+	const struct sieve_comparator *cmp = &i_octet_comparator;
+	unsigned int opt_code;
 	struct sieve_coded_stringlist *hdr_list;
 	struct sieve_coded_stringlist *key_list;
 	string_t *hdr_item;
@@ -105,6 +136,23 @@ static bool tst_address_opcode_execute
 	
 	printf("?? ADDRESS\n");
 
+	/* Handle any optional arguments */
+    if ( sieve_operand_optional_present(sbin, address) ) {
+        while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
+            switch ( opt_code ) {
+            case OPT_COMPARATOR:
+                cmp = sieve_opr_comparator_read(sbin, address);
+                break;
+            case OPT_MATCH_TYPE:
+                break;
+			case OPT_ADDRESS_PART:
+				break;
+            default:
+                return FALSE;
+            }
+        }
+    }
+
 	t_push();
 		
 	/* Read header-list */
diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c
index 7183b3e86..91444b351 100644
--- a/src/lib-sieve/tst-header.c
+++ b/src/lib-sieve/tst-header.c
@@ -2,6 +2,7 @@
 
 #include "sieve-commands.h"
 #include "sieve-commands-private.h"
+#include "sieve-comparators.h"
 #include "sieve-validator.h"
 #include "sieve-generator.h"
 #include "sieve-interpreter.h"
@@ -16,13 +17,21 @@ static bool tst_header_opcode_execute
 const struct sieve_opcode tst_header_opcode = 
 	{ tst_header_opcode_dump, tst_header_opcode_execute };
 
+/* Optional arguments */
+
+enum tst_header_optional {	
+	OPT_END,
+	OPT_COMPARATOR,
+	OPT_MATCH_TYPE
+};
+
 /* Test registration */
 
 bool tst_header_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
 {
 	/* The order of these is not significant */
-	sieve_validator_link_comparator_tag(validator, cmd_reg);
-	sieve_validator_link_match_type_tags(validator, cmd_reg);
+	sieve_validator_link_comparator_tag(validator, cmd_reg, OPT_COMPARATOR);
+	sieve_validator_link_match_type_tags(validator, cmd_reg, OPT_MATCH_TYPE);
 
 	return TRUE;
 }
@@ -81,8 +90,25 @@ static bool tst_header_opcode_dump
 	(struct sieve_interpreter *interp ATTR_UNUSED, 
 	struct sieve_binary *sbin, sieve_size_t *address)
 {
+	unsigned int opt_code;
+
     printf("HEADER\n");
 
+	/* Handle any optional arguments */
+	if ( sieve_operand_optional_present(sbin, address) ) {
+		while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
+			switch ( opt_code ) {
+			case OPT_COMPARATOR:
+				sieve_opr_comparator_dump(sbin, address);
+				break;
+			case OPT_MATCH_TYPE:
+				break;
+			default: 
+				return FALSE;
+			}
+ 		}
+	}
+
 	return
     	sieve_opr_stringlist_dump(sbin, address) &&
     	sieve_opr_stringlist_dump(sbin, address);
@@ -94,6 +120,9 @@ static bool tst_header_opcode_execute
 	(struct sieve_interpreter *interp, struct sieve_binary *sbin, sieve_size_t *address)
 {
 	struct mail *mail = sieve_interpreter_get_mail(interp);
+
+	unsigned int opt_code;
+	const struct sieve_comparator *cmp = &i_octet_comparator;
 	struct sieve_coded_stringlist *hdr_list;
 	struct sieve_coded_stringlist *key_list;
 	string_t *hdr_item;
@@ -101,6 +130,21 @@ static bool tst_header_opcode_execute
 	
 	printf("?? HEADER\n");
 
+	/* Handle any optional arguments */
+    if ( sieve_operand_optional_present(sbin, address) ) {
+        while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
+            switch ( opt_code ) {
+            case OPT_COMPARATOR:
+                cmp = sieve_opr_comparator_read(sbin, address);
+                break;
+            case OPT_MATCH_TYPE:
+                break;
+            default:
+                return FALSE;
+            }
+        }
+    }
+
 	t_push();
 		
 	/* Read header-list */
diff --git a/src/lib-sieve/tst-size.c b/src/lib-sieve/tst-size.c
index 715ea9667..9c6650707 100644
--- a/src/lib-sieve/tst-size.c
+++ b/src/lib-sieve/tst-size.c
@@ -83,8 +83,8 @@ static const struct sieve_argument size_under_tag =
 
 bool tst_size_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
 {
-	sieve_validator_register_tag(validator, cmd_reg, &size_over_tag); 	
-	sieve_validator_register_tag(validator, cmd_reg, &size_under_tag); 	
+	sieve_validator_register_tag(validator, cmd_reg, &size_over_tag, 0); 	
+	sieve_validator_register_tag(validator, cmd_reg, &size_under_tag, 0); 	
 
 	return TRUE;
 }
-- 
GitLab