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 6d02802985852ace3d09426f895436cf1898c4f4..650330e47a3d963eb1979a4a719bdfb358c59a85 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
@@ -59,7 +59,6 @@ extern const struct sieve_comparator_extension i_ascii_numeric_comparator_ext;
 
 const struct sieve_comparator i_ascii_numeric_comparator = { 
 	"i;ascii-numeric",
-	SIEVE_COMPARATOR_CUSTOM,
 	SIEVE_COMPARATOR_FLAG_ORDERING | SIEVE_COMPARATOR_FLAG_EQUALITY,
 	&i_ascii_numeric_comparator_ext,
 	0,
@@ -70,8 +69,7 @@ const struct sieve_comparator i_ascii_numeric_comparator = {
 
 const struct sieve_comparator_extension i_ascii_numeric_comparator_ext = { 
 	&comparator_i_ascii_numeric_extension,
-	&i_ascii_numeric_comparator, 
-	NULL
+	SIEVE_EXT_DEFINE_COMPARATOR(i_ascii_numeric_comparator)
 };
 
 /* Load extension into validator */
diff --git a/src/lib-sieve/plugins/regex/ext-regex.c b/src/lib-sieve/plugins/regex/ext-regex.c
index 6fcb32a629c2ac789ef2dbdbeffbd28169a20f69..12b31e37330cb40e24b5fb7445d234abd4e2f3fc 100644
--- a/src/lib-sieve/plugins/regex/ext-regex.c
+++ b/src/lib-sieve/plugins/regex/ext-regex.c
@@ -78,9 +78,7 @@ bool mtch_regex_validate_context
     struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg);
 
 const struct sieve_match_type regex_match_type = {
-	"regex",
-	SIEVE_MATCH_TYPE_CUSTOM,
-	TRUE,
+	"regex", TRUE,
 	&regex_match_extension,
 	0,
 	NULL,
@@ -92,8 +90,7 @@ const struct sieve_match_type regex_match_type = {
 
 const struct sieve_match_type_extension regex_match_extension = { 
 	&regex_extension,
-	&regex_match_type, 
-	NULL
+	SIEVE_EXT_DEFINE_MATCH_TYPE(regex_match_type)
 };
 
 /* Validation */
diff --git a/src/lib-sieve/plugins/relational/ext-relational.c b/src/lib-sieve/plugins/relational/ext-relational.c
index 12426b05f1e86114a828dacbafa934e8b38b0229..0d03d7ae44eb7405e7a9c24f263092d6a7bdb172 100644
--- a/src/lib-sieve/plugins/relational/ext-relational.c
+++ b/src/lib-sieve/plugins/relational/ext-relational.c
@@ -85,7 +85,7 @@ static bool ext_relational_load(int ext_id)
 
 /* Validation */
 
-static const struct sieve_match_type rel_match_types[];
+static const struct sieve_match_type *rel_match_types[];
 
 static bool mtch_relational_validate
 	(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
@@ -177,8 +177,8 @@ static bool mtch_relational_validate
 	ctx->ctx_data = (void *) rel_match;
 
 	/* Override the actual match type with a parameter-specific one */
-	ctx->match_type = &rel_match_types
-		[REL_MATCH_INDEX(ctx->match_type->ext_code, rel_match)];
+	ctx->match_type = rel_match_types
+		[REL_MATCH_INDEX(ctx->match_type->code, rel_match)];
 
 	return TRUE;
 }
@@ -190,7 +190,7 @@ static bool mtch_value_match
 	const char *key, size_t key_size, int key_index ATTR_UNUSED)
 {
 	const struct sieve_match_type *mtch = mctx->match_type;
-	unsigned int rel_match = REL_MATCH(mtch->ext_code);	
+	unsigned int rel_match = REL_MATCH(mtch->code);	
 	int cmp_result = mctx->comparator->
 		compare(mctx->comparator, val, val_size, key, key_size);
 
@@ -271,9 +271,7 @@ extern const struct sieve_match_type_extension relational_match_extension;
 /* Parameter-independent match type objects, only used during validation */
 
 const struct sieve_match_type value_match_type = {
-	"value",
-	SIEVE_MATCH_TYPE_CUSTOM,
-	TRUE,
+	"value", TRUE,
 	&relational_match_extension,
 	RELATIONAL_VALUE,
 	mtch_relational_validate,
@@ -281,9 +279,7 @@ const struct sieve_match_type value_match_type = {
 };
 
 const struct sieve_match_type count_match_type = {
-	"count",
-	SIEVE_MATCH_TYPE_CUSTOM,
-	FALSE,
+	"count", FALSE,
 	&relational_match_extension,
 	RELATIONAL_COUNT,
 	mtch_relational_validate,
@@ -296,58 +292,51 @@ const struct sieve_match_type count_match_type = {
  * not such a great idea. This needs more thought
  */
 
-#define VALUE_MATCH_TYPE(name, rel_match, func) {         \
-		"value-" name,                                    \
-		SIEVE_MATCH_TYPE_CUSTOM,                          \
-		TRUE,                                             \
-		&relational_match_extension,                      \
-		REL_MATCH_INDEX(RELATIONAL_VALUE, rel_match),     \
-		NULL, NULL, NULL,                                 \
-		mtch_value_match,                                 \
-		NULL                                              \
-	}
+#define VALUE_MATCH_TYPE(name, rel_match)                   \
+const struct sieve_match_type rel_match_value_ ## name = {  \
+	"value-" #name, TRUE,                                   \
+	&relational_match_extension,                            \
+	REL_MATCH_INDEX(RELATIONAL_VALUE, rel_match),           \
+	NULL, NULL, NULL,                                       \
+	mtch_value_match,                                       \
+	NULL                                                    \
+}
 
-#define COUNT_MATCH_TYPE(name, rel_match, func) {         \
-		"count-" name,                                    \
-		SIEVE_MATCH_TYPE_CUSTOM,                          \
-        FALSE,                                            \
-		&relational_match_extension,                      \
-		REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match),     \
-		NULL, NULL,                                       \
-		mtch_count_match_init,                            \
-		mtch_count_match,                                 \
-		mtch_count_match_deinit                           \
-	}
+#define COUNT_MATCH_TYPE(name, rel_match)                   \
+const struct sieve_match_type rel_match_count_ ## name = {  \
+	"count-" #name, FALSE,                                  \
+	&relational_match_extension,                            \
+	REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match),           \
+	NULL, NULL,                                             \
+	mtch_count_match_init,                                  \
+	mtch_count_match,                                       \
+	mtch_count_match_deinit                                 \
+}
 	
-static const struct sieve_match_type rel_match_types[] = { 
-	VALUE_MATCH_TYPE("gt", REL_MATCH_GREATER, NULL), 
-	VALUE_MATCH_TYPE("ge", REL_MATCH_GREATER_EQUAL, NULL), 
-	VALUE_MATCH_TYPE("lt", REL_MATCH_LESS, NULL), 
-	VALUE_MATCH_TYPE("le", REL_MATCH_LESS_EQUAL, NULL), 
-	VALUE_MATCH_TYPE("eq", REL_MATCH_EQUAL, NULL), 
-	VALUE_MATCH_TYPE("ne", REL_MATCH_NOT_EQUAL, NULL),
-
-	COUNT_MATCH_TYPE("gt", REL_MATCH_GREATER, NULL), 
-	COUNT_MATCH_TYPE("ge", REL_MATCH_GREATER_EQUAL, NULL), 
-	COUNT_MATCH_TYPE("lt", REL_MATCH_LESS, NULL), 
-	COUNT_MATCH_TYPE("le", REL_MATCH_LESS_EQUAL, NULL), 
-	COUNT_MATCH_TYPE("eq", REL_MATCH_EQUAL, NULL), 
-	COUNT_MATCH_TYPE("ne", REL_MATCH_NOT_EQUAL, NULL)
+VALUE_MATCH_TYPE(gt, REL_MATCH_GREATER);
+VALUE_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL); 
+VALUE_MATCH_TYPE(lt, REL_MATCH_LESS);
+VALUE_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL); 
+VALUE_MATCH_TYPE(eq, REL_MATCH_EQUAL);
+VALUE_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);
+
+COUNT_MATCH_TYPE(gt, REL_MATCH_GREATER);
+COUNT_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL);
+COUNT_MATCH_TYPE(lt, REL_MATCH_LESS);
+COUNT_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL);
+COUNT_MATCH_TYPE(eq, REL_MATCH_EQUAL);
+COUNT_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);
+
+static const struct sieve_match_type *rel_match_types[] = { 
+	&rel_match_value_gt, &rel_match_value_ge, &rel_match_value_lt, 
+	&rel_match_value_le, &rel_match_value_eq, &rel_match_value_ne,
+	&rel_match_count_gt, &rel_match_count_ge, &rel_match_count_lt, 
+	&rel_match_count_le, &rel_match_count_eq, &rel_match_count_ne 
 };
  
-static const struct sieve_match_type *ext_relational_get_match 
-	(unsigned int code)
-{
-	if ( code < N_ELEMENTS(rel_match_types) ) 
-		return &rel_match_types[code];
-			
-	return NULL;
-}
-
 const struct sieve_match_type_extension relational_match_extension = { 
 	&relational_extension,
-	NULL, 
-	ext_relational_get_match
+	SIEVE_EXT_DEFINE_MATCH_TYPES(rel_match_types) 
 };
 
 /* Load extension into validator */
diff --git a/src/lib-sieve/plugins/subaddress/ext-subaddress.c b/src/lib-sieve/plugins/subaddress/ext-subaddress.c
index 180f0558acba440781e0f14990de7f360e9baaf0..2f24a38148bca46debefbd558907d8e739785fe0 100644
--- a/src/lib-sieve/plugins/subaddress/ext-subaddress.c
+++ b/src/lib-sieve/plugins/subaddress/ext-subaddress.c
@@ -88,7 +88,6 @@ extern const struct sieve_address_part_extension subaddress_addrp_extension;
 
 const struct sieve_address_part user_address_part = {
 	"user",
-	SIEVE_ADDRESS_PART_CUSTOM,
 	&subaddress_addrp_extension,
 	SUBADDRESS_USER,
 	subaddress_user_extract_from
@@ -96,31 +95,18 @@ const struct sieve_address_part user_address_part = {
 
 const struct sieve_address_part detail_address_part = {
 	"detail",
-	SIEVE_ADDRESS_PART_CUSTOM,
 	&subaddress_addrp_extension,
 	SUBADDRESS_DETAIL,
 	subaddress_detail_extract_from
 };
 
-static const struct sieve_address_part *ext_subaddress_get_part 
-	(unsigned int code)
-{
-	switch ( code ) {
-	case SUBADDRESS_USER:
-		return &user_address_part;
-	case SUBADDRESS_DETAIL:
-		return &detail_address_part;
-	default:
-		break;
-	}
-	
-	return NULL;
-}
+const struct sieve_address_part *ext_subaddress_parts[] = {
+	&user_address_part, &detail_address_part
+};
 
 const struct sieve_address_part_extension subaddress_addrp_extension = { 
 	&subaddress_extension,
-	NULL, 
-	ext_subaddress_get_part
+	SIEVE_EXT_DEFINE_ADDRESS_PARTS(ext_subaddress_parts)
 };
 
 /* Load extension into validator */
diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c
index 0eeced2c3dcbbe279f804dc6d650229b9b9b2f56..c03fa2b536e12cad0fc718a66d6ee2a631b62024 100644
--- a/src/lib-sieve/sieve-address-parts.c
+++ b/src/lib-sieve/sieve-address-parts.c
@@ -27,8 +27,6 @@
  */
  
 static void opr_address_part_emit
-	(struct sieve_binary *sbin, const struct sieve_address_part *addrp);
-static void opr_address_part_emit_ext
 	(struct sieve_binary *sbin, const struct sieve_address_part *addrp, 
 		int ext_id);
 
@@ -236,22 +234,20 @@ static bool tag_address_part_validate
 /* Code generation */
 
 static void opr_address_part_emit
-(struct sieve_binary *sbin, const struct sieve_address_part *addrp)
-{ 
-	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_ADDRESS_PART);
-	(void) sieve_binary_emit_byte(sbin, addrp->code);
-}
-
-static void opr_address_part_emit_ext
 (struct sieve_binary *sbin, const struct sieve_address_part *addrp, int ext_id)
 { 
-	unsigned char addrp_code = SIEVE_ADDRESS_PART_CUSTOM + 
-		sieve_binary_extension_get_index(sbin, ext_id);
-	
 	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_ADDRESS_PART);	
-	(void) sieve_binary_emit_byte(sbin, addrp_code);
-	if ( addrp->extension->address_part == NULL )
-		(void) sieve_binary_emit_byte(sbin, addrp->ext_code);
+
+	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_binary_emit_byte(sbin, addrp->code);
 }
 
 /* FIXME: Duplicated */
@@ -271,26 +267,22 @@ const struct sieve_address_part *sieve_opr_address_part_read
 			else
 				return NULL;
 		} else {
-			int ext_id = -1;
-			const struct sieve_address_part_extension *ap_ext;
-
-			if ( sieve_binary_extension_get_by_index(sbin,
-				addrp_code - SIEVE_ADDRESS_PART_CUSTOM, &ext_id) == NULL )
-				return NULL; 
+			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)
 
-			ap_ext = sieve_address_part_extension_get(sbin, ext_id); 
- 
-			if ( ap_ext != NULL ) {  	
-				unsigned int code;
-				if ( ap_ext->address_part != NULL )
-					return ap_ext->address_part;
-		  	
-				if ( sieve_binary_read_byte(sbin, address, &code) &&
-					ap_ext->get_part != NULL )
-				return ap_ext->get_part(code);
-			} else {
-				i_info("Unknown address-part modifier %d.", addrp_code); 
-			}
+			return addrp;
 		}
 	}		
 		
@@ -324,11 +316,11 @@ static bool tag_address_part_generate
 	
 	if ( addrp->extension == NULL ) {
 		if ( addrp->code < SIEVE_ADDRESS_PART_CUSTOM )
-			opr_address_part_emit(sbin, addrp);
+			opr_address_part_emit(sbin, addrp, -1);
 		else
 			return FALSE;
 	} else {
-		opr_address_part_emit_ext(sbin, addrp, adpctx->ext_id);
+		opr_address_part_emit(sbin, addrp, adpctx->ext_id);
 	} 
 		
 	return TRUE;
@@ -477,25 +469,22 @@ static const char *addrp_localpart_extract_from
 
 const struct sieve_address_part all_address_part = {
 	"all",
-	SIEVE_ADDRESS_PART_ALL,
 	NULL,
-	0,
+	SIEVE_ADDRESS_PART_ALL,
 	addrp_all_extract_from
 };
 
 const struct sieve_address_part local_address_part = {
 	"localpart",
-	SIEVE_ADDRESS_PART_LOCAL,
 	NULL,
-	0,
+	SIEVE_ADDRESS_PART_LOCAL,
 	addrp_localpart_extract_from
 };
 
 const struct sieve_address_part domain_address_part = {
 	"domain",
-	SIEVE_ADDRESS_PART_DOMAIN,
 	NULL,
-	0,
+	SIEVE_ADDRESS_PART_DOMAIN,
 	addrp_domain_extract_from
 };
 
diff --git a/src/lib-sieve/sieve-address-parts.h b/src/lib-sieve/sieve-address-parts.h
index 12368faf324439242f8563958e4b67613f9a4fd7..ff0365107d159b2e0e0b6cdbab397c690fcc304f 100644
--- a/src/lib-sieve/sieve-address-parts.h
+++ b/src/lib-sieve/sieve-address-parts.h
@@ -16,11 +16,9 @@ struct sieve_address_part_extension;
 
 struct sieve_address_part {
 	const char *identifier;
-	
-	enum sieve_address_part_code code;
-	
+		
 	const struct sieve_address_part_extension *extension;
-	unsigned int ext_code;
+	unsigned int code;
 
 	const char *(*extract_from)(const struct message_address *address);
 };
@@ -28,14 +26,12 @@ struct sieve_address_part {
 struct sieve_address_part_extension {
 	const struct sieve_extension *extension;
 
-	/* Either a single addr-part in this extension ... */
-	const struct sieve_address_part *address_part;
-	
-	/* ... or multiple: then the extension must handle emit/read */
-	const struct sieve_address_part *(*get_part)
-		(unsigned int code);
+	struct sieve_extension_obj_registry address_parts;
 };
 
+#define SIEVE_EXT_DEFINE_ADDRESS_PART(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_ADDRESS_PARTS(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
 struct sieve_address_part_context {
 	struct sieve_command_context *command_ctx;
 	const struct sieve_address_part *address_part;
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index b298ed1d8d6e44eb885be17503108c1ad2cb571e..e79e8acd9ea3fd9299863e9399250a88796f60c4 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -588,8 +588,16 @@ static struct sieve_coded_stringlist *opr_stringlist_read
 inline sieve_size_t sieve_operation_emit_code
 	(struct sieve_binary *sbin, const struct sieve_operation *op, int ext_id)
 {	
-	return sieve_extension_emit_operation
-		(op, sbin, ext_id, SIEVE_OPERATION_CUSTOM);
+	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
@@ -604,8 +612,18 @@ const struct sieve_operation *sieve_operation_read
 			else
 				return NULL;
 		} else {
-			return sieve_extension_read_operation
-				(opcode - SIEVE_OPERATION_CUSTOM, sbin, address);
+			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;
 		}
 	}		
 	
diff --git a/src/lib-sieve/sieve-comparators.c b/src/lib-sieve/sieve-comparators.c
index e1d33e37ebe54893a57e4e813e2d384b08f0deee..620d8c2fce55f503bfc950b39b0bb8cba6619602 100644
--- a/src/lib-sieve/sieve-comparators.c
+++ b/src/lib-sieve/sieve-comparators.c
@@ -26,8 +26,6 @@ extern const struct sieve_comparator *sieve_core_comparators[];
 extern const unsigned int sieve_core_comparators_count;
 
 static void opr_comparator_emit
-	(struct sieve_binary *sbin, const struct sieve_comparator *cmp);
-static void opr_comparator_emit_ext
 	(struct sieve_binary *sbin, const struct sieve_comparator *cmp, int ext_id);
 
 static int cmp_i_octet_compare
@@ -292,22 +290,20 @@ inline const struct sieve_comparator *sieve_comparator_tag_get
 /* Code generation */
 
 static void opr_comparator_emit
-	(struct sieve_binary *sbin, const struct sieve_comparator *cmp)
-{ 
-	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_COMPARATOR);
-	(void) sieve_binary_emit_byte(sbin, cmp->code);
-}
-
-static void opr_comparator_emit_ext
 	(struct sieve_binary *sbin, const struct sieve_comparator *cmp, int ext_id)
 { 
-	unsigned char cmp_code = SIEVE_COMPARATOR_CUSTOM + 
-		sieve_binary_extension_get_index(sbin, ext_id);
-	
 	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_COMPARATOR);	
-	(void) sieve_binary_emit_byte(sbin, cmp_code);
-	if ( cmp->extension->comparator == NULL ) 
-		(void) sieve_binary_emit_byte(sbin, cmp->ext_code);
+
+	if ( ext_id >= 0 ) {
+		sieve_size_t dummy;
+		
+		sieve_extension_emit_object
+			(cmp, comparators, sbin, ext_id, SIEVE_COMPARATOR_CUSTOM, dummy); 
+		
+		return;
+	} 
+	
+	(void) sieve_binary_emit_byte(sbin, cmp->code);
 }
 
 const struct sieve_comparator *sieve_opr_comparator_read
@@ -326,26 +322,21 @@ const struct sieve_comparator *sieve_opr_comparator_read
 			else
 				return NULL;
 		} else {
-			int ext_id = -1;
 			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)
 
-			if ( sieve_binary_extension_get_by_index(sbin,
-				cmp_code - SIEVE_COMPARATOR_CUSTOM, &ext_id) == NULL )
-				return NULL; 
-
-			cmp_ext = sieve_comparator_extension_get(sbin, ext_id); 
- 
-			if ( cmp_ext != NULL ) {  	
-				unsigned int code;
-				if ( cmp_ext->comparator != NULL )
-					return cmp_ext->comparator;
-		  	
-				if ( sieve_binary_read_byte(sbin, address, &code) &&
-					cmp_ext->get_comparator != NULL )
-					return cmp_ext->get_comparator(code);
-			} else {
-				i_info("Unknown comparator %d.", cmp_code); 
-			}
+			return cmp;
 		}
 	}		
 		
@@ -379,11 +370,11 @@ static bool tag_comparator_generate
 	
 	if ( cmp->extension == NULL ) {
 		if ( cmp->code < SIEVE_COMPARATOR_CUSTOM )
-			opr_comparator_emit(sbin, cmp);
+			opr_comparator_emit(sbin, cmp, -1);
 		else
 			return FALSE;
 	} else {
-		opr_comparator_emit_ext(sbin, cmp, cmpctx->ext_id);
+		opr_comparator_emit(sbin, cmp, cmpctx->ext_id);
 	} 
 		
 	return TRUE;
@@ -395,11 +386,10 @@ static bool tag_comparator_generate
 
 const struct sieve_comparator i_octet_comparator = {
 	"i;octet",
-	SIEVE_COMPARATOR_I_OCTET,
 	SIEVE_COMPARATOR_FLAG_ORDERING | SIEVE_COMPARATOR_FLAG_EQUALITY |
 		SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH | SIEVE_COMPARATOR_FLAG_PREFIX_MATCH,
 	NULL,
-	0,
+	SIEVE_COMPARATOR_I_OCTET,
 	cmp_i_octet_compare,
 	cmp_i_octet_char_match,
 	cmp_i_octet_char_skip	
@@ -407,11 +397,10 @@ const struct sieve_comparator i_octet_comparator = {
 
 const struct sieve_comparator i_ascii_casemap_comparator = {
 	"i;ascii-casemap",
-	SIEVE_COMPARATOR_I_ASCII_CASEMAP,
 	SIEVE_COMPARATOR_FLAG_ORDERING | SIEVE_COMPARATOR_FLAG_EQUALITY |
 		SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH | SIEVE_COMPARATOR_FLAG_PREFIX_MATCH,
 	NULL,
-	0,
+	SIEVE_COMPARATOR_I_ASCII_CASEMAP,
 	cmp_i_ascii_casemap_compare,
 	cmp_i_ascii_casemap_char_match,
 	cmp_i_octet_char_skip
diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h
index 61016ded7799299404edbd9865b7dae93fc63300..56bb5db5f386703cdfd678fde846665467f405ae 100644
--- a/src/lib-sieve/sieve-comparators.h
+++ b/src/lib-sieve/sieve-comparators.h
@@ -2,6 +2,7 @@
 #define __SIEVE_COMPARATORS_H
 
 #include "sieve-common.h"
+#include "sieve-extensions-private.h"
 
 enum sieve_comparator_code {
 	SIEVE_COMPARATOR_I_OCTET,
@@ -19,11 +20,10 @@ enum sieve_comparator_flags {
 struct sieve_comparator {
 	const char *identifier;
 	
-	enum sieve_comparator_code code;
 	unsigned int flags;
 	
 	const struct sieve_comparator_extension *extension;
-	unsigned int ext_code;
+	unsigned int code;
 	
 	/* Equality and ordering */
 
@@ -43,14 +43,12 @@ struct sieve_comparator {
 struct sieve_comparator_extension {
 	const struct sieve_extension *extension;
 	
-	/* Either a single comparator in this extension ... */
-	const struct sieve_comparator *comparator;
-	
-	/* ... or multiple: then the extension must handle emit/read */
-	const struct sieve_comparator *(*get_comparator)
-		(unsigned int code);
+	struct sieve_extension_obj_registry comparators;
 };
 
+#define SIEVE_EXT_DEFINE_COMPARATOR(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_COMPARATORS(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
 struct sieve_comparator_context {
 	struct sieve_command_context *command_ctx;
 	const struct sieve_comparator *comparator;
diff --git a/src/lib-sieve/sieve-extensions-private.h b/src/lib-sieve/sieve-extensions-private.h
index 1e18dc3240a28945537512abcd8fd57ac25716dd..1fad34e71ae0239b8b659bb654098f6cce66549e 100644
--- a/src/lib-sieve/sieve-extensions-private.h
+++ b/src/lib-sieve/sieve-extensions-private.h
@@ -2,7 +2,6 @@
 #define __SIEVE_EXTENSIONS_PRIVATE_H
 
 #include "sieve-common.h"
-#include "sieve-code.h"
 #include "sieve-extensions.h"
 #include "sieve-binary.h"
 
@@ -87,47 +86,13 @@ struct sieve_extension {
 };
 
 /*  
- * Opcode access
+ * 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)
 
-static inline const struct sieve_operation *sieve_extension_read_operation
-(unsigned int ext_code, struct sieve_binary *sbin, sieve_size_t *address) 
-{
-	struct sieve_operation *op;
-	int ext_id = -1; 
-	const struct sieve_extension *ext = sieve_binary_extension_get_by_index
-		(sbin, ext_code, &ext_id);
-	
-	sieve_extension_read_object 
-		(ext, struct sieve_operation, opcodes, sbin, address, op)
-
-	return op;
-}
-
-static inline sieve_size_t sieve_extension_emit_operation
-(const struct sieve_operation *op, struct sieve_binary *sbin, int ext_id, 
-	unsigned int offset)
-{
-	if ( ext_id >= 0 ) {
-		sieve_size_t address;
-		
-		sieve_extension_emit_object
-			(op, opcodes, sbin, ext_id, offset, address); 
-		
-		return address;
-	} 
-	
-	return sieve_binary_emit_byte(sbin, op->code);
-}
-
-/* 
- * Operand access 
- */
-
 #define SIEVE_EXT_DEFINE_NO_OPERANDS SIEVE_EXT_DEFINE_NO_OBJECTS
 
 /* 
diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c
index feece92ce49856baeb5237371d4f01f7d9b76533..732bce7b7e5a822f618e8ba43e35bfe5c391b7d0 100644
--- a/src/lib-sieve/sieve-match-types.c
+++ b/src/lib-sieve/sieve-match-types.c
@@ -25,8 +25,6 @@
  */
  
 static void opr_match_type_emit
-	(struct sieve_binary *sbin, const struct sieve_match_type *mtch);
-static void opr_match_type_emit_ext
 	(struct sieve_binary *sbin, const struct sieve_match_type *mtch, int ext_id);
 
 /* 
@@ -279,22 +277,21 @@ bool sieve_match_type_validate
 /* Code generation */
 
 static void opr_match_type_emit
-	(struct sieve_binary *sbin, const struct sieve_match_type *mtch)
-{ 
-	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_MATCH_TYPE);
-	(void) sieve_binary_emit_byte(sbin, mtch->code);
-}
-
-static void opr_match_type_emit_ext
 	(struct sieve_binary *sbin, const struct sieve_match_type *mtch, int ext_id)
 { 
-	unsigned char mtch_code = SIEVE_MATCH_TYPE_CUSTOM + 
-		sieve_binary_extension_get_index(sbin, ext_id);
-	
 	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_MATCH_TYPE);	
-	(void) sieve_binary_emit_byte(sbin, mtch_code);
-	if ( mtch->extension->match_type == NULL )
-		(void) sieve_binary_emit_byte(sbin, mtch->ext_code);
+
+	if ( ext_id >= 0 ) {
+		sieve_size_t dummy;
+		
+		sieve_extension_emit_object
+			(mtch, match_types, sbin, ext_id, SIEVE_MATCH_TYPE_CUSTOM, dummy); 
+		
+		return;
+	} 
+	
+	(void) sieve_binary_emit_byte(sbin, mtch->code);
+
 }
 
 const struct sieve_match_type *sieve_opr_match_type_read
@@ -313,26 +310,21 @@ const struct sieve_match_type *sieve_opr_match_type_read
 			else
 				return NULL;
 		} else {
-			int ext_id = -1;
 			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)
 
-			if ( sieve_binary_extension_get_by_index(sbin,
-				mtch_code - SIEVE_MATCH_TYPE_CUSTOM, &ext_id) == NULL )
-				return NULL; 
-
-			mtch_ext = sieve_match_type_extension_get(sbin, ext_id); 
- 
-			if ( mtch_ext != NULL ) {  	
-				unsigned int code;
-				if ( mtch_ext->match_type != NULL )
-					return mtch_ext->match_type;
-		  	
-				if ( sieve_binary_read_byte(sbin, address, &code) &&
-					mtch_ext->get_match != NULL )
-					return mtch_ext->get_match(code);
-			} else {
-				i_info("Unknown match-type modifier %d.", mtch_code); 
-			}
+			return mtch;
 		}
 	}		
 		
@@ -365,11 +357,11 @@ static bool tag_match_type_generate
 	
 	if ( mtctx->match_type->extension == NULL ) {
 		if ( mtctx->match_type->code < SIEVE_MATCH_TYPE_CUSTOM )
-			opr_match_type_emit(sbin, mtctx->match_type);
+			opr_match_type_emit(sbin, mtctx->match_type, -1);
 		else
 			return FALSE;
 	} else {
-		opr_match_type_emit_ext(sbin, mtctx->match_type, mtctx->ext_id);
+		opr_match_type_emit(sbin, mtctx->match_type, mtctx->ext_id);
 	} 
 			
 	return TRUE;
@@ -685,22 +677,18 @@ const struct sieve_argument match_type_tag = {
 };
  
 const struct sieve_match_type is_match_type = {
-	"is",
-	SIEVE_MATCH_TYPE_IS,
-	TRUE,
+	"is", TRUE,
 	NULL,
-	0,
+	SIEVE_MATCH_TYPE_IS,
 	NULL, NULL, NULL,
 	mtch_is_match,
 	NULL
 };
 
 const struct sieve_match_type contains_match_type = {
-	"contains",
-	SIEVE_MATCH_TYPE_CONTAINS,
-	TRUE,
+	"contains", TRUE,
 	NULL,
-	0,
+	SIEVE_MATCH_TYPE_CONTAINS,
 	NULL,
 	mtch_contains_validate_context, 
 	NULL,
@@ -709,11 +697,9 @@ const struct sieve_match_type contains_match_type = {
 };
 
 const struct sieve_match_type matches_match_type = {
-	"matches",
-	SIEVE_MATCH_TYPE_MATCHES,
-	TRUE,
+	"matches", TRUE,
 	NULL,
-	0,
+	SIEVE_MATCH_TYPE_MATCHES,
 	NULL,
 	mtch_contains_validate_context, 
 	NULL,
diff --git a/src/lib-sieve/sieve-match-types.h b/src/lib-sieve/sieve-match-types.h
index 810992897e137bdb316b3221cc8a22d6b0b4639e..fc275f1188f969517e51466d2f5fe99ea18e534f 100644
--- a/src/lib-sieve/sieve-match-types.h
+++ b/src/lib-sieve/sieve-match-types.h
@@ -24,8 +24,6 @@ struct sieve_match_type_context;
 
 struct sieve_match_type {
 	const char *identifier;
-	
-	enum sieve_match_type_code code;
 
 	/* Match function called for every key value or should it be called once
 	 * for every tested value? (TRUE = first alternative)
@@ -33,7 +31,7 @@ struct sieve_match_type {
 	bool is_iterative;
 	
 	const struct sieve_match_type_extension *extension;
-	unsigned int ext_code;
+	unsigned int code;
 	
 	bool (*validate)
 		(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
@@ -52,14 +50,12 @@ struct sieve_match_type {
 struct sieve_match_type_extension {
 	const struct sieve_extension *extension;
 
-	/* Either a single match-type in this extension ... */
-	const struct sieve_match_type *match_type;
-	
-	/* ... or multiple: then the extension must handle emit/read */
-	const struct sieve_match_type *(*get_match)
-		(unsigned int code);
+	struct sieve_extension_obj_registry match_types;
 };
 
+#define SIEVE_EXT_DEFINE_MATCH_TYPE(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_MATCH_TYPES(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
 struct sieve_match_type_context {
 	struct sieve_command_context *command_ctx;
 	const struct sieve_match_type *match_type;