From 691db805aca90bbc53c3d02424fc040b8639f6df Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Fri, 14 May 2010 13:08:14 +0200
Subject: [PATCH] Restructured binary implementation and added lineinfo debug
 blocks to the binary.

---
 src/lib-sieve-tool/sieve-tool.c               |    2 +-
 src/lib-sieve/Makefile.am                     |    4 +
 src/lib-sieve/cmd-discard.c                   |    4 +-
 src/lib-sieve/cmd-if.c                        |   16 +-
 src/lib-sieve/cmd-keep.c                      |    4 +-
 src/lib-sieve/cmd-redirect.c                  |    4 +-
 src/lib-sieve/cmd-stop.c                      |    2 +-
 src/lib-sieve/ext-envelope.c                  |    2 +-
 src/lib-sieve/ext-fileinto.c                  |    4 +-
 src/lib-sieve/ext-reject.c                    |    6 +-
 src/lib-sieve/plugins/body/tst-body.c         |    8 +-
 src/lib-sieve/plugins/copy/ext-copy.c         |    2 +-
 src/lib-sieve/plugins/date/tst-date.c         |   10 +-
 src/lib-sieve/plugins/enotify/cmd-notify.c    |   12 +-
 .../enotify/tst-notify-method-capability.c    |    2 +-
 .../plugins/enotify/tst-valid-notify-method.c |    2 +-
 .../plugins/environment/tst-environment.c     |    2 +-
 src/lib-sieve/plugins/imap4flags/cmd-flag.c   |   10 +-
 src/lib-sieve/plugins/imap4flags/tag-flags.c  |    8 +-
 .../plugins/imap4flags/tst-hasflag.c          |    2 +-
 src/lib-sieve/plugins/include/cmd-global.c    |   19 +-
 src/lib-sieve/plugins/include/cmd-include.c   |   16 +-
 src/lib-sieve/plugins/include/cmd-return.c    |    2 +-
 .../plugins/include/ext-include-binary.c      |   97 +-
 .../plugins/include/ext-include-binary.h      |    5 +-
 .../plugins/include/ext-include-common.c      |   78 +-
 .../plugins/include/ext-include-variables.c   |   28 +-
 .../plugins/include/ext-include-variables.h   |    7 +-
 .../plugins/mailbox/tag-mailbox-create.c      |    2 +-
 .../plugins/mailbox/tst-mailboxexists.c       |    2 +-
 src/lib-sieve/plugins/notify/cmd-denotify.c   |   12 +-
 src/lib-sieve/plugins/notify/cmd-notify.c     |   12 +-
 .../plugins/spamvirustest/tst-spamvirustest.c |    4 +-
 src/lib-sieve/plugins/vacation/cmd-vacation.c |   14 +-
 src/lib-sieve/plugins/variables/cmd-set.c     |   12 +-
 .../variables/ext-variables-arguments.c       |    4 +-
 .../plugins/variables/ext-variables-common.c  |   12 +-
 .../plugins/variables/ext-variables-dump.c    |    6 +-
 .../variables/ext-variables-modifiers.h       |    4 +-
 .../variables/ext-variables-namespaces.c      |   11 +-
 .../variables/ext-variables-namespaces.h      |    5 -
 .../variables/ext-variables-operands.c        |   38 +-
 .../plugins/variables/sieve-ext-variables.h   |    6 +-
 src/lib-sieve/plugins/variables/tst-string.c  |    2 +-
 src/lib-sieve/sieve-actions.h                 |    4 +-
 src/lib-sieve/sieve-address-parts.c           |   10 +-
 src/lib-sieve/sieve-address-parts.h           |    4 +-
 src/lib-sieve/sieve-binary-code.c             |  386 ++++
 src/lib-sieve/sieve-binary-debug.c            |  256 +++
 src/lib-sieve/sieve-binary-dumper.c           |   46 +-
 src/lib-sieve/sieve-binary-dumper.h           |    2 +-
 src/lib-sieve/sieve-binary-file.c             |  839 +++++++++
 src/lib-sieve/sieve-binary-private.h          |  208 ++
 src/lib-sieve/sieve-binary.c                  | 1666 ++---------------
 src/lib-sieve/sieve-binary.h                  |  127 +-
 src/lib-sieve/sieve-code-dumper.c             |   74 +-
 src/lib-sieve/sieve-code.c                    |  135 +-
 src/lib-sieve/sieve-code.h                    |   33 +-
 src/lib-sieve/sieve-commands.c                |   11 +-
 src/lib-sieve/sieve-common.h                  |    3 +
 src/lib-sieve/sieve-comparators.c             |    2 +-
 src/lib-sieve/sieve-comparators.h             |    4 +-
 src/lib-sieve/sieve-dump.h                    |    1 +
 src/lib-sieve/sieve-generator.c               |  157 +-
 src/lib-sieve/sieve-generator.h               |   14 +-
 src/lib-sieve/sieve-interpreter.c             |   59 +-
 src/lib-sieve/sieve-interpreter.h             |    3 +
 src/lib-sieve/sieve-match-types.c             |    2 +-
 src/lib-sieve/sieve-match-types.h             |    4 +-
 src/lib-sieve/sieve-match.c                   |    8 +-
 src/lib-sieve/sieve-objects.c                 |   18 +-
 src/lib-sieve/sieve-objects.h                 |    4 +-
 src/lib-sieve/sieve.c                         |    6 +-
 src/lib-sieve/sieve.h                         |    2 +-
 src/lib-sieve/tst-address.c                   |    2 +-
 src/lib-sieve/tst-allof.c                     |    8 +-
 src/lib-sieve/tst-anyof.c                     |    8 +-
 src/lib-sieve/tst-exists.c                    |    2 +-
 src/lib-sieve/tst-header.c                    |    2 +-
 src/lib-sieve/tst-size.c                      |    4 +-
 src/lib-sieve/tst-truefalse.c                 |    8 +-
 src/sieve-tools/debug/cmd-debug-print.c       |    2 +-
 src/testsuite/cmd-test-binary.c               |    4 +-
 src/testsuite/cmd-test-config.c               |    2 +-
 src/testsuite/cmd-test-fail.c                 |    6 +-
 src/testsuite/cmd-test-mailbox.c              |    2 +-
 src/testsuite/cmd-test-message.c              |   12 +-
 src/testsuite/cmd-test-result-print.c         |    2 +-
 src/testsuite/cmd-test-result-reset.c         |    2 +-
 src/testsuite/cmd-test-set.c                  |    4 +-
 src/testsuite/cmd-test.c                      |    4 +-
 src/testsuite/testsuite-common.c              |    4 +-
 src/testsuite/testsuite-objects.c             |   24 +-
 src/testsuite/testsuite-objects.h             |    4 +-
 src/testsuite/testsuite-substitutions.c       |   22 +-
 src/testsuite/tst-test-error.c                |    2 +-
 src/testsuite/tst-test-multiscript.c          |    2 +-
 src/testsuite/tst-test-result-execute.c       |    2 +-
 src/testsuite/tst-test-result.c               |    2 +-
 src/testsuite/tst-test-script-compile.c       |    2 +-
 src/testsuite/tst-test-script-run.c           |   10 +-
 101 files changed, 2642 insertions(+), 2098 deletions(-)
 create mode 100644 src/lib-sieve/sieve-binary-code.c
 create mode 100644 src/lib-sieve/sieve-binary-debug.c
 create mode 100644 src/lib-sieve/sieve-binary-file.c
 create mode 100644 src/lib-sieve/sieve-binary-private.h

diff --git a/src/lib-sieve-tool/sieve-tool.c b/src/lib-sieve-tool/sieve-tool.c
index 6b69ec7f7..edb3e40f0 100644
--- a/src/lib-sieve-tool/sieve-tool.c
+++ b/src/lib-sieve-tool/sieve-tool.c
@@ -244,7 +244,7 @@ void sieve_tool_dump_binary_to(struct sieve_binary *sbin, const char *filename)
 	}
 	
 	if ( dumpstream != NULL ) {
-		(void) sieve_dump(sbin, dumpstream);
+		(void) sieve_dump(sbin, dumpstream, FALSE);
 		o_stream_destroy(&dumpstream);
 	} else {
 		i_fatal("Failed to create stream for sieve code dump.");
diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am
index e29cb36fc..9ad44e736 100644
--- a/src/lib-sieve/Makefile.am
+++ b/src/lib-sieve/Makefile.am
@@ -76,6 +76,9 @@ libdovecot_sieve_la_SOURCES = \
 	sieve-script.c \
 	sieve-ast.c \
 	sieve-binary.c \
+	sieve-binary-file.c \
+	sieve-binary-code.c \
+	sieve-binary-debug.c \
 	sieve-parser.c \
 	sieve-address.c \
 	sieve-validator.c \
@@ -116,6 +119,7 @@ headers = \
 	sieve-script-private.h \
 	sieve-ast.h \
 	sieve-binary.h \
+	sieve-binary-private.h \
 	sieve-parser.h \
 	sieve-address.h \
 	sieve-validator.h \
diff --git a/src/lib-sieve/cmd-discard.c b/src/lib-sieve/cmd-discard.c
index 340c437ba..f62fd0f4e 100644
--- a/src/lib-sieve/cmd-discard.c
+++ b/src/lib-sieve/cmd-discard.c
@@ -79,10 +79,10 @@ const struct sieve_action_def act_discard = {
 static bool cmd_discard_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	sieve_operation_emit(cgenv->sbin, NULL, &cmd_discard_operation);
+	sieve_operation_emit(cgenv->sblock, NULL, &cmd_discard_operation);
 
 	/* Emit line number */
-  sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(cmd));
+	sieve_code_source_line_emit(cgenv->sblock, sieve_command_source_line(cmd));
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/cmd-if.c b/src/lib-sieve/cmd-if.c
index 9e6343f66..2d2aaae61 100644
--- a/src/lib-sieve/cmd-if.c
+++ b/src/lib-sieve/cmd-if.c
@@ -149,7 +149,7 @@ static bool cmd_elsif_validate
  */
 
 static void cmd_if_resolve_exit_jumps
-(struct sieve_binary *sbin, struct cmd_if_context_data *cmd_data) 
+(struct sieve_binary_block *sblock, struct cmd_if_context_data *cmd_data) 
 {
 	struct cmd_if_context_data *if_ctx = cmd_data->previous;
 	
@@ -158,7 +158,7 @@ static void cmd_if_resolve_exit_jumps
 	 */
 	while ( if_ctx != NULL ) {
 		if ( if_ctx->jump_generated ) 
-			sieve_binary_resolve_offset(sbin, if_ctx->exit_jump);
+			sieve_binary_resolve_offset(sblock, if_ctx->exit_jump);
 		if_ctx = if_ctx->previous;	
 	}
 }
@@ -166,14 +166,14 @@ static void cmd_if_resolve_exit_jumps
 static bool cmd_if_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
 {
-	struct sieve_binary *sbin = cgenv->sbin;
+	struct sieve_binary_block *sblock = cgenv->sblock;
 	struct cmd_if_context_data *cmd_data = 
 		(struct cmd_if_context_data *) cmd->data;
 	struct sieve_ast_node *test;
 	struct sieve_jumplist jmplist;
 	
 	/* Prepare jumplist */
-	sieve_jumplist_init_temp(&jmplist, sbin);
+	sieve_jumplist_init_temp(&jmplist, sblock);
 	
 	/* Generate test condition */
 	test = sieve_ast_test_first(cmd->ast_node);
@@ -192,13 +192,13 @@ static bool cmd_if_generate
 		 * anyway. 
 		 */
 		if ( !sieve_command_block_exits_unconditionally(cmd) ) {
-			sieve_operation_emit(sbin, NULL, &sieve_jmp_operation);
-			cmd_data->exit_jump = sieve_binary_emit_offset(sbin, 0);
+			sieve_operation_emit(sblock, NULL, &sieve_jmp_operation);
+			cmd_data->exit_jump = sieve_binary_emit_offset(sblock, 0);
 			cmd_data->jump_generated = TRUE;
 		}
 	} else {
 		/* Yes, Resolve previous exit jumps to this point */
-		cmd_if_resolve_exit_jumps(sbin, cmd_data);
+		cmd_if_resolve_exit_jumps(sblock, cmd_data);
 	}
 	
 	/* Case false ... (subsequent elsif/else commands might generate more) */
@@ -218,7 +218,7 @@ static bool cmd_else_generate
 		return FALSE;
 		
 	/* } End: resolve all exit blocks */	
-	cmd_if_resolve_exit_jumps(cgenv->sbin, cmd_data);
+	cmd_if_resolve_exit_jumps(cgenv->sblock, cmd_data);
 		
 	return TRUE;
 }
diff --git a/src/lib-sieve/cmd-keep.c b/src/lib-sieve/cmd-keep.c
index 60cba5fb3..c228a2943 100644
--- a/src/lib-sieve/cmd-keep.c
+++ b/src/lib-sieve/cmd-keep.c
@@ -57,10 +57,10 @@ static bool cmd_keep_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
 	/* Emit opcode */
-	sieve_operation_emit(cgenv->sbin, NULL, &cmd_keep_operation);
+	sieve_operation_emit(cgenv->sblock, NULL, &cmd_keep_operation);
 
 	/* Emit line number */
-	sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(cmd));
+	sieve_code_source_line_emit(cgenv->sblock, sieve_command_source_line(cmd));
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index 1c2b39146..0be56bffe 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -160,10 +160,10 @@ static bool cmd_redirect_validate
 static bool cmd_redirect_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	sieve_operation_emit(cgenv->sbin, NULL,  &cmd_redirect_operation);
+	sieve_operation_emit(cgenv->sblock, NULL,  &cmd_redirect_operation);
 
 	/* Emit line number */
-	sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(cmd));
+	sieve_code_source_line_emit(cgenv->sblock, sieve_command_source_line(cmd));
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
diff --git a/src/lib-sieve/cmd-stop.c b/src/lib-sieve/cmd-stop.c
index 054a11552..eaae8affe 100644
--- a/src/lib-sieve/cmd-stop.c
+++ b/src/lib-sieve/cmd-stop.c
@@ -65,7 +65,7 @@ static bool cmd_stop_generate
 (const struct sieve_codegen_env *cgenv, 
 	struct sieve_command *cmd ATTR_UNUSED) 
 {
-	sieve_operation_emit(cgenv->sbin, NULL, &cmd_stop_operation);
+	sieve_operation_emit(cgenv->sblock, NULL, &cmd_stop_operation);
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index aa0ed7fa3..2c294226b 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -288,7 +288,7 @@ static bool tst_envelope_validate
 static bool tst_envelope_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	(void)sieve_operation_emit(cgenv->sbin, cmd->ext, &envelope_operation);
+	(void)sieve_operation_emit(cgenv->sblock, cmd->ext, &envelope_operation);
 
 	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c
index 6bbc126a7..1d963ab13 100644
--- a/src/lib-sieve/ext-fileinto.c
+++ b/src/lib-sieve/ext-fileinto.c
@@ -123,10 +123,10 @@ static bool cmd_fileinto_validate
 static bool cmd_fileinto_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &fileinto_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &fileinto_operation);
 
 	/* Emit line number */
-	sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(cmd));
+	sieve_code_source_line_emit(cgenv->sblock, sieve_command_source_line(cmd));
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index 2486acd7b..3b8f70f02 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -231,12 +231,12 @@ static bool cmd_reject_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
 	if ( sieve_command_is(cmd, reject_command) )
-		sieve_operation_emit(cgenv->sbin, cmd->ext, &reject_operation);
+		sieve_operation_emit(cgenv->sblock, cmd->ext, &reject_operation);
 	else
-		sieve_operation_emit(cgenv->sbin, cmd->ext, &ereject_operation);
+		sieve_operation_emit(cgenv->sblock, cmd->ext, &ereject_operation);
 
 	/* Emit line number */
-	sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(cmd));
+	sieve_code_source_line_emit(cgenv->sblock, sieve_command_source_line(cmd));
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
diff --git a/src/lib-sieve/plugins/body/tst-body.c b/src/lib-sieve/plugins/body/tst-body.c
index 3a9e058c6..91f4ba386 100644
--- a/src/lib-sieve/plugins/body/tst-body.c
+++ b/src/lib-sieve/plugins/body/tst-body.c
@@ -230,7 +230,7 @@ static bool tst_body_validate
 static bool tst_body_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	(void)sieve_operation_emit(cgenv->sbin, cmd->ext, &body_operation);
+	(void)sieve_operation_emit(cgenv->sblock, cmd->ext, &body_operation);
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
@@ -243,7 +243,7 @@ static bool tag_body_transform_generate
 	enum tst_body_transform transform =	
 		(enum tst_body_transform) arg->argument->data;
 	
-	sieve_binary_emit_byte(cgenv->sbin, transform);
+	sieve_binary_emit_byte(cgenv->sblock, transform);
 	sieve_generate_argument_parameters(cgenv, cmd, arg); 
 			
 	return TRUE;
@@ -272,7 +272,7 @@ static bool ext_body_operation_dump
 		case SIEVE_MATCH_OPT_END:
 			break;
 		case OPT_BODY_TRANSFORM:
-			if ( !sieve_binary_read_byte(denv->sbin, address, &transform) )
+			if ( !sieve_binary_read_byte(denv->sblock, address, &transform) )
 				return FALSE;
 			
 			switch ( transform ) {
@@ -339,7 +339,7 @@ static int ext_body_operation_execute
 		case SIEVE_MATCH_OPT_END: 
 			break;
 		case OPT_BODY_TRANSFORM:
-			if ( !sieve_binary_read_byte(renv->sbin, address, &transform) ||
+			if ( !sieve_binary_read_byte(renv->sblock, address, &transform) ||
 				transform > TST_BODY_TRANSFORM_TEXT ) {
 				sieve_runtime_trace_error(renv, "invalid body transform type");
 				return SIEVE_EXEC_BIN_CORRUPT;
diff --git a/src/lib-sieve/plugins/copy/ext-copy.c b/src/lib-sieve/plugins/copy/ext-copy.c
index 33d5422b3..510f63441 100644
--- a/src/lib-sieve/plugins/copy/ext-copy.c
+++ b/src/lib-sieve/plugins/copy/ext-copy.c
@@ -144,7 +144,7 @@ static bool tag_copy_generate
 	}
 
 	sieve_opr_side_effect_emit
-		(cgenv->sbin, sieve_argument_ext(arg), &copy_side_effect);
+		(cgenv->sblock, sieve_argument_ext(arg), &copy_side_effect);
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/plugins/date/tst-date.c b/src/lib-sieve/plugins/date/tst-date.c
index 30d519034..53e6d67e7 100644
--- a/src/lib-sieve/plugins/date/tst-date.c
+++ b/src/lib-sieve/plugins/date/tst-date.c
@@ -298,9 +298,9 @@ static bool tst_date_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst) 
 {
 	if ( sieve_command_is(tst, date_test) )
-		sieve_operation_emit(cgenv->sbin, tst->ext, &date_operation);
+		sieve_operation_emit(cgenv->sblock, tst->ext, &date_operation);
 	else if ( sieve_command_is(tst, currentdate_test) )
-		sieve_operation_emit(cgenv->sbin, tst->ext, &currentdate_operation);
+		sieve_operation_emit(cgenv->sblock, tst->ext, &currentdate_operation);
 	else
 		i_unreached();
 
@@ -313,7 +313,7 @@ static bool tag_zone_generate
     struct sieve_command *cmd)
 {
 	if ( arg->parameters == NULL ) {
-		sieve_opr_omitted_emit(cgenv->sbin);
+		sieve_opr_omitted_emit(cgenv->sblock);
 		return TRUE;
 	}
 
@@ -343,7 +343,7 @@ static bool tst_date_operation_dump
 		case SIEVE_MATCH_OPT_END:
 			break;
 		case OPT_DATE_ZONE:
-			if ( !sieve_operand_read(denv->sbin, address, &operand) ) {
+			if ( !sieve_operand_read(denv->sblock, address, &operand) ) {
 				sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
 				return FALSE;
 			}				
@@ -405,7 +405,7 @@ static int tst_date_operation_execute
 		case SIEVE_MATCH_OPT_END:
 			break;
 		case OPT_DATE_ZONE:
-			if ( !sieve_operand_read(renv->sbin, address, &operand) ) {
+			if ( !sieve_operand_read(renv->sblock, address, &operand) ) {
 				sieve_runtime_trace_error(renv, "invalid operand");
 				return SIEVE_EXEC_BIN_CORRUPT;
 			}
diff --git a/src/lib-sieve/plugins/enotify/cmd-notify.c b/src/lib-sieve/plugins/enotify/cmd-notify.c
index 9bddb87ab..4e9500e68 100644
--- a/src/lib-sieve/plugins/enotify/cmd-notify.c
+++ b/src/lib-sieve/plugins/enotify/cmd-notify.c
@@ -334,10 +334,10 @@ static bool cmd_notify_validate
 static bool cmd_notify_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {		 
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &notify_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &notify_operation);
 
 	/* Emit source line */
-	sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(cmd));
+	sieve_code_source_line_emit(cgenv->sblock, sieve_command_source_line(cmd));
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
@@ -360,11 +360,11 @@ static bool cmd_notify_operation_dump
 		return FALSE;
 
 	/* Dump optional operands */
-	if ( sieve_operand_optional_present(denv->sbin, address) ) {
+	if ( sieve_operand_optional_present(denv->sblock, address) ) {
 		while ( opt_code != 0 ) {
 			sieve_code_mark(denv);
 			
-			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) 
+			if ( !sieve_operand_optional_read(denv->sblock, address, &opt_code) ) 
 				return FALSE;
 
 			switch ( opt_code ) {
@@ -427,9 +427,9 @@ static int cmd_notify_operation_execute
 	}
 	
 	/* Optional operands */	
-	if ( sieve_operand_optional_present(renv->sbin, address) ) {
+	if ( sieve_operand_optional_present(renv->sblock, address) ) {
 		while ( opt_code != 0 ) {
-			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) {
+			if ( !sieve_operand_optional_read(renv->sblock, address, &opt_code) ) {
 				sieve_runtime_trace_error(renv, "invalid optional operand");
 				return SIEVE_EXEC_BIN_CORRUPT;
 			}
diff --git a/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c b/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
index 751dc6b4f..7d87b017b 100644
--- a/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+++ b/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
@@ -141,7 +141,7 @@ static bool tst_notifymc_generate
 	(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
 	sieve_operation_emit
-		(cgenv->sbin, cmd->ext, &notify_method_capability_operation);
+		(cgenv->sblock, cmd->ext, &notify_method_capability_operation);
 
  	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
diff --git a/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c b/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
index 2595d86dc..db45c68f3 100644
--- a/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+++ b/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
@@ -77,7 +77,7 @@ static bool tst_vnotifym_validate
 static bool tst_vnotifym_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &valid_notify_method_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &valid_notify_method_operation);
 
  	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
diff --git a/src/lib-sieve/plugins/environment/tst-environment.c b/src/lib-sieve/plugins/environment/tst-environment.c
index 80a4d1d0d..110f053e1 100644
--- a/src/lib-sieve/plugins/environment/tst-environment.c
+++ b/src/lib-sieve/plugins/environment/tst-environment.c
@@ -116,7 +116,7 @@ static bool tst_environment_validate
 static bool tst_environment_generate
 	(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &tst_environment_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &tst_environment_operation);
 
  	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
diff --git a/src/lib-sieve/plugins/imap4flags/cmd-flag.c b/src/lib-sieve/plugins/imap4flags/cmd-flag.c
index a1c6fd964..8cc194a0d 100644
--- a/src/lib-sieve/plugins/imap4flags/cmd-flag.c
+++ b/src/lib-sieve/plugins/imap4flags/cmd-flag.c
@@ -123,11 +123,11 @@ static bool cmd_flag_generate
 {
 	/* Emit operation */
 	if ( sieve_command_is(cmd, cmd_setflag) ) 
-		sieve_operation_emit(cgenv->sbin, cmd->ext, &setflag_operation);
+		sieve_operation_emit(cgenv->sblock, cmd->ext, &setflag_operation);
 	else if ( sieve_command_is(cmd, cmd_addflag) ) 
-		sieve_operation_emit(cgenv->sbin, cmd->ext, &addflag_operation);
+		sieve_operation_emit(cgenv->sblock, cmd->ext, &addflag_operation);
 	else if ( sieve_command_is(cmd, cmd_removeflag) ) 
-		sieve_operation_emit(cgenv->sbin, cmd->ext, &removeflag_operation);
+		sieve_operation_emit(cgenv->sblock, cmd->ext, &removeflag_operation);
 
 	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
@@ -149,7 +149,7 @@ bool cmd_flag_operation_dump
 	sieve_code_descend(denv);
 	
 	sieve_code_mark(denv);
-	if ( !sieve_operand_read(denv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(denv->sblock, address, &operand) ) {
 		sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
 		return FALSE;
 	}
@@ -188,7 +188,7 @@ static int cmd_flag_operation_execute
 	 * Read operands 
 	 */
 
-	if ( !sieve_operand_read(renv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(renv->sblock, address, &operand) ) {
 		sieve_runtime_trace_error(renv, "invalid operand");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
diff --git a/src/lib-sieve/plugins/imap4flags/tag-flags.c b/src/lib-sieve/plugins/imap4flags/tag-flags.c
index 026faf0b6..1645a0871 100644
--- a/src/lib-sieve/plugins/imap4flags/tag-flags.c
+++ b/src/lib-sieve/plugins/imap4flags/tag-flags.c
@@ -155,7 +155,7 @@ static bool tag_flags_generate
 	}
 
 	sieve_opr_side_effect_emit
-		(cgenv->sbin, arg->argument->ext, &flags_side_effect);
+		(cgenv->sblock, arg->argument->ext, &flags_side_effect);
 
 	if ( sieve_argument_is(arg, tag_flags) ) {
 		/* Explicit :flags tag */
@@ -169,7 +169,7 @@ static bool tag_flags_generate
 
 	} else if ( sieve_argument_is(arg, tag_flags_implicit) ) {
 		/* Implicit flags */
-		sieve_opr_omitted_emit(cgenv->sbin);
+		sieve_opr_omitted_emit(cgenv->sblock);
 	
 	} else {
 		/* Something else?! */
@@ -198,7 +198,7 @@ static bool seff_flags_dump_context
 {
   struct sieve_operand operand;
 
-  if ( !sieve_operand_read(denv->sbin, address, &operand) ) {
+  if ( !sieve_operand_read(denv->sblock, address, &operand) ) {
 		sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
 		return FALSE;
 	}
@@ -269,7 +269,7 @@ static bool seff_flags_read_context
 	t_push();
 
 	/* Check whether explicit flag list operand is present */
-	if ( !sieve_operand_read(renv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(renv->sblock, address, &operand) ) {
         sieve_runtime_trace_error(renv, "invalid operand");
 		t_pop();
         return FALSE;
diff --git a/src/lib-sieve/plugins/imap4flags/tst-hasflag.c b/src/lib-sieve/plugins/imap4flags/tst-hasflag.c
index 01f03191a..cbcec03de 100644
--- a/src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+++ b/src/lib-sieve/plugins/imap4flags/tst-hasflag.c
@@ -119,7 +119,7 @@ static bool tst_hasflag_validate
 static bool tst_hasflag_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &hasflag_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &hasflag_operation);
 
 	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
diff --git a/src/lib-sieve/plugins/include/cmd-global.c b/src/lib-sieve/plugins/include/cmd-global.c
index 06afdb3fe..1c50483bc 100644
--- a/src/lib-sieve/plugins/include/cmd-global.c
+++ b/src/lib-sieve/plugins/include/cmd-global.c
@@ -201,26 +201,27 @@ static bool cmd_global_generate
 {
 	struct sieve_ast_argument *arg = cmd->first_positional;
 
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &global_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &global_operation);
  	 			
 	if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
 		/* Single string */
 		struct sieve_variable *var = (struct sieve_variable *) arg->argument->data;
 		
-		(void)sieve_binary_emit_unsigned(cgenv->sbin, 1);
-		(void)sieve_binary_emit_unsigned(cgenv->sbin, var->index);
+		(void)sieve_binary_emit_unsigned(cgenv->sblock, 1);
+		(void)sieve_binary_emit_unsigned(cgenv->sblock, var->index);
 		
 	} else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
 		/* String list */
 		struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg);
 		
-		(void)sieve_binary_emit_unsigned(cgenv->sbin, sieve_ast_strlist_count(arg));
+		(void)sieve_binary_emit_unsigned
+			(cgenv->sblock, sieve_ast_strlist_count(arg));
 						
 		while ( stritem != NULL ) {
 			struct sieve_variable *var = 
 				(struct sieve_variable *) stritem->argument->data;
 			
-			(void)sieve_binary_emit_unsigned(cgenv->sbin, var->index);
+			(void)sieve_binary_emit_unsigned(cgenv->sblock, var->index);
 			
 			stritem = sieve_ast_strlist_next(stritem);
 		}
@@ -243,7 +244,7 @@ static bool opc_global_dump
 	struct sieve_variable_scope *scope;
 	struct sieve_variable * const *vars;
 	
-	if ( !sieve_binary_read_unsigned(denv->sbin, address, &count) )
+	if ( !sieve_binary_read_unsigned(denv->sblock, address, &count) )
 		return FALSE;
 
 	sieve_code_dumpf(denv, "GLOBAL (count: %u):", count);
@@ -257,7 +258,7 @@ static bool opc_global_dump
 		unsigned int index;
 		
 		sieve_code_mark(denv);
-		if ( !sieve_binary_read_unsigned(denv->sbin, address, &index) ||
+		if ( !sieve_binary_read_unsigned(denv->sblock, address, &index) ||
 			index >= var_count )
 			return FALSE;
 			
@@ -280,7 +281,7 @@ static int opc_global_execute
 	struct sieve_variable * const *vars;
 	unsigned int var_count, count, i;
 		
-	if ( !sieve_binary_read_unsigned(renv->sbin, address, &count) ) {
+	if ( !sieve_binary_read_unsigned(renv->sblock, address, &count) ) {
 		sieve_runtime_trace_error(renv, "invalid count operand");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
@@ -293,7 +294,7 @@ static int opc_global_execute
 	for ( i = 0; i < count; i++ ) {
 		unsigned int index;
 		
-		if ( !sieve_binary_read_unsigned(renv->sbin, address, &index) ) {
+		if ( !sieve_binary_read_unsigned(renv->sblock, address, &index) ) {
 			sieve_runtime_trace_error(renv, "invalid global variable operand");
 			return SIEVE_EXEC_BIN_CORRUPT;
 		}
diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c
index ce25fbcd8..2be54eee2 100644
--- a/src/lib-sieve/plugins/include/cmd-include.c
+++ b/src/lib-sieve/plugins/include/cmd-include.c
@@ -287,9 +287,9 @@ static bool cmd_include_generate
 			ctx_data->include_once) )
  		return FALSE;
  		
- 	(void)sieve_operation_emit(cgenv->sbin, cmd->ext, &include_operation);
-	(void)sieve_binary_emit_unsigned(cgenv->sbin, included->id); 
-	(void)sieve_binary_emit_byte(cgenv->sbin, flags); 
+ 	(void)sieve_operation_emit(cgenv->sblock, cmd->ext, &include_operation);
+	(void)sieve_binary_emit_unsigned(cgenv->sblock, included->id); 
+	(void)sieve_binary_emit_byte(cgenv->sblock, flags); 
  	 		
 	return TRUE;
 }
@@ -308,10 +308,10 @@ static bool opc_include_dump
 	sieve_code_dumpf(denv, "INCLUDE:");
 	
 	sieve_code_mark(denv);
-	if ( !sieve_binary_read_unsigned(denv->sbin, address, &include_id) )
+	if ( !sieve_binary_read_unsigned(denv->sblock, address, &include_id) )
 		return FALSE;
 
-	if ( !sieve_binary_read_byte(denv->sbin, address, &flags) )
+	if ( !sieve_binary_read_byte(denv->sblock, address, &flags) )
 		return FALSE;
 
 	binctx = ext_include_binary_get_context(denv->oprtn.ext, denv->sbin);
@@ -322,7 +322,7 @@ static bool opc_include_dump
 	sieve_code_descend(denv);
 	sieve_code_dumpf(denv, "script: %s %s[ID: %d, BLOCK: %d]", 
 		sieve_script_filename(included->script), (flags & 0x01 ? "(once) " : ""),
-		include_id, included->block_id);
+		include_id, sieve_binary_block_get_id(included->block));
 
 	return TRUE;
 }
@@ -336,12 +336,12 @@ static int opc_include_execute
 {
 	unsigned int include_id, flags;
 		
-	if ( !sieve_binary_read_unsigned(renv->sbin, address, &include_id) ) {
+	if ( !sieve_binary_read_unsigned(renv->sblock, address, &include_id) ) {
 		sieve_runtime_trace_error(renv, "invalid include-id operand");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
 
-	if ( !sieve_binary_read_unsigned(renv->sbin, address, &flags) ) {
+	if ( !sieve_binary_read_unsigned(renv->sblock, address, &flags) ) {
 		sieve_runtime_trace_error(renv, "invalid flags operand");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
diff --git a/src/lib-sieve/plugins/include/cmd-return.c b/src/lib-sieve/plugins/include/cmd-return.c
index f3dec7877..37625400b 100644
--- a/src/lib-sieve/plugins/include/cmd-return.c
+++ b/src/lib-sieve/plugins/include/cmd-return.c
@@ -52,7 +52,7 @@ const struct sieve_operation_def return_operation = {
 static bool cmd_return_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &return_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &return_operation);
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/plugins/include/ext-include-binary.c b/src/lib-sieve/plugins/include/ext-include-binary.c
index eb661a41c..802ee5805 100644
--- a/src/lib-sieve/plugins/include/ext-include-binary.c
+++ b/src/lib-sieve/plugins/include/ext-include-binary.c
@@ -50,7 +50,7 @@ const struct sieve_binary_extension include_binary_ext = {
  
 struct ext_include_binary_context {
 	struct sieve_binary *binary;
-	unsigned int dependency_block;
+	struct sieve_binary_block *dependency_block;
 	
 	struct hash_table *included_scripts;
 	ARRAY_DEFINE(include_index, struct ext_include_script_info *);
@@ -120,7 +120,7 @@ struct ext_include_binary_context *ext_include_binary_init
 
 const struct ext_include_script_info *ext_include_binary_script_include
 (struct ext_include_binary_context *binctx, struct sieve_script *script,
-	enum ext_include_script_location location, unsigned int block_id)
+	enum ext_include_script_location location, struct sieve_binary_block *inc_block)
 {
 	pool_t pool = sieve_binary_pool(binctx->binary);
 	struct ext_include_script_info *incscript;
@@ -129,7 +129,7 @@ const struct ext_include_script_info *ext_include_binary_script_include
 	incscript->id = array_count(&binctx->include_index)+1;
 	incscript->script = script;
 	incscript->location = location;
-	incscript->block_id = block_id;
+	incscript->block = inc_block;
 	
 	/* Unreferenced on binary_free */
 	sieve_script_ref(script);
@@ -200,36 +200,32 @@ struct sieve_variable_scope *ext_include_binary_get_global_scope
  */
 
 static bool ext_include_binary_save
-(const struct sieve_extension *ext ATTR_UNUSED, struct sieve_binary *sbin, 
-	void *context)
+(const struct sieve_extension *ext ATTR_UNUSED, 
+	struct sieve_binary *sbin ATTR_UNUSED, void *context)
 {
 	struct ext_include_binary_context *binctx = 
 		(struct ext_include_binary_context *) context;
 	struct ext_include_script_info *const *scripts;
+	struct sieve_binary_block *sblock = binctx->dependency_block;
 	unsigned int script_count, i;
-	unsigned int prvblk;
 	bool result = TRUE;
 	
-	sieve_binary_block_clear(sbin, binctx->dependency_block);
-	if ( !sieve_binary_block_set_active(sbin, binctx->dependency_block, &prvblk) )	
-		return FALSE;
+	sieve_binary_block_clear(sblock);
 
 	scripts = array_get(&binctx->include_index, &script_count);
 
-	sieve_binary_emit_unsigned(sbin, script_count);
+	sieve_binary_emit_unsigned(sblock, script_count);
 
 	for ( i = 0; i < script_count; i++ ) {
 		struct ext_include_script_info *incscript = scripts[i];
 
-		sieve_binary_emit_unsigned(sbin, incscript->block_id);
-		sieve_binary_emit_byte(sbin, incscript->location);
-		sieve_binary_emit_cstring(sbin, sieve_script_name(incscript->script));
+		sieve_binary_emit_unsigned(sblock, sieve_binary_block_get_id(incscript->block));
+		sieve_binary_emit_byte(sblock, incscript->location);
+		sieve_binary_emit_cstring(sblock, sieve_script_name(incscript->script));
 	}
 
-	result = ext_include_variables_save(sbin, binctx->global_vars);
+	result = ext_include_variables_save(sblock, binctx->global_vars);
 	
-	(void) sieve_binary_block_set_active(sbin, prvblk, NULL);
-
 	return result;
 }
 
@@ -238,19 +234,20 @@ static bool ext_include_binary_open
 {
 	struct ext_include_binary_context *binctx = 
 		(struct ext_include_binary_context *) context;
-	unsigned int block, prvblk, depcount, i;
+	struct sieve_binary_block *sblock;
+	unsigned int depcount, i, block_id;
 	sieve_size_t offset;
 	
-	block = sieve_binary_extension_get_block(sbin, ext);
-	
-	if ( !sieve_binary_block_set_active(sbin, block, &prvblk) )
-		return FALSE; 
-		
+	sblock = sieve_binary_extension_get_block(sbin, ext);
+	block_id = sieve_binary_block_get_id(sblock);
+			
 	offset = 0;	
 		
-	if ( !sieve_binary_read_unsigned(sbin, &offset, &depcount) ) {
+	if ( !sieve_binary_read_unsigned(sblock, &offset, &depcount) ) {
 		sieve_sys_error("include: failed to read include count "
-			"for dependency block %d of binary %s", block, sieve_binary_path(sbin)); 
+			"for dependency block %d of binary %s", block_id, 
+			sieve_binary_path(sbin));
+		printf("BLOCK: %ld\n", sieve_binary_block_get_size(sblock));
 		return FALSE;
 	}
 	
@@ -263,19 +260,29 @@ static bool ext_include_binary_open
 	
 	/* Read dependencies */
 	for ( i = 0; i < depcount; i++ ) {
-		unsigned int block_id;
+		unsigned int inc_block_id;
+		struct sieve_binary_block *inc_block;
 		enum ext_include_script_location location;
 		string_t *script_name;
 		const char *script_dir;
 		struct sieve_script *script;
 		
 		if ( 
-			!sieve_binary_read_unsigned(sbin, &offset, &block_id) ||
-			!sieve_binary_read_byte(sbin, &offset, &location) ||
-			!sieve_binary_read_string(sbin, &offset, &script_name) ) {
+			!sieve_binary_read_unsigned(sblock, &offset, &inc_block_id) ||
+			!sieve_binary_read_byte(sblock, &offset, &location) ||
+			!sieve_binary_read_string(sblock, &offset, &script_name) ) {
 			/* Binary is corrupt, recompile */
 			sieve_sys_error("include: failed to read included script "
-				"from dependency block %d of binary %s", block, sieve_binary_path(sbin)); 
+				"from dependency block %d of binary %s", block_id, 
+				sieve_binary_path(sbin)); 
+			return FALSE;
+		}
+
+		if ( (inc_block=sieve_binary_block_get(sbin, inc_block_id)) == NULL ) {
+			sieve_sys_error("include: failed to find block %d for included script "
+				"from dependency block %d of binary %s", inc_block_id, block_id, 
+				sieve_binary_path(sbin)); 
+
 			return FALSE;
 		}
 		
@@ -283,7 +290,7 @@ static bool ext_include_binary_open
 			/* Binary is corrupt, recompile */
 			sieve_sys_error("include: dependency block %d of binary %s "
 				"reports invalid script location (id %d)", 
-				block, sieve_binary_path(sbin), location); 
+				block_id, sieve_binary_path(sbin), location); 
 			return FALSE;
 		}		
 		
@@ -297,18 +304,16 @@ static bool ext_include_binary_open
 			return FALSE;
 		}
 		
-		(void)ext_include_binary_script_include(binctx, script, location, block_id);
+		(void)ext_include_binary_script_include
+			(binctx, script, location, inc_block);
 				
 		sieve_script_unref(&script);
 	}
 
 	if ( !ext_include_variables_load
-		(ext, sbin, &offset, block, &binctx->global_vars) )
+		(ext, sblock, &offset, &binctx->global_vars) )
 		return FALSE;
 	
-	/* Restore previously active block */
-	(void)sieve_binary_block_set_active(sbin, prvblk, NULL);
-
 	return TRUE;	
 }
 
@@ -375,7 +380,6 @@ bool ext_include_binary_dump
 		ext_include_binary_get_context(ext, sbin);
 	struct hash_iterate_context *hctx;
 	void *key, *value;
-	unsigned int prvblk = 0;
 
 	if ( !ext_include_variables_dump(denv, binctx->global_vars) )
 		return FALSE;
@@ -384,19 +388,13 @@ bool ext_include_binary_dump
 	while ( hash_table_iterate(hctx, &key, &value) ) {
 		struct ext_include_script_info *incscript = 
 			(struct ext_include_script_info *) value;
-
+		unsigned int block_id = sieve_binary_block_get_id(incscript->block);
+		
 		sieve_binary_dump_sectionf(denv, "Included %s script '%s' (block: %d)", 
 			ext_include_script_location_name(incscript->location), 
-			sieve_script_name(incscript->script), incscript->block_id);
-			
-		if ( prvblk == 0 ) {
-			if ( !sieve_binary_block_set_active(sbin, incscript->block_id, &prvblk) )	
-				return FALSE;
-		} else {
-			if ( !sieve_binary_block_set_active(sbin, incscript->block_id, NULL) )	
-				return FALSE;
-		}
-				
+			sieve_script_name(incscript->script), block_id);
+							
+		denv->sblock = incscript->block;
 		denv->cdumper = sieve_code_dumper_create(denv);
 
 		if ( denv->cdumper == NULL )
@@ -405,10 +403,7 @@ bool ext_include_binary_dump
 		sieve_code_dumper_run(denv->cdumper);
 		sieve_code_dumper_free(&(denv->cdumper));
 	}
-	
-	if ( !sieve_binary_block_set_active(sbin, prvblk, NULL) ) 
-		return FALSE;
-	
+		
 	hash_table_iterate_deinit(&hctx);
 	
 	return TRUE;
diff --git a/src/lib-sieve/plugins/include/ext-include-binary.h b/src/lib-sieve/plugins/include/ext-include-binary.h
index 68f3344db..dfc63a487 100644
--- a/src/lib-sieve/plugins/include/ext-include-binary.h
+++ b/src/lib-sieve/plugins/include/ext-include-binary.h
@@ -35,12 +35,13 @@ struct ext_include_script_info {
     struct sieve_script *script;
     enum ext_include_script_location location;
 
-    unsigned int block_id;
+    struct sieve_binary_block *block;
 };
 
 const struct ext_include_script_info *ext_include_binary_script_include
 	(struct ext_include_binary_context *binctx, struct sieve_script *script,
-		enum ext_include_script_location location, unsigned int block_id);
+		enum ext_include_script_location location, 
+		struct sieve_binary_block *block);
 bool ext_include_binary_script_is_included
 	(struct ext_include_binary_context *binctx, struct sieve_script *script,
 		const struct ext_include_script_info **script_info_r);
diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c
index 436c6e47a..6a3289030 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.c
+++ b/src/lib-sieve/plugins/include/ext-include-common.c
@@ -433,7 +433,7 @@ bool ext_include_generate_include
 	/* Is the script already compiled into the current binary? */
 	if ( !ext_include_binary_script_is_included(binctx, script, &included) )	
 	{	
-		unsigned int inc_block_id, this_block_id;
+		struct sieve_binary_block *inc_block;
 		const char *script_name = sieve_script_name(script);
 
 		/* Check whether include limit is exceeded */
@@ -447,9 +447,9 @@ bool ext_include_generate_include
 		
 		/* No, allocate a new block in the binary and mark the script as included.
 		 */
-		inc_block_id = sieve_binary_block_create(sbin);
+		inc_block = sieve_binary_block_create(sbin);
 		included = ext_include_binary_script_include
-			(binctx, script, location, inc_block_id);
+			(binctx, script, location, inc_block);
 
 		/* Parse */
 		if ( (ast = sieve_parse(script, ehandler)) == NULL ) {
@@ -475,28 +475,18 @@ bool ext_include_generate_include
 		 * FIXME: It might not be a good idea to recurse code generation for 
 		 * included scripts.
 		 */
-		if ( sieve_binary_block_set_active(sbin, inc_block_id, &this_block_id) ) {
-		 	subgentr = sieve_generator_create(ast, ehandler);			
-			ext_include_initialize_generator_context(cmd->ext, subgentr, ctx, script);
-				
-			if ( !sieve_generator_run(subgentr, &sbin) ) {
-				sieve_command_generate_error(gentr, cmd, 
-					"failed to generate code for included script '%s'", 
-					str_sanitize(script_name, 80));
-		 		result = FALSE;
-			}
+	 	subgentr = sieve_generator_create(ast, ehandler);			
+		ext_include_initialize_generator_context(cmd->ext, subgentr, ctx, script);
 			
-			if ( sbin != NULL )		
-				(void) sieve_binary_block_set_active(sbin, this_block_id, NULL); 	
-
-			sieve_generator_free(&subgentr);
-
-		} else {
-			sieve_sys_error("include: failed to activate binary  block %d for "
-				"generating code for the included script", inc_block_id);
-			result = FALSE;
+		if ( sieve_generator_run(subgentr, &inc_block) == NULL ) {
+			sieve_command_generate_error(gentr, cmd, 
+				"failed to generate code for included script '%s'", 
+				str_sanitize(script_name, 80));
+	 		result = FALSE;
 		}
 		
+		sieve_generator_free(&subgentr);
+		
 		/* Cleanup */
 		sieve_ast_unref(&ast);		
 	} 
@@ -537,6 +527,7 @@ static bool ext_include_runtime_include_mark
 	
 	includes = array_get(&ctx->global->included_scripts, &count);
 	for ( i = 0; i < count; i++ )	{
+
 		if ( sieve_script_equals(include->script, includes[i]) )
 			return ( !once );
 	}
@@ -555,6 +546,7 @@ int ext_include_execute_include
 	const struct ext_include_script_info *included;
 	struct ext_include_binary_context *binctx = 
 		ext_include_binary_get_context(this_ext, renv->sbin);
+	unsigned int block_id;
 
 	/* Check for invalid include id (== corrupt binary) */
 	included = ext_include_binary_script_get_included(binctx, include_id);
@@ -565,16 +557,18 @@ int ext_include_execute_include
 
 	ctx = ext_include_get_interpreter_context(this_ext, renv->interp);
 	
+	block_id = sieve_binary_block_get_id(included->block);
+
 	sieve_runtime_trace(renv, 
 		"INCLUDE command (script: %s, id: %d block: %d) START::", 
-		sieve_script_name(included->script), include_id, included->block_id);
+		sieve_script_name(included->script), include_id, block_id);
 
 	/* If :once modifier is specified, check for duplicate include */
 	if ( !ext_include_runtime_include_mark(ctx, included, once) ) {
 		/* skip */
 
 		sieve_runtime_trace(renv, 
-			"INCLUDE command (block: %d) SKIPPED ::", included->block_id);
+			"INCLUDE command (block: %d) SKIPPED ::", block_id);
 		return result;
 	}
 
@@ -584,7 +578,7 @@ int ext_include_execute_include
 	if ( ext_include_runtime_check_circular(ctx, included) ) {
 		sieve_runtime_trace_error(renv, 
 			"circular include for script: %s [%d]", 
-			sieve_script_name(included->script), included->block_id);
+			sieve_script_name(included->script), block_id);
 
 		/* Situation has no valid way to emerge at runtime */
 		return SIEVE_EXEC_BIN_CORRUPT; 
@@ -595,24 +589,16 @@ int ext_include_execute_include
 		struct sieve_error_handler *ehandler = 
 			sieve_interpreter_get_error_handler(renv->interp);
 		struct sieve_interpreter *subinterp;
-		unsigned int this_block_id;
 		bool interrupted = FALSE;	
 
 		/* We are the top-level interpreter instance */	
 		
-		/* Activate block for included script */
-		if ( !sieve_binary_block_set_active
-			(renv->sbin, included->block_id, &this_block_id) ) {			
-			sieve_runtime_trace_error(renv, "invalid block id: %d", 
-				included->block_id);
-			result = SIEVE_EXEC_BIN_CORRUPT;
-		}
-
 		if ( result == SIEVE_EXEC_OK ) {
 			/* Create interpreter for top-level included script
 			 * (first sub-interpreter) 
 			 */
-			subinterp = sieve_interpreter_create(renv->sbin, ehandler);
+			subinterp = sieve_interpreter_create_for_block
+				(included->block, ehandler);
 
 			if ( subinterp != NULL ) {			
 				curctx = ext_include_interpreter_context_init_child
@@ -639,7 +625,7 @@ int ext_include_execute_include
 					/* Sub-interpreter ended or executed return */
 					
 					sieve_runtime_trace(renv, "INCLUDE command (block: %d) END ::", 
-						curctx->script_info->block_id);
+						sieve_binary_block_get_id(curctx->script_info->block));
 
 					/* Ascend interpreter stack */
 					curctx = curctx->parent;
@@ -648,9 +634,6 @@ int ext_include_execute_include
 					/* This is the top-most sub-interpreter, bail out */
 					if ( curctx->parent == NULL ) break;
 					
-					/* Reactivate parent */
-					(void) sieve_binary_block_set_active
-						(renv->sbin, curctx->script_info->block_id, NULL);
 					subinterp = curctx->interp; 	
 					
 					/* Continue parent */
@@ -662,18 +645,11 @@ int ext_include_execute_include
 					if ( curctx->include != NULL ) {
 
 						/* Sub-include requested */
-															
-						/* Activate the sub-include's block */
-						if ( !sieve_binary_block_set_active
-							(renv->sbin, curctx->include->block_id, NULL) ) {
-							sieve_runtime_trace_error(renv, "invalid block id: %d", 
-								curctx->include->block_id);
-							result = SIEVE_EXEC_BIN_CORRUPT;
-						}
-				
+																	
 						if ( result == SIEVE_EXEC_OK ) {
 							/* Create sub-interpreter */
-							subinterp = sieve_interpreter_create(renv->sbin, ehandler);			
+							subinterp = sieve_interpreter_create_for_block
+								(curctx->include->block, ehandler);			
 
 							if ( subinterp != NULL ) {
 								curctx = ext_include_interpreter_context_init_child
@@ -701,7 +677,7 @@ int ext_include_execute_include
 			}
 		} else 
 			sieve_runtime_trace(renv, "INCLUDE command (block: %d) END ::", 
-				curctx->script_info->block_id);
+				sieve_binary_block_get_id(curctx->script_info->block));
 
 		/* Free any sub-interpreters that might still be active */
 		while ( curctx != NULL && curctx->parent != NULL ) {
@@ -715,8 +691,6 @@ int ext_include_execute_include
 			curctx = nextctx;
 		}
 
-		/* Return to our own block */
-		(void) sieve_binary_block_set_active(renv->sbin, this_block_id, NULL); 	
 	} else {
 		/* We are an included script already, defer inclusion to main interpreter */
 
diff --git a/src/lib-sieve/plugins/include/ext-include-variables.c b/src/lib-sieve/plugins/include/ext-include-variables.c
index 4ef36dae5..16b175cac 100644
--- a/src/lib-sieve/plugins/include/ext-include-variables.c
+++ b/src/lib-sieve/plugins/include/ext-include-variables.c
@@ -70,11 +70,11 @@ struct sieve_variable *ext_include_variable_import_global
  */
  
 bool ext_include_variables_save
-(struct sieve_binary *sbin, struct sieve_variable_scope *global_vars)
+(struct sieve_binary_block *sblock, struct sieve_variable_scope *global_vars)
 {
 	unsigned int count = sieve_variable_scope_size(global_vars);
 
-	sieve_binary_emit_unsigned(sbin, count);
+	sieve_binary_emit_unsigned(sblock, count);
 
 	if ( count > 0 ) {
 		unsigned int size, i;
@@ -82,7 +82,7 @@ bool ext_include_variables_save
 			sieve_variable_scope_get_variables(global_vars, &size);
 
 		for ( i = 0; i < size; i++ ) {
-			sieve_binary_emit_cstring(sbin, vars[i]->identifier);
+			sieve_binary_emit_cstring(sblock, vars[i]->identifier);
 		}
 	}
 
@@ -90,20 +90,21 @@ bool ext_include_variables_save
 }
 
 bool ext_include_variables_load
-(const struct sieve_extension *this_ext, struct sieve_binary *sbin, 
-	sieve_size_t *offset, unsigned int block,
-	struct sieve_variable_scope **global_vars_r)
+(const struct sieve_extension *this_ext, struct sieve_binary_block *sblock, 
+	sieve_size_t *offset, struct sieve_variable_scope **global_vars_r)
 {
-	unsigned int count = 0;
-	unsigned int i;
+	struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
+	unsigned int block_id = sieve_binary_block_get_id(sblock);
+	unsigned int i, count = 0;
 	pool_t pool;
 
 	/* Sanity assert */
 	i_assert( *global_vars_r == NULL );
 
-	if ( !sieve_binary_read_unsigned(sbin, offset, &count) ) {
+	if ( !sieve_binary_read_unsigned(sblock, offset, &count) ) {
 		sieve_sys_error("include: failed to read global variables count "
-			"from dependency block %d of binary %s", block, sieve_binary_path(sbin));
+			"from dependency block %d of binary %s", block_id, 
+			sieve_binary_path(sbin));
 		return FALSE;
 	}
 
@@ -122,10 +123,11 @@ bool ext_include_variables_load
 		struct sieve_variable *var;
 		string_t *identifier;
 
-		if ( !sieve_binary_read_string(sbin, offset, &identifier) ) {
+		if ( !sieve_binary_read_string(sblock, offset, &identifier) ) {
 			/* Binary is corrupt, recompile */
 			sieve_sys_error("include: failed to read global variable specification "
-				"from dependency block %d of binary %s", block, sieve_binary_path(sbin));
+				"from dependency block %d of binary %s", block_id, 
+				sieve_binary_path(sbin));
 			return FALSE;
 		}
 		
@@ -248,7 +250,7 @@ bool vnspc_global_variables_generate
 
 	struct sieve_variable *var = (struct sieve_variable *) var_data;
 	
-	sieve_variables_opr_variable_emit(cgenv->sbin, ectx->var_ext, var);
+	sieve_variables_opr_variable_emit(cgenv->sblock, ectx->var_ext, var);
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/plugins/include/ext-include-variables.h b/src/lib-sieve/plugins/include/ext-include-variables.h
index 036136895..9d494165d 100644
--- a/src/lib-sieve/plugins/include/ext-include-variables.h
+++ b/src/lib-sieve/plugins/include/ext-include-variables.h
@@ -23,11 +23,10 @@ struct sieve_variable *ext_include_variable_import_global
  */
 
 bool ext_include_variables_save
-	(struct sieve_binary *sbin, struct sieve_variable_scope *global_vars);
+	(struct sieve_binary_block *sblock, struct sieve_variable_scope *global_vars);
 bool ext_include_variables_load
-	(const struct sieve_extension *this_ext, struct sieve_binary *sbin, 
-		sieve_size_t *offset, unsigned int block,
-		struct sieve_variable_scope **global_vars_r);
+	(const struct sieve_extension *this_ext, struct sieve_binary_block *sblock, 
+		sieve_size_t *offset, struct sieve_variable_scope **global_vars_r);
 bool ext_include_variables_dump
 	(struct sieve_dumptime_env *denv, struct sieve_variable_scope *global_vars);
 
diff --git a/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c b/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
index d67d9a277..f78142f4f 100644
--- a/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+++ b/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
@@ -96,7 +96,7 @@ static bool tag_mailbox_create_generate
 	}
 
 	sieve_opr_side_effect_emit
-		(cgenv->sbin, arg->argument->ext, &mailbox_create_side_effect);
+		(cgenv->sblock, arg->argument->ext, &mailbox_create_side_effect);
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c b/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
index 5a07cffc3..ac9044e64 100644
--- a/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+++ b/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
@@ -78,7 +78,7 @@ static bool tst_mailboxexists_validate
 static bool tst_mailboxexists_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst) 
 {
-	sieve_operation_emit(cgenv->sbin, tst->ext, &mailboxexists_operation);
+	sieve_operation_emit(cgenv->sblock, tst->ext, &mailboxexists_operation);
 
  	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, tst, NULL);
diff --git a/src/lib-sieve/plugins/notify/cmd-denotify.c b/src/lib-sieve/plugins/notify/cmd-denotify.c
index 4b1919193..f1512e56c 100644
--- a/src/lib-sieve/plugins/notify/cmd-denotify.c
+++ b/src/lib-sieve/plugins/notify/cmd-denotify.c
@@ -218,10 +218,10 @@ static bool cmd_denotify_validate
 static bool cmd_denotify_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &denotify_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &denotify_operation);
 
 	/* Emit source line */
-	sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(cmd));
+	sieve_code_source_line_emit(cgenv->sblock, sieve_command_source_line(cmd));
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
@@ -245,11 +245,11 @@ static bool cmd_denotify_operation_dump
 		return FALSE;
 
 	/* Dump optional operands */
-	if ( sieve_operand_optional_present(denv->sbin, address) ) {
+	if ( sieve_operand_optional_present(denv->sblock, address) ) {
 		while ( opt_code != 0 ) {
 			sieve_code_mark(denv);
 			
-			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) 
+			if ( !sieve_operand_optional_read(denv->sblock, address, &opt_code) ) 
 				return FALSE;
 
 			switch ( opt_code ) {
@@ -308,9 +308,9 @@ static int cmd_denotify_operation_execute
 	}
 	
 	/* Optional operands */	
-	if ( sieve_operand_optional_present(renv->sbin, address) ) {
+	if ( sieve_operand_optional_present(renv->sblock, address) ) {
 		while ( opt_code != 0 ) {
-			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) {
+			if ( !sieve_operand_optional_read(renv->sblock, address, &opt_code) ) {
 				sieve_runtime_trace_error(renv, "invalid optional operand");
 				return SIEVE_EXEC_BIN_CORRUPT;
 			}
diff --git a/src/lib-sieve/plugins/notify/cmd-notify.c b/src/lib-sieve/plugins/notify/cmd-notify.c
index d7d31742f..69586a240 100644
--- a/src/lib-sieve/plugins/notify/cmd-notify.c
+++ b/src/lib-sieve/plugins/notify/cmd-notify.c
@@ -353,10 +353,10 @@ static bool cmd_notify_validate
 static bool cmd_notify_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &notify_old_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &notify_old_operation);
 
 	/* Emit source line */
-	sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(cmd));
+	sieve_code_source_line_emit(cgenv->sblock, sieve_command_source_line(cmd));
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
@@ -379,11 +379,11 @@ static bool cmd_notify_operation_dump
 		return FALSE;
 
 	/* Dump optional operands */
-	if ( sieve_operand_optional_present(denv->sbin, address) ) {
+	if ( sieve_operand_optional_present(denv->sblock, address) ) {
 		while ( opt_code != 0 ) {
 			sieve_code_mark(denv);
 			
-			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) 
+			if ( !sieve_operand_optional_read(denv->sblock, address, &opt_code) ) 
 				return FALSE;
 
 			switch ( opt_code ) {
@@ -442,9 +442,9 @@ static int cmd_notify_operation_execute
 	}
 	
 	/* Optional operands */	
-	if ( sieve_operand_optional_present(renv->sbin, address) ) {
+	if ( sieve_operand_optional_present(renv->sblock, address) ) {
 		while ( opt_code != 0 ) {
-			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) {
+			if ( !sieve_operand_optional_read(renv->sblock, address, &opt_code) ) {
 				sieve_runtime_trace_error(renv, "invalid optional operand");
 				return SIEVE_EXEC_BIN_CORRUPT;
 			}
diff --git a/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c b/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
index ef9b1bade..3f1103d8a 100644
--- a/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+++ b/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
@@ -187,9 +187,9 @@ static bool tst_spamvirustest_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst) 
 { 
 	if ( sieve_command_is(tst, spamtest_test) )
-		sieve_operation_emit(cgenv->sbin, tst->ext, &spamtest_operation);
+		sieve_operation_emit(cgenv->sblock, tst->ext, &spamtest_operation);
 	else if ( sieve_command_is(tst, virustest_test) )
-		sieve_operation_emit(cgenv->sbin, tst->ext, &virustest_operation);
+		sieve_operation_emit(cgenv->sblock, tst->ext, &virustest_operation);
 	else
 		i_unreached();
 
diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c
index c5e632349..52dfe4702 100644
--- a/src/lib-sieve/plugins/vacation/cmd-vacation.c
+++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -463,17 +463,17 @@ static bool cmd_vacation_generate
 	struct cmd_vacation_context_data *ctx_data = 
 		(struct cmd_vacation_context_data *) cmd->data;
 		 
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &vacation_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &vacation_operation);
 
 	/* Emit source line */
-	sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(cmd));
+	sieve_code_source_line_emit(cgenv->sblock, sieve_command_source_line(cmd));
 
 	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
 		return FALSE;	
 
 	/* FIXME: this will not allow the handle to be a variable */
-	sieve_opr_string_emit(cgenv->sbin, ctx_data->handle);
+	sieve_opr_string_emit(cgenv->sblock, ctx_data->handle);
 		
 	return TRUE;
 }
@@ -495,11 +495,11 @@ static bool ext_vacation_operation_dump
 		return FALSE;
 
 	/* Dump optional operands */
-	if ( sieve_operand_optional_present(denv->sbin, address) ) {
+	if ( sieve_operand_optional_present(denv->sblock, address) ) {
 		while ( opt_code != 0 ) {
 			sieve_code_mark(denv);
 			
-			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) 
+			if ( !sieve_operand_optional_read(denv->sblock, address, &opt_code) ) 
 				return FALSE;
 
 			switch ( opt_code ) {
@@ -567,9 +567,9 @@ static int ext_vacation_operation_execute
 	}
 	
 	/* Optional operands */	
-	if ( sieve_operand_optional_present(renv->sbin, address) ) {
+	if ( sieve_operand_optional_present(renv->sblock, address) ) {
 		while ( opt_code != 0 ) {
-			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) {
+			if ( !sieve_operand_optional_read(renv->sblock, address, &opt_code) ) {
 				sieve_runtime_trace_error(renv, "invalid optional operand");
 				return SIEVE_EXEC_BIN_CORRUPT;
 			}
diff --git a/src/lib-sieve/plugins/variables/cmd-set.c b/src/lib-sieve/plugins/variables/cmd-set.c
index 5476be283..1870a07aa 100644
--- a/src/lib-sieve/plugins/variables/cmd-set.c
+++ b/src/lib-sieve/plugins/variables/cmd-set.c
@@ -223,23 +223,23 @@ static bool cmd_set_generate
 	(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
 	const struct sieve_extension *this_ext = cmd->ext;
-	struct sieve_binary *sbin = cgenv->sbin;
+	struct sieve_binary_block *sblock = cgenv->sblock;
 	struct cmd_set_context *sctx = (struct cmd_set_context *) cmd->data;
 	const struct sieve_variables_modifier *const *modfs;
 	unsigned int i, modf_count;	
 
-	sieve_operation_emit(sbin, this_ext, &cmd_set_operation); 
+	sieve_operation_emit(sblock, this_ext, &cmd_set_operation); 
 
 	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
 		return FALSE;	
 		
 	/* Generate modifiers (already sorted during validation) */
-	sieve_binary_emit_byte(sbin, array_count(&sctx->modifiers));
+	sieve_binary_emit_byte(sblock, array_count(&sctx->modifiers));
 
 	modfs = array_get(&sctx->modifiers, &modf_count); 
 	for ( i = 0; i < modf_count; i++ ) {
-		ext_variables_opr_modifier_emit(sbin, modfs[i]->object.ext, modfs[i]->def);
+		ext_variables_opr_modifier_emit(sblock, modfs[i]->object.ext, modfs[i]->def);
 	}
 
 	return TRUE;
@@ -263,7 +263,7 @@ static bool cmd_set_operation_dump
 		return FALSE;
 	
 	/* Read the number of applied modifiers we need to read */
-	if ( !sieve_binary_read_byte(denv->sbin, address, &mdfs) ) 
+	if ( !sieve_binary_read_byte(denv->sblock, address, &mdfs) ) 
 		return FALSE;
 	
 	/* Print all modifiers (sorted during code generation already) */
@@ -305,7 +305,7 @@ static int cmd_set_operation_execute
 	}
 		
 	/* Read the number of modifiers used */
-	if ( !sieve_binary_read_byte(renv->sbin, address, &mdfs) ) {
+	if ( !sieve_binary_read_byte(renv->sblock, address, &mdfs) ) {
 		sieve_runtime_trace_error(renv, "invalid modifier count");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
diff --git a/src/lib-sieve/plugins/variables/ext-variables-arguments.c b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
index 70f91eac0..d0874c68e 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-arguments.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
@@ -82,7 +82,7 @@ static bool arg_variable_generate
 	struct sieve_argument *argument = arg->argument;
 	struct sieve_variable *var = (struct sieve_variable *) argument->data;
 	
-	sieve_variables_opr_variable_emit(cgenv->sbin, argument->ext, var);
+	sieve_variables_opr_variable_emit(cgenv->sblock, argument->ext, var);
 
 	return TRUE;
 }
@@ -152,7 +152,7 @@ static bool arg_match_value_generate
 	struct sieve_argument *argument = arg->argument;
 	unsigned int index = POINTER_CAST_TO(argument->data, unsigned int);
 	
-	sieve_variables_opr_match_value_emit(cgenv->sbin, argument->ext, index);
+	sieve_variables_opr_match_value_emit(cgenv->sblock, argument->ext, index);
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.c b/src/lib-sieve/plugins/variables/ext-variables-common.c
index 051612c98..4d28541a6 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-common.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-common.c
@@ -459,9 +459,9 @@ bool ext_variables_generator_load
 	unsigned int count = sieve_variable_scope_size(main_scope);
 	sieve_size_t jump;
 
-	sieve_binary_emit_unsigned(cgenv->sbin, count);
+	sieve_binary_emit_unsigned(cgenv->sblock, count);
 
-	jump = sieve_binary_emit_offset(cgenv->sbin, 0);
+	jump = sieve_binary_emit_offset(cgenv->sblock, 0);
 
 	if ( count > 0 ) {
 		unsigned int size, i;
@@ -469,11 +469,11 @@ bool ext_variables_generator_load
 			sieve_variable_scope_get_variables(main_scope, &size);
 
 		for ( i = 0; i < size; i++ ) {			
-			sieve_binary_emit_cstring(cgenv->sbin, vars[i]->identifier);
+			sieve_binary_emit_cstring(cgenv->sblock, vars[i]->identifier);
 		}
 	}
 	
-	sieve_binary_resolve_offset(cgenv->sbin, jump);
+	sieve_binary_resolve_offset(cgenv->sblock, jump);
 		
 	return TRUE;
 }
@@ -515,7 +515,7 @@ bool ext_variables_interpreter_load
 	sieve_size_t pc;
 	int end_offset;
 		
-	if ( !sieve_binary_read_unsigned(renv->sbin, address, &scope_size) ) {
+	if ( !sieve_binary_read_unsigned(renv->sblock, address, &scope_size) ) {
 		sieve_sys_error("variables: failed to read main scope size");
 		return FALSE;
 	}
@@ -527,7 +527,7 @@ bool ext_variables_interpreter_load
 	}
 	
 	pc = *address;
-	if ( !sieve_binary_read_offset(renv->sbin, address, &end_offset) )
+	if ( !sieve_binary_read_offset(renv->sblock, address, &end_offset) )
 		return NULL;
 	*address = pc + end_offset;
 	
diff --git a/src/lib-sieve/plugins/variables/ext-variables-dump.c b/src/lib-sieve/plugins/variables/ext-variables-dump.c
index 93d7572c6..a9e60ada6 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-dump.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-dump.c
@@ -77,11 +77,11 @@ bool ext_variables_code_dump
 	int end_offset;
 	
 	sieve_code_mark(denv);
-	if ( !sieve_binary_read_unsigned(denv->sbin, address, &scope_size) )
+	if ( !sieve_binary_read_unsigned(denv->sblock, address, &scope_size) )
 		return FALSE;
 		
 	pc = *address;	
-	if ( !sieve_binary_read_offset(denv->sbin, address, &end_offset) )
+	if ( !sieve_binary_read_offset(denv->sblock, address, &end_offset) )
 		return FALSE;
 	
 	main_scope = sieve_variable_scope_create(NULL);
@@ -95,7 +95,7 @@ bool ext_variables_code_dump
 		string_t *identifier;
 
 		sieve_code_mark(denv);
-		if (!sieve_binary_read_string(denv->sbin, address, &identifier) ) {
+		if (!sieve_binary_read_string(denv->sblock, address, &identifier) ) {
 			return FALSE;
 		}
 		
diff --git a/src/lib-sieve/plugins/variables/ext-variables-modifiers.h b/src/lib-sieve/plugins/variables/ext-variables-modifiers.h
index 4462f54ca..92ee6cceb 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+++ b/src/lib-sieve/plugins/variables/ext-variables-modifiers.h
@@ -34,10 +34,10 @@ void ext_variables_register_core_modifiers
 extern const struct sieve_operand_def modifier_operand;
 
 static inline void ext_variables_opr_modifier_emit
-(struct sieve_binary *sbin, const struct sieve_extension *ext,
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
 	const struct sieve_variables_modifier_def *modf_def)
 { 
-	sieve_opr_object_emit(sbin, ext, &modf_def->obj_def);
+	sieve_opr_object_emit(sblock, ext, &modf_def->obj_def);
 }
 
 static inline bool ext_variables_opr_modifier_read
diff --git a/src/lib-sieve/plugins/variables/ext-variables-namespaces.c b/src/lib-sieve/plugins/variables/ext-variables-namespaces.c
index 69b2cf5d4..2f8897de9 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-namespaces.c
@@ -178,12 +178,12 @@ const struct sieve_operand_def namespace_variable_operand = {
 };
 
 void sieve_variables_opr_namespace_variable_emit
-(struct sieve_binary *sbin, const struct sieve_extension *var_ext,
+(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext,
 	const struct sieve_extension *ext,
 	const struct sieve_variables_namespace_def *nspc_def)
 { 
-	sieve_operand_emit(sbin, var_ext, &namespace_variable_operand);
-	sieve_opr_object_emit(sbin, ext, &nspc_def->obj_def);
+	sieve_operand_emit(sblock, var_ext, &namespace_variable_operand);
+	sieve_opr_object_emit(sblock, ext, &nspc_def->obj_def);
 }
 
 static bool opr_namespace_variable_read
@@ -202,7 +202,6 @@ static bool opr_namespace_variable_read
 	if ( nspc.def == NULL || nspc.def->read_variable == NULL )
 		return FALSE;
 		
-
 	return nspc.def->read_variable(renv, &nspc, address, str);
 }
 
@@ -214,12 +213,12 @@ static bool opr_namespace_variable_dump
 	struct sieve_variables_namespace nspc;
 	struct sieve_operand oprnd; 
 
-	if ( !sieve_operand_read(denv->sbin, address, &oprnd) ) {
+	if ( !sieve_operand_read(denv->sblock, address, &oprnd) ) {
 		return FALSE;
 	}
 
 	if ( !sieve_opr_object_read_data
-		(denv->sbin, &oprnd, &sieve_variables_namespace_operand_class, address, 
+		(denv->sblock, &oprnd, &sieve_variables_namespace_operand_class, address, 
 			&nspc.object) ) {
 		return FALSE;
   }
diff --git a/src/lib-sieve/plugins/variables/ext-variables-namespaces.h b/src/lib-sieve/plugins/variables/ext-variables-namespaces.h
index 184d14ae6..2e7030101 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+++ b/src/lib-sieve/plugins/variables/ext-variables-namespaces.h
@@ -43,9 +43,4 @@ bool ext_variables_namespace_argument_activate
 
 extern const struct sieve_operand_def namespace_variable_operand;
 
-void ext_variables_opr_namespace_variable_emit
-	(struct sieve_binary *sbin, const struct sieve_extension *var_ext,
-		const struct sieve_extension *ext,
-		const struct sieve_variables_namespace_def *nspc_def);
-
 #endif /* __EXT_VARIABLES_NAMESPACES_H */
diff --git a/src/lib-sieve/plugins/variables/ext-variables-operands.c b/src/lib-sieve/plugins/variables/ext-variables-operands.c
index a3f790414..fccfd673f 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-operands.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-operands.c
@@ -49,20 +49,20 @@ const struct sieve_operand_def variable_operand = {
 };
 
 void sieve_variables_opr_variable_emit
-(struct sieve_binary *sbin, const struct sieve_extension *var_ext, 
+(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext, 
 	struct sieve_variable *var) 
 {
 	if ( var->ext == NULL ) {
 		/* Default variable storage */
-		(void) sieve_operand_emit(sbin, var_ext, &variable_operand);
-		(void) sieve_binary_emit_byte(sbin, 0); /* Default */
-		(void) sieve_binary_emit_unsigned(sbin, var->index);
+		(void) sieve_operand_emit(sblock, var_ext, &variable_operand);
+		(void) sieve_binary_emit_byte(sblock, 0); /* Default */
+		(void) sieve_binary_emit_unsigned(sblock, var->index);
 		return;
 	} 
 
-	(void) sieve_operand_emit(sbin, var_ext, &variable_operand);
-	(void) sieve_binary_emit_extension(sbin, var->ext, 1); /* Extension */
-	(void) sieve_binary_emit_unsigned(sbin, var->index);
+	(void) sieve_operand_emit(sblock, var_ext, &variable_operand);
+	(void) sieve_binary_emit_extension(sblock, var->ext, 1); /* Extension */
+	(void) sieve_binary_emit_unsigned(sblock, var->index);
 }
 
 static bool opr_variable_dump
@@ -75,10 +75,10 @@ static bool opr_variable_dump
 	unsigned int code = 1; /* Initially set to offset value */
 	const char *identifier;
 
-	if ( !sieve_binary_read_extension(denv->sbin, address, &code, &ext) )
+	if ( !sieve_binary_read_extension(denv->sblock, address, &code, &ext) )
 		return FALSE;
 	
-	if ( !sieve_binary_read_unsigned(denv->sbin, address, &index) )
+	if ( !sieve_binary_read_unsigned(denv->sblock, address, &index) )
 		return FALSE;
 		
 	identifier = ext_variables_dump_get_identifier(this_ext, denv, ext, index);
@@ -112,14 +112,14 @@ static bool opr_variable_read_value
 	struct sieve_variable_storage *storage;
 	unsigned int index = 0;
 	
-	if ( !sieve_binary_read_extension(renv->sbin, address, &code, &ext) )
+	if ( !sieve_binary_read_extension(renv->sblock, address, &code, &ext) )
 		return FALSE;
 
 	storage = sieve_ext_variables_get_storage(this_ext, renv->interp, ext);
 	if ( storage == NULL ) 
 		return FALSE;
 	
-	if (sieve_binary_read_unsigned(renv->sbin, address, &index) ) {
+	if (sieve_binary_read_unsigned(renv->sblock, address, &index) ) {
 		/* Parameter str can be NULL if we are requested to only skip and not 
 		 * actually read the argument.
 		 */
@@ -148,14 +148,14 @@ bool sieve_variable_operand_read_data
 		return FALSE;
 	}
 
-	if ( !sieve_binary_read_extension(renv->sbin, address, &code, &ext) )
+	if ( !sieve_binary_read_extension(renv->sblock, address, &code, &ext) )
 		return FALSE;
 		
 	*storage = sieve_ext_variables_get_storage(operand->ext, renv->interp, ext);
 	if ( *storage == NULL )	
 		return FALSE;
 	
-	if ( !sieve_binary_read_unsigned(renv->sbin, address, &idx) )
+	if ( !sieve_binary_read_unsigned(renv->sblock, address, &idx) )
 		return FALSE;		
 
 	*var_index = idx;
@@ -168,7 +168,7 @@ bool sieve_variable_operand_read
 {
 	struct sieve_operand operand;
 
-	if ( !sieve_operand_read(renv->sbin, address, &operand) )
+	if ( !sieve_operand_read(renv->sblock, address, &operand) )
 		return FALSE;
 
 	return sieve_variable_operand_read_data
@@ -200,11 +200,11 @@ const struct sieve_operand_def match_value_operand = {
 };	
 
 void sieve_variables_opr_match_value_emit
-(struct sieve_binary *sbin, const struct sieve_extension *var_ext, 
+(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext, 
 	unsigned int index) 
 {
-	(void) sieve_operand_emit(sbin, var_ext, &match_value_operand);
-	(void) sieve_binary_emit_unsigned(sbin, index);
+	(void) sieve_operand_emit(sblock, var_ext, &match_value_operand);
+	(void) sieve_binary_emit_unsigned(sblock, index);
 }
 
 static bool opr_match_value_dump
@@ -214,7 +214,7 @@ static bool opr_match_value_dump
 {
 	unsigned int index = 0;
 	
-	if (sieve_binary_read_unsigned(denv->sbin, address, &index) ) {
+	if (sieve_binary_read_unsigned(denv->sblock, address, &index) ) {
 		if ( field_name != NULL )
 			sieve_code_dumpf
 				(denv, "%s: MATCHVAL %lu", field_name, (unsigned long) index);
@@ -234,7 +234,7 @@ static bool opr_match_value_read
 { 
 	unsigned int index = 0;
 			
-	if (sieve_binary_read_unsigned(renv->sbin, address, &index) ) {
+	if (sieve_binary_read_unsigned(renv->sblock, address, &index) ) {
 		/* Parameter str can be NULL if we are requested to only skip and not 
 		 * actually read the argument.
 		 	*/
diff --git a/src/lib-sieve/plugins/variables/sieve-ext-variables.h b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
index 1fefc202c..3a6aa7208 100644
--- a/src/lib-sieve/plugins/variables/sieve-ext-variables.h
+++ b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
@@ -124,7 +124,7 @@ void sieve_variables_namespace_register
 extern const struct sieve_operand_class sieve_variables_namespace_operand_class;
 
 void sieve_variables_opr_namespace_variable_emit
-(struct sieve_binary *sbin, const struct sieve_extension *var_ext,
+	(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext,
     const struct sieve_extension *ext,
     const struct sieve_variables_namespace_def *nspc_def);
 
@@ -204,10 +204,10 @@ bool sieve_variable_argument_activate
 extern const struct sieve_operand_def variable_operand;
 
 void sieve_variables_opr_variable_emit
-	(struct sieve_binary *sbin, const struct sieve_extension *var_ext, 
+	(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext, 
 		struct sieve_variable *var);
 void sieve_variables_opr_match_value_emit
-	(struct sieve_binary *sbin, const struct sieve_extension *var_ext, 
+	(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext, 
 		unsigned int index);
 
 bool sieve_variable_operand_read_data
diff --git a/src/lib-sieve/plugins/variables/tst-string.c b/src/lib-sieve/plugins/variables/tst-string.c
index fbbeb5c48..7ca25ab36 100644
--- a/src/lib-sieve/plugins/variables/tst-string.c
+++ b/src/lib-sieve/plugins/variables/tst-string.c
@@ -126,7 +126,7 @@ static bool tst_string_validate
 static bool tst_string_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &tst_string_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &tst_string_operation);
 
  	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h
index 060e88ce1..211f5606e 100644
--- a/src/lib-sieve/sieve-actions.h
+++ b/src/lib-sieve/sieve-actions.h
@@ -170,10 +170,10 @@ struct sieve_side_effect {
 extern const struct sieve_operand_class sieve_side_effect_operand_class;
 
 static inline void sieve_opr_side_effect_emit
-(struct sieve_binary *sbin, const struct sieve_extension *ext,
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
 	const struct sieve_side_effect_def *seff)
 { 
-	sieve_opr_object_emit(sbin, ext, &seff->obj_def);
+	sieve_opr_object_emit(sblock, ext, &seff->obj_def);
 }
 
 bool sieve_opr_side_effect_read
diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c
index 297b23bd2..247848aa5 100644
--- a/src/lib-sieve/sieve-address-parts.c
+++ b/src/lib-sieve/sieve-address-parts.c
@@ -204,7 +204,7 @@ static bool tag_address_part_generate
 	struct sieve_address_part *addrp =
 		(struct sieve_address_part *) arg->argument->data;
 		
-	sieve_opr_address_part_emit(cgenv->sbin, addrp); 
+	sieve_opr_address_part_emit(cgenv->sblock, addrp); 
 		
 	return TRUE;
 }
@@ -295,9 +295,9 @@ bool sieve_addrmatch_default_dump_optionals
 {
 	int opt_code = 1;
 	
-	if ( sieve_operand_optional_present(denv->sbin, address) ) {
+	if ( sieve_operand_optional_present(denv->sblock, address) ) {
 		while ( opt_code != 0 ) {
-			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) 
+			if ( !sieve_operand_optional_read(denv->sblock, address, &opt_code) ) 
 				return FALSE;
 
 			switch ( opt_code ) {
@@ -331,9 +331,9 @@ bool sieve_addrmatch_default_get_optionals
 {
 	int opt_code = 1;
 	
-	if ( sieve_operand_optional_present(renv->sbin, address) ) {
+	if ( sieve_operand_optional_present(renv->sblock, address) ) {
 		while ( opt_code != 0 ) {
-			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) )
+			if ( !sieve_operand_optional_read(renv->sblock, address, &opt_code) )
 				return FALSE;
 				  
 			switch ( opt_code ) {
diff --git a/src/lib-sieve/sieve-address-parts.h b/src/lib-sieve/sieve-address-parts.h
index f50971602..699bf2398 100644
--- a/src/lib-sieve/sieve-address-parts.h
+++ b/src/lib-sieve/sieve-address-parts.h
@@ -82,9 +82,9 @@ extern const struct sieve_operand_class sieve_address_part_operand_class;
 #define SIEVE_EXT_DEFINE_ADDRESS_PARTS(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
 
 static inline void sieve_opr_address_part_emit
-(struct sieve_binary *sbin, const struct sieve_address_part *addrp)
+(struct sieve_binary_block *sblock, const struct sieve_address_part *addrp)
 { 
-	sieve_opr_object_emit(sbin, addrp->object.ext, addrp->object.def);
+	sieve_opr_object_emit(sblock, addrp->object.ext, addrp->object.def);
 }
 
 static inline bool sieve_opr_address_part_read
diff --git a/src/lib-sieve/sieve-binary-code.c b/src/lib-sieve/sieve-binary-code.c
new file mode 100644
index 000000000..1f1052a46
--- /dev/null
+++ b/src/lib-sieve/sieve-binary-code.c
@@ -0,0 +1,386 @@
+/* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "mempool.h"
+#include "buffer.h"
+#include "hash.h"
+#include "array.h"
+#include "ostream.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-script.h"
+
+#include "sieve-binary-private.h"
+
+/*
+ * Forward declarations
+ */
+
+static inline sieve_size_t sieve_binary_emit_dynamic_data
+	(struct sieve_binary_block *sblock, const void *data, size_t size);
+
+/*
+ * Emission functions
+ */
+
+/* Low-level emission functions */
+
+static inline void _sieve_binary_emit_data
+(struct sieve_binary_block *sblock, const void *data, sieve_size_t size) 
+{	  
+	buffer_append(sblock->data, data, size);
+}
+
+static inline void _sieve_binary_emit_byte
+(struct sieve_binary_block *sblock, unsigned char byte)
+{
+	_sieve_binary_emit_data(sblock, &byte, 1);
+}
+
+static inline void _sieve_binary_update_data
+(struct sieve_binary_block *sblock, sieve_size_t address, const void *data, 
+	sieve_size_t size) 
+{
+	buffer_write(sblock->data, address, data, size);
+}
+
+sieve_size_t sieve_binary_emit_data
+(struct sieve_binary_block *sblock, const void *data, sieve_size_t size)
+{
+	sieve_size_t address = _sieve_binary_block_get_size(sblock);
+
+	_sieve_binary_emit_data(sblock, data, size);
+
+	return address;
+}
+
+sieve_size_t sieve_binary_emit_byte
+(struct sieve_binary_block *sblock, unsigned char byte) 
+{
+	sieve_size_t address = _sieve_binary_block_get_size(sblock);
+
+	_sieve_binary_emit_data(sblock, &byte, 1);
+	
+	return address;
+}
+
+void sieve_binary_update_data
+(struct sieve_binary_block *sblock, sieve_size_t address, const void *data, 
+	sieve_size_t size) 
+{
+	_sieve_binary_update_data(sblock, address, data, size);
+}
+
+/* Offset emission functions */
+
+sieve_size_t sieve_binary_emit_offset
+(struct sieve_binary_block *sblock, int offset) 
+{
+	int i;
+	sieve_size_t address = _sieve_binary_block_get_size(sblock);
+
+	for ( i = 3; i >= 0; i-- ) {
+		char c = (char) (offset >> (i * 8));
+		_sieve_binary_emit_data(sblock, &c, 1);
+	}
+	
+	return address;
+}
+
+void sieve_binary_resolve_offset
+(struct sieve_binary_block *sblock, sieve_size_t address) 
+{
+	int i;
+	int offset = _sieve_binary_block_get_size(sblock) - address; 
+	
+	for ( i = 3; i >= 0; i-- ) {
+		char c = (char) (offset >> (i * 8));	
+		_sieve_binary_update_data(sblock, address + 3 - i, &c, 1);
+	}
+}
+
+/* Literal emission */
+
+sieve_size_t sieve_binary_emit_integer
+(struct sieve_binary_block *sblock, sieve_number_t integer)
+{
+	sieve_size_t address = _sieve_binary_block_get_size(sblock);
+	int i;
+	char buffer[sizeof(sieve_number_t) + 1];
+	int bufpos = sizeof(buffer) - 1;
+  
+	buffer[bufpos] = integer & 0x7F;
+	bufpos--;
+	integer >>= 7;
+	while ( integer > 0 ) {
+		buffer[bufpos] = integer & 0x7F;
+		bufpos--;
+		integer >>= 7;  
+	}
+  
+	bufpos++;
+	if ( (sizeof(buffer) - bufpos) > 1 ) { 
+		for ( i = bufpos; i < ((int) sizeof(buffer) - 1); i++) {
+			buffer[i] |= 0x80;
+		}
+	} 
+  
+	_sieve_binary_emit_data
+		(sblock, buffer + bufpos, sizeof(buffer) - bufpos);
+
+	return address;
+}
+
+static inline sieve_size_t sieve_binary_emit_dynamic_data
+(struct sieve_binary_block *sblock, const void *data, sieve_size_t size)
+{
+	sieve_size_t address = sieve_binary_emit_integer
+		(sblock, (sieve_number_t) size);
+
+	_sieve_binary_emit_data(sblock, data, size);
+  
+	return address;
+}
+
+sieve_size_t sieve_binary_emit_cstring
+(struct sieve_binary_block *sblock, const char *str)
+{
+	sieve_size_t address = sieve_binary_emit_dynamic_data
+		(sblock, (void *) str, (sieve_size_t) strlen(str));
+	_sieve_binary_emit_byte(sblock, 0);
+  
+	return address;
+}
+
+sieve_size_t sieve_binary_emit_string
+(struct sieve_binary_block *sblock, const string_t *str)
+{
+	sieve_size_t address = sieve_binary_emit_dynamic_data
+		(sblock, (void *) str_data(str), (sieve_size_t) str_len(str));
+	_sieve_binary_emit_byte(sblock, 0);
+	
+	return address;
+}
+
+/*
+ * Extension emission
+ */
+
+sieve_size_t sieve_binary_emit_extension
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
+	unsigned int offset)
+{
+	sieve_size_t address = _sieve_binary_block_get_size(sblock);
+	struct sieve_binary_extension_reg *ereg = NULL;
+
+	(void)sieve_binary_extension_register(sblock->sbin, ext, &ereg);
+
+	i_assert(ereg != NULL);
+
+	_sieve_binary_emit_byte(sblock, offset + ereg->index);
+	return address;
+}
+
+void sieve_binary_emit_extension_object
+(struct sieve_binary_block *sblock, const struct sieve_extension_objects *objs,
+	unsigned int code)
+{
+	if ( objs->count > 1 )
+		_sieve_binary_emit_byte(sblock, code);
+}
+
+/*
+ * Code retrieval
+ */
+
+#define ADDR_CODE_READ(block) \
+	size_t _code_size; \
+	const signed char *_code = buffer_get_data((block)->data, &_code_size)
+ 
+#define ADDR_CODE_AT(address) \
+	((signed char) (_code[*address]))
+#define ADDR_DATA_AT(address) \
+	((unsigned char) (_code[*address]))
+#define ADDR_POINTER(address) \
+	((const char *) (&_code[*address]))
+
+#define ADDR_BYTES_LEFT(address) \
+	((_code_size) - (*address))
+#define ADDR_JUMP(address, offset) \
+	(*address) += offset
+
+/* Literals */
+
+bool sieve_binary_read_byte
+(struct sieve_binary_block *sblock, sieve_size_t *address, unsigned int *byte_r) 
+{
+	ADDR_CODE_READ(sblock);
+	
+	if ( ADDR_BYTES_LEFT(address) >= 1 ) {
+		if ( byte_r != NULL )
+			*byte_r = ADDR_DATA_AT(address);
+		ADDR_JUMP(address, 1);
+			
+		return TRUE;
+	}
+	
+	*byte_r = 0;
+	return FALSE;
+}
+
+bool sieve_binary_read_code
+(struct sieve_binary_block *sblock, sieve_size_t *address, signed int *code_r) 
+{	
+	ADDR_CODE_READ(sblock);
+
+	if ( ADDR_BYTES_LEFT(address) >= 1 ) {
+		if ( code_r != NULL )
+			*code_r = ADDR_CODE_AT(address);
+		ADDR_JUMP(address, 1);
+			
+		return TRUE;
+	}
+	
+	*code_r = 0;
+	return FALSE;
+}
+
+
+bool sieve_binary_read_offset
+(struct sieve_binary_block *sblock, sieve_size_t *address, int *offset_r) 
+{
+	uint32_t offs = 0;
+	ADDR_CODE_READ(sblock);
+	
+	if ( ADDR_BYTES_LEFT(address) >= 4 ) {
+		int i; 
+	  
+		for ( i = 0; i < 4; i++ ) {
+			offs = (offs << 8) + ADDR_DATA_AT(address);
+			ADDR_JUMP(address, 1);
+		}
+	  
+		if ( offset_r != NULL )
+			*offset_r = (int) offs;
+			
+		return TRUE;
+	}
+	
+	return FALSE;
+}
+
+/* FIXME: might need negative numbers in the future */
+bool sieve_binary_read_integer
+(struct sieve_binary_block *sblock, sieve_size_t *address, sieve_number_t *int_r) 
+{
+	int bits = sizeof(sieve_number_t) * 8;
+	*int_r = 0;
+
+	ADDR_CODE_READ(sblock);
+  
+	if ( ADDR_BYTES_LEFT(address) == 0 )
+		return FALSE;
+  
+	while ( (ADDR_DATA_AT(address) & 0x80) > 0 ) {
+		if ( ADDR_BYTES_LEFT(address) > 0 && bits > 0) {
+			*int_r |= ADDR_DATA_AT(address) & 0x7F;
+			ADDR_JUMP(address, 1);
+    
+			*int_r <<= 7;
+			bits -= 7;
+		} else {
+			/* This is an error */
+			return FALSE;
+		}
+	}
+  
+	*int_r |= ADDR_DATA_AT(address) & 0x7F;
+	ADDR_JUMP(address, 1);
+  
+	return TRUE;
+}
+
+bool sieve_binary_read_string
+(struct sieve_binary_block *sblock, sieve_size_t *address, string_t **str_r) 
+{
+	unsigned int strlen = 0;
+
+	ADDR_CODE_READ(sblock);
+  
+	if ( !sieve_binary_read_unsigned(sblock, address, &strlen) ) 
+		return FALSE;
+    	  
+	if ( strlen > ADDR_BYTES_LEFT(address) ) 
+		return FALSE;
+ 
+ 	if ( str_r != NULL )  
+		*str_r = t_str_new_const(ADDR_POINTER(address), strlen);
+	ADDR_JUMP(address, strlen);
+	
+	if ( ADDR_CODE_AT(address) != 0 )
+		return FALSE;
+	
+	ADDR_JUMP(address, 1);
+  
+	return TRUE;
+}
+
+bool sieve_binary_read_extension
+(struct sieve_binary_block *sblock, sieve_size_t *address, 
+	unsigned int *offset_r, const struct sieve_extension **ext_r)
+{
+	unsigned int code;
+	unsigned int offset = *offset_r;
+	const struct sieve_extension *ext = NULL;
+
+	ADDR_CODE_READ(sblock);
+
+	if ( ADDR_BYTES_LEFT(address) <= 0 )
+		return FALSE;
+
+	(*offset_r) = code = ADDR_DATA_AT(address);
+	ADDR_JUMP(address, 1);
+
+	if ( code >= offset ) {
+		ext = sieve_binary_extension_get_by_index(sblock->sbin, code - offset);
+		
+		if ( ext == NULL ) 
+			return FALSE;
+	}
+
+	(*ext_r) = ext;
+
+	return TRUE;
+}
+
+const void *sieve_binary_read_extension_object
+(struct sieve_binary_block *sblock, sieve_size_t *address, 
+	const struct sieve_extension_objects *objs)
+{
+	unsigned int code;
+
+	ADDR_CODE_READ(sblock);
+
+	if ( objs->count == 0 ) 
+		return NULL;
+
+	if ( objs->count == 1 )
+		return objs->objects;
+
+	if ( ADDR_BYTES_LEFT(address) <= 0 )
+		return NULL;
+
+	code = ADDR_DATA_AT(address);
+	ADDR_JUMP(address, 1);	
+
+	if ( code >= objs->count )
+		return NULL;
+
+	return ((const void *const *) objs->objects)[code];
+}
diff --git a/src/lib-sieve/sieve-binary-debug.c b/src/lib-sieve/sieve-binary-debug.c
new file mode 100644
index 000000000..af71c6d24
--- /dev/null
+++ b/src/lib-sieve/sieve-binary-debug.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-code.h"
+
+#include "sieve-binary-private.h"
+
+/* Quick 'n dirty debug */
+#if 0
+#define debug_printf(...) printf ("lineinfo: " __VA_ARGS__)
+#else
+#define debug_printf(...) 
+#endif
+
+/*
+ * Opcodes
+ */
+
+enum {
+	LINPROG_OP_COPY,
+	LINPROG_OP_ADVANCE_PC,
+	LINPROG_OP_ADVANCE_LINE,
+	LINPROG_OP_SET_COLUMN,
+	LINPROG_OP_SPECIAL_BASE
+};
+
+#define LINPROG_LINE_BASE   0
+#define LINPROG_LINE_RANGE  4
+
+/*
+ * Lineinfo writer
+ */
+
+struct sieve_binary_debug_writer {
+	struct sieve_binary_block *sblock;
+
+	sieve_size_t address;
+	unsigned long int line;
+	unsigned long int column;
+};
+
+struct sieve_binary_debug_writer *sieve_binary_debug_writer_init
+(struct sieve_binary_block *sblock)
+{
+	struct sieve_binary_debug_writer *dwriter;
+
+	dwriter = i_new(struct sieve_binary_debug_writer, 1);
+	dwriter->sblock = sblock;
+
+	return dwriter;
+}
+
+void sieve_binary_debug_writer_deinit
+(struct sieve_binary_debug_writer **dwriter)
+{
+	i_free(*dwriter);
+	*dwriter = NULL;
+}
+
+void sieve_binary_debug_emit
+(struct sieve_binary_debug_writer *dwriter, sieve_size_t code_address, 
+	unsigned int code_line, unsigned int code_column)
+{
+	struct sieve_binary_block *sblock = dwriter->sblock;
+	sieve_size_t address_inc = code_address - dwriter->address;
+	unsigned int line_inc = code_line - dwriter->line;
+	unsigned int sp_opcode = 0;
+	
+	/* Check for applicability of special opcode */
+	if ( (LINPROG_LINE_BASE + LINPROG_LINE_RANGE - 1) >= line_inc ) {
+		sp_opcode = LINPROG_OP_SPECIAL_BASE + (line_inc - LINPROG_LINE_BASE) + 
+			(LINPROG_LINE_RANGE * address_inc);
+		
+		if ( sp_opcode > 255 )
+			sp_opcode = 0;
+	}
+
+	/* Update line and address */
+	if ( sp_opcode == 0 ) {
+		if ( line_inc > 0 ) {
+			(void)sieve_binary_emit_byte(sblock, LINPROG_OP_ADVANCE_LINE);
+			(void)sieve_binary_emit_unsigned(sblock, line_inc);
+		}
+
+		if ( address_inc > 0 ) {
+			(void)sieve_binary_emit_byte(sblock, LINPROG_OP_ADVANCE_PC);
+			(void)sieve_binary_emit_unsigned(sblock, address_inc);
+		}
+	} else {
+		(void)sieve_binary_emit_byte(sblock, sp_opcode); 	
+	}
+
+	/* Set column */
+	if ( dwriter->column != code_column ) {
+		(void)sieve_binary_emit_byte(sblock, LINPROG_OP_SET_COLUMN);
+		(void)sieve_binary_emit_unsigned(sblock, code_column);
+	}
+
+	/* Generate matrix row */
+	(void)sieve_binary_emit_byte(sblock, LINPROG_OP_COPY);
+
+	dwriter->address = code_address;
+	dwriter->line = code_line;
+	dwriter->column = code_column;
+}
+
+/*
+ * Debug reader
+ */
+
+struct sieve_binary_debug_reader {
+	struct sieve_binary_block *sblock;
+
+	sieve_size_t address, last_address;
+	unsigned long int line, last_line;
+
+	unsigned long int column;
+
+	sieve_size_t state;
+};
+
+struct sieve_binary_debug_reader *sieve_binary_debug_reader_init
+(struct sieve_binary_block *sblock)
+{
+	struct sieve_binary_debug_reader *dreader;
+
+	dreader = i_new(struct sieve_binary_debug_reader, 1);
+	dreader->sblock = sblock;
+
+	return dreader;
+}
+
+void sieve_binary_debug_reader_deinit
+(struct sieve_binary_debug_reader **dreader)
+{
+	i_free(*dreader);
+	*dreader = NULL;
+}
+
+void sieve_binary_debug_reader_reset
+(struct sieve_binary_debug_reader *dreader)
+{
+	dreader->address = 0;
+	dreader->line = 0;
+	dreader->column = 0;
+	dreader->state = 0;
+}
+
+unsigned int sieve_binary_debug_read_line
+(struct sieve_binary_debug_reader *dreader, sieve_size_t code_address)
+{
+	size_t linprog_size; 
+	sieve_size_t address;
+	unsigned long int line;
+
+	if ( code_address < dreader->last_address )
+		sieve_binary_debug_reader_reset(dreader);
+
+	if ( code_address >= dreader->last_address && 
+		code_address < dreader->address ) {
+		debug_printf("%08llx: NOOP [%08llx]\n", 
+			(unsigned long long) dreader->state, (unsigned long long) code_address);
+		return dreader->last_line;
+	}
+
+	address = dreader->address;
+	line = dreader->line;
+
+	debug_printf("%08llx: READ [%08llx]\n", 
+		(unsigned long long) dreader->state, (unsigned long long) code_address);
+
+	linprog_size = sieve_binary_block_get_size(dreader->sblock);
+	while ( dreader->state < linprog_size ) {
+		unsigned int opcode;
+		unsigned int value;
+
+		if ( sieve_binary_read_byte(dreader->sblock, &dreader->state, &opcode) ) {
+			switch ( opcode ) {
+
+			case LINPROG_OP_COPY:
+				debug_printf("%08llx: COPY ==> %08llx: %ld\n", 
+					(unsigned long long) dreader->state, (unsigned long long) address, 
+					line);
+			
+				dreader->last_address = dreader->address;				
+				dreader->last_line = dreader->line;				
+
+				dreader->address = address;
+				dreader->line = line;
+
+				if ( code_address < address ) {
+					return dreader->last_line;
+				} else if ( code_address == address ) {
+					return dreader->line;
+				}
+				break;
+
+			case LINPROG_OP_ADVANCE_PC:
+				debug_printf("%08llx: ADV_PC\n", (unsigned long long) dreader->state);
+				if ( !sieve_binary_read_unsigned
+					(dreader->sblock, &dreader->state, &value) ) {
+					sieve_binary_debug_reader_reset(dreader);
+					return 0;
+				}
+				debug_printf("        : + %d\n", value);
+				address += value;
+				break;
+
+			case LINPROG_OP_ADVANCE_LINE:
+				debug_printf("%08llx: ADV_LINE\n", (unsigned long long) dreader->state);
+				if ( !sieve_binary_read_unsigned
+					(dreader->sblock, &dreader->state, &value) ) {
+					sieve_binary_debug_reader_reset(dreader);
+					return 0;
+				}
+				debug_printf("        : + %d\n", value);
+				line += value;
+				break;
+
+			case LINPROG_OP_SET_COLUMN:
+				debug_printf("%08llx: SET_COL\n", (unsigned long long) dreader->state);
+				if ( !sieve_binary_read_unsigned
+					(dreader->sblock, &dreader->state, &value) ) {
+					sieve_binary_debug_reader_reset(dreader);
+					return 0;
+				}
+				debug_printf("        : = %d\n", value);
+				dreader->column = value;
+				break;			
+
+			default:
+				opcode -= LINPROG_OP_SPECIAL_BASE;
+
+				address += (opcode / LINPROG_LINE_RANGE);
+				line += LINPROG_LINE_BASE + (opcode % LINPROG_LINE_RANGE);
+
+				debug_printf("%08llx: SPECIAL\n", (unsigned long long) dreader->state);
+				debug_printf("        :  +A %d +L %d\n", (opcode / LINPROG_LINE_RANGE),
+					LINPROG_LINE_BASE + (opcode % LINPROG_LINE_RANGE));				
+				break;
+			}
+		} else {
+			debug_printf("OPCODE READ FAILED\n");
+			sieve_binary_debug_reader_reset(dreader);
+			return 0;
+		}
+	}
+
+	return dreader->line;
+}
+
diff --git a/src/lib-sieve/sieve-binary-dumper.c b/src/lib-sieve/sieve-binary-dumper.c
index cb9ffabc8..455b4fe84 100644
--- a/src/lib-sieve/sieve-binary-dumper.c
+++ b/src/lib-sieve/sieve-binary-dumper.c
@@ -23,7 +23,7 @@ struct sieve_binary_dumper {
 };
 
 struct sieve_binary_dumper *sieve_binary_dumper_create
-	(struct sieve_binary *sbin) 
+(struct sieve_binary *sbin) 
 {
 	pool_t pool;
 	struct sieve_binary_dumper *dumper;
@@ -91,25 +91,52 @@ void sieve_binary_dump_sectionf
  */
 
 bool sieve_binary_dumper_run
-(struct sieve_binary_dumper *dumper, struct ostream *stream) 
+(struct sieve_binary_dumper *dumper, struct ostream *stream, bool verbose) 
 {	
 	struct sieve_binary *sbin = dumper->dumpenv.sbin;
 	struct sieve_dumptime_env *denv = &(dumper->dumpenv);
 	int count, i;
 	
 	dumper->dumpenv.stream = stream;
+
+	/* Dump list of binary blocks */
+	if ( verbose ) {
+		count = sieve_binary_block_count(sbin);
+
+		sieve_binary_dump_sectionf
+			(denv, "Binary blocks (count: %d)", count);
+
+		for ( i = 0; i < count; i++ ) {
+			struct sieve_binary_block *sblock = sieve_binary_block_get(sbin, i);
+
+			sieve_binary_dumpf(denv, 
+				"%3d: size: %"PRIuSIZE_T" bytes\n", i, 
+				sieve_binary_block_get_size(sblock));
+		}
+	}
 	
 	/* Dump list of used extensions */
 	
 	count = sieve_binary_extensions_count(sbin);
 	if ( count > 0 ) {
-		sieve_binary_dump_sectionf(denv, "Required extensions");
+		sieve_binary_dump_sectionf
+			(denv, "Required extensions (block: %d)", SBIN_SYSBLOCK_EXTENSIONS);
 	
 		for ( i = 0; i < count; i++ ) {
 			const struct sieve_extension *ext = sieve_binary_extension_get_by_index
 				(sbin, i);
-			sieve_binary_dumpf(denv, "%3d: %s (%d)\n", i, sieve_extension_name(ext), 
-				ext->id);
+
+			struct sieve_binary_block *sblock = sieve_binary_extension_get_block
+				(sbin, ext);
+	
+			if ( sblock == NULL ) {
+				sieve_binary_dumpf(denv, "%3d: %s (id: %d)\n", 
+					i, sieve_extension_name(ext), ext->id);
+			} else {
+				sieve_binary_dumpf(denv, "%3d: %s (id: %d; block: %d)\n", 
+					i, sieve_extension_name(ext), ext->id, 
+					sieve_binary_block_get_id(sblock));
+			}
 		}
 	}
 
@@ -135,12 +162,11 @@ bool sieve_binary_dumper_run
 	
 	/* Dump main program */
 	
-	sieve_binary_dump_sectionf(denv, "Main program (block: %d)", SBIN_SYSBLOCK_MAIN_PROGRAM);
-
-	if ( !sieve_binary_block_set_active(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM, NULL) ) {
-        return FALSE;
-	}
+	sieve_binary_dump_sectionf
+		(denv, "Main program (block: %d)", SBIN_SYSBLOCK_MAIN_PROGRAM);
 
+	dumper->dumpenv.sblock = 
+		sieve_binary_block_get(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM);
 	dumper->dumpenv.cdumper = sieve_code_dumper_create(&(dumper->dumpenv));
 
 	if ( dumper->dumpenv.cdumper != NULL ) {
diff --git a/src/lib-sieve/sieve-binary-dumper.h b/src/lib-sieve/sieve-binary-dumper.h
index 7c55bfcb8..47ff81981 100644
--- a/src/lib-sieve/sieve-binary-dumper.h
+++ b/src/lib-sieve/sieve-binary-dumper.h
@@ -34,7 +34,7 @@ void sieve_binary_dump_sectionf
  */
 
 bool sieve_binary_dumper_run
-	(struct sieve_binary_dumper *dumper, struct ostream *stream);
+	(struct sieve_binary_dumper *dumper, struct ostream *stream, bool verbose);
 
 
 #endif /* __SIEVE_BINARY_DUMPER_H */
diff --git a/src/lib-sieve/sieve-binary-file.c b/src/lib-sieve/sieve-binary-file.c
new file mode 100644
index 000000000..47ab4c955
--- /dev/null
+++ b/src/lib-sieve/sieve-binary-file.c
@@ -0,0 +1,839 @@
+/* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "mempool.h"
+#include "buffer.h"
+#include "hash.h"
+#include "array.h"
+#include "ostream.h"
+#include "eacces-error.h"	
+#include "safe-mkstemp.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-script.h"
+
+#include "sieve-binary-private.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/*
+ * Macros
+ */
+
+#define SIEVE_BINARY_MAGIC              0xcafebabe
+#define SIEVE_BINARY_MAGIC_OTHER_ENDIAN 0xbebafeca 
+
+#define SIEVE_BINARY_ALIGN(offset) \
+	(((offset) + 3) & ~3)
+#define SIEVE_BINARY_ALIGN_PTR(ptr) \
+	((void *) SIEVE_BINARY_ALIGN(((size_t) ptr)))
+
+/*
+ * Header and record structures of the binary on disk 
+ */
+ 
+struct sieve_binary_header {
+	uint32_t magic;
+	uint16_t version_major;
+	uint16_t version_minor;
+	uint32_t blocks;
+};
+
+struct sieve_binary_block_index {
+	uint32_t id;
+	uint32_t size;
+	uint32_t offset;
+	uint32_t ext_id;
+};
+
+struct sieve_binary_block_header {
+	uint32_t id; 
+	uint32_t size;
+};
+
+/* 
+ * Saving the binary to a file. 
+ */
+
+static inline bool _save_skip(struct ostream *stream, size_t size)
+{	
+	if ( (o_stream_seek(stream, stream->offset + size)) <= 0 ) 
+		return FALSE;
+		
+	return TRUE;
+}
+
+static inline bool _save_skip_aligned
+(struct ostream *stream, size_t size, uoff_t *offset)
+{
+	uoff_t aligned_offset = SIEVE_BINARY_ALIGN(stream->offset);
+	
+	if ( (o_stream_seek(stream, aligned_offset + size)) <= 0 ) 
+		return FALSE;
+		
+	if ( offset != NULL )
+		*offset = aligned_offset;
+		
+	return TRUE;
+}
+
+/* FIXME: Is this even necessary for a file? */
+static bool _save_full(struct ostream *stream, const void *data, size_t size)
+{
+	size_t bytes_left = size;
+	const void *pdata = data;
+	
+	while ( bytes_left > 0 ) {
+		ssize_t ret;
+		
+		if ( (ret=o_stream_send(stream, pdata, bytes_left)) <= 0 ) 
+			return FALSE;
+			
+		pdata = PTR_OFFSET(pdata, ret);
+		bytes_left -= ret;
+	}	
+	
+	return TRUE;
+}
+
+static bool _save_aligned
+(struct ostream *stream, const void *data, size_t size, uoff_t *offset)
+{	
+	uoff_t aligned_offset = SIEVE_BINARY_ALIGN(stream->offset);
+
+	o_stream_cork(stream);
+	
+	/* Align the data by adding zeroes to the output stream */
+	if ( stream->offset < aligned_offset ) {
+		if ( !_save_skip(stream, aligned_offset - stream->offset) ) 
+			return FALSE;
+	}
+	
+	if ( !_save_full(stream, data, size) )
+		return FALSE;
+	
+	o_stream_uncork(stream); 
+
+	if ( offset != NULL )
+		*offset = aligned_offset;
+
+	return TRUE;
+} 
+
+static bool _save_block
+(struct sieve_binary *sbin, struct ostream *stream, unsigned int id)
+{
+	struct sieve_binary_block_header block_header;
+	struct sieve_binary_block *block;
+	const void *data;
+	size_t size;
+		
+	block = sieve_binary_block_get(sbin, id);
+	if ( block == NULL )
+		return FALSE;
+		
+	data = buffer_get_data(block->data, &size);
+	
+	block_header.id = id;
+	block_header.size = size;
+	
+	if ( !_save_aligned(stream, &block_header,
+		sizeof(block_header), &block->offset) )
+		return FALSE;
+	
+	return _save_aligned(stream, data, size, NULL);
+}
+
+static bool _save_block_index_record
+(struct sieve_binary *sbin, struct ostream *stream, unsigned int id)
+{
+	struct sieve_binary_block *block;
+	struct sieve_binary_block_index header;
+	
+	block = sieve_binary_block_get(sbin, id);
+	if ( block == NULL )
+		return FALSE;
+	
+	header.id = id;
+	header.size = buffer_get_used_size(block->data);
+	header.ext_id = block->ext_index;
+	header.offset = block->offset;
+	
+	if ( !_save_full(stream, &header, sizeof(header)) ) {
+		sieve_sys_error("failed to save block index header %d: %m", id);
+		
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+static bool _sieve_binary_save
+(struct sieve_binary *sbin, struct ostream *stream)
+{
+	struct sieve_binary_header header;
+	struct sieve_binary_extension_reg *const *regs;
+	struct sieve_binary_block *ext_block;
+	unsigned int ext_count, blk_count, i;
+	uoff_t block_index;
+	
+	blk_count = sieve_binary_block_count(sbin);
+	
+	/* Signal all extensions to finish generating their blocks */
+	
+	regs = array_get(&sbin->extensions, &ext_count);	
+	for ( i = 0; i < ext_count; i++ ) {
+		const struct sieve_binary_extension *binext = regs[i]->binext;
+		
+		if ( binext != NULL && binext->binary_save != NULL )
+			binext->binary_save(regs[i]->extension, sbin, regs[i]->context);
+	}
+		
+	/* Create header */
+	
+	header.magic = SIEVE_BINARY_MAGIC;
+	header.version_major = SIEVE_BINARY_VERSION_MAJOR;
+	header.version_minor = SIEVE_BINARY_VERSION_MINOR;
+	header.blocks = blk_count;
+
+	if ( !_save_aligned(stream, &header, sizeof(header), NULL) ) {
+		sieve_sys_error("failed to save binary header: %m");
+		return FALSE;
+	} 
+	
+	/* Skip block index for now */
+	
+	if ( !_save_skip_aligned(stream, 
+		sizeof(struct sieve_binary_block_index) * blk_count, &block_index) )
+		return FALSE;
+	
+	/* Create block containing all used extensions 
+	 *   FIXME: Per-extension this should also store binary version numbers.
+	 */
+	ext_block = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_EXTENSIONS);
+	i_assert( ext_block != NULL );
+		
+	ext_count = array_count(&sbin->linked_extensions);
+	sieve_binary_emit_unsigned(ext_block, ext_count);
+	
+	for ( i = 0; i < ext_count; i++ ) {
+		struct sieve_binary_extension_reg * const *ext
+			= array_idx(&sbin->linked_extensions, i);
+		
+		sieve_binary_emit_cstring
+			(ext_block, sieve_extension_name((*ext)->extension));
+		sieve_binary_emit_unsigned(ext_block, (*ext)->block_id);
+	}
+		
+	/* Save all blocks into the binary */
+	
+	for ( i = 0; i < blk_count; i++ ) {
+		if ( !_save_block(sbin, stream, i) ) 
+			return FALSE;
+	}
+	
+	/* Create the block index */
+	o_stream_seek(stream, block_index);
+	for ( i = 0; i < blk_count; i++ ) {
+		if ( !_save_block_index_record(sbin, stream, i) ) 
+			return FALSE;
+	}
+
+	return TRUE;
+} 
+
+bool sieve_binary_save
+(struct sieve_binary *sbin, const char *path)
+{
+	bool result = TRUE;
+	string_t *temp_path;
+	struct ostream *stream;
+	int fd;
+	mode_t save_mode =
+		sbin->script == NULL ? 0600 : sieve_script_permissions(sbin->script);
+	
+	/* Use default path if none is specified */
+	if ( path == NULL ) {
+		if ( sbin->script == NULL ) {
+			sieve_sys_error("cannot determine default binary save path "
+				"with missing script object");
+        	return FALSE;
+		}
+		path = sieve_script_binpath(sbin->script);
+	}
+
+	/* Open it as temp file first, as not to overwrite an existing just yet */
+	temp_path = t_str_new(256);
+	str_append(temp_path, path);
+	fd = safe_mkstemp_hostpid(temp_path, save_mode, (uid_t)-1, (gid_t)-1);
+	if ( fd < 0 ) {
+		if ( errno == EACCES ) {
+			sieve_sys_error("failed to save binary temporary file: %s",
+				eacces_error_get_creating("open", str_c(temp_path)));
+		} else {
+			sieve_sys_error("failed to save binary temporary file: "
+				"open(%s) failed: %m", str_c(temp_path));
+		}
+		return FALSE;
+	}
+
+	/* Save binary */
+	stream = o_stream_create_fd(fd, 0, FALSE);
+	result = _sieve_binary_save(sbin, stream);
+	o_stream_destroy(&stream);
+
+	/* Close saved binary */ 
+	if ( close(fd) < 0 ) {
+		sieve_sys_error("failed to close saved binary temporary file: "
+			"close(fd=%s) failed: %m", str_c(temp_path));
+	}
+
+	/* Replace any original binary atomically */
+	if ( result && (rename(str_c(temp_path), path) < 0) ) {
+		if ( errno == EACCES ) {
+			sieve_sys_error("failed to replace existing binary: %s", 
+				eacces_error_get_creating("rename", path));			
+		} else { 		
+			sieve_sys_error("failed to replace existing binary: "
+				"rename(%s, %s) failed: %m", str_c(temp_path), path);
+		}
+		result = FALSE;
+	}
+
+	if ( !result ) {
+		/* Get rid of temp output (if any) */
+		(void) unlink(str_c(temp_path));
+	} else {
+		if ( sbin->path == NULL || strcmp(sbin->path, path) != 0 ) {
+			sbin->path = p_strdup(sbin->pool, path);
+		}
+	}
+	
+	return result;
+}
+
+/* 
+ * Binary file management 
+ */
+
+bool sieve_binary_file_open
+	(struct sieve_binary_file *file, const char *path)
+{
+	int fd;
+	struct stat st;
+	
+	if ( (fd=open(path, O_RDONLY)) < 0 ) {
+		if ( errno != ENOENT ) {
+			if ( errno == EACCES ) {
+				sieve_sys_error("failed to open binary: %s", 
+					eacces_error_get("open", path));			
+			} else {
+				sieve_sys_error("failed to open binary: "
+					"open(%s) failed: %m", path);
+			}
+		}
+		return FALSE;
+	}
+
+	if ( fstat(fd, &st) < 0 ) {
+		if ( errno != ENOENT ) {
+			sieve_sys_error("failed to open binary: "
+				"fstat(fd=%s) failed: %m", path);
+		}
+		return FALSE;
+	}
+
+	if ( !S_ISREG(st.st_mode) ) {
+		sieve_sys_error("binary %s is not a regular file", path);
+		return FALSE;		
+	}
+	
+	file->fd = fd;
+	file->st = st;
+
+	return TRUE;
+}
+	
+void sieve_binary_file_close(struct sieve_binary_file **file)
+{
+	if ( (*file)->fd != -1 ) {
+		if ( close((*file)->fd) < 0 ) {
+			sieve_sys_error("failed to close opened binary: "
+				"close(fd=%s) failed: %m", (*file)->path);
+		}
+	}
+
+	pool_unref(&(*file)->pool);
+	
+	*file = NULL;
+}
+
+#if 0 /* file_memory is currently unused */
+
+/* File loaded/mapped to memory */
+
+struct _file_memory {
+	struct sieve_binary_file binfile;
+
+	/* Pointer to the binary in memory */
+	const void *memory;
+	off_t memory_size;
+};
+
+static const void *_file_memory_load_data
+	(struct sieve_binary_file *file, off_t *offset, size_t size)
+{	
+	struct _file_memory *fmem = (struct _file_memory *) file;
+
+	*offset = SIEVE_BINARY_ALIGN(*offset);
+
+	if ( (*offset) + size <= fmem->memory_size ) {
+		const void *data = PTR_OFFSET(fmem->memory, *offset);
+		*offset += size;
+		file->offset = *offset;
+		
+		return data;
+	}
+		
+	return NULL;
+}
+
+static buffer_t *_file_memory_load_buffer
+	(struct sieve_binary_file *file, off_t *offset, size_t size)
+{	
+	struct _file_memory *fmem = (struct _file_memory *) file;
+
+	*offset = SIEVE_BINARY_ALIGN(*offset);
+
+	if ( (*offset) + size <= fmem->memory_size ) {
+		const void *data = PTR_OFFSET(fmem->memory, *offset);
+		*offset += size;
+		file->offset = *offset;
+		
+		return buffer_create_const_data(file->pool, data, size);
+	}
+	
+	return NULL;
+}
+
+static bool _file_memory_load(struct sieve_binary_file *file)
+{
+	struct _file_memory *fmem = (struct _file_memory *) file;
+	int ret;
+	size_t size;
+	void *indata;
+		
+	i_assert(file->fd > 0);
+		
+	/* Allocate memory buffer
+	 */
+	indata = p_malloc(file->pool, file->st.st_size);
+	size = file->st.st_size; 
+	
+	file->offset = 0; 
+	fmem->memory = indata;
+	fmem->memory_size = file->st.st_size;
+
+	/* Return to beginning of the file */
+	if ( lseek(file->fd, 0, SEEK_SET) == (off_t) -1 ) {
+		sieve_sys_error("failed to seek() in binary %s: %m", file->path);
+		return FALSE;
+	}	
+
+	/* Read the whole file into memory */
+	while (size > 0) {
+		if ( (ret=read(file->fd, indata, size)) <= 0 ) {
+			sieve_sys_error("failed to read from binary %s: %m", file->path);
+			break;
+		}
+		
+		indata = PTR_OFFSET(indata, ret);
+		size -= ret;
+	}	
+
+	if ( size != 0 ) {
+		/* Failed to read the whole file */
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+static struct sieve_binary_file *_file_memory_open(const char *path)
+{
+	pool_t pool;
+	struct _file_memory *file;
+	
+	pool = pool_alloconly_create("sieve_binary_file_memory", 1024);
+	file = p_new(pool, struct _file_memory, 1);
+	file->binfile.pool = pool;
+	file->binfile.path = p_strdup(pool, path);
+	file->binfile.load = _file_memory_load;
+	file->binfile.load_data = _file_memory_load_data;
+	file->binfile.load_buffer = _file_memory_load_buffer;
+	
+	if ( !sieve_binary_file_open(&file->binfile, path) ) {
+		pool_unref(&pool);
+		return NULL;
+	}
+
+	return &file->binfile;
+}
+
+#endif /* file_memory is currently unused */
+
+/* File open in lazy mode (only read what is needed into memory) */
+
+static bool _file_lazy_read
+(struct sieve_binary_file *file, off_t *offset, void *buffer, size_t size)
+{
+	int ret;
+	void *indata = buffer;
+	size_t insize = size;
+	
+	*offset = SIEVE_BINARY_ALIGN(*offset);
+	
+	/* Seek to the correct position */ 
+	if ( *offset != file->offset && 
+		lseek(file->fd, *offset, SEEK_SET) == (off_t) -1 ) {
+		sieve_sys_error("failed to seek(fd, %lld, SEEK_SET) in binary %s: %m", 
+			(long long) *offset, file->path);
+		return FALSE;
+	}	
+
+	/* Read record into memory */
+	while (insize > 0) {
+		if ( (ret=read(file->fd, indata, insize)) <= 0 ) {
+			if ( ret == 0 ) 
+				sieve_sys_error("binary %s is truncated (more data expected)", 
+					file->path);
+			else
+				sieve_sys_error("failed to read from binary %s: %m", file->path);
+			break;
+		}
+		
+		indata = PTR_OFFSET(indata, ret);
+		insize -= ret;
+	}	
+
+	if ( insize != 0 ) {
+		/* Failed to read the whole requested record */
+		return FALSE;
+	}
+	
+	*offset += size;
+	file->offset = *offset;
+
+	return TRUE;
+}
+
+static const void *_file_lazy_load_data
+(struct sieve_binary_file *file, off_t *offset, size_t size)
+{	
+	void *data = t_malloc(size);
+
+	if ( _file_lazy_read(file, offset, data, size) ) {
+		return data;
+	}
+	
+	return NULL;
+}
+
+static buffer_t *_file_lazy_load_buffer
+(struct sieve_binary_file *file, off_t *offset, size_t size)
+{			
+	buffer_t *buffer = buffer_create_dynamic(file->pool, size);
+	
+	if ( _file_lazy_read
+		(file, offset, buffer_get_space_unsafe(buffer, 0, size), size) ) {
+		return buffer;
+	}
+	
+	return NULL;
+}
+
+static struct sieve_binary_file *_file_lazy_open(const char *path)
+{
+	pool_t pool;
+	struct sieve_binary_file *file;
+	
+	pool = pool_alloconly_create("sieve_binary_file_lazy", 4096);
+	file = p_new(pool, struct sieve_binary_file, 1);
+	file->pool = pool;
+	file->path = p_strdup(pool, path);
+	file->load_data = _file_lazy_load_data;
+	file->load_buffer = _file_lazy_load_buffer;
+	
+	if ( !sieve_binary_file_open(file, path) ) {
+		pool_unref(&pool);
+		return NULL;
+	}
+
+	return file;
+}
+
+/* 
+ * Load binary from a file
+ */
+
+#define LOAD_HEADER(sbin, offset, header) \
+	(header *) sbin->file->load_data(sbin->file, offset, sizeof(header))
+
+bool sieve_binary_load_block
+(struct sieve_binary_block *sblock)
+{
+	struct sieve_binary *sbin = sblock->sbin;
+	unsigned int id = sblock->id;
+	off_t offset = sblock->offset;
+	const struct sieve_binary_block_header *header = 
+		LOAD_HEADER(sbin, &offset, const struct sieve_binary_block_header);
+		
+	if ( header == NULL ) {
+		sieve_sys_error
+			("block %d of loaded binary %s is truncated", id, sbin->path);
+		return FALSE;
+	}
+	
+	if ( header->id != id ) {
+		sieve_sys_error("block %d of loaded binary %s has unexpected id %d", id, 
+			sbin->path, header->id);
+		return FALSE;
+	}
+	
+	sblock->data = sbin->file->load_buffer(sbin->file, &offset, header->size);
+	if ( sblock->data == NULL ) {
+		sieve_sys_error("block %d of loaded binary %s has invalid size %d",
+			id, sbin->path, header->size);
+		return FALSE;
+	}
+		
+	return TRUE;
+}
+
+static bool _load_block_index_record
+(struct sieve_binary *sbin, off_t *offset, unsigned int id)
+{
+	const struct sieve_binary_block_index *record = 
+		LOAD_HEADER(sbin, offset, const struct sieve_binary_block_index);
+	struct sieve_binary_block *block;
+	
+	if ( record == NULL ) {
+		sieve_sys_error("failed to read index record for block %d in binary %s", 
+			id, sbin->path);
+		return FALSE;
+	}
+	
+	if ( record->id != id ) {
+		sieve_sys_error("block index record %d of loaded binary %s "
+			"has unexpected id %d", id, sbin->path, record->id);
+		return FALSE;
+	}
+	
+	block = sieve_binary_block_create_id(sbin, id);
+	block->ext_index = record->ext_id;
+	block->offset = record->offset;
+	
+	return TRUE;
+}
+
+static bool _sieve_binary_load_extensions(struct sieve_binary_block *sblock)
+{
+	struct sieve_binary *sbin = sblock->sbin;
+	sieve_size_t offset = 0;
+	unsigned int i, count;
+	bool result = TRUE;
+	
+	if ( !sieve_binary_read_unsigned(sblock, &offset, &count) )
+		return FALSE;
+	
+	for ( i = 0; result && i < count; i++ ) {
+		T_BEGIN {
+			string_t *extension;
+			const struct sieve_extension *ext;
+			
+			if ( sieve_binary_read_string(sblock, &offset, &extension) ) { 
+				ext = sieve_extension_get_by_name(sbin->svinst, str_c(extension));	
+			
+				if ( ext == NULL ) { 
+					sieve_sys_error("loaded binary %s requires unknown extension '%s'", 
+						sbin->path, str_sanitize(str_c(extension), 128));
+					result = FALSE;					
+				} else {
+					struct sieve_binary_extension_reg *ereg = NULL;
+					
+					(void) sieve_binary_extension_register(sbin, ext, &ereg);
+					if ( !sieve_binary_read_unsigned(sblock, &offset, &ereg->block_id) )
+						result = FALSE;
+				}
+			}	else
+				result = FALSE;
+		} T_END;
+	}		
+		
+	return result;
+}
+
+static bool _sieve_binary_open(struct sieve_binary *sbin)
+{
+	bool result = TRUE;
+	off_t offset = 0;
+	const struct sieve_binary_header *header;
+	struct sieve_binary_block *ext_block;
+	unsigned int i, blk_count;
+	
+	/* Verify header */
+	
+	T_BEGIN {
+		header = LOAD_HEADER(sbin, &offset, const struct sieve_binary_header);
+		if ( header == NULL ) {
+			sieve_sys_error("opened binary %s is not even large enough "
+				"to contain a header.", sbin->path);
+			result = FALSE;
+
+		} else if ( header->magic != SIEVE_BINARY_MAGIC ) {
+			if ( header->magic != SIEVE_BINARY_MAGIC_OTHER_ENDIAN ) 
+				sieve_sys_error("opened binary %s has corrupted header (0x%08x)", 
+					sbin->path, header->magic);
+			result = FALSE;
+
+		} else if ( result && (
+		  header->version_major != SIEVE_BINARY_VERSION_MAJOR || 
+			header->version_minor != SIEVE_BINARY_VERSION_MINOR ) ) {
+
+			/* Binary is of different version. Caller will have to recompile */
+			result = FALSE;
+
+		} else if ( result && header->blocks == 0 ) {
+			sieve_sys_error("opened binary %s contains no blocks", sbin->path);
+			result = FALSE; 
+
+		} else {
+			blk_count = header->blocks;
+		}
+	} T_END;
+	
+	if ( !result ) return FALSE;
+	
+	/* Load block index */
+	
+	for ( i = 0; i < blk_count && result; i++ ) {	
+		T_BEGIN {
+			if ( !_load_block_index_record(sbin, &offset, i) ) {
+				sieve_sys_error(
+					"block index record %d of opened binary %s is corrupt", 
+					i, sbin->path);
+				result = FALSE;
+			}
+		} T_END;
+	}
+	
+	if ( !result ) return FALSE;
+	
+	/* Load extensions used by this binary */
+	
+	T_BEGIN {
+		ext_block = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_EXTENSIONS);
+		if ( ext_block == NULL ) {
+			result = FALSE;
+		} else {
+			if ( !_sieve_binary_load_extensions(ext_block) ) {
+				sieve_sys_error("extension block of opened binary %s is corrupt", 
+					sbin->path);
+				result = FALSE;
+			}
+		}
+	} T_END;
+		
+	return result;
+}
+
+static bool _sieve_binary_load(struct sieve_binary *sbin) 
+{	
+	bool result = TRUE;
+	unsigned int i, blk_count;
+	
+	blk_count = array_count(&sbin->blocks);
+	if ( blk_count == 1 ) {
+		/* Binary is empty */
+		return TRUE;
+	}	
+
+	/* Load the other blocks */
+	
+	for ( i = 0; result && i < blk_count; i++ ) {	
+		T_BEGIN {
+			if ( sieve_binary_block_get(sbin, i) == NULL )
+				result = FALSE;
+		} T_END;
+	}
+				
+	return result;
+}
+
+struct sieve_binary *sieve_binary_open
+(struct sieve_instance *svinst, const char *path, struct sieve_script *script)
+{
+	struct sieve_binary_extension_reg *const *regs;
+	unsigned int ext_count, i;
+	struct sieve_binary *sbin;
+	struct sieve_binary_file *file;
+	
+	i_assert( script == NULL || sieve_script_svinst(script) == svinst );
+	
+	//file = _file_memory_open(path);	
+	file = _file_lazy_open(path);
+	if ( file == NULL )
+		return NULL;
+		
+	/* Create binary object */
+	sbin = sieve_binary_create(svinst, script);
+	sbin->path = p_strdup(sbin->pool, path);
+	sbin->file = file;
+	
+	if ( !_sieve_binary_open(sbin) ) {
+		sieve_binary_unref(&sbin);
+		return NULL;
+	}
+	
+	sieve_binary_activate(sbin);
+	
+	/* Signal open event to extensions */
+	regs = array_get(&sbin->extensions, &ext_count);	
+	for ( i = 0; i < ext_count; i++ ) {
+		const struct sieve_binary_extension *binext = regs[i]->binext;
+		
+		if ( binext != NULL && binext->binary_open != NULL && 
+			!binext->binary_open(regs[i]->extension, sbin, regs[i]->context) ) {
+			/* Extension thinks its corrupt */
+			sieve_binary_unref(&sbin);
+			return NULL;
+		}
+	}	
+
+	return sbin;
+}
+
+bool sieve_binary_load(struct sieve_binary *sbin)
+{
+	i_assert(sbin->file != NULL);
+
+	/*
+	if ( sbin->file->load != NULL && !sbin->file->load(sbin->file) )
+		return FALSE;	*/		
+	
+	if ( !_sieve_binary_load(sbin) ) {
+		/* Failed to interpret binary header and/or block structure */
+		return FALSE;
+	}
+	
+	return TRUE;
+}
diff --git a/src/lib-sieve/sieve-binary-private.h b/src/lib-sieve/sieve-binary-private.h
new file mode 100644
index 000000000..c63cacb8d
--- /dev/null
+++ b/src/lib-sieve/sieve-binary-private.h
@@ -0,0 +1,208 @@
+/* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file
+ */
+
+#ifndef __SIEVE_BINARY_PRIVATE_H
+#define __SIEVE_BINARY_PRIVATE_H
+
+#include "sieve-common.h"
+#include "sieve-binary.h"
+#include "sieve-extensions.h"
+
+#include <sys/stat.h>
+
+/*
+ * Binary file
+ */
+
+struct sieve_binary_file {
+	pool_t pool;
+	const char *path;
+	
+	struct stat st;
+	int fd;
+	off_t offset;
+
+	bool (*load)(struct sieve_binary_file *file);	
+	const void *(*load_data)
+		(struct sieve_binary_file *file, off_t *offset, size_t size);
+	buffer_t *(*load_buffer)
+		(struct sieve_binary_file *file, off_t *offset, size_t size);
+};
+
+bool sieve_binary_file_open
+	(struct sieve_binary_file *file, const char *path);
+void sieve_binary_file_close(struct sieve_binary_file **file);
+
+/* 
+ * Internal structures
+ */
+
+/* Extension registration */
+
+struct sieve_binary_extension_reg {
+	/* The identifier of the extension within this binary */
+	int index;
+	
+	/* Global extension object */
+	const struct sieve_extension *extension; 
+	
+	/* Extension to the binary; typically used to manage extension-specific blocks 
+	 * in the binary and as a means to get a binary_free notification to release
+	 * references held by extensions. 
+	 */
+	const struct sieve_binary_extension *binext;	
+	
+	/* Context data associated to the binary by this extension */
+	void *context;
+	
+	/* Main block for this extension */
+	unsigned int block_id;
+};
+
+/* Block */
+
+struct sieve_binary_block {
+	struct sieve_binary *sbin;
+	unsigned int id;
+	int ext_index;
+
+	buffer_t *data;
+	
+	uoff_t offset;
+};
+
+/*
+ * Binary object
+ */
+
+struct sieve_binary {
+	pool_t pool;
+	int refcount;
+
+	struct sieve_instance *svinst;
+	
+	struct sieve_script *script;
+	
+	struct sieve_binary_file *file;
+	
+	/* When the binary is loaded into memory or when it is being constructed by
+	 * the generator, extensions can be associated to the binary. The extensions
+	 * array is a sequential list of all linked extensions. The extension_index 
+	 * array is a mapping ext_id -> binary_extension. This is used to obtain the 
+	 * index code associated with an extension for this particular binary. The 
+	 * linked_extensions list all extensions linked to this binary object other
+	 * than the preloaded language features implemented as 'extensions'. 
+	 * 
+	 * All arrays refer to the same extension registration objects. Upon loading 
+	 * a binary, the 'require'd extensions will sometimes need to associate 
+	 * context data to the binary object in memory. This is stored in these 
+	 * registration objects as well.
+	 */
+	ARRAY_DEFINE(extensions, struct sieve_binary_extension_reg *); 
+	ARRAY_DEFINE(extension_index, struct sieve_binary_extension_reg *); 
+	ARRAY_DEFINE(linked_extensions, struct sieve_binary_extension_reg *); 
+		
+	/* Attributes of a loaded binary */
+	const char *path;
+		
+	/* Blocks */
+	ARRAY_DEFINE(blocks, struct sieve_binary_block *); 
+};
+
+struct sieve_binary *sieve_binary_create
+	(struct sieve_instance *svinst, struct sieve_script *script);
+
+/* Blocks management */
+
+static inline struct sieve_binary_block *sieve_binary_block_index
+(struct sieve_binary *sbin, unsigned int id) 
+{
+	struct sieve_binary_block * const *sblock;
+
+	if  ( id >= array_count(&sbin->blocks) )
+		return NULL;
+	
+	sblock = array_idx(&sbin->blocks, id);
+
+	if ( *sblock == NULL ) {
+		return NULL;
+	}
+
+	return *sblock;
+}
+
+static inline size_t _sieve_binary_block_get_size
+(const struct sieve_binary_block *sblock)
+{
+	return buffer_get_used_size(sblock->data);
+}
+
+struct sieve_binary_block *sieve_binary_block_create_id
+	(struct sieve_binary *sbin, unsigned int id);
+
+buffer_t *sieve_binary_block_get_buffer
+	(struct sieve_binary_block *sblock);
+
+/* Extension registration */
+
+static inline struct sieve_binary_extension_reg *
+	sieve_binary_extension_create_reg
+(struct sieve_binary *sbin, const struct sieve_extension *ext)
+{
+	int index = array_count(&sbin->extensions);
+	struct sieve_binary_extension_reg *ereg;
+
+	if ( ext->id < 0 ) return NULL;
+
+	ereg = p_new(sbin->pool, struct sieve_binary_extension_reg, 1);
+	ereg->index = index;
+	ereg->extension = ext;
+	
+	array_idx_set(&sbin->extensions, (unsigned int) index, &ereg);
+	array_idx_set(&sbin->extension_index, (unsigned int) ext->id, &ereg);
+	
+	return ereg;
+}
+
+static inline struct sieve_binary_extension_reg *sieve_binary_extension_get_reg 
+(struct sieve_binary *sbin, const struct sieve_extension *ext, bool create) 
+{
+	struct sieve_binary_extension_reg *reg = NULL;
+
+	if ( ext->id >= 0 && ext->id < (int) array_count(&sbin->extension_index) ) {
+		struct sieve_binary_extension_reg * const *ereg = 
+			array_idx(&sbin->extension_index, (unsigned int) ext->id);
+		
+		reg = *ereg;
+	}
+
+	/* Register if not known */
+	if ( reg == NULL && create )
+		return sieve_binary_extension_create_reg(sbin, ext);
+
+	return reg;
+}
+
+static inline int sieve_binary_extension_register
+(struct sieve_binary *sbin, const struct sieve_extension *ext, 
+	struct sieve_binary_extension_reg **reg_r) 
+{
+	struct sieve_binary_extension_reg *ereg;
+
+	if ( (ereg=sieve_binary_extension_get_reg(sbin, ext, FALSE)) == NULL ) {
+		ereg = sieve_binary_extension_create_reg(sbin, ext);
+		
+		if ( ereg == NULL ) return -1;
+
+		array_append(&sbin->linked_extensions, &ereg, 1);
+	}
+
+	if ( reg_r != NULL ) *reg_r = ereg;
+	return ereg->index;
+}
+
+/* Load/Save */
+
+bool sieve_binary_load_block(struct sieve_binary_block *);
+
+#endif /* __SIEVE_BINARY_PRIVATE_H */
diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c
index 955c3c93e..3f5631159 100644
--- a/src/lib-sieve/sieve-binary.c
+++ b/src/lib-sieve/sieve-binary.c
@@ -17,155 +17,25 @@
 #include "sieve-code.h"
 #include "sieve-script.h"
 
-#include "sieve-binary.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/*
- * Config
- */
- 
-#define SIEVE_BINARY_VERSION_MAJOR     0
-#define SIEVE_BINARY_VERSION_MINOR     1
+#include "sieve-binary-private.h"
 
 /*
- * Macros
- */
-
-#define SIEVE_BINARY_MAGIC              0xcafebabe
-#define SIEVE_BINARY_MAGIC_OTHER_ENDIAN 0xbebafeca 
-
-#define SIEVE_BINARY_ALIGN(offset) \
-	(((offset) + 3) & ~3)
-#define SIEVE_BINARY_ALIGN_PTR(ptr) \
-	((void *) SIEVE_BINARY_ALIGN(((size_t) ptr)))
-
-/* 
- * Forward declarations 
+ * Forward declarations
  */
 
-struct sieve_binary_file;
-
-static bool sieve_binary_file_open
-	(struct sieve_binary_file *file, const char *path);
-static void sieve_binary_file_close(struct sieve_binary_file **file);
-
-static struct sieve_binary_block *sieve_binary_load_block
-	(struct sieve_binary *sbin, unsigned int id);
-
 static inline struct sieve_binary_extension_reg *sieve_binary_extension_get_reg
 	(struct sieve_binary *sbin, const struct sieve_extension *ext, 
 		bool create);
+
 static inline int sieve_binary_extension_register
 	(struct sieve_binary *sbin, const struct sieve_extension *ext, 
 		struct sieve_binary_extension_reg **reg);
 
-static inline sieve_size_t sieve_binary_emit_dynamic_data
-	(struct sieve_binary *binary, const void *data, size_t size);
-
-/* 
- * Internal structures
- */
-
-/* Extension registration */
-
-struct sieve_binary_extension_reg {
-	/* The identifier of the extension within this binary */
-	int index;
-	
-	/* Global extension object */
-	const struct sieve_extension *extension; 
-	
-	/* Extension to the binary; typically used to manage extension-specific blocks 
-	 * in the binary and as a means to get a binary_free notification to release
-	 * references held by extensions. 
-	 */
-	const struct sieve_binary_extension *binext;	
-	
-	/* Context data associated to the binary by this extension */
-	void *context;
-	
-	/* Main block for this extension */
-	unsigned int block_id;
-};
-
-/* Block */
-
-struct sieve_binary_block {
-	buffer_t *buffer;
-	int ext_index;
-	
-	uoff_t offset;
-};
-
-/* File */
-
-/* FIXME: In essence this is an unbuffered stream implementation. Maybe this 
- * can be merged with the generic dovecot istream interface.
- */
-struct sieve_binary_file {
-	pool_t pool;
-	const char *path;
-	
-	struct stat st;
-	int fd;
-	off_t offset;
-
-	bool (*load)(struct sieve_binary_file *file);	
-	const void *(*load_data)
-		(struct sieve_binary_file *file, off_t *offset, size_t size);
-	buffer_t *(*load_buffer)
-		(struct sieve_binary_file *file, off_t *offset, size_t size);
-};
-
 /*
  * Binary object
  */
 
-struct sieve_binary {
-	pool_t pool;
-	int refcount;
-
-	struct sieve_instance *svinst;
-	
-	struct sieve_script *script;
-	
-	struct sieve_binary_file *file;
-	
-	/* When the binary is loaded into memory or when it is being constructed by
-	 * the generator, extensions can be associated to the binary. The extensions
-	 * array is a sequential list of all linked extensions. The extension_index 
-	 * array is a mapping ext_id -> binary_extension. This is used to obtain the 
-	 * index code associated with an extension for this particular binary. The 
-	 * linked_extensions list all extensions linked to this binary object other
-	 * than the preloaded language features implemented as 'extensions'. 
-	 * 
-	 * All arrays refer to the same extension registration objects. Upon loading 
-	 * a binary, the 'require'd extensions will sometimes need to associate 
-	 * context data to the binary object in memory. This is stored in these 
-	 * registration objects as well.
-	 */
-	ARRAY_DEFINE(extensions, struct sieve_binary_extension_reg *); 
-	ARRAY_DEFINE(extension_index, struct sieve_binary_extension_reg *); 
-	ARRAY_DEFINE(linked_extensions, struct sieve_binary_extension_reg *); 
-		
-	/* Attributes of a loaded binary */
-	const char *path;
-		
-	/* Blocks */
-	ARRAY_DEFINE(blocks, struct sieve_binary_block *); 
-	unsigned int active_block;
-	
-	/* Current block buffer: all emit and read functions act upon this buffer */
-	buffer_t *data;
-	const signed char *code;
-	size_t code_size;
-};
-
-static struct sieve_binary *sieve_binary_create
+struct sieve_binary *sieve_binary_create
 (struct sieve_instance *svinst, struct sieve_script *script) 
 {
 	pool_t pool;
@@ -212,8 +82,7 @@ struct sieve_binary *sieve_binary_create_new(struct sieve_script *script)
 	(void) sieve_binary_block_create(sbin);
 	
 	/* Main program block */
-	(void) sieve_binary_block_set_active
-		(sbin, sieve_binary_block_create(sbin), NULL);
+	(void) sieve_binary_block_create(sbin);
 	
 	return sbin;
 }
@@ -258,17 +127,6 @@ void sieve_binary_unref(struct sieve_binary **sbin)
 	*sbin = NULL;
 }
 
-static inline sieve_size_t _sieve_binary_get_code_size
-(struct sieve_binary *sbin)
-{
-	return buffer_get_used_size(sbin->data);
-}
-
-sieve_size_t sieve_binary_get_code_size(struct sieve_binary *sbin)
-{
-	return _sieve_binary_get_code_size(sbin);
-}
-
 pool_t sieve_binary_pool(struct sieve_binary *sbin)
 {
 	return sbin->pool;
@@ -310,1110 +168,232 @@ const char *sieve_binary_script_path(struct sieve_binary *sbin)
 	return ( script == NULL ? NULL : sieve_script_path(script) );
 }
 
-
 /* 
  * Block management 
  */
 
-static inline struct sieve_binary_block *sieve_binary_block_get
-(struct sieve_binary *sbin, unsigned int id) 
+unsigned int sieve_binary_block_count
+(struct sieve_binary *sbin)
 {
-	struct sieve_binary_block * const *block;
-
-	if  ( id >= array_count(&sbin->blocks) )
-		return NULL;
-	
-	block = array_idx(&sbin->blocks, id);		
-
-	return *block;
+	return array_count(&sbin->blocks);
 }
 
-static inline unsigned int sieve_binary_block_add
-(struct sieve_binary *sbin, struct sieve_binary_block *block)
+struct sieve_binary_block *sieve_binary_block_create(struct sieve_binary *sbin)
 {
-	unsigned int id = array_count(&sbin->blocks);
+	unsigned int id = sieve_binary_block_count(sbin);
+	struct sieve_binary_block *sblock;
 	
-	array_append(&sbin->blocks, &block, 1);	
-	return id;
-}
+	sblock = p_new(sbin->pool, struct sieve_binary_block, 1);
+	sblock->data = buffer_create_dynamic(sbin->pool, 64);
+	sblock->sbin = sbin;
+	sblock->id = id;
 
-static inline unsigned int sieve_binary_block_count
-(struct sieve_binary *sbin)
-{
-	return array_count(&sbin->blocks);
+	array_append(&sbin->blocks, &sblock, 1);
+
+	return sblock;
 }
 
-void sieve_binary_block_clear
+struct sieve_binary_block *sieve_binary_block_create_id
 (struct sieve_binary *sbin, unsigned int id)
 {
-	struct sieve_binary_block *block = sieve_binary_block_get(sbin, id);
+	struct sieve_binary_block *sblock;
 	
-	buffer_reset(block->buffer);
+	sblock = p_new(sbin->pool, struct sieve_binary_block, 1);
+
+	array_idx_set(&sbin->blocks, id, &sblock);		
+	sblock->data = NULL;
+	sblock->sbin = sbin;
+	sblock->id = id;
+	
+	return sblock;
 }
 
-bool sieve_binary_block_set_active
-(struct sieve_binary *sbin, unsigned int id, unsigned *old_id_r)
+static bool sieve_binary_block_fetch(struct sieve_binary_block *sblock)
 {
-	struct sieve_binary_block *block = sieve_binary_block_get(sbin, id);
-			
-	if ( block == NULL ) return FALSE;
-	
-	if ( block->buffer == NULL ) {
-		if ( sbin->file ) {
-			/* Try to acces the block in the binary on disk (apperently we were lazy)
-			 */
-			if ( sieve_binary_load_block(sbin, id) == NULL || block->buffer == NULL )
-				return FALSE;
-		} else {
-			/* Block buffer is missing during code generation. This is what we would 
-			 * call a bug. FAIL. 
-			 */
+	struct sieve_binary *sbin = sblock->sbin;
+
+	if ( sbin->file ) {
+		/* Try to acces the block in the binary on disk (apperently we were lazy)
+		 */
+		if ( !sieve_binary_load_block(sblock) || sblock->data == NULL ) {
+			sieve_sys_error("block %d of loaded binary %s is corrupt", 
+				sblock->id, sbin->path);			
 			return FALSE;
 		}
+	} else {
+		sblock->data = buffer_create_dynamic(sbin->pool, 64);
+		return TRUE;
 	}
-	
-	if ( old_id_r != NULL ) 
-		*old_id_r = sbin->active_block;
 
-	sbin->data = block->buffer;
-	sbin->code = buffer_get_data(block->buffer, &sbin->code_size);
-	sbin->active_block = id;
-	
 	return TRUE;
 }
 
-unsigned int sieve_binary_block_create(struct sieve_binary *sbin)
+struct sieve_binary_block *sieve_binary_block_get
+(struct sieve_binary *sbin, unsigned int id) 
 {
-	struct sieve_binary_block *block;
-	
-	block = p_new(sbin->pool, struct sieve_binary_block, 1);
-	block->buffer = buffer_create_dynamic(sbin->pool, 64);
+	struct sieve_binary_block *sblock = sieve_binary_block_index(sbin, id);
 
-	return sieve_binary_block_add(sbin, block);
-}
+	if ( sblock == NULL )
+		return NULL;
 
-static struct sieve_binary_block *sieve_binary_block_create_id
-(struct sieve_binary *sbin, unsigned int id)
-{
-	struct sieve_binary_block *block;
-	
-	block = p_new(sbin->pool, struct sieve_binary_block, 1);
+	if ( sblock->data == NULL && !sieve_binary_block_fetch(sblock) )
+		return NULL;
 
-	if ( id >= SBIN_SYSBLOCK_LAST )
-		array_idx_set(&sbin->blocks, id, &block);		
-	else
-		(void)sieve_binary_block_add(sbin, block);
-	
-	return block;
+	return sblock;
 }
 
-/*
- * Header and record structures of the binary on disk 
- */
- 
-struct sieve_binary_header {
-	uint32_t magic;
-	uint16_t version_major;
-	uint16_t version_minor;
-	uint32_t blocks;
-};
-
-struct sieve_binary_block_index {
-	uint32_t id;
-	uint32_t size;
-	uint32_t offset;
-	uint32_t ext_id;
-};
-
-struct sieve_binary_block_header {
-	uint32_t id; 
-	uint32_t size;
-};
-
-/* 
- * Saving the binary to a file. 
- */
-
-static inline bool _save_skip(struct ostream *stream, size_t size)
+void sieve_binary_block_clear
+(struct sieve_binary_block *sblock)
 {	
-	if ( (o_stream_seek(stream, stream->offset + size)) <= 0 ) 
-		return FALSE;
-		
-	return TRUE;
+	buffer_reset(sblock->data);
 }
 
-static inline bool _save_skip_aligned
-(struct ostream *stream, size_t size, uoff_t *offset)
-{
-	uoff_t aligned_offset = SIEVE_BINARY_ALIGN(stream->offset);
+buffer_t *sieve_binary_block_get_buffer
+(struct sieve_binary_block *sblock)
+{			
+	if ( sblock->data == NULL && !sieve_binary_block_fetch(sblock) )
+		return NULL;	
 	
-	if ( (o_stream_seek(stream, aligned_offset + size)) <= 0 ) 
-		return FALSE;
-		
-	if ( offset != NULL )
-		*offset = aligned_offset;
-		
-	return TRUE;
+	return sblock->data;
 }
 
-/* FIXME: Is this even necessary for a file? */
-static bool _save_full(struct ostream *stream, const void *data, size_t size)
+struct sieve_binary *sieve_binary_block_get_binary
+(const struct sieve_binary_block *sblock)
 {
-	size_t bytes_left = size;
-	const void *pdata = data;
-	
-	while ( bytes_left > 0 ) {
-		ssize_t ret;
-		
-		if ( (ret=o_stream_send(stream, pdata, bytes_left)) <= 0 ) 
-			return FALSE;
-			
-		pdata = PTR_OFFSET(pdata, ret);
-		bytes_left -= ret;
-	}	
-	
-	return TRUE;
+	return sblock->sbin;
 }
 
-static bool _save_aligned
-(struct ostream *stream, const void *data, size_t size, uoff_t *offset)
-{	
-	uoff_t aligned_offset = SIEVE_BINARY_ALIGN(stream->offset);
-
-	o_stream_cork(stream);
-	
-	/* Align the data by adding zeroes to the output stream */
-	if ( stream->offset < aligned_offset ) {
-		if ( !_save_skip(stream, aligned_offset - stream->offset) ) 
-			return FALSE;
-	}
-	
-	if ( !_save_full(stream, data, size) )
-		return FALSE;
-	
-	o_stream_uncork(stream); 
-
-	if ( offset != NULL )
-		*offset = aligned_offset;
-
-	return TRUE;
-} 
-
-static bool _save_block
-(struct sieve_binary *sbin, struct ostream *stream, unsigned int id)
+unsigned int sieve_binary_block_get_id
+(const struct sieve_binary_block *sblock)
 {
-	struct sieve_binary_block_header block_header;
-	struct sieve_binary_block *block;
-	const void *data;
-	size_t size;
-		
-	block = sieve_binary_block_get(sbin, id);
-	if ( block == NULL )
-		return FALSE;
-		
-	data = buffer_get_data(block->buffer, &size);
-	
-	block_header.id = id;
-	block_header.size = size;
-	
-	if ( !_save_aligned(stream, &block_header,
-		sizeof(block_header), &block->offset) )
-		return FALSE;
-	
-	return _save_aligned(stream, data, size, NULL);
+	return sblock->id;
 }
 
-static bool _save_block_index_record
-(struct sieve_binary *sbin, struct ostream *stream, unsigned int id)
+size_t sieve_binary_block_get_size
+(const struct sieve_binary_block *sblock)
 {
-	struct sieve_binary_block *block;
-	struct sieve_binary_block_index header;
-	
-	block = sieve_binary_block_get(sbin, id);
-	if ( block == NULL )
-		return FALSE;
-	
-	header.id = id;
-	header.size = buffer_get_used_size(block->buffer);
-	header.ext_id = block->ext_index;
-	header.offset = block->offset;
-	
-	if ( !_save_full(stream, &header, sizeof(header)) ) {
-		sieve_sys_error("failed to save block index header %d: %m", id);
-		
-		return FALSE;
-	}
-	
-	return TRUE;
+	return _sieve_binary_block_get_size(sblock);
 }
 
-static bool _sieve_binary_save
-(struct sieve_binary *sbin, struct ostream *stream)
+/*
+ * Up-to-date checking
+ */
+
+bool sieve_binary_up_to_date(struct sieve_binary *sbin)
 {
-	struct sieve_binary_header header;
 	struct sieve_binary_extension_reg *const *regs;
-	unsigned int ext_count, blk_count, i;
-	uoff_t block_index;
-	
-	blk_count = sieve_binary_block_count(sbin);
+	unsigned int ext_count, i;
 	
-	/* Signal all extensions to finish generating their blocks */
+	i_assert(sbin->file != NULL);
+
+	if ( sbin->script == NULL || sieve_script_newer
+		(sbin->script, sbin->file->st.st_mtime) )
+		return FALSE;
 	
 	regs = array_get(&sbin->extensions, &ext_count);	
 	for ( i = 0; i < ext_count; i++ ) {
 		const struct sieve_binary_extension *binext = regs[i]->binext;
 		
-		if ( binext != NULL && binext->binary_save != NULL )
-			binext->binary_save(regs[i]->extension, sbin, regs[i]->context);
+		if ( binext != NULL && binext->binary_up_to_date != NULL && 
+			!binext->binary_up_to_date(regs[i]->extension, sbin, regs[i]->context) )
+			return FALSE;
 	}
-		
-	/* Create header */
 	
-	header.magic = SIEVE_BINARY_MAGIC;
-	header.version_major = SIEVE_BINARY_VERSION_MAJOR;
-	header.version_minor = SIEVE_BINARY_VERSION_MINOR;
-	header.blocks = blk_count;
+	return TRUE;
+}
 
-	if ( !_save_aligned(stream, &header, sizeof(header), NULL) ) {
-		sieve_sys_error("failed to save binary header: %m");
-		return FALSE;
-	} 
-	
-	/* Skip block index for now */
-	
-	if ( !_save_skip_aligned(stream, 
-		sizeof(struct sieve_binary_block_index) * blk_count, &block_index) )
-		return FALSE;
-	
-	/* Create block containing all used extensions 
-	 *   FIXME: Per-extension this should also store binary version numbers.
-	 */
-	if ( !sieve_binary_block_set_active(sbin, SBIN_SYSBLOCK_EXTENSIONS, NULL) )
-		return FALSE;
-		
-	ext_count = array_count(&sbin->linked_extensions);
-	sieve_binary_emit_unsigned(sbin, ext_count);
+/*
+ * Activate the binary (after code generation)
+ */
+ 
+void sieve_binary_activate(struct sieve_binary *sbin)
+{
+	struct sieve_binary_extension_reg *const *regs;
+	unsigned int i, ext_count;
 	
+	/* Load other extensions into binary */
+	regs = array_get(&sbin->linked_extensions, &ext_count);
 	for ( i = 0; i < ext_count; i++ ) {
-		struct sieve_binary_extension_reg * const *ext
-			= array_idx(&sbin->linked_extensions, i);
+		const struct sieve_extension *ext = regs[i]->extension;
 		
-		sieve_binary_emit_cstring(sbin, sieve_extension_name((*ext)->extension));
-		sieve_binary_emit_unsigned(sbin, (*ext)->block_id);
-	}
-	
-	if ( !sieve_binary_block_set_active(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM, NULL) )
-		return FALSE;
-	
-	/* Save all blocks into the binary */
-	
-	for ( i = 0; i < blk_count; i++ ) {
-		if ( !_save_block(sbin, stream, i) ) 
-			return FALSE;
-	}
-	
-	/* Create the block index */
-	o_stream_seek(stream, block_index);
-	for ( i = 0; i < blk_count; i++ ) {
-		if ( !_save_block_index_record(sbin, stream, i) ) 
-			return FALSE;
+		if ( ext != NULL && ext->def != NULL && ext->def->binary_load != NULL )
+			ext->def->binary_load(ext, sbin);
 	}
+}
 
-	return TRUE;
-} 
+/* 
+ * Extension handling 
+ */
 
-bool sieve_binary_save
-(struct sieve_binary *sbin, const char *path)
+void sieve_binary_extension_set_context
+(struct sieve_binary *sbin, const struct sieve_extension *ext, void *context)
 {
-	bool result = TRUE;
-	string_t *temp_path;
-	struct ostream *stream;
-	int fd;
-	mode_t save_mode = sbin->script == NULL ? 0600 : sieve_script_permissions(sbin->script);
+	struct sieve_binary_extension_reg *ereg = 
+		sieve_binary_extension_get_reg(sbin, ext, TRUE);
 	
-	/* Use default path if none is specified */
-	if ( path == NULL ) {
-		if ( sbin->script == NULL ) {
-			sieve_sys_error("cannot determine default binary save path "
-				"with missing script object");
-        	return FALSE;
-		}
-		path = sieve_script_binpath(sbin->script);
-	}
-
-	/* Open it as temp file first, as not to overwrite an existing just yet */
-	temp_path = t_str_new(256);
-	str_append(temp_path, path);
-	fd = safe_mkstemp_hostpid(temp_path, save_mode, (uid_t)-1, (gid_t)-1);
-	if ( fd < 0 ) {
-		if ( errno == EACCES ) {
-			sieve_sys_error("failed to save binary temporary file: %s",
-				eacces_error_get_creating("open", str_c(temp_path)));
-		} else {
-			sieve_sys_error("failed to save binary temporary file: "
-				"open(%s) failed: %m", str_c(temp_path));
-		}
-		return FALSE;
-	}
-
-	/* Save binary */
-	stream = o_stream_create_fd(fd, 0, FALSE);
-	result = _sieve_binary_save(sbin, stream);
-	o_stream_destroy(&stream);
-
-	/* Close saved binary */ 
-	if ( close(fd) < 0 ) {
-		sieve_sys_error("failed to close saved binary temporary file: "
-			"close(fd=%s) failed: %m", str_c(temp_path));
-	}
+	if ( ereg != NULL )
+		ereg->context = context;
+}
 
-	/* Replace any original binary atomically */
-	if ( result && (rename(str_c(temp_path), path) < 0) ) {
-		if ( errno == EACCES ) {
-			sieve_sys_error("failed to replace existing binary: %s", 
-				eacces_error_get_creating("rename", path));			
-		} else { 		
-			sieve_sys_error("failed to replace existing binary: "
-				"rename(%s, %s) failed: %m", str_c(temp_path), path);
-		}
-		result = FALSE;
-	}
+const void *sieve_binary_extension_get_context
+	(struct sieve_binary *sbin, const struct sieve_extension *ext) 
+{
+	struct sieve_binary_extension_reg *ereg = 
+		sieve_binary_extension_get_reg(sbin, ext, TRUE);
 
-	if ( !result ) {
-		/* Get rid of temp output (if any) */
-		(void) unlink(str_c(temp_path));
-	} else {
-		if ( sbin->path == NULL || strcmp(sbin->path, path) != 0 ) {
-			sbin->path = p_strdup(sbin->pool, path);
-		}
+	if ( ereg != NULL ) {
+		return ereg->context;
 	}
-	
-	return result;
+		
+	return NULL;
 }
 
-/* 
- * Binary file management 
- */
-
-static bool sieve_binary_file_open
-	(struct sieve_binary_file *file, const char *path)
+void sieve_binary_extension_set
+(struct sieve_binary *sbin, const struct sieve_extension *ext,
+	const struct sieve_binary_extension *bext, void *context)
 {
-	int fd;
-	struct stat st;
+	struct sieve_binary_extension_reg *ereg = 
+		sieve_binary_extension_get_reg(sbin, ext, TRUE);
 	
-	if ( (fd=open(path, O_RDONLY)) < 0 ) {
-		if ( errno != ENOENT ) {
-			if ( errno == EACCES ) {
-				sieve_sys_error("failed to open binary: %s", 
-					eacces_error_get("open", path));			
-			} else {
-				sieve_sys_error("failed to open binary: "
-					"open(%s) failed: %m", path);
-			}
-		}
-		return FALSE;
-	}
+	if ( ereg != NULL ) {
+		ereg->binext = bext;
 
-	if ( fstat(fd, &st) < 0 ) {
-		if ( errno != ENOENT ) {
-			sieve_sys_error("failed to open binary: "
-				"fstat(fd=%s) failed: %m", path);
-		}
-		return FALSE;
+		if ( context != NULL )
+			ereg->context = context;
 	}
+}
 
-	if ( !S_ISREG(st.st_mode) ) {
-		sieve_sys_error("binary %s is not a regular file", path);
-		return FALSE;		
-	}
+struct sieve_binary_block *sieve_binary_extension_create_block
+(struct sieve_binary *sbin, const struct sieve_extension *ext)
+{
+	struct sieve_binary_block *sblock;	
+	struct sieve_binary_extension_reg *ereg = 
+		sieve_binary_extension_get_reg(sbin, ext, TRUE);
 	
-	file->fd = fd;
-	file->st = st;
+	i_assert(ereg != NULL);
 
-	return TRUE;
-}
+	sblock = sieve_binary_block_create(sbin);
 	
-static void sieve_binary_file_close(struct sieve_binary_file **file)
-{
-	if ( (*file)->fd != -1 ) {
-		if ( close((*file)->fd) < 0 ) {
-			sieve_sys_error("failed to close opened binary: "
-				"close(fd=%s) failed: %m", (*file)->path);
-		}
-	}
-
-	pool_unref(&(*file)->pool);
+	if ( ereg->block_id < SBIN_SYSBLOCK_LAST )
+		ereg->block_id = sblock->id;
+	sblock->ext_index = ereg->index;
 	
-	*file = NULL;
+	return sblock;
 }
 
-#if 0 /* file_memory is currently unused */
-
-/* File loaded/mapped to memory */
+struct sieve_binary_block *sieve_binary_extension_get_block
+(struct sieve_binary *sbin, const struct sieve_extension *ext)
+{
+	struct sieve_binary_extension_reg *ereg = 
+		sieve_binary_extension_get_reg(sbin, ext, TRUE);
+		
+	i_assert(ereg != NULL);
 
-struct _file_memory {
-	struct sieve_binary_file binfile;
+	if ( ereg->block_id < SBIN_SYSBLOCK_LAST )
+		return NULL;
 
-	/* Pointer to the binary in memory */
-	const void *memory;
-	off_t memory_size;
-};
-
-static const void *_file_memory_load_data
-	(struct sieve_binary_file *file, off_t *offset, size_t size)
-{	
-	struct _file_memory *fmem = (struct _file_memory *) file;
-
-	*offset = SIEVE_BINARY_ALIGN(*offset);
-
-	if ( (*offset) + size <= fmem->memory_size ) {
-		const void *data = PTR_OFFSET(fmem->memory, *offset);
-		*offset += size;
-		file->offset = *offset;
-		
-		return data;
-	}
-		
-	return NULL;
-}
-
-static buffer_t *_file_memory_load_buffer
-	(struct sieve_binary_file *file, off_t *offset, size_t size)
-{	
-	struct _file_memory *fmem = (struct _file_memory *) file;
-
-	*offset = SIEVE_BINARY_ALIGN(*offset);
-
-	if ( (*offset) + size <= fmem->memory_size ) {
-		const void *data = PTR_OFFSET(fmem->memory, *offset);
-		*offset += size;
-		file->offset = *offset;
-		
-		return buffer_create_const_data(file->pool, data, size);
-	}
-	
-	return NULL;
-}
-
-static bool _file_memory_load(struct sieve_binary_file *file)
-{
-	struct _file_memory *fmem = (struct _file_memory *) file;
-	int ret;
-	size_t size;
-	void *indata;
-		
-	i_assert(file->fd > 0);
-		
-	/* Allocate memory buffer
-	 */
-	indata = p_malloc(file->pool, file->st.st_size);
-	size = file->st.st_size; 
-	
-	file->offset = 0; 
-	fmem->memory = indata;
-	fmem->memory_size = file->st.st_size;
-
-	/* Return to beginning of the file */
-	if ( lseek(file->fd, 0, SEEK_SET) == (off_t) -1 ) {
-		sieve_sys_error("failed to seek() in binary %s: %m", file->path);
-		return FALSE;
-	}	
-
-	/* Read the whole file into memory */
-	while (size > 0) {
-		if ( (ret=read(file->fd, indata, size)) <= 0 ) {
-			sieve_sys_error("failed to read from binary %s: %m", file->path);
-			break;
-		}
-		
-		indata = PTR_OFFSET(indata, ret);
-		size -= ret;
-	}	
-
-	if ( size != 0 ) {
-		/* Failed to read the whole file */
-		return FALSE;
-	}
-	
-	return TRUE;
-}
-
-static struct sieve_binary_file *_file_memory_open(const char *path)
-{
-	pool_t pool;
-	struct _file_memory *file;
-	
-	pool = pool_alloconly_create("sieve_binary_file_memory", 1024);
-	file = p_new(pool, struct _file_memory, 1);
-	file->binfile.pool = pool;
-	file->binfile.path = p_strdup(pool, path);
-	file->binfile.load = _file_memory_load;
-	file->binfile.load_data = _file_memory_load_data;
-	file->binfile.load_buffer = _file_memory_load_buffer;
-	
-	if ( !sieve_binary_file_open(&file->binfile, path) ) {
-		pool_unref(&pool);
-		return NULL;
-	}
-
-	return &file->binfile;
-}
-
-#endif /* file_memory is currently unused */
-
-/* File open in lazy mode (only read what is needed into memory) */
-
-static bool _file_lazy_read
-(struct sieve_binary_file *file, off_t *offset, void *buffer, size_t size)
-{
-	int ret;
-	void *indata = buffer;
-	size_t insize = size;
-	
-	*offset = SIEVE_BINARY_ALIGN(*offset);
-	
-	/* Seek to the correct position */ 
-	if ( *offset != file->offset && 
-		lseek(file->fd, *offset, SEEK_SET) == (off_t) -1 ) {
-		sieve_sys_error("failed to seek(fd, %lld, SEEK_SET) in binary %s: %m", 
-			(long long) *offset, file->path);
-		return FALSE;
-	}	
-
-	/* Read record into memory */
-	while (insize > 0) {
-		if ( (ret=read(file->fd, indata, insize)) <= 0 ) {
-			if ( ret == 0 ) 
-				sieve_sys_error("binary %s is truncated (more data expected)", 
-					file->path);
-			else
-				sieve_sys_error("failed to read from binary %s: %m", file->path);
-			break;
-		}
-		
-		indata = PTR_OFFSET(indata, ret);
-		insize -= ret;
-	}	
-
-	if ( insize != 0 ) {
-		/* Failed to read the whole requested record */
-		return FALSE;
-	}
-	
-	*offset += size;
-	file->offset = *offset;
-
-	return TRUE;
-}
-
-static const void *_file_lazy_load_data
-(struct sieve_binary_file *file, off_t *offset, size_t size)
-{	
-	void *data = t_malloc(size);
-
-	if ( _file_lazy_read(file, offset, data, size) ) {
-		return data;
-	}
-	
-	return NULL;
-}
-
-static buffer_t *_file_lazy_load_buffer
-(struct sieve_binary_file *file, off_t *offset, size_t size)
-{			
-	buffer_t *buffer = buffer_create_dynamic(file->pool, size);
-	
-	if ( _file_lazy_read
-		(file, offset, buffer_get_space_unsafe(buffer, 0, size), size) ) {
-		return buffer;
-	}
-	
-	return NULL;
-}
-
-static struct sieve_binary_file *_file_lazy_open(const char *path)
-{
-	pool_t pool;
-	struct sieve_binary_file *file;
-	
-	pool = pool_alloconly_create("sieve_binary_file_lazy", 4096);
-	file = p_new(pool, struct sieve_binary_file, 1);
-	file->pool = pool;
-	file->path = p_strdup(pool, path);
-	file->load_data = _file_lazy_load_data;
-	file->load_buffer = _file_lazy_load_buffer;
-	
-	if ( !sieve_binary_file_open(file, path) ) {
-		pool_unref(&pool);
-		return NULL;
-	}
-
-	return file;
-}
-
-/* 
- * Load binary from a file
- */
-
-#define LOAD_HEADER(sbin, offset, header) \
-	(header *) sbin->file->load_data(sbin->file, offset, sizeof(header))
-
-static struct sieve_binary_block *_load_block
-(struct sieve_binary *sbin, off_t *offset, unsigned int id)
-{
-	const struct sieve_binary_block_header *header = 
-		LOAD_HEADER(sbin, offset, const struct sieve_binary_block_header);
-	struct sieve_binary_block *block;
-		
-	if ( header == NULL ) {
-		sieve_sys_error("block %d of loaded binary %s is truncated", id, sbin->path);
-		return NULL;
-	}
-	
-	if ( header->id != id ) {
-		sieve_sys_error("block %d of loaded binary %s has unexpected id %d", id, 
-			sbin->path, header->id);
-		return NULL;
-	}
-	
-	block = sieve_binary_block_get(sbin, id);
-	
-	if ( block == NULL ) {
-		sieve_sys_error("!!BUG!!: block %d missing in index (impossible) "
-			"of binary %s",	id, sbin->path);
-		return NULL;
-	}
-	
-	block->buffer = sbin->file->load_buffer(sbin->file, offset, header->size);
-	if ( block->buffer == NULL ) {
-		sieve_sys_error("block %d of loaded binary %s has invalid size %d",
-			id, sbin->path, header->size);
-		return NULL;
-	}
-		
-	return block;
-}
-
-static struct sieve_binary_block *sieve_binary_load_block
-(struct sieve_binary *sbin, unsigned int id)
-{
-	struct sieve_binary_block *block;
-	off_t offset;
-	
-	block = sieve_binary_block_get(sbin, id);
-	
-	if ( block == NULL ) return NULL;
-	
-	offset = block->offset;
-	
-	return _load_block(sbin, &offset, id);
-}
-
-static bool _load_block_index_record
-(struct sieve_binary *sbin, off_t *offset, unsigned int id)
-{
-	const struct sieve_binary_block_index *record = 
-		LOAD_HEADER(sbin, offset, const struct sieve_binary_block_index);
-	struct sieve_binary_block *block;
-	
-	if ( record == NULL ) {
-		sieve_sys_error("failed to read index record for block %d in binary %s", 
-			id, sbin->path);
-		return FALSE;
-	}
-	
-	if ( record->id != id ) {
-		sieve_sys_error("block index record %d of loaded binary %s "
-			"has unexpected id %d", id, sbin->path, record->id);
-		return FALSE;
-	}
-	
-	block = sieve_binary_block_create_id(sbin, id);
-	block->ext_index = record->ext_id;
-	block->offset = record->offset;
-	
-	return TRUE;
-}
-
-static bool _sieve_binary_load_extensions(struct sieve_binary *sbin)
-{
-	sieve_size_t offset = 0;
-	unsigned int i, count;
-	bool result = TRUE;
-	
-	if ( !sieve_binary_block_set_active(sbin, SBIN_SYSBLOCK_EXTENSIONS, NULL) ) 
-		return FALSE;
-
-	if ( !sieve_binary_read_unsigned(sbin, &offset, &count) )
-		return FALSE;
-	
-	for ( i = 0; result && i < count; i++ ) {
-		T_BEGIN {
-			string_t *extension;
-			const struct sieve_extension *ext;
-			
-			if ( sieve_binary_read_string(sbin, &offset, &extension) ) { 
-				ext = sieve_extension_get_by_name(sbin->svinst, str_c(extension));	
-			
-				if ( ext == NULL ) { 
-					sieve_sys_error("loaded binary %s requires unknown extension '%s'", 
-						sbin->path, str_sanitize(str_c(extension), 128));
-					result = FALSE;					
-				} else {
-					struct sieve_binary_extension_reg *ereg = NULL;
-					
-					(void) sieve_binary_extension_register(sbin, ext, &ereg);
-					if ( !sieve_binary_read_unsigned(sbin, &offset, &ereg->block_id) )
-						result = FALSE;
-				}
-			}	else
-				result = FALSE;
-		} T_END;
-	}		
-		
-	return result;
-}
-
-static bool _sieve_binary_open(struct sieve_binary *sbin)
-{
-	bool result = TRUE;
-	off_t offset = 0;
-	const struct sieve_binary_header *header;
-	struct sieve_binary_block *extensions;
-	unsigned int i, blk_count;
-	
-	/* Verify header */
-	
-	T_BEGIN {
-		header = LOAD_HEADER(sbin, &offset, const struct sieve_binary_header);
-		if ( header == NULL ) {
-			sieve_sys_error("opened binary %s is not even large enough "
-				"to contain a header.", sbin->path);
-			result = FALSE;
-
-		} else if ( header->magic != SIEVE_BINARY_MAGIC ) {
-			if ( header->magic != SIEVE_BINARY_MAGIC_OTHER_ENDIAN ) 
-				sieve_sys_error("opened binary %s has corrupted header (0x%08x)", 
-					sbin->path, header->magic);
-			result = FALSE;
-
-		} else if ( result && (
-		  header->version_major != SIEVE_BINARY_VERSION_MAJOR || 
-			header->version_minor != SIEVE_BINARY_VERSION_MINOR ) ) {
-
-			/* Binary is of different version. Caller will have to recompile */
-			result = FALSE;
-
-		} else if ( result && header->blocks == 0 ) {
-			sieve_sys_error("opened binary %s contains no blocks", sbin->path);
-			result = FALSE; 
-
-		} else {
-			blk_count = header->blocks;
-		}
-	} T_END;
-	
-	if ( !result ) return FALSE;
-	
-	/* Load block index */
-	
-	for ( i = 0; i < blk_count && result; i++ ) {	
-		T_BEGIN {
-			if ( !_load_block_index_record(sbin, &offset, i) ) {
-				sieve_sys_error(
-					"block index record %d of opened binary %s is corrupt", 
-					i, sbin->path);
-				result = FALSE;
-			}
-		} T_END;
-	}
-	
-	if ( !result ) return FALSE;
-	
-	/* Load extensions used by this binary */
-	
-	T_BEGIN {
-		extensions =_load_block(sbin, &offset, 0);
-		if ( extensions == NULL ) {
-			result = FALSE;
-		} else if ( !_sieve_binary_load_extensions(sbin) ) {
-			sieve_sys_error("extension block of opened binary %s is corrupt", 
-				sbin->path);
-			result = FALSE;
-		}
-	} T_END;
-		
-	return result;
-}
-
-static bool _sieve_binary_load(struct sieve_binary *sbin) 
-{	
-	bool result = TRUE;
-	unsigned int i, blk_count;
-	struct sieve_binary_block *block;
-	off_t offset;
-	
-	blk_count = array_count(&sbin->blocks);
-	if ( blk_count == 1 ) {
-		/* Binary is empty */
-		return TRUE;
-	}	
-
-	block = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM);
-	offset = block->offset;
-	
-	/* Load the other blocks */
-	
-	for ( i = 1; result && i < blk_count; i++ ) {	
-		T_BEGIN {
-			if ( _load_block(sbin, &offset, i) == NULL ) {
-				sieve_sys_error("block %d of loaded binary %s is corrupt", 
-					i, sbin->path);
-				result = FALSE;
-			}
-		} T_END;
-	}
-				
-	return result;
-}
-
-struct sieve_binary *sieve_binary_open
-(struct sieve_instance *svinst, const char *path, struct sieve_script *script)
-{
-	struct sieve_binary_extension_reg *const *regs;
-	unsigned int ext_count, i;
-	struct sieve_binary *sbin;
-	struct sieve_binary_file *file;
-	
-	i_assert( script == NULL || sieve_script_svinst(script) == svinst );
-	
-	//file = _file_memory_open(path);	
-	file = _file_lazy_open(path);
-	if ( file == NULL )
-		return NULL;
-		
-	/* Create binary object */
-	sbin = sieve_binary_create(svinst, script);
-	sbin->path = p_strdup(sbin->pool, path);
-	sbin->file = file;
-	
-	if ( !_sieve_binary_open(sbin) ) {
-		sieve_binary_unref(&sbin);
-		return NULL;
-	}
-	
-	sieve_binary_activate(sbin);
-	
-	/* Signal open event to extensions */
-	regs = array_get(&sbin->extensions, &ext_count);	
-	for ( i = 0; i < ext_count; i++ ) {
-		const struct sieve_binary_extension *binext = regs[i]->binext;
-		
-		if ( binext != NULL && binext->binary_open != NULL && 
-			!binext->binary_open(regs[i]->extension, sbin, regs[i]->context) ) {
-			/* Extension thinks its corrupt */
-			sieve_binary_unref(&sbin);
-			return NULL;
-		}
-	}	
-
-	return sbin;
-}
-
-bool sieve_binary_load(struct sieve_binary *sbin)
-{
-	i_assert(sbin->file != NULL);
-
-	/*
-	if ( sbin->file->load != NULL && !sbin->file->load(sbin->file) )
-		return FALSE;	*/		
-	
-	if ( !_sieve_binary_load(sbin) ) {
-		/* Failed to interpret binary header and/or block structure */
-		return FALSE;
-	}
-	
-	return TRUE;
-}
-
-/*
- * Up-to-date checking
- */
-
-bool sieve_binary_up_to_date(struct sieve_binary *sbin)
-{
-	struct sieve_binary_extension_reg *const *regs;
-	unsigned int ext_count, i;
-	
-	i_assert(sbin->file != NULL);
-
-	if ( sbin->script == NULL || sieve_script_newer
-		(sbin->script, sbin->file->st.st_mtime) )
-		return FALSE;
-	
-	regs = array_get(&sbin->extensions, &ext_count);	
-	for ( i = 0; i < ext_count; i++ ) {
-		const struct sieve_binary_extension *binext = regs[i]->binext;
-		
-		if ( binext != NULL && binext->binary_up_to_date != NULL && 
-			!binext->binary_up_to_date(regs[i]->extension, sbin, regs[i]->context) )
-			return FALSE;
-	}
-	
-	return TRUE;
-}
-
-/*
- * Activate the binary (after code generation)
- */
- 
-void sieve_binary_activate(struct sieve_binary *sbin)
-{
-	struct sieve_binary_extension_reg *const *regs;
-	unsigned int i, ext_count;
-	
-	(void)sieve_binary_block_set_active(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM, NULL);
-	
-	/* Load other extensions into binary */
-	regs = array_get(&sbin->linked_extensions, &ext_count);
-	for ( i = 0; i < ext_count; i++ ) {
-		const struct sieve_extension *ext = regs[i]->extension;
-		
-		if ( ext != NULL && ext->def != NULL && ext->def->binary_load != NULL )
-			ext->def->binary_load(ext, sbin);
-	}
-}
-
-/* 
- * Extension handling 
- */
-
-static inline struct sieve_binary_extension_reg *
-	sieve_binary_extension_create_reg
-(struct sieve_binary *sbin, const struct sieve_extension *ext)
-{
-	int index = array_count(&sbin->extensions);
-	struct sieve_binary_extension_reg *ereg;
-
-	if ( ext->id < 0 ) return NULL;
-
-	ereg = p_new(sbin->pool, struct sieve_binary_extension_reg, 1);
-	ereg->index = index;
-	ereg->extension = ext;
-	
-	array_idx_set(&sbin->extensions, (unsigned int) index, &ereg);
-	array_idx_set(&sbin->extension_index, (unsigned int) ext->id, &ereg);
-	
-	return ereg;
-}
-
-static inline struct sieve_binary_extension_reg *sieve_binary_extension_get_reg 
-(struct sieve_binary *sbin, const struct sieve_extension *ext, bool create) 
-{
-	struct sieve_binary_extension_reg *reg = NULL;
-
-	if ( ext->id >= 0 && ext->id < (int) array_count(&sbin->extension_index) ) {
-		struct sieve_binary_extension_reg * const *ereg = 
-			array_idx(&sbin->extension_index, (unsigned int) ext->id);
-		
-		reg = *ereg;
-	}
-
-	/* Register if not known */
-	if ( reg == NULL && create )
-		return sieve_binary_extension_create_reg(sbin, ext);
-
-	return reg;
-}
-
-void sieve_binary_extension_set_context
-(struct sieve_binary *sbin, const struct sieve_extension *ext, void *context)
-{
-	struct sieve_binary_extension_reg *ereg = 
-		sieve_binary_extension_get_reg(sbin, ext, TRUE);
-	
-	if ( ereg != NULL )
-		ereg->context = context;
-}
-
-const void *sieve_binary_extension_get_context
-	(struct sieve_binary *sbin, const struct sieve_extension *ext) 
-{
-	struct sieve_binary_extension_reg *ereg = 
-		sieve_binary_extension_get_reg(sbin, ext, TRUE);
-
-	if ( ereg != NULL ) {
-		return ereg->context;
-	}
-		
-	return NULL;
-}
-
-void sieve_binary_extension_set
-(struct sieve_binary *sbin, const struct sieve_extension *ext,
-	const struct sieve_binary_extension *bext, void *context)
-{
-	struct sieve_binary_extension_reg *ereg = 
-		sieve_binary_extension_get_reg(sbin, ext, TRUE);
-	
-	if ( ereg != NULL ) {
-		ereg->binext = bext;
-
-		if ( context != NULL )
-			ereg->context = context;
-	}
-}
-
-unsigned int sieve_binary_extension_create_block
-(struct sieve_binary *sbin, const struct sieve_extension *ext)
-{
-	struct sieve_binary_block *block;	
-	unsigned int block_id;
-	struct sieve_binary_extension_reg *ereg = 
-		sieve_binary_extension_get_reg(sbin, ext, TRUE);
-	
-	i_assert(ereg != NULL);
-
-	block = p_new(sbin->pool, struct sieve_binary_block, 1);
-	block->buffer = buffer_create_dynamic(sbin->pool, 64);
-
-	block_id = sieve_binary_block_add(sbin, block);
-	
-	if ( ereg->block_id < SBIN_SYSBLOCK_LAST )
-		ereg->block_id = block_id;
-	block->ext_index = ereg->index;
-	
-	return block_id;
-}
-
-unsigned int sieve_binary_extension_get_block
-(struct sieve_binary *sbin, const struct sieve_extension *ext)
-{
-	struct sieve_binary_extension_reg *ereg = 
-		sieve_binary_extension_get_reg(sbin, ext, TRUE);
-		
-	i_assert(ereg != NULL);
-
-	return ereg->block_id;
-}
-
-static inline int sieve_binary_extension_register
-(struct sieve_binary *sbin, const struct sieve_extension *ext, 
-	struct sieve_binary_extension_reg **reg_r) 
-{
-	struct sieve_binary_extension_reg *ereg;
-
-	if ( (ereg=sieve_binary_extension_get_reg(sbin, ext, FALSE)) == NULL ) {
-		ereg = sieve_binary_extension_create_reg(sbin, ext);
-		
-		if ( ereg == NULL ) return -1;
-
-		array_append(&sbin->linked_extensions, &ereg, 1);
-	}
-
-	if ( reg_r != NULL ) *reg_r = ereg;
-	return ereg->index;
-}
+	return sieve_binary_block_get(sbin, ereg->block_id);
+}
 
 int sieve_binary_extension_link
 (struct sieve_binary *sbin, const struct sieve_extension *ext) 
@@ -1421,7 +401,7 @@ int sieve_binary_extension_link
 	return sieve_binary_extension_register(sbin, ext, NULL);
 }
 
-static inline const struct sieve_extension *_sieve_binary_extension_get_by_index
+const struct sieve_extension *sieve_binary_extension_get_by_index
 (struct sieve_binary *sbin, int index) 
 {
 	struct sieve_binary_extension_reg * const *ereg;
@@ -1435,12 +415,6 @@ static inline const struct sieve_extension *_sieve_binary_extension_get_by_index
 	return NULL;
 }
 
-const struct sieve_extension *sieve_binary_extension_get_by_index
-(struct sieve_binary *sbin, int index)
-{
-	return _sieve_binary_extension_get_by_index(sbin, index);
-}
-
 int sieve_binary_extension_get_index
 	(struct sieve_binary *sbin, const struct sieve_extension *ext) 
 {
@@ -1454,345 +428,3 @@ int sieve_binary_extensions_count(struct sieve_binary *sbin)
 {
 	return (int) array_count(&sbin->extensions);
 }
-
-/*
- * Emission functions
- */
-
-/* Low-level emission functions */
-
-static inline void _sieve_binary_emit_data
-(struct sieve_binary *sbin, const void *data, sieve_size_t size) 
-{	  
-	buffer_append(sbin->data, data, size);
-}
-
-static inline void _sieve_binary_emit_byte
-(struct sieve_binary *sbin, unsigned char byte)
-{
-    _sieve_binary_emit_data(sbin, &byte, 1);
-}
-
-static inline void _sieve_binary_update_data
-(struct sieve_binary *sbin, sieve_size_t address, const void *data, 
-	sieve_size_t size) 
-{
-	buffer_write(sbin->data, address, data, size);
-}
-
-sieve_size_t sieve_binary_emit_data
-(struct sieve_binary *sbin, const void *data, sieve_size_t size)
-{
-	sieve_size_t address = _sieve_binary_get_code_size(sbin);
-
-	_sieve_binary_emit_data(sbin, data, size);
-
-	return address;
-}
-
-sieve_size_t sieve_binary_emit_byte
-(struct sieve_binary *sbin, unsigned char byte) 
-{
-	sieve_size_t address = _sieve_binary_get_code_size(sbin);
-
-	_sieve_binary_emit_data(sbin, &byte, 1);
-	
-	return address;
-}
-
-void sieve_binary_update_data
-(struct sieve_binary *sbin, sieve_size_t address, const void *data, 
-	sieve_size_t size) 
-{
-	_sieve_binary_update_data(sbin, address, data, size);
-}
-
-/* Offset emission functions */
-
-sieve_size_t sieve_binary_emit_offset(struct sieve_binary *binary, int offset) 
-{
-	int i;
-	sieve_size_t address = _sieve_binary_get_code_size(binary);
-
-	for ( i = 3; i >= 0; i-- ) {
-		char c = (char) (offset >> (i * 8));
-		_sieve_binary_emit_data(binary, &c, 1);
-	}
-	
-	return address;
-}
-
-void sieve_binary_resolve_offset
-	(struct sieve_binary *binary, sieve_size_t address) 
-{
-	int i;
-	int offset = _sieve_binary_get_code_size(binary) - address; 
-	
-	for ( i = 3; i >= 0; i-- ) {
-		char c = (char) (offset >> (i * 8));	
-		_sieve_binary_update_data(binary, address + 3 - i, &c, 1);
-	}
-}
-
-/* Literal emission */
-
-/* FIXME: this integer format is compact, but it might be too slow. 
- */
-
-sieve_size_t sieve_binary_emit_integer
-(struct sieve_binary *binary, sieve_number_t integer)
-{
-	sieve_size_t address = _sieve_binary_get_code_size(binary);
-	int i;
-	char buffer[sizeof(sieve_number_t) + 1];
-	int bufpos = sizeof(buffer) - 1;
-  
-	buffer[bufpos] = integer & 0x7F;
-	bufpos--;
-	integer >>= 7;
-	while ( integer > 0 ) {
-		buffer[bufpos] = integer & 0x7F;
-		bufpos--;
-		integer >>= 7;  
-	}
-  
-	bufpos++;
-	if ( (sizeof(buffer) - bufpos) > 1 ) { 
-		for ( i = bufpos; i < ((int) sizeof(buffer) - 1); i++) {
-			buffer[i] |= 0x80;
-		}
-	} 
-  
-	_sieve_binary_emit_data(binary, buffer + bufpos, sizeof(buffer) - bufpos);
-
-	return address;
-}
-
-static inline sieve_size_t sieve_binary_emit_dynamic_data
-	(struct sieve_binary *binary, const void *data, sieve_size_t size)
-{
-	sieve_size_t address = sieve_binary_emit_integer(binary, (sieve_number_t) size);
-
-	_sieve_binary_emit_data(binary, data, size);
-  
-	return address;
-}
-
-sieve_size_t sieve_binary_emit_cstring
-	(struct sieve_binary *binary, const char *str)
-{
-	sieve_size_t address = sieve_binary_emit_dynamic_data
-		(binary, (void *) str, (sieve_size_t) strlen(str));
-	_sieve_binary_emit_byte(binary, 0);
-  
-	return address;
-}
-
-sieve_size_t sieve_binary_emit_string
-	(struct sieve_binary *binary, const string_t *str)
-{
-	sieve_size_t address = sieve_binary_emit_dynamic_data
-		(binary, (void *) str_data(str), (sieve_size_t) str_len(str));
-	_sieve_binary_emit_byte(binary, 0);
-	
-	return address;
-}
-
-/*
- * Extension emission
- */
-
-sieve_size_t sieve_binary_emit_extension
-(struct sieve_binary *sbin, const struct sieve_extension *ext,
-	unsigned int offset)
-{
-	sieve_size_t address = _sieve_binary_get_code_size(sbin);
-	struct sieve_binary_extension_reg *ereg = NULL;
-
-	(void)sieve_binary_extension_register(sbin, ext, &ereg);
-
-	i_assert(ereg != NULL);
-
-	_sieve_binary_emit_byte(sbin, offset + ereg->index);
-	return address;
-}
-
-void sieve_binary_emit_extension_object
-(struct sieve_binary *sbin, const struct sieve_extension_objects *objs,
-	unsigned int code)
-{
-	if ( objs->count > 1 )
-		_sieve_binary_emit_byte(sbin, code);
-}
-
-/*
- * Code retrieval
- */
- 
-#define ADDR_CODE_AT(binary, address) \
-	((signed char) ((binary)->code[*address]))
-#define ADDR_DATA_AT(binary, address) \
-	((unsigned char) ((binary)->code[*address]))
-#define ADDR_POINTER(binary, address) \
-	((const char *) (&(binary)->code[*address]))
-#define ADDR_BYTES_LEFT(binary, address) \
-	((binary)->code_size - (*address))
-#define ADDR_JUMP(address, offset) \
-	(*address) += offset
-
-/* Literals */
-
-bool sieve_binary_read_byte
-	(struct sieve_binary *binary, sieve_size_t *address, unsigned int *byte_r) 
-{	
-	if ( ADDR_BYTES_LEFT(binary, address) >= 1 ) {
-		if ( byte_r != NULL )
-			*byte_r = ADDR_DATA_AT(binary, address);
-		ADDR_JUMP(address, 1);
-			
-		return TRUE;
-	}
-	
-	*byte_r = 0;
-	return FALSE;
-}
-
-bool sieve_binary_read_code
-	(struct sieve_binary *binary, sieve_size_t *address, signed int *code_r) 
-{	
-	if ( ADDR_BYTES_LEFT(binary, address) >= 1 ) {
-		if ( code_r != NULL )
-			*code_r = ADDR_CODE_AT(binary, address);
-		ADDR_JUMP(address, 1);
-			
-		return TRUE;
-	}
-	
-	*code_r = 0;
-	return FALSE;
-}
-
-
-bool sieve_binary_read_offset
-	(struct sieve_binary *binary, sieve_size_t *address, int *offset_r) 
-{
-	uint32_t offs = 0;
-	
-	if ( ADDR_BYTES_LEFT(binary, address) >= 4 ) {
-		int i; 
-	  
-		for ( i = 0; i < 4; i++ ) {
-			offs = (offs << 8) + ADDR_DATA_AT(binary, address);
-			ADDR_JUMP(address, 1);
-		}
-	  
-		if ( offset_r != NULL )
-			*offset_r = (int) offs;
-			
-		return TRUE;
-	}
-	
-	return FALSE;
-}
-
-/* FIXME: might need negative numbers in the future */
-bool sieve_binary_read_integer
-  (struct sieve_binary *binary, sieve_size_t *address, sieve_number_t *int_r) 
-{
-	int bits = sizeof(sieve_number_t) * 8;
-	*int_r = 0;
-  
-	if ( ADDR_BYTES_LEFT(binary, address) == 0 )
-		return FALSE;
-  
-	while ( (ADDR_DATA_AT(binary, address) & 0x80) > 0 ) {
-		if ( ADDR_BYTES_LEFT(binary, address) > 0 && bits > 0) {
-			*int_r |= ADDR_DATA_AT(binary, address) & 0x7F;
-			ADDR_JUMP(address, 1);
-    
-			*int_r <<= 7;
-			bits -= 7;
-		} else {
-			/* This is an error */
-			return FALSE;
-		}
-	}
-  
-	*int_r |= ADDR_DATA_AT(binary, address) & 0x7F;
-	ADDR_JUMP(address, 1);
-  
-	return TRUE;
-}
-
-bool sieve_binary_read_string
-(struct sieve_binary *binary, sieve_size_t *address, string_t **str_r) 
-{
-	unsigned int strlen = 0;
-  
-	if ( !sieve_binary_read_unsigned(binary, address, &strlen) ) 
-		return FALSE;
-    	  
-	if ( strlen > ADDR_BYTES_LEFT(binary, address) ) 
-		return FALSE;
- 
- 	if ( str_r != NULL )  
-		*str_r = t_str_new_const(ADDR_POINTER(binary, address), strlen);
-	ADDR_JUMP(address, strlen);
-	
-	if ( ADDR_CODE_AT(binary, address) != 0 )
-		return FALSE;
-	
-	ADDR_JUMP(address, 1);
-  
-	return TRUE;
-}
-
-bool sieve_binary_read_extension
-(struct sieve_binary *sbin, sieve_size_t *address, unsigned int *offset_r,
-	const struct sieve_extension **ext_r)
-{
-	unsigned int code;
-	unsigned int offset = *offset_r;
-	const struct sieve_extension *ext = NULL;
-
-	if ( ADDR_BYTES_LEFT(sbin, address) <= 0 )
-		return FALSE;
-
-	(*offset_r) = code = ADDR_DATA_AT(sbin, address);
-	ADDR_JUMP(address, 1);
-
-	if ( code >= offset ) {
-		ext = _sieve_binary_extension_get_by_index(sbin, code - offset);
-		
-		if ( ext == NULL ) 
-			return FALSE;
-	}
-
-	(*ext_r) = ext;
-
-	return TRUE;
-}
-
-const void *sieve_binary_read_extension_object
-(struct sieve_binary *sbin, sieve_size_t *address, 
-	const struct sieve_extension_objects *objs)
-{
-	unsigned int code;
-
-	if ( objs->count == 0 ) 
-		return NULL;
-
-	if ( objs->count == 1 )
-		return objs->objects;
-
-	if ( ADDR_BYTES_LEFT(sbin, address) <= 0 )
-		return NULL;
-
-	code = ADDR_DATA_AT(sbin, address);
-	ADDR_JUMP(address, 1);	
-
-	if ( code >= objs->count )
-		return NULL;
-
-	return ((const void *const *) objs->objects)[code];
-}
diff --git a/src/lib-sieve/sieve-binary.h b/src/lib-sieve/sieve-binary.h
index a30cf2932..877799c39 100644
--- a/src/lib-sieve/sieve-binary.h
+++ b/src/lib-sieve/sieve-binary.h
@@ -8,6 +8,13 @@
 
 #include "sieve-common.h"
 
+/*
+ * Config
+ */
+ 
+#define SIEVE_BINARY_VERSION_MAJOR     0
+#define SIEVE_BINARY_VERSION_MINOR     2
+
 /*
  * Binary object
  */
@@ -65,12 +72,27 @@ enum sieve_binary_system_block {
 	SBIN_SYSBLOCK_LAST
 };
 
-bool sieve_binary_block_set_active
-	(struct sieve_binary *sbin, unsigned int id, unsigned *old_id_r);
-unsigned int sieve_binary_block_create(struct sieve_binary *sbin);
-void sieve_binary_block_clear
+struct sieve_binary_block *sieve_binary_block_create
+	(struct sieve_binary *sbin);
+
+unsigned int sieve_binary_block_count
+	(struct sieve_binary *sbin);
+
+struct sieve_binary_block *sieve_binary_block_get
 	(struct sieve_binary *sbin, unsigned int id);
-	
+
+void sieve_binary_block_clear
+	(struct sieve_binary_block *sblock);
+
+size_t sieve_binary_block_get_size
+	(const struct sieve_binary_block *sblock);
+
+struct sieve_binary *sieve_binary_block_get_binary
+	(const struct sieve_binary_block *sblock);
+
+unsigned int sieve_binary_block_get_id
+	(const struct sieve_binary_block *sblock);
+
 /* 
  * Extension support 
  */
@@ -103,9 +125,9 @@ void sieve_binary_extension_set
 	(struct sieve_binary *sbin, const struct sieve_extension *ext,
 		const struct sieve_binary_extension *bext, void *context);
 
-unsigned int sieve_binary_extension_create_block
+struct sieve_binary_block *sieve_binary_extension_create_block
 	(struct sieve_binary *sbin, const struct sieve_extension *ext);
-unsigned int sieve_binary_extension_get_block
+struct sieve_binary_block *sieve_binary_extension_get_block
 (struct sieve_binary *sbin, const struct sieve_extension *ext);
 
 int sieve_binary_extension_link
@@ -124,68 +146,73 @@ int sieve_binary_extensions_count(struct sieve_binary *sbin);
 /* Low-level emission functions */
 
 sieve_size_t sieve_binary_emit_data
-	(struct sieve_binary *binary, const void *data, sieve_size_t size);
+	(struct sieve_binary_block *sblock, const void *data, sieve_size_t size);
 sieve_size_t sieve_binary_emit_byte
-	(struct sieve_binary *binary, unsigned char byte);
+	(struct sieve_binary_block *sblock, unsigned char byte);
 void sieve_binary_update_data
-	(struct sieve_binary *binary, sieve_size_t address, const void *data, 
+	(struct sieve_binary_block *sblock, sieve_size_t address, const void *data, 
 		sieve_size_t size);
-sieve_size_t sieve_binary_get_code_size(struct sieve_binary *binary);
 
 /* Offset emission functions */
 
 sieve_size_t sieve_binary_emit_offset
-	(struct sieve_binary *binary, int offset);
+	(struct sieve_binary_block *sblock, int offset);
 void sieve_binary_resolve_offset
-	(struct sieve_binary *binary, sieve_size_t address);
+	(struct sieve_binary_block *sblock, sieve_size_t address);
 
 /* Literal emission functions */
 
 sieve_size_t sieve_binary_emit_integer
-	(struct sieve_binary *binary, sieve_number_t integer);
+	(struct sieve_binary_block *sblock, sieve_number_t integer);
 sieve_size_t sieve_binary_emit_string
-	(struct sieve_binary *binary, const string_t *str);
+	(struct sieve_binary_block *sblock, const string_t *str);
 sieve_size_t sieve_binary_emit_cstring
-	(struct sieve_binary *binary, const char *str);
+	(struct sieve_binary_block *sblock, const char *str);
 
 static inline sieve_size_t sieve_binary_emit_unsigned
-	(struct sieve_binary *binary, unsigned int count)
+	(struct sieve_binary_block *sblock, unsigned int count)
 {
-	return sieve_binary_emit_integer(binary, count);
+	return sieve_binary_emit_integer(sblock, count);
 }
 
-
 /* Extension emission functions */
 
 sieve_size_t sieve_binary_emit_extension
-	(struct sieve_binary *sbin, const struct sieve_extension *ext,
+	(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
 		unsigned int offset);
 void sieve_binary_emit_extension_object
-	(struct sieve_binary *sbin, const struct sieve_extension_objects *objs,
-    	unsigned int code);
+	(struct sieve_binary_block *sblock, 
+		const struct sieve_extension_objects *objs, unsigned int code);
 
 /* 
  * Code retrieval 
  */
 
 /* Literals */
+
 bool sieve_binary_read_byte
-	(struct sieve_binary *binary, sieve_size_t *address, unsigned int *byte_r);
+	(struct sieve_binary_block *sblock, sieve_size_t *address, 
+		unsigned int *byte_r);
 bool sieve_binary_read_code
-	(struct sieve_binary *binary, sieve_size_t *address, signed int *code_r);
+	(struct sieve_binary_block *sblock, sieve_size_t *address, 
+		signed int *code_r);
 bool sieve_binary_read_offset
-	(struct sieve_binary *binary, sieve_size_t *address, int *offset_r);
+	(struct sieve_binary_block *sblock, sieve_size_t *address,
+		int *offset_r);
 bool sieve_binary_read_integer
-  (struct sieve_binary *binary, sieve_size_t *address, sieve_number_t *int_r); 
+  (struct sieve_binary_block *sblock, sieve_size_t *address, 
+		sieve_number_t *int_r); 
 bool sieve_binary_read_string
-  (struct sieve_binary *binary, sieve_size_t *address, string_t **str_r);
+  (struct sieve_binary_block *sblock, sieve_size_t *address, 
+		string_t **str_r);
 
 static inline bool sieve_binary_read_unsigned
-  (struct sieve_binary *binary, sieve_size_t *address, unsigned int *count_r)
+(struct sieve_binary_block *sblock, sieve_size_t *address, 
+	unsigned int *count_r)
 {
 	sieve_number_t integer;
 
-	if ( !sieve_binary_read_integer(binary, address, &integer) )
+	if ( !sieve_binary_read_integer(sblock, address, &integer) )
 		return FALSE;
 
 	*count_r = integer;
@@ -193,12 +220,44 @@ static inline bool sieve_binary_read_unsigned
 	return TRUE;
 }
 
-/* Extension */
+/* Extensions */
+
 bool sieve_binary_read_extension
-	(struct sieve_binary *sbin, sieve_size_t *address, unsigned int *offset_r,
-		const struct sieve_extension **ext_r);
+	(struct sieve_binary_block *sblock, sieve_size_t *address,
+		unsigned int *offset_r, const struct sieve_extension **ext_r);
 const void *sieve_binary_read_extension_object
-	(struct sieve_binary *binary, sieve_size_t *address,
-    	const struct sieve_extension_objects *objs);
+	(struct sieve_binary_block *sblock, sieve_size_t *address,
+    const struct sieve_extension_objects *objs);
+
+/*
+ * Debug info
+ */
+
+/* Writer */
+
+struct sieve_binary_debug_writer;
+
+struct sieve_binary_debug_writer *sieve_binary_debug_writer_init
+	(struct sieve_binary_block *sblock);
+void sieve_binary_debug_writer_deinit
+	(struct sieve_binary_debug_writer **dwriter);
+
+void sieve_binary_debug_emit
+	(struct sieve_binary_debug_writer *dwriter, sieve_size_t code_address, 
+		unsigned int code_line, unsigned int code_column);
+
+/* Reader */
+
+struct sieve_binary_debug_reader *sieve_binary_debug_reader_init
+	(struct sieve_binary_block *sblock);
+void sieve_binary_debug_reader_deinit
+	(struct sieve_binary_debug_reader **dreader);
+
+
+void sieve_binary_debug_reader_reset
+	(struct sieve_binary_debug_reader *dreader);
+
+unsigned int sieve_binary_debug_read_line
+	(struct sieve_binary_debug_reader *dreader, sieve_size_t code_address);
 
 #endif
diff --git a/src/lib-sieve/sieve-code-dumper.c b/src/lib-sieve/sieve-code-dumper.c
index 872cfd432..1c224c13c 100644
--- a/src/lib-sieve/sieve-code-dumper.c
+++ b/src/lib-sieve/sieve-code-dumper.c
@@ -39,16 +39,20 @@ struct sieve_code_dumper {
 	
 	const struct sieve_operation *operation;
 	sieve_size_t mark_address;
+	unsigned int mark_line;
+	unsigned int mark_last_line;
 	unsigned int indent;
 	
 	/* Dump environment */
 	struct sieve_dumptime_env *dumpenv; 
+
+	struct sieve_binary_debug_reader *dreader;
 	
 	ARRAY_DEFINE(extensions, struct sieve_code_dumper_extension_reg);
 };
 
 struct sieve_code_dumper *sieve_code_dumper_create
-	(struct sieve_dumptime_env *denv) 
+(struct sieve_dumptime_env *denv) 
 {
 	pool_t pool;
 	struct sieve_code_dumper *dumper;
@@ -67,9 +71,10 @@ struct sieve_code_dumper *sieve_code_dumper_create
 }
 
 void sieve_code_dumper_free(struct sieve_code_dumper **dumper) 
-{
+{	
+	sieve_binary_debug_reader_deinit(&(*dumper)->dreader);
+
 	pool_unref(&((*dumper)->pool));
-	
 	*dumper = NULL;
 }
 
@@ -133,6 +138,14 @@ void sieve_code_dumpf
 	va_start(args, fmt);	
 	str_printfa(outbuf, "%08llx: ", (unsigned long long) cdumper->mark_address);
 	
+	if ( cdumper->mark_line > 0 && (cdumper->indent == 0 ||
+		cdumper->mark_line != cdumper->mark_last_line) ) {
+		str_printfa(outbuf, "%4u: ", cdumper->mark_line);
+		cdumper->mark_last_line = cdumper->mark_line;
+	} else {
+		str_append(outbuf, "      ");
+	}
+
 	while ( tab > 0 )	{
 		str_append(outbuf, "  ");
 		tab--;
@@ -145,15 +158,26 @@ void sieve_code_dumpf
 	o_stream_send(denv->stream, str_data(outbuf), str_len(outbuf));
 }
 
+static inline void sieve_code_line_mark
+(const struct sieve_dumptime_env *denv, sieve_size_t location)
+{
+	if ( denv->cdumper->dreader != NULL )  {
+		denv->cdumper->mark_line = sieve_binary_debug_read_line
+			(denv->cdumper->dreader, location); 
+	}
+}
+
 void sieve_code_mark(const struct sieve_dumptime_env *denv)
 {
 	denv->cdumper->mark_address = denv->cdumper->pc;
+	sieve_code_line_mark(denv, denv->cdumper->pc);
 }
 
 void sieve_code_mark_specific
 (const struct sieve_dumptime_env *denv, sieve_size_t location)
 {
 	denv->cdumper->mark_address = location;
+	sieve_code_line_mark(denv, location);
 }
 
 void sieve_code_descend(const struct sieve_dumptime_env *denv)
@@ -174,10 +198,10 @@ bool sieve_code_dumper_print_optional_operands
 {
 	int opt_code = -1;
 	
-	if ( sieve_operand_optional_present(denv->sbin, address) ) {
+	if ( sieve_operand_optional_present(denv->sblock, address) ) {
 		
 		while ( opt_code != 0 ) {			
-			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) {
+			if ( !sieve_operand_optional_read(denv->sblock, address, &opt_code) ) {
 				return FALSE;
 			}
 
@@ -203,8 +227,10 @@ static bool sieve_code_dumper_print_operation
 	dumper->indent = 0;
 	address = dumper->mark_address = dumper->pc;
 
+	sieve_code_line_mark(denv, address);
+
 	/* Read operation */
-	if ( sieve_operation_read(denv->sbin, &(dumper->pc), oprtn) ) {
+	if ( sieve_operation_read(denv->sblock, &(dumper->pc), oprtn) ) {
 		const struct sieve_operation_def *op = oprtn->def;
 
 		if ( op->dump != NULL )
@@ -225,15 +251,41 @@ void sieve_code_dumper_run(struct sieve_code_dumper *dumper)
 {
 	const struct sieve_dumptime_env *denv = dumper->dumpenv;
 	struct sieve_binary *sbin = denv->sbin;
-	unsigned int ext_count;
+	struct sieve_binary_block *sblock = denv->sblock;
+	unsigned int debug_block_id, ext_count;
 	bool success = TRUE;
 
 	dumper->pc = 0;
+
+	/* Heading */
+	o_stream_send_str(denv->stream, "Address   Line  Code\n");
+
+	/* Load debug block */
+	sieve_code_mark(denv);
 	
+	if ( sieve_binary_read_unsigned(sblock, &dumper->pc, &debug_block_id) ) {
+		struct sieve_binary_block *debug_block =
+			sieve_binary_block_get(sbin, debug_block_id);
+
+		if ( debug_block == NULL ) {
+			sieve_code_dumpf(denv, "Invalid id %d for debug block.", debug_block_id);
+			return;
+		} else {
+			/* Initialize debug reader */
+			dumper->dreader = sieve_binary_debug_reader_init(debug_block);
+
+			/* Dump block id */
+			sieve_code_dumpf(denv, "DEBUG BLOCK: %d", debug_block_id);
+		}
+	} else {
+		sieve_code_dumpf(denv, "Binary code header is corrupt.");
+		return;
+	}
+
 	/* Load and dump extensions listed in code */
 	sieve_code_mark(denv);
 	
-	if ( sieve_binary_read_unsigned(sbin, &dumper->pc, &ext_count) ) {
+	if ( sieve_binary_read_unsigned(sblock, &dumper->pc, &ext_count) ) {
 		unsigned int i;
 		
 		sieve_code_dumpf(denv, "EXTENSIONS [%d]:", ext_count);
@@ -246,7 +298,7 @@ void sieve_code_dumper_run(struct sieve_code_dumper *dumper)
 			T_BEGIN {
 				sieve_code_mark(denv);
 			
-				if ( !sieve_binary_read_extension(sbin, &dumper->pc, &code, &ext) ) {
+				if ( !sieve_binary_read_extension(sblock, &dumper->pc, &code, &ext) ) {
 					success = FALSE;
 					break;
 				}
@@ -274,7 +326,7 @@ void sieve_code_dumper_run(struct sieve_code_dumper *dumper)
 	}
 	
 	while ( dumper->pc < 
-		sieve_binary_get_code_size(sbin) ) {
+		sieve_binary_block_get_size(sblock) ) {
 
 		T_BEGIN {
 			success = sieve_code_dumper_print_operation(dumper);
@@ -288,6 +340,6 @@ void sieve_code_dumper_run(struct sieve_code_dumper *dumper)
 	
 	/* Mark end of the binary */
 	dumper->indent = 0;
-	dumper->mark_address = sieve_binary_get_code_size(sbin);
+	dumper->mark_address = sieve_binary_block_get_size(sblock);
 	sieve_code_dumpf(dumper->dumpenv, "[End of code]");	
 }
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index 5ccd5f43c..ea93fbd1a 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -37,7 +37,7 @@ static struct sieve_coded_stringlist *sieve_coded_stringlist_create
 {
 	struct sieve_coded_stringlist *strlist;
 	
-	if ( end > sieve_binary_get_code_size(renv->sbin) ) 
+	if ( end > sieve_binary_block_get_size(renv->sblock) ) 
   		return NULL;
     
 	strlist = t_new(struct sieve_coded_stringlist, 1);
@@ -128,7 +128,7 @@ static bool sieve_coded_stringlist_dump
 {
 	unsigned int i;
 	
-	if ( end > sieve_binary_get_code_size(denv->sbin) ) 
+	if ( end > sieve_binary_block_get_size(denv->sblock) ) 
   		return FALSE;
     
 	if ( field_name != NULL )
@@ -163,31 +163,31 @@ static bool sieve_coded_stringlist_dump
  */
 
 void sieve_code_source_line_emit
-(struct sieve_binary *sbin, unsigned int source_line)
+(struct sieve_binary_block *sblock, unsigned int source_line)
 {
-    (void)sieve_binary_emit_unsigned(sbin, source_line);
+	(void)sieve_binary_emit_unsigned(sblock, source_line);
 }
 
 bool sieve_code_source_line_dump
 (const struct sieve_dumptime_env *denv, sieve_size_t *address)
 {
-    unsigned int number = 0;
+	unsigned int number = 0;
 
 	sieve_code_mark(denv);
-    if (sieve_binary_read_unsigned(denv->sbin, address, &number) ) {
-        sieve_code_dumpf(denv, "(source line: %lu)", (unsigned long) number);
+	if (sieve_binary_read_unsigned(denv->sblock, address, &number) ) {
+		sieve_code_dumpf(denv, "(source line: %lu)", (unsigned long) number);
 
-        return TRUE;
-    }
+		return TRUE;
+	}
 
-    return FALSE;
+	return FALSE;
 }
 
 bool sieve_code_source_line_read
 (const struct sieve_runtime_env *renv, sieve_size_t *address,
 	unsigned int *source_line_r)
 {
-	return sieve_binary_read_unsigned(renv->sbin, address, source_line_r);
+	return sieve_binary_read_unsigned(renv->sblock, address, source_line_r);
 }
 
 /*
@@ -217,26 +217,26 @@ const unsigned int sieve_operand_count =
  */
 
 sieve_size_t sieve_operand_emit
-(struct sieve_binary *sbin, const struct sieve_extension *ext, 
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext, 
 	const struct sieve_operand_def *opr_def)
 {
 	sieve_size_t address;
 
 	if ( ext != NULL ) {
 		address = sieve_binary_emit_extension
-			(sbin, ext, sieve_operand_count);
+			(sblock, ext, sieve_operand_count);
 	
 		sieve_binary_emit_extension_object
-			(sbin, &opr_def->ext_def->operands, opr_def->code);
+			(sblock, &opr_def->ext_def->operands, opr_def->code);
 
 		return address;
 	}
 
-	return sieve_binary_emit_byte(sbin, opr_def->code);
+	return sieve_binary_emit_byte(sblock, opr_def->code);
 }
 
 bool sieve_operand_read
-(struct sieve_binary *sbin, sieve_size_t *address, 
+(struct sieve_binary_block *sblock, sieve_size_t *address, 
 	struct sieve_operand *operand) 
 {
 	unsigned int code = sieve_operand_count;
@@ -245,7 +245,7 @@ bool sieve_operand_read
 	operand->ext = NULL;
 	operand->def = NULL;
 
-	if ( !sieve_binary_read_extension(sbin, address, &code, &operand->ext) )
+	if ( !sieve_binary_read_extension(sblock, address, &code, &operand->ext) )
 		return NULL;
 
 	if ( operand->ext == NULL ) {
@@ -259,19 +259,19 @@ bool sieve_operand_read
 		return FALSE;
 
 	operand->def = (const struct sieve_operand_def *) 
-		sieve_binary_read_extension_object(sbin, address, 
+		sieve_binary_read_extension_object(sblock, address, 
 			&operand->ext->def->operands);
 
 	return ( operand->def != NULL );
 }
 
 bool sieve_operand_optional_present
-(struct sieve_binary *sbin, sieve_size_t *address)
+(struct sieve_binary_block *sblock, sieve_size_t *address)
 {	
 	sieve_size_t tmp_addr = *address;
 	unsigned int op = -1;
 	
-	if ( sieve_binary_read_byte(sbin, &tmp_addr, &op) && 
+	if ( sieve_binary_read_byte(sblock, &tmp_addr, &op) && 
 		(op == SIEVE_OPERAND_OPTIONAL) ) {
 		*address = tmp_addr;
 		return TRUE;
@@ -281,9 +281,9 @@ bool sieve_operand_optional_present
 }
 
 bool sieve_operand_optional_read
-(struct sieve_binary *sbin, sieve_size_t *address, signed int *id_code)
+(struct sieve_binary_block *sblock, sieve_size_t *address, signed int *id_code)
 {
-	if ( sieve_binary_read_code(sbin, address, id_code) ) 
+	if ( sieve_binary_read_code(sblock, address, id_code) ) 
 		return TRUE;
 	
 	*id_code = 0;
@@ -404,17 +404,18 @@ const struct sieve_operand_def catenated_string_operand = {
 
 /* Omitted */
 
-void sieve_opr_omitted_emit(struct sieve_binary *sbin)
+void sieve_opr_omitted_emit(struct sieve_binary_block *sblock)
 {
-	(void) sieve_operand_emit(sbin, NULL, &omitted_operand);
+	(void) sieve_operand_emit(sblock, NULL, &omitted_operand);
 }
  
 /* Number */
 
-void sieve_opr_number_emit(struct sieve_binary *sbin, sieve_number_t number) 
+void sieve_opr_number_emit
+(struct sieve_binary_block *sblock, sieve_number_t number) 
 {
-	(void) sieve_operand_emit(sbin, NULL, &number_operand);
-	(void) sieve_binary_emit_integer(sbin, number);
+	(void) sieve_operand_emit(sblock, NULL, &number_operand);
+	(void) sieve_binary_emit_integer(sblock, number);
 }
 
 bool sieve_opr_number_dump_data
@@ -442,7 +443,7 @@ bool sieve_opr_number_dump
 	
 	sieve_code_mark(denv);
 	
-	if ( !sieve_operand_read(denv->sbin, address, &operand) )
+	if ( !sieve_operand_read(denv->sblock, address, &operand) )
 		return FALSE;
 
 	return sieve_opr_number_dump_data(denv, &operand, address, field_name);
@@ -471,7 +472,7 @@ bool sieve_opr_number_read
 {
 	struct sieve_operand operand;
 
-	if ( !sieve_operand_read(renv->sbin, address, &operand) )
+	if ( !sieve_operand_read(renv->sblock, address, &operand) )
 		return FALSE;
 		
 	return sieve_opr_number_read_data(renv, &operand, address, number_r);
@@ -483,7 +484,7 @@ static bool opr_number_dump
 {
 	sieve_number_t number = 0;
 	
-	if (sieve_binary_read_integer(denv->sbin, address, &number) ) {
+	if (sieve_binary_read_integer(denv->sblock, address, &number) ) {
 		if ( field_name != NULL ) 
 			sieve_code_dumpf(denv, "%s: NUM %llu", field_name, 
 				(unsigned long long) number);
@@ -500,15 +501,15 @@ static bool opr_number_read
 (const struct sieve_runtime_env *renv, sieve_size_t *address, 
 	sieve_number_t *number_r)
 { 
-	return sieve_binary_read_integer(renv->sbin, address, number_r);
+	return sieve_binary_read_integer(renv->sblock, address, number_r);
 }
 
 /* String */
 
-void sieve_opr_string_emit(struct sieve_binary *sbin, string_t *str)
+void sieve_opr_string_emit(struct sieve_binary_block *sblock, string_t *str)
 {
-	(void) sieve_operand_emit(sbin, NULL, &string_operand);
-	(void) sieve_binary_emit_string(sbin, str);
+	(void) sieve_operand_emit(sblock, NULL, &string_operand);
+	(void) sieve_binary_emit_string(sblock, str);
 }
 
 bool sieve_opr_string_dump_data
@@ -541,7 +542,7 @@ bool sieve_opr_string_dump
 	
 	sieve_code_mark(denv);
 
-	if ( !sieve_operand_read(denv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(denv->sblock, address, &operand) ) {
 		sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
 		return FALSE;
 	}
@@ -556,7 +557,7 @@ bool sieve_opr_string_dump_ex
 	struct sieve_operand operand;
 	
 	sieve_code_mark(denv);
-	if ( !sieve_operand_read(denv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(denv->sblock, address, &operand) ) {
 		sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
 		return FALSE;
 	}
@@ -588,7 +589,7 @@ bool sieve_opr_string_read
 {
 	struct sieve_operand operand;
 
-	if ( !sieve_operand_read(renv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(renv->sblock, address, &operand) ) {
 		return FALSE;
 	}
 
@@ -601,7 +602,7 @@ bool sieve_opr_string_read_ex
 {
 	struct sieve_operand operand;
 
-	if ( !sieve_operand_read(renv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(renv->sblock, address, &operand) ) {
 		return FALSE;
 	}
 
@@ -638,7 +639,7 @@ bool opr_string_dump
 {
 	string_t *str; 
 	
-	if ( sieve_binary_read_string(denv->sbin, address, &str) ) {
+	if ( sieve_binary_read_string(denv->sblock, address, &str) ) {
 		_dump_string(denv, str, field_name);   		
 		
 		return TRUE;
@@ -652,39 +653,39 @@ static bool opr_string_read
 	const struct sieve_operand *opr ATTR_UNUSED, sieve_size_t *address, 
 	string_t **str_r)
 { 	
-	return sieve_binary_read_string(renv->sbin, address, str_r);
+	return sieve_binary_read_string(renv->sblock, address, str_r);
 }
 
 /* String list */
 
 void sieve_opr_stringlist_emit_start
-(struct sieve_binary *sbin, unsigned int listlen, void **context)
+(struct sieve_binary_block *sblock, unsigned int listlen, void **context)
 {
 	sieve_size_t *end_offset = t_new(sieve_size_t, 1);
 
 	/* Emit byte identifying the type of operand */	  
-	(void) sieve_operand_emit(sbin, NULL, &stringlist_operand);
+	(void) sieve_operand_emit(sblock, NULL, &stringlist_operand);
   
 	/* Give the interpreter an easy way to skip over this string list */
-	*end_offset = sieve_binary_emit_offset(sbin, 0);
+	*end_offset = sieve_binary_emit_offset(sblock, 0);
 	*context = (void *) end_offset;
 
 	/* Emit the length of the list */
-	(void) sieve_binary_emit_unsigned(sbin, listlen);
+	(void) sieve_binary_emit_unsigned(sblock, listlen);
 }
 
 void sieve_opr_stringlist_emit_item
-(struct sieve_binary *sbin, void *context ATTR_UNUSED, string_t *item)
+(struct sieve_binary_block *sblock, void *context ATTR_UNUSED, string_t *item)
 {
-	(void) sieve_opr_string_emit(sbin, item);
+	(void) sieve_opr_string_emit(sblock, item);
 }
 
 void sieve_opr_stringlist_emit_end
-(struct sieve_binary *sbin, void *context)
+(struct sieve_binary_block *sblock, void *context)
 {
 	sieve_size_t *end_offset = (sieve_size_t *) context;
 
-	(void) sieve_binary_resolve_offset(sbin, *end_offset);
+	(void) sieve_binary_resolve_offset(sblock, *end_offset);
 }
 
 bool sieve_opr_stringlist_dump_data
@@ -723,7 +724,7 @@ bool sieve_opr_stringlist_dump
 
 	sieve_code_mark(denv);
 
-	if ( !sieve_operand_read(denv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(denv->sblock, address, &operand) ) {
 		return FALSE;
 	}
 
@@ -765,7 +766,7 @@ struct sieve_coded_stringlist *sieve_opr_stringlist_read
 {
 	struct sieve_operand operand;
 
-	if ( !sieve_operand_read(renv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(renv->sblock, address, &operand) ) {
 		return NULL;
 	}
 	
@@ -781,12 +782,12 @@ static bool opr_stringlist_dump
 	unsigned int length = 0; 
  	int end_offset;
 
-	if ( !sieve_binary_read_offset(denv->sbin, address, &end_offset) )
+	if ( !sieve_binary_read_offset(denv->sblock, address, &end_offset) )
 		return FALSE;
 
 	end = pc + end_offset;
 
-	if ( !sieve_binary_read_unsigned(denv->sbin, address, &length) ) 
+	if ( !sieve_binary_read_unsigned(denv->sblock, address, &length) ) 
 		return FALSE;	
   	
 	return sieve_coded_stringlist_dump(denv, address, length, end, field_name); 
@@ -801,12 +802,12 @@ static struct sieve_coded_stringlist *opr_stringlist_read
 	unsigned int length = 0;  
 	int end_offset;
 	
-	if ( !sieve_binary_read_offset(renv->sbin, address, &end_offset) )
+	if ( !sieve_binary_read_offset(renv->sblock, address, &end_offset) )
 		return NULL;
 
 	end = pc + end_offset;
 
-	if ( !sieve_binary_read_unsigned(renv->sbin, address, &length) ) 
+	if ( !sieve_binary_read_unsigned(renv->sblock, address, &length) ) 
 	  	return NULL;	
   	
 	strlist = sieve_coded_stringlist_create(renv, *address, (unsigned int) length, end); 
@@ -820,10 +821,10 @@ static struct sieve_coded_stringlist *opr_stringlist_read
 /* Catenated String */
 
 void sieve_opr_catenated_string_emit
-(struct sieve_binary *sbin, unsigned int elements) 
+(struct sieve_binary_block *sblock, unsigned int elements) 
 {
-	(void) sieve_operand_emit(sbin, NULL, &catenated_string_operand);
-	(void) sieve_binary_emit_unsigned(sbin, elements);
+	(void) sieve_operand_emit(sblock, NULL, &catenated_string_operand);
+	(void) sieve_binary_emit_unsigned(sblock, elements);
 }
 
 static bool opr_catenated_string_dump
@@ -834,7 +835,7 @@ static bool opr_catenated_string_dump
 	unsigned int elements = 0;
 	unsigned int i;
 	
-	if (!sieve_binary_read_unsigned(denv->sbin, address, &elements) )
+	if (!sieve_binary_read_unsigned(denv->sblock, address, &elements) )
 		return FALSE;
 	
 	if ( field_name != NULL ) 
@@ -861,7 +862,7 @@ static bool opr_catenated_string_read
 	unsigned int elements = 0;
 	unsigned int i;
 		
-	if ( !sieve_binary_read_unsigned(renv->sbin, address, &elements) )
+	if ( !sieve_binary_read_unsigned(renv->sblock, address, &elements) )
 		return FALSE;
 
 	/* Parameter str can be NULL if we are requested to only skip and not 
@@ -978,26 +979,26 @@ const unsigned int sieve_operation_count =
  */
 
 sieve_size_t sieve_operation_emit
-(struct sieve_binary *sbin, const struct sieve_extension *ext,
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
 	const struct sieve_operation_def *op_def)
 {
 	sieve_size_t address;
 
   if ( ext != NULL ) {
 		address = sieve_binary_emit_extension
-			(sbin, ext, sieve_operation_count);
+			(sblock, ext, sieve_operation_count);
 
 		sieve_binary_emit_extension_object
-			(sbin, &op_def->ext_def->operations, op_def->code);
+			(sblock, &op_def->ext_def->operations, op_def->code);
 
 		return address;
   }
 
-  return sieve_binary_emit_byte(sbin, op_def->code);
+  return sieve_binary_emit_byte(sblock, op_def->code);
 }
 
 bool sieve_operation_read
-(struct sieve_binary *sbin, sieve_size_t *address,
+(struct sieve_binary_block *sblock, sieve_size_t *address,
 	struct sieve_operation *oprtn) 
 {
 	unsigned int code = sieve_operation_count;
@@ -1006,7 +1007,7 @@ bool sieve_operation_read
 	oprtn->def = NULL;
 	oprtn->ext = NULL;
 
-	if ( !sieve_binary_read_extension(sbin, address, &code, &oprtn->ext) )
+	if ( !sieve_binary_read_extension(sblock, address, &code, &oprtn->ext) )
 		return FALSE;
 
 	if ( !oprtn->ext ) {
@@ -1018,7 +1019,7 @@ bool sieve_operation_read
 	}
 
 	oprtn->def = (const struct sieve_operation_def *) 
-		sieve_binary_read_extension_object(sbin, address, 
+		sieve_binary_read_extension_object(sblock, address, 
 			&oprtn->ext->def->operations);
 
 	return ( oprtn->def != NULL );
@@ -1037,7 +1038,7 @@ static bool opc_jmp_dump
 	unsigned int pc = *address;
 	int offset;
 	
-	if ( sieve_binary_read_offset(denv->sbin, address, &offset) ) 
+	if ( sieve_binary_read_offset(denv->sblock, address, &offset) ) 
 		sieve_code_dumpf(denv, "%s %d [%08x]", 
 			sieve_operation_mnemonic(op), offset, pc + offset);
 	else
diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h
index 83b4dabff..46963cea5 100644
--- a/src/lib-sieve/sieve-code.h
+++ b/src/lib-sieve/sieve-code.h
@@ -37,7 +37,7 @@ sieve_size_t sieve_coded_stringlist_get_current_offset
  */
 
 void sieve_code_source_line_emit
-	(struct sieve_binary *sbin, unsigned int source_line);
+	(struct sieve_binary_block *sblock, unsigned int source_line);
 bool sieve_code_source_line_dump
 	(const struct sieve_dumptime_env *denv, sieve_size_t *address);
 bool sieve_code_source_line_read
@@ -74,16 +74,16 @@ struct sieve_operand {
 	( (opr)->def == &(definition) )
 
 sieve_size_t sieve_operand_emit
-	(struct sieve_binary *sbin, const struct sieve_extension *ext,
+	(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
 		const struct sieve_operand_def *oprnd);
 bool sieve_operand_read
-	(struct sieve_binary *sbin, sieve_size_t *address, 
+	(struct sieve_binary_block *sblock, sieve_size_t *address, 
 		struct sieve_operand *oprnd);
 
 bool sieve_operand_optional_present
-	(struct sieve_binary *sbin, sieve_size_t *address);
+	(struct sieve_binary_block *sblock, sieve_size_t *address);
 bool sieve_operand_optional_read	
-	(struct sieve_binary *sbin, sieve_size_t *address, 
+	(struct sieve_binary_block *sblock, sieve_size_t *address, 
 		signed int *id_code);
 
 /*
@@ -156,7 +156,7 @@ struct sieve_opr_stringlist_interface {
 
 /* Omitted */
 
-void sieve_opr_omitted_emit(struct sieve_binary *sbin);
+void sieve_opr_omitted_emit(struct sieve_binary_block *sblock);
 
 static inline bool sieve_operand_is_omitted
 (const struct sieve_operand *operand)
@@ -167,7 +167,8 @@ static inline bool sieve_operand_is_omitted
 
 /* Number */
 
-void sieve_opr_number_emit(struct sieve_binary *sbin, sieve_number_t number);
+void sieve_opr_number_emit
+	(struct sieve_binary_block *sblock, sieve_number_t number);
 bool sieve_opr_number_dump_data	
 	(const struct sieve_dumptime_env *denv, const struct sieve_operand *operand,
 		sieve_size_t *address, const char *field_name); 
@@ -190,7 +191,8 @@ static inline bool sieve_operand_is_number
 
 /* String */
 
-void sieve_opr_string_emit(struct sieve_binary *sbin, string_t *str);
+void sieve_opr_string_emit
+	(struct sieve_binary_block *sblock, string_t *str);
 bool sieve_opr_string_dump_data
 	(const struct sieve_dumptime_env *denv, const struct sieve_operand *operand,
 		sieve_size_t *address, const char *field_name); 
@@ -219,11 +221,12 @@ static inline bool sieve_operand_is_string
 /* String list */
 
 void sieve_opr_stringlist_emit_start
-	(struct sieve_binary *sbin, unsigned int listlen, void **context);
+	(struct sieve_binary_block *sblock, unsigned int listlen, void **context);
 void sieve_opr_stringlist_emit_item
-	(struct sieve_binary *sbin, void *context ATTR_UNUSED, string_t *item);
+	(struct sieve_binary_block *sblock, void *context ATTR_UNUSED,
+		string_t *item);
 void sieve_opr_stringlist_emit_end
-	(struct sieve_binary *sbin, void *context);
+	(struct sieve_binary_block *sblock, void *context);
 bool sieve_opr_stringlist_dump_data
 	(const struct sieve_dumptime_env *denv, const struct sieve_operand *operand, 
 		sieve_size_t *address, const char *field_name);
@@ -247,7 +250,7 @@ static inline bool sieve_operand_is_stringlist
 /* Catenated string */
 
 void sieve_opr_catenated_string_emit
-	(struct sieve_binary *sbin, unsigned int elements);
+	(struct sieve_binary_block *sblock, unsigned int elements);
 	
 /*
  * Operation object
@@ -278,13 +281,13 @@ struct sieve_operation {
 	( (oprtn)->def == NULL ? "(NULL)" : (oprtn)->def->mnemonic )
 
 sieve_size_t sieve_operation_emit
-	(struct sieve_binary *sbin, const struct sieve_extension *ext,
+	(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
 		const struct sieve_operation_def *op_def);	
 bool sieve_operation_read
-	(struct sieve_binary *sbin, sieve_size_t *address,
+	(struct sieve_binary_block *sblock, sieve_size_t *address,
 		struct sieve_operation *oprtn);
 const char *sieve_operation_read_string
-	(struct sieve_binary *sbin, sieve_size_t *address);
+	(struct sieve_binary_block *sblock, sieve_size_t *address);
 
 /* 
  * Core operations 
diff --git a/src/lib-sieve/sieve-commands.c b/src/lib-sieve/sieve-commands.c
index 705483ede..5245ee2de 100644
--- a/src/lib-sieve/sieve-commands.c
+++ b/src/lib-sieve/sieve-commands.c
@@ -63,7 +63,7 @@ static bool arg_number_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, 
 	struct sieve_command *cmd ATTR_UNUSED)
 {
-	sieve_opr_number_emit(cgenv->sbin, sieve_ast_argument_number(arg));
+	sieve_opr_number_emit(cgenv->sblock, sieve_ast_argument_number(arg));
 
 	return TRUE;
 }
@@ -72,7 +72,7 @@ static bool arg_string_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, 
 	struct sieve_command *cmd ATTR_UNUSED)
 {
-	sieve_opr_string_emit(cgenv->sbin, sieve_ast_argument_str(arg));
+	sieve_opr_string_emit(cgenv->sblock, sieve_ast_argument_str(arg));
   
 	return TRUE;
 }
@@ -102,7 +102,7 @@ static bool emit_string_list_operand
 	struct sieve_ast_argument *stritem;
    	
 	sieve_opr_stringlist_emit_start
-		(cgenv->sbin, sieve_ast_strlist_count(strlist), &list_context);
+		(cgenv->sblock, sieve_ast_strlist_count(strlist), &list_context);
 
 	stritem = sieve_ast_strlist_first(strlist);
 	while ( stritem != NULL ) {
@@ -112,7 +112,7 @@ static bool emit_string_list_operand
 		stritem = sieve_ast_strlist_next(stritem);
 	}
 
-	sieve_opr_stringlist_emit_end(cgenv->sbin, list_context);
+	sieve_opr_stringlist_emit_end(cgenv->sblock, list_context);
 	
 	return TRUE;
 }
@@ -185,7 +185,6 @@ bool sieve_arg_catenated_string_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, 
 	struct sieve_command *cmd) 
 {
-	struct sieve_binary *sbin = cgenv->sbin;
 	struct sieve_arg_catenated_string *catstr = 
 		(struct sieve_arg_catenated_string *) arg->argument->data;
 	struct sieve_ast_argument *strpart;
@@ -193,7 +192,7 @@ bool sieve_arg_catenated_string_generate
 	if ( _cat_string_count(catstr) == 1 )
 		sieve_generate_argument(cgenv, _cat_string_first(catstr), cmd);
 	else {
-		sieve_opr_catenated_string_emit(sbin, _cat_string_count(catstr));
+		sieve_opr_catenated_string_emit(cgenv->sblock, _cat_string_count(catstr));
 
 		strpart = _cat_string_first(catstr);
 		while ( strpart != NULL ) {
diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h
index 28b601541..d037b165a 100644
--- a/src/lib-sieve/sieve-common.h
+++ b/src/lib-sieve/sieve-common.h
@@ -86,6 +86,9 @@ struct sieve_coded_stringlist;
 
 /* sieve-binary.h */
 struct sieve_binary;
+struct sieve_binary_block;
+struct sieve_binary_debug_writer;
+struct sieve_binary_debug_reader;
 
 /* sieve-objects.h */
 struct sieve_object_def;
diff --git a/src/lib-sieve/sieve-comparators.c b/src/lib-sieve/sieve-comparators.c
index 6b175ffdb..81dca88e4 100644
--- a/src/lib-sieve/sieve-comparators.c
+++ b/src/lib-sieve/sieve-comparators.c
@@ -193,7 +193,7 @@ static bool tag_comparator_generate
 	const struct sieve_comparator *cmp = 
 		(const struct sieve_comparator *) arg->argument->data;
 	
-	sieve_opr_comparator_emit(cgenv->sbin, cmp);
+	sieve_opr_comparator_emit(cgenv->sblock, cmp);
 		
 	return TRUE;
 }
diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h
index d12d0d8c5..727ab93f5 100644
--- a/src/lib-sieve/sieve-comparators.h
+++ b/src/lib-sieve/sieve-comparators.h
@@ -120,9 +120,9 @@ extern const struct sieve_operand_class sieve_comparator_operand_class;
 extern const struct sieve_operand_def comparator_operand;
 
 static inline void sieve_opr_comparator_emit
-(struct sieve_binary *sbin, const struct sieve_comparator *cmp)
+(struct sieve_binary_block *sblock, const struct sieve_comparator *cmp)
 { 
-	sieve_opr_object_emit(sbin, cmp->object.ext, cmp->object.def);
+	sieve_opr_object_emit(sblock, cmp->object.ext, cmp->object.def);
 }
 
 static inline bool sieve_opr_comparator_read
diff --git a/src/lib-sieve/sieve-dump.h b/src/lib-sieve/sieve-dump.h
index 22f99bf03..5e0a96f3c 100644
--- a/src/lib-sieve/sieve-dump.h
+++ b/src/lib-sieve/sieve-dump.h
@@ -21,6 +21,7 @@ struct sieve_dumptime_env {
 	struct sieve_instance *svinst;
 
 	struct sieve_binary *sbin;
+	struct sieve_binary_block *sblock;
 
 	struct sieve_operation oprtn;
 	
diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c
index 25c9ee823..0d04b7016 100644
--- a/src/lib-sieve/sieve-generator.c
+++ b/src/lib-sieve/sieve-generator.c
@@ -18,21 +18,21 @@
  */
 
 struct sieve_jumplist *sieve_jumplist_create
-	(pool_t pool, struct sieve_binary *sbin)
+(pool_t pool, struct sieve_binary_block *sblock)
 {
 	struct sieve_jumplist *jlist;
 	
 	jlist = p_new(pool, struct sieve_jumplist, 1);
-	jlist->binary = sbin;
+	jlist->block = sblock;
 	p_array_init(&jlist->jumps, pool, 4);
 	
 	return jlist;
 }
 
 void sieve_jumplist_init_temp
-	(struct sieve_jumplist *jlist, struct sieve_binary *sbin)
+(struct sieve_jumplist *jlist, struct sieve_binary_block *sblock)
 {
-	jlist->binary = sbin;
+	jlist->block = sblock;
 	t_array_init(&jlist->jumps, 4);
 }
 
@@ -54,7 +54,7 @@ void sieve_jumplist_resolve(struct sieve_jumplist *jlist)
 	for ( i = 0; i < array_count(&jlist->jumps); i++ ) {
 		const sieve_size_t *jump = array_idx(&jlist->jumps, i);
 	
-		sieve_binary_resolve_offset(jlist->binary, *jump);
+		sieve_binary_resolve_offset(jlist->block, *jump);
 	}
 }
 
@@ -70,6 +70,7 @@ struct sieve_generator {
 	struct sieve_error_handler *ehandler;
 
 	struct sieve_codegen_env genenv;
+	struct sieve_binary_debug_writer *dwriter;
 	
 	ARRAY_DEFINE(ext_contexts, void *);
 };
@@ -105,18 +106,19 @@ struct sieve_generator *sieve_generator_create
 	return gentr;
 }
 
-void sieve_generator_free(struct sieve_generator **generator) 
+void sieve_generator_free(struct sieve_generator **gentr) 
 {
-	sieve_ast_unref(&(*generator)->genenv.ast);
-	
-	if ( (*generator)->genenv.sbin != NULL )
-		sieve_binary_unref(&(*generator)->genenv.sbin);
-	
-	sieve_error_handler_unref(&(*generator)->ehandler);
+	sieve_ast_unref(&(*gentr)->genenv.ast);
+		
+	sieve_error_handler_unref(&(*gentr)->ehandler);
+	sieve_binary_debug_writer_deinit(&(*gentr)->dwriter);
+
+	if ( (*gentr)->genenv.sbin != NULL )
+		sieve_binary_unref(&(*gentr)->genenv.sbin);
 
-	pool_unref(&((*generator)->pool));
+	pool_unref(&((*gentr)->pool));
 	
-	*generator = NULL;
+	*gentr = NULL;
 }
 
 /* 
@@ -141,11 +143,17 @@ struct sieve_script *sieve_generator_script
 }
 
 struct sieve_binary *sieve_generator_get_binary
-	(struct sieve_generator *gentr)
+(struct sieve_generator *gentr)
 {
 	return gentr->genenv.sbin;
 }
 
+struct sieve_binary_block *sieve_generator_get_block
+(struct sieve_generator *gentr)
+{
+	return gentr->genenv.sblock;
+}
+
 /* 
  * Error handling 
  */
@@ -218,6 +226,24 @@ const void *sieve_generator_extension_get_context
  * Code generation API
  */
 
+static void sieve_generate_debug_from_ast_node
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_node *ast_node)
+{
+	sieve_size_t address = sieve_binary_block_get_size(cgenv->sblock);
+	unsigned int line = sieve_ast_node_line(ast_node);
+
+	sieve_binary_debug_emit(cgenv->gentr->dwriter, address, line, 0);
+}
+
+static void sieve_generate_debug_from_ast_argument
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *ast_arg)
+{
+	sieve_size_t address = sieve_binary_block_get_size(cgenv->sblock);
+	unsigned int line = sieve_ast_argument_line(ast_arg);
+
+	sieve_binary_debug_emit(cgenv->gentr->dwriter, address, line, 0);
+}
+
 bool sieve_generate_argument
 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, 
 	struct sieve_command *cmd)
@@ -228,8 +254,12 @@ bool sieve_generate_argument
 
 	arg_def = arg->argument->def;
 	
-	return ( arg_def->generate == NULL || 	
-		arg_def->generate(cgenv, arg, cmd) );
+	if ( arg_def->generate == NULL )
+		return TRUE;
+
+	sieve_generate_debug_from_ast_argument(cgenv, arg);
+
+	return arg_def->generate(cgenv, arg, cmd);
 }
 
 bool sieve_generate_arguments
@@ -257,10 +287,11 @@ bool sieve_generate_arguments
 				state = ARG_POSITIONAL;
 			else {
 				/* Mark start of optional operands with 0 operand identifier */
-				sieve_binary_emit_byte(cgenv->sbin, SIEVE_OPERAND_OPTIONAL);
+				sieve_binary_emit_byte(cgenv->sblock, SIEVE_OPERAND_OPTIONAL);
 								
 				/* Emit argument id for optional operand */
-				sieve_binary_emit_byte(cgenv->sbin, (unsigned char) argument->id_code);
+				sieve_binary_emit_byte
+					(cgenv->sblock, (unsigned char) argument->id_code);
 
 				state = ARG_OPTIONAL;
 			}
@@ -270,7 +301,8 @@ bool sieve_generate_arguments
 				state = ARG_POSITIONAL;
 			
 			/* Emit argument id for optional operand (0 marks the end of the optionals) */
-			sieve_binary_emit_byte(cgenv->sbin, (unsigned char) argument->id_code);
+			sieve_binary_emit_byte
+				(cgenv->sblock, (unsigned char) argument->id_code);
 
 			break;
 		case ARG_POSITIONAL:
@@ -280,7 +312,9 @@ bool sieve_generate_arguments
 		}
 		
 		/* Call the generation function for the argument */ 
-		if ( arg_def->generate != NULL ) { 
+		if ( arg_def->generate != NULL ) {
+			sieve_generate_debug_from_ast_argument(cgenv, arg);
+ 
 			if ( !arg_def->generate(cgenv, arg, cmd) ) 
 				return FALSE;
 		} else if ( state == ARG_POSITIONAL ) break;
@@ -290,7 +324,7 @@ bool sieve_generate_arguments
 
 	/* Mark end of optional list if it is still open */
 	if ( state == ARG_OPTIONAL )
-		sieve_binary_emit_byte(cgenv->sbin, 0);
+		sieve_binary_emit_byte(cgenv->sblock, 0);
 	
 	if ( last_arg_r != NULL )
 		*last_arg_r = arg;
@@ -311,7 +345,9 @@ bool sieve_generate_argument_parameters
 			const struct sieve_argument_def *parameter = param->argument->def;
 				
 			/* Call the generation function for the parameter */ 
-			if ( parameter->generate != NULL ) { 
+			if ( parameter->generate != NULL ) {
+				sieve_generate_debug_from_ast_argument(cgenv, param);
+			 
 				if ( !parameter->generate(cgenv, param, cmd) ) 
 					return FALSE;
 			}
@@ -336,6 +372,8 @@ bool sieve_generate_test
 	tst_def = test->def;
 
 	if ( tst_def->control_generate != NULL ) {
+		sieve_generate_debug_from_ast_node(cgenv, tst_node);
+		
 		if ( tst_def->control_generate(cgenv, test, jlist, jump_true) ) 
 			return TRUE;
 		
@@ -343,14 +381,15 @@ bool sieve_generate_test
 	}
 	
 	if ( tst_def->generate != NULL ) {
+		sieve_generate_debug_from_ast_node(cgenv, tst_node);
 
 		if ( tst_def->generate(cgenv, test) ) {
 			
 			if ( jump_true ) 
-				sieve_operation_emit(cgenv->sbin, NULL, &sieve_jmptrue_operation);
+				sieve_operation_emit(cgenv->sblock, NULL, &sieve_jmptrue_operation);
 			else
-				sieve_operation_emit(cgenv->sbin, NULL, &sieve_jmpfalse_operation);
-			sieve_jumplist_add(jlist, sieve_binary_emit_offset(cgenv->sbin, 0));
+				sieve_operation_emit(cgenv->sblock, NULL, &sieve_jmpfalse_operation);
+			sieve_jumplist_add(jlist, sieve_binary_emit_offset(cgenv->sblock, 0));
 						
 			return TRUE;
 		}	
@@ -373,6 +412,8 @@ static bool sieve_generate_command
 	cmd_def = command->def;
 
 	if ( cmd_def->generate != NULL ) {
+		sieve_generate_debug_from_ast_node(cgenv, cmd_node);
+
 		return cmd_def->generate(cgenv, command);
 	}
 	
@@ -396,40 +437,52 @@ bool sieve_generate_block
 	return result;
 }
 
-bool sieve_generator_run
-(struct sieve_generator *gentr, struct sieve_binary **sbin) 
+struct sieve_binary *sieve_generator_run
+(struct sieve_generator *gentr, struct sieve_binary_block **sblock_r) 
 {
-	bool topmost = ( *sbin == NULL );
-	bool result = TRUE;
+	bool topmost = ( sblock_r == NULL || *sblock_r == NULL );
+	struct sieve_binary *sbin;
+	struct sieve_binary_block *sblock, *debug_block;
 	const struct sieve_extension *const *extensions;
 	unsigned int i, ext_count;
+	bool result = TRUE;
 	
 	/* Initialize */
 	
-	if ( topmost )
-		*sbin = sieve_binary_create_new(sieve_ast_script(gentr->genenv.ast));
+	if ( topmost ) {
+		sbin = sieve_binary_create_new(sieve_ast_script(gentr->genenv.ast));
+		sblock = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM);
+	} else {
+		sblock = *sblock_r;
+		sbin = sieve_binary_block_get_binary(sblock);
+	}
 	
-	sieve_binary_ref(*sbin);
-		
-	gentr->genenv.sbin = *sbin;
+	sieve_binary_ref(sbin);
+	gentr->genenv.sbin = sbin;
+	gentr->genenv.sblock = sblock;
+
+	/* Create debug block */
+	debug_block = sieve_binary_block_create(sbin);
+	gentr->dwriter = sieve_binary_debug_writer_init(debug_block);
+	(void)sieve_binary_emit_unsigned
+		(sblock, sieve_binary_block_get_id(debug_block));
 		
 	/* Load extensions linked to the AST and emit a list in code */
 	extensions = sieve_ast_extensions_get(gentr->genenv.ast, &ext_count);
-	(void) sieve_binary_emit_unsigned(*sbin, ext_count);
-	for ( i = 0; i < ext_count; i++ ) {
+	(void) sieve_binary_emit_unsigned(sblock, ext_count);
+	for ( i = 0; i < ext_count && sbin != NULL; i++ ) {
 		const struct sieve_extension *ext = extensions[i];
 
 		/* Link to binary */
-		(void)sieve_binary_extension_link(*sbin, ext);
+		(void)sieve_binary_extension_link(sbin, ext);
 	
 		/* Emit */
-		sieve_binary_emit_extension(*sbin, ext, 0);
+		sieve_binary_emit_extension(sblock, ext, 0);
 	
 		/* Load */
 		if ( ext->def != NULL && ext->def->generator_load != NULL &&
-			!ext->def->generator_load(ext, &gentr->genenv) ) {
+			!ext->def->generator_load(ext, &gentr->genenv) )
 			result = FALSE;
-		}
 	}
 
 	/* Generate code */
@@ -439,20 +492,28 @@ bool sieve_generator_run
 			(&gentr->genenv, sieve_ast_root(gentr->genenv.ast))) 
 			result = FALSE;
 		else if ( topmost ) 
-			sieve_binary_activate(*sbin);
+			sieve_binary_activate(sbin);
 	}
 
 	/* Cleanup */
 		
 	gentr->genenv.sbin = NULL;
-	sieve_binary_unref(sbin);
-
-	if ( topmost && !result ) {
-		sieve_binary_unref(sbin);
-		*sbin = NULL;
+	gentr->genenv.sblock = NULL;
+	sieve_binary_unref(&sbin);
+
+	if ( !result ) {
+		if ( topmost ) {
+			sieve_binary_unref(&sbin);
+			if ( sblock_r != NULL )
+				*sblock_r = NULL;
+		}
+		sbin = NULL;
+	} else {
+		if ( sblock_r != NULL )
+			*sblock_r = sblock;
 	}
 	
-	return result;
+	return sbin;
 }
 
 
diff --git a/src/lib-sieve/sieve-generator.h b/src/lib-sieve/sieve-generator.h
index c353bea87..0fb8a1177 100644
--- a/src/lib-sieve/sieve-generator.h
+++ b/src/lib-sieve/sieve-generator.h
@@ -18,7 +18,9 @@ struct sieve_codegen_env {
 	struct sieve_instance *svinst;
 	struct sieve_script *script;
 	struct sieve_ast *ast;
+
 	struct sieve_binary *sbin;
+	struct sieve_binary_block *sblock;
 };
 
 struct sieve_generator *sieve_generator_create
@@ -36,6 +38,8 @@ struct sieve_script *sieve_generator_script
 	(struct sieve_generator *gentr);
 struct sieve_binary *sieve_generator_get_binary
 	(struct sieve_generator *gentr);
+struct sieve_binary_block *sieve_generator_get_block
+	(struct sieve_generator *gentr);
 
 /* 
  * Error handling 
@@ -67,14 +71,14 @@ const void *sieve_generator_extension_get_context
 
 struct sieve_jumplist {
 	pool_t pool;
-	struct sieve_binary *binary;
+	struct sieve_binary_block *block;
 	ARRAY_DEFINE(jumps, sieve_size_t);
 };
 
 struct sieve_jumplist *sieve_jumplist_create
-	(pool_t pool, struct sieve_binary *sbin);
+	(pool_t pool, struct sieve_binary_block *sblock);
 void sieve_jumplist_init_temp
-	(struct sieve_jumplist *jlist, struct sieve_binary *sbin);
+	(struct sieve_jumplist *jlist, struct sieve_binary_block *sblock);
 void sieve_jumplist_reset
 	(struct sieve_jumplist *jlist);
 void sieve_jumplist_add
@@ -100,8 +104,8 @@ bool sieve_generate_block
 bool sieve_generate_test
 	(const struct sieve_codegen_env *cgenv, struct sieve_ast_node *tst_node, 
 		struct sieve_jumplist *jlist, bool jump_true);
-bool sieve_generator_run
-	(struct sieve_generator *gentr, struct sieve_binary **sbin);
+struct sieve_binary *sieve_generator_run
+	(struct sieve_generator *gentr, struct sieve_binary_block **sblock_r);
 
 #endif /* __SIEVE_GENERATOR_H */
 
diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index e1bf25471..0c4e5ee76 100644
--- a/src/lib-sieve/sieve-interpreter.c
+++ b/src/lib-sieve/sieve-interpreter.c
@@ -58,16 +58,20 @@ struct sieve_interpreter {
 	
 	/* Runtime environment */
 	struct sieve_runtime_env runenv; 
+
+	struct sieve_binary_debug_reader *dreader;
 };
 
-struct sieve_interpreter *sieve_interpreter_create
-(struct sieve_binary *sbin, struct sieve_error_handler *ehandler) 
+static struct sieve_interpreter *_sieve_interpreter_create
+(struct sieve_binary *sbin, struct sieve_binary_block *sblock, 
+	struct sieve_error_handler *ehandler) 
 {
 	unsigned int i, ext_count;
 	struct sieve_interpreter *interp;
 	pool_t pool;
 	struct sieve_instance *svinst;
 	const struct sieve_extension *const *ext_preloaded;
+	unsigned int debug_block_id;
 	bool success = TRUE;
 	
 	pool = pool_alloconly_create("sieve_interpreter", 4096);	
@@ -79,6 +83,7 @@ struct sieve_interpreter *sieve_interpreter_create
 
 	interp->runenv.interp = interp;	
 	interp->runenv.sbin = sbin;
+	interp->runenv.sblock = sblock;
 	sieve_binary_ref(sbin);
 
 	svinst = sieve_binary_svinst(sbin);
@@ -100,13 +105,29 @@ struct sieve_interpreter *sieve_interpreter_create
 				(ext_preloaded[i], &interp->runenv, &interp->pc);		
 	}
 
+	/* Load debug block */
+	if ( sieve_binary_read_unsigned(sblock, &interp->pc, &debug_block_id) ) {
+		struct sieve_binary_block *debug_block =
+			sieve_binary_block_get(sbin, debug_block_id);
+
+		if ( debug_block == NULL ) {
+			sieve_runtime_trace_error(&interp->runenv, "invalid id for debug block");
+			success = FALSE;
+		} else {
+			/* Initialize debug reader */
+			interp->dreader = sieve_binary_debug_reader_init(debug_block);
+		}
+	}
+
 	/* Load other extensions listed in code */
-	if ( sieve_binary_read_unsigned(sbin, &interp->pc, &ext_count) ) {
+	if ( success && 
+		sieve_binary_read_unsigned(sblock, &interp->pc, &ext_count) ) {
+
 		for ( i = 0; i < ext_count; i++ ) {
 			unsigned int code = 0;
 			const struct sieve_extension *ext;
 			
-			if ( !sieve_binary_read_extension(sbin, &interp->pc, &code, &ext) ) {
+			if ( !sieve_binary_read_extension(sblock, &interp->pc, &code, &ext) ) {
 				success = FALSE;
 				break;
 			}
@@ -129,6 +150,23 @@ struct sieve_interpreter *sieve_interpreter_create
 	return interp;
 }
 
+struct sieve_interpreter *sieve_interpreter_create
+(struct sieve_binary *sbin, struct sieve_error_handler *ehandler) 
+{
+	struct sieve_binary_block *sblock =
+		sieve_binary_block_get(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM);
+
+ 	return _sieve_interpreter_create(sbin, sblock, ehandler);
+}
+
+struct sieve_interpreter *sieve_interpreter_create_for_block
+(struct sieve_binary_block *sblock, struct sieve_error_handler *ehandler) 
+{
+	struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
+
+ 	return _sieve_interpreter_create(sbin, sblock, ehandler);
+}
+
 void sieve_interpreter_free(struct sieve_interpreter **interp) 
 {
 	const struct sieve_interpreter_extension_reg *eregs;
@@ -141,6 +179,7 @@ void sieve_interpreter_free(struct sieve_interpreter **interp)
 			eregs[i].intext->free(eregs[i].ext, *interp, eregs[i].context);
 	}
 
+	sieve_binary_debug_reader_deinit(&(*interp)->dreader);
 	sieve_binary_unref(&(*interp)->runenv.sbin);
 	sieve_error_handler_unref(&(*interp)->ehandler);
 		 
@@ -349,13 +388,13 @@ int sieve_interpreter_program_jump
 	sieve_size_t pc = interp->pc;
 	int offset;
 	
-	if ( !sieve_binary_read_offset(renv->sbin, &(interp->pc), &offset) )
+	if ( !sieve_binary_read_offset(renv->sblock, &(interp->pc), &offset) )
 	{
 		sieve_runtime_trace_error(renv, "invalid jump offset"); 
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
 
-	if ( pc + offset <= sieve_binary_get_code_size(renv->sbin) && 
+	if ( pc + offset <= sieve_binary_block_get_size(renv->sblock) && 
 		pc + offset > 0 ) 
 	{	
 		if ( jump )
@@ -394,9 +433,9 @@ int sieve_interpreter_handle_optional_operands
 {
 	signed int opt_code = -1;
 	
-	if ( sieve_operand_optional_present(renv->sbin, address) ) {
+	if ( sieve_operand_optional_present(renv->sblock, address) ) {
 		while ( opt_code != 0 ) {
-			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) {
+			if ( !sieve_operand_optional_read(renv->sblock, address, &opt_code) ) {
 				sieve_runtime_trace_error(renv, "invalid optional operand");
 				return SIEVE_EXEC_BIN_CORRUPT;
 			}
@@ -431,7 +470,7 @@ static int sieve_interpreter_execute_operation
 {
 	struct sieve_operation *oprtn = &(interp->runenv.oprtn);
 
-	if ( sieve_operation_read(interp->runenv.sbin, &(interp->pc), oprtn) ) {
+	if ( sieve_operation_read(interp->runenv.sblock, &(interp->pc), oprtn) ) {
 		const struct sieve_operation_def *op = oprtn->def;
 
 		int result = SIEVE_EXEC_OK;
@@ -463,7 +502,7 @@ int sieve_interpreter_continue
 		*interrupted = FALSE;
 	
 	while ( ret == SIEVE_EXEC_OK && !interp->interrupted && 
-		interp->pc < sieve_binary_get_code_size(interp->runenv.sbin) ) {
+		interp->pc < sieve_binary_block_get_size(interp->runenv.sblock) ) {
 		
 		ret = sieve_interpreter_execute_operation(interp);
 
diff --git a/src/lib-sieve/sieve-interpreter.h b/src/lib-sieve/sieve-interpreter.h
index 6c0ce14ed..41336be9a 100644
--- a/src/lib-sieve/sieve-interpreter.h
+++ b/src/lib-sieve/sieve-interpreter.h
@@ -27,6 +27,7 @@ struct sieve_runtime_env {
 	struct sieve_instance *svinst;
 
 	struct sieve_binary *sbin;
+	struct sieve_binary_block *sblock;
 	struct sieve_operation oprtn; 
 
 	struct sieve_script *script;
@@ -47,6 +48,8 @@ struct sieve_runtime_env {
 
 struct sieve_interpreter *sieve_interpreter_create
 	(struct sieve_binary *sbin, struct sieve_error_handler *ehandler);
+struct sieve_interpreter *sieve_interpreter_create_for_block
+	(struct sieve_binary_block *sblock, struct sieve_error_handler *ehandler);
 void sieve_interpreter_free(struct sieve_interpreter **interp);
 
 /*
diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c
index 2ff3eb73a..96d039278 100644
--- a/src/lib-sieve/sieve-match-types.c
+++ b/src/lib-sieve/sieve-match-types.c
@@ -431,7 +431,7 @@ static bool tag_match_type_generate
 	struct sieve_match_type_context *mtctx =
 		(struct sieve_match_type_context *) arg->argument->data;
 	
-	(void) sieve_opr_match_type_emit(cgenv->sbin, mtctx->match_type);
+	(void) sieve_opr_match_type_emit(cgenv->sblock, mtctx->match_type);
 			
 	return TRUE;
 }
diff --git a/src/lib-sieve/sieve-match-types.h b/src/lib-sieve/sieve-match-types.h
index df3c85dfa..b96fa7aaa 100644
--- a/src/lib-sieve/sieve-match-types.h
+++ b/src/lib-sieve/sieve-match-types.h
@@ -201,9 +201,9 @@ static inline bool sieve_operand_is_match_type
 }
 
 static inline void sieve_opr_match_type_emit
-(struct sieve_binary *sbin, const struct sieve_match_type *mcht)
+(struct sieve_binary_block *sblock, const struct sieve_match_type *mcht)
 { 
-	sieve_opr_object_emit(sbin, mcht->object.ext, mcht->object.def);
+	sieve_opr_object_emit(sblock, mcht->object.ext, mcht->object.def);
 }
 
 static inline bool sieve_opr_match_type_read
diff --git a/src/lib-sieve/sieve-match.c b/src/lib-sieve/sieve-match.c
index ad1a17329..88aa4e517 100644
--- a/src/lib-sieve/sieve-match.c
+++ b/src/lib-sieve/sieve-match.c
@@ -140,9 +140,9 @@ bool sieve_match_dump_optional_operands
 (const struct sieve_dumptime_env *denv, sieve_size_t *address, int *opt_code)
 {
 	if ( *opt_code != SIEVE_MATCH_OPT_END || 
-		sieve_operand_optional_present(denv->sbin, address) ) {
+		sieve_operand_optional_present(denv->sblock, address) ) {
 		do {
-			if ( !sieve_operand_optional_read(denv->sbin, address, opt_code) ) 
+			if ( !sieve_operand_optional_read(denv->sblock, address, opt_code) ) 
 				return FALSE;
 
 			switch ( *opt_code ) {
@@ -171,9 +171,9 @@ int sieve_match_read_optional_operands
 {	 
 	/* Handle any optional arguments */
 	if ( *opt_code != SIEVE_MATCH_OPT_END || 
-		sieve_operand_optional_present(renv->sbin, address) ) {
+		sieve_operand_optional_present(renv->sblock, address) ) {
 		do {
-			if ( !sieve_operand_optional_read(renv->sbin, address, opt_code) ) {
+			if ( !sieve_operand_optional_read(renv->sblock, address, opt_code) ) {
 				sieve_runtime_trace_error(renv, "invalid optional operand");
 				return SIEVE_EXEC_BIN_CORRUPT;
 			}
diff --git a/src/lib-sieve/sieve-objects.c b/src/lib-sieve/sieve-objects.c
index 108ae2f03..614dd1b5e 100644
--- a/src/lib-sieve/sieve-objects.c
+++ b/src/lib-sieve/sieve-objects.c
@@ -15,21 +15,21 @@
  */
 
 void sieve_opr_object_emit
-(struct sieve_binary *sbin, const struct sieve_extension *ext,
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
 	const struct sieve_object_def *obj_def)
 {
 	struct sieve_extension_objects *objs = 
 		(struct sieve_extension_objects *) obj_def->operand->interface;
 		 
-	(void) sieve_operand_emit(sbin, ext, obj_def->operand);
+	(void) sieve_operand_emit(sblock, ext, obj_def->operand);
 	
 	if ( objs->count > 1 ) {	
-		(void) sieve_binary_emit_byte(sbin, obj_def->code);
+		(void) sieve_binary_emit_byte(sblock, obj_def->code);
 	} 
 }
 
 bool sieve_opr_object_read_data
-(struct sieve_binary *sbin, const struct sieve_operand *operand,
+(struct sieve_binary_block *sblock, const struct sieve_operand *operand,
 	const struct sieve_operand_class *opclass, sieve_size_t *address,
 	struct sieve_object *obj)
 {
@@ -44,7 +44,7 @@ bool sieve_opr_object_read_data
 		return FALSE;
 			
 	if ( objs->count > 1 ) {
-		if ( !sieve_binary_read_byte(sbin, address, &obj_code) ) 
+		if ( !sieve_binary_read_byte(sblock, address, &obj_code) ) 
 			return FALSE;
 
 		if ( obj_code < objs->count ) {
@@ -69,12 +69,12 @@ bool sieve_opr_object_read
 {
 	struct sieve_operand operand; 
 
-	if ( !sieve_operand_read(renv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(renv->sblock, address, &operand) ) {
 		return FALSE;
 	}
 	
 	return sieve_opr_object_read_data
-		(renv->sbin, &operand, opclass, address, obj);
+		(renv->sblock, &operand, opclass, address, obj);
 }
 
 bool sieve_opr_object_dump
@@ -91,12 +91,12 @@ bool sieve_opr_object_dump
 
 	sieve_code_mark(denv);
 	
-	if ( !sieve_operand_read(denv->sbin, address, &operand) ) {
+	if ( !sieve_operand_read(denv->sblock, address, &operand) ) {
 		return FALSE;
 	}
 
 	if ( !sieve_opr_object_read_data
-		(denv->sbin, &operand, opclass, address, obj) )
+		(denv->sblock, &operand, opclass, address, obj) )
 		return FALSE;
 			
 	if ( operand.def->class == NULL )
diff --git a/src/lib-sieve/sieve-objects.h b/src/lib-sieve/sieve-objects.h
index 2d69164fe..4ffb12196 100644
--- a/src/lib-sieve/sieve-objects.h
+++ b/src/lib-sieve/sieve-objects.h
@@ -44,11 +44,11 @@ struct sieve_object {
  */
  
 void sieve_opr_object_emit
-	(struct sieve_binary *sbin, const struct sieve_extension *ext,
+	(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
 		const struct sieve_object_def *obj_def);
 
 bool sieve_opr_object_read_data
-	(struct sieve_binary *sbin, const struct sieve_operand *operand,
+	(struct sieve_binary_block *sblock, const struct sieve_operand *operand,
 		const struct sieve_operand_class *opclass, sieve_size_t *address,
 		struct sieve_object *obj);
 
diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c
index 123b46556..55e393fd3 100644
--- a/src/lib-sieve/sieve.c
+++ b/src/lib-sieve/sieve.c
@@ -156,7 +156,7 @@ static struct sieve_binary *sieve_generate
 	struct sieve_generator *generator = sieve_generator_create(ast, ehandler);
 	struct sieve_binary *sbin = NULL;
 		
-	(void) sieve_generator_run(generator, &sbin);
+	sbin = sieve_generator_run(generator, NULL);
 	
 	sieve_generator_free(&generator);
 	
@@ -343,11 +343,11 @@ void sieve_close(struct sieve_binary **sbin)
  * Debugging
  */
 
-void sieve_dump(struct sieve_binary *sbin, struct ostream *stream) 
+void sieve_dump(struct sieve_binary *sbin, struct ostream *stream, bool verbose) 
 {
 	struct sieve_binary_dumper *dumpr = sieve_binary_dumper_create(sbin);			
 
-	sieve_binary_dumper_run(dumpr, stream);	
+	sieve_binary_dumper_run(dumpr, stream, verbose);	
 	
 	sieve_binary_dumper_free(&dumpr);
 }
diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h
index ebc340b8c..346328352 100644
--- a/src/lib-sieve/sieve.h
+++ b/src/lib-sieve/sieve.h
@@ -105,7 +105,7 @@ void sieve_close(struct sieve_binary **sbin);
  *
  *   Dumps the byte code in human-readable form to the specified ostream.
  */
-void sieve_dump(struct sieve_binary *sbin, struct ostream *stream);
+void sieve_dump(struct sieve_binary *sbin, struct ostream *stream, bool verbose);
 
 /* sieve_test:
  *
diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c
index 76aabfda2..44e52cb49 100644
--- a/src/lib-sieve/tst-address.c
+++ b/src/lib-sieve/tst-address.c
@@ -191,7 +191,7 @@ static bool tst_address_validate
 static bool tst_address_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst) 
 {
-	sieve_operation_emit(cgenv->sbin, NULL, &tst_address_operation);
+	sieve_operation_emit(cgenv->sblock, NULL, &tst_address_operation);
 	
 	/* Generate arguments */  	
 	return sieve_generate_arguments(cgenv, tst, NULL);
diff --git a/src/lib-sieve/tst-allof.c b/src/lib-sieve/tst-allof.c
index 6d610b8e4..5e3eb2fea 100644
--- a/src/lib-sieve/tst-allof.c
+++ b/src/lib-sieve/tst-allof.c
@@ -36,14 +36,14 @@ static bool tst_allof_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx,
 	struct sieve_jumplist *jumps, bool jump_true)
 {
-	struct sieve_binary *sbin = cgenv->sbin;
+	struct sieve_binary_block *sblock = cgenv->sblock;
 	struct sieve_ast_node *test;
 	struct sieve_jumplist false_jumps;
 
 	if ( sieve_ast_test_count(ctx->ast_node) > 1 ) {	
 		if ( jump_true ) {
 			/* Prepare jumplist */
-			sieve_jumplist_init_temp(&false_jumps, sbin);
+			sieve_jumplist_init_temp(&false_jumps, sblock);
 		}
 	
 		test = sieve_ast_test_first(ctx->ast_node);
@@ -67,8 +67,8 @@ static bool tst_allof_generate
 	
 		if ( jump_true ) {
 			/* All tests succeeded, jump to case TRUE */
-			sieve_operation_emit(cgenv->sbin, NULL, &sieve_jmp_operation);
-			sieve_jumplist_add(jumps, sieve_binary_emit_offset(sbin, 0));
+			sieve_operation_emit(cgenv->sblock, NULL, &sieve_jmp_operation);
+			sieve_jumplist_add(jumps, sieve_binary_emit_offset(sblock, 0));
 			
 			/* All false exits jump here */
 			sieve_jumplist_resolve(&false_jumps);
diff --git a/src/lib-sieve/tst-anyof.c b/src/lib-sieve/tst-anyof.c
index 9fbe4775c..55fcd5ba5 100644
--- a/src/lib-sieve/tst-anyof.c
+++ b/src/lib-sieve/tst-anyof.c
@@ -36,14 +36,14 @@ static bool tst_anyof_generate
 	(const struct sieve_codegen_env *cgenv, struct sieve_command *ctx,
 		struct sieve_jumplist *jumps, bool jump_true)
 {
-	struct sieve_binary *sbin = cgenv->sbin;
+	struct sieve_binary_block *sblock = cgenv->sblock;
 	struct sieve_ast_node *test;
 	struct sieve_jumplist true_jumps;
 
 	if ( sieve_ast_test_count(ctx->ast_node) > 1 ) {	
 		if ( !jump_true ) {
 			/* Prepare jumplist */
-			sieve_jumplist_init_temp(&true_jumps, sbin);
+			sieve_jumplist_init_temp(&true_jumps, sblock);
 		}
 	
 		test = sieve_ast_test_first(ctx->ast_node);
@@ -67,8 +67,8 @@ static bool tst_anyof_generate
 	
 		if ( !jump_true ) {
 			/* All tests failed, jump to case FALSE */
-			sieve_operation_emit(sbin, NULL, &sieve_jmp_operation);
-			sieve_jumplist_add(jumps, sieve_binary_emit_offset(sbin, 0));
+			sieve_operation_emit(sblock, NULL, &sieve_jmp_operation);
+			sieve_jumplist_add(jumps, sieve_binary_emit_offset(sblock, 0));
 			
 			/* All true exits jump here */
 			sieve_jumplist_resolve(&true_jumps);
diff --git a/src/lib-sieve/tst-exists.c b/src/lib-sieve/tst-exists.c
index fa7280085..e70b064a1 100644
--- a/src/lib-sieve/tst-exists.c
+++ b/src/lib-sieve/tst-exists.c
@@ -76,7 +76,7 @@ static bool tst_exists_validate
 static bool tst_exists_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst) 
 {
-	sieve_operation_emit(cgenv->sbin, NULL, &tst_exists_operation);
+	sieve_operation_emit(cgenv->sblock, NULL, &tst_exists_operation);
 
  	/* Generate arguments */
     return sieve_generate_arguments(cgenv, tst, NULL);
diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c
index c2ad3dc18..872b3e5da 100644
--- a/src/lib-sieve/tst-header.c
+++ b/src/lib-sieve/tst-header.c
@@ -117,7 +117,7 @@ static bool tst_header_validate
 static bool tst_header_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst) 
 {
-	sieve_operation_emit(cgenv->sbin, NULL, &tst_header_operation);
+	sieve_operation_emit(cgenv->sblock, NULL, &tst_header_operation);
 
  	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, tst, NULL);
diff --git a/src/lib-sieve/tst-size.c b/src/lib-sieve/tst-size.c
index 5accafb36..437a224f1 100644
--- a/src/lib-sieve/tst-size.c
+++ b/src/lib-sieve/tst-size.c
@@ -200,9 +200,9 @@ bool tst_size_generate
 		(struct tst_size_context_data *) tst->data;
 
 	if ( ctx_data->type == SIZE_OVER ) 
-		sieve_operation_emit(cgenv->sbin, NULL, &tst_size_over_operation);
+		sieve_operation_emit(cgenv->sblock, NULL, &tst_size_over_operation);
 	else
-		sieve_operation_emit(cgenv->sbin, NULL, &tst_size_under_operation);
+		sieve_operation_emit(cgenv->sblock, NULL, &tst_size_under_operation);
 
  	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, tst, NULL) )
diff --git a/src/lib-sieve/tst-truefalse.c b/src/lib-sieve/tst-truefalse.c
index 5df1b6a25..d64bd7b08 100644
--- a/src/lib-sieve/tst-truefalse.c
+++ b/src/lib-sieve/tst-truefalse.c
@@ -43,8 +43,8 @@ static bool tst_false_generate
 	struct sieve_jumplist *jumps, bool jump_true)
 {
 	if ( !jump_true ) {
-		sieve_operation_emit(cgenv->sbin, NULL, &sieve_jmp_operation);
-		sieve_jumplist_add(jumps, sieve_binary_emit_offset(cgenv->sbin, 0));
+		sieve_operation_emit(cgenv->sblock, NULL, &sieve_jmp_operation);
+		sieve_jumplist_add(jumps, sieve_binary_emit_offset(cgenv->sblock, 0));
 	}
 	
 	return TRUE;
@@ -56,8 +56,8 @@ static bool tst_true_generate
 	struct sieve_jumplist *jumps, bool jump_true)
 {
 	if ( jump_true ) {
-		sieve_operation_emit(cgenv->sbin, NULL, &sieve_jmp_operation);
-		sieve_jumplist_add(jumps, sieve_binary_emit_offset(cgenv->sbin, 0));
+		sieve_operation_emit(cgenv->sblock, NULL, &sieve_jmp_operation);
+		sieve_jumplist_add(jumps, sieve_binary_emit_offset(cgenv->sblock, 0));
 	}
 	
 	return TRUE;
diff --git a/src/sieve-tools/debug/cmd-debug-print.c b/src/sieve-tools/debug/cmd-debug-print.c
index 32c5e22e6..c6e3cfda5 100644
--- a/src/sieve-tools/debug/cmd-debug-print.c
+++ b/src/sieve-tools/debug/cmd-debug-print.c
@@ -76,7 +76,7 @@ static bool cmd_debug_print_validate
 static bool cmd_debug_print_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	(void)sieve_operation_emit(cgenv->sbin, cmd->ext, &debug_print_operation);
+	(void)sieve_operation_emit(cgenv->sblock, cmd->ext, &debug_print_operation);
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
diff --git a/src/testsuite/cmd-test-binary.c b/src/testsuite/cmd-test-binary.c
index 46bee4b32..c7361a505 100644
--- a/src/testsuite/cmd-test-binary.c
+++ b/src/testsuite/cmd-test-binary.c
@@ -188,7 +188,7 @@ static bool cmd_test_binary_generate
 	i_assert( ctx_data->binary_op < BINARY_OP_LAST );
 	
 	/* Emit operation */
-	sieve_operation_emit(cgenv->sbin, cmd->ext, 
+	sieve_operation_emit(cgenv->sblock, cmd->ext, 
 		test_binary_operations[ctx_data->binary_op]);
 	  	
  	/* Generate arguments */
@@ -241,7 +241,7 @@ static int cmd_test_binary_operation_execute
 	 */
 		
 	sieve_runtime_trace
-		(renv, "%s %s:", sieve_operation_mnemonic(op), str_c(binary_name));
+		(renv, "%s %s", sieve_operation_mnemonic(op), str_c(binary_name));
 
 	if ( sieve_operation_is(op, test_binary_load_operation) ) {
 		struct sieve_binary *sbin = testsuite_binary_load(str_c(binary_name));
diff --git a/src/testsuite/cmd-test-config.c b/src/testsuite/cmd-test-config.c
index 9ba9f2fa2..194946936 100644
--- a/src/testsuite/cmd-test-config.c
+++ b/src/testsuite/cmd-test-config.c
@@ -246,7 +246,7 @@ static bool tag_action_generate
 	i_assert(ctx_data->action < CONFIG_ACTION_LAST);
 
 	sieve_operation_emit
-		(cgenv->sbin, cmd->ext, test_config_operations[ctx_data->action]);
+		(cgenv->sblock, cmd->ext, test_config_operations[ctx_data->action]);
 
 	while ( param != NULL ) {
 		if ( !sieve_generate_argument(cgenv, param, cmd) )
diff --git a/src/testsuite/cmd-test-fail.c b/src/testsuite/cmd-test-fail.c
index 5b634de83..ac43cdda3 100644
--- a/src/testsuite/cmd-test-fail.c
+++ b/src/testsuite/cmd-test-fail.c
@@ -85,14 +85,14 @@ static bool cmd_test_fail_generate
 	struct testsuite_generator_context *genctx = 
 		_get_generator_context(cgenv->gentr);
 	
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &test_fail_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &test_fail_operation);
 
 	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
 		return FALSE;
 		
 	sieve_jumplist_add(genctx->exit_jumps, 
-		sieve_binary_emit_offset(cgenv->sbin, 0));			
+		sieve_binary_emit_offset(cgenv->sblock, 0));			
 	
 	return TRUE;
 }
@@ -115,7 +115,7 @@ static bool cmd_test_fail_operation_dump
 
 	sieve_code_mark(denv);
 	pc = *address;
-	if ( sieve_binary_read_offset(denv->sbin, address, &offset) )
+	if ( sieve_binary_read_offset(denv->sblock, address, &offset) )
 		sieve_code_dumpf(denv, "offset: %d [%08x]", offset, pc + offset);
 	else
 		return FALSE;
diff --git a/src/testsuite/cmd-test-mailbox.c b/src/testsuite/cmd-test-mailbox.c
index 8605cc408..e61cc44d6 100644
--- a/src/testsuite/cmd-test-mailbox.c
+++ b/src/testsuite/cmd-test-mailbox.c
@@ -189,7 +189,7 @@ static bool cmd_test_mailbox_generate
 	i_assert( ctx_data->mailbox_op < MAILBOX_OP_LAST );
 	
 	/* Emit operation */
-	sieve_operation_emit(cgenv->sbin, cmd->ext,
+	sieve_operation_emit(cgenv->sblock, cmd->ext,
 		test_mailbox_operations[ctx_data->mailbox_op]);
 	  	
  	/* Generate arguments */
diff --git a/src/testsuite/cmd-test-message.c b/src/testsuite/cmd-test-message.c
index c1dbbcc86..8df89a0ba 100644
--- a/src/testsuite/cmd-test-message.c
+++ b/src/testsuite/cmd-test-message.c
@@ -240,11 +240,11 @@ static bool cmd_test_message_generate
 	i_assert( ctx_data->msg_source < MSG_SOURCE_LAST );
 	
 	/* Emit operation */
-	sieve_operation_emit(cgenv->sbin, cmd->ext,
+	sieve_operation_emit(cgenv->sblock, cmd->ext,
 		test_message_operations[ctx_data->msg_source]);
 
 	/* Emit is_test flag */
-	sieve_binary_emit_byte(cgenv->sbin, ( cmd->ast_node->type == SAT_TEST ));
+	sieve_binary_emit_byte(cgenv->sblock, ( cmd->ast_node->type == SAT_TEST ));
 	  	
  	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
@@ -262,7 +262,7 @@ static bool cmd_test_message_smtp_operation_dump
 {
 	unsigned int is_test;
 
-	if ( !sieve_binary_read_byte(denv->sbin, address, &is_test) )
+	if ( !sieve_binary_read_byte(denv->sblock, address, &is_test) )
 		return FALSE;
 
 	sieve_code_dumpf(denv, "TEST_MESSAGE_SMTP (%s):", 
@@ -278,7 +278,7 @@ static bool cmd_test_message_mailbox_operation_dump
 {
 	unsigned int is_test;
 
-	if ( !sieve_binary_read_byte(denv->sbin, address, &is_test) )
+	if ( !sieve_binary_read_byte(denv->sblock, address, &is_test) )
 		return FALSE;
 
 	sieve_code_dumpf(denv, "TEST_MESSAGE_MAILBOX (%s):",
@@ -308,7 +308,7 @@ static int cmd_test_message_smtp_operation_execute
 
 	/* Is test */
 
-	if ( !sieve_binary_read_byte(renv->sbin, address, &is_test) ) {
+	if ( !sieve_binary_read_byte(renv->sblock, address, &is_test) ) {
 		sieve_runtime_trace_error(renv, "invalid is_test flag");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
@@ -353,7 +353,7 @@ static int cmd_test_message_mailbox_operation_execute
 	 */
 
 	/* Is test */
-	if ( !sieve_binary_read_byte(renv->sbin, address, &is_test) ) {
+	if ( !sieve_binary_read_byte(renv->sblock, address, &is_test) ) {
 		sieve_runtime_trace_error(renv, "invalid is_test flag");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
diff --git a/src/testsuite/cmd-test-result-print.c b/src/testsuite/cmd-test-result-print.c
index f1525c40a..4af964976 100644
--- a/src/testsuite/cmd-test-result-print.c
+++ b/src/testsuite/cmd-test-result-print.c
@@ -56,7 +56,7 @@ const struct sieve_operation_def test_result_print_operation = {
 static bool cmd_test_result_print_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &test_result_print_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &test_result_print_operation);
 
 	return TRUE;
 }
diff --git a/src/testsuite/cmd-test-result-reset.c b/src/testsuite/cmd-test-result-reset.c
index faea128e9..285afee2a 100644
--- a/src/testsuite/cmd-test-result-reset.c
+++ b/src/testsuite/cmd-test-result-reset.c
@@ -57,7 +57,7 @@ const struct sieve_operation_def test_result_reset_operation = {
 static bool cmd_test_result_reset_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
 {
-	sieve_operation_emit(cgenv->sbin, tst->ext, &test_result_reset_operation);
+	sieve_operation_emit(cgenv->sblock, tst->ext, &test_result_reset_operation);
 
 	return TRUE;
 }
diff --git a/src/testsuite/cmd-test-set.c b/src/testsuite/cmd-test-set.c
index 35df0f9f3..590934c33 100644
--- a/src/testsuite/cmd-test-set.c
+++ b/src/testsuite/cmd-test-set.c
@@ -97,7 +97,7 @@ static bool cmd_test_set_validate
 static bool cmd_test_set_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 {
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &test_set_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &test_set_operation);
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, cmd, NULL);
@@ -130,7 +130,7 @@ static int cmd_test_set_operation_execute
 	int member_id;
 
 	if ( !testsuite_object_read_member
-		(renv->sbin, address, &tobj, &member_id) ) {
+		(renv->sblock, address, &tobj, &member_id) ) {
 		sieve_runtime_trace_error(renv, "invalid testsuite object member");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
diff --git a/src/testsuite/cmd-test.c b/src/testsuite/cmd-test.c
index e125878e1..b81382571 100644
--- a/src/testsuite/cmd-test.c
+++ b/src/testsuite/cmd-test.c
@@ -108,7 +108,7 @@ static bool cmd_test_generate
 	struct testsuite_generator_context *genctx = 
 		_get_generator_context(cgenv->gentr);
 	
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &test_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &test_operation);
 
 	/* Generate arguments */
 	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
@@ -121,7 +121,7 @@ static bool cmd_test_generate
 	if ( !sieve_generate_block(cgenv, cmd->ast_node) )
 		return FALSE;
 	
-	sieve_operation_emit(cgenv->sbin, cmd->ext, &test_finish_operation);
+	sieve_operation_emit(cgenv->sblock, cmd->ext, &test_finish_operation);
 	
 	/* Resolve exit jumps to this point */
 	sieve_jumplist_resolve(genctx->exit_jumps); 
diff --git a/src/testsuite/testsuite-common.c b/src/testsuite/testsuite-common.c
index 1df391fd5..c23c80a2c 100644
--- a/src/testsuite/testsuite-common.c
+++ b/src/testsuite/testsuite-common.c
@@ -88,12 +88,12 @@ bool testsuite_generator_context_initialize
 (struct sieve_generator *gentr, const struct sieve_extension *this_ext)
 {
 	pool_t pool = sieve_generator_pool(gentr);
-	struct sieve_binary *sbin = sieve_generator_get_binary(gentr);
+	struct sieve_binary_block *sblock = sieve_generator_get_block(gentr);
 	struct testsuite_generator_context *ctx = 
 		p_new(pool, struct testsuite_generator_context, 1);
 	
 	/* Setup exit jumplist */
-	ctx->exit_jumps = sieve_jumplist_create(pool, sbin);
+	ctx->exit_jumps = sieve_jumplist_create(pool, sblock);
 	
 	sieve_generator_extension_set_context(gentr, this_ext, ctx);
 
diff --git a/src/testsuite/testsuite-objects.c b/src/testsuite/testsuite-objects.c
index 93a750a13..9c0c11c1e 100644
--- a/src/testsuite/testsuite-objects.c
+++ b/src/testsuite/testsuite-objects.c
@@ -110,26 +110,27 @@ const struct sieve_operand_def testsuite_object_operand = {
 };
 
 static void testsuite_object_emit
-(struct sieve_binary *sbin,	const struct testsuite_object *tobj, int member_id)
+(struct sieve_binary_block *sblock, const struct testsuite_object *tobj,
+	int member_id)
 { 
-	sieve_opr_object_emit(sbin, tobj->object.ext, tobj->object.def);
+	sieve_opr_object_emit(sblock, tobj->object.ext, tobj->object.def);
 	
 	if ( tobj->def != NULL && tobj->def->get_member_id != NULL ) {
-		(void) sieve_binary_emit_byte(sbin, (unsigned char) member_id);
+		(void) sieve_binary_emit_byte(sblock, (unsigned char) member_id);
 	}
 }
 
 bool testsuite_object_read
-(struct sieve_binary *sbin, sieve_size_t *address, 
+(struct sieve_binary_block *sblock, sieve_size_t *address, 
 	struct testsuite_object *tobj)
 {
 	struct sieve_operand operand;
 
-	if ( !sieve_operand_read(sbin, address, &operand) )
+	if ( !sieve_operand_read(sblock, address, &operand) )
 		return FALSE;
 	
 	if ( !sieve_opr_object_read_data
-		(sbin, &operand, &sieve_testsuite_object_operand_class, address,
+		(sblock, &operand, &sieve_testsuite_object_operand_class, address,
 			&tobj->object) )
 		return FALSE;
 
@@ -139,15 +140,15 @@ bool testsuite_object_read
 }
 
 bool testsuite_object_read_member
-(struct sieve_binary *sbin, sieve_size_t *address, 
+(struct sieve_binary_block *sblock, sieve_size_t *address, 
 	struct testsuite_object *tobj, int *member_id_r)
 {		
-	if ( !testsuite_object_read(sbin, address, tobj) )
+	if ( !testsuite_object_read(sblock, address, tobj) )
 		return FALSE;
 		
 	*member_id_r = -1;
 	if ( tobj->def != NULL && tobj->def->get_member_id != NULL ) {
-		if ( !sieve_binary_read_code(sbin, address, member_id_r) ) 
+		if ( !sieve_binary_read_code(sblock, address, member_id_r) ) 
 			return FALSE;
 	}
 	
@@ -180,7 +181,8 @@ bool testsuite_object_dump
 
 	sieve_code_mark(denv);
 		
-	if ( !testsuite_object_read_member(denv->sbin, address, &object, &member_id) )
+	if ( !testsuite_object_read_member
+		(denv->sblock, address, &object, &member_id) )
 		return FALSE;
 	
 	sieve_code_dumpf(denv, "%s: %s",
@@ -268,7 +270,7 @@ static bool arg_testsuite_object_generate
 	struct testsuite_object_argctx *ctx = 
 		(struct testsuite_object_argctx *) arg->argument->data;
 	
-	testsuite_object_emit(cgenv->sbin, ctx->object, ctx->member);
+	testsuite_object_emit(cgenv->sblock, ctx->object, ctx->member);
 		
 	return TRUE;
 }
diff --git a/src/testsuite/testsuite-objects.h b/src/testsuite/testsuite-objects.h
index a17087038..812376a30 100644
--- a/src/testsuite/testsuite-objects.h
+++ b/src/testsuite/testsuite-objects.h
@@ -64,10 +64,10 @@ bool testsuite_object_argument_activate
  */
 
 bool testsuite_object_read
-  (struct sieve_binary *sbin, sieve_size_t *address, 
+  (struct sieve_binary_block *sblock, sieve_size_t *address, 
 		struct testsuite_object *tobj);
 bool testsuite_object_read_member
-  (struct sieve_binary *sbin, sieve_size_t *address,
+  (struct sieve_binary_block *sblock, sieve_size_t *address,
 		struct testsuite_object *tobj, int *member_id_r);
 
 bool testsuite_object_dump
diff --git a/src/testsuite/testsuite-substitutions.c b/src/testsuite/testsuite-substitutions.c
index 7235b301f..bb6d79c4d 100644
--- a/src/testsuite/testsuite-substitutions.c
+++ b/src/testsuite/testsuite-substitutions.c
@@ -19,7 +19,7 @@
  */
  
 void testsuite_opr_substitution_emit
-	(struct sieve_binary *sbin, const struct testsuite_substitution *tsub,
+	(struct sieve_binary_block *sblock, const struct testsuite_substitution *tsub,
 		const char *param);
 			
 /*
@@ -126,7 +126,7 @@ static bool arg_testsuite_substitution_generate
 	struct _testsuite_substitution_context *tsctx =  
 		(struct _testsuite_substitution_context *) arg->argument->data;
 	
-	testsuite_opr_substitution_emit(cgenv->sbin, tsctx->tsub, tsctx->param);
+	testsuite_opr_substitution_emit(cgenv->sblock, tsctx->tsub, tsctx->param);
 
 	return TRUE;
 }
@@ -156,14 +156,14 @@ const struct sieve_operand_def testsuite_substitution_operand = {
 };
 
 void testsuite_opr_substitution_emit
-(struct sieve_binary *sbin, const struct testsuite_substitution *tsub,
+(struct sieve_binary_block *sblock, const struct testsuite_substitution *tsub,
 	const char *param) 
 {
 	/* Default variable storage */
 	(void) sieve_operand_emit
-		(sbin, testsuite_ext, &testsuite_substitution_operand);
-	(void) sieve_binary_emit_unsigned(sbin, tsub->object.def->code);
-	(void) sieve_binary_emit_cstring(sbin, param);
+		(sblock, testsuite_ext, &testsuite_substitution_operand);
+	(void) sieve_binary_emit_unsigned(sblock, tsub->object.def->code);
+	(void) sieve_binary_emit_cstring(sblock, param);
 }
 
 static bool opr_substitution_dump
@@ -175,14 +175,14 @@ static bool opr_substitution_dump
 	const struct testsuite_substitution_def *tsub;
 	string_t *param; 
 
-	if ( !sieve_binary_read_unsigned(denv->sbin, address, &code) )
+	if ( !sieve_binary_read_unsigned(denv->sblock, address, &code) )
 		return FALSE;
 		
 	tsub = testsuite_substitution_get(code);
 	if ( tsub == NULL )
 		return FALSE;	
 			
-	if ( !sieve_binary_read_string(denv->sbin, address, &param) )
+	if ( !sieve_binary_read_string(denv->sblock, address, &param) )
 		return FALSE;
 	
 	if ( field_name != NULL ) 
@@ -203,7 +203,7 @@ static bool opr_substitution_read_value
 	unsigned int code = 0;
 	string_t *param;
 	
-	if ( !sieve_binary_read_unsigned(renv->sbin, address, &code) )
+	if ( !sieve_binary_read_unsigned(renv->sblock, address, &code) )
 		return FALSE;
 		
 	tsub = testsuite_substitution_get(code);
@@ -214,9 +214,9 @@ static bool opr_substitution_read_value
 	 * actually read the argument.
 	 */	
 	if ( str == NULL ) 
-		return sieve_binary_read_string(renv->sbin, address, NULL);
+		return sieve_binary_read_string(renv->sblock, address, NULL);
 	
-	if ( !sieve_binary_read_string(renv->sbin, address, &param) )
+	if ( !sieve_binary_read_string(renv->sblock, address, &param) )
 		return FALSE;
 				
 	return tsub->get_value(str_c(param), str);
diff --git a/src/testsuite/tst-test-error.c b/src/testsuite/tst-test-error.c
index f5ae3b3c7..cb3b9ae24 100644
--- a/src/testsuite/tst-test-error.c
+++ b/src/testsuite/tst-test-error.c
@@ -163,7 +163,7 @@ static bool tst_test_error_validate
 static bool tst_test_error_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
 {
-	sieve_operation_emit(cgenv->sbin, tst->ext, &test_error_operation);
+	sieve_operation_emit(cgenv->sblock, tst->ext, &test_error_operation);
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, tst, NULL);
diff --git a/src/testsuite/tst-test-multiscript.c b/src/testsuite/tst-test-multiscript.c
index 0daddda3a..7dba89b68 100644
--- a/src/testsuite/tst-test-multiscript.c
+++ b/src/testsuite/tst-test-multiscript.c
@@ -78,7 +78,7 @@ static bool tst_test_multiscript_validate
 static bool tst_test_multiscript_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
 {
-	sieve_operation_emit(cgenv->sbin, tst->ext, &test_multiscript_operation);
+	sieve_operation_emit(cgenv->sblock, tst->ext, &test_multiscript_operation);
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, tst, NULL);
diff --git a/src/testsuite/tst-test-result-execute.c b/src/testsuite/tst-test-result-execute.c
index c854415ca..b7bfe28fe 100644
--- a/src/testsuite/tst-test-result-execute.c
+++ b/src/testsuite/tst-test-result-execute.c
@@ -56,7 +56,7 @@ const struct sieve_operation_def test_result_execute_operation = {
 static bool tst_test_result_execute_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
 {
-	sieve_operation_emit(cgenv->sbin, tst->ext, &test_result_execute_operation);
+	sieve_operation_emit(cgenv->sblock, tst->ext, &test_result_execute_operation);
 
 	return TRUE;
 }
diff --git a/src/testsuite/tst-test-result.c b/src/testsuite/tst-test-result.c
index d09e87df1..1c0e5a21a 100644
--- a/src/testsuite/tst-test-result.c
+++ b/src/testsuite/tst-test-result.c
@@ -168,7 +168,7 @@ static bool tst_test_result_validate
 static bool tst_test_result_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
 {
-	sieve_operation_emit(cgenv->sbin, tst->ext, &test_result_operation);
+	sieve_operation_emit(cgenv->sblock, tst->ext, &test_result_operation);
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, tst, NULL);
diff --git a/src/testsuite/tst-test-script-compile.c b/src/testsuite/tst-test-script-compile.c
index b60464017..ad1705289 100644
--- a/src/testsuite/tst-test-script-compile.c
+++ b/src/testsuite/tst-test-script-compile.c
@@ -78,7 +78,7 @@ static bool tst_test_script_compile_validate
 static bool tst_test_script_compile_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
 {
-	sieve_operation_emit(cgenv->sbin, tst->ext, &test_script_compile_operation);
+	sieve_operation_emit(cgenv->sblock, tst->ext, &test_script_compile_operation);
 
 	/* Generate arguments */
 	return sieve_generate_arguments(cgenv, tst, NULL);
diff --git a/src/testsuite/tst-test-script-run.c b/src/testsuite/tst-test-script-run.c
index d36594568..8c2bf0e2c 100644
--- a/src/testsuite/tst-test-script-run.c
+++ b/src/testsuite/tst-test-script-run.c
@@ -92,7 +92,7 @@ static bool tst_test_script_run_registered
 static bool tst_test_script_run_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
 {
-	sieve_operation_emit(cgenv->sbin, tst->ext, &test_script_run_operation);
+	sieve_operation_emit(cgenv->sblock, tst->ext, &test_script_run_operation);
 
 	return sieve_generate_arguments(cgenv, tst, NULL);
 }
@@ -110,11 +110,11 @@ static bool tst_test_script_run_operation_dump
 	sieve_code_descend(denv);	
 
 	/* Dump optional operands */
-	if ( sieve_operand_optional_present(denv->sbin, address) ) {
+	if ( sieve_operand_optional_present(denv->sblock, address) ) {
 		while ( opt_code != 0 ) {
 			sieve_code_mark(denv);
 			
-			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) 
+			if ( !sieve_operand_optional_read(denv->sblock, address, &opt_code) ) 
 				return FALSE;
 
 			switch ( opt_code ) {
@@ -150,9 +150,9 @@ static int tst_test_script_run_operation_execute
 	 */
 
 	/* Optional operands */	
-	if ( sieve_operand_optional_present(renv->sbin, address) ) {
+	if ( sieve_operand_optional_present(renv->sblock, address) ) {
 		while ( opt_code != 0 ) {
-			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) {
+			if ( !sieve_operand_optional_read(renv->sblock, address, &opt_code) ) {
 				sieve_runtime_trace_error(renv, "invalid optional operand");
 				return SIEVE_EXEC_BIN_CORRUPT;
 			}
-- 
GitLab