From cc7a4672bbcbde9b686cff494bd95972f4f875ca Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Thu, 25 Oct 2007 22:43:53 +0200
Subject: [PATCH] Made address and size tests executable and fixed minor bug
 regarding the lexer.

---
 sieve/tests/basic.sieve           |   4 +-
 src/lib-sieve/sieve-binary.c      |  10 +-
 src/lib-sieve/sieve-code.c        |  42 +++-
 src/lib-sieve/sieve-code.h        |   1 +
 src/lib-sieve/sieve-interpreter.c | 321 ++++++++++++++++++++++++------
 src/lib-sieve/sieve-interpreter.h |  50 +++--
 src/lib-sieve/sieve-lexer.c       |  13 +-
 src/lib-sieve/sieve.c             |  13 +-
 src/lib-sieve/sieve.h             |   2 +-
 src/lib-sieve/tst-address.c       |  60 +++++-
 src/lib-sieve/tst-size.c          |  55 ++++-
 src/sieve-bin/Makefile.am         |   4 +-
 src/sieve-bin/sieve_test.c        |  37 +++-
 src/sieve-bin/sievec.c            |   4 +-
 14 files changed, 497 insertions(+), 119 deletions(-)

diff --git a/sieve/tests/basic.sieve b/sieve/tests/basic.sieve
index 5ee7bc2dc..876dc5a00 100644
--- a/sieve/tests/basic.sieve
+++ b/sieve/tests/basic.sieve
@@ -1,6 +1,6 @@
-if false {	
+if address :is ["from", "to", "cc"] "sirius@drunksnipers.com {
   keep;
-} elsif false {
+} elsif size :under 4000 {
   stop;
 } else {
   discard;
diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c
index 90920446e..811470d0b 100644
--- a/src/lib-sieve/sieve-binary.c
+++ b/src/lib-sieve/sieve-binary.c
@@ -51,12 +51,16 @@ unsigned int sieve_binary_link_extension(struct sieve_binary *binary, const stru
 
 const struct sieve_extension *sieve_binary_get_extension(struct sieve_binary *binary, unsigned int index) 
 {
-	const struct sieve_extension * const*ext = array_idx(&(binary->extensions), index);
+	const struct sieve_extension * const *ext;
 	
-	return *ext;
+	if ( array_count(&(binary->extensions)) > index ) {
+		ext = array_idx(&(binary->extensions), index);
+		return *ext;
+	}
+	
+	return NULL;
 }
 
-
 /* Emission functions */
 
 inline sieve_size_t sieve_binary_emit_data(struct sieve_binary *binary, void *data, sieve_size_t size) 
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index 8c5e7713b..fafb6c1be 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -45,14 +45,20 @@ const struct sieve_opcode *sieve_opcodes[] = {
   &tst_size_under_opcode
 }; 
 
+const unsigned int sieve_opcode_count =
+	(sizeof(sieve_opcodes) / sizeof(sieve_opcodes[0]));
+
 /* Code dump for core commands */
 
 static bool sieve_code_dump_jmp(struct sieve_interpreter *interpreter)
 {
 	unsigned int pc = sieve_interpreter_program_counter(interpreter);
-	int offset = sieve_interpreter_read_offset(interpreter);
+	int offset;
 	
-	printf("JMP %d [%08x]\n", offset, pc + offset);
+	if ( sieve_interpreter_read_offset_operand(interpreter, &offset) ) 
+		printf("JMP %d [%08x]\n", offset, pc + offset);
+	else
+		return FALSE;
 	
 	return TRUE;
 }	
@@ -60,9 +66,12 @@ static bool sieve_code_dump_jmp(struct sieve_interpreter *interpreter)
 static bool sieve_code_dump_jmptrue(struct sieve_interpreter *interpreter)
 {	
 	unsigned int pc = sieve_interpreter_program_counter(interpreter);
-	int offset = sieve_interpreter_read_offset(interpreter);
-		
-	printf("JMPTRUE %d [%08x]\n", offset, pc + offset);
+	int offset;
+	
+	if ( sieve_interpreter_read_offset_operand(interpreter, &offset) ) 
+		printf("JMPTRUE %d [%08x]\n", offset, pc + offset);
+	else
+		return FALSE;
 	
 	return TRUE;
 }
@@ -70,9 +79,12 @@ static bool sieve_code_dump_jmptrue(struct sieve_interpreter *interpreter)
 static bool sieve_code_dump_jmpfalse(struct sieve_interpreter *interpreter)
 {	
 	unsigned int pc = sieve_interpreter_program_counter(interpreter);
-	int offset = sieve_interpreter_read_offset(interpreter);
+	int offset;
 	
-	printf("JMPFALSE %d [%08x]\n", offset, pc + offset);
+	if ( sieve_interpreter_read_offset_operand(interpreter, &offset) )
+		printf("JMPFALSE %d [%08x]\n", offset, pc + offset);
+	else
+		return FALSE;
 	
 	return TRUE;
 }	
@@ -102,21 +114,31 @@ static bool sieve_code_dump_discard(struct sieve_interpreter *interpreter ATTR_U
 
 static bool sieve_code_execute_jmp(struct sieve_interpreter *interpreter)
 {
-	sieve_interpreter_program_jump(interpreter);
+	printf("JMP\n");
+	if ( !sieve_interpreter_program_jump(interpreter, TRUE) )
+		return FALSE;
 	
 	return TRUE;
 }	
 		
 static bool sieve_code_execute_jmptrue(struct sieve_interpreter *interpreter)
 {	
-	sieve_interpreter_program_jump(interpreter);
+	if ( !sieve_interpreter_program_jump(interpreter,
+		sieve_interpreter_get_test_result(interpreter)) )
+		return FALSE;
+		
+	printf("JMPTRUE\n");
 	
 	return TRUE;
 }
 
 static bool sieve_code_execute_jmpfalse(struct sieve_interpreter *interpreter)
 {	
-	sieve_interpreter_program_jump(interpreter);
+	if ( !sieve_interpreter_program_jump(interpreter,
+		!sieve_interpreter_get_test_result(interpreter)) )
+		return FALSE;
+		
+	printf("JMPFALSE\n");
 	
 	return TRUE;
 }	
diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h
index 3af305ba0..3e34eb5fc 100644
--- a/src/lib-sieve/sieve-code.h
+++ b/src/lib-sieve/sieve-code.h
@@ -29,6 +29,7 @@ enum sieve_core_operation {
 };
 
 extern const struct sieve_opcode *sieve_opcodes[];
+extern const unsigned int sieve_opcode_count;
 
 enum sieve_core_operand {
   SIEVE_OPERAND_NUMBER       = 0x01,
diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index 1f59d2069..a1702edfb 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 "mail-storage.h"
 
 #include "sieve-commands-private.h"
 #include "sieve-generator.h"
@@ -16,6 +17,7 @@ struct sieve_coded_stringlist {
   struct sieve_interpreter *interpreter;
   sieve_size_t start_address;
   sieve_size_t end_address;
+  sieve_size_t current_offset;
   int length;
   int index;
 };
@@ -25,6 +27,11 @@ struct sieve_coded_stringlist {
 #define CODE_BYTES_LEFT(interpreter) (interpreter->code_size - interpreter->pc)
 #define CODE_JUMP(interpreter, offset) interpreter->pc += offset
 
+#define ADDR_CODE_AT(interpreter, address) (interpreter->code[*address])
+#define ADDR_DATA_AT(interpreter, address) ((unsigned char) (interpreter->code[*address]))
+#define ADDR_BYTES_LEFT(interpreter, address) (interpreter->code_size - (*address))
+#define ADDR_JUMP(address, offset) (*address) += offset
+
 struct sieve_interpreter {
 	pool_t pool;
 	
@@ -34,9 +41,13 @@ struct sieve_interpreter {
 	const char *code;
 	sieve_size_t code_size;
 	
+	/* Execution status */
 	sieve_size_t pc; 
-	
+	bool test_result;
 	struct sieve_result *result; 
+	
+	/* Execution environment */
+	struct mail *mail;	
 };
 
 struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *binary) 
@@ -63,6 +74,15 @@ void sieve_interpreter_free(struct sieve_interpreter *interpreter)
 	pool_unref(&(interpreter->pool));
 }
 
+/* Accessing runtinme environment */
+
+inline struct mail *sieve_interpreter_get_mail(struct sieve_interpreter *interpreter) 
+{
+	return interpreter->mail;
+}
+
+/* Program counter */
+
 inline void sieve_interpreter_reset(struct sieve_interpreter *interpreter) 
 {
 	interpreter->pc = 0;
@@ -74,48 +94,68 @@ inline sieve_size_t sieve_interpreter_program_counter(struct sieve_interpreter *
 }
 
 inline bool sieve_interpreter_program_jump
-	(struct sieve_interpreter *interpreter)
+	(struct sieve_interpreter *interpreter, bool jump)
 {
 	sieve_size_t pc = sieve_interpreter_program_counter(interpreter);
-	int offset = sieve_interpreter_read_offset(interpreter);
+	int offset;
+	
+	if ( !sieve_interpreter_read_offset(interpreter, &(interpreter->pc), &offset) )
+		return FALSE;
 
-	if ( pc + offset < interpreter->code_size && pc + offset > 0 ) {
-		interpreter->pc = pc + offset;
+	if ( pc + offset <= interpreter->code_size && pc + offset > 0 ) {
+		if ( jump )
+			interpreter->pc = pc + offset;
+		
 		return TRUE;
 	}
 	
 	return FALSE;
 }
 
+inline void sieve_interpreter_set_test_result(struct sieve_interpreter *interpreter, bool result)
+{
+	interpreter->test_result = result;
+}
+
+inline bool sieve_interpreter_get_test_result(struct sieve_interpreter *interpreter)
+{
+	return interpreter->test_result;
+}
 
 /* Literals */
 
-int sieve_interpreter_read_offset(struct sieve_interpreter *interpreter) 
+bool sieve_interpreter_read_offset
+	(struct sieve_interpreter *interpreter, sieve_size_t *address, int *offset) 
 {
-	uint32_t offset = 0;
+	uint32_t offs = 0;
 	
-	if ( CODE_BYTES_LEFT(interpreter) >= 4 ) {
+	if ( ADDR_BYTES_LEFT(interpreter, address) >= 4 ) {
 	  int i; 
 	  
 	  for ( i = 0; i < 4; i++ ) {
-	    offset = (offset << 8) + DATA_AT_PC(interpreter);
-	  	CODE_JUMP(interpreter, 1);
+	    offs = (offs << 8) + ADDR_DATA_AT(interpreter, address);
+	  	ADDR_JUMP(address, 1);
 	  }
+	  
+	  if ( offset != NULL )
+			*offset = (int) offs;
+			
+		return TRUE;
 	}
 	
-	return (int) offset;
+	return FALSE;
 }
 
 bool sieve_interpreter_read_integer
-  (struct sieve_interpreter *interpreter, sieve_size_t *integer) 
+  (struct sieve_interpreter *interpreter, sieve_size_t *address, sieve_size_t *integer) 
 {
   int bits = sizeof(sieve_size_t) * 8;
   *integer = 0;
   
-  while ( (DATA_AT_PC(interpreter) & 0x80) > 0 ) {
-    if ( CODE_BYTES_LEFT(interpreter) > 0 && bits > 0) {
-      *integer |= DATA_AT_PC(interpreter) & 0x7F;
-      CODE_JUMP(interpreter, 1);
+  while ( (ADDR_DATA_AT(interpreter, address) & 0x80) > 0 ) {
+    if ( ADDR_BYTES_LEFT(interpreter, address) > 0 && bits > 0) {
+      *integer |= ADDR_DATA_AT(interpreter, address) & 0x7F;
+      ADDR_JUMP(address, 1);
     
       *integer <<= 7;
       bits -= 7;
@@ -125,69 +165,113 @@ bool sieve_interpreter_read_integer
     }
   }
   
-  *integer |= DATA_AT_PC(interpreter) & 0x7F;
-  CODE_JUMP(interpreter, 1);
+  *integer |= ADDR_DATA_AT(interpreter, address) & 0x7F;
+  ADDR_JUMP(address, 1);
   
   return TRUE;
 }
 
-/* FIXME: add this to lib/str. (cannot use str_c on non-modifyable buffer) */
+/* FIXME: add this to lib/str. */
 static string_t *t_str_const(const void *cdata, size_t size)
 {
-	return buffer_create_const_data(pool_datastack_create(), cdata, size);
+	string_t *result = t_str_new(size);
+	
+	str_append_n(result, cdata, size);
+	
+	return result;
+	//return buffer_create_const_data(pool_datastack_create(), cdata, size);
 }
 
 bool sieve_interpreter_read_string
-  (struct sieve_interpreter *interpreter, string_t **str) 
+  (struct sieve_interpreter *interpreter, sieve_size_t *address, string_t **str) 
 {
   sieve_size_t strlen = 0;
   
-  if ( !sieve_interpreter_read_integer(interpreter, &strlen) ) 
+  if ( !sieve_interpreter_read_integer(interpreter, address, &strlen) ) 
     return FALSE;
       
-  if ( strlen > CODE_BYTES_LEFT(interpreter) ) 
+  if ( strlen > ADDR_BYTES_LEFT(interpreter, address) ) 
     return FALSE;
    
-  *str = t_str_const(&CODE_AT_PC(interpreter), strlen);
-	CODE_JUMP(interpreter, strlen);
+  *str = t_str_const(&ADDR_CODE_AT(interpreter, address), strlen);
+	ADDR_JUMP(address, strlen);
   
   return TRUE;
 }
 
-bool sieve_interpreter_read_stringlist
-  (struct sieve_interpreter *interpreter, struct sieve_coded_stringlist **strlist)
+struct sieve_coded_stringlist *sieve_interpreter_read_stringlist
+  (struct sieve_interpreter *interpreter, sieve_size_t *address, bool single)
 {
-  sieve_size_t pc = interpreter->pc;
-  sieve_size_t end = pc + sieve_interpreter_read_offset(interpreter);
+	struct sieve_coded_stringlist *strlist;
+
+  sieve_size_t pc = *address;
+  sieve_size_t end; 
   sieve_size_t length = 0; 
+ 
+ 	if ( single ) {
+ 		sieve_size_t strlen;
+ 		
+ 		if ( !sieve_interpreter_read_integer(interpreter, address, &strlen) ) 
+    	return FALSE;
+    	
+    end = *address + strlen;
+    length = 1;
+    *address = pc;
+	} else {
+		int end_offset;
+		
+  	if ( !sieve_interpreter_read_offset(interpreter, address, &end_offset) )
+  		return NULL;
   
-  if ( !sieve_interpreter_read_integer(interpreter, &length) ) 
-    return FALSE;
+  	end = pc + end_offset;
+  
+  	if ( !sieve_interpreter_read_integer(interpreter, address, &length) ) 
+    	return NULL;
+  }
+  
+  if ( end > interpreter->code_size ) 
+  		return NULL;
     
-	*strlist = p_new(pool_datastack_create(), struct sieve_coded_stringlist, 1);
-	(*strlist)->interpreter = interpreter;
-	(*strlist)->start_address = pc;
-	(*strlist)->end_address = end;
-	(*strlist)->length = length;
-	(*strlist)->index = 0;
+	strlist = p_new(pool_datastack_create(), struct sieve_coded_stringlist, 1);
+	strlist->interpreter = interpreter;
+	strlist->start_address = *address;
+	strlist->current_offset = *address;
+	strlist->end_address = end;
+	strlist->length = length;
+	strlist->index = 0;
   
-  return TRUE;
+  /* Skip over the string list for now */
+  *address = end;
+  
+  return strlist;
 }
 
-bool sieve_coded_stringlist_read_item(struct sieve_coded_stringlist *strlist, string_t **str) 
+bool sieve_coded_stringlist_next_item(struct sieve_coded_stringlist *strlist, string_t **str) 
 {
+	sieve_size_t address;
   *str = NULL;
   
   if ( strlist->index >= strlist->length ) 
     return TRUE;
-  else if ( sieve_interpreter_read_string(strlist->interpreter, str) ) {
-    strlist->index++;
-    return TRUE;
+  else {
+  	address = strlist->current_offset;
+  	
+  	if ( sieve_interpreter_read_string(strlist->interpreter, &address, str) ) {
+    	strlist->index++;
+    	strlist->current_offset = address;
+    	return TRUE;
+    }
   }  
   
   return FALSE;
 }
 
+void sieve_coded_stringlist_reset(struct sieve_coded_stringlist *strlist) 
+{  
+  strlist->current_offset = strlist->start_address;
+  strlist->index = 0;
+}
+
 /* Opcodes and operands */
 
 static const struct sieve_opcode *sieve_interpreter_read_opcode
@@ -200,21 +284,95 @@ static const struct sieve_opcode *sieve_interpreter_read_opcode
 		CODE_JUMP(interpreter, 1);
 	
 		if ( opcode < SIEVE_OPCODE_EXT_OFFSET ) {
-			return sieve_opcodes[opcode];
+			if ( opcode < sieve_opcode_count )
+				return sieve_opcodes[opcode];
+			else
+				return NULL;
 		} else {
 		  const struct sieve_extension *ext = 
 		  	sieve_binary_get_extension(interpreter->binary, opcode - SIEVE_OPCODE_EXT_OFFSET);
 		  
-		  return &(ext->opcode);	
+		  if ( ext != NULL )
+		  	return &(ext->opcode);	
+		  else
+		  	return NULL;
 		}
 	}		
 	
 	return NULL;
 }
+
+bool sieve_interpreter_read_offset_operand
+	(struct sieve_interpreter *interpreter, int *offset) 
+{
+	return sieve_interpreter_read_offset(interpreter, &(interpreter->pc), offset);
+}
+
+bool sieve_interpreter_read_number_operand
+  (struct sieve_interpreter *interpreter, sieve_size_t *number)
+{ 
+	if ( CODE_AT_PC(interpreter) != SIEVE_OPERAND_NUMBER ) {
+		return FALSE;
+	}
+	CODE_JUMP(interpreter, 1);
+
+	return sieve_interpreter_read_integer(interpreter, &(interpreter->pc), number);
+}
+
+bool sieve_interpreter_read_string_operand
+  (struct sieve_interpreter *interpreter, string_t **str)
+{ 
+	if ( CODE_AT_PC(interpreter) != SIEVE_OPERAND_STRING ) {
+		return FALSE;
+	}
+	CODE_JUMP(interpreter, 1);
+
+	return sieve_interpreter_read_string(interpreter, &(interpreter->pc), str);
+}
+
+struct sieve_coded_stringlist *
+	sieve_interpreter_read_stringlist_operand
+	  (struct sieve_interpreter *interpreter)
+{
+	bool single = FALSE;
+	
+	switch ( CODE_AT_PC(interpreter) ) {
+  case SIEVE_OPERAND_STRING:
+  	single = TRUE;		
+  	break;
+ 	case SIEVE_OPERAND_STRING_LIST:
+ 		single = FALSE;
+ 		break;
+ 	default:
+  	return NULL;
+	}
+	CODE_JUMP(interpreter, 1);
+	
+	return sieve_interpreter_read_stringlist
+	  (interpreter, &(interpreter->pc), single);
+}
+
+/* Stringlist Utility */
+
+bool sieve_stringlist_match
+	(struct sieve_coded_stringlist *key_list, const char *value)
+{
+	string_t *key_item;
+	sieve_coded_stringlist_reset(key_list);
+				
+	/* Match to all key values */
+	key_item = NULL;
+	while ( sieve_coded_stringlist_next_item(key_list, &key_item) && key_item != NULL ) {
+		if ( strncmp(value, str_c(key_item), str_len(key_item)) == 0 )
+			return TRUE;  
+  }
+  
+  return FALSE;
+}
  
 /* Code Dump */
 
-static void sieve_interpreter_dump_operation
+static bool sieve_interpreter_dump_operation
 	(struct sieve_interpreter *interpreter) 
 {
 	const struct sieve_opcode *opcode = sieve_interpreter_read_opcode(interpreter);
@@ -226,20 +384,28 @@ static void sieve_interpreter_dump_operation
 			(void) opcode->dump(interpreter);
 		else
 			printf("<< UNSPECIFIED OPERATION >>\n");
+			
+		return TRUE;
 	}		
+	
+	return FALSE;
 }
 
-void sieve_interpreter_dump_number
+bool sieve_interpreter_dump_number
 	(struct sieve_interpreter *interpreter) 
 {
 	sieve_size_t number = 0;
 	
-	if (sieve_interpreter_read_integer(interpreter, &number) ) {
+	if (sieve_interpreter_read_integer(interpreter, &(interpreter->pc), &number) ) {
 	  printf("NUM: %ld\n", (long) number);		
+	  
+	  return TRUE;
 	}
+	
+	return FALSE;
 }
 
-static void sieve_interpreter_print_string(string_t *str) 
+void sieve_interpreter_print_string(string_t *str) 
 {
 	unsigned int i = 0;
   const unsigned char *sdata = str_data(str);
@@ -261,41 +427,50 @@ static void sieve_interpreter_print_string(string_t *str)
 	  printf("...\n");
 }
 
-void sieve_interpreter_dump_string
+bool sieve_interpreter_dump_string
 	(struct sieve_interpreter *interpreter) 
 {
 	string_t *str; 
 	
-	if ( sieve_interpreter_read_string(interpreter, &str) ) {
+	if ( sieve_interpreter_read_string(interpreter, &(interpreter->pc), &str) ) {
 		sieve_interpreter_print_string(str);   		
+		
+		return TRUE;
   }
+  
+  return FALSE;
 }
 
-void sieve_interpreter_dump_string_list
+bool sieve_interpreter_dump_string_list
 	(struct sieve_interpreter *interpreter) 
 {
 	struct sieve_coded_stringlist *strlist;
 	
-  if ( sieve_interpreter_read_stringlist(interpreter, &strlist) ) {
-  	sieve_size_t pc = interpreter->pc;
+  if ( (strlist=sieve_interpreter_read_stringlist(interpreter, &(interpreter->pc), FALSE)) != NULL ) {
+  	sieve_size_t pc;
 		string_t *stritem;
 		
 		printf("STRLIST [%d] (END %08x)\n", strlist->length, strlist->end_address);
 	  	
-		while ( sieve_coded_stringlist_read_item(strlist, &stritem) && stritem != NULL ) {
+	 	pc = strlist->current_offset;
+		while ( sieve_coded_stringlist_next_item(strlist, &stritem) && stritem != NULL ) {	
 			printf("%08x:      ", pc);
 			sieve_interpreter_print_string(stritem);
-			pc = interpreter->pc;  
+			pc = strlist->current_offset;  
 		}
+		
+		return TRUE;
 	}
+	
+	return FALSE;
 }
 
-void sieve_interpreter_dump_operand
+bool sieve_interpreter_dump_operand
 	(struct sieve_interpreter *interpreter) 
 {
   char opcode = CODE_AT_PC(interpreter);
 	printf("%08x:   ", interpreter->pc);
-	CODE_JUMP(interpreter, 1);
+  CODE_JUMP(interpreter, 1);
   
   if ( opcode < SIEVE_CORE_OPERAND_MASK ) {  	
     switch (opcode) {
@@ -308,16 +483,29 @@ void sieve_interpreter_dump_operand
     case SIEVE_OPERAND_STRING_LIST:
     	sieve_interpreter_dump_string_list(interpreter);
     	break;
+    	
+    default:
+    	return FALSE;
     }
+    
+    return TRUE;
   }  
+  
+  return FALSE;
 }
 
 void sieve_interpreter_dump_code(struct sieve_interpreter *interpreter) 
 {
 	sieve_interpreter_reset(interpreter);
 	
+	interpreter->result = NULL;
+	interpreter->mail = NULL;
+	
 	while ( interpreter->pc < interpreter->code_size ) {
-		sieve_interpreter_dump_operation(interpreter);
+		if ( !sieve_interpreter_dump_operation(interpreter) ) {
+			printf("Binary is corrupt.\n");
+			return;
+		}
 	}
 	
 	printf("%08x: [End of code]\n", interpreter->code_size);	
@@ -333,27 +521,36 @@ bool sieve_interpreter_execute_opcode
 	if ( opcode != NULL ) {
 		if ( opcode->execute != NULL )
 			return opcode->execute(interpreter);
-		
+		else
+			printf("\n");
+			
 		return TRUE;
 	}
 	
 	return FALSE;
 }		
 
-struct sieve_result *sieve_interpreter_run(struct sieve_interpreter *interpreter) 
+struct sieve_result *sieve_interpreter_run
+	(struct sieve_interpreter *interpreter, struct mail *mail) 
 {
 	struct sieve_result *result;
 	sieve_interpreter_reset(interpreter);
 	
 	result = sieve_result_create();
+	interpreter->result = result;
+	interpreter->mail = mail;
 	
 	while ( interpreter->pc < interpreter->code_size ) {
-		printf("%08x:\n", interpreter->pc);
+		printf("%08x: ", interpreter->pc);
 		
-		if ( !sieve_interpreter_execute_opcode(interpreter) )
+		if ( !sieve_interpreter_execute_opcode(interpreter) ) {
+			printf("Execution aborted.\n");
 			return NULL;
+		}
 	}
 	
+	interpreter->result = NULL;
+	
 	return result;
 }
 
diff --git a/src/lib-sieve/sieve-interpreter.h b/src/lib-sieve/sieve-interpreter.h
index 0c7bf2ca4..f022fb96c 100644
--- a/src/lib-sieve/sieve-interpreter.h
+++ b/src/lib-sieve/sieve-interpreter.h
@@ -19,33 +19,57 @@ inline void sieve_interpreter_reset
 inline sieve_size_t sieve_interpreter_program_counter
 	(struct sieve_interpreter *interpreter);
 inline bool sieve_interpreter_program_jump
+	(struct sieve_interpreter *interpreter, bool jump);
+	
+inline void sieve_interpreter_set_test_result
+	(struct sieve_interpreter *interpreter, bool result);
+inline bool sieve_interpreter_get_test_result
 	(struct sieve_interpreter *interpreter);
 
-
-int sieve_interpreter_read_offset(struct sieve_interpreter *interpreter);
+bool sieve_interpreter_read_offset
+	(struct sieve_interpreter *interpreter, sieve_size_t *address, int *offset);
 bool sieve_interpreter_read_integer
-  (struct sieve_interpreter *interpreter, sieve_size_t *integer); 
+  (struct sieve_interpreter *interpreter, sieve_size_t *address, sieve_size_t *integer); 
 bool sieve_interpreter_read_string
-  (struct sieve_interpreter *interpreter, string_t **str);
+  (struct sieve_interpreter *interpreter, sieve_size_t *address, string_t **str);
   
-bool sieve_interpreter_read_stringlist
-  (struct sieve_interpreter *interpreter, struct sieve_coded_stringlist **strlist);
-bool sieve_coded_stringlist_read_item
-	(struct sieve_coded_stringlist *strlist, string_t **str);  
+struct sieve_coded_stringlist *sieve_interpreter_read_stringlist
+  (struct sieve_interpreter *interpreter, sieve_size_t *address, bool single);
+bool sieve_coded_stringlist_next_item(struct sieve_coded_stringlist *strlist, string_t **str);
+void sieve_coded_stringlist_reset(struct sieve_coded_stringlist *strlist);
+
+/* 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
+	(struct sieve_coded_stringlist *key_list, const char *value);
+
+/* Accessing runtime information */
+inline struct mail *sieve_interpreter_get_mail(struct sieve_interpreter *interpreter);
 
 /* Code dump (debugging purposes) */
 
-void sieve_interpreter_dump_number(struct sieve_interpreter *interpreter);
-void sieve_interpreter_dump_string(struct sieve_interpreter *interpreter);
-void sieve_interpreter_dump_string_list(struct sieve_interpreter *interpreter);
-void sieve_interpreter_dump_operand(struct sieve_interpreter *interpreter);
+bool sieve_interpreter_dump_number(struct sieve_interpreter *interpreter);
+bool sieve_interpreter_dump_string(struct sieve_interpreter *interpreter);
+bool sieve_interpreter_dump_string_list(struct sieve_interpreter *interpreter);
+bool sieve_interpreter_dump_operand(struct sieve_interpreter *interpreter);
 
 void sieve_interpreter_dump_code(struct sieve_interpreter *interpreter);
 
 /* Code execute */
 
 bool sieve_interpreter_execute_opcode(struct sieve_interpreter *interpreter); 
-struct sieve_result *sieve_interpreter_run(struct sieve_interpreter *interpreter);
+struct sieve_result *sieve_interpreter_run
+	(struct sieve_interpreter *interpreter, struct mail *mail);
 
 
 #endif
diff --git a/src/lib-sieve/sieve-lexer.c b/src/lib-sieve/sieve-lexer.c
index 804e9d2f3..4b08cc1b4 100644
--- a/src/lib-sieve/sieve-lexer.c
+++ b/src/lib-sieve/sieve-lexer.c
@@ -194,6 +194,7 @@ __inline__ int sieve_lexer_current_line(struct sieve_lexer *lexer) {
  */
 bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer) 
 {
+	int start_line;
 	string_t *str;
 
 	/* Read first character */
@@ -228,6 +229,7 @@ bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer)
 	//        ;; or unless it is followed by a character that isn't a
 	//        ;; slash.)
 	case '/': 
+		start_line = lexer->current_line;
 		sieve_lexer_shift(lexer);
 		
 		if ( sieve_lexer_curchar(lexer) == '*' ) { 
@@ -244,13 +246,13 @@ bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer)
 						return TRUE;
 						
 					} else if ( sieve_lexer_curchar(lexer) == -1 ) {
-						sieve_lexer_error(lexer, "end of file before end of bracket comment ('/* ... */')");
+						sieve_lexer_error(lexer, "end of file before end of bracket comment ('/* ... */') started at line %d", start_line);
 						lexer->token_type = STT_ERROR;
 						return FALSE;
 					}
 
 				} else if ( sieve_lexer_curchar(lexer) == -1 ) {
-					sieve_lexer_error(lexer, "end of file before end of bracket comment ('/* ... */')");
+					sieve_lexer_error(lexer, "end of file before end of bracket comment ('/* ... */') started at line %d", start_line);
 					lexer->token_type = STT_ERROR;
 					return FALSE;
 					
@@ -286,11 +288,18 @@ bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer)
 		
 	/* quoted-string */
 	case '"':
+		start_line = lexer->current_line;
 		sieve_lexer_shift(lexer);
 		str = str_new(lexer->pool, 16);
 		lexer->token_str_value = str;
 		
 		while ( sieve_lexer_curchar(lexer) != '"' ) {
+			if ( sieve_lexer_curchar(lexer) == -1 ) {
+				sieve_lexer_error(lexer, "end of file before end of quoted string started at line %d", start_line);
+				lexer->token_type = STT_ERROR;
+				return FALSE;
+			}
+			
 			if ( sieve_lexer_curchar(lexer) == '\\' ) {
 				sieve_lexer_shift(lexer);
 			}
diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c
index 05d9d902d..76473cda0 100644
--- a/src/lib-sieve/sieve.c
+++ b/src/lib-sieve/sieve.c
@@ -128,18 +128,13 @@ void sieve_dump(struct sieve_binary *binary)
 	sieve_interpreter_free(interpreter);
 }
 	
-bool sieve_execute(struct sieve_binary *binary) 
+bool sieve_execute(struct sieve_binary *binary, struct mail *mail) 
 {
+	struct sieve_interpreter *interpreter = sieve_interpreter_create(binary);			
 	bool result = TRUE;
-	struct sieve_interpreter *interpreter;			
-				
-	printf("Code Dump:\n\n");
-	interpreter = sieve_interpreter_create(binary);
-				
-	sieve_interpreter_dump_code(interpreter);
-				
+							
 	printf("Code Execute:\n\n");
-	if ( sieve_interpreter_run(interpreter) == NULL ) {
+	if ( sieve_interpreter_run(interpreter, mail) == NULL ) {
 		result = FALSE;
 	}
 				
diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h
index 29dff8791..42fab8b1d 100644
--- a/src/lib-sieve/sieve.h
+++ b/src/lib-sieve/sieve.h
@@ -5,6 +5,6 @@
 
 struct sieve_binary *sieve_compile(int fd);
 void sieve_dump(struct sieve_binary *binary);
-bool sieve_execute(struct sieve_binary *binary); 
+bool sieve_execute(struct sieve_binary *binary, struct mail *mail);
 
 #endif
diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c
index 665bfebec..ed849e8a6 100644
--- a/src/lib-sieve/tst-address.c
+++ b/src/lib-sieve/tst-address.c
@@ -9,9 +9,10 @@
 /* Opcodes */
 
 static bool tst_address_opcode_dump(struct sieve_interpreter *interpreter);
+static bool tst_address_opcode_execute(struct sieve_interpreter *interpreter);
 
 const struct sieve_opcode tst_address_opcode = 
-	{ tst_address_opcode_dump, NULL };
+	{ tst_address_opcode_dump, tst_address_opcode_execute };
 
 /* Test registration */
 
@@ -84,9 +85,58 @@ bool tst_address_generate
 
 static bool tst_address_opcode_dump(struct sieve_interpreter *interpreter)
 {
-    printf("ADDRESS\n");
-    sieve_interpreter_dump_operand(interpreter);
-    sieve_interpreter_dump_operand(interpreter);
+	printf("ADDRESS\n");
+	sieve_interpreter_dump_operand(interpreter);
+	sieve_interpreter_dump_operand(interpreter);
 
-    return TRUE;
+	return TRUE;
+}
+
+/* Code execution */
+
+static bool tst_address_opcode_execute(struct sieve_interpreter *interpreter)
+{
+	struct mail *mail = sieve_interpreter_get_mail(interpreter);
+	struct sieve_coded_stringlist *hdr_list;
+	struct sieve_coded_stringlist *key_list;
+	string_t *hdr_item;
+	bool matched;
+	
+	printf("?? ADDRESS\n");
+
+	t_push();
+		
+	/* Read header-list */
+	if ( (hdr_list=sieve_interpreter_read_stringlist_operand(interpreter)) == NULL ) {
+		t_pop();
+		return FALSE;
+	}
+	
+	/* Read key-list */
+	if ( (key_list=sieve_interpreter_read_stringlist_operand(interpreter)) == NULL ) {
+		t_pop();
+		return FALSE;
+	}
+	
+	/* Iterate through all requested headers to match */
+	hdr_item = NULL;
+	matched = FALSE;
+	while ( !matched && sieve_coded_stringlist_next_item(hdr_list, &hdr_item) && hdr_item != NULL ) {
+		const char *const *headers;
+			
+		if ( mail_get_headers_utf8(mail, str_c(hdr_item), &headers) >= 0 ) {	
+			
+			int i;
+			for ( i = 0; !matched && headers[i] != NULL; i++ ) {
+				if ( sieve_stringlist_match(key_list, headers[i]) )
+					matched = TRUE;				
+			} 
+		}
+	}
+	
+	t_pop();
+	
+	sieve_interpreter_set_test_result(interpreter, matched);
+	
+	return TRUE;
 }
diff --git a/src/lib-sieve/tst-size.c b/src/lib-sieve/tst-size.c
index 751c76f45..20f89cd76 100644
--- a/src/lib-sieve/tst-size.c
+++ b/src/lib-sieve/tst-size.c
@@ -11,11 +11,13 @@
 
 static bool tst_size_over_opcode_dump(struct sieve_interpreter *interpreter);
 static bool tst_size_under_opcode_dump(struct sieve_interpreter *interpreter);
+static bool tst_size_over_opcode_execute(struct sieve_interpreter *interpreter);
+static bool tst_size_under_opcode_execute(struct sieve_interpreter *interpreter);
 
 const struct sieve_opcode tst_size_over_opcode = 
-	{ tst_size_over_opcode_dump, NULL };
+	{ tst_size_over_opcode_dump, tst_size_over_opcode_execute };
 const struct sieve_opcode tst_size_under_opcode = 
-	{ tst_size_under_opcode_dump, NULL };
+	{ tst_size_under_opcode_dump, tst_size_under_opcode_execute };
 
 /* Context structures */
 
@@ -147,3 +149,52 @@ static bool tst_size_under_opcode_dump(struct sieve_interpreter *interpreter)
 
     return TRUE;
 }
+
+/* Code execution */
+
+static bool tst_size_get(struct sieve_interpreter *interpreter, sieve_size_t *size) 
+{
+	struct mail *mail = sieve_interpreter_get_mail(interpreter);
+	uoff_t psize;
+
+	if (	mail_get_physical_size(mail, &psize) < 0	)
+		return FALSE;
+
+  *size = psize;
+  
+  return TRUE;
+}
+
+static bool tst_size_over_opcode_execute(struct sieve_interpreter *interpreter)
+{
+	sieve_size_t mail_size, limit;
+	
+	printf("SIZEOVER\n");
+	
+	if ( !sieve_interpreter_read_number_operand(interpreter, &limit) ) 
+		return FALSE;	
+	
+	if ( !tst_size_get(interpreter, &mail_size) )
+		return FALSE;
+	
+	sieve_interpreter_set_test_result(interpreter, (mail_size > limit));
+	
+	return TRUE;
+}
+
+static bool tst_size_under_opcode_execute(struct sieve_interpreter *interpreter)
+{ 
+	sieve_size_t mail_size, limit;
+	
+	printf("SIZEUNDER\n");
+	
+	if ( !sieve_interpreter_read_number_operand(interpreter, &limit) ) 
+		return FALSE;	
+	
+	if ( !tst_size_get(interpreter, &mail_size) )
+		return FALSE;
+	
+	sieve_interpreter_set_test_result(interpreter, (mail_size < limit));
+	
+	return TRUE;
+}
diff --git a/src/sieve-bin/Makefile.am b/src/sieve-bin/Makefile.am
index 2aa0b5243..f00371f1a 100644
--- a/src/sieve-bin/Makefile.am
+++ b/src/sieve-bin/Makefile.am
@@ -16,8 +16,8 @@ plugin_dir = \
 plugins = \
 	$(plugin_dir)/vacation/lib_ext_vacation.a
 
-sievec_LDFLAGS = -export-dynamic
-sieve_test_LDFLAGS = -export-dynamic
+sievec_LDFLAGS = -export-dynamic -Wl,--start-group 
+sieve_test_LDFLAGS = -export-dynamic -Wl,--start-group
 
 libs = \
 	$(top_srcdir)/src/lib-sieve/libsieve.a \
diff --git a/src/sieve-bin/sieve_test.c b/src/sieve-bin/sieve_test.c
index 367609f99..da3cf665f 100644
--- a/src/sieve-bin/sieve_test.c
+++ b/src/sieve-bin/sieve_test.c
@@ -185,22 +185,22 @@ create_mbox_stream(int fd, const char *envelope_sender, bool **first_r)
 	return input;
 }
 
-void mail_test(struct mail *mail)
+void sieve_test(struct sieve_binary *sbin, struct mail *mail)
 {
 	const char *const *headers;
 
 	printf("HEADERS\n");
-    if (mail_get_headers_utf8(mail, "from", &headers) >= 0)
-	{
-		printf("HEADERS FOUND\n");	
+	if (mail_get_headers_utf8(mail, "from", &headers) >= 0) {	
 		int i;
 		for ( i = 0; headers[i] != NULL; i++ ) {
 			printf("HEADER: From: %s\n", headers[i]);
-        } 
+		} 
 	}
+	
+	sieve_execute(sbin, mail);
 }
 
-int main(void)
+int main(int argc, char **argv) 
 {
 	const char *envelope_sender = DEFAULT_ENVELOPE_SENDER;
 	const char *mailbox = "INBOX";
@@ -215,6 +215,8 @@ int main(void)
 	uid_t process_euid;
 	pool_t namespace_pool;
 	bool *input_first;
+	int fd;
+	struct sieve_binary *sbin;
 
 	lib_init();
 	ioloop = io_loop_create();
@@ -224,6 +226,27 @@ int main(void)
 	lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
 	lib_signals_ignore(SIGPIPE, TRUE);
 	lib_signals_ignore(SIGALRM, FALSE);
+		
+	if ( argc < 2 ) {
+		printf( "Usage: sieve_test <filename>\n");
+ 		exit(1);
+ 	}
+  
+  /* Compile sieve script */
+  
+	if ( (fd = open(argv[1], O_RDONLY)) < 0 ) {
+		perror("open()");
+		exit(1);
+	}
+
+	printf("Parsing sieve script '%s'...\n", argv[1]);
+
+	if ( (sbin = sieve_compile(fd)) == NULL ) 
+		exit(1);
+	
+	(void) sieve_dump(sbin);
+
+ 	close(fd);
 
 	/* we're non-root. get our username and possibly our home. */
 	process_euid = geteuid();
@@ -264,7 +287,7 @@ int main(void)
 
 	/* */
 	i_stream_seek(input, 0);
-	mail_test(mail);
+	sieve_test(sbin, mail);
 	//ret = deliver_save(ns, &storage, mailbox, mail, 0, NULL);
 
 	i_stream_unref(&input);
diff --git a/src/sieve-bin/sievec.c b/src/sieve-bin/sievec.c
index a4e01dbb7..583ea07af 100644
--- a/src/sieve-bin/sievec.c
+++ b/src/sieve-bin/sievec.c
@@ -35,7 +35,9 @@ int main(int argc, char **argv) {
 	printf("Parsing sieve script '%s'...\n", argv[1]);
 
 	sbin = sieve_compile(fd);
-	(void) sieve_dump(sbin);
+	
+	if ( sbin != NULL ) 
+		(void) sieve_dump(sbin);
 
  	close(fd);
 }
-- 
GitLab