diff --git a/TODO b/TODO
index 6feabb2320782b81bcfc0c1c0727d7bf7899bd75..c526512f9ec9b8f00c9a3f8991c85dab6337b504 100644
--- a/TODO
+++ b/TODO
@@ -8,8 +8,7 @@ Current:
 	- Limit the number of notifications generated (on a per-method basis)
 * Implement mailto method for the enotify extension:
 	- Check that URI headers are not duplicated if not allowed.
-* Implement means to configure which extensions to provide and incorporate
-  enotify extension into default compile.  
+* Incorporate enotify extension into default compile.  
 
 Next (in order of descending priority/precedence):
 
diff --git a/doc/man/sieve-test.1 b/doc/man/sieve-test.1
index 0d40e0f1523ad35ba5815a01223dcea4df5acb2a..4955f1d5ce6ed4132d6f17ea992191b5c6361f1c 100644
--- a/doc/man/sieve-test.1
+++ b/doc/man/sieve-test.1
@@ -1,12 +1,9 @@
-.TH "SIEVE-TEST" "1" "11 November 2008"
+.TH "SIEVE-TEST" "1" "21 December 2008"
 .SH NAME
 sieve-test \- Sieve script tester for the Dovecot secure IMAP server
 .SH SYNOPSIS
-.TP
-sieve-test [\fB-r\fR \fIrecipient-address\fR][\fB-s\fR \fIenvelope-sender\fR]
-[\fB-m\fR \fImailbox\fR][\fB-d\fR \fIdump-file\fR][\fB-c\fR][\fB-t\fR]
-\fIscript-file\fR \fImail-file\fR
-.br
+sieve-test [\fB-r\fR \fIrecipient-address\fR] [\fB-s\fR \fIenvelope-sender\fR] [\fB-m\fR \fImailbox\fR] [\fB-d\fR \fIdump-file\fR] [\fB-c\fR] [\fB-t\fR]
+[\fB-x\fR "\fIextension extension ...\fR"] \fIscript-file\fR \fImail-file\fR
 .SH DESCRIPTION
 .PP
 The \fBsieve-test\fP command is part of the Sieve implementation for the Dovecot secure 
@@ -50,6 +47,10 @@ Sieve compilation.
 .TP
 \fB-t\fP
 Enable simple trace debugging; prints all encountered byte code instructions on \fBstdout\fP.
+.TP
+\fB-x\fP "\fIextension extension ...\fP"
+Set the available extensions. The parameter is a space-separated list of the active extensions. 
+Unknown extensions are ignored, but a warning is produced.
 .SH AUTHOR
 .PP
 The Sieve implementation for Dovecot was written by Stephan Bosch <stephan@rename-it.nl>.
diff --git a/doc/man/sievec.1 b/doc/man/sievec.1
index c8c0feb77ae95314f35ef1cc60c3eae9f345f0f6..a34b3733da97f8312164ff696dd52f6f9e1c8772 100644
--- a/doc/man/sievec.1
+++ b/doc/man/sievec.1
@@ -1,9 +1,8 @@
-.TH "SIEVEC" "1" "11 November 2008"
+.TH "SIEVEC" "1" "21 December 2008"
 .SH NAME
 sievec \- Sieve script compiler for the Dovecot secure IMAP server
 .SH SYNOPSIS
-sievec [\fB-d\fR] \fIsieve-script\fR \fIoutfile\fR
-.br
+sievec [\fB-d\fR] [\fB-x\fR "\fIextension extension ...\fR"] \fIsieve-script\fR \fIoutfile\fR
 .SH DESCRIPTION
 .PP
 The \fBsievec\fP command is part of the Sieve implementation for the Dovecot secure 
@@ -41,9 +40,14 @@ compiler that yield corrupt binaries.
 \fB-d\fP 
 Don't write the binary to \fIoutfile\fP, but write a textual dump of the binary in 
 stead. In this context, the \fIoutfile\fP value '-' has special meaning: it causes the the textual 
-dump to be written to \fBstdout\fP. The output is identical to what the 
+dump to be written to \fBstdout\fP. The \fIoutfile\fP argument may also be omitted when this option 
+is active, which has the same effect as '-'. The output is identical to what the 
 .BR sieved (1) 
 command produces for a compiled Sieve binary file. 
+.TP
+\fB-x\fP "\fIextension extension ...\fP"
+Set the available extensions. The \fIextensions\fP parameter is a space-separated list of the 
+active extensions. Unknown extensions are ignored, but a warning is produced.
 .SH AUTHOR
 .PP
 The Sieve implementation for Dovecot was written by Stephan Bosch <stephan@rename-it.nl>.
diff --git a/src/lib-sieve-tool/sieve-tool.c b/src/lib-sieve-tool/sieve-tool.c
index 04d0ade3ec43a81bbe9d31464be05ec2560d6f3e..8215648e0409b87d8d2394c716c4966a8cbd4804 100644
--- a/src/lib-sieve-tool/sieve-tool.c
+++ b/src/lib-sieve-tool/sieve-tool.c
@@ -55,7 +55,7 @@ void sieve_tool_init(void)
 	lib_signals_ignore(SIGPIPE, TRUE);
 	lib_signals_ignore(SIGALRM, FALSE);
 
-	if ( !sieve_init("") ) 
+	if ( !sieve_init() ) 
 		i_fatal("failed to initialize sieve implementation\n");
 }
 
diff --git a/src/lib-sieve/sieve-extensions.c b/src/lib-sieve/sieve-extensions.c
index 6d2e59138aca3fae10ee24b7c319cd099d2aadc9..dc2bbc824a56055e3892d1b25010f3a1ca4a834f 100644
--- a/src/lib-sieve/sieve-extensions.c
+++ b/src/lib-sieve/sieve-extensions.c
@@ -122,7 +122,7 @@ const unsigned int sieve_core_extensions_count =
  * Extensions init/deinit
  */
 
-bool sieve_extensions_init(const char *sieve_plugins ATTR_UNUSED) 
+bool sieve_extensions_init(void) 
 {
 	unsigned int i;
 	
@@ -152,14 +152,15 @@ void sieve_extensions_deinit(void)
 struct sieve_extension_registration {
 	const struct sieve_extension *extension;
 	int id;
+	bool disabled;
 };
 
-static ARRAY_DEFINE(extensions, const struct sieve_extension *); 
+static ARRAY_DEFINE(extensions, struct sieve_extension_registration); 
 static struct hash_table *extension_index; 
 
 static void sieve_extensions_init_registry(void)
 {	
-	p_array_init(&extensions, default_pool, 4);
+	p_array_init(&extensions, default_pool, 30);
 	extension_index = hash_table_create
 		(default_pool, default_pool, 0, str_hash, (hash_cmp_callback_t *)strcmp);
 }
@@ -169,11 +170,11 @@ int sieve_extension_register(const struct sieve_extension *extension)
 	int ext_id = array_count(&extensions); 
 	struct sieve_extension_registration *ereg;
 	
-	array_append(&extensions, &extension, 1);
+	ereg = array_append_space(&extensions);
 	
-	ereg = p_new(default_pool, struct sieve_extension_registration, 1);
 	ereg->extension = extension;
 	ereg->id = ext_id;
+	ereg->disabled = FALSE;
 	
 	hash_table_insert(extension_index, (void *) extension->name, (void *) ereg);
 
@@ -192,11 +193,13 @@ int sieve_extensions_get_count(void)
 
 const struct sieve_extension *sieve_extension_get_by_id(unsigned int ext_id) 
 {
-	const struct sieve_extension * const *ext;
+	const struct sieve_extension_registration *ereg;
 	
 	if ( ext_id < array_count(&extensions) ) {
-		ext = array_idx(&extensions, ext_id);
-		return *ext;
+		ereg = array_idx(&extensions, ext_id);
+
+		if ( !ereg->disabled ) 
+			return ereg->extension;
 	}
 	
 	return NULL;
@@ -212,42 +215,44 @@ const struct sieve_extension *sieve_extension_get_by_name(const char *name)
 	ereg = (struct sieve_extension_registration *) 
 		hash_table_lookup(extension_index, name);
 
-	if ( ereg == NULL )
+	if ( ereg == NULL || ereg->disabled )
 		return NULL;
 		
 	return ereg->extension;
 }
 
-static inline bool _list_extension(const struct sieve_extension *ext)
+static inline bool _list_extension
+	(const struct sieve_extension_registration *ereg)
 {
-	return ( ext->id != NULL && *ext->name != '@' );
+	return ( !ereg->disabled && ereg->extension->id != NULL && 
+		*(ereg->extension->name) != '@' );
 }
 
 const char *sieve_extensions_get_string(void)
 {
 	unsigned int i, ext_count;
-	const struct sieve_extension *const *exts;
+	const struct sieve_extension_registration *eregs;
 	string_t *extstr = t_str_new(256);
 
-	exts = array_get(&extensions, &ext_count);
+	eregs = array_get(&extensions, &ext_count);
 
 	if ( ext_count > 0 ) {
 		i = 0;
 		
 		/* Find first listable extension */
-		while ( i < ext_count && !_list_extension(exts[i]) )
+		while ( i < ext_count && !_list_extension(&eregs[i]) )
 			i++;
 
 		if ( i < ext_count ) {
 			/* Add first to string */
-			str_append(extstr, exts[i]->name);
+			str_append(extstr, eregs[i].extension->name);
 			i++;	 
 
 	 		/* Add others */
 			for ( ; i < ext_count; i++ ) {
-				if ( _list_extension(exts[i]) ) {
+				if ( _list_extension(&eregs[i]) ) {
 					str_append_c(extstr, ' ');
-					str_append(extstr, exts[i]->name);
+					str_append(extstr, eregs[i].extension->name);
 				}
 			}
 		}
@@ -256,6 +261,78 @@ const char *sieve_extensions_get_string(void)
 	return str_c(extstr);
 }
 
+void sieve_extensions_set_string(const char *ext_string)
+{
+	ARRAY_DEFINE(enabled_extensions, const struct sieve_extension_registration *);
+	const struct sieve_extension_registration *const *ena_eregs;
+	struct sieve_extension_registration *eregs;
+	const char *bp = ext_string;
+	const char *ep = bp;
+	unsigned int i, ext_count, ena_count;
+
+	if ( ext_string == NULL ) {
+		/* Enable all */
+		eregs = array_get_modifiable(&extensions, &ext_count);
+		
+		for ( i = 0; i < ext_count; i++ ) {
+			eregs[i].disabled = FALSE;
+		}
+
+		return;	
+	}
+
+	t_array_init(&enabled_extensions, array_count(&extensions));
+
+	do {
+		const char *name;
+
+		ep = strchr(bp, ' ');
+		if ( ep == NULL ) 
+			name = bp;
+		else { 
+			name = t_strdup_until(bp, ep);
+			bp = ep + 1;
+		}
+
+		if ( *name != '\0' ) {
+			const struct sieve_extension_registration *ereg;
+	
+			if ( *name == '@' )
+				ereg = NULL;
+			else
+				ereg = (const struct sieve_extension_registration *) 
+					hash_table_lookup(extension_index, name);
+
+			if ( ereg == NULL ) {
+				sieve_sys_warning("ignored unknown extension '%s' while configuring "
+					"available extensions", name);
+				continue;
+			}
+
+			array_append(&enabled_extensions, &ereg, 1);
+		}
+
+	} while ( *bp == '\0' || ep != NULL );
+
+	eregs = array_get_modifiable(&extensions, &ext_count);
+	ena_eregs = array_get(&enabled_extensions, &ena_count);
+
+	/* Set new extension status */
+	for ( i = 0; i < ext_count; i++ ) {
+		unsigned int j;
+		bool disabled = TRUE;
+
+		for ( j = 0; j < ena_count; j++ ) {
+			if ( ena_eregs[j] == &eregs[i] ) {
+				disabled = FALSE;
+				break;
+			}		
+		}
+
+		eregs[i].disabled = disabled;
+	}
+}
+
 static void sieve_extensions_deinit_registry(void) 
 {
 	struct hash_iterate_context *itx = 
@@ -269,8 +346,6 @@ static void sieve_extensions_deinit_registry(void)
 		
 		if ( ext->unload != NULL )
 			ext->unload();
-			
-		p_free(default_pool, ereg);
 	}
 
 	hash_table_iterate_deinit(&itx); 	
diff --git a/src/lib-sieve/sieve-extensions.h b/src/lib-sieve/sieve-extensions.h
index f023d1154a7d29a5450a95fbfe59865d5fa8f703..06c6569940dfd269ed91efdef31e6198eeff076c 100644
--- a/src/lib-sieve/sieve-extensions.h
+++ b/src/lib-sieve/sieve-extensions.h
@@ -78,7 +78,7 @@ extern const unsigned int sieve_preloaded_extensions_count;
  * Extensions init/deinit 
  */
 
-bool sieve_extensions_init(const char *sieve_plugins ATTR_UNUSED);
+bool sieve_extensions_init(void);
 void sieve_extensions_deinit(void);
 
 /* 
@@ -91,6 +91,7 @@ const struct sieve_extension *sieve_extension_get_by_id(unsigned int ext_id);
 const struct sieve_extension *sieve_extension_get_by_name(const char *name);
 
 const char *sieve_extensions_get_string(void);
+void sieve_extensions_set_string(const char *ext_string);
 
 /*
  * Capability registries
diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c
index 760f6eb68d68d40de7427109d7eed113a4a8aba7..2ae1c00de8547a06139e4a94d9effa4832a33edd 100644
--- a/src/lib-sieve/sieve.c
+++ b/src/lib-sieve/sieve.c
@@ -33,9 +33,9 @@
  * Main Sieve library interface
  */
 
-bool sieve_init(const char *plugins)
+bool sieve_init(void)
 {
-	return sieve_extensions_init(plugins);
+	return sieve_extensions_init();
 }
 
 void sieve_deinit(void)
@@ -43,6 +43,11 @@ void sieve_deinit(void)
 	sieve_extensions_deinit();
 }
 
+void sieve_set_extensions(const char *extensions)
+{
+	sieve_extensions_set_string(extensions);
+}
+
 const char *sieve_get_capabilities(const char *name) 
 {
 	if ( name == NULL || *name == '\0' )
diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h
index b4f110f7b20acde0ea92f7648ac1c72100728db4..e8091a0c48438d19fb6b79225f5892751aa61877 100644
--- a/src/lib-sieve/sieve.h
+++ b/src/lib-sieve/sieve.h
@@ -21,18 +21,23 @@ struct sieve_binary;
  *   Initializes the sieve engine. Must be called before any sieve functionality
  *   is used.
  */
-bool sieve_init(const char *plugins);
+bool sieve_init(void);
 
 /* sieve_deinit():
  *   Frees all memory allocated by the sieve engine. 
  */
 void sieve_deinit(void);
 
-/* sieve_get_capabilities:
+/* sieve_get_capabilities():
  *
  */
 const char *sieve_get_capabilities(const char *name);
 
+/* sieve_set_extensions():
+ *
+ */
+void sieve_set_extensions(const char *extensions);
+
 /*
  * Script compilation
  */
diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c
index b04d48b3f55f69b143ac25b1ed81ca19cda873b4..f7709299dd4c73454b0197d1a39f29d2dd2345aa 100644
--- a/src/plugins/lda-sieve/lda-sieve-plugin.c
+++ b/src/plugins/lda-sieve/lda-sieve-plugin.c
@@ -297,8 +297,15 @@ static int lda_sieve_deliver_mail
 
 void sieve_plugin_init(void)
 {
+	const char *extensions = NULL;
+
 	/* Initialize Sieve engine */
-	sieve_init("");
+	sieve_init();
+
+	extensions = getenv("SIEVE_EXTENSIONS");
+	if ( extensions != NULL ) {
+		sieve_set_extensions(extensions);
+	}
 
 	/* Hook into the delivery process */
 	next_deliver_mail = deliver_mail;
diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c
index 854942593451d9da38986449343e8d9bc9497bb5..d335afa330048b2dec3506e8f384aeffcf66c1a9 100644
--- a/src/sieve-tools/sieve-test.c
+++ b/src/sieve-tools/sieve-test.c
@@ -32,14 +32,14 @@
 static void print_help(void)
 {
 #ifdef SIEVE_RUNTIME_TRACE
-#  define SVTRACE "[-t]"
+#  define SVTRACE " [-t]"
 #else
 #  define SVTRACE
 #endif
 	printf(
-"Usage: sieve-test [-r <recipient address>][-s <envelope sender>]\n"
-"                  [-m <mailbox>][-d <dump filename>][-c]" SVTRACE "\n"
-"                  <scriptfile> <mailfile>\n"
+"Usage: sieve-test [-r <recipient address>] [-s <envelope sender>]\n"
+"                  [-m <mailbox>] [-d <dump filename>] [-x <extensions>]\n"
+"                  [-c]"SVTRACE" <scriptfile> <mailfile>\n"
 	);
 }
 
@@ -49,7 +49,8 @@ static void print_help(void)
 
 int main(int argc, char **argv) 
 {
-	const char *scriptfile, *recipient, *sender, *mailbox, *dumpfile, *mailfile; 
+	const char *scriptfile, *recipient, *sender, *mailbox, *dumpfile, *mailfile,
+		*extensions; 
 	const char *user;
 	int i;
 	struct mail_raw *mailr;
@@ -65,7 +66,8 @@ int main(int argc, char **argv)
 	struct ostream *trace_stream = FALSE;
 
 	/* Parse arguments */
-	scriptfile = recipient = sender = mailbox = dumpfile = mailfile = NULL;
+	scriptfile = recipient = sender = mailbox = dumpfile = mailfile = 
+		extensions = NULL;
 	for (i = 1; i < argc; i++) {
 		if (strcmp(argv[i], "-r") == 0) {
 			/* recipient address */
@@ -91,6 +93,12 @@ int main(int argc, char **argv)
 			if (i == argc)
 				i_fatal("Missing -d argument");
 			dumpfile = argv[i];
+		} else if (strcmp(argv[i], "-x") == 0) {
+			/* extensions */
+			i++;
+			if (i == argc)
+				i_fatal("Missing -x argument");
+			extensions = argv[i];
 		} else if (strcmp(argv[i], "-c") == 0) {
             /* force compile */
 			force_compile = TRUE;
@@ -120,6 +128,10 @@ int main(int argc, char **argv)
 	}
 
 	sieve_tool_init();
+
+	if ( extensions != NULL ) {
+		sieve_set_extensions(extensions);
+	}
 	
 	/* Compile sieve script */
 	if ( force_compile ) {
diff --git a/src/sieve-tools/sievec.c b/src/sieve-tools/sievec.c
index 317a9402d455d607f09453cfa2363d9bc97d3bca..a9c03d6a68a1aa88cd1ebb0ca2e5f006cf55cb4c 100644
--- a/src/sieve-tools/sievec.c
+++ b/src/sieve-tools/sievec.c
@@ -21,7 +21,7 @@
 static void print_help(void)
 {
 	printf(
-"Usage: sievec [-d] <scriptfile> <outfile>\n"
+"Usage: sievec [-d] [-x <extensions>] <scriptfile> <outfile>\n"
 	);
 }
 
@@ -33,15 +33,19 @@ int main(int argc, char **argv) {
 	int i;
 	struct sieve_binary *sbin;
 	bool dump = FALSE;
-	const char *scriptfile, *outfile;
-	
-	sieve_tool_init();
-	
-	scriptfile = outfile = NULL;
+	const char *scriptfile, *outfile, *extensions;
+		
+	scriptfile = outfile = extensions = NULL;
 	for (i = 1; i < argc; i++) {
 		if (strcmp(argv[i], "-d") == 0) {
 			/* dump file */
 			dump = TRUE;
+		} else if (strcmp(argv[i], "-x") == 0) {
+			/* extensions */
+			i++;
+			if (i == argc)
+				i_fatal("Missing -x argument");
+			extensions = argv[i];
 		} else if ( scriptfile == NULL ) {
 			scriptfile = argv[i];
 		} else if ( outfile == NULL ) {
@@ -58,8 +62,17 @@ int main(int argc, char **argv) {
 	}
 	
 	if ( outfile == NULL ) {
-		print_help();
-		i_fatal("Missing <outfile> argument");
+		if ( !dump ) {
+			print_help();
+			i_fatal("The <outfile> argument is mandatory without -d");
+		}
+		outfile = "-";
+	}
+
+	sieve_tool_init();
+
+	if ( extensions != NULL ) {
+		sieve_set_extensions(extensions);
 	}
 
 	sbin = sieve_tool_script_compile(scriptfile);