diff --git a/src/lib-sieve/plugins/vacation/Makefile.am b/src/lib-sieve/plugins/vacation/Makefile.am
index cc10d1d4385f92342363e3f47691f3e89c5e4eeb..78b38c881bc4dd54d5761eb92e521332f40eb6ea 100644
--- a/src/lib-sieve/plugins/vacation/Makefile.am
+++ b/src/lib-sieve/plugins/vacation/Makefile.am
@@ -7,7 +7,14 @@ AM_CPPFLAGS = \
 	-I$(dovecot_incdir)/src/lib-mail \
 	-I$(dovecot_incdir)/src/lib-storage 
 
+cmds = \
+	cmd-vacation.c
+
 libsieve_ext_vacation_la_SOURCES = \
+	$(cmds) \
 	ext-vacation.c
 
+noinst_HEADERS = \
+	ext-vacation-common.h
+
 EXTRA_DIST = *.txt *.sieve
diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c
new file mode 100644
index 0000000000000000000000000000000000000000..420fa9dfcf240b8cadbf5bfe1bda416f18d8d0ec
--- /dev/null
+++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -0,0 +1,769 @@
+#include "lib.h"
+#include "md5.h"
+#include "hostpid.h"
+#include "str-sanitize.h"
+#include "message-address.h"
+#include "message-date.h"
+#include "ioloop.h"
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+
+#include "ext-vacation-common.h"
+
+#include <stdio.h>
+
+/* 
+ * Forward declarations 
+ */
+
+static bool ext_vacation_operation_dump
+	(const struct sieve_operation *op,	
+		const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static bool ext_vacation_operation_execute
+	(const struct sieve_operation *op, 
+		const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+static bool cmd_vacation_registered
+	(struct sieve_validator *validator, 
+		struct sieve_command_registration *cmd_reg);
+static bool cmd_vacation_validate
+	(struct sieve_validator *validator, struct sieve_command_context *cmd);
+static bool cmd_vacation_generate
+	(struct sieve_generator *generator,	struct sieve_command_context *ctx);
+
+static int act_vacation_check_duplicate
+	(const struct sieve_runtime_env *renv, const struct sieve_action *action1,
+    	void *context1, void *context2);
+int act_vacation_check_conflict
+	(const struct sieve_runtime_env *renv, const struct sieve_action *action,
+		const struct sieve_action *other_action, void *context);
+static void act_vacation_print
+	(const struct sieve_action *action, void *context, bool *keep);	
+static bool act_vacation_commit
+	(const struct sieve_action *action,	const struct sieve_action_exec_env *aenv, 
+		void *tr_context, bool *keep);
+
+/* Vacation command 
+ *	
+ * Syntax: 
+ *    vacation [":days" number] [":subject" string]
+ *                 [":from" string] [":addresses" string-list]
+ *                 [":mime"] [":handle" string] <reason: string>
+ */
+const struct sieve_command vacation_command = { 
+	"vacation",
+	SCT_COMMAND, 
+	1, 0, FALSE, FALSE, 
+	cmd_vacation_registered,
+	NULL,  
+	cmd_vacation_validate, 
+	cmd_vacation_generate, 
+	NULL 
+};
+
+/* 
+ * Vacation operation 
+ */
+const struct sieve_operation vacation_operation = { 
+	"VACATION",
+	&vacation_extension,
+	0,
+	ext_vacation_operation_dump, 
+	ext_vacation_operation_execute
+};
+
+/* 
+ * Vacation action 
+ */
+		
+struct act_vacation_context {
+	const char *reason;
+
+	sieve_size_t days;
+	const char *subject;
+	const char *handle;
+	bool mime;
+	const char *from;
+	const char *const *addresses;
+};
+
+const struct sieve_action act_vacation = {
+	"vacation",
+	SIEVE_ACTFLAG_SENDS_RESPONSE,
+	act_vacation_check_duplicate, 
+	act_vacation_check_conflict,
+	act_vacation_print,
+	NULL, NULL,
+	act_vacation_commit,
+	NULL
+};
+
+/* 
+ * Tag validation 
+ */
+
+static bool cmd_vacation_validate_number_tag
+(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
+	struct sieve_command_context *cmd)
+{
+	struct sieve_ast_argument *tag = *arg;
+	
+	/* Detach the tag itself */
+	*arg = sieve_ast_arguments_detach(*arg,1);
+	
+	/* Check syntax:
+	 *   :days number
+	 */
+	if ( !sieve_validate_tag_parameter
+		(validator, cmd, tag, *arg, SAAT_NUMBER) ) {
+		return FALSE;
+	}
+
+	/* Skip parameter */
+	*arg = sieve_ast_argument_next(*arg);
+	
+	return TRUE;
+}
+
+static bool cmd_vacation_validate_string_tag
+(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
+	struct sieve_command_context *cmd)
+{
+	struct sieve_ast_argument *tag = *arg;
+
+	/* Detach the tag itself */
+	*arg = sieve_ast_arguments_detach(*arg,1);
+	
+	/* Check syntax:
+	 *   :subject string
+	 *   :from string
+	 *   :handle string
+	 */
+	if ( !sieve_validate_tag_parameter
+		(validator, cmd, tag, *arg, SAAT_STRING) ) {
+		return FALSE;
+	}
+		
+	/* Skip parameter */
+	*arg = sieve_ast_argument_next(*arg);
+
+	return TRUE;
+}
+
+static bool cmd_vacation_validate_stringlist_tag
+(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
+	struct sieve_command_context *cmd)
+{
+	struct sieve_ast_argument *tag = *arg;
+
+	/* Detach the tag itself */
+	*arg = sieve_ast_arguments_detach(*arg,1);
+	
+	/* Check syntax:
+	 *   :addresses string-list
+	 */
+	if ( !sieve_validate_tag_parameter
+		(validator, cmd, tag, *arg, SAAT_STRING_LIST) ) {
+		return FALSE;
+	}
+	
+	/* Skip parameter */
+	*arg = sieve_ast_argument_next(*arg);
+
+	return TRUE;
+}
+
+/* 
+ * Command registration 
+ */
+
+static const struct sieve_argument vacation_days_tag = { 
+	"days", NULL, 
+	cmd_vacation_validate_number_tag, 
+	NULL, NULL 
+};
+
+static const struct sieve_argument vacation_subject_tag = { 
+	"subject", NULL, 
+	cmd_vacation_validate_string_tag, 
+	NULL, NULL 
+};
+
+static const struct sieve_argument vacation_from_tag = { 
+	"from", NULL, 
+	cmd_vacation_validate_string_tag, 
+	NULL, NULL 
+};
+
+static const struct sieve_argument vacation_addresses_tag = { 
+	"addresses", NULL, 
+	cmd_vacation_validate_stringlist_tag, 
+	NULL, NULL 
+};
+
+static const struct sieve_argument vacation_mime_tag = { 
+	"mime",	NULL, NULL, NULL, NULL /* Only generate opt_code */ 
+};
+
+static const struct sieve_argument vacation_handle_tag = { 
+	"handle", NULL, 
+	cmd_vacation_validate_string_tag, 
+	NULL, NULL 
+};
+
+enum cmd_vacation_optional {
+	OPT_END,
+	OPT_DAYS,
+	OPT_SUBJECT,
+	OPT_FROM,
+	OPT_ADDRESSES,
+	OPT_MIME,
+	OPT_HANDLE
+};
+
+static bool cmd_vacation_registered
+(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
+{
+	sieve_validator_register_tag
+		(validator, cmd_reg, &vacation_days_tag, OPT_DAYS); 	
+	sieve_validator_register_tag
+		(validator, cmd_reg, &vacation_subject_tag, OPT_SUBJECT); 	
+	sieve_validator_register_tag
+		(validator, cmd_reg, &vacation_from_tag, OPT_FROM); 	
+	sieve_validator_register_tag
+		(validator, cmd_reg, &vacation_addresses_tag, OPT_ADDRESSES); 	
+	sieve_validator_register_tag
+		(validator, cmd_reg, &vacation_mime_tag, OPT_MIME); 	
+	sieve_validator_register_tag
+		(validator, cmd_reg, &vacation_handle_tag, OPT_HANDLE); 	
+
+	return TRUE;
+}
+
+/* 
+ * Command validation 
+ */
+
+static bool cmd_vacation_validate
+(struct sieve_validator *validator, struct sieve_command_context *cmd) 
+{ 	
+	struct sieve_ast_argument *arg = cmd->first_positional;
+
+	if ( !sieve_validate_positional_argument
+		(validator, cmd, arg, "reason", 1, SAAT_STRING) ) {
+		return FALSE;
+	}
+	
+	return sieve_validator_argument_activate(validator, cmd, arg, FALSE);	
+}
+
+/*
+ * Code generation
+ */
+ 
+static bool cmd_vacation_generate
+(struct sieve_generator *generator,	struct sieve_command_context *ctx) 
+{
+	sieve_generator_emit_operation_ext(generator, &vacation_operation, 
+		ext_vacation_my_id);
+
+	/* Generate arguments */
+	if ( !sieve_generate_arguments(generator, ctx, NULL) )
+		return FALSE;	
+
+	return TRUE;
+}
+
+/* 
+ * Code dump
+ */
+ 
+static bool ext_vacation_operation_dump
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{	
+	int opt_code = 1;
+	
+	sieve_code_dumpf(denv, "VACATION");
+	sieve_code_descend(denv);	
+
+	if ( sieve_operand_optional_present(denv->sbin, address) ) {
+		while ( opt_code != 0 ) {
+			sieve_code_mark(denv);
+			
+			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) 
+				return FALSE;
+
+			switch ( opt_code ) {
+			case 0:
+				break;
+			case OPT_DAYS:
+				if ( !sieve_opr_number_dump(denv, address) )
+					return FALSE;
+				break;
+			case OPT_SUBJECT:
+			case OPT_FROM:
+			case OPT_HANDLE: 
+				if ( !sieve_opr_string_dump(denv, address) )
+					return FALSE;
+				break;
+			case OPT_ADDRESSES:
+				if ( !sieve_opr_stringlist_dump(denv, address) )
+					return FALSE;
+				break;
+			case OPT_MIME:
+				sieve_code_dumpf(denv, "MIME");	
+				break;
+			
+			default:
+				return FALSE;
+			}
+		}
+	}
+	
+	return sieve_opr_string_dump(denv, address);
+}
+
+/* 
+ * Code execution
+ */
+ 
+static bool ext_vacation_operation_execute
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_runtime_env *renv, sieve_size_t *address)
+{	
+	struct sieve_side_effects_list *slist = NULL;
+	struct act_vacation_context *act;
+	pool_t pool;
+	int opt_code = 1;
+	sieve_size_t days = 7;
+	bool mime = FALSE;
+	struct sieve_coded_stringlist *addresses = NULL;
+	string_t *reason, *subject = NULL, *from = NULL, *handle = NULL; 
+		
+	if ( sieve_operand_optional_present(renv->sbin, address) ) {
+		while ( opt_code != 0 ) {
+			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) 
+				return FALSE;
+
+			switch ( opt_code ) {
+			case 0:
+				break;
+			case OPT_DAYS:
+				if ( !sieve_opr_number_read(renv, address, &days) ) 
+					return FALSE;
+				break;
+			case OPT_SUBJECT:
+				if ( !sieve_opr_string_read(renv, address, &subject) ) 
+					return FALSE;
+				break;
+			case OPT_FROM:
+				if ( !sieve_opr_string_read(renv, address, &from) ) 
+					return FALSE;
+				break;
+			case OPT_HANDLE: 
+				if ( !sieve_opr_string_read(renv, address, &handle) ) 	
+					return FALSE;
+				break;
+			case OPT_ADDRESSES:
+				if ( (addresses=sieve_opr_stringlist_read(renv, address)) 
+					== NULL ) 
+					return FALSE;
+				break;
+			case OPT_MIME:
+				mime = TRUE;
+				break;
+			default:
+				return FALSE;
+			}
+		}
+	}
+	
+	if ( !sieve_opr_string_read(renv, address, &reason) ) 
+		return FALSE;
+	
+	printf(">> VACATION \"%s\"\n", str_c(reason));
+	
+	/* Add vacation action to the result */
+	pool = sieve_result_pool(renv->result);
+	act = p_new(pool, struct act_vacation_context, 1);
+	act->reason = p_strdup(pool, str_c(reason));
+	act->days = days;
+	act->mime = mime;
+	if ( subject != NULL )
+		act->subject = p_strdup(pool, str_c(subject));
+	if ( from != NULL )
+		act->from = p_strdup(pool, str_c(from));
+	if ( handle != NULL )
+		act->handle = p_strdup(pool, str_c(handle));
+	if ( addresses != NULL )
+		sieve_coded_stringlist_read_all(addresses, pool, &(act->addresses));
+		
+	return ( sieve_result_add_action(renv, &act_vacation, slist, (void *) act) >= 0 );
+}
+
+/*
+ * Action
+ */
+
+static int act_vacation_check_duplicate
+(const struct sieve_runtime_env *renv ATTR_UNUSED,
+	const struct sieve_action *action1 ATTR_UNUSED,
+	void *context1 ATTR_UNUSED, void *context2 ATTR_UNUSED)
+{
+	sieve_runtime_error(renv, "duplicate 'vacation' action not allowed.");
+	return -1;
+}
+
+int act_vacation_check_conflict
+(const struct sieve_runtime_env *renv,
+	const struct sieve_action *action ATTR_UNUSED,
+	const struct sieve_action *other_action, void *context ATTR_UNUSED)
+{
+	if ( (other_action->flags & SIEVE_ACTFLAG_SENDS_RESPONSE) > 0 ) {
+		sieve_runtime_error(renv, "'vacation' action conflicts with other action: "
+			"'%s' action sends a response back to the sender.",	
+			other_action->name);
+		return -1;
+	}
+
+	return 0;
+}
+ 
+static void act_vacation_print
+(const struct sieve_action *action ATTR_UNUSED, void *context, 
+	bool *keep ATTR_UNUSED)	
+{
+	struct act_vacation_context *ctx = (struct act_vacation_context *) context;
+	
+	printf( 	"* send vacation message:\n"
+						"    => days   : %d\n", ctx->days);
+	if ( ctx->subject != NULL )
+		printf(	"    => subject: %s\n", ctx->subject);
+	if ( ctx->from != NULL )
+		printf(	"    => from   : %s\n", ctx->from);
+	if ( ctx->handle != NULL )
+		printf(	"    => handle : %s\n", ctx->handle);
+	printf(		"\nSTART MESSAGE\n%s\nEND MESSAGE\n", ctx->reason);
+}
+
+static const char * const _list_headers[] = {
+	"list-id",
+	"list-owner",
+	"list-subscribe",
+	"list-post",	
+	"list-unsubscribe",
+	"list-help",
+	"list-archive",
+	NULL
+};
+
+static const char * const _my_address_headers[] = {
+	"to",
+	"cc",
+	"bcc",
+	"resent-to",	
+	"resent-cc",
+	"resent-bcc",
+	NULL
+};
+
+static inline bool _is_system_address(const char *address)
+{
+	if ( strncasecmp(address, "MAILER-DAEMON", 13) == 0 )
+		return TRUE;
+
+	if ( strncasecmp(address, "LISTSERV", 8) == 0 )
+		return TRUE;
+
+	if ( strncasecmp(address, "majordomo", 9) == 0 )
+		return TRUE;
+
+	if ( strstr(address, "-request@") != NULL )
+		return TRUE;
+
+	if ( strncmp(address, "owner-", 6) == 0 )
+		return TRUE;
+
+	return FALSE;
+}
+
+static inline bool _contains_my_address
+	(const char * const *headers, const char *my_address)
+{
+	const char *const *hdsp = headers;
+	
+	while ( *hdsp != NULL ) {
+		const struct message_address *addr;
+
+		t_push();
+	
+		addr = message_address_parse
+			(pool_datastack_create(), (const unsigned char *) *hdsp, 
+				strlen(*hdsp), 256, FALSE);
+
+		while ( addr != NULL ) {
+			if (addr->domain != NULL) {
+				i_assert(addr->mailbox != NULL);
+
+				if ( strcmp(t_strconcat(addr->mailbox, "@", addr->domain, NULL),
+					my_address) == 0 ) {
+					t_pop();
+					return TRUE;
+				}
+			}
+
+			addr = addr->next;
+		}
+
+		t_pop();
+		
+		hdsp++;
+	}
+	
+	return FALSE;
+}
+
+static bool act_vacation_send	
+	(const struct sieve_action_exec_env *aenv, struct act_vacation_context *ctx)
+{
+	const struct sieve_message_data *msgdata = aenv->msgdata;
+	const struct sieve_script_env *senv = aenv->scriptenv;
+	void *smtp_handle;
+	FILE *f;
+ 	const char *outmsgid;
+
+	/* Just to be sure */
+	if ( senv->smtp_open == NULL || senv->smtp_close == NULL ) {
+		sieve_result_error(aenv, "vacation action has no means to send mail.");
+		return FALSE;
+	}
+
+	smtp_handle = senv->smtp_open(msgdata->return_path, NULL, &f);
+	outmsgid = sieve_get_new_message_id(senv);
+    
+	fprintf(f, "Message-ID: %s\r\n", outmsgid);
+	fprintf(f, "Date: %s\r\n", message_date_create(ioloop_time));
+	if ( ctx->from != NULL && *(ctx->from) != '\0' )
+		fprintf(f, "From: <%s>\r\n", ctx->from);
+	else
+		fprintf(f, "From: <%s>\r\n", msgdata->to_address);
+		
+	fprintf(f, "To: <%s>\r\n", msgdata->return_path);
+	fprintf(f, "Subject: %s\r\n", str_sanitize(ctx->subject, 80));
+	
+	/* Produce a proper reply */
+	if ( msgdata->id != NULL ) {
+		fprintf(f, "In-Reply-To: %s\r\n", msgdata->id);
+		
+		/* FIXME: Update References header */
+	}
+	fprintf(f, "Auto-Submitted: auto-replied (vacation)\r\n");
+
+	fprintf(f, "X-Sieve: %s\r\n", SIEVE_IMPLEMENTATION);
+
+	fprintf(f, "Precedence: bulk\r\n");
+	fprintf(f, "MIME-Version: 1.0\r\n");
+    
+	if ( !ctx->mime ) {
+		fprintf(f, "Content-Type: text/plain; charset=utf-8\r\n");
+		fprintf(f, "Content-Transfer-Encoding: 8bit\r\n");
+		fprintf(f, "\r\n");
+	}
+
+	fprintf(f, "%s\r\n", ctx->reason);
+    
+	if ( senv->smtp_close(smtp_handle) ) {
+		/*senv->duplicate_mark(outmsgid, strlen(outmsgid),          WHY?!
+		  senv->username, ioloop_time + DUPLICATE_DEFAULT_KEEP);*/
+		return TRUE;
+	}
+	
+	return FALSE;
+}
+
+static void act_vacation_hash
+(const struct sieve_message_data *msgdata, struct act_vacation_context *vctx, 
+	unsigned char hash_r[])
+{
+	struct md5_context ctx;
+
+	md5_init(&ctx);
+	md5_update(&ctx, msgdata->return_path, strlen(msgdata->return_path));
+
+	if ( vctx->handle != NULL && *(vctx->handle) != '\0' ) 
+		md5_update(&ctx, vctx->handle, strlen(vctx->handle));
+	else {
+		md5_update(&ctx, msgdata->to_address, strlen(msgdata->to_address));
+		md5_update(&ctx, vctx->reason, strlen(vctx->reason));
+	}
+
+	md5_final(&ctx, hash_r);
+}
+
+static bool act_vacation_commit
+(const struct sieve_action *action ATTR_UNUSED, 
+	const struct sieve_action_exec_env *aenv, void *tr_context, 
+	bool *keep ATTR_UNUSED)
+{
+	const char *const *hdsp;
+	const struct sieve_message_data *msgdata = aenv->msgdata;
+	const struct sieve_script_env *senv = aenv->scriptenv;
+	struct act_vacation_context *ctx = (struct act_vacation_context *) tr_context;
+	unsigned char dupl_hash[MD5_RESULTLEN];
+	const char *const *headers;
+	pool_t pool;
+
+	/* Is the return_path unset ?
+	 */
+	if ( msgdata->return_path == NULL || *(msgdata->return_path) == '\0' ) {
+		sieve_result_log(aenv, "discarded vacation reply to <>");
+  	return TRUE;
+  }    
+	
+	/* Are we perhaps trying to respond to ourselves ? 
+	 * (FIXME: verify this to :addresses as well?)
+	 */
+	if ( strcmp(msgdata->return_path, msgdata->to_address) == 0 ) {
+		sieve_result_log(aenv, "discarded vacation reply to own address");
+  	return TRUE;
+	}
+	
+	/* Did whe respond to this user before? */
+	act_vacation_hash(msgdata, ctx, dupl_hash);
+	if (senv->duplicate_check(dupl_hash, sizeof(dupl_hash), senv->username)) 
+	{
+		sieve_result_log(aenv, "discarded duplicate vacation response to <%s>",
+			str_sanitize(msgdata->return_path, 80));
+		return TRUE;
+	}
+	
+	/* Are we trying to respond to a mailing list ? */
+	hdsp = _list_headers;
+	while ( *hdsp != NULL ) {
+		if ( mail_get_headers_utf8
+			(msgdata->mail, *hdsp, &headers) >= 0 && headers[0] != NULL ) {	
+			/* Yes, bail out */
+			sieve_result_log(aenv, 
+				"discarding vacation response to mailinglist recipient <%s>", 
+				msgdata->return_path);	
+			return TRUE;				 
+		}
+		hdsp++;
+	}
+	
+	/* Is the message that we are replying to an automatic reply ? */
+	if ( mail_get_headers_utf8
+		(msgdata->mail, "auto-submitted", &headers) >= 0 ) {
+		/* Theoretically multiple headers could exist, so lets make sure */
+		hdsp = headers;
+		while ( *hdsp != NULL ) {
+			if ( strcasecmp(*hdsp, "no") != 0 ) {
+				sieve_result_log(aenv, 
+					"discardig vacation response to auto-submitted message from <%s>", 
+					msgdata->return_path);	
+					return TRUE;				 
+			}
+			hdsp++;
+		}
+	}
+	
+	/* Check for non-standard precedence header */
+	if ( mail_get_headers_utf8
+		(msgdata->mail, "precedence", &headers) >= 0 ) {
+		/* Theoretically multiple headers could exist, so lets make sure */
+		hdsp = headers;
+		while ( *hdsp != NULL ) {
+			if ( strcasecmp(*hdsp, "junk") == 0 || strcasecmp(*hdsp, "bulk") == 0 ||
+				strcasecmp(*hdsp, "list") == 0 ) {
+				sieve_result_log(aenv, 
+					"discarding vacation response to precedence=%s message from <%s>", 
+					*hdsp, msgdata->return_path);	
+					return TRUE;				 
+			}
+			hdsp++;
+		}
+	}
+	
+	/* Do not reply to system addresses */
+	if ( _is_system_address(msgdata->return_path) ) {
+		sieve_result_log(aenv, 
+			"not sending vacation response to system address <%s>", 
+			msgdata->return_path);	
+		return TRUE;				
+	} 
+	
+	/* Is the original message directly addressed to the user or the addresses
+	 * specified using the :addresses tag? 
+	 */
+	hdsp = _my_address_headers;
+	while ( *hdsp != NULL ) {
+		if ( mail_get_headers_utf8
+			(msgdata->mail, *hdsp, &headers) >= 0 && headers[0] != NULL ) {	
+			
+			if ( _contains_my_address(headers, msgdata->to_address) ) 
+				break;
+			
+			if ( ctx->addresses != NULL ) {
+				bool found = FALSE;
+				const char * const *my_address = ctx->addresses;
+		
+				while ( !found && *my_address != NULL ) {
+					found = _contains_my_address(headers, *my_address);
+					my_address++;
+				}
+				
+				if ( found ) break;
+			}
+		}
+		hdsp++;
+	}	
+
+	if ( *hdsp == NULL ) {
+		/* No, bail out */
+		sieve_result_log(aenv, 
+			"discarding vacation response for implicitly delivered message");	
+		return TRUE;				 
+	}	
+		
+	/* Make sure we have a subject for our reply */
+	if ( ctx->subject == NULL || *(ctx->subject) == '\0' ) {
+		if ( mail_get_headers_utf8
+			(msgdata->mail, "subject", &headers) >= 0 && headers[0] != NULL ) {
+			pool = sieve_result_pool(aenv->result);
+			ctx->subject = p_strconcat(pool, "Auto: ", headers[0], NULL);
+		}	else {
+			ctx->subject = "Automated reply";
+		}
+	}	
+	
+	/* Send the message */
+	
+	if ( act_vacation_send(aenv, ctx) ) {
+		sieve_result_log(aenv, "sent vacation response to <%s>", 
+			str_sanitize(msgdata->return_path, 80));	
+
+		senv->duplicate_mark(dupl_hash, sizeof(dupl_hash), senv->username,
+			ioloop_time + ctx->days * (24 * 60 * 60));
+
+  	return TRUE;
+  }
+
+	sieve_result_error(aenv, "failed to send vacation response to <%s>", 
+		str_sanitize(msgdata->return_path, 80));	
+	return FALSE;
+}
+
+
+
+
diff --git a/src/lib-sieve/plugins/vacation/ext-vacation-common.h b/src/lib-sieve/plugins/vacation/ext-vacation-common.h
new file mode 100644
index 0000000000000000000000000000000000000000..e92538de853ab568e471c37168ac87448d144323
--- /dev/null
+++ b/src/lib-sieve/plugins/vacation/ext-vacation-common.h
@@ -0,0 +1,19 @@
+#ifndef __EXT_VACATION_COMMON_H
+#define __EXT_VACATION_COMMON_H
+
+#include "sieve-common.h"
+
+/* Commands */
+
+extern const struct sieve_command vacation_command;
+
+/* Operations */
+
+extern const struct sieve_operation vacation_operation;
+
+/* Extension */
+
+extern int ext_vacation_my_id;
+extern const struct sieve_extension vacation_extension;
+
+#endif /* __EXT_VACATION_COMMON_H */
diff --git a/src/lib-sieve/plugins/vacation/ext-vacation.c b/src/lib-sieve/plugins/vacation/ext-vacation.c
index 9ee3cf780e8a9e32d3cf2b3141120f22a8bcb59e..d3f7cf64d60cc3d0df373bb04af8a98bb6e35765 100644
--- a/src/lib-sieve/plugins/vacation/ext-vacation.c
+++ b/src/lib-sieve/plugins/vacation/ext-vacation.c
@@ -1,7 +1,7 @@
 /* Extension vacation
  * ------------------
  *
- * Authors: Stephan Bosch
+ * Authors: Stephan Bosch <stephan@rename-it.nl>
  * Specification: draft-ietf-sieve-vacation-07
  * Implementation: almost complete; the required sopport for Refences header 
  *   is missing.
@@ -10,51 +10,30 @@
  */
 
 #include "lib.h"
-#include "md5.h"
-#include "hostpid.h"
-#include "str-sanitize.h"
-#include "message-address.h"
-#include "message-date.h"
-#include "ioloop.h"
 
 #include "sieve-common.h"
 
-#include "sieve-code.h"
 #include "sieve-extensions.h"
 #include "sieve-commands.h"
-#include "sieve-actions.h"
 #include "sieve-validator.h"
 #include "sieve-generator.h"
 #include "sieve-interpreter.h"
 #include "sieve-dump.h"
-#include "sieve-result.h"
 
-#include <stdio.h>
+#include "ext-vacation-common.h"
 
-/* Forward declarations */
+/* 
+ * Forward declarations 
+ */
 
 static bool ext_vacation_load(int ext_id);
 static bool ext_vacation_validator_load(struct sieve_validator *validator);
 
-static bool ext_vacation_operation_dump
-	(const struct sieve_operation *op,	
-		const struct sieve_dumptime_env *denv, sieve_size_t *address);
-static bool ext_vacation_operation_execute
-	(const struct sieve_operation *op, 
-		const struct sieve_runtime_env *renv, sieve_size_t *address);
-
-static bool cmd_vacation_registered
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg);
-static bool cmd_vacation_validate
-	(struct sieve_validator *validator, struct sieve_command_context *cmd);
-static bool cmd_vacation_generate
-	(struct sieve_generator *generator,	struct sieve_command_context *ctx);
-
-/* Extension definitions */
-
-int ext_my_id;
+/* 
+ * Extension definitions 
+ */
 
-const struct sieve_operation vacation_operation;
+int ext_vacation_my_id;
 
 const struct sieve_extension vacation_extension = { 
 	"vacation", 
@@ -67,231 +46,13 @@ const struct sieve_extension vacation_extension = {
 
 static bool ext_vacation_load(int ext_id)
 {
-	ext_my_id = ext_id;
+	ext_vacation_my_id = ext_id;
 
 	return TRUE;
 }
 
-/* Vacation command 
- *	
- * Syntax: 
- *    vacation [":days" number] [":subject" string]
- *                 [":from" string] [":addresses" string-list]
- *                 [":mime"] [":handle" string] <reason: string>
- */
-static const struct sieve_command vacation_command = { 
-	"vacation",
-	SCT_COMMAND, 
-	1, 0, FALSE, FALSE, 
-	cmd_vacation_registered,
-	NULL,  
-	cmd_vacation_validate, 
-	cmd_vacation_generate, 
-	NULL 
-};
-
-/* Vacation operation */
-const struct sieve_operation vacation_operation = { 
-	"VACATION",
-	&vacation_extension,
-	0,
-	ext_vacation_operation_dump, 
-	ext_vacation_operation_execute
-};
-
-/* Vacation action */
-
-static int act_vacation_check_duplicate
-	(const struct sieve_runtime_env *renv, const struct sieve_action *action1,
-    	void *context1, void *context2);
-int act_vacation_check_conflict
-	(const struct sieve_runtime_env *renv, const struct sieve_action *action,
-		const struct sieve_action *other_action, void *context);
-static void act_vacation_print
-	(const struct sieve_action *action, void *context, bool *keep);	
-static bool act_vacation_commit
-	(const struct sieve_action *action,	const struct sieve_action_exec_env *aenv, 
-		void *tr_context, bool *keep);
-		
-struct act_vacation_context {
-	const char *reason;
-
-	sieve_size_t days;
-	const char *subject;
-	const char *handle;
-	bool mime;
-	const char *from;
-	const char *const *addresses;
-};
-
-const struct sieve_action act_vacation = {
-	"vacation",
-	SIEVE_ACTFLAG_SENDS_RESPONSE,
-	act_vacation_check_duplicate, 
-	act_vacation_check_conflict,
-	act_vacation_print,
-	NULL, NULL,
-	act_vacation_commit,
-	NULL
-};
-
-/* Tag validation */
-
-static bool cmd_vacation_validate_number_tag
-	(struct sieve_validator *validator, 
-	struct sieve_ast_argument **arg, 
-	struct sieve_command_context *cmd)
-{
-	struct sieve_ast_argument *tag = *arg;
-	
-	/* Detach the tag itself */
-	*arg = sieve_ast_arguments_detach(*arg,1);
-	
-	/* Check syntax:
-	 *   :days number
-	 */
-	if ( !sieve_validate_tag_parameter
-		(validator, cmd, tag, *arg, SAAT_NUMBER) ) {
-		return FALSE;
-	}
-
-	/* Skip parameter */
-	*arg = sieve_ast_argument_next(*arg);
-	
-	return TRUE;
-}
-
-static bool cmd_vacation_validate_string_tag
-	(struct sieve_validator *validator, 
-	struct sieve_ast_argument **arg, 
-	struct sieve_command_context *cmd)
-{
-	struct sieve_ast_argument *tag = *arg;
-
-	/* Detach the tag itself */
-	*arg = sieve_ast_arguments_detach(*arg,1);
-	
-	/* Check syntax:
-	 *   :subject string
-	 *   :from string
-	 *   :handle string
-	 */
-	if ( !sieve_validate_tag_parameter
-		(validator, cmd, tag, *arg, SAAT_STRING) ) {
-		return FALSE;
-	}
-		
-	/* Skip parameter */
-	*arg = sieve_ast_argument_next(*arg);
-
-	return TRUE;
-}
-
-static bool cmd_vacation_validate_stringlist_tag
-	(struct sieve_validator *validator, 
-	struct sieve_ast_argument **arg, 
-	struct sieve_command_context *cmd)
-{
-	struct sieve_ast_argument *tag = *arg;
-
-	/* Detach the tag itself */
-	*arg = sieve_ast_arguments_detach(*arg,1);
-	
-	/* Check syntax:
-	 *   :addresses string-list
-	 */
-	if ( !sieve_validate_tag_parameter
-		(validator, cmd, tag, *arg, SAAT_STRING_LIST) ) {
-		return FALSE;
-	}
-	
-	/* Skip parameter */
-	*arg = sieve_ast_argument_next(*arg);
-
-	return TRUE;
-}
-
-/* Command registration */
-
-static const struct sieve_argument vacation_days_tag = { 
-	"days", NULL, 
-	cmd_vacation_validate_number_tag, 
-	NULL, NULL 
-};
-
-static const struct sieve_argument vacation_subject_tag = { 
-	"subject", NULL, 
-	cmd_vacation_validate_string_tag, 
-	NULL, NULL 
-};
-
-static const struct sieve_argument vacation_from_tag = { 
-	"from", NULL, 
-	cmd_vacation_validate_string_tag, 
-	NULL, NULL 
-};
-
-static const struct sieve_argument vacation_addresses_tag = { 
-	"addresses", NULL, 
-	cmd_vacation_validate_stringlist_tag, 
-	NULL, NULL 
-};
-
-static const struct sieve_argument vacation_mime_tag = { 
-	"mime",	NULL, NULL, NULL, NULL /* Only generate opt_code */ 
-};
-
-static const struct sieve_argument vacation_handle_tag = { 
-	"handle", NULL, 
-	cmd_vacation_validate_string_tag, 
-	NULL, NULL 
-};
-
-enum cmd_vacation_optional {
-	OPT_END,
-	OPT_DAYS,
-	OPT_SUBJECT,
-	OPT_FROM,
-	OPT_ADDRESSES,
-	OPT_MIME,
-	OPT_HANDLE
-};
-
-static bool cmd_vacation_registered
-	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
-{
-	sieve_validator_register_tag
-		(validator, cmd_reg, &vacation_days_tag, OPT_DAYS); 	
-	sieve_validator_register_tag
-		(validator, cmd_reg, &vacation_subject_tag, OPT_SUBJECT); 	
-	sieve_validator_register_tag
-		(validator, cmd_reg, &vacation_from_tag, OPT_FROM); 	
-	sieve_validator_register_tag
-		(validator, cmd_reg, &vacation_addresses_tag, OPT_ADDRESSES); 	
-	sieve_validator_register_tag
-		(validator, cmd_reg, &vacation_mime_tag, OPT_MIME); 	
-	sieve_validator_register_tag
-		(validator, cmd_reg, &vacation_handle_tag, OPT_HANDLE); 	
-
-	return TRUE;
-}
-
-/* Command validation */
-
-static bool cmd_vacation_validate(struct sieve_validator *validator, 
-	struct sieve_command_context *cmd) 
-{ 	
-	struct sieve_ast_argument *arg = cmd->first_positional;
-
-	if ( !sieve_validate_positional_argument
-		(validator, cmd, arg, "reason", 1, SAAT_STRING) ) {
-		return FALSE;
-	}
-	
-	return sieve_validator_argument_activate(validator, cmd, arg, FALSE);	
-}
-
 /* Load extension into validator */
+
 static bool ext_vacation_validator_load(struct sieve_validator *validator)
 {
 	/* Register new command */
@@ -299,507 +60,3 @@ static bool ext_vacation_validator_load(struct sieve_validator *validator)
 
 	return TRUE;
 }
-
-/*
- * Generation
- */
- 
-static bool cmd_vacation_generate
-	(struct sieve_generator *generator,	struct sieve_command_context *ctx) 
-{
-	sieve_generator_emit_operation_ext(generator, &vacation_operation, ext_my_id);
-
-	/* Generate arguments */
-	if ( !sieve_generate_arguments(generator, ctx, NULL) )
-		return FALSE;	
-
-	return TRUE;
-}
-
-/* 
- * Code dump
- */
- 
-static bool ext_vacation_operation_dump
-(const struct sieve_operation *op ATTR_UNUSED,
-	const struct sieve_dumptime_env *denv, sieve_size_t *address)
-{	
-	int opt_code = 1;
-	
-	sieve_code_dumpf(denv, "VACATION");
-	sieve_code_descend(denv);	
-
-	if ( sieve_operand_optional_present(denv->sbin, address) ) {
-		while ( opt_code != 0 ) {
-			sieve_code_mark(denv);
-			
-			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) 
-				return FALSE;
-
-			switch ( opt_code ) {
-			case 0:
-				break;
-			case OPT_DAYS:
-				if ( !sieve_opr_number_dump(denv, address) )
-					return FALSE;
-				break;
-			case OPT_SUBJECT:
-			case OPT_FROM:
-			case OPT_HANDLE: 
-				if ( !sieve_opr_string_dump(denv, address) )
-					return FALSE;
-				break;
-			case OPT_ADDRESSES:
-				if ( !sieve_opr_stringlist_dump(denv, address) )
-					return FALSE;
-				break;
-			case OPT_MIME:
-				sieve_code_dumpf(denv, "MIME");	
-				break;
-			
-			default:
-				return FALSE;
-			}
-		}
-	}
-	
-	return sieve_opr_string_dump(denv, address);
-}
-
-/* 
- * Code execution
- */
- 
-static bool ext_vacation_operation_execute
-(const struct sieve_operation *op ATTR_UNUSED,
-	const struct sieve_runtime_env *renv, sieve_size_t *address)
-{	
-	struct sieve_side_effects_list *slist = NULL;
-	struct act_vacation_context *act;
-	pool_t pool;
-	int opt_code = 1;
-	sieve_size_t days = 7;
-	bool mime = FALSE;
-	struct sieve_coded_stringlist *addresses = NULL;
-	string_t *reason, *subject = NULL, *from = NULL, *handle = NULL; 
-		
-	if ( sieve_operand_optional_present(renv->sbin, address) ) {
-		while ( opt_code != 0 ) {
-			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) 
-				return FALSE;
-
-			switch ( opt_code ) {
-			case 0:
-				break;
-			case OPT_DAYS:
-				if ( !sieve_opr_number_read(renv, address, &days) ) 
-					return FALSE;
-				break;
-			case OPT_SUBJECT:
-				if ( !sieve_opr_string_read(renv, address, &subject) ) 
-					return FALSE;
-				break;
-			case OPT_FROM:
-				if ( !sieve_opr_string_read(renv, address, &from) ) 
-					return FALSE;
-				break;
-			case OPT_HANDLE: 
-				if ( !sieve_opr_string_read(renv, address, &handle) ) 	
-					return FALSE;
-				break;
-			case OPT_ADDRESSES:
-				if ( (addresses=sieve_opr_stringlist_read(renv, address)) 
-					== NULL ) 
-					return FALSE;
-				break;
-			case OPT_MIME:
-				mime = TRUE;
-				break;
-			default:
-				return FALSE;
-			}
-		}
-	}
-	
-	if ( !sieve_opr_string_read(renv, address, &reason) ) 
-		return FALSE;
-	
-	printf(">> VACATION \"%s\"\n", str_c(reason));
-	
-	/* Add vacation action to the result */
-	pool = sieve_result_pool(renv->result);
-	act = p_new(pool, struct act_vacation_context, 1);
-	act->reason = p_strdup(pool, str_c(reason));
-	act->days = days;
-	act->mime = mime;
-	if ( subject != NULL )
-		act->subject = p_strdup(pool, str_c(subject));
-	if ( from != NULL )
-		act->from = p_strdup(pool, str_c(from));
-	if ( handle != NULL )
-		act->handle = p_strdup(pool, str_c(handle));
-	if ( addresses != NULL )
-		sieve_coded_stringlist_read_all(addresses, pool, &(act->addresses));
-	
-	/* FIXME: :addresses is ignored */
-	
-	return ( sieve_result_add_action(renv, &act_vacation, slist, (void *) act) >= 0 );
-}
-
-/*
- * Action
- */
-
-static int act_vacation_check_duplicate
-(const struct sieve_runtime_env *renv ATTR_UNUSED,
-	const struct sieve_action *action1 ATTR_UNUSED,
-	void *context1 ATTR_UNUSED, void *context2 ATTR_UNUSED)
-{
-	sieve_runtime_error(renv, "duplicate 'vacation' action not allowed.");
-	return -1;
-}
-
-int act_vacation_check_conflict
-(const struct sieve_runtime_env *renv,
-	const struct sieve_action *action ATTR_UNUSED,
-	const struct sieve_action *other_action, void *context ATTR_UNUSED)
-{
-	if ( (other_action->flags & SIEVE_ACTFLAG_SENDS_RESPONSE) > 0 ) {
-		sieve_runtime_error(renv, "'vacation' action conflicts with other action: "
-			"'%s' action sends a response back to the sender.",	
-			other_action->name);
-		return -1;
-	}
-
-	return 0;
-}
- 
-static void act_vacation_print
-(const struct sieve_action *action ATTR_UNUSED, void *context, 
-	bool *keep ATTR_UNUSED)	
-{
-	struct act_vacation_context *ctx = (struct act_vacation_context *) context;
-	
-	printf( 	"* send vacation message:\n"
-						"    => days   : %d\n", ctx->days);
-	if ( ctx->subject != NULL )
-		printf(	"    => subject: %s\n", ctx->subject);
-	if ( ctx->from != NULL )
-		printf(	"    => from   : %s\n", ctx->from);
-	if ( ctx->handle != NULL )
-		printf(	"    => handle : %s\n", ctx->handle);
-	printf(		"\nSTART MESSAGE\n%s\nEND MESSAGE\n", ctx->reason);
-}
-
-static const char * const _list_headers[] = {
-	"list-id",
-	"list-owner",
-	"list-subscribe",
-	"list-post",	
-	"list-unsubscribe",
-	"list-help",
-	"list-archive",
-	NULL
-};
-
-static const char * const _my_address_headers[] = {
-	"to",
-	"cc",
-	"bcc",
-	"resent-to",	
-	"resent-cc",
-	"resent-bcc",
-	NULL
-};
-
-static inline bool _is_system_address(const char *address)
-{
-	if ( strncasecmp(address, "MAILER-DAEMON", 13) == 0 )
-		return TRUE;
-
-	if ( strncasecmp(address, "LISTSERV", 8) == 0 )
-		return TRUE;
-
-	if ( strncasecmp(address, "majordomo", 9) == 0 )
-		return TRUE;
-
-	if ( strstr(address, "-request@") != NULL )
-		return TRUE;
-
-	if ( strncmp(address, "owner-", 6) == 0 )
-		return TRUE;
-
-	return FALSE;
-}
-
-static inline bool _contains_my_address
-	(const char * const *headers, const char *my_address)
-{
-	const char *const *hdsp = headers;
-	
-	while ( *hdsp != NULL ) {
-		const struct message_address *addr;
-
-		t_push();
-	
-		addr = message_address_parse
-			(pool_datastack_create(), (const unsigned char *) *hdsp, 
-				strlen(*hdsp), 256, FALSE);
-
-		while ( addr != NULL ) {
-			if (addr->domain != NULL) {
-				i_assert(addr->mailbox != NULL);
-
-				if ( strcmp(t_strconcat(addr->mailbox, "@", addr->domain, NULL),
-					my_address) == 0 ) {
-					t_pop();
-					return TRUE;
-				}
-			}
-
-			addr = addr->next;
-		}
-
-		t_pop();
-		
-		hdsp++;
-	}
-	
-	return FALSE;
-}
-
-static bool act_vacation_send	
-	(const struct sieve_action_exec_env *aenv, struct act_vacation_context *ctx)
-{
-	const struct sieve_message_data *msgdata = aenv->msgdata;
-	const struct sieve_script_env *senv = aenv->scriptenv;
-	void *smtp_handle;
-	FILE *f;
- 	const char *outmsgid;
-
-	/* Just to be sure */
-	if ( senv->smtp_open == NULL || senv->smtp_close == NULL ) {
-		sieve_result_error(aenv, "vacation action has no means to send mail.");
-		return FALSE;
-	}
-
-	smtp_handle = senv->smtp_open(msgdata->return_path, NULL, &f);
-	outmsgid = sieve_get_new_message_id(senv);
-    
-	fprintf(f, "Message-ID: %s\r\n", outmsgid);
-	fprintf(f, "Date: %s\r\n", message_date_create(ioloop_time));
-	if ( ctx->from != NULL && *(ctx->from) != '\0' )
-		fprintf(f, "From: <%s>\r\n", ctx->from);
-	else
-		fprintf(f, "From: <%s>\r\n", msgdata->to_address);
-		
-	fprintf(f, "To: <%s>\r\n", msgdata->return_path);
-	fprintf(f, "Subject: %s\r\n", str_sanitize(ctx->subject, 80));
-	
-	/* Produce a proper reply */
-	if ( msgdata->id != NULL ) {
-		fprintf(f, "In-Reply-To: %s\r\n", msgdata->id);
-		
-		/* FIXME: Update References header */
-	}
-	fprintf(f, "Auto-Submitted: auto-replied (vacation)\r\n");
-
-	/* FIXME: What about the required references header ? */
-
-	fprintf(f, "X-Sieve: %s\r\n", SIEVE_IMPLEMENTATION);
-
-	fprintf(f, "Precedence: bulk\r\n");
-	fprintf(f, "MIME-Version: 1.0\r\n");
-    
-	if ( !ctx->mime ) {
-		fprintf(f, "Content-Type: text/plain; charset=utf-8\r\n");
-		fprintf(f, "Content-Transfer-Encoding: 8bit\r\n");
-		fprintf(f, "\r\n");
-	}
-
-	fprintf(f, "%s\r\n", ctx->reason);
-    
-	if ( senv->smtp_close(smtp_handle) ) {
-		/*senv->duplicate_mark(outmsgid, strlen(outmsgid),          WHY?!
-		  senv->username, ioloop_time + DUPLICATE_DEFAULT_KEEP);*/
-		return TRUE;
-	}
-	
-	return FALSE;
-}
-
-static void act_vacation_hash
-(const struct sieve_message_data *msgdata, struct act_vacation_context *vctx, 
-	unsigned char hash_r[])
-{
-	struct md5_context ctx;
-
-	md5_init(&ctx);
-	md5_update(&ctx, msgdata->return_path, strlen(msgdata->return_path));
-
-	if ( vctx->handle != NULL && *(vctx->handle) != '\0' ) 
-		md5_update(&ctx, vctx->handle, strlen(vctx->handle));
-	else {
-		md5_update(&ctx, msgdata->to_address, strlen(msgdata->to_address));
-		md5_update(&ctx, vctx->reason, strlen(vctx->reason));
-	}
-
-	md5_final(&ctx, hash_r);
-}
-
-static bool act_vacation_commit
-(const struct sieve_action *action ATTR_UNUSED, 
-	const struct sieve_action_exec_env *aenv, void *tr_context, 
-	bool *keep ATTR_UNUSED)
-{
-	const char *const *hdsp;
-	const struct sieve_message_data *msgdata = aenv->msgdata;
-	const struct sieve_script_env *senv = aenv->scriptenv;
-	struct act_vacation_context *ctx = (struct act_vacation_context *) tr_context;
-	unsigned char dupl_hash[MD5_RESULTLEN];
-	const char *const *headers;
-	pool_t pool;
-
-	/* Is the return_path unset ?
-	 */
-	if ( msgdata->return_path == NULL || *(msgdata->return_path) == '\0' ) {
-		sieve_result_log(aenv, "discarded vacation reply to <>");
-  	return TRUE;
-  }    
-	
-	/* Are we perhaps trying to respond to ourselves ? 
-	 * (FIXME: verify this to :addresses as well?)
-	 */
-	if ( strcmp(msgdata->return_path, msgdata->to_address) == 0 ) {
-		sieve_result_log(aenv, "discarded vacation reply to own address");
-  	return TRUE;
-	}
-	
-	/* Did whe respond to this user before? */
-	act_vacation_hash(msgdata, ctx, dupl_hash);
-	if (senv->duplicate_check(dupl_hash, sizeof(dupl_hash), senv->username)) 
-	{
-		sieve_result_log(aenv, "discarded duplicate vacation response to <%s>",
-			str_sanitize(msgdata->return_path, 80));
-		return TRUE;
-	}
-	
-	/* Are we trying to respond to a mailing list ? */
-	hdsp = _list_headers;
-	while ( *hdsp != NULL ) {
-		if ( mail_get_headers_utf8
-			(msgdata->mail, *hdsp, &headers) >= 0 && headers[0] != NULL ) {	
-			/* Yes, bail out */
-			sieve_result_log(aenv, 
-				"discarding vacation response to mailinglist recipient <%s>", 
-				msgdata->return_path);	
-			return TRUE;				 
-		}
-		hdsp++;
-	}
-	
-	/* Is the message that we are replying to an automatic reply ? */
-	if ( mail_get_headers_utf8
-		(msgdata->mail, "auto-submitted", &headers) >= 0 ) {
-		/* Theoretically multiple headers could exist, so lets make sure */
-		hdsp = headers;
-		while ( *hdsp != NULL ) {
-			if ( strcasecmp(*hdsp, "no") != 0 ) {
-				sieve_result_log(aenv, 
-					"discardig vacation response to auto-submitted message from <%s>", 
-					msgdata->return_path);	
-					return TRUE;				 
-			}
-			hdsp++;
-		}
-	}
-	
-	/* Check for non-standard precedence header */
-	if ( mail_get_headers_utf8
-		(msgdata->mail, "precedence", &headers) >= 0 ) {
-		/* Theoretically multiple headers could exist, so lets make sure */
-		hdsp = headers;
-		while ( *hdsp != NULL ) {
-			if ( strcasecmp(*hdsp, "junk") == 0 || strcasecmp(*hdsp, "bulk") == 0 ||
-				strcasecmp(*hdsp, "list") == 0 ) {
-				sieve_result_log(aenv, 
-					"discarding vacation response to precedence=%s message from <%s>", 
-					*hdsp, msgdata->return_path);	
-					return TRUE;				 
-			}
-			hdsp++;
-		}
-	}
-	
-	/* Do not reply to system addresses */
-	if ( _is_system_address(msgdata->return_path) ) {
-		sieve_result_log(aenv, 
-			"not sending vacation response to system address <%s>", 
-			msgdata->return_path);	
-		return TRUE;				
-	} 
-	
-	/* Is the original message directly addressed to the user or the addresses
-	 * specified using the :addresses tag? 
-	 */
-	hdsp = _my_address_headers;
-	while ( *hdsp != NULL ) {
-		if ( mail_get_headers_utf8
-			(msgdata->mail, *hdsp, &headers) >= 0 && headers[0] != NULL ) {	
-			
-			if ( _contains_my_address(headers, msgdata->to_address) ) 
-				break;
-			
-			if ( ctx->addresses != NULL ) {
-				bool found = FALSE;
-				const char * const *my_address = ctx->addresses;
-		
-				while ( !found && *my_address != NULL ) {
-					found = _contains_my_address(headers, *my_address);
-					my_address++;
-				}
-				
-				if ( found ) break;
-			}
-		}
-		hdsp++;
-	}	
-
-	if ( *hdsp == NULL ) {
-		/* No, bail out */
-		sieve_result_log(aenv, 
-			"discarding vacation response for implicitly delivered message");	
-		return TRUE;				 
-	}	
-		
-	/* Make sure we have a subject for our reply */
-	if ( ctx->subject == NULL || *(ctx->subject) == '\0' ) {
-		if ( mail_get_headers_utf8
-			(msgdata->mail, "subject", &headers) >= 0 && headers[0] != NULL ) {
-			pool = sieve_result_pool(aenv->result);
-			ctx->subject = p_strconcat(pool, "Auto: ", headers[0], NULL);
-		}	else {
-			ctx->subject = "Automated reply";
-		}
-	}	
-	
-	/* Send the message */
-	
-	if ( act_vacation_send(aenv, ctx) ) {
-		sieve_result_log(aenv, "sent vacation response to <%s>", 
-			str_sanitize(msgdata->return_path, 80));	
-
-		senv->duplicate_mark(dupl_hash, sizeof(dupl_hash), senv->username,
-			ioloop_time + ctx->days * (24 * 60 * 60));
-
-  	return TRUE;
-  }
-
-	sieve_result_error(aenv, "failed to send vacation response to <%s>", 
-		str_sanitize(msgdata->return_path, 80));	
-	return FALSE;
-}
-
-
-
-