diff --git a/sieve/tests/address-part.sieve b/sieve/tests/address-part.sieve
index fbe58b6b5bae85af03065f7778835d16ce60ba2b..1bc36eb8ba56e8eaa03faa2ddf71b7011503aedc 100644
--- a/sieve/tests/address-part.sieve
+++ b/sieve/tests/address-part.sieve
@@ -1,7 +1,7 @@
 if address :comparator "i;octet" :domain "from" "STEPHAN" {
 	discard;
 
-	if address :domain :comparator "i;octet" "from" "drunksnipers.com" {
+	if address :localpart :comparator "i;octet" "from" "drunksnipers.com" {
 		keep;
 	}
 	stop;
diff --git a/src/lib-sieve/ext-encoded-character.c b/src/lib-sieve/ext-encoded-character.c
index 8733ec93abf6a4db4a987d22cbc362702dc930b1..23608ea468187dc2b36b96107c82c7271a10cc9f 100644
--- a/src/lib-sieve/ext-encoded-character.c
+++ b/src/lib-sieve/ext-encoded-character.c
@@ -11,7 +11,7 @@
 #include "lib.h"
 #include "unichar.h"
 
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-validator.h"
 
diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index 641eeaccb3d894c2ca0270c3dd370f50dc60a4c8..00bc1457a7adc4374560d5cf23759053923427ff 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -13,7 +13,7 @@
 #include "lib.h"
 #include "array.h"
 
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-code.h"
 #include "sieve-comparators.h"
diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c
index e4e3c5b76335fe356b094d4f9ee75bc626bb445d..8dcc093fb129e41ef98e9abfd52e4b4c456c1c4a 100644
--- a/src/lib-sieve/ext-fileinto.c
+++ b/src/lib-sieve/ext-fileinto.c
@@ -10,7 +10,7 @@
 
 #include <stdio.h>
 
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-code.h"
 #include "sieve-actions.h"
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index 88765aa37fa114dec6e761946ffc21746f554e0f..41a38aef13fcf3e855fb0986db9c23831ca594e0 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -16,7 +16,7 @@
 #include "istream.h"
 #include "istream-header-filter.h"
 
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-code.h"
 #include "sieve-actions.h"
diff --git a/src/lib-sieve/plugins/body/ext-body.c b/src/lib-sieve/plugins/body/ext-body.c
index 8fba4e08b81ba7aa0420979b1389581317fec118..0a3218d5033b10a25fda5d6a9fff55d3d79a4480 100644
--- a/src/lib-sieve/plugins/body/ext-body.c
+++ b/src/lib-sieve/plugins/body/ext-body.c
@@ -27,7 +27,7 @@
 #include "lib.h"
 #include "array.h"
 
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-comparators.h"
 #include "sieve-match-types.h"
diff --git a/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c b/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
index 650330e47a3d963eb1979a4a719bdfb358c59a85..99f7b89e45378ee3e983353c7373df1124514a83 100644
--- a/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+++ b/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
@@ -11,7 +11,7 @@
 #include "sieve-common.h"
 
 #include "sieve-code.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-comparators.h"
 #include "sieve-validator.h"
 #include "sieve-generator.h"
diff --git a/src/lib-sieve/plugins/copy/ext-copy.c b/src/lib-sieve/plugins/copy/ext-copy.c
index f25cf894afcf15cdd0ea0689095328e2a75a4698..a674bf151daecd9913617430ce3f7861c73c62f6 100644
--- a/src/lib-sieve/plugins/copy/ext-copy.c
+++ b/src/lib-sieve/plugins/copy/ext-copy.c
@@ -13,7 +13,7 @@
 #include "sieve-common.h"
 
 #include "sieve-code.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-actions.h"
 #include "sieve-commands.h"
 #include "sieve-validator.h"
diff --git a/src/lib-sieve/plugins/imapflags/tag-flags.c b/src/lib-sieve/plugins/imapflags/tag-flags.c
index b1f061a8a05427afc0228d9445d1b4c8d1904cb7..989902bee02f0b7ebacff14ae1bc23a3f8a5ca42 100644
--- a/src/lib-sieve/plugins/imapflags/tag-flags.c
+++ b/src/lib-sieve/plugins/imapflags/tag-flags.c
@@ -3,7 +3,7 @@
 #include "mail-storage.h"
 
 #include "sieve-code.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-result.h"
 #include "sieve-validator.h" 
diff --git a/src/lib-sieve/plugins/include/ext-include.c b/src/lib-sieve/plugins/include/ext-include.c
index 622ba1d2bc5d6da5061ef5fd599b3551978dcda5..b914869e75c7d67cf16b2e569a4374dc1f94d089 100644
--- a/src/lib-sieve/plugins/include/ext-include.c
+++ b/src/lib-sieve/plugins/include/ext-include.c
@@ -21,7 +21,7 @@
 
 #include "sieve-common.h"
 
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-validator.h"
 #include "sieve-generator.h"
 #include "sieve-interpreter.h"
diff --git a/src/lib-sieve/plugins/regex/ext-regex.c b/src/lib-sieve/plugins/regex/ext-regex.c
index 12b31e37330cb40e24b5fb7445d234abd4e2f3fc..b5270c3a16c4b9920c993a42c5e826c412a5c235 100644
--- a/src/lib-sieve/plugins/regex/ext-regex.c
+++ b/src/lib-sieve/plugins/regex/ext-regex.c
@@ -21,7 +21,7 @@
 #include "sieve-common.h"
 
 #include "sieve-code.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 
 #include "sieve-comparators.h"
diff --git a/src/lib-sieve/plugins/relational/ext-relational.c b/src/lib-sieve/plugins/relational/ext-relational.c
index 0d03d7ae44eb7405e7a9c24f263092d6a7bdb172..1a886ef2f4ac91849e26d4ec64999eb7be9c2101 100644
--- a/src/lib-sieve/plugins/relational/ext-relational.c
+++ b/src/lib-sieve/plugins/relational/ext-relational.c
@@ -23,7 +23,7 @@
 
 #include "sieve-ast.h"
 #include "sieve-code.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-comparators.h"
 #include "sieve-match-types.h"
diff --git a/src/lib-sieve/plugins/subaddress/ext-subaddress.c b/src/lib-sieve/plugins/subaddress/ext-subaddress.c
index 2f24a38148bca46debefbd558907d8e739785fe0..c2b409789ba4685fb02a180dcb3c4d897b9e8940 100644
--- a/src/lib-sieve/plugins/subaddress/ext-subaddress.c
+++ b/src/lib-sieve/plugins/subaddress/ext-subaddress.c
@@ -14,7 +14,7 @@
 #include "sieve-common.h"
 
 #include "sieve-code.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-address-parts.h"
 #include "sieve-validator.h"
diff --git a/src/lib-sieve/plugins/vacation/ext-vacation.c b/src/lib-sieve/plugins/vacation/ext-vacation.c
index 236004509217971d29831f1f507ddadbf52471d8..47f70b81740daccdfe0bc2df3bef5454706f7ade 100644
--- a/src/lib-sieve/plugins/vacation/ext-vacation.c
+++ b/src/lib-sieve/plugins/vacation/ext-vacation.c
@@ -20,7 +20,7 @@
 #include "sieve-common.h"
 
 #include "sieve-code.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-actions.h"
 #include "sieve-validator.h"
diff --git a/src/lib-sieve/plugins/variables/ext-variables.c b/src/lib-sieve/plugins/variables/ext-variables.c
index 367be81297772bb303d8a5eede5f8d326705840e..e25fa996ef5297dc3300d65853e79009f300b6c3 100644
--- a/src/lib-sieve/plugins/variables/ext-variables.c
+++ b/src/lib-sieve/plugins/variables/ext-variables.c
@@ -11,7 +11,7 @@
 #include "lib.h"
 #include "unichar.h"
 
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-validator.h"
 
diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c
index bdccc318acb073b47962a0b53f9a051e5461eb4b..9b7d389e332f16b554d30661582808cebeb15759 100644
--- a/src/lib-sieve/sieve-actions.c
+++ b/src/lib-sieve/sieve-actions.c
@@ -14,6 +14,9 @@
 
 #include <ctype.h>
 
+static struct sieve_extension_obj_registry seff_default_reg =
+	SIEVE_EXT_DEFINE_NO_SIDE_EFFECTS;
+
 /*
  * Message transmission (FIXME: place this somewhere more appropriate)
  */
@@ -93,12 +96,40 @@ void sieve_opr_side_effect_emit
 	(struct sieve_binary *sbin, const struct sieve_side_effect *seffect, 
 		int ext_id)
 { 
-	sieve_size_t address;
-
 	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_SIDE_EFFECT);
 
-	sieve_extension_emit_object
-		(seffect, side_effects, sbin, ext_id, 0, address); 
+	(void) sieve_extension_emit_obj
+		(sbin, &seff_default_reg, seffect, side_effects, ext_id);
+}
+
+static const struct sieve_extension_obj_registry *
+	sieve_side_effect_registry_get
+(struct sieve_binary *sbin, unsigned int ext_index)
+{
+	int ext_id = -1; 
+	const struct sieve_side_effect_extension *ext;
+	
+	if ( sieve_binary_extension_get_by_index(sbin, ext_index, &ext_id) == NULL )
+		return NULL;
+
+	if ( (ext=sieve_side_effect_extension_get(sbin, ext_id)) == NULL ) 
+		return NULL;
+		
+	return &(ext->side_effects);
+}
+
+const struct sieve_side_effect *sieve_opr_side_effect_read
+(struct sieve_binary *sbin, sieve_size_t *address)
+{
+	unsigned int seffect_code;
+	const struct sieve_operand *operand = sieve_operand_read(sbin, address);
+
+	if ( operand == NULL || operand->class != &side_effect_class ) 
+		return NULL;
+		
+	return sieve_extension_read_obj
+		(struct sieve_side_effect, sbin, address, &seff_default_reg, 
+			sieve_side_effect_registry_get);
 }
 
 bool sieve_opr_side_effect_dump
@@ -106,13 +137,13 @@ bool sieve_opr_side_effect_dump
 {
 	const struct sieve_side_effect *seffect;
 
-    sieve_code_mark(denv);
+	sieve_code_mark(denv);
 	seffect = sieve_opr_side_effect_read(denv->sbin, address);
 
 	if ( seffect == NULL ) 
 		return FALSE;
 
-    sieve_code_dumpf(denv, "SIDE-EFFECT: %s", seffect->name);
+	sieve_code_dumpf(denv, "SIDE-EFFECT: %s", seffect->name);
 
 	if ( seffect->dump_context != NULL ) {
 		sieve_code_descend(denv);
@@ -121,39 +152,7 @@ bool sieve_opr_side_effect_dump
 		sieve_code_ascend(denv);
 	}
 
-    return TRUE;
-}
-
-/* FIXME: Duplicated */
-const struct sieve_side_effect *sieve_opr_side_effect_read
-(struct sieve_binary *sbin, sieve_size_t *address)
-{
-	unsigned int seffect_code;
-	const struct sieve_operand *operand = sieve_operand_read(sbin, address);
-
-	if ( operand == NULL || operand->class != &side_effect_class ) 
-		return NULL;
-		
-	
-	if ( sieve_binary_read_byte(sbin, address, &seffect_code) ) {
-		int ext_id = -1;
-		const struct sieve_side_effect_extension *se_ext;
-		const struct sieve_side_effect *seffect;
-
-		if ( sieve_binary_extension_get_by_index(sbin,
-			seffect_code, &ext_id) == NULL )
-			return NULL; 
-
-		se_ext = sieve_side_effect_extension_get(sbin, ext_id); 
-
-		sieve_extension_read_object 
-			(se_ext, struct sieve_side_effect, side_effects, sbin, 
-			address, seffect)
-
-		return seffect;
-	}		
-		
-	return NULL; 
+	return TRUE;
 }
 
 /*
diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h
index 2d879769f7dde51c55f67e67609f22cb164590e4..7806872f3f522ca76d6ba3189b8f9b2b393f5425 100644
--- a/src/lib-sieve/sieve-actions.h
+++ b/src/lib-sieve/sieve-actions.h
@@ -5,7 +5,7 @@
 #include "mail-storage.h"
 
 #include "sieve-common.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 
 /* Sieve action */
 
@@ -98,6 +98,7 @@ struct sieve_side_effect_extension {
 	struct sieve_extension_obj_registry side_effects;
 };
 
+#define SIEVE_EXT_DEFINE_NO_SIDE_EFFECTS SIEVE_EXT_DEFINE_NO_OBJECTS
 #define SIEVE_EXT_DEFINE_SIDE_EFFECT(SEF) SIEVE_EXT_DEFINE_OBJECT(SEF)
 #define SIEVE_EXT_DEFINE_SIDE_EFFECTS(SEFS) SIEVE_EXT_DEFINE_OBJECTS(SEFS)
 
diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c
index c03fa2b536e12cad0fc718a66d6ee2a631b62024..bf6f70dddfa28b57b8ffbc461651b64713e0f2c9 100644
--- a/src/lib-sieve/sieve-address-parts.c
+++ b/src/lib-sieve/sieve-address-parts.c
@@ -23,9 +23,23 @@
 #include <string.h>
 
 /* 
- * Predeclarations 
+ * Default address parts
  */
- 
+
+const struct sieve_address_part *sieve_core_address_parts[] = {
+	&all_address_part, &local_address_part, &domain_address_part
+};
+
+const unsigned int sieve_core_address_parts_count = 
+	N_ELEMENTS(sieve_core_address_parts);
+
+static struct sieve_extension_obj_registry addrp_default_reg =
+	SIEVE_EXT_DEFINE_ADDRESS_PARTS(sieve_core_address_parts);
+
+/* 
+ * Forward declarations 
+ */
+  
 static void opr_address_part_emit
 	(struct sieve_binary *sbin, const struct sieve_address_part *addrp, 
 		int ext_id);
@@ -231,62 +245,46 @@ static bool tag_address_part_validate
 	return TRUE;
 }
 
-/* Code generation */
+/* 
+ * Code generation 
+ */
 
 static void opr_address_part_emit
 (struct sieve_binary *sbin, const struct sieve_address_part *addrp, int ext_id)
-{ 
+{
 	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_ADDRESS_PART);	
 
-	if ( ext_id >= 0 ) {
-		sieve_size_t dummy;
-		
-		sieve_extension_emit_object
-			(addrp, address_parts, sbin, ext_id, SIEVE_ADDRESS_PART_CUSTOM, dummy); 
-		
-		return;
-	} 
+	(void) sieve_extension_emit_obj
+		(sbin, &addrp_default_reg, addrp, address_parts, ext_id);
+}
+
+static const struct sieve_extension_obj_registry *
+	sieve_address_part_registry_get
+(struct sieve_binary *sbin, unsigned int ext_index)
+{
+	int ext_id = -1; 
+	const struct sieve_address_part_extension *ext;
 	
-	(void) sieve_binary_emit_byte(sbin, addrp->code);
+	if ( sieve_binary_extension_get_by_index(sbin, ext_index, &ext_id) == NULL )
+		return NULL;
+
+	if ( (ext=sieve_address_part_extension_get(sbin, ext_id)) == NULL ) 
+		return NULL;
+		
+	return &(ext->address_parts);
 }
 
-/* FIXME: Duplicated */
 const struct sieve_address_part *sieve_opr_address_part_read
 (struct sieve_binary *sbin, sieve_size_t *address)
 {
-	unsigned int addrp_code;
 	const struct sieve_operand *operand = sieve_operand_read(sbin, address);
 	
 	if ( operand == NULL || operand->class != &address_part_class ) 
 		return NULL;
-	
-	if ( sieve_binary_read_byte(sbin, address, &addrp_code) ) {
-		if ( addrp_code < SIEVE_ADDRESS_PART_CUSTOM ) {
-			if ( addrp_code < sieve_core_address_parts_count )
-				return sieve_core_address_parts[addrp_code];
-			else
-				return NULL;
-		} else {
-			const struct sieve_address_part_extension *addrp_ext;
-			const struct sieve_address_part *addrp;
-			int ext_id = -1; 
-			
-			if ( sieve_binary_extension_get_by_index
-				(sbin, addrp_code - SIEVE_ADDRESS_PART_CUSTOM, &ext_id) == NULL )
-				return NULL;
-	
-			if ( (addrp_ext=sieve_address_part_extension_get(sbin, ext_id)) == NULL )
-				return NULL;
-	
-			sieve_extension_read_object 
-				(addrp_ext, struct sieve_address_part, address_parts, sbin, address, 
-					addrp)
 
-			return addrp;
-		}
-	}		
-		
-	return NULL; 
+	return sieve_extension_read_obj
+		(struct sieve_address_part, sbin, address, &addrp_default_reg, 
+			sieve_address_part_registry_get);
 }
 
 bool sieve_opr_address_part_dump
@@ -488,11 +486,3 @@ const struct sieve_address_part domain_address_part = {
 	addrp_domain_extract_from
 };
 
-const struct sieve_address_part *sieve_core_address_parts[] = {
-	&all_address_part, &local_address_part, &domain_address_part
-};
-
-const unsigned int sieve_core_address_parts_count = 
-	N_ELEMENTS(sieve_core_address_parts);
-
-
diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c
index 35c11d74a5ab73161d5fb0199db8adbae034c3e5..be358a8589ff3ff92d3993c03f6ba12eb4a96829 100644
--- a/src/lib-sieve/sieve-binary.c
+++ b/src/lib-sieve/sieve-binary.c
@@ -6,7 +6,7 @@
 #include "array.h"
 #include "ostream.h"
 
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-code.h"
 #include "sieve-script.h"
 
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index e79e8acd9ea3fd9299863e9399250a88796f60c4..9a95cf19bafe20ba15c8e3df38a318d28cd86c39 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -3,7 +3,7 @@
 #include "str-sanitize.h"
 
 #include "sieve-common.h"
-#include "sieve-extensions.h"
+#include "sieve-extensions-private.h"
 #include "sieve-actions.h"
 #include "sieve-binary.h"
 #include "sieve-generator.h"
@@ -582,54 +582,7 @@ static struct sieve_coded_stringlist *opr_stringlist_read
 /* 
  * Operations
  */
-
-/* Operation functions */
-
-inline sieve_size_t sieve_operation_emit_code
-	(struct sieve_binary *sbin, const struct sieve_operation *op, int ext_id)
-{	
-	if ( ext_id >= 0 ) {
-		sieve_size_t address;
-		
-		sieve_extension_emit_object
-			(op, opcodes, sbin, ext_id, SIEVE_OPERATION_CUSTOM, address); 
-		
-		return address;
-	} 
-	
-	return sieve_binary_emit_byte(sbin, op->code);
-}
-
-const struct sieve_operation *sieve_operation_read
-	(struct sieve_binary *sbin, sieve_size_t *address) 
-{
-	unsigned int opcode;
-	
-	if ( sieve_binary_read_byte(sbin, address, &opcode) ) {
-		if ( opcode < SIEVE_OPERATION_CUSTOM ) {
-			if ( opcode < sieve_operations_count )
-				return sieve_operations[opcode];
-			else
-				return NULL;
-		} else {
-			struct sieve_operation *op;
-			int ext_id = -1; 
-			const struct sieve_extension *ext;
-			
-			if ( (ext=sieve_binary_extension_get_by_index
-				(sbin, opcode - SIEVE_OPERATION_CUSTOM, &ext_id)) == NULL )
-				return NULL;
-	
-			sieve_extension_read_object 
-				(ext, struct sieve_operation, opcodes, sbin, address, op)
-
-			return op;
-		}
-	}		
-	
-	return NULL;
-}
-
+ 
 /* Declaration of opcodes defined in this file */
 
 static bool opc_jmp_dump
@@ -703,6 +656,67 @@ const struct sieve_operation *sieve_operations[] = {
 const unsigned int sieve_operations_count =
 	N_ELEMENTS(sieve_operations);
 
+static struct sieve_extension_obj_registry oprt_default_reg =
+	SIEVE_EXT_DEFINE_OPERATIONS(sieve_operations);
+
+/* Operation functions */
+
+inline sieve_size_t sieve_operation_emit_code
+	(struct sieve_binary *sbin, const struct sieve_operation *op, int ext_id)
+{	
+	return sieve_extension_emit_obj
+		(sbin, &oprt_default_reg, op, operations, ext_id);
+}
+
+static const struct sieve_extension_obj_registry *
+	sieve_operation_registry_get
+(struct sieve_binary *sbin, unsigned int ext_index)
+{
+	int ext_id = -1; 
+	const struct sieve_extension *ext;
+	
+	if ( (ext=sieve_binary_extension_get_by_index(sbin, ext_index, &ext_id)) 
+		== NULL )
+		return NULL;
+		
+	return &(ext->operations);
+}
+
+const struct sieve_operation *sieve_operation_read
+	(struct sieve_binary *sbin, sieve_size_t *address) 
+{
+	return sieve_extension_read_obj
+		(struct sieve_operation, sbin, address, &oprt_default_reg, 
+			sieve_operation_registry_get);
+
+/*	unsigned int opcode;
+	
+	if ( sieve_binary_read_byte(sbin, address, &opcode) ) {
+		if ( opcode < SIEVE_OPERATION_CUSTOM ) {
+			if ( opcode < sieve_operations_count )
+				return sieve_operations[opcode];
+			else
+				return NULL;
+		} else {
+			struct sieve_operation *op;
+			int ext_id = -1; 
+			const struct sieve_extension *ext;
+			
+			if ( (ext=sieve_binary_extension_get_by_index
+				(sbin, opcode - SIEVE_OPERATION_CUSTOM, &ext_id)) == NULL )
+				return NULL;
+	
+			sieve_extension_read_object 
+				(ext, struct sieve_operation, opcodes, sbin, address, op)
+
+			return op;
+		}
+	}		
+	
+	return NULL;*/
+}
+
+	
 /* Code dump for core commands */
 
 static bool opc_jmp_dump
diff --git a/src/lib-sieve/sieve-comparators.c b/src/lib-sieve/sieve-comparators.c
index 620d8c2fce55f503bfc950b39b0bb8cba6619602..644247f2db61ffff7743a27f53e3bc1814fb5ead 100644
--- a/src/lib-sieve/sieve-comparators.c
+++ b/src/lib-sieve/sieve-comparators.c
@@ -19,12 +19,23 @@
 #include <ctype.h>
 
 /* 
- * Predeclarations 
+ * Default comparators
  */
  
-extern const struct sieve_comparator *sieve_core_comparators[];
-extern const unsigned int sieve_core_comparators_count;
+const struct sieve_comparator *sieve_core_comparators[] = {
+	&i_octet_comparator, &i_ascii_casemap_comparator
+};
+
+const unsigned int sieve_core_comparators_count =
+	N_ELEMENTS(sieve_core_comparators);
 
+static struct sieve_extension_obj_registry cmp_default_reg =
+	SIEVE_EXT_DEFINE_COMPARATORS(sieve_core_comparators);
+
+/* 
+ * Forward declarations 
+ */
+ 
 static void opr_comparator_emit
 	(struct sieve_binary *sbin, const struct sieve_comparator *cmp, int ext_id);
 
@@ -188,8 +199,10 @@ static bool cmp_binary_load(struct sieve_binary *sbin)
  * Comparator operand
  */
  
-struct sieve_operand_class comparator_class = { "comparator", NULL };
-struct sieve_operand comparator_operand = { "comparator", &comparator_class, FALSE };
+struct sieve_operand_class comparator_class = 
+	{ "comparator", NULL };
+struct sieve_operand comparator_operand = 
+	{ "comparator", &comparator_class, FALSE };
 
 /* 
  * Comparator tag 
@@ -294,53 +307,37 @@ static void opr_comparator_emit
 { 
 	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_COMPARATOR);	
 
-	if ( ext_id >= 0 ) {
-		sieve_size_t dummy;
-		
-		sieve_extension_emit_object
-			(cmp, comparators, sbin, ext_id, SIEVE_COMPARATOR_CUSTOM, dummy); 
-		
-		return;
-	} 
+	(void) sieve_extension_emit_obj
+		(sbin, &cmp_default_reg, cmp, comparators, ext_id);
+}
+
+static const struct sieve_extension_obj_registry *
+	sieve_comparator_registry_get
+(struct sieve_binary *sbin, unsigned int ext_index)
+{
+	int ext_id = -1; 
+	const struct sieve_comparator_extension *ext;
 	
-	(void) sieve_binary_emit_byte(sbin, cmp->code);
+	if ( sieve_binary_extension_get_by_index(sbin, ext_index, &ext_id) == NULL )
+		return NULL;
+
+	if ( (ext=sieve_comparator_extension_get(sbin, ext_id)) == NULL ) 
+		return NULL;
+		
+	return &(ext->comparators);
 }
 
 const struct sieve_comparator *sieve_opr_comparator_read
   (struct sieve_binary *sbin, sieve_size_t *address)
 {
-	unsigned int cmp_code;
 	const struct sieve_operand *operand = sieve_operand_read(sbin, address);
 	
 	if ( operand == NULL || operand->class != &comparator_class ) 
 		return NULL;
 	
-	if ( sieve_binary_read_byte(sbin, address, &cmp_code) ) {
-		if ( cmp_code < SIEVE_COMPARATOR_CUSTOM ) {
-			if ( cmp_code < sieve_core_comparators_count )
-				return sieve_core_comparators[cmp_code];
-			else
-				return NULL;
-		} else {
-			const struct sieve_comparator_extension *cmp_ext;
-			const struct sieve_comparator *cmp;
-			int ext_id = -1; 
-			
-			if ( sieve_binary_extension_get_by_index
-				(sbin, cmp_code - SIEVE_COMPARATOR_CUSTOM, &ext_id) == NULL )
-				return NULL;
-	
-			if ( (cmp_ext=sieve_comparator_extension_get(sbin, ext_id)) == NULL )
-				return NULL;
-	
-			sieve_extension_read_object 
-				(cmp_ext, struct sieve_comparator, comparators, sbin, address, cmp)
-
-			return cmp;
-		}
-	}		
-		
-	return NULL;
+	return sieve_extension_read_obj
+		(struct sieve_comparator, sbin, address, &cmp_default_reg, 
+			sieve_comparator_registry_get);
 }
 
 bool sieve_opr_comparator_dump
@@ -406,13 +403,6 @@ const struct sieve_comparator i_ascii_casemap_comparator = {
 	cmp_i_octet_char_skip
 };
 
-const struct sieve_comparator *sieve_core_comparators[] = {
-	&i_octet_comparator, &i_ascii_casemap_comparator
-};
-
-const unsigned int sieve_core_comparators_count =
-	N_ELEMENTS(sieve_core_comparators);
-
 static int cmp_i_octet_compare(
 	const struct sieve_comparator *cmp ATTR_UNUSED,
 	const char *val1, size_t val1_size, const char *val2, size_t val2_size)
diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h
index 56bb5db5f386703cdfd678fde846665467f405ae..b082870033fa8bd76da8f3cea6af1e1664dcf8b4 100644
--- a/src/lib-sieve/sieve-comparators.h
+++ b/src/lib-sieve/sieve-comparators.h
@@ -2,7 +2,7 @@
 #define __SIEVE_COMPARATORS_H
 
 #include "sieve-common.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 
 enum sieve_comparator_code {
 	SIEVE_COMPARATOR_I_OCTET,
diff --git a/src/lib-sieve/sieve-extensions-private.h b/src/lib-sieve/sieve-extensions-private.h
index 1fad34e71ae0239b8b659bb654098f6cce66549e..16c694c727309c18e76dd12d543936ef057fa368 100644
--- a/src/lib-sieve/sieve-extensions-private.h
+++ b/src/lib-sieve/sieve-extensions-private.h
@@ -9,37 +9,31 @@
  * Per-extension object declaration
  */
 
-struct sieve_extension_obj_registry {
-	const void *objects;
-	unsigned int count;
-};
-
-#define SIEVE_EXT_DEFINE_NO_OBJECTS \
-	{ NULL, 0 }
-#define SIEVE_EXT_DEFINE_OBJECT(OBJ) \
-	{ &OBJ, 1 }
-#define SIEVE_EXT_DEFINE_OBJECTS(OBJS) \
-	{ OBJS, N_ELEMENTS(OBJS) }
-
-#define SIEVE_EXT_GET_OBJECTS_COUNT(ext, field) \
-	ext->field->count;
-
-static inline const void *_sieve_extension_read_object
-(const struct sieve_extension_obj_registry *reg, struct sieve_binary *sbin, 
-	sieve_size_t *address)
+static inline const void *_sieve_extension_get_object
+(const struct sieve_extension_obj_registry *reg, unsigned int code)
 { 		
-	unsigned int code; 	
-		
 	if ( reg->count == 1 ) 
 		return reg->objects; 
 	
-	if ( sieve_binary_read_byte(sbin, address, &code) && code < reg->count ) {
+	if ( code < reg->count ) {
 		const void * const *objects = (const void * const *) reg->objects;
 		return objects[code]; 
 	}
 	return NULL;
 }
 
+static inline const void *_sieve_extension_read_object
+(const struct sieve_extension_obj_registry *reg, struct sieve_binary *sbin, 
+	sieve_size_t *address)
+{ 		
+	unsigned int code = 0; 	
+		
+	if ( reg->count > 1) 
+		sieve_binary_read_byte(sbin, address, &code); 
+	
+	return _sieve_extension_get_object(reg, code);
+}
+
 #define sieve_extension_read_object\
 (ext, type, field, sbin, address, result) \
 { \
@@ -71,35 +65,57 @@ static inline sieve_size_t _sieve_extension_emit_object
  * Extension object
  */
 
-struct sieve_extension {
-	const char *name;
+static inline sieve_size_t _sieve_extension_emit_obj
+(struct sieve_binary *sbin, 
+	const struct sieve_extension_obj_registry *defreg,
+	const struct sieve_extension_obj_registry *reg,
+	unsigned int obj_code, int ext_id) 
+{ 
+	if ( ext_id >= 0 ) {
+		sieve_size_t address; 
+		unsigned char code = defreg->count +
+			sieve_binary_extension_get_index(sbin, ext_id);
+
+		address = sieve_binary_emit_byte(sbin, code);
+		
+		if ( reg->count > 1 ) 
+			(void) sieve_binary_emit_byte(sbin, obj_code);
 	
-	bool (*load)(int ext_id);
-
-	bool (*validator_load)(struct sieve_validator *validator);	
-	bool (*generator_load)(struct sieve_generator *generator);
-	bool (*binary_load)(struct sieve_binary *binary);
-	bool (*interpreter_load)(struct sieve_interpreter *interpreter);
-
-	struct sieve_extension_obj_registry opcodes;
-	struct sieve_extension_obj_registry operands;
-};
-
-/*  
- * Opcodes and operands
- */
- 
-#define SIEVE_EXT_DEFINE_NO_OPERATIONS SIEVE_EXT_DEFINE_NO_OBJECTS
-#define SIEVE_EXT_DEFINE_OPERATION(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
-#define SIEVE_EXT_DEFINE_OPERATIONS(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
-
-#define SIEVE_EXT_DEFINE_NO_OPERANDS SIEVE_EXT_DEFINE_NO_OBJECTS
-
-/* 
- * Pre-loaded extensions
- */
-
-extern const struct sieve_extension *sieve_preloaded_extensions[];
-extern const unsigned int sieve_preloaded_extensions_count;
+		return address;
+	} 
+	
+	return sieve_binary_emit_byte(sbin, obj_code);
+}
+#define sieve_extension_emit_obj(sbin, defreg, obj, reg, ext_id)\
+	_sieve_extension_emit_obj\
+		(sbin, defreg, &obj->extension->reg, obj->code, ext_id)
+
+static inline const void *_sieve_extension_read_obj
+(struct sieve_binary *sbin, sieve_size_t *address, 
+	const struct sieve_extension_obj_registry *defreg, 
+	const struct sieve_extension_obj_registry *(*get_reg_func)
+		(struct sieve_binary *sbin, unsigned int index)) 
+{ 
+	unsigned int obj_code; 
+
+	if ( sieve_binary_read_byte(sbin, address, &obj_code) ) { 
+		if ( obj_code < defreg->count ) { 
+			return _sieve_extension_get_object(defreg, obj_code); 
+		} else { 
+			const struct sieve_extension_obj_registry *reg;
+		
+			if ( (reg=get_reg_func(sbin, obj_code - defreg->count)) == NULL || 
+				reg->count == 0 ) 
+				return NULL; 
+				
+			return _sieve_extension_read_object(reg, sbin, address);
+		}
+	}
+	
+	return NULL;
+}
+#define sieve_extension_read_obj(type, sbin, address, defreg, get_reg_func) \
+	((const type *) _sieve_extension_read_obj \
+		(sbin, address, defreg, get_reg_func))
 
 #endif /* __SIEVE_EXTENSIONS_PRIVATE_H */
diff --git a/src/lib-sieve/sieve-extensions.h b/src/lib-sieve/sieve-extensions.h
index e1327af3ebedca78a5626d6eb6a3776b40df4ade..1db54d10f4b2ebf097ee7e5d15c53954caba3964 100644
--- a/src/lib-sieve/sieve-extensions.h
+++ b/src/lib-sieve/sieve-extensions.h
@@ -4,7 +4,52 @@
 #include "lib.h"
 #include "sieve-common.h"
 
-struct sieve_extension;
+/* Per-extension object registry */
+
+struct sieve_extension_obj_registry {
+	const void *objects;
+	unsigned int count;
+};
+
+/* Extension object */
+
+struct sieve_extension {
+	const char *name;
+	
+	bool (*load)(int ext_id);
+
+	bool (*validator_load)(struct sieve_validator *validator);	
+	bool (*generator_load)(struct sieve_generator *generator);
+	bool (*binary_load)(struct sieve_binary *binary);
+	bool (*interpreter_load)(struct sieve_interpreter *interpreter);
+
+	struct sieve_extension_obj_registry operations;
+	struct sieve_extension_obj_registry operands;
+};
+
+#define SIEVE_EXT_DEFINE_NO_OBJECTS \
+	{ NULL, 0 }
+#define SIEVE_EXT_DEFINE_OBJECT(OBJ) \
+	{ &OBJ, 1 }
+#define SIEVE_EXT_DEFINE_OBJECTS(OBJS) \
+	{ OBJS, N_ELEMENTS(OBJS) }
+
+#define SIEVE_EXT_GET_OBJECTS_COUNT(ext, field) \
+	ext->field->count;
+
+/* Opcodes and operands */
+ 
+#define SIEVE_EXT_DEFINE_NO_OPERATIONS SIEVE_EXT_DEFINE_NO_OBJECTS
+#define SIEVE_EXT_DEFINE_OPERATION(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_OPERATIONS(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
+#define SIEVE_EXT_DEFINE_NO_OPERANDS SIEVE_EXT_DEFINE_NO_OBJECTS
+
+/* Pre-loaded extensions */
+
+extern const struct sieve_extension *sieve_preloaded_extensions[];
+extern const unsigned int sieve_preloaded_extensions_count;
+
 
 const struct sieve_extension *sieve_extension_acquire(const char *extension);
 
diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c
index 447ff2d1e26df946378a6b621d1a42d851b606ff..88e026a482a702a0d7a819d6aea3bc0e065da354 100644
--- a/src/lib-sieve/sieve-generator.c
+++ b/src/lib-sieve/sieve-generator.c
@@ -4,7 +4,7 @@
 #include "mempool.h"
 
 #include "sieve-common.h"
-#include "sieve-extensions-private.h"
+#include "sieve-extensions.h"
 #include "sieve-commands-private.h"
 #include "sieve-code.h"
 #include "sieve-binary.h"
diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c
index 732bce7b7e5a822f618e8ba43e35bfe5c391b7d0..edd79cfbafdfb61e7425029b5ca759ef4e51d88c 100644
--- a/src/lib-sieve/sieve-match-types.c
+++ b/src/lib-sieve/sieve-match-types.c
@@ -21,9 +21,23 @@
 #include <string.h>
 
 /* 
- * Predeclarations 
+ * Default match types
+ */ 
+
+const struct sieve_match_type *sieve_core_match_types[] = {
+	&is_match_type, &contains_match_type, &matches_match_type
+};
+
+const unsigned int sieve_core_match_types_count = 
+	N_ELEMENTS(sieve_core_match_types);
+
+static struct sieve_extension_obj_registry mtch_default_reg =
+	SIEVE_EXT_DEFINE_MATCH_TYPES(sieve_core_match_types);
+
+/* 
+ * Forward declarations 
  */
- 
+  
 static void opr_match_type_emit
 	(struct sieve_binary *sbin, const struct sieve_match_type *mtch, int ext_id);
 
@@ -274,61 +288,46 @@ bool sieve_match_type_validate
 	return TRUE;	
 }
 
-/* Code generation */
+/* 
+ * Code generation 
+ */
 
 static void opr_match_type_emit
 	(struct sieve_binary *sbin, const struct sieve_match_type *mtch, int ext_id)
 { 
 	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_MATCH_TYPE);	
+	
+	(void) sieve_extension_emit_obj
+		(sbin, &mtch_default_reg, mtch, match_types, ext_id);
+}
 
-	if ( ext_id >= 0 ) {
-		sieve_size_t dummy;
-		
-		sieve_extension_emit_object
-			(mtch, match_types, sbin, ext_id, SIEVE_MATCH_TYPE_CUSTOM, dummy); 
-		
-		return;
-	} 
+static const struct sieve_extension_obj_registry *
+	sieve_match_type_registry_get
+(struct sieve_binary *sbin, unsigned int ext_index)
+{
+	int ext_id = -1; 
+	const struct sieve_match_type_extension *ext;
 	
-	(void) sieve_binary_emit_byte(sbin, mtch->code);
+	if ( sieve_binary_extension_get_by_index(sbin, ext_index, &ext_id) == NULL )
+		return NULL;
 
+	if ( (ext=sieve_match_type_extension_get(sbin, ext_id)) == NULL ) 
+		return NULL;
+		
+	return &(ext->match_types);
 }
 
 const struct sieve_match_type *sieve_opr_match_type_read
   (struct sieve_binary *sbin, sieve_size_t *address)
 {
-	unsigned int mtch_code;
 	const struct sieve_operand *operand = sieve_operand_read(sbin, address);
 	
 	if ( operand == NULL || operand->class != &match_type_class ) 
 		return NULL;
-	
-	if ( sieve_binary_read_byte(sbin, address, &mtch_code) ) {
-		if ( mtch_code < SIEVE_MATCH_TYPE_CUSTOM ) {
-			if ( mtch_code < sieve_core_match_types_count )
-				return sieve_core_match_types[mtch_code];
-			else
-				return NULL;
-		} else {
-			const struct sieve_match_type_extension *mtch_ext;
-			const struct sieve_match_type *mtch;
-			int ext_id = -1; 
-			
-			if ( sieve_binary_extension_get_by_index
-				(sbin, mtch_code - SIEVE_MATCH_TYPE_CUSTOM, &ext_id) == NULL )
-				return NULL;
-	
-			if ( (mtch_ext=sieve_match_type_extension_get(sbin, ext_id)) == NULL )
-				return NULL;
-	
-			sieve_extension_read_object 
-				(mtch_ext, struct sieve_match_type, match_types, sbin, address, mtch)
 
-			return mtch;
-		}
-	}		
-		
-	return NULL; 
+	return sieve_extension_read_obj
+		(struct sieve_match_type, sbin, address, &mtch_default_reg, 
+			sieve_match_type_registry_get);
 }
 
 bool sieve_opr_match_type_dump
@@ -706,10 +705,3 @@ const struct sieve_match_type matches_match_type = {
 	mtch_matches_match,
 	NULL
 };
-
-const struct sieve_match_type *sieve_core_match_types[] = {
-	&is_match_type, &contains_match_type, &matches_match_type
-};
-
-const unsigned int sieve_core_match_types_count = 
-	N_ELEMENTS(sieve_core_match_types);
diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c
index a1c679e80bfbe945897d3b0aaf1ee9bce664212a..87a9107d9f36024cce2c8cb4acb392af0cd37434 100644
--- a/src/lib-sieve/sieve-validator.c
+++ b/src/lib-sieve/sieve-validator.c
@@ -4,12 +4,12 @@
 #include "mempool.h"
 #include "hash.h"
 
+#include "sieve-extensions.h"
 #include "sieve-script.h"
 #include "sieve-ast.h"
 #include "sieve-commands.h"
 #include "sieve-commands-private.h"
 #include "sieve-validator.h"
-#include "sieve-extensions-private.h"
 
 #include "sieve-comparators.h"
 #include "sieve-address-parts.h"