diff --git a/Makefile.am b/Makefile.am
index 93406a2c16b34417daa5a78c670cf770c46cd142..bcf53d7561bb3755cc21c8442f6336a34bba7457 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -76,6 +76,7 @@ test_cases = \
 	tests/extensions/imap4flags/hasflag.svtest \
 	tests/extensions/imap4flags/errors.svtest \
 	tests/extensions/imap4flags/execute.svtest \
+	tests/extensions/imap4flags/multiscript.svtest \
 	tests/extensions/imap4flags/flagstore.svtest \
 	tests/extensions/body/basic.svtest \
 	tests/extensions/body/raw.svtest \
diff --git a/TODO b/TODO
index 001517603529ff5339073116eb0bb7d62cbce590..7c0433df7ffbe0d876758519220c1d9dafe8c0a7 100644
--- a/TODO
+++ b/TODO
@@ -4,7 +4,6 @@ Current activities:
 	- Implement proper :content "multipart" behavior
 	- Implement proper :content "message/rfc822" behavior
 	- Build test cases for decoding MIME encodings to UTF-8
-* Add multiscript support to the testsuite. 
 * Build a sieve tool to filter an entire existing mailbox through a Sieve 
   script:
 	- Add commandline options to fully customize execution
diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.am
index be1fb1c6a6e9614a4bb03393af71584489b1f360..d722fdab26df0321921ddd0d2ce3710bccbbbc81 100644
--- a/src/testsuite/Makefile.am
+++ b/src/testsuite/Makefile.am
@@ -35,10 +35,10 @@ commands = \
 	cmd-test-mailbox.c \
 	cmd-test-binary.c
 
-
 tests = \
 	tst-test-script-compile.c \
 	tst-test-script-run.c \
+	tst-test-multiscript.c \
 	tst-test-error.c \
 	tst-test-result.c \
 	tst-test-result-execute.c
diff --git a/src/testsuite/ext-testsuite.c b/src/testsuite/ext-testsuite.c
index e6f07318f7eebcb9368f3faa0b67cc5f5720b4a0..42100b5b7456e1f91745a65a0940422556f407ea 100644
--- a/src/testsuite/ext-testsuite.c
+++ b/src/testsuite/ext-testsuite.c
@@ -58,6 +58,7 @@ const struct sieve_operation *testsuite_operations[] = {
 	&test_set_operation,
 	&test_script_compile_operation,
 	&test_script_run_operation,
+	&test_multiscript_operation,
 	&test_error_operation,
 	&test_result_operation,
 	&test_result_execute_operation,
@@ -122,6 +123,7 @@ static bool ext_testsuite_validator_load(struct sieve_validator *valdtr)
 
 	sieve_validator_register_command(valdtr, &tst_test_script_compile);
 	sieve_validator_register_command(valdtr, &tst_test_script_run);
+	sieve_validator_register_command(valdtr, &tst_test_multiscript);
 	sieve_validator_register_command(valdtr, &tst_test_error);
 	sieve_validator_register_command(valdtr, &tst_test_result);	
 	sieve_validator_register_command(valdtr, &tst_test_result_execute);	
diff --git a/src/testsuite/testsuite-common.h b/src/testsuite/testsuite-common.h
index 2d5022be035b65e511b05d5a042dbbbbaa7ad041..398b4b44152c804793c8069431833b084a3bc379 100644
--- a/src/testsuite/testsuite-common.h
+++ b/src/testsuite/testsuite-common.h
@@ -55,6 +55,7 @@ extern const struct sieve_command cmd_test_binary;
 
 extern const struct sieve_command tst_test_script_compile;
 extern const struct sieve_command tst_test_script_run;
+extern const struct sieve_command tst_test_multiscript;
 extern const struct sieve_command tst_test_error;
 extern const struct sieve_command tst_test_result;
 extern const struct sieve_command tst_test_result_execute;
@@ -70,6 +71,7 @@ enum testsuite_operation_code {
 	TESTSUITE_OPERATION_TEST_SET,
 	TESTSUITE_OPERATION_TEST_SCRIPT_COMPILE,
 	TESTSUITE_OPERATION_TEST_SCRIPT_RUN,
+	TESTSUITE_OPERATION_TEST_MULTISCRIPT,
 	TESTSUITE_OPERATION_TEST_ERROR,
 	TESTSUITE_OPERATION_TEST_RESULT,
 	TESTSUITE_OPERATION_TEST_RESULT_EXECUTE,
@@ -89,6 +91,7 @@ extern const struct sieve_operation test_fail_operation;
 extern const struct sieve_operation test_set_operation;
 extern const struct sieve_operation test_script_compile_operation;
 extern const struct sieve_operation test_script_run_operation;
+extern const struct sieve_operation test_multiscript_operation;
 extern const struct sieve_operation test_error_operation;
 extern const struct sieve_operation test_result_operation;
 extern const struct sieve_operation test_result_execute_operation;
diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c
index a12ff4005cd3d61fcaa6552bd4353fcc5900232d..f234d2f991588eb376eba3fa788bf96c2a1d780f 100644
--- a/src/testsuite/testsuite-script.c
+++ b/src/testsuite/testsuite-script.c
@@ -35,13 +35,11 @@ void testsuite_script_deinit(void)
 	}
 }
 
-bool testsuite_script_compile(const char *script_path)
+static struct sieve_binary *_testsuite_script_compile(const char *script_path)
 {
 	struct sieve_binary *sbin;
 	const char *sieve_dir;
 
-	testsuite_log_clear_messages();
-
 	/* Initialize environment */
 	sieve_dir = strrchr(script_path, '/');
 	if ( sieve_dir == NULL )
@@ -53,8 +51,19 @@ bool testsuite_script_compile(const char *script_path)
 	env_put(t_strconcat("SIEVE_DIR=", sieve_dir, "included", NULL));
 	env_put(t_strconcat("SIEVE_GLOBAL_DIR=", sieve_dir, "included-global", NULL));
 	
-
 	if ( (sbin = sieve_compile(script_path, NULL, testsuite_log_ehandler)) == NULL )
+		return NULL;
+
+	return sbin;
+}
+
+bool testsuite_script_compile(const char *script_path)
+{
+	struct sieve_binary *sbin;
+
+	testsuite_log_clear_messages();
+
+	if ( (sbin=_testsuite_script_compile(script_path)) == NULL )
 		return FALSE;
 
 	if ( _testsuite_compiled_script != NULL ) {
@@ -125,3 +134,63 @@ void testsuite_script_set_binary(struct sieve_binary *sbin)
 	sieve_binary_ref(sbin);
 }
 
+/*
+ * Multiscript
+ */
+
+bool testsuite_script_multiscript
+(const struct sieve_runtime_env *renv, ARRAY_TYPE (const_string) *scriptfiles)
+{
+	struct sieve_script_env scriptenv;
+	struct sieve_multiscript *mscript;
+	struct sieve_result *result;
+	const char *const *scripts;
+	unsigned int count, i;
+	bool more = TRUE;
+	int ret;
+
+	testsuite_log_clear_messages();
+
+	/* Compose script execution environment */
+	memset(&scriptenv, 0, sizeof(scriptenv));
+	scriptenv.default_mailbox = "INBOX";
+	scriptenv.namespaces = NULL;
+	scriptenv.username = "user";
+	scriptenv.hostname = "host.example.com";
+	scriptenv.postmaster_address = "postmaster@example.com";
+	scriptenv.smtp_open = NULL;
+	scriptenv.smtp_close = NULL;
+	scriptenv.duplicate_mark = NULL;
+	scriptenv.duplicate_check = NULL;
+	
+	result = testsuite_result_get();
+
+	/* Start execution */
+
+	mscript = sieve_multiscript_start_execute(renv->msgdata, &scriptenv);
+
+	/* Execute scripts before main script */
+
+	scripts = array_get(scriptfiles, &count);
+
+	for ( i = 0; i < count && more; i++ ) {
+		struct sieve_binary *sbin = NULL;
+		const char *script_path = scripts[i];
+		bool final = ( i == count - 1 );
+
+		/* Open */
+	
+		if ( (sbin=_testsuite_script_compile(script_path)) == NULL )
+			break;
+
+		/* Execute */
+
+		more = sieve_multiscript_run(mscript, sbin, testsuite_log_ehandler, final);
+
+		sieve_close(&sbin);
+	}
+
+	ret = sieve_multiscript_finish(&mscript, testsuite_log_ehandler, NULL);
+	
+	return ( ret > 0 );
+}
diff --git a/src/testsuite/testsuite-script.h b/src/testsuite/testsuite-script.h
index 7ce8992d0005e6677d163048b551adea6b5240b3..2c720c2b7e36eb77ac96439b7f4860c81a0c86b3 100644
--- a/src/testsuite/testsuite-script.h
+++ b/src/testsuite/testsuite-script.h
@@ -11,6 +11,8 @@ void testsuite_script_deinit(void);
 
 bool testsuite_script_compile(const char *script_path);
 bool testsuite_script_run(const struct sieve_runtime_env *renv);
+bool testsuite_script_multiscript
+(const struct sieve_runtime_env *renv, ARRAY_TYPE (const_string) *scriptfiles);
 
 struct sieve_binary *testsuite_script_get_binary(void);
 void testsuite_script_set_binary(struct sieve_binary *sbin);
diff --git a/src/testsuite/tst-test-multiscript.c b/src/testsuite/tst-test-multiscript.c
new file mode 100644
index 0000000000000000000000000000000000000000..e013159686d43c3d72f0f0cbe27994ca343b521b
--- /dev/null
+++ b/src/testsuite/tst-test-multiscript.c
@@ -0,0 +1,170 @@
+/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve.h"
+
+#include "testsuite-common.h"
+#include "testsuite-script.h"
+
+/*
+ * Test_multiscript command
+ *
+ * Syntax:   
+ *   test_multiscript <scripts: string-list>
+ */
+
+static bool tst_test_multiscript_validate
+	(struct sieve_validator *validator, struct sieve_command_context *cmd);
+static bool tst_test_multiscript_generate
+	(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx);
+
+const struct sieve_command tst_test_multiscript = { 
+	"test_multiscript", 
+	SCT_TEST, 
+	1, 0, FALSE, FALSE,
+	NULL, NULL,
+	tst_test_multiscript_validate, 
+	tst_test_multiscript_generate, 
+	NULL 
+};
+
+/* 
+ * Operation 
+ */
+
+static bool tst_test_multiscript_operation_dump
+	(const struct sieve_operation *op,
+		const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_test_multiscript_operation_execute
+	(const struct sieve_operation *op, 
+		const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation test_multiscript_operation = { 
+	"TEST_MULTISCRIPT",
+	&testsuite_extension, 
+	TESTSUITE_OPERATION_TEST_MULTISCRIPT,
+	tst_test_multiscript_operation_dump, 
+	tst_test_multiscript_operation_execute 
+};
+
+/* 
+ * Validation 
+ */
+
+static bool tst_test_multiscript_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command_context *tst) 
+{
+	struct sieve_ast_argument *arg = tst->first_positional;
+	
+	if ( !sieve_validate_positional_argument
+		(valdtr, tst, arg, "scripts", 1, SAAT_STRING_LIST) ) {
+		return FALSE;
+	}
+	
+	return sieve_validator_argument_activate(valdtr, tst, arg, FALSE);
+}
+
+/* 
+ * Code generation 
+ */
+
+static inline struct testsuite_generator_context *
+	_get_generator_context(struct sieve_generator *gentr)
+{
+	return (struct testsuite_generator_context *) 
+		sieve_generator_extension_get_context(gentr, &testsuite_extension);
+}
+
+static bool tst_test_multiscript_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command_context *tst)
+{
+	sieve_operation_emit_code(cgenv->sbin, &test_multiscript_operation);
+
+	/* Generate arguments */
+	return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/* 
+ * Code dump
+ */
+ 
+static bool tst_test_multiscript_operation_dump
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+	sieve_code_dumpf(denv, "TEST_MULTISCRIPT:");
+	sieve_code_descend(denv);
+
+	if ( !sieve_opr_stringlist_dump(denv, address, "scripts") ) 
+		return FALSE;
+
+	return TRUE;
+}
+
+/*
+ * Intepretation
+ */
+
+static int tst_test_multiscript_operation_execute
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+	struct sieve_coded_stringlist *scripts_list;
+	string_t *script_name;
+	const char *script_path;
+	ARRAY_TYPE (const_string) scriptfiles;
+	bool result = TRUE;
+
+	/*
+	 * Read operands
+	 */
+
+  if ( (scripts_list=sieve_opr_stringlist_read(renv, address)) == NULL ) {
+		sieve_runtime_trace_error(renv, "invalid scripts operand");
+		return SIEVE_EXEC_BIN_CORRUPT;
+	}
+
+	/*
+	 * Perform operation
+	 */
+
+	sieve_runtime_trace(renv, "TEST MULTISCRIPT");
+
+	t_array_init(&scriptfiles, 16);
+
+	script_path = sieve_script_dirpath(renv->script);
+	if ( script_path == NULL ) 
+		return SIEVE_EXEC_FAILURE;
+
+	script_name = NULL;
+	while ( result && 
+		(result=sieve_coded_stringlist_next_item(scripts_list, &script_name))
+		&& script_name != NULL ) {	
+
+		const char *path = 
+			t_strconcat(script_path, "/", str_c(script_name), NULL);
+
+		/* Attempt script compile */
+		array_append(&scriptfiles, &path, 1);	
+	}
+
+	result = result && testsuite_script_multiscript(renv, &scriptfiles);
+
+	/* Set result */
+	sieve_interpreter_set_test_result(renv->interp, result);
+
+	return SIEVE_EXEC_OK;
+}
+
+
+
+
diff --git a/tests/extensions/imap4flags/multiscript.svtest b/tests/extensions/imap4flags/multiscript.svtest
new file mode 100644
index 0000000000000000000000000000000000000000..0a0418cb1dec445e901fb88e8850521a4cb46e54
--- /dev/null
+++ b/tests/extensions/imap4flags/multiscript.svtest
@@ -0,0 +1,13 @@
+require "vnd.dovecot.testsuite";
+
+test "Segfault Trigger 1" {
+
+	if not test_multiscript [
+		"multiscript/group-spam.sieve", 
+		"multiscript/spam.sieve", 
+		"multiscript/sent-store.sieve"]
+	{
+		test_fail "failed multiscript execution";	
+	}
+}
+
diff --git a/tests/extensions/imap4flags/multiscript/group-spam.sieve b/tests/extensions/imap4flags/multiscript/group-spam.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..700d33de52bd91ed9ed2c95033e220185125040c
--- /dev/null
+++ b/tests/extensions/imap4flags/multiscript/group-spam.sieve
@@ -0,0 +1,14 @@
+require ["fileinto", "variables", "envelope"];
+
+if header :contains "X-Group-Mail" ["Yes", "YES", "1"] {
+  if header :contains "X-Spam-Flag" ["Yes", "YES", "1"] {
+        if envelope :matches :localpart "to" "*" {
+		fileinto "group/${1}/SPAM"; stop;
+	}
+  }
+  if address :is ["To"] "sales@florist.ru" {
+  	fileinto "group/info/Orders";
+  }
+  stop;
+}
+keep;
diff --git a/tests/extensions/imap4flags/multiscript/sent-store.sieve b/tests/extensions/imap4flags/multiscript/sent-store.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..e5e3906df4b577f4b6160ea32ff7999304443e99
--- /dev/null
+++ b/tests/extensions/imap4flags/multiscript/sent-store.sieve
@@ -0,0 +1,7 @@
+require ["imap4flags"];
+
+if header :contains "X-Set-Seen" ["Yes", "YES", "1"] {
+  	setflag "\\Seen";
+}
+
+keep;
diff --git a/tests/extensions/imap4flags/multiscript/spam.sieve b/tests/extensions/imap4flags/multiscript/spam.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..9e1b6c34978cecade76f02677985f6900c74a6b1
--- /dev/null
+++ b/tests/extensions/imap4flags/multiscript/spam.sieve
@@ -0,0 +1,8 @@
+require ["fileinto"];
+
+if header :contains "X-Spam-Flag" ["Yes", "YES", "1"] {
+  fileinto "SPAM";
+}
+keep;
+
+