diff --git a/.hgignore b/.hgignore
index 33fd8cd09b3f81449f634b819c20bfbc8e6a6f69..ab593f7d6bd763f1d650ad916ea2289b505c4795 100644
--- a/.hgignore
+++ b/.hgignore
@@ -47,4 +47,4 @@ Makefile.in
 **/Makefile
 **/Makefile.in
 
-src/libsieve/sievec
+src/lib-sieve/sievec
diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am
index 723b566c2007808dbbe3831719fd985ac2f40073..243d17ea20201f34d1c76b51bf84773cf3af92c4 100644
--- a/src/lib-sieve/Makefile.am
+++ b/src/lib-sieve/Makefile.am
@@ -31,6 +31,7 @@ exts = \
 sievec_SOURCES = \
 	sieve-lexer.c \
 	sieve-ast.c \
+	sieve-binary.c \
 	sieve-parser.c \
 	sieve-validator.c \
 	sieve-generator.c \
diff --git a/src/lib-sieve/cmd-require.c b/src/lib-sieve/cmd-require.c
index 0091eec3681427d4fb81e9c23a4db236e7b27bbc..0179afc21a51eba72fc1a28049e782cfb9a94282 100644
--- a/src/lib-sieve/cmd-require.c
+++ b/src/lib-sieve/cmd-require.c
@@ -5,6 +5,11 @@
 #include "sieve-extensions.h"
 #include "sieve-validator.h" 
 
+struct cmd_require_context_data {
+	struct sieve_ast_argument *arg;
+	struct sieve_extension *extension;
+};
+
 bool cmd_require_validate(struct sieve_validator *validator, struct sieve_command_context *cmd) 
 {
 	struct sieve_ast_argument *arg;
@@ -28,18 +33,20 @@ bool cmd_require_validate(struct sieve_validator *validator, struct sieve_comman
 	 	return FALSE;
 	}
 	
-	cmd->data = arg;
-
+	cmd->data = (void *) arg;
+	
 	/* Check argument and load specified extension(s) */
 	if ( sieve_ast_argument_type(arg) == SAAT_STRING )
 		/* Single string */
-		sieve_validator_load_extension(validator, cmd, sieve_ast_argument_strc(arg));
+		arg->context = (void *) sieve_validator_load_extension
+			(validator, cmd, sieve_ast_argument_strc(arg));	
 	else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
 		/* String list */
 		struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg);
 		
 		while ( stritem != NULL ) {
-			sieve_validator_load_extension(validator, cmd, sieve_ast_strlist_strc(stritem));
+			stritem->context = (void *) sieve_validator_load_extension
+				(validator, cmd, sieve_ast_strlist_strc(stritem));
 			
 			stritem = sieve_ast_strlist_next(stritem);
 		}
@@ -59,11 +66,24 @@ bool cmd_require_generate
 {
 	struct sieve_ast_argument *arg = (struct sieve_ast_argument *) ctx->data;
 	
-	sieve_generator_emit_core_opcode(generator, SIEVE_OPCODE_LOAD);
-
-	/* Emit  */  	
-	if ( !sieve_generator_emit_stringlist_argument(generator, arg) ) 
-		return FALSE;
+	if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
+		struct sieve_extension *ext = (struct sieve_extension *) arg->context;
+		
+		sieve_generator_register_extension(generator, ext);
+	} else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
+		/* String list */
+		struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg);
+		
+		while ( stritem != NULL ) {
+			struct sieve_extension *ext = (struct sieve_extension *) arg->context;
+		
+			sieve_generator_register_extension(generator, ext);
+			
+			stritem = sieve_ast_strlist_next(stritem);
+		}
+	} else {
+		i_unreached();
+	}
 	
 	return TRUE;
 }
diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index 88bf792e4c5ffc62ecb054f7805b50f55d43458b..fe17a5c8a561521833da450ec823b19ba2e6ffc8 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -3,12 +3,17 @@
 #include "sieve-validator.h"
 
 /* Forward declarations */
+
+static bool ext_envelope_validator_load(struct sieve_validator *validator);
 static bool tst_envelope_registered
 	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg);
 static bool tst_envelope_validate
 	(struct sieve_validator *validator, struct sieve_command_context *tst);
 
-/* Test definitions */
+/* Extension definitions */
+
+const struct sieve_extension envelope_extension = 
+	{ "envelope", ext_envelope_validator_load, NULL, NULL, NULL };
 static const struct sieve_command envelope_test = 
 	{ "envelope", SCT_TEST, tst_envelope_registered, tst_envelope_validate, NULL, NULL };
 
@@ -55,7 +60,7 @@ static bool tst_envelope_validate(struct sieve_validator *validator, struct siev
 }
 
 /* Load extension into validator */
-bool ext_envelope_validator_load(struct sieve_validator *validator)
+static bool ext_envelope_validator_load(struct sieve_validator *validator)
 {
 	/* Register new test */
 	sieve_validator_register_command(validator, &envelope_test);
diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c
index 85a9d042b812a79fa7d8a4a2047efa60b2d5da99..34113465006ffb400286e8a2927379150da3a92f 100644
--- a/src/lib-sieve/ext-fileinto.c
+++ b/src/lib-sieve/ext-fileinto.c
@@ -3,9 +3,12 @@
 #include "sieve-validator.h"
 
 /* Forward declarations */
+static bool ext_fileinto_validator_load(struct sieve_validator *validator);
 static bool cmd_fileinto_validate(struct sieve_validator *validator, struct sieve_command_context *cmd);
 
-/* Command definitions */
+/* Extension definitions */
+const struct sieve_extension fileinto_extension = 
+	{ "fileinto", ext_fileinto_validator_load, NULL, NULL, NULL };
 static const struct sieve_command fileinto_command = 
 	{ "fileinto", SCT_COMMAND, NULL, cmd_fileinto_validate, NULL, NULL };
 
@@ -26,7 +29,7 @@ static bool cmd_fileinto_validate(struct sieve_validator *validator, struct siev
 }
 
 /* Load extension into validator */
-bool ext_fileinto_validator_load(struct sieve_validator *validator)
+static bool ext_fileinto_validator_load(struct sieve_validator *validator)
 {
 	/* Register new command */
 	sieve_validator_register_command(validator, &fileinto_command);
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index 65c92b13840e030755b57887a29b6b853ef4d4ad..3ae44d0a75fd1578558376b92847cf82ac75c43c 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -9,14 +9,17 @@
 
 static bool cmd_reject_validate(struct sieve_validator *validator, struct sieve_command_context *cmd);
 static bool cmd_reject_generate(struct sieve_generator *generator,	struct sieve_command_context *ctx);
-static bool opc_reject_dump(struct sieve_interpreter *interpreter);
+ 
+static bool ext_reject_validator_load(struct sieve_validator *validator);
+static bool ext_reject_generator_load(struct sieve_generator *generator);
+static bool ext_reject_opcode_dump(struct sieve_interpreter *interpreter);
 
 /* Extension definitions */
+struct sieve_extension reject_extension = 
+	{ "reject", ext_reject_validator_load, ext_reject_generator_load, ext_reject_opcode_dump, NULL };
 
 static const struct sieve_command reject_command = 
 	{ "reject", SCT_COMMAND, NULL, cmd_reject_validate, cmd_reject_generate, NULL };
-static const struct sieve_opcode reject_opcode = 
-	{ opc_reject_dump, NULL };
 
 /* 
  * Validation 
@@ -42,7 +45,7 @@ static bool cmd_reject_validate(struct sieve_validator *validator, struct sieve_
 }
 
 /* Load extension into validator */
-bool ext_reject_validator_load(struct sieve_validator *validator)
+static bool ext_reject_validator_load(struct sieve_validator *validator)
 {
 	/* Register new command */
 	sieve_validator_register_command(validator, &reject_command);
@@ -59,7 +62,7 @@ static bool cmd_reject_generate
 {
 	struct sieve_ast_argument *arg = (struct sieve_ast_argument *) ctx->data;
 	
-	sieve_generator_emit_opcode(generator, &reject_opcode);
+	sieve_generator_emit_opcode(generator, &reject_extension);
 
 	/* Emit reason string */  	
 	if ( !sieve_generator_emit_string_argument(generator, arg) ) 
@@ -69,11 +72,8 @@ static bool cmd_reject_generate
 }
 
 /* Load extension into generator */
-bool ext_reject_generator_load(struct sieve_generator *generator)
+static bool ext_reject_generator_load(struct sieve_generator *generator __attr_unused__)
 {
-	/* Register new command */
-	sieve_generator_register_opcode(generator, &reject_opcode);
-
 	return TRUE;
 }
 
@@ -82,7 +82,7 @@ bool ext_reject_generator_load(struct sieve_generator *generator)
  * Code dump
  */
  
-static bool opc_reject_dump(struct sieve_interpreter *interpreter)
+static bool ext_reject_opcode_dump(struct sieve_interpreter *interpreter)
 {
 	printf("REJECT\n");
 	sieve_interpreter_dump_operand(interpreter);
diff --git a/src/lib-sieve/scripts/tests/reject.sieve b/src/lib-sieve/scripts/tests/reject.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..c8d1d311898ecfa81f6ef6f7bcb522fad2e74302
--- /dev/null
+++ b/src/lib-sieve/scripts/tests/reject.sieve
@@ -0,0 +1,7 @@
+require "reject";
+
+if anyof(exists "frop", size :over 45, size :under 10, address "from" "frop@student.utwente.nl") {
+	keep;
+} else {
+	reject "I dont want your email.";
+}
diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h
index 195c29217df3c0cdb14ba4596791ba22e7c6b388..bcbeae6a6bb8975a75bb64649bc864b22ce265b6 100644
--- a/src/lib-sieve/sieve-ast.h
+++ b/src/lib-sieve/sieve-ast.h
@@ -72,6 +72,9 @@ struct sieve_ast_argument {
   } _value;
   
   unsigned int source_line;
+
+	/* Arbitrary data associated with this ast element */
+	void *context;
 };
 
 struct sieve_ast_list {
diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c
new file mode 100644
index 0000000000000000000000000000000000000000..99ae39472ea660303cd1587f3b5ead7715afc86d
--- /dev/null
+++ b/src/lib-sieve/sieve-binary.c
@@ -0,0 +1,91 @@
+#include "lib.h"
+#include "mempool.h"
+#include "buffer.h"
+#include "array.h"
+
+#include "sieve-binary.h"
+
+struct sieve_binary {
+	pool_t pool;
+	array_t ARRAY_DEFINE(extensions, struct sieve_extension *); 
+	buffer_t *code;
+};
+
+struct sieve_binary *sieve_binary_create_new() 
+{
+	pool_t pool;
+	struct sieve_binary *binary;
+	
+	pool = pool_alloconly_create("sieve_binary", 4096);	
+	binary = p_new(pool, struct sieve_binary, 1);
+	binary->pool = pool;
+	
+	binary->code = buffer_create_dynamic(pool, 256);
+	
+	ARRAY_CREATE(&binary->extensions, pool, struct sieve_extension *, 4);
+	
+	return binary;
+}
+
+void sieve_binary_ref(struct sieve_binary *binary) 
+{
+	pool_ref(binary->pool);
+}
+
+void sieve_binary_unref(struct sieve_binary **binary) 
+{
+	if ( binary != NULL && *binary != NULL ) {
+		pool_unref((*binary)->pool);
+		*binary = NULL;
+	}
+}
+
+/* Extension handling */
+
+unsigned int sieve_binary_link_extension(struct sieve_binary *binary, const struct sieve_extension *extension) 
+{
+	array_append(&binary->extensions, &extension, 1);
+	
+	return array_count(&binary->extensions) - 1;
+}
+
+const struct sieve_extension *sieve_binary_get_extension(struct sieve_binary *binary, unsigned int index) 
+{
+	const struct sieve_extension * const *ext = array_idx(&binary->extensions, index);
+	
+	return *ext;
+}
+
+
+/* Emission functions */
+
+inline sieve_size_t sieve_binary_emit_data(struct sieve_binary *binary, void *data, sieve_size_t size) 
+{
+	sieve_size_t address = buffer_get_used_size(binary->code);
+	  
+	buffer_append(binary->code, data, size);
+	
+	return address;
+}
+
+inline sieve_size_t sieve_binary_emit_byte(struct sieve_binary *binary, unsigned char byte) 
+{
+	return sieve_binary_emit_data(binary, &byte, 1);
+}
+
+inline void sieve_binary_update_data
+	(struct sieve_binary *binary, sieve_size_t address, void *data, sieve_size_t size) 
+{
+	buffer_write(binary->code, address, data, size);
+}
+
+inline sieve_size_t sieve_binary_get_code_size(struct sieve_binary *binary)
+{
+	return buffer_get_used_size(binary->code);
+}
+
+inline const char *sieve_binary_get_code(struct sieve_binary *binary, sieve_size_t *code_size)
+{
+	return buffer_get_data(binary->code, code_size);		
+}
+
diff --git a/src/lib-sieve/sieve-binary.h b/src/lib-sieve/sieve-binary.h
new file mode 100644
index 0000000000000000000000000000000000000000..78da1afec9d9f6017941d81334ea8f6077133d30
--- /dev/null
+++ b/src/lib-sieve/sieve-binary.h
@@ -0,0 +1,30 @@
+#ifndef __SIEVE_BINARY_H__
+#define __SIEVE_BINARY_H__
+
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+
+struct sieve_binary;
+
+struct sieve_binary *sieve_binary_create_new();
+void sieve_binary_ref(struct sieve_binary *binary);
+void sieve_binary_unref(struct sieve_binary **binary);
+
+/* Extension handling */
+
+unsigned int sieve_binary_link_extension(struct sieve_binary *binary, const struct sieve_extension *extension);
+const struct sieve_extension *sieve_binary_get_extension(struct sieve_binary *binary, unsigned int index); 
+
+/* Emission functions */
+
+inline sieve_size_t sieve_binary_emit_data(struct sieve_binary *binary, void *data, sieve_size_t size);
+inline sieve_size_t sieve_binary_emit_byte(struct sieve_binary *binary, unsigned char byte);
+inline void sieve_binary_update_data
+	(struct sieve_binary *binary, sieve_size_t address, void *data, sieve_size_t size);
+inline sieve_size_t sieve_binary_get_code_size(struct sieve_binary *binary);
+
+/* Retrieval functions */
+
+inline const char *sieve_binary_get_code(struct sieve_binary *binary, sieve_size_t *code_size);
+
+#endif
diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h
index 02c4734ce8075fbf4806a7c85c3c521f0570a823..08f4d3ac55583016007f73aa3e78b3afbbb439f4 100644
--- a/src/lib-sieve/sieve-code.h
+++ b/src/lib-sieve/sieve-code.h
@@ -1,16 +1,15 @@
 #ifndef __SIEVE_CODE_H__
 #define __SIEVE_CODE_H__
 
+#include <lib.h>
+#include <buffer.h>
+#include <array.h>
+
 #include "sieve-common.h"
 #include "sieve-extensions.h"
 
 typedef size_t sieve_size_t;
 
-struct sieve_opcode {
-	bool (*dump)(struct sieve_interpreter *interpreter);
-	bool (*execute)(struct sieve_interpreter *interpreter);
-};
-
 enum sieve_core_operation {
 	SIEVE_OPCODE_LOAD      = 0x01,
 	SIEVE_OPCODE_JMP       = 0x02,
@@ -32,6 +31,9 @@ enum sieve_core_operand {
   SIEVE_OPERAND_STRING_LIST  = 0x03
 };
 
+#define SIEVE_OPCODE_CORE_MASK  0x1F
+#define SIEVE_OPCODE_EXT_OFFSET (SIEVE_OPCODE_CORE_MASK + 1)
+
 #define SIEVE_CORE_OPERAND_MASK 0x0F
 #define SIEVE_CORE_OPERAND_BITS 4
  
diff --git a/src/lib-sieve/sieve-extensions.c b/src/lib-sieve/sieve-extensions.c
index d46f0a302867f8a0f0d58fae11a5710aa7658208..4112b028cfa57b269731a22c5016fb61ce9c0f72 100644
--- a/src/lib-sieve/sieve-extensions.c
+++ b/src/lib-sieve/sieve-extensions.c
@@ -3,10 +3,12 @@
 
 #include "sieve-extensions.h"
 
-const struct sieve_extension sieve_core_extensions[] = {
-	{ "fileinto", ext_fileinto_validator_load, NULL },
-	{ "reject", ext_reject_validator_load, ext_reject_generator_load },
-	{ "envelope", ext_envelope_validator_load, NULL }
+extern const struct sieve_extension fileinto_extension;
+extern const struct sieve_extension reject_extension;
+extern const struct sieve_extension envelope_extension;
+
+const struct sieve_extension *sieve_core_extensions[] = {
+	&fileinto_extension, &reject_extension, &envelope_extension 
 };
 
 const unsigned int sieve_core_extensions_count =
@@ -17,8 +19,8 @@ const struct sieve_extension *sieve_extension_acquire(const char *extension) {
 	
 	/* First try to acquire one of the compiled-in extensions */
 	for ( i = 0; i < sieve_core_extensions_count; i++ ) {
-		if ( strcasecmp(extension, sieve_core_extensions[i].name) == 0 ) 
-			return &sieve_core_extensions[i];
+		if ( strcasecmp(extension, sieve_core_extensions[i]->name) == 0 ) 
+			return sieve_core_extensions[i];
 	}
 	
 	/* Try to load a plugin */
diff --git a/src/lib-sieve/sieve-extensions.h b/src/lib-sieve/sieve-extensions.h
index 15a841b3b4bc8f530fb4c67f07c12906bd29e578..ca9338b10dee08eeb029e82abec9cce3c4bca0d1 100644
--- a/src/lib-sieve/sieve-extensions.h
+++ b/src/lib-sieve/sieve-extensions.h
@@ -9,16 +9,11 @@ struct sieve_extension {
 	
 	bool (*validator_load)(struct sieve_validator *validator);
 	bool (*generator_load)(struct sieve_generator *generator);
+	
+	bool (*opcode_dump)(struct sieve_interpreter *interpreter);
+	bool (*opcode_execute)(struct sieve_interpreter *interpreter);
 };
 
 const struct sieve_extension *sieve_extension_acquire(const char *extension);
 
-bool ext_fileinto_validator_load(struct sieve_validator *validator);
-
-bool ext_reject_validator_load(struct sieve_validator *validator);
-bool ext_reject_generator_load(struct sieve_generator *generator);
-
-bool ext_envelope_validator_load(struct sieve_validator *validator);
-
-
 #endif /* __SIEVE_EXTENSIONS_H__ */
diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c
index 921e90990b5baa58e4fd71c631a6f6e912e041ef..fcb2fb6e0b3dc0a9bf900d9712c3b199358a89ed 100644
--- a/src/lib-sieve/sieve-generator.c
+++ b/src/lib-sieve/sieve-generator.c
@@ -2,18 +2,16 @@
 
 #include "lib.h"
 #include "mempool.h"
-#include "buffer.h"
-#include "array.h"
 #include "hash.h"
 
 #include "sieve-common.h"
 #include "sieve-extensions.h"
 #include "sieve-commands-private.h"
 #include "sieve-code.h"
+#include "sieve-binary.h"
 
 #include "sieve-generator.h"
 
-
 /* Jump list */
 void sieve_jumplist_init(struct sieve_jumplist *jlist)
 {
@@ -38,11 +36,11 @@ void sieve_jumplist_resolve(struct sieve_jumplist *jlist, struct sieve_generator
 	array_free(&jlist->jumps);
 }
 
-/* Opcode */
+/* Extensions */
 
-struct sieve_opcode_registration {
-	const struct sieve_opcode *opcode;
-	unsigned int code;
+struct sieve_extension_registration {
+	const struct sieve_extension *extension;
+	unsigned int opcode;
 };
 
 /* Generator */
@@ -52,11 +50,13 @@ struct sieve_generator {
 	
 	struct sieve_ast *ast;
 	
-	buffer_t *code_buffer;
-	struct hash_table *opcodes; 
+	struct sieve_binary *binary;
+	
+	struct hash_table *extension_index; 
 };
 
-struct sieve_generator *sieve_generator_create(struct sieve_ast *ast) {
+struct sieve_generator *sieve_generator_create(struct sieve_ast *ast) 
+{
 	pool_t pool;
 	struct sieve_generator *generator;
 	
@@ -66,10 +66,11 @@ struct sieve_generator *sieve_generator_create(struct sieve_ast *ast) {
 	
 	generator->ast = ast;	
 	sieve_ast_ref(ast);
+
+	generator->binary = sieve_binary_create_new();
+	sieve_binary_ref(generator->binary);
 	
-	generator->code_buffer = buffer_create_dynamic(pool, 256);
-	
-	generator->opcodes = hash_create
+	generator->extension_index = hash_create
 		(pool, pool, 0, NULL, NULL);
 	
 	return generator;
@@ -77,74 +78,46 @@ struct sieve_generator *sieve_generator_create(struct sieve_ast *ast) {
 
 void sieve_generator_free(struct sieve_generator *generator) 
 {
-	hash_destroy(generator->opcodes);
+	hash_destroy(generator->extension_index);
 	
 	sieve_ast_unref(&generator->ast);
+	sieve_binary_unref(&generator->binary);
 	pool_unref(generator->pool);
 }
 
 /* Registration functions */
 
-void sieve_generator_register_opcode
-	(struct sieve_generator *generator, const struct sieve_opcode *opcode) 
+void sieve_generator_register_extension
+	(struct sieve_generator *generator, const struct sieve_extension *extension) 
 {
-	struct sieve_opcode_registration *reg;
+	struct sieve_extension_registration *reg;
 	
-	reg = p_new(generator->pool, struct sieve_opcode_registration, 1);
-	reg->opcode = opcode;
-	reg->code = hash_size(generator->opcodes);
+	reg = p_new(generator->pool, struct sieve_extension_registration, 1);
+	reg->extension = extension;
+	reg->opcode = sieve_binary_link_extension(generator->binary, extension);
 	
-	hash_insert(generator->opcodes, (void *) opcode, (void *) reg);
+	hash_insert(generator->extension_index, (void *) extension, (void *) reg);
 }
 
-unsigned int sieve_generator_find_opcode
-		(struct sieve_generator *generator, const struct sieve_opcode *opcode) 
+unsigned int sieve_generator_find_extension		
+	(struct sieve_generator *generator, const struct sieve_extension *extension) 
 {
-  struct sieve_opcode_registration *reg = 
-    (struct sieve_opcode_registration *) hash_lookup(generator->opcodes, opcode);
+  struct sieve_extension_registration *reg = 
+    (struct sieve_extension_registration *) hash_lookup(generator->extension_index, extension);
     
-  return reg->code;
+  return reg->opcode;
 }
 
 /* Emission functions */
 
-inline sieve_size_t sieve_generator_emit_data(struct sieve_generator *generator, void *data, sieve_size_t size) 
-{
-	buffer_append(generator->code_buffer, data, size);
-	
-	return buffer_get_used_size(generator->code_buffer);
-}
-
-inline sieve_size_t sieve_generator_emit_byte(struct sieve_generator *generator, unsigned char byte) 
-{
-  sieve_size_t address = buffer_get_used_size(generator->code_buffer);
-  
-	buffer_append(generator->code_buffer, &byte, 1);
-	
-	return address;
-}
-
-inline void sieve_generator_update_data
-	(struct sieve_generator *generator, sieve_size_t address, void *data, sieve_size_t size) 
-{
-	buffer_write(generator->code_buffer, address, data, size);
-}
-
-inline sieve_size_t sieve_generator_get_current_address(struct sieve_generator *generator)
-{
-	return buffer_get_used_size(generator->code_buffer);
-}
-
-/* 
- */
 sieve_size_t sieve_generator_emit_offset(struct sieve_generator *generator, int offset) 
 {
   int i;
-	sieve_size_t address = buffer_get_used_size(generator->code_buffer);
+	sieve_size_t address = sieve_binary_get_code_size(generator->binary);
 
   for ( i = 3; i >= 0; i-- ) {
     char c = (char) (offset >> (i * 8));
-	  (void) sieve_generator_emit_data(generator, &c, 1);
+	  (void) sieve_binary_emit_data(generator->binary, &c, 1);
 	}
 	
 	return address;
@@ -154,11 +127,11 @@ void sieve_generator_resolve_offset
 	(struct sieve_generator *generator, sieve_size_t address) 
 {
   int i;
-	int offset = sieve_generator_get_current_address(generator) - address; 
+	int offset = sieve_binary_get_code_size(generator->binary) - address; 
 	
 	for ( i = 3; i >= 0; i-- ) {
     char c = (char) (offset >> (i * 8));
-	  (void) sieve_generator_update_data(generator, address + 3 - i, &c, 1);
+	  (void) sieve_binary_update_data(generator->binary, address + 3 - i, &c, 1);
 	}
 } 
 
@@ -167,7 +140,6 @@ void sieve_generator_resolve_offset
 sieve_size_t sieve_generator_emit_integer(struct sieve_generator *generator, sieve_size_t integer)
 {
   int i;
-	sieve_size_t address = buffer_get_used_size(generator->code_buffer);
   char buffer[sizeof(sieve_size_t) + 1];
   int bufpos = sizeof(buffer) - 1;
   
@@ -187,14 +159,12 @@ sieve_size_t sieve_generator_emit_integer(struct sieve_generator *generator, sie
     }
   } 
   
-  (void) sieve_generator_emit_data(generator, buffer + bufpos, sizeof(buffer) - bufpos);
-  
-  return address;
+  return sieve_binary_emit_data(generator->binary, buffer + bufpos, sizeof(buffer) - bufpos);
 }
 
 sieve_size_t sieve_generator_emit_number(struct sieve_generator *generator, sieve_size_t number)
 {
-  sieve_size_t address = sieve_generator_emit_byte(generator, SIEVE_OPERAND_NUMBER);
+  sieve_size_t address = sieve_binary_emit_byte(generator->binary, SIEVE_OPERAND_NUMBER);
   
   (void) sieve_generator_emit_integer(generator, number);
 
@@ -203,17 +173,15 @@ sieve_size_t sieve_generator_emit_number(struct sieve_generator *generator, siev
 
 static sieve_size_t sieve_generator_emit_string_item(struct sieve_generator *generator, const string_t *str)
 {
-	sieve_size_t address = buffer_get_used_size(generator->code_buffer);
-  
-  (void) sieve_generator_emit_integer(generator, str_len(str));
-  (void) sieve_generator_emit_data(generator, (void *) str_data(str), str_len(str));
+	sieve_size_t address = sieve_generator_emit_integer(generator, str_len(str));
+  (void) sieve_binary_emit_data(generator->binary, (void *) str_data(str), str_len(str));
 
   return address;
 }
 
 sieve_size_t sieve_generator_emit_string(struct sieve_generator *generator, const string_t *str)
 {
-  sieve_size_t address = sieve_generator_emit_byte(generator, SIEVE_OPERAND_STRING);
+  sieve_size_t address = sieve_binary_emit_byte(generator->binary, SIEVE_OPERAND_STRING);
   
   (void) sieve_generator_emit_string_item(generator, str);
   
@@ -248,12 +216,13 @@ bool sieve_generator_emit_string_argument
 sieve_size_t sieve_generator_emit_string_list
 	(struct sieve_generator *generator, const struct sieve_ast_argument *strlist)
 {
+	sieve_size_t address;
   const struct sieve_ast_argument *stritem;
   unsigned int listlen = sieve_ast_strlist_count(strlist);
   sieve_size_t end_offset = 0;
 
 	/* Emit byte identifying the type of operand */	  
-  sieve_size_t address = sieve_generator_emit_byte(generator, SIEVE_OPERAND_STRING_LIST);
+  address = sieve_binary_emit_byte(generator->binary, SIEVE_OPERAND_STRING_LIST);
   
   /* Give the interpreter an easy way to skip over this string list */
   end_offset = sieve_generator_emit_offset(generator, 0);
@@ -277,17 +246,17 @@ sieve_size_t sieve_generator_emit_string_list
 
 sieve_size_t sieve_generator_emit_core_opcode(struct sieve_generator *generator, int opcode) 
 {
-	unsigned char op = opcode & 0x3F;
+	unsigned char op = opcode & SIEVE_OPCODE_CORE_MASK;
 	
-	return sieve_generator_emit_data(generator, (void *) &op, 1);
+	return sieve_binary_emit_byte(generator->binary, op);
 }
 
 sieve_size_t sieve_generator_emit_opcode
-	(struct sieve_generator *generator, const struct sieve_opcode *opcode) 
+	(struct sieve_generator *generator, const struct sieve_extension *extension) 
 {
-	unsigned char op = (1 << 6) + sieve_generator_find_opcode(generator, opcode);
+	unsigned char op = SIEVE_OPCODE_EXT_OFFSET + sieve_generator_find_extension(generator, extension);
 	
-	return sieve_generator_emit_data(generator, (void *) &op, 1);
+	return sieve_binary_emit_byte(generator->binary, op);
 }
 
 /* Generator functions */
@@ -351,14 +320,12 @@ bool sieve_generate_block(struct sieve_generator *generator, struct sieve_ast_no
 	return TRUE;
 }
 
-bool sieve_generate(struct sieve_generator *generator, buffer_t **code) {	
+struct sieve_binary *sieve_generate(struct sieve_generator *generator) {	
 	if ( sieve_generate_block(generator, sieve_ast_root(generator->ast)) ) {
-		if ( code != NULL )
-			*code = generator->code_buffer;
-	 	return TRUE;
+	 	return generator->binary;
 	} 
 	
-	return FALSE;
+	return NULL;
 }
 
 
diff --git a/src/lib-sieve/sieve-generator.h b/src/lib-sieve/sieve-generator.h
index 808dc76480a73ad5506648252c8471bafffac029..a8ded0b25f5cafb971e691d6a65f29e5fd3bf168 100644
--- a/src/lib-sieve/sieve-generator.h
+++ b/src/lib-sieve/sieve-generator.h
@@ -9,10 +9,10 @@ struct sieve_generator;
 struct sieve_generator *sieve_generator_create(struct sieve_ast *ast);
 void sieve_generator_free(struct sieve_generator *generator);
 
-void sieve_generator_register_opcode
-	(struct sieve_generator *generator, const struct sieve_opcode *opcode);
-unsigned int sieve_generator_find_opcode
-		(struct sieve_generator *generator, const struct sieve_opcode *opcode); 
+void sieve_generator_register_extension
+	(struct sieve_generator *generator, const struct sieve_extension *extension);
+unsigned int sieve_generator_find_extension
+		(struct sieve_generator *generator, const struct sieve_extension *extension); 
 		
 /* Jump list */
 
@@ -32,7 +32,7 @@ inline void sieve_generator_update_data
 inline sieve_size_t sieve_generator_get_current_address(struct sieve_generator *generator);
 
 sieve_size_t sieve_generator_emit_core_opcode(struct sieve_generator *generator, int opcode);
-sieve_size_t sieve_generator_emit_opcode(struct sieve_generator *generator, const struct sieve_opcode *opcode);
+sieve_size_t sieve_generator_emit_opcode(struct sieve_generator *generator, const struct sieve_extension *extension);
 
 sieve_size_t sieve_generator_emit_offset(struct sieve_generator *generator, int offset);
 void sieve_generator_resolve_offset(struct sieve_generator *generator, sieve_size_t address); 
@@ -55,7 +55,7 @@ bool sieve_generator_emit_stringlist_argument
 bool sieve_generate_block(struct sieve_generator *generator, struct sieve_ast_node *block);
 bool sieve_generate_test(struct sieve_generator *generator, struct sieve_ast_node *tst_node, 
 	struct sieve_jumplist *jlist, bool jump_true);
-bool sieve_generate(struct sieve_generator *genarator, buffer_t **code);
+struct sieve_binary *sieve_generate(struct sieve_generator *genarator);
 
 #endif
 
diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index 1961e8852c9ca45a0cf317d7b38dd2ad836d9e3c..f072237805367499c32485a5cdc3d0827a94ecbd 100644
--- a/src/lib-sieve/sieve-interpreter.c
+++ b/src/lib-sieve/sieve-interpreter.c
@@ -7,6 +7,8 @@
 
 #include "sieve-commands-private.h"
 #include "sieve-generator.h"
+#include "sieve-binary.h"
+
 #include "sieve-interpreter.h"
 
 struct sieve_coded_stringlist {
@@ -24,15 +26,17 @@ struct sieve_coded_stringlist {
 
 struct sieve_interpreter {
 	pool_t pool;
+	
+	struct sieve_binary *binary;
+	
+	/* Direct pointer to code inside binary (which is considered immutable) */
 	const char *code;
 	sieve_size_t code_size;
 	
-	sieve_size_t pc;
-	
-	array_t ARRAY_DEFINE(opcode_extensions, struct sieve_operation_extension *); 
+	sieve_size_t pc; 
 };
 
-struct sieve_interpreter *sieve_interpreter_create(buffer_t *code) 
+struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *binary) 
 {
 	pool_t pool;
 	struct sieve_interpreter *interpreter;
@@ -41,18 +45,19 @@ struct sieve_interpreter *sieve_interpreter_create(buffer_t *code)
 	interpreter = p_new(pool, struct sieve_interpreter, 1);
 	interpreter->pool = pool;
 	
-	interpreter->code = buffer_get_data(code, &interpreter->code_size);	
+	interpreter->binary = binary;
+	interpreter->code = sieve_binary_get_code(binary, &interpreter->code_size);	
+	sieve_binary_ref(binary);
 	
 	interpreter->pc = 0;
 	
-	ARRAY_CREATE(&interpreter->opcode_extensions, pool, struct sieve_operation_extension *, 4);
-	
 	return interpreter;
 }
 
 void sieve_interpreter_free(struct sieve_interpreter *interpreter) 
 {
 	pool_unref(interpreter->pool);
+	sieve_binary_unref(&interpreter->binary);
 }
 
 void sieve_interpreter_reset(struct sieve_interpreter *interpreter) 
@@ -165,16 +170,23 @@ bool sieve_coded_stringlist_read_item(struct sieve_coded_stringlist *strlist, st
 static void sieve_interpreter_dump_operation
 	(struct sieve_interpreter *interpreter) 
 {
-	int opcode;
+	unsigned int opcode;
 	
 	if ( CODE_BYTES_LEFT(interpreter) > 0 ) {
-		opcode = CODE_AT_PC(interpreter);
+		opcode = DATA_AT_PC(interpreter);
 		CODE_JUMP(interpreter, 1);
 	
-		if ( opcode <= 0x3F ) {
+		if ( opcode < SIEVE_OPCODE_EXT_OFFSET ) {
 			sieve_core_code_dump(interpreter, interpreter->pc-1, opcode);
 		} else {
-		  printf("DUMPING EXTENSIONS NOT IMPLEMENTED\n");
+		  const struct sieve_extension *ext = 
+		  	sieve_binary_get_extension(interpreter->binary, opcode - SIEVE_OPCODE_EXT_OFFSET);
+		  	
+		  printf("%08x: ", interpreter->pc-1);
+		  if ( ext->opcode_dump != NULL )
+			  (void) ext->opcode_dump(interpreter);
+			else
+				printf("OPCODE: %d, Extension %s provides no opcode_dump implementation.\n", opcode, ext->name);
 		}
 	}		
 }
@@ -269,5 +281,7 @@ void sieve_interpreter_dump_code(struct sieve_interpreter *interpreter)
 	while ( interpreter->pc < interpreter->code_size ) {
 		sieve_interpreter_dump_operation(interpreter);
 	}
+	
+	printf("%08x: [End of code]\n", interpreter->code_size);	
 }
 
diff --git a/src/lib-sieve/sieve-interpreter.h b/src/lib-sieve/sieve-interpreter.h
index 8b9d27ae569c3402b4695163598b0c244669fa83..28cdcba9794fe4880417edfd6cfe2e0dc20f69da 100644
--- a/src/lib-sieve/sieve-interpreter.h
+++ b/src/lib-sieve/sieve-interpreter.h
@@ -3,13 +3,14 @@
 
 #include "lib.h"
 #include "buffer.h"
-#include "sieve-interpreter.h"
+
+#include "sieve-binary.h"
 
 struct sieve_coded_stringlist;
 
 struct sieve_interpreter;
 
-struct sieve_interpreter *sieve_interpreter_create(buffer_t *code);
+struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *binary);
 void sieve_interpreter_free(struct sieve_interpreter *interpreter);
 
 int sieve_interpreter_read_offset(struct sieve_interpreter *interpreter);
@@ -23,6 +24,8 @@ bool sieve_interpreter_read_stringlist
 bool sieve_coded_stringlist_read_item
 	(struct sieve_coded_stringlist *strlist, string_t **str);  
 
+/* Code dump (debugging purposes) */
+
 void sieve_interpreter_dump_number(struct sieve_interpreter *interpreter);
 void sieve_interpreter_dump_string(struct sieve_interpreter *interpreter);
 void sieve_interpreter_dump_string_list(struct sieve_interpreter *interpreter);
diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c
index e449ba8dc0a2bee721bc4f25df242210903a1d2d..d3d06d0c37659c8b52658fa4a793b0cee4616e32 100644
--- a/src/lib-sieve/sieve-validator.c
+++ b/src/lib-sieve/sieve-validator.c
@@ -201,7 +201,7 @@ static const struct sieve_tag *sieve_validator_find_tag
 
 /* Extension support */
 
-bool sieve_validator_load_extension
+const struct sieve_extension *sieve_validator_load_extension
 	(struct sieve_validator *validator, struct sieve_command_context *cmd, const char *extension) 
 {
 	const struct sieve_extension *ext = sieve_extension_acquire(extension); 
@@ -209,17 +209,17 @@ bool sieve_validator_load_extension
 	if ( ext == NULL ) {
 		sieve_command_validate_error(validator, cmd, 
 			"unsupported sieve capability '%s'", extension);
-		return FALSE;
+		return NULL;
 	}
 
 	if ( ext->validator_load != NULL && !ext->validator_load(validator) ) {
 		sieve_command_validate_error(validator, cmd, 
 			"failed to load sieve capability '%s'", extension);
-		return FALSE;
+		return NULL;
 	}
 	
 	i_info("loaded extension '%s'", extension);
-	return TRUE;
+	return ext;
 }
 
 /* Comparator validation */
diff --git a/src/lib-sieve/sieve-validator.h b/src/lib-sieve/sieve-validator.h
index 97c0f61e2eb2439c06a91fbdea458ab95a6d90e5..f00ee5c1e018c33becc6ee93c719ddccdee34132 100644
--- a/src/lib-sieve/sieve-validator.h
+++ b/src/lib-sieve/sieve-validator.h
@@ -46,7 +46,9 @@ bool sieve_validate_command_subtests
 	(struct sieve_validator *validator, struct sieve_command_context *cmd, const unsigned int count);
 bool sieve_validate_command_block(struct sieve_validator *validator, struct sieve_command_context *cmd, 
 	bool block_allowed, bool block_required);
-bool sieve_validator_load_extension
+
+/* Extensions */
+const struct sieve_extension *sieve_validator_load_extension
 	(struct sieve_validator *validator, struct sieve_command_context *cmd, const char *extension);
 
 #endif /* __SIEVE_VALIDATOR_H__ */
diff --git a/src/lib-sieve/sievec.c b/src/lib-sieve/sievec.c
index 0df9d23eaba43e553f855a4b4ae11ef4085b3f68..cafc4240c34f6cbd26f186ad5a0a8ead0b8b94b4 100644
--- a/src/lib-sieve/sievec.c
+++ b/src/lib-sieve/sievec.c
@@ -31,9 +31,8 @@ int main(int argc, char **argv) {
 	struct sieve_validator *validator;
 	struct sieve_generator *generator;
 	struct sieve_interpreter *interpreter;
-	buffer_t *code = NULL;
+	struct sieve_binary *binary;
 	
-
 	if ( argc < 2 ) {
 		printf( "Usage: sievec <filename>\n");
  		exit(1);
@@ -73,13 +72,14 @@ int main(int argc, char **argv) {
 			printf("Generating script...\n"); 		
 			generator = sieve_generator_create(ast);
 	
-			if ( !sieve_generate(generator, &code) || sieve_get_errors(ehandler) > 0 ) {
+			binary = sieve_generate(generator);
+			if ( sieve_get_errors(ehandler) > 0 || (binary == NULL) ) {
 				printf("Script generation failed.\n");
 			} else {
 				printf("Script generation successful.\n");
 				
 				printf("Code Dump:\n\n");
-				interpreter = sieve_interpreter_create(code);
+				interpreter = sieve_interpreter_create(binary);
 				
 				sieve_interpreter_dump_code(interpreter);