From 23ce5abaa5821948435bf00a57463567435dc0ce Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sat, 8 Dec 2007 00:08:12 +0100
Subject: [PATCH] First defined an encapsulating script object and implemented
 part of the include extension.

---
 src/lib-sieve/Makefile.am                     |   1 +
 src/lib-sieve/plugins/include/Makefile.am     |   1 +
 src/lib-sieve/plugins/include/cmd-include.c   | 115 +++++++++++++--
 .../plugins/include/ext-include-common.c      | 125 +++++++++++++++++
 .../plugins/include/ext-include-common.h      |  31 ++++-
 src/lib-sieve/plugins/include/ext-include.c   |   7 +-
 src/lib-sieve/plugins/include/include.sieve   |   6 +-
 src/lib-sieve/plugins/include/included1.sieve |   3 +
 src/lib-sieve/plugins/include/included2.sieve |   3 +
 src/lib-sieve/plugins/include/included3.sieve |   1 +
 src/lib-sieve/sieve-ast.c                     |  25 +++-
 src/lib-sieve/sieve-ast.h                     |   9 +-
 src/lib-sieve/sieve-commands.h                |   3 +
 src/lib-sieve/sieve-common.h                  |  11 ++
 src/lib-sieve/sieve-error.c                   |  20 +++
 src/lib-sieve/sieve-error.h                   |  18 +++
 src/lib-sieve/sieve-lexer.c                   |  65 ++++++---
 src/lib-sieve/sieve-lexer.h                   |   7 +-
 src/lib-sieve/sieve-parser.c                  |  50 +++----
 src/lib-sieve/sieve-parser.h                  |   4 +-
 src/lib-sieve/sieve-script.c                  | 131 ++++++++++++++++++
 src/lib-sieve/sieve-script.h                  |  27 ++++
 src/lib-sieve/sieve-validator.c               |  74 ++++++++--
 src/lib-sieve/sieve-validator.h               |  31 +++--
 src/lib-sieve/sieve.c                         |  52 +++----
 src/lib-sieve/sieve.h                         |   4 +-
 26 files changed, 684 insertions(+), 140 deletions(-)
 create mode 100644 src/lib-sieve/plugins/include/ext-include-common.c
 create mode 100644 src/lib-sieve/plugins/include/included1.sieve
 create mode 100644 src/lib-sieve/plugins/include/included2.sieve
 create mode 100644 src/lib-sieve/plugins/include/included3.sieve
 create mode 100644 src/lib-sieve/sieve-script.c
 create mode 100644 src/lib-sieve/sieve-script.h

diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am
index 0ca84586e..3bab6db66 100644
--- a/src/lib-sieve/Makefile.am
+++ b/src/lib-sieve/Makefile.am
@@ -45,6 +45,7 @@ libsieve_la_LIBADD = $(plugins)
 
 libsieve_la_SOURCES = \
 	sieve-lexer.c \
+	sieve-script.c \
 	sieve-ast.c \
 	sieve-binary.c \
 	sieve-parser.c \
diff --git a/src/lib-sieve/plugins/include/Makefile.am b/src/lib-sieve/plugins/include/Makefile.am
index 54e8fd0b5..89e93524b 100644
--- a/src/lib-sieve/plugins/include/Makefile.am
+++ b/src/lib-sieve/plugins/include/Makefile.am
@@ -13,6 +13,7 @@ cmds = \
 
 libsieve_ext_include_la_SOURCES = \
 	$(cmds) \
+	ext-include-common.c \
 	ext-include.c
 
 noinst_HEADERS = \
diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c
index ca09ec5a9..cffd608dc 100644
--- a/src/lib-sieve/plugins/include/cmd-include.c
+++ b/src/lib-sieve/plugins/include/cmd-include.c
@@ -2,6 +2,7 @@
 
 #include "sieve-common.h"
 
+#include "sieve-script.h"
 #include "sieve-code.h"
 #include "sieve-extensions.h"
 #include "sieve-commands.h"
@@ -22,7 +23,11 @@ static bool opc_include_execute
 		const struct sieve_runtime_env *renv, sieve_size_t *address);
 
 static bool cmd_include_registered
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg);
+	(struct sieve_validator *validator, 
+		struct sieve_command_registration *cmd_reg);
+static bool cmd_include_pre_validate
+	(struct sieve_validator *validator ATTR_UNUSED, 
+		struct sieve_command_context *cmd);
 static bool cmd_include_validate
 	(struct sieve_validator *validator, struct sieve_command_context *cmd);
 static bool cmd_include_generate
@@ -41,7 +46,7 @@ const struct sieve_command cmd_include = {
 	SCT_COMMAND, 
 	1, 0, FALSE, FALSE, 
 	cmd_include_registered,
-	NULL,  
+	cmd_include_pre_validate,  
 	cmd_include_validate, 
 	cmd_include_generate, 
 	NULL 
@@ -58,20 +63,20 @@ const struct sieve_opcode include_opcode = {
 	opc_include_execute
 };
 
-/* Tag validation */
+/* Context structures */
 
-static bool cmd_include_validate_location_tag
-	(struct sieve_validator *validator, 
-	struct sieve_ast_argument **arg, 
-	struct sieve_command_context *cmd)
-{
-	/* SKELETON: Self destruct */
-	*arg = sieve_ast_arguments_detach(*arg,1);
-	
-	return TRUE;
-}
+struct cmd_include_context_data {
+	enum { LOCATION_PERSONAL, LOCATION_GLOBAL } location;
+	bool location_assigned;
+	struct sieve_script *script;
+	struct sieve_ast *ast;
+};   
 
-/* Command registration */
+/* Tags */
+
+static bool cmd_include_validate_location_tag
+	(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
+		struct sieve_command_context *cmd);
 
 static const struct sieve_argument include_personal_tag = { 
 	"personal", NULL, 
@@ -85,6 +90,39 @@ static const struct sieve_argument include_global_tag = {
 	NULL, NULL 
 };
 
+/* Tag validation */
+
+static bool cmd_include_validate_location_tag
+(struct sieve_validator *validator,	struct sieve_ast_argument **arg, 
+	struct sieve_command_context *cmd)
+{    
+	struct cmd_include_context_data *ctx_data = 
+		(struct cmd_include_context_data *) cmd->data;
+	
+	if ( ctx_data->location_assigned) {
+		sieve_command_validate_error(validator, cmd, 
+			"cannot use location tags ':personal' and ':global' multiple times "
+			"for the include command");
+		return FALSE;
+	}
+	
+	if ( (*arg)->argument == &include_personal_tag )
+		ctx_data->location = LOCATION_PERSONAL;
+	else if ( (*arg)->argument == &include_global_tag )
+		ctx_data->location = LOCATION_GLOBAL;
+	else
+		return FALSE;
+	
+	ctx_data->location_assigned = TRUE;
+
+	/* Delete this tag (for now) */
+	*arg = sieve_ast_arguments_detach(*arg, 1);
+
+	return TRUE;
+}
+
+/* Command registration */
+
 enum cmd_include_optional {
 	OPT_END,
 	OPT_LOCATION
@@ -103,22 +141,69 @@ static bool cmd_include_registered
 
 /* Command validation */
 
+static bool cmd_include_pre_validate
+	(struct sieve_validator *validator ATTR_UNUSED, 
+		struct sieve_command_context *cmd)
+{
+	struct cmd_include_context_data *ctx_data;
+
+	/* Assign context */
+	ctx_data = p_new(sieve_command_pool(cmd), struct cmd_include_context_data, 1);
+	ctx_data->location = LOCATION_PERSONAL;
+	cmd->data = ctx_data;
+	
+	return TRUE;
+}
+
 static bool cmd_include_validate(struct sieve_validator *validator, 
 	struct sieve_command_context *cmd) 
 { 	
 	struct sieve_ast_argument *arg = cmd->first_positional;
+	struct cmd_include_context_data *ctx_data = 
+		(struct cmd_include_context_data *) cmd->data;
+	const char *script_name, *script_path;
+	struct sieve_script *script;
+	struct sieve_ast *ast;
 
 	if ( !sieve_validate_positional_argument
 		(validator, cmd, arg, "value", 1, SAAT_STRING) ) {
 		return FALSE;
 	}
+	
+	/* Get script path */
+
+	script_name = sieve_ast_argument_strc(arg);
+	
+	/* FIXME: Hardcoded */
+#define HARDCODED_DIR "src/lib-sieve/plugins/include/"
+	if ( ctx_data->location == LOCATION_PERSONAL )
+		script_path = t_strconcat
+  		(HARDCODED_DIR, script_name, ".sieve", NULL);
+	else if ( ctx_data->location == LOCATION_GLOBAL )
+		script_path = t_strconcat
+  		(HARDCODED_DIR, script_name, ".sieve", NULL);
+	else 
+		return FALSE;
+
+	script = sieve_script_create(script_path, script_name);
+
+	/* Validate */
+	if ( !ext_include_validate_include
+		(validator, cmd, script, &ast) ) {
+		sieve_script_unref(&script);
+ 		return FALSE;
+ 	}
+ 	
+ 	sieve_script_unref(&script);
+ 	
+ 	ctx_data->ast = ast;
 	sieve_validator_argument_activate(validator, arg);	
 	
 	return TRUE;
 }
 
 /*
- * Generation
+ * Code Generation
  */
  
 static bool cmd_include_generate
diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c
new file mode 100644
index 000000000..4e6394ffa
--- /dev/null
+++ b/src/lib-sieve/plugins/include/ext-include-common.c
@@ -0,0 +1,125 @@
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-ast.h"
+#include "sieve-commands.h"
+#include "sieve-error.h"
+#include "sieve-validator.h"
+
+#include "ext-include-common.h"
+
+/* Validator context management */
+
+static struct ext_include_main_context *ext_include_create_main_context
+(struct sieve_validator *validator)
+{
+	pool_t pool = sieve_validator_pool(validator);
+	
+	struct ext_include_main_context *ctx = 
+		p_new(pool, struct ext_include_main_context, 1);
+	
+	ctx->validator = validator;
+	ctx->included_scripts = hash_create
+		(pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp);
+	
+	return ctx;
+}
+
+static struct ext_include_validator_context *
+	ext_include_create_validator_context
+(struct sieve_validator *validator, 
+	struct ext_include_validator_context *parent, struct sieve_script *script)
+{	
+	struct ext_include_validator_context *ctx;
+
+	pool_t pool = sieve_validator_pool(validator);
+	ctx = p_new(pool, struct ext_include_validator_context, 1);
+	ctx->parent = parent;
+	ctx->script = script;
+	if ( parent == NULL ) {
+		ctx->nesting_level = 0;
+		ctx->main = ext_include_create_main_context(validator);
+	} else {
+		ctx->nesting_level = parent->nesting_level + 1;
+		ctx->main = parent->main;
+	}
+	
+	return ctx;
+}
+
+inline struct ext_include_validator_context *
+	ext_include_get_validator_context
+(struct sieve_validator *validator)
+{
+	return (struct ext_include_validator_context *)
+		sieve_validator_extension_get_context(validator, ext_include_my_id);
+}
+
+void ext_include_register_validator_context
+(struct sieve_validator *validator, struct sieve_script *script)
+{
+	struct ext_include_validator_context *ctx = 
+		ext_include_get_validator_context(validator);
+	
+	if ( ctx == NULL ) {
+		ctx = ext_include_create_validator_context(validator, NULL, script);
+		
+		sieve_validator_extension_set_context
+			(validator, ext_include_my_id, (void *) ctx);		
+	}
+}
+
+bool ext_include_validate_include
+(struct sieve_validator *validator, struct sieve_command_context *cmd,
+	struct sieve_script *script, struct sieve_ast **ast_r)
+{
+	bool result = TRUE;
+	struct sieve_validator *subvalid; 
+	struct ext_include_validator_context *parent =
+		ext_include_get_validator_context(validator);
+	struct ext_include_validator_context *ctx;
+	struct sieve_error_handler *ehandler = 
+		sieve_validator_get_error_handler(validator);
+	
+	*ast_r = NULL;
+	
+	/* Check for circular include */
+	
+	ctx = parent;
+	while ( ctx != NULL ) {
+		if ( sieve_script_equals(ctx->script, script) ) {
+			sieve_command_validate_error
+				(validator, cmd, "circular include");
+			return FALSE;
+		}
+		
+		ctx = ctx->parent;
+	}
+			
+	/* Parse script */
+	
+	if ( (*ast_r = sieve_parse(script, ehandler)) == NULL ) {
+ 		sieve_command_validate_error
+ 			(validator, cmd, "parse failed for included script '%s'", 
+ 				sieve_script_name(script));
+		return FALSE;
+	}
+	
+	/* Validate script */
+
+	subvalid = sieve_validator_create(*ast_r, ehandler);	
+	ctx = ext_include_create_validator_context(subvalid, parent, script);
+	sieve_validator_extension_set_context(subvalid, ext_include_my_id, ctx);		
+		
+	if ( !sieve_validator_run(subvalid) || sieve_get_errors(ehandler) > 0 ) {
+		sieve_command_validate_error
+			(validator, cmd, "validation failed for included script '%s'", 
+				sieve_script_name(script));
+		sieve_ast_unref(ast_r);
+		result = FALSE;
+	}
+		
+	sieve_validator_free(&subvalid);	
+		
+	return result;
+}
+
diff --git a/src/lib-sieve/plugins/include/ext-include-common.h b/src/lib-sieve/plugins/include/ext-include-common.h
index 7a95aaf9a..f7e89a3fa 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.h
+++ b/src/lib-sieve/plugins/include/ext-include-common.h
@@ -1,6 +1,35 @@
 #ifndef __EXT_INCLUDE_COMMON_H
-#define __EXT_INCLIDE_COMMON_H
+#define __EXT_INCLUDE_COMMON_H
 
+#include "lib.h"
+#include "hash.h"
+
+#include "sieve-common.h"
+
+#define EXT_INCLUDE_MAX_NESTING_LEVEL 10
+
+extern int ext_include_my_id;
 extern const struct sieve_extension include_extension;
 
+struct ext_include_main_context {
+	struct sieve_validator *validator;
+	struct hash_table *included_scripts;
+};
+
+struct ext_include_validator_context {
+	unsigned int nesting_level;
+	struct sieve_script *script;
+	struct ext_include_main_context *main;
+	struct ext_include_validator_context *parent;
+};
+
+inline struct ext_include_validator_context *ext_include_get_validator_context
+	(struct sieve_validator *validator);
+void ext_include_register_validator_context
+	(struct sieve_validator *validator, struct sieve_script *script);
+
+bool ext_include_validate_include
+(struct sieve_validator *validator, struct sieve_command_context *cmd,
+	struct sieve_script *script, struct sieve_ast **ast_r);
+
 #endif /* __EXT_INCLUDE_COMMON_H */
diff --git a/src/lib-sieve/plugins/include/ext-include.c b/src/lib-sieve/plugins/include/ext-include.c
index 5148fe981..6e3b02efb 100644
--- a/src/lib-sieve/plugins/include/ext-include.c
+++ b/src/lib-sieve/plugins/include/ext-include.c
@@ -40,7 +40,7 @@ static const struct sieve_opcode *ext_include_opcodes[] =
 
 /* Extension definitions */
 
-int ext_my_id;
+int ext_include_my_id;
 
 const struct sieve_extension include_extension = { 
 	"include", 
@@ -53,7 +53,7 @@ const struct sieve_extension include_extension = {
 
 static bool ext_include_load(int ext_id)
 {
-	ext_my_id = ext_id;
+	ext_include_my_id = ext_id;
 
 	return TRUE;
 }
@@ -65,6 +65,9 @@ static bool ext_include_validator_load(struct sieve_validator *validator)
 	/* Register new commands */
 	sieve_validator_register_command(validator, &cmd_include);
 	sieve_validator_register_command(validator, &cmd_return);
+	
+	ext_include_register_validator_context(validator,
+		sieve_validator_get_script(validator));
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/plugins/include/include.sieve b/src/lib-sieve/plugins/include/include.sieve
index 17a92222b..294754cc4 100644
--- a/src/lib-sieve/plugins/include/include.sieve
+++ b/src/lib-sieve/plugins/include/include.sieve
@@ -1,5 +1,5 @@
 require "include";
 
-include "frop.sieve";
-include :global "friep.sieve";
-include :personal "frml.sieve";
+include "included1";
+include :global "included2";
+include :personal "included3";
diff --git a/src/lib-sieve/plugins/include/included1.sieve b/src/lib-sieve/plugins/include/included1.sieve
new file mode 100644
index 000000000..41e84c2dd
--- /dev/null
+++ b/src/lib-sieve/plugins/include/included1.sieve
@@ -0,0 +1,3 @@
+require "fileinto";
+
+fileinto "INBOX.frop";
diff --git a/src/lib-sieve/plugins/include/included2.sieve b/src/lib-sieve/plugins/include/included2.sieve
new file mode 100644
index 000000000..178e1d37b
--- /dev/null
+++ b/src/lib-sieve/plugins/include/included2.sieve
@@ -0,0 +1,3 @@
+require "vacation";
+
+vacation "Ik ben er ff niet.";
diff --git a/src/lib-sieve/plugins/include/included3.sieve b/src/lib-sieve/plugins/include/included3.sieve
new file mode 100644
index 000000000..08a6621ed
--- /dev/null
+++ b/src/lib-sieve/plugins/include/included3.sieve
@@ -0,0 +1 @@
+discard
diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c
index 47af4aef0..95a4db158 100644
--- a/src/lib-sieve/sieve-ast.c
+++ b/src/lib-sieve/sieve-ast.c
@@ -4,6 +4,8 @@
 #include "str.h"
 #include "mempool.h"
 
+#include "sieve-script.h"
+
 #include "sieve-ast.h"
 
 /* Very simplistic linked list implementation
@@ -354,14 +356,17 @@ struct sieve_ast_node *sieve_ast_command_create
 }
 
 /* The AST */
-struct sieve_ast *sieve_ast_create(const char *scriptname) {
+struct sieve_ast *sieve_ast_create(struct sieve_script *script) {
 	pool_t pool;
 	struct sieve_ast *ast;
 	
 	pool = pool_alloconly_create("sieve_ast", 4096);	
 	ast = p_new(pool, struct sieve_ast, 1);
 	ast->pool = pool;
-	ast->scriptname = p_strdup(pool, scriptname);
+	ast->refcount = 1;
+	
+	ast->script = script;
+	sieve_script_ref(script);
 	
 	ast->root = sieve_ast_node_create(ast, NULL, SAT_ROOT, 0);
 	
@@ -371,14 +376,20 @@ struct sieve_ast *sieve_ast_create(const char *scriptname) {
 }
 
 void sieve_ast_ref(struct sieve_ast *ast) {
-	pool_ref(ast->pool);
+	ast->refcount++;
 }
 
 void sieve_ast_unref(struct sieve_ast **ast) {
-	if ( ast != NULL && *ast != NULL ) {
-		pool_unref(&((*ast)->pool));
-		*ast = NULL;
-	}
+	i_assert((*ast)->refcount > 0);
+
+	if (--(*ast)->refcount != 0)
+		return;
+	
+	sieve_script_unref(&(*ast)->script);
+		
+	pool_unref(&(*ast)->pool);
+	
+	*ast = NULL;
 }
 
 const char *sieve_ast_type_name(enum sieve_ast_type ast_type) {
diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h
index 0a8f024f1..aeac21da9 100644
--- a/src/lib-sieve/sieve-ast.h
+++ b/src/lib-sieve/sieve-ast.h
@@ -153,9 +153,10 @@ struct sieve_ast_node {
 
 struct sieve_ast {
 	pool_t pool;
+	int refcount;
 	
-	const char *scriptname;
-	
+	struct sieve_script *script;
+		
 	struct sieve_ast_node *root;
 };
 	
@@ -193,7 +194,7 @@ struct sieve_ast_node *sieve_ast_command_create
 	(struct sieve_ast_node *parent, const char *identifier, unsigned int source_line);
 	
 /* sieve_ast */
-struct sieve_ast *sieve_ast_create(const char *scriptname);
+struct sieve_ast *sieve_ast_create(struct sieve_script *script);
 void sieve_ast_ref(struct sieve_ast *ast);
 void sieve_ast_unref(struct sieve_ast **ast);
 
@@ -213,7 +214,7 @@ void sieve_ast_unparse(struct sieve_ast *ast);
 
 /* AST macros */
 #define sieve_ast_root(ast) (ast->root)
-#define sieve_ast_scriptname(ast) (ast->scriptname)
+#define sieve_ast_script(ast) (ast->script)
 #define sieve_ast_pool(ast) (ast->pool)
 
 /* AST node macros */
diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h
index 79255f968..1bfd5bfce 100644
--- a/src/lib-sieve/sieve-commands.h
+++ b/src/lib-sieve/sieve-commands.h
@@ -87,6 +87,9 @@ const char *sieve_command_type_name(const struct sieve_command *command);
 		
 #define sieve_command_validate_error(validator, context, ...) \
 	sieve_validator_error(validator, (context)->ast_node, __VA_ARGS__)
+#define sieve_command_validate_critical(validator, context, ...) \
+	sieve_validator_critical(validator, (context)->ast_node, __VA_ARGS__)
+
 #define sieve_command_pool(context) \
 	sieve_ast_node_pool((context)->ast_node)
 
diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h
index 2d49d79b3..be312ad3a 100644
--- a/src/lib-sieve/sieve-common.h
+++ b/src/lib-sieve/sieve-common.h
@@ -16,6 +16,9 @@ typedef uint64_t sieve_number_t;
  * Predeclarations
  */
 
+/* sieve-error.h */
+struct sieve_error_handler;
+
 /* sieve-ast.h */
 enum sieve_ast_argument_type;
 
@@ -84,4 +87,12 @@ struct sieve_action_exec_env;
 struct sieve_action;
 struct sieve_side_effect;
 
+/* sieve-script.h */
+struct sieve_script;
+
+/* sieve.c */
+struct sieve_ast *sieve_parse
+	(struct sieve_script *script, struct sieve_error_handler *ehandler);
+	
+
 #endif /* __SIEVE_COMMON_H */
diff --git a/src/lib-sieve/sieve-error.c b/src/lib-sieve/sieve-error.c
index 4cfec4fef..f8091cbd6 100644
--- a/src/lib-sieve/sieve-error.c
+++ b/src/lib-sieve/sieve-error.c
@@ -12,6 +12,10 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#define CRITICAL_MSG \
+	"internal error occurred: refer to server log for more information."
+#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
+
 /* This should be moved to a sieve-errors-private.h when the need for other 
  * types of (externally defined) error handlers arises.
  */
@@ -76,6 +80,22 @@ void sieve_vinfo
 		ehandler->vinfo(ehandler, location, fmt, args);
 }
 
+void sieve_vcritical
+	(struct sieve_error_handler *ehandler, const char *location, 
+		const char *fmt, va_list args)
+{
+	char str[256];
+	struct tm *tm; 
+	
+	tm = localtime(&ioloop_time);
+	
+	i_error("sieve: %s: %s", location, t_strdup_vprintf(fmt, args));
+	
+	sieve_error(ehandler, location, "%s", 
+		strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ? 
+			str : CRITICAL_MSG );	
+}
+
 unsigned int sieve_get_errors(struct sieve_error_handler *ehandler) {
 	return ehandler->errors;
 }
diff --git a/src/lib-sieve/sieve-error.h b/src/lib-sieve/sieve-error.h
index 2a095abcf..37ab8d23e 100644
--- a/src/lib-sieve/sieve-error.h
+++ b/src/lib-sieve/sieve-error.h
@@ -20,6 +20,9 @@ void sieve_vwarning
 void sieve_vinfo
 	(struct sieve_error_handler *ehandler, const char *location, 
 		const char *fmt, va_list args); 
+void sieve_vcritical
+	(struct sieve_error_handler *ehandler, const char *location, 
+		const char *fmt, va_list args); 
 
 inline static void sieve_error
 (struct sieve_error_handler *ehandler, const char *location, 
@@ -28,6 +31,9 @@ inline static void sieve_warning
 (struct sieve_error_handler *ehandler, const char *location, 
 	const char *fmt, ...) ATTR_FORMAT(3, 4);
 inline static void sieve_info
+(struct sieve_error_handler *ehandler, const char *location, 
+	const char *fmt, ...) ATTR_FORMAT(3, 4);
+inline static void sieve_critical
 (struct sieve_error_handler *ehandler, const char *location, 
 	const char *fmt, ...) ATTR_FORMAT(3, 4);
 
@@ -67,6 +73,18 @@ inline static void sieve_info
 	va_end(args);
 }
 
+inline static void sieve_critical
+(struct sieve_error_handler *ehandler, const char *location, 
+	const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	
+	T_FRAME(sieve_vcritical(ehandler, location, fmt, args));
+	
+	va_end(args);
+}
+
 void sieve_error_handler_accept_infolog
 	(struct sieve_error_handler *ehandler, bool enable);
 void sieve_error_handler_copy_masterlog
diff --git a/src/lib-sieve/sieve-lexer.c b/src/lib-sieve/sieve-lexer.c
index c0e1e6614..f6e87ac23 100644
--- a/src/lib-sieve/sieve-lexer.c
+++ b/src/lib-sieve/sieve-lexer.c
@@ -1,17 +1,19 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-
 #include "lib.h"
 #include "compat.h"
 #include "str.h"
 #include "istream.h"
 
-#include "sieve-lexer.h"
 #include "sieve-error.h"
+#include "sieve-script.h"
+
+#include "sieve-lexer.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
 
 #define IS_DIGIT(c) ( c >= '0' && c <= '9' )
 #define DIGIT_VAL(c) ( c - '0' )
@@ -20,7 +22,8 @@
 
 struct sieve_lexer {
 	pool_t pool;
-	const char *scriptname;
+
+	struct sieve_script *script;
 	struct istream *input;
 		
 	int current_line;
@@ -42,7 +45,6 @@ inline static void sieve_lexer_error
 inline static void sieve_lexer_warning
 	(struct sieve_lexer *lexer, const char *fmt, ...) ATTR_FORMAT(2, 3);
 
-
 inline static void sieve_lexer_error
 (struct sieve_lexer *lexer, const char *fmt, ...)
 {
@@ -50,7 +52,8 @@ inline static void sieve_lexer_error
 	va_start(args, fmt);
 
 	T_FRAME(sieve_verror(lexer->ehandler, 
-		t_strdup_printf("%s:%d", lexer->scriptname, lexer->current_line),
+		t_strdup_printf("%s:%d", sieve_script_name(lexer->script), 
+			lexer->current_line),
 		fmt, args));
 		
 	va_end(args);
@@ -63,22 +66,33 @@ inline static void sieve_lexer_warning
 	va_start(args, fmt);
 
 	T_FRAME(sieve_vwarning(lexer->ehandler, 
-		t_strdup_printf("%s:%d", lexer->scriptname, lexer->current_line),
+		t_strdup_printf("%s:%d", sieve_script_name(lexer->script), 
+			lexer->current_line),
 		fmt, args));
 		
 	va_end(args);
 }
 
 struct sieve_lexer *sieve_lexer_create
-(struct istream *stream, const char *scriptname, 
-	struct sieve_error_handler *ehandler) 
+(struct sieve_script *script, struct sieve_error_handler *ehandler) 
 {
-	pool_t pool = pool_alloconly_create("sieve_lexer", 1024);	
-	struct sieve_lexer *lexer = p_new(pool, struct sieve_lexer, 1);
-
+	pool_t pool;
+	struct sieve_lexer *lexer;
+	struct istream *stream;
+	
+	stream = sieve_script_open(script, ehandler);
+	if ( stream == NULL )
+		return NULL;
+	
+	pool = pool_alloconly_create("sieve_lexer", 1024);	
+	lexer = p_new(pool, struct sieve_lexer, 1);
 	lexer->pool = pool;
-	lexer->scriptname = p_strdup(pool, scriptname);
+	
 	lexer->input = stream;
+	i_stream_ref(lexer->input);
+	
+	lexer->script = script;
+	sieve_script_ref(script);
 	
 	lexer->buffer = NULL;
 	lexer->buffer_size = 0;
@@ -94,11 +108,20 @@ struct sieve_lexer *sieve_lexer_create
 	return lexer;
 }
 
-void sieve_lexer_free(struct sieve_lexer *lexer ATTR_UNUSED) {
-	pool_unref(&(lexer->pool)); /* This frees any allocated string value as well */
+void sieve_lexer_free(struct sieve_lexer **lexer) 
+{	
+	i_stream_unref(&(*lexer)->input);
+
+	sieve_script_close((*lexer)->script);
+	sieve_script_unref(&(*lexer)->script);
+
+	pool_unref(&(*lexer)->pool); 
+
+	*lexer = NULL;
 }
 
-static void sieve_lexer_shift(struct sieve_lexer *lexer) {
+static void sieve_lexer_shift(struct sieve_lexer *lexer) 
+{
 	if ( lexer->buffer != NULL && lexer->buffer[lexer->buffer_pos] == '\n' ) 
 		lexer->current_line++;	
 	
diff --git a/src/lib-sieve/sieve-lexer.h b/src/lib-sieve/sieve-lexer.h
index aa092d6d7..e33b19577 100644
--- a/src/lib-sieve/sieve-lexer.h
+++ b/src/lib-sieve/sieve-lexer.h
@@ -3,7 +3,7 @@
 
 #include "lib.h"
 
-#include "sieve-error.h"
+#include "sieve-common.h"
 
 enum sieve_token_type {
 	STT_NONE,
@@ -41,9 +41,8 @@ struct sieve_token;
 struct sieve_lexer;
 
 struct sieve_lexer *sieve_lexer_create
-	(struct istream *stream, const char *scriptname,  
-		struct sieve_error_handler *ehandler);
-void sieve_lexer_free(struct sieve_lexer *lexer);
+	(struct sieve_script *script, struct sieve_error_handler *ehandler);
+void sieve_lexer_free(struct sieve_lexer **lexer);
 
 bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer);
 bool sieve_lexer_skip_token(struct sieve_lexer *lexer);
diff --git a/src/lib-sieve/sieve-parser.c b/src/lib-sieve/sieve-parser.c
index f7df7a480..0b06796b4 100644
--- a/src/lib-sieve/sieve-parser.c
+++ b/src/lib-sieve/sieve-parser.c
@@ -4,6 +4,7 @@
 #include "istream.h"
 #include "failures.h"
 
+#include "sieve-script.h"
 #include "sieve-lexer.h"
 #include "sieve-parser.h"
 #include "sieve-error.h"
@@ -15,18 +16,15 @@
 
 struct sieve_parser {
 	pool_t pool;
-	const char *scriptname;
-	
-	struct istream *input;
 	
+	struct sieve_script *script;
+		
 	struct sieve_error_handler *ehandler;
 	
 	struct sieve_lexer *lexer;
 	struct sieve_ast *ast;
 };
 
-#define SIEVE_READ_BLOCK_SIZE (1024*8)
-
 inline static void sieve_parser_error
 	(struct sieve_parser *parser, const char *fmt, ...) ATTR_FORMAT(2, 3);
 inline static void sieve_parser_warning
@@ -42,7 +40,8 @@ inline static void sieve_parser_error
 	if ( sieve_lexer_current_token(parser->lexer) != STT_ERROR )  
 	{
 		T_FRAME(sieve_verror(parser->ehandler, 
-			t_strdup_printf("%s:%d", parser->scriptname,
+			t_strdup_printf("%s:%d", 
+			sieve_script_name(parser->script),
 			sieve_lexer_current_line(parser->lexer)),
 			fmt, args)); 
 	}
@@ -57,7 +56,8 @@ inline static void sieve_parser_warning
 	va_start(args, fmt);
 
 	T_FRAME(sieve_vwarning(parser->ehandler, 
-		t_strdup_printf("%s:%d", parser->scriptname,
+		t_strdup_printf("%s:%d", 
+		sieve_script_name(parser->script),
 		sieve_lexer_current_line(parser->lexer)),
 		fmt, args));
 		
@@ -69,23 +69,23 @@ static bool sieve_parser_recover
 	(struct sieve_parser *parser, enum sieve_token_type end_token);
 
 struct sieve_parser *sieve_parser_create
-(int fd, const char *scriptname, struct sieve_error_handler *ehandler)
+(struct sieve_script *script, struct sieve_error_handler *ehandler)
 {
 	struct sieve_parser *parser;
-	struct istream *stream;
+	struct sieve_lexer *lexer;
+	
+	lexer = sieve_lexer_create(script, ehandler);
   
-	stream = i_stream_create_fd
-		(fd, SIEVE_READ_BLOCK_SIZE, TRUE);
-
-	if ( stream != NULL ) {
+	if ( lexer != NULL ) {
 		pool_t pool = pool_alloconly_create("sieve_parser", 4096);	
 
 		parser = p_new(pool, struct sieve_parser, 1);
 		parser->pool = pool;
-		parser->scriptname = p_strdup(pool, scriptname);
-		parser->input = stream;
 		
-		parser->lexer = sieve_lexer_create(stream, scriptname, ehandler);
+		parser->script = script;
+		sieve_script_ref(script);
+				
+		parser->lexer = lexer;
 		parser->ast = NULL;
 		
 		parser->ehandler = ehandler;
@@ -96,17 +96,17 @@ struct sieve_parser *sieve_parser_create
 	return NULL;
 }
 
-void sieve_parser_free(struct sieve_parser *parser)
+void sieve_parser_free(struct sieve_parser **parser)
 {
-	if (parser->input != NULL ) 
-		i_stream_unref(&parser->input);
+	if ((*parser)->ast != NULL)	  
+		sieve_ast_unref(&(*parser)->ast);
 
-	if (parser->ast != NULL)	  
-		sieve_ast_unref(&parser->ast);
+	sieve_lexer_free(&(*parser)->lexer);
+	sieve_script_unref(&(*parser)->script);
 
-	sieve_lexer_free(parser->lexer);
-
-	pool_unref(&(parser->pool));
+	pool_unref(&(*parser)->pool);
+	
+	*parser = NULL;
 }
 
 /* arguments = *argument [test / test-list]
@@ -380,7 +380,7 @@ bool sieve_parser_run
 		sieve_ast_unref(&parser->ast);
 	
 	*ast = NULL;
-	parser->ast = sieve_ast_create(parser->scriptname);
+	parser->ast = sieve_ast_create(parser->script);
 
 	/* Scan first token */
 	sieve_lexer_skip_token(parser->lexer);
diff --git a/src/lib-sieve/sieve-parser.h b/src/lib-sieve/sieve-parser.h
index b0c81e281..b06854f78 100644
--- a/src/lib-sieve/sieve-parser.h
+++ b/src/lib-sieve/sieve-parser.h
@@ -8,8 +8,8 @@
 struct sieve_parser;
 
 struct sieve_parser *sieve_parser_create
-	(int fd, const char *scriptname, struct sieve_error_handler *ehandler);
-void sieve_parser_free(struct sieve_parser *parser);
+	(struct sieve_script *script, struct sieve_error_handler *ehandler);
+void sieve_parser_free(struct sieve_parser **parser);
 bool sieve_parser_run(struct sieve_parser *parser, struct sieve_ast **ast);
 
 #endif /* __SIEVE_PARSER_H */
diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c
new file mode 100644
index 000000000..55ba5fa39
--- /dev/null
+++ b/src/lib-sieve/sieve-script.c
@@ -0,0 +1,131 @@
+#include "lib.h"
+#include "compat.h"
+#include "istream.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+
+#include "sieve-script.h"
+
+#define SIEVE_READ_BLOCK_SIZE (1024*8)
+
+struct sieve_script {
+	pool_t pool;
+	unsigned int refcount;
+	
+	/* Parameters */
+	const char *name;
+	const char *path;	
+
+	/* Stream */
+	int fd; /* FIXME: we could use the stream's autoclose facility */
+	struct istream *stream;
+};
+
+/* Script object */
+
+struct sieve_script *sieve_script_create
+	(const char *path, const char *name)
+{
+	pool_t pool;
+	struct sieve_script *script;
+	
+	pool = pool_alloconly_create("sieve_script", 1024);
+	script = p_new(pool, struct sieve_script, 1);
+	script->pool = pool;
+	script->refcount = 1;
+	
+	script->path = p_strdup(pool, path);
+		
+	if ( name == NULL || *name == '\0' ) {
+		const char *filename, *ext;
+	
+		T_FRAME(
+			/* Extract filename from path */
+			filename = strrchr(path, '/');
+			if ( filename == NULL )
+				filename = path;
+			else
+				filename++;
+
+			/* Extract the script name */
+		  ext = strrchr(filename, '.');
+		  if ( ext == NULL || ext == filename || strncmp(ext,".sieve",6) != 0 )
+				script->name = p_strdup(pool, filename);
+		  else
+		  	script->name = p_strdup_until(pool, filename, ext);
+		);
+	} else {
+		script->name = p_strdup(pool, name);
+	}
+	
+	return script;
+}
+
+void sieve_script_ref(struct sieve_script *script)
+{
+	script->refcount++;
+}
+
+void sieve_script_unref(struct sieve_script **script)
+{
+	i_assert((*script)->refcount > 0);
+
+	if (--(*script)->refcount != 0)
+		return;
+
+	if ( (*script)->stream != NULL )
+		i_stream_destroy(&(*script)->stream);
+
+	pool_unref(&(*script)->pool);
+
+	*script = NULL;
+}
+
+/* Stream manageement */
+
+struct istream *sieve_script_open(struct sieve_script *script, 
+	struct sieve_error_handler *ehandler)
+{
+	int fd;
+
+	if ( (fd=open(script->path, O_RDONLY)) < 0 ) {
+		if ( errno == ENOENT )
+			sieve_error(ehandler, script->path, "sieve script '%s' does not exist",
+				script->name);
+		else 
+			sieve_critical(ehandler, script->path, "failed to open sieve script: %m");
+		return NULL;
+	}	
+
+	script->stream = i_stream_create_fd(fd, SIEVE_READ_BLOCK_SIZE, TRUE);
+	
+	return script->stream;
+}
+
+void sieve_script_close(struct sieve_script *script)
+{
+	i_stream_destroy(&script->stream);
+}
+
+/* Comparison */
+
+bool sieve_script_equals
+(struct sieve_script *script1, struct sieve_script *script2)
+{
+	return ( strcmp(script1->path, script2->path) == 0 );
+}
+
+/* Inline accessors */
+
+inline const char *sieve_script_name(struct sieve_script *script)
+{
+	return script->name;
+}
+
+inline const char *sieve_script_path(struct sieve_script *script)
+{
+	return script->path;
+}
+
+
diff --git a/src/lib-sieve/sieve-script.h b/src/lib-sieve/sieve-script.h
new file mode 100644
index 000000000..1266d1757
--- /dev/null
+++ b/src/lib-sieve/sieve-script.h
@@ -0,0 +1,27 @@
+#ifndef __SIEVE_SCRIPT_H
+#define __SIEVE_SCRIPT_H
+
+#include "sieve-common.h"
+
+/* FIXME: This conflicts with the managesieve implementation */
+
+struct sieve_script;
+
+struct sieve_script *sieve_script_create(const char *path, const char *name);
+
+void sieve_script_ref(struct sieve_script *script);
+void sieve_script_unref(struct sieve_script **script);
+
+/* Stream manageement */
+
+struct istream *sieve_script_open(struct sieve_script *script, 
+	struct sieve_error_handler *ehandler);
+void sieve_script_close(struct sieve_script *script);
+
+bool sieve_script_equals
+(struct sieve_script *script1, struct sieve_script *script2);
+
+inline const char *sieve_script_name(struct sieve_script *script);
+inline const char *sieve_script_path(struct sieve_script *script);
+
+#endif /* __SIEVE_SCRIPT_H */
diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c
index 370cdfb49..6ca58191e 100644
--- a/src/lib-sieve/sieve-validator.c
+++ b/src/lib-sieve/sieve-validator.c
@@ -2,6 +2,7 @@
 #include "mempool.h"
 #include "hash.h"
 
+#include "sieve-script.h"
 #include "sieve-ast.h"
 #include "sieve-commands.h"
 #include "sieve-commands-private.h"
@@ -15,15 +16,16 @@
 
 struct sieve_validator {
 	pool_t pool;
-	const char *scriptname;
+	
 	struct sieve_ast *ast;
+	struct sieve_script *script;
 	
 	struct sieve_error_handler *ehandler;
 	
 	/* Registries */
 	struct hash_table *commands;
 	
-	ARRAY_DEFINE(ext_contexts, void);
+	ARRAY_DEFINE(ext_contexts, void *);
 };
 
 /* Predeclared statics */
@@ -41,7 +43,7 @@ void sieve_validator_warning
 	va_start(args, fmt);
 	
 	T_FRAME(sieve_vwarning(validator->ehandler, 
-		t_strdup_printf("%s:%d", sieve_ast_scriptname(validator->ast),
+		t_strdup_printf("%s:%d", sieve_script_name(validator->script),
 			sieve_ast_node_line(node)), fmt, args)); 
 	
 	va_end(args);
@@ -55,12 +57,28 @@ void sieve_validator_error
 	va_start(args, fmt);
 	
 	T_FRAME(sieve_verror(validator->ehandler, 
-		t_strdup_printf("%s:%d", sieve_ast_scriptname(validator->ast),
+		t_strdup_printf("%s:%d", sieve_script_name(validator->script),
+		sieve_ast_node_line(node)), fmt, args)); 
+	
+	va_end(args);
+}
+
+void sieve_validator_critical
+(struct sieve_validator *validator, struct sieve_ast_node *node, 
+	const char *fmt, ...) 
+{
+	va_list args;
+	va_start(args, fmt);
+	
+	T_FRAME(sieve_vcritical(validator->ehandler, 
+		t_strdup_printf("%s:%d", sieve_script_name(validator->script),
 		sieve_ast_node_line(node)), fmt, args)); 
 	
 	va_end(args);
 }
 
+/* Validator object */
+
 struct sieve_validator *sieve_validator_create
 	(struct sieve_ast *ast, struct sieve_error_handler *ehandler) 
 {
@@ -71,9 +89,11 @@ struct sieve_validator *sieve_validator_create
 	pool = pool_alloconly_create("sieve_validator", 4096);	
 	validator = p_new(pool, struct sieve_validator, 1);
 	validator->pool = pool;
+	
 	validator->ehandler = ehandler;
 	
 	validator->ast = ast;	
+	validator->script = sieve_ast_script(ast);
 	sieve_ast_ref(ast);
 
 	/* Setup storage for extension contexts */		
@@ -97,12 +117,14 @@ struct sieve_validator *sieve_validator_create
 	return validator;
 }
 
-void sieve_validator_free(struct sieve_validator *validator) 
+void sieve_validator_free(struct sieve_validator **validator) 
 {
-	hash_destroy(&validator->commands);
-	
-	sieve_ast_unref(&validator->ast);
-	pool_unref(&(validator->pool));
+	hash_destroy(&(*validator)->commands);
+	sieve_ast_unref(&(*validator)->ast);
+
+	pool_unref(&(*validator)->pool);
+
+	*validator = NULL;
 }
 
 inline pool_t sieve_validator_pool(struct sieve_validator *validator)
@@ -110,6 +132,24 @@ inline pool_t sieve_validator_pool(struct sieve_validator *validator)
 	return validator->pool;
 }
 
+inline struct sieve_error_handler *sieve_validator_get_error_handler
+	(struct sieve_validator *validator)
+{
+	return validator->ehandler;
+}
+
+inline struct sieve_ast *sieve_validator_get_ast
+	(struct sieve_validator *validator)
+{
+	return validator->ast;
+}
+
+inline struct sieve_script *sieve_validator_get_script
+	(struct sieve_validator *validator)
+{
+	return validator->script;
+}
+
 /* Command registry */
 
 struct sieve_tag_registration;
@@ -342,17 +382,23 @@ int sieve_validator_extension_load
 	return ext_id;
 }
 
-inline void sieve_validator_extension_set_context(struct sieve_validator *validator, int ext_id, void *context)
+inline void sieve_validator_extension_set_context
+	(struct sieve_validator *validator, int ext_id, void *context)
 {
-	array_idx_set(&validator->ext_contexts, (unsigned int) ext_id, context);	
+	array_idx_set(&validator->ext_contexts, (unsigned int) ext_id, &context);	
 }
 
-inline const void *sieve_validator_extension_get_context(struct sieve_validator *validator, int ext_id) 
+inline const void *sieve_validator_extension_get_context
+	(struct sieve_validator *validator, int ext_id) 
 {
-	if  ( ext_id < 0 || ext_id > (int) array_count(&validator->ext_contexts) )
+	void * const *ctx;
+
+	if  ( ext_id < 0 || ext_id >= (int) array_count(&validator->ext_contexts) )
 		return NULL;
 	
-	return array_idx(&validator->ext_contexts, (unsigned int) ext_id);		
+	ctx = array_idx(&validator->ext_contexts, (unsigned int) ext_id);		
+
+	return *ctx;
 }
 
 /* Argument Validation API */
diff --git a/src/lib-sieve/sieve-validator.h b/src/lib-sieve/sieve-validator.h
index 78f789f55..dbeb70989 100644
--- a/src/lib-sieve/sieve-validator.h
+++ b/src/lib-sieve/sieve-validator.h
@@ -9,10 +9,18 @@
 struct sieve_validator;
 struct sieve_command_registration;
 
-struct sieve_validator *sieve_validator_create(struct sieve_ast *ast, struct sieve_error_handler *ehandler);
-void sieve_validator_free(struct sieve_validator *validator);
+struct sieve_validator *sieve_validator_create
+	(struct sieve_ast *ast, struct sieve_error_handler *ehandler);
+void sieve_validator_free(struct sieve_validator **validator);
 inline pool_t sieve_validator_pool(struct sieve_validator *validator);
 
+inline struct sieve_error_handler *sieve_validator_get_error_handler
+	(struct sieve_validator *validator);
+inline struct sieve_ast *sieve_validator_get_ast
+	(struct sieve_validator *validator);
+inline struct sieve_script *sieve_validator_get_script
+	(struct sieve_validator *validator);
+
 bool sieve_validator_run(struct sieve_validator *validator);
 
 void sieve_validator_warning
@@ -21,6 +29,9 @@ void sieve_validator_warning
 void sieve_validator_error
 	(struct sieve_validator *validator, struct sieve_ast_node *node, 
 		const char *fmt, ...) ATTR_FORMAT(3, 4);
+void sieve_validator_critical
+	(struct sieve_validator *validator, struct sieve_ast_node *node, 
+		const char *fmt, ...) ATTR_FORMAT(3, 4);
 
 /* Command Programmers Interface */
 
@@ -33,13 +44,9 @@ void sieve_validator_register_external_tag
 
 /* Argument registration */
 void sieve_validator_register_tag
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, 
-	const struct sieve_argument *argument, int id_code);
-
-/* Special test arguments */
-void sieve_validator_link_match_type_tags
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,
-		unsigned int id_code); 
+	(struct sieve_validator *validator, 
+		struct sieve_command_registration *cmd_reg, 
+		const struct sieve_argument *argument, int id_code);
 
 /* Argument validation */
 
@@ -58,7 +65,9 @@ bool sieve_validate_tag_parameter
 int sieve_validator_extension_load
 	(struct sieve_validator *validator, struct sieve_command_context *cmd, 
 		const char *ext_name); 
-inline void sieve_validator_extension_set_context(struct sieve_validator *validator, int ext_id, void *context);
-inline const void *sieve_validator_extension_get_context(struct sieve_validator *validator, int ext_id);
+inline void sieve_validator_extension_set_context
+	(struct sieve_validator *validator, int ext_id, void *context);
+inline const void *sieve_validator_extension_get_context
+	(struct sieve_validator *validator, int ext_id);
 
 #endif /* __SIEVE_VALIDATOR_H */
diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c
index 8e9c560fd..ebbbd89d0 100644
--- a/src/lib-sieve/sieve.c
+++ b/src/lib-sieve/sieve.c
@@ -7,6 +7,7 @@
 
 #include "sieve-extensions.h"
 
+#include "sieve-script.h"
 #include "sieve-ast.h"
 #include "sieve-binary.h"
 #include "sieve-result.h"
@@ -18,6 +19,7 @@
 #include "sieve-code-dumper.h"
 
 #include "sieve.h"
+#include "sieve-common.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -36,14 +38,14 @@ void sieve_deinit(void)
 	sieve_extensions_deinit();
 }
 
-static struct sieve_ast *sieve_parse
-	(int fd, const char *scriptname, struct sieve_error_handler *ehandler)
+struct sieve_ast *sieve_parse
+	(struct sieve_script *script, struct sieve_error_handler *ehandler)
 {
 	struct sieve_parser *parser;
 	struct sieve_ast *ast;
 	
 	/* Parse */
-	parser = sieve_parser_create(fd, scriptname, ehandler);
+	parser = sieve_parser_create(script, ehandler);
 
  	if ( !sieve_parser_run(parser, &ast) || sieve_get_errors(ehandler) > 0 ) {
  		if ( ast != NULL )
@@ -53,7 +55,7 @@ static struct sieve_ast *sieve_parse
  	} else 
 		sieve_ast_ref(ast);
 	
-	sieve_parser_free(parser); 	
+	sieve_parser_free(&parser); 	
 	
 	return ast;
 }
@@ -66,7 +68,7 @@ static bool sieve_validate(struct sieve_ast *ast, struct sieve_error_handler *eh
 	if ( !sieve_validator_run(validator) || sieve_get_errors(ehandler) > 0 ) 
 		result = FALSE;
 	
-	sieve_validator_free(validator);	
+	sieve_validator_free(&validator);	
 		
 	return result;
 }
@@ -83,29 +85,29 @@ static struct sieve_binary *sieve_generate(struct sieve_ast *ast)
 	return result;
 }
 
-static struct sieve_binary *sieve_compile_fd
-(int fd, const char *scriptname, struct sieve_error_handler *ehandler) 
+static struct sieve_binary *sieve_compile_script
+(struct sieve_script *script, struct sieve_error_handler *ehandler) 
 {
-	struct sieve_binary *result;
 	struct sieve_ast *ast;
+	struct sieve_binary *sbin;		
   	
 	/* Parse */
-	if ( (ast = sieve_parse(fd, scriptname, ehandler)) == NULL ) {
- 		sieve_error(ehandler, scriptname, "failed to parse script");
+	if ( (ast = sieve_parse(script, ehandler)) == NULL ) {
+ 		sieve_error(ehandler, sieve_script_name(script), "parse failed");
 		return NULL;
 	}
 
 	/* Validate */
 	if ( !sieve_validate(ast, ehandler) ) {
-		sieve_error(ehandler, scriptname, "failed to validate script");
+		sieve_error(ehandler, sieve_script_name(script), "validation failed");
 		
  		sieve_ast_unref(&ast);
  		return NULL;
  	}
  	
 	/* Generate */
-	if ( (result=sieve_generate(ast)) == NULL ) {
-		sieve_error(ehandler, scriptname, "failed to generate script");
+	if ( (sbin=sieve_generate(ast)) == NULL ) {
+		sieve_error(ehandler, sieve_script_name(script), "code generation failed");
 		
 		sieve_ast_unref(&ast);
 		return NULL;
@@ -114,31 +116,21 @@ static struct sieve_binary *sieve_compile_fd
 	/* Cleanup */
 	sieve_ast_unref(&ast);
 
-	return result;
+	return sbin;
 }
 
 struct sieve_binary *sieve_compile
-	(const char *scriptpath, struct sieve_error_handler *ehandler)
+	(const char *script_path, struct sieve_error_handler *ehandler)
 {
-	int sfd;
-	const char *scriptname;
+	struct sieve_script *script;
 	struct sieve_binary *sbin;
+
+	script = sieve_script_create(script_path, NULL);
 	
+	sbin = sieve_compile_script(script, ehandler);
 	
-	if ( (sfd = open(scriptpath, O_RDONLY)) < 0 ) {
-		sieve_error(ehandler, scriptpath, "failed to open sieve script: %m");
-		return NULL;
-	}
-	
-	scriptname = strrchr(scriptpath, '/');
-	if ( scriptname == NULL )	
-		scriptname = scriptpath;
-	else
-		scriptname++;
+	sieve_script_unref(&script);
 	
-	sbin = sieve_compile_fd(sfd, scriptname, ehandler);
-		
-	close(sfd);
 	return sbin;
 }
 
diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h
index aa9840e0e..3647ee7ad 100644
--- a/src/lib-sieve/sieve.h
+++ b/src/lib-sieve/sieve.h
@@ -24,13 +24,15 @@ struct sieve_message_data {
 };
 
 struct sieve_script_env {
+	/* Mail-related */
 	const char *inbox;
 	struct mail_namespace *namespaces;
 	
+	/* System-related */
 	const char *username;
 	const char *hostname;
 	const char *postmaster_address;
-	
+		
 	/* Callbacks */
 	
 	/* Interface for sending mail */
-- 
GitLab