From 6f0cf81a03a04e1454d0421d6bc7db1104adafe5 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Wed, 11 Aug 2010 18:20:41 +0200
Subject: [PATCH] Improved and simplified file error handling

- Administrators now get properly notified about uncompiled global scripts and the inability of the sieve plugin to store global binaries.
- Improved binary load/save error handling and fixed a few smal bugs.
- Simplified ManageSieve error handling.
---
 TODO                                          |  10 +-
 src/lib-sieve-tool/sieve-tool.c               |   5 +-
 src/lib-sieve/plugins/include/cmd-include.c   |   6 +-
 .../plugins/include/ext-include-common.c      |   4 +-
 src/lib-sieve/sieve-binary-file.c             | 279 +++++++++++-------
 src/lib-sieve/sieve-binary-private.h          |   3 +-
 src/lib-sieve/sieve-binary.c                  |  31 +-
 src/lib-sieve/sieve-binary.h                  |  18 +-
 src/lib-sieve/sieve-common.h                  |   6 +-
 src/lib-sieve/sieve-lexer.c                   |   7 +-
 src/lib-sieve/sieve-lexer.h                   |   3 +-
 src/lib-sieve/sieve-parser.c                  |   5 +-
 src/lib-sieve/sieve-parser.h                  |   3 +-
 src/lib-sieve/sieve-script-private.h          |   2 +-
 src/lib-sieve/sieve-script.c                  | 129 ++++----
 src/lib-sieve/sieve-script.h                  |   7 +-
 src/lib-sieve/sieve-types.h                   |  29 ++
 src/lib-sieve/sieve.c                         | 156 ++++++----
 src/lib-sieve/sieve.h                         |  55 ++--
 src/lib-sievestorage/Makefile.am              |   1 -
 src/lib-sievestorage/sieve-storage-error.h    |  32 --
 src/lib-sievestorage/sieve-storage-list.c     |  20 +-
 src/lib-sievestorage/sieve-storage-private.h  |   6 +-
 src/lib-sievestorage/sieve-storage-quota.c    |   6 +-
 src/lib-sievestorage/sieve-storage-save.c     |  36 ++-
 src/lib-sievestorage/sieve-storage-script.c   | 147 +++++----
 src/lib-sievestorage/sieve-storage-script.h   |  10 +-
 src/lib-sievestorage/sieve-storage.c          |  31 +-
 src/lib-sievestorage/sieve-storage.h          |   5 +-
 src/managesieve/cmd-deletescript.c            |  10 +-
 src/managesieve/cmd-getscript.c               |  53 ++--
 src/managesieve/cmd-putscript.c               |   2 +-
 src/managesieve/cmd-renamescript.c            |  10 +-
 src/managesieve/cmd-setactive.c               |  12 +-
 src/managesieve/managesieve-client.c          |  20 +-
 src/plugins/lda-sieve/lda-sieve-plugin.c      | 178 ++++++-----
 src/sieve-tools/sieve-test.c                  |   4 +-
 src/sieve-tools/sievec.c                      |   4 +-
 src/sieve-tools/sieved.c                      |   2 +-
 src/testsuite/testsuite-binary.c              |   6 +-
 src/testsuite/testsuite-script.c              |   4 +-
 src/testsuite/testsuite.c                     |   2 +-
 42 files changed, 746 insertions(+), 613 deletions(-)
 delete mode 100644 src/lib-sievestorage/sieve-storage-error.h

diff --git a/TODO b/TODO
index 0b54d5b21..b99887f61 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,8 @@
 Current activities:
 
+* Improve error handling and logging
+	- Avoid reporting user-caused errors to the master log.
+	- Review logging and error handling; add more warning/info/debug messages where useful.
 * Cleanup the test suite
 	- Make uniform command implementations
 	- Cleanup test scripts
@@ -7,13 +10,6 @@ Current activities:
 Next (in order of descending priority/precedence):
 
 * Update man pages to match style of Dovecot man pages.
-* Improve error handling and logging
-	- Detect permission errors when writing global script binaries and advise the 
-	  administrator on using sievec to precompile the scripts.
-	- Avoid reporting user-caused errors to the master log.
-	- Review logging and error handling; add more warning/info/debug messages where useful.
-	- Improve logging of script execution (particularly what is currently executed;
-	  a promptly compiled script or the stored binary).
 * Update include extension to latest draft:
 	- Implement required ManageSieve behavior
 * Unfinished new extensions:
diff --git a/src/lib-sieve-tool/sieve-tool.c b/src/lib-sieve-tool/sieve-tool.c
index a1a0cb0bf..746c1a3f4 100644
--- a/src/lib-sieve-tool/sieve-tool.c
+++ b/src/lib-sieve-tool/sieve-tool.c
@@ -516,11 +516,11 @@ struct sieve_binary *sieve_tool_script_compile
 	ehandler = sieve_stderr_ehandler_create(0);
 	sieve_error_handler_accept_infolog(ehandler, TRUE);
 
-	if ( (sbin = sieve_compile(svinst, filename, name, ehandler)) == NULL )
+	if ( (sbin = sieve_compile(svinst, filename, name, ehandler, NULL)) == NULL )
 		i_error("failed to compile sieve script '%s'", filename);
 
 	sieve_error_handler_unref(&ehandler);
-		
+
 	return sbin;
 }
 	
@@ -540,6 +540,7 @@ struct sieve_binary *sieve_tool_script_open
 
 	sieve_error_handler_unref(&ehandler);
 		
+	sieve_save(sbin, NULL, FALSE, NULL);
 	return sbin;
 }
 
diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c
index c36f31e5b..dd915b44c 100644
--- a/src/lib-sieve/plugins/include/cmd-include.c
+++ b/src/lib-sieve/plugins/include/cmd-include.c
@@ -202,7 +202,7 @@ static bool cmd_include_validate
 		(struct cmd_include_context_data *) cmd->data;
 	struct sieve_script *script;
 	const char *script_path, *script_name;
-	bool exists = TRUE;
+	enum sieve_error error = TRUE;
 	
 	/* Check argument */
 	if ( !sieve_validate_positional_argument
@@ -247,10 +247,10 @@ static bool cmd_include_validate
 	/* Create script object */
 	script = sieve_script_create_in_directory
 		(this_ext->svinst, script_path, script_name, 
-			sieve_validator_error_handler(valdtr), &exists);
+			sieve_validator_error_handler(valdtr), &error);
 
 	if ( script == NULL ) {
-		if ( !exists ) {
+		if ( error == SIEVE_ERROR_NOT_FOUND ) {
 			sieve_argument_validate_error(valdtr, arg, 
 				"included %s script '%s' does not exist", 
 				ext_include_script_location_name(ctx_data->location),
diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c
index 336685a2c..a1bcf839c 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.c
+++ b/src/lib-sieve/plugins/include/ext-include-common.c
@@ -456,7 +456,7 @@ bool ext_include_generate_include
 			(binctx, script, location, inc_block);
 
 		/* Parse */
-		if ( (ast = sieve_parse(script, ehandler)) == NULL ) {
+		if ( (ast = sieve_parse(script, ehandler, NULL)) == NULL ) {
 	 		sieve_command_generate_error(gentr, cmd, 
 	 			"failed to parse included script '%s'", str_sanitize(script_name, 80));
 	 		return FALSE;
@@ -466,7 +466,7 @@ bool ext_include_generate_include
 		(void)ext_include_create_ast_context(this_ext, ast, cmd->ast_node->ast);
 
 		/* Validate */
-		if ( !sieve_validate(ast, ehandler) ) {
+		if ( !sieve_validate(ast, ehandler, NULL) ) {
 			sieve_command_generate_error(gentr, cmd, 
 				"failed to validate included script '%s'", 
 				str_sanitize(script_name, 80));
diff --git a/src/lib-sieve/sieve-binary-file.c b/src/lib-sieve/sieve-binary-file.c
index 47ab4c955..4e59058f8 100644
--- a/src/lib-sieve/sieve-binary-file.c
+++ b/src/lib-sieve/sieve-binary-file.c
@@ -66,9 +66,13 @@ struct sieve_binary_block_header {
 
 static inline bool _save_skip(struct ostream *stream, size_t size)
 {	
-	if ( (o_stream_seek(stream, stream->offset + size)) <= 0 ) 
+	if ( (o_stream_seek(stream, stream->offset + size)) <= 0 ) {
+		sieve_sys_error("binary save: failed to skip output stream "
+			"to position %"PRIuUOFF_T": %s", stream->offset + size,
+			strerror(stream->stream_errno));
 		return FALSE;
-		
+	}
+
 	return TRUE;
 }
 
@@ -77,8 +81,12 @@ static inline bool _save_skip_aligned
 {
 	uoff_t aligned_offset = SIEVE_BINARY_ALIGN(stream->offset);
 	
-	if ( (o_stream_seek(stream, aligned_offset + size)) <= 0 ) 
+	if ( (o_stream_seek(stream, aligned_offset + size)) <= 0 ) {
+		sieve_sys_error("binary save: failed to skip output stream "
+			"to position %"PRIuUOFF_T": %s", aligned_offset + size,
+			strerror(stream->stream_errno));
 		return FALSE;
+	}
 		
 	if ( offset != NULL )
 		*offset = aligned_offset;
@@ -95,8 +103,11 @@ static bool _save_full(struct ostream *stream, const void *data, size_t size)
 	while ( bytes_left > 0 ) {
 		ssize_t ret;
 		
-		if ( (ret=o_stream_send(stream, pdata, bytes_left)) <= 0 ) 
+		if ( (ret=o_stream_send(stream, pdata, bytes_left)) <= 0 ) {
+			sieve_sys_error("binary save: failed to write %"PRIuSIZE_T" bytes "
+				"to output stream: %s", bytes_left, strerror(stream->stream_errno));
 			return FALSE;
+		}
 			
 		pdata = PTR_OFFSET(pdata, ret);
 		bytes_left -= ret;
@@ -169,8 +180,7 @@ static bool _save_block_index_record
 	header.offset = block->offset;
 	
 	if ( !_save_full(stream, &header, sizeof(header)) ) {
-		sieve_sys_error("failed to save block index header %d: %m", id);
-		
+		sieve_sys_error("binary save: failed to save block index header %d", id);
 		return FALSE;
 	}
 	
@@ -206,7 +216,7 @@ static bool _sieve_binary_save
 	header.blocks = blk_count;
 
 	if ( !_save_aligned(stream, &header, sizeof(header), NULL) ) {
-		sieve_sys_error("failed to save binary header: %m");
+		sieve_sys_error("binary save: failed to save header");
 		return FALSE;
 	} 
 	
@@ -251,69 +261,100 @@ static bool _sieve_binary_save
 	return TRUE;
 } 
 
-bool sieve_binary_save
-(struct sieve_binary *sbin, const char *path)
+int sieve_binary_save
+(struct sieve_binary *sbin, const char *path, bool update, 
+	enum sieve_error *error_r)
 {
-	bool result = TRUE;
+	int result, fd;
 	string_t *temp_path;
 	struct ostream *stream;
-	int fd;
 	mode_t save_mode =
 		sbin->script == NULL ? 0600 : sieve_script_permissions(sbin->script);
+
+	if ( error_r != NULL )
+		*error_r = SIEVE_ERROR_NONE;
 	
 	/* Use default path if none is specified */
 	if ( path == NULL ) {
 		if ( sbin->script == NULL ) {
-			sieve_sys_error("cannot determine default binary save path "
+			sieve_sys_error("binary save: cannot determine default path "
 				"with missing script object");
-        	return FALSE;
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_NOT_POSSIBLE;
+			return -1;
 		}
 		path = sieve_script_binpath(sbin->script);
 	}
 
+	/* Check whether saving is necessary */
+	if ( !update && sbin->path != NULL && strcmp(sbin->path, path) == 0 ) {
+		if ( sbin->svinst->debug ) {
+			sieve_sys_debug("binary save: not saving binary %s, "
+				"because it is already stored", path);
+		}		
+		return 0;
+	}
+
 	/* Open it as temp file first, as not to overwrite an existing just yet */
 	temp_path = t_str_new(256);
 	str_append(temp_path, path);
+	str_append_c(temp_path, '.');
 	fd = safe_mkstemp_hostpid(temp_path, save_mode, (uid_t)-1, (gid_t)-1);
 	if ( fd < 0 ) {
 		if ( errno == EACCES ) {
-			sieve_sys_error("failed to save binary temporary file: %s",
+			sieve_sys_error("binary save: failed to create temporary file: %s",
 				eacces_error_get_creating("open", str_c(temp_path)));
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_NO_PERM;
 		} else {
-			sieve_sys_error("failed to save binary temporary file: "
+			sieve_sys_error("binary save: failed to create temporary file: "
 				"open(%s) failed: %m", str_c(temp_path));
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_TEMP_FAIL;
 		}
-		return FALSE;
+		return -1;
 	}
 
 	/* Save binary */
+	result = 1;
 	stream = o_stream_create_fd(fd, 0, FALSE);
-	result = _sieve_binary_save(sbin, stream);
+	if ( !_sieve_binary_save(sbin, stream) ) {
+		result = -1;
+		if ( error_r != NULL )
+			*error_r = SIEVE_ERROR_TEMP_FAIL;
+	}
 	o_stream_destroy(&stream);
 
 	/* Close saved binary */ 
 	if ( close(fd) < 0 ) {
-		sieve_sys_error("failed to close saved binary temporary file: "
+		sieve_sys_error("binary save: failed to close temporary file: "
 			"close(fd=%s) failed: %m", str_c(temp_path));
 	}
 
 	/* Replace any original binary atomically */
 	if ( result && (rename(str_c(temp_path), path) < 0) ) {
 		if ( errno == EACCES ) {
-			sieve_sys_error("failed to replace existing binary: %s", 
-				eacces_error_get_creating("rename", path));			
+			sieve_sys_error("binary save: failed to save binary: %s", 
+				eacces_error_get_creating("rename", path));
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_NO_PERM;
 		} else { 		
-			sieve_sys_error("failed to replace existing binary: "
+			sieve_sys_error("binary save: failed to save binary: "
 				"rename(%s, %s) failed: %m", str_c(temp_path), path);
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_TEMP_FAIL;
 		}
-		result = FALSE;
+		result = -1;
 	}
 
-	if ( !result ) {
+	if ( result < 0 ) {
 		/* Get rid of temp output (if any) */
-		(void) unlink(str_c(temp_path));
+		if ( unlink(str_c(temp_path)) < 0 && errno != ENOENT ) {
+			sieve_sys_error("binary save: failed to clean up after error: "
+				"unlink(%s) failed: %m", str_c(temp_path));
+		}
 	} else {
-		if ( sbin->path == NULL || strcmp(sbin->path, path) != 0 ) {
+		if ( sbin->path == NULL ) {
 			sbin->path = p_strdup(sbin->pool, path);
 		}
 	}
@@ -326,37 +367,57 @@ bool sieve_binary_save
  */
 
 bool sieve_binary_file_open
-	(struct sieve_binary_file *file, const char *path)
+(struct sieve_binary_file *file, const char *path, enum sieve_error *error_r)
 {
 	int fd;
+	bool result = TRUE;
 	struct stat st;
+
+	if ( error_r != NULL )
+		*error_r = SIEVE_ERROR_NONE;
 	
 	if ( (fd=open(path, O_RDONLY)) < 0 ) {
-		if ( errno != ENOENT ) {
-			if ( errno == EACCES ) {
-				sieve_sys_error("failed to open binary: %s", 
-					eacces_error_get("open", path));			
-			} else {
-				sieve_sys_error("failed to open binary: "
-					"open(%s) failed: %m", path);
-			}
+		switch ( errno ) {
+		case ENOENT:
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_NOT_FOUND;
+			break;
+		case EACCES:
+			sieve_sys_error("binary open: failed to open: %s", 
+				eacces_error_get("open", path));
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_NO_PERM;
+			break;
+		default:
+			sieve_sys_error("binary open: failed to open: "
+				"open(%s) failed: %m", path);
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_TEMP_FAIL;
+			break;
 		}
 		return FALSE;
 	}
 
 	if ( fstat(fd, &st) < 0 ) {
 		if ( errno != ENOENT ) {
-			sieve_sys_error("failed to open binary: "
-				"fstat(fd=%s) failed: %m", path);
+			sieve_sys_error("binary open: fstat(fd=%s) failed: %m", path);
 		}
-		return FALSE;
+		result = FALSE;
 	}
 
-	if ( !S_ISREG(st.st_mode) ) {
-		sieve_sys_error("binary %s is not a regular file", path);
-		return FALSE;		
+	if ( result && !S_ISREG(st.st_mode) ) {
+		sieve_sys_error("binary open: %s is not a regular file", path);
+		result = FALSE;		
 	}
 	
+	if ( !result )	{
+		if ( close(fd) < 0 ) {
+			sieve_sys_error("binary open: close(fd=%s) failed after error: %m",
+				path);
+		}
+		return FALSE;
+	}
+
 	file->fd = fd;
 	file->st = st;
 
@@ -367,7 +428,7 @@ void sieve_binary_file_close(struct sieve_binary_file **file)
 {
 	if ( (*file)->fd != -1 ) {
 		if ( close((*file)->fd) < 0 ) {
-			sieve_sys_error("failed to close opened binary: "
+			sieve_sys_error("binary close: failed to close: "
 				"close(fd=%s) failed: %m", (*file)->path);
 		}
 	}
@@ -505,7 +566,8 @@ static bool _file_lazy_read
 	/* Seek to the correct position */ 
 	if ( *offset != file->offset && 
 		lseek(file->fd, *offset, SEEK_SET) == (off_t) -1 ) {
-		sieve_sys_error("failed to seek(fd, %lld, SEEK_SET) in binary %s: %m", 
+		sieve_sys_error("binary read:"
+			"failed to seek(fd, %lld, SEEK_SET) in binary %s: %m", 
 			(long long) *offset, file->path);
 		return FALSE;
 	}	
@@ -514,10 +576,12 @@ static bool _file_lazy_read
 	while (insize > 0) {
 		if ( (ret=read(file->fd, indata, insize)) <= 0 ) {
 			if ( ret == 0 ) 
-				sieve_sys_error("binary %s is truncated (more data expected)", 
+				sieve_sys_error(
+					"binary read: binary %s is truncated (more data expected)", 
 					file->path);
 			else
-				sieve_sys_error("failed to read from binary %s: %m", file->path);
+				sieve_sys_error(
+					"binary read: failed to read from binary %s: %m", file->path);
 			break;
 		}
 		
@@ -561,7 +625,8 @@ static buffer_t *_file_lazy_load_buffer
 	return NULL;
 }
 
-static struct sieve_binary_file *_file_lazy_open(const char *path)
+static struct sieve_binary_file *_file_lazy_open
+(const char *path, enum sieve_error *error_r)
 {
 	pool_t pool;
 	struct sieve_binary_file *file;
@@ -573,7 +638,7 @@ static struct sieve_binary_file *_file_lazy_open(const char *path)
 	file->load_data = _file_lazy_load_data;
 	file->load_buffer = _file_lazy_load_buffer;
 	
-	if ( !sieve_binary_file_open(file, path) ) {
+	if ( !sieve_binary_file_open(file, path, error_r) ) {
 		pool_unref(&pool);
 		return NULL;
 	}
@@ -598,20 +663,24 @@ bool sieve_binary_load_block
 		LOAD_HEADER(sbin, &offset, const struct sieve_binary_block_header);
 		
 	if ( header == NULL ) {
-		sieve_sys_error
-			("block %d of loaded binary %s is truncated", id, sbin->path);
+		sieve_sys_error(
+			"binary load: binary %s is corrupt: "
+			"failed to read header of block %d", sbin->path, id);
 		return FALSE;
 	}
 	
 	if ( header->id != id ) {
-		sieve_sys_error("block %d of loaded binary %s has unexpected id %d", id, 
-			sbin->path, header->id);
+		sieve_sys_error(
+			"binary load: binary %s is corrupt: "
+			"header of block %d has non-matching id %d",
+			sbin->path, id, header->id);
 		return FALSE;
 	}
 	
 	sblock->data = sbin->file->load_buffer(sbin->file, &offset, header->size);
 	if ( sblock->data == NULL ) {
-		sieve_sys_error("block %d of loaded binary %s has invalid size %d",
+		sieve_sys_error(
+			"binary load: failed to read block %d of binary %s (size=%d)",
 			id, sbin->path, header->size);
 		return FALSE;
 	}
@@ -619,7 +688,7 @@ bool sieve_binary_load_block
 	return TRUE;
 }
 
-static bool _load_block_index_record
+static bool _read_block_index_record
 (struct sieve_binary *sbin, off_t *offset, unsigned int id)
 {
 	const struct sieve_binary_block_index *record = 
@@ -627,14 +696,16 @@ static bool _load_block_index_record
 	struct sieve_binary_block *block;
 	
 	if ( record == NULL ) {
-		sieve_sys_error("failed to read index record for block %d in binary %s", 
-			id, sbin->path);
+		sieve_sys_error(
+			"binary open: binary %s is corrupt: "
+			"failed to load block index record %d", sbin->path, id);
 		return FALSE;
 	}
 	
 	if ( record->id != id ) {
-		sieve_sys_error("block index record %d of loaded binary %s "
-			"has unexpected id %d", id, sbin->path, record->id);
+		sieve_sys_error(
+			"binary open: binary %s is corrupt: "
+			"block index record %d has unexpected id %d", sbin->path, id, record->id);
 		return FALSE;
 	}
 	
@@ -645,7 +716,7 @@ static bool _load_block_index_record
 	return TRUE;
 }
 
-static bool _sieve_binary_load_extensions(struct sieve_binary_block *sblock)
+static bool _read_extensions(struct sieve_binary_block *sblock)
 {
 	struct sieve_binary *sbin = sblock->sbin;
 	sieve_size_t offset = 0;
@@ -664,7 +735,8 @@ static bool _sieve_binary_load_extensions(struct sieve_binary_block *sblock)
 				ext = sieve_extension_get_by_name(sbin->svinst, str_c(extension));	
 			
 				if ( ext == NULL ) { 
-					sieve_sys_error("loaded binary %s requires unknown extension '%s'", 
+					sieve_sys_error(
+						"binary open: binary %s requires unknown extension '%s'", 
 						sbin->path, str_sanitize(str_c(extension), 128));
 					result = FALSE;					
 				} else {
@@ -694,28 +766,48 @@ static bool _sieve_binary_open(struct sieve_binary *sbin)
 	
 	T_BEGIN {
 		header = LOAD_HEADER(sbin, &offset, const struct sieve_binary_header);
+		/* Check header presence */
 		if ( header == NULL ) {
-			sieve_sys_error("opened binary %s is not even large enough "
-				"to contain a header.", sbin->path);
+			sieve_sys_error("binary_open: file %s is not large enough "
+				"to contain the header.", sbin->path);
 			result = FALSE;
 
+		/* Check header validity */
 		} else if ( header->magic != SIEVE_BINARY_MAGIC ) {
 			if ( header->magic != SIEVE_BINARY_MAGIC_OTHER_ENDIAN ) 
-				sieve_sys_error("opened binary %s has corrupted header (0x%08x)", 
-					sbin->path, header->magic);
+				sieve_sys_error("binary_open: binary %s has corrupted header "
+					"(0x%08x) or it is not a Sieve binary", sbin->path, header->magic);
+			else if ( sbin->svinst->debug )
+				sieve_sys_debug("binary open: binary %s stored "
+					"with in different endian format "
+					"(automatically fixed when re-compiled)",
+					sbin->path);
 			result = FALSE;
 
+		/* Check binary version */
 		} else if ( result && (
 		  header->version_major != SIEVE_BINARY_VERSION_MAJOR || 
 			header->version_minor != SIEVE_BINARY_VERSION_MINOR ) ) {
 
 			/* Binary is of different version. Caller will have to recompile */
+			
+			if ( sbin->svinst->debug ) {
+				sieve_sys_debug("binary open: binary %s stored "
+					"with different binary version %d.%d "
+					"(!= %d.%d; automatically fixed when re-compiled)", sbin->path,
+					(int) header->version_major, header->version_minor,
+					SIEVE_BINARY_VERSION_MAJOR, SIEVE_BINARY_VERSION_MINOR);
+			}
 			result = FALSE;
 
+		/* Check block content */
 		} else if ( result && header->blocks == 0 ) {
-			sieve_sys_error("opened binary %s contains no blocks", sbin->path);
+			sieve_sys_error(
+				"binary open: binary %s is corrupt: it contains no blocks",
+				sbin->path);
 			result = FALSE; 
 
+		/* Valid */
 		} else {
 			blk_count = header->blocks;
 		}
@@ -727,10 +819,7 @@ static bool _sieve_binary_open(struct sieve_binary *sbin)
 	
 	for ( i = 0; i < blk_count && result; i++ ) {	
 		T_BEGIN {
-			if ( !_load_block_index_record(sbin, &offset, i) ) {
-				sieve_sys_error(
-					"block index record %d of opened binary %s is corrupt", 
-					i, sbin->path);
+			if ( !_read_block_index_record(sbin, &offset, i) ) {
 				result = FALSE;
 			}
 		} T_END;
@@ -745,8 +834,9 @@ static bool _sieve_binary_open(struct sieve_binary *sbin)
 		if ( ext_block == NULL ) {
 			result = FALSE;
 		} else {
-			if ( !_sieve_binary_load_extensions(ext_block) ) {
-				sieve_sys_error("extension block of opened binary %s is corrupt", 
+			if ( !_read_extensions(ext_block) ) {
+				sieve_sys_error("binary open: binary %s is corrupt: "
+					"failed to load extension block", 
 					sbin->path);
 				result = FALSE;
 			}
@@ -756,31 +846,9 @@ static bool _sieve_binary_open(struct sieve_binary *sbin)
 	return result;
 }
 
-static bool _sieve_binary_load(struct sieve_binary *sbin) 
-{	
-	bool result = TRUE;
-	unsigned int i, blk_count;
-	
-	blk_count = array_count(&sbin->blocks);
-	if ( blk_count == 1 ) {
-		/* Binary is empty */
-		return TRUE;
-	}	
-
-	/* Load the other blocks */
-	
-	for ( i = 0; result && i < blk_count; i++ ) {	
-		T_BEGIN {
-			if ( sieve_binary_block_get(sbin, i) == NULL )
-				result = FALSE;
-		} T_END;
-	}
-				
-	return result;
-}
-
 struct sieve_binary *sieve_binary_open
-(struct sieve_instance *svinst, const char *path, struct sieve_script *script)
+(struct sieve_instance *svinst, const char *path, struct sieve_script *script,
+	enum sieve_error *error_r)
 {
 	struct sieve_binary_extension_reg *const *regs;
 	unsigned int ext_count, i;
@@ -790,8 +858,7 @@ struct sieve_binary *sieve_binary_open
 	i_assert( script == NULL || sieve_script_svinst(script) == svinst );
 	
 	//file = _file_memory_open(path);	
-	file = _file_lazy_open(path);
-	if ( file == NULL )
+	if ( (file=_file_lazy_open(path, error_r)) == NULL ) 
 		return NULL;
 		
 	/* Create binary object */
@@ -801,6 +868,8 @@ struct sieve_binary *sieve_binary_open
 	
 	if ( !_sieve_binary_open(sbin) ) {
 		sieve_binary_unref(&sbin);
+		if ( error_r != NULL )
+			*error_r = SIEVE_ERROR_NOT_VALID;
 		return NULL;
 	}
 	
@@ -814,6 +883,10 @@ struct sieve_binary *sieve_binary_open
 		if ( binext != NULL && binext->binary_open != NULL && 
 			!binext->binary_open(regs[i]->extension, sbin, regs[i]->context) ) {
 			/* Extension thinks its corrupt */
+
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_NOT_VALID;
+
 			sieve_binary_unref(&sbin);
 			return NULL;
 		}
@@ -821,19 +894,3 @@ struct sieve_binary *sieve_binary_open
 
 	return sbin;
 }
-
-bool sieve_binary_load(struct sieve_binary *sbin)
-{
-	i_assert(sbin->file != NULL);
-
-	/*
-	if ( sbin->file->load != NULL && !sbin->file->load(sbin->file) )
-		return FALSE;	*/		
-	
-	if ( !_sieve_binary_load(sbin) ) {
-		/* Failed to interpret binary header and/or block structure */
-		return FALSE;
-	}
-	
-	return TRUE;
-}
diff --git a/src/lib-sieve/sieve-binary-private.h b/src/lib-sieve/sieve-binary-private.h
index c63cacb8d..97e08d3b2 100644
--- a/src/lib-sieve/sieve-binary-private.h
+++ b/src/lib-sieve/sieve-binary-private.h
@@ -22,7 +22,6 @@ struct sieve_binary_file {
 	int fd;
 	off_t offset;
 
-	bool (*load)(struct sieve_binary_file *file);	
 	const void *(*load_data)
 		(struct sieve_binary_file *file, off_t *offset, size_t size);
 	buffer_t *(*load_buffer)
@@ -30,7 +29,7 @@ struct sieve_binary_file {
 };
 
 bool sieve_binary_file_open
-	(struct sieve_binary_file *file, const char *path);
+	(struct sieve_binary_file *file, const char *path, enum sieve_error *error_r);
 void sieve_binary_file_close(struct sieve_binary_file **file);
 
 /* 
diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c
index 3f5631159..bf695be6a 100644
--- a/src/lib-sieve/sieve-binary.c
+++ b/src/lib-sieve/sieve-binary.c
@@ -142,6 +142,24 @@ const char *sieve_binary_path(struct sieve_binary *sbin)
 	return sbin->path;
 }
 
+bool sieve_binary_saved(struct sieve_binary *sbin)
+{
+	return ( sbin->path != NULL );
+}
+
+bool sieve_binary_loaded(struct sieve_binary *sbin)
+{
+	return ( sbin->file != NULL );
+}
+
+const char *sieve_binary_source(struct sieve_binary *sbin)
+{
+	if ( sbin->script != NULL && (sbin->path == NULL || sbin->file == NULL) )
+		return sieve_script_path(sbin->script);
+
+	return sbin->path;
+}
+
 struct sieve_instance *sieve_binary_svinst(struct sieve_binary *sbin)
 {
 	return sbin->svinst;
@@ -156,16 +174,12 @@ bool sieve_binary_script_newer
 
 const char *sieve_binary_script_name(struct sieve_binary *sbin)
 {
-	struct sieve_script *script = sieve_binary_script(sbin);
-
-	return ( script == NULL ? NULL : sieve_script_name(script) );
+	return ( sbin->script == NULL ? NULL : sieve_script_name(sbin->script) );
 }
 
 const char *sieve_binary_script_path(struct sieve_binary *sbin)
 {
-	struct sieve_script *script = sieve_binary_script(sbin);
-
-	return ( script == NULL ? NULL : sieve_script_path(script) );
+	return ( sbin->script == NULL ? NULL : sieve_script_path(sbin->script) );
 }
 
 /* 
@@ -215,11 +229,8 @@ static bool sieve_binary_block_fetch(struct sieve_binary_block *sblock)
 	if ( sbin->file ) {
 		/* Try to acces the block in the binary on disk (apperently we were lazy)
 		 */
-		if ( !sieve_binary_load_block(sblock) || sblock->data == NULL ) {
-			sieve_sys_error("block %d of loaded binary %s is corrupt", 
-				sblock->id, sbin->path);			
+		if ( !sieve_binary_load_block(sblock) || sblock->data == NULL )		
 			return FALSE;
-		}
 	} else {
 		sblock->data = buffer_create_dynamic(sbin->pool, 64);
 		return TRUE;
diff --git a/src/lib-sieve/sieve-binary.h b/src/lib-sieve/sieve-binary.h
index ae3b93314..3d63282d6 100644
--- a/src/lib-sieve/sieve-binary.h
+++ b/src/lib-sieve/sieve-binary.h
@@ -30,15 +30,19 @@ void sieve_binary_unref(struct sieve_binary **sbin);
  */
 
 pool_t sieve_binary_pool(struct sieve_binary *sbin);
-struct sieve_script *sieve_binary_script(struct sieve_binary *sbin);
+struct sieve_instance *sieve_binary_svinst(struct sieve_binary *sbin);
 const char *sieve_binary_path(struct sieve_binary *sbin);
+struct sieve_script *sieve_binary_script(struct sieve_binary *sbin);
+
 bool sieve_binary_script_newer
 	(struct sieve_binary *sbin, struct sieve_script *script);
-struct sieve_instance *sieve_binary_svinst(struct sieve_binary *sbin);
-
 const char *sieve_binary_script_name(struct sieve_binary *sbin);
 const char *sieve_binary_script_path(struct sieve_binary *sbin);
 
+const char *sieve_binary_source(struct sieve_binary *sbin);
+bool sieve_binary_loaded(struct sieve_binary *sbin);
+bool sieve_binary_saved(struct sieve_binary *sbin);
+
 /*
  * Activation after code generation
  */ 
@@ -49,8 +53,9 @@ void sieve_binary_activate(struct sieve_binary *sbin);
  * Saving the binary
  */
  
-bool sieve_binary_save
-	(struct sieve_binary *sbin, const char *path);
+int sieve_binary_save
+(struct sieve_binary *sbin, const char *path, bool update,
+	enum sieve_error *error_r);
 	
 /* 
  * Loading the binary
@@ -58,9 +63,8 @@ bool sieve_binary_save
 	
 struct sieve_binary *sieve_binary_open
 	(struct sieve_instance *svinst, const char *path, 
-		struct sieve_script *script);
+		struct sieve_script *script, enum sieve_error *error_r);
 bool sieve_binary_up_to_date(struct sieve_binary *sbin);
-bool sieve_binary_load(struct sieve_binary *sbin);
 	
 /* 
  * Block management 
diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h
index dab8d5d77..db4209e10 100644
--- a/src/lib-sieve/sieve-common.h
+++ b/src/lib-sieve/sieve-common.h
@@ -141,9 +141,11 @@ struct sieve_plugin;
 
 /* sieve.c */
 struct sieve_ast *sieve_parse
-	(struct sieve_script *script, struct sieve_error_handler *ehandler);
+	(struct sieve_script *script, struct sieve_error_handler *ehandler, 
+		enum sieve_error *error_r);
 bool sieve_validate
-	(struct sieve_ast *ast, struct sieve_error_handler *ehandler);	
+	(struct sieve_ast *ast, struct sieve_error_handler *ehandler,
+		enum sieve_error *error_r);	
 
 /*
  * Sieve engine instance
diff --git a/src/lib-sieve/sieve-lexer.c b/src/lib-sieve/sieve-lexer.c
index 9e8b0a655..f6633604e 100644
--- a/src/lib-sieve/sieve-lexer.c
+++ b/src/lib-sieve/sieve-lexer.c
@@ -61,7 +61,8 @@ struct sieve_lexical_scanner {
 };
 
 const struct sieve_lexer *sieve_lexer_create
-(struct sieve_script *script, struct sieve_error_handler *ehandler) 
+(struct sieve_script *script, struct sieve_error_handler *ehandler,
+	enum sieve_error *error_r) 
 {
 	pool_t pool;
 	struct sieve_lexical_scanner *scanner;
@@ -70,7 +71,7 @@ const struct sieve_lexer *sieve_lexer_create
 	const struct stat *st;
 
 	/* Open script as stream */
-	stream = sieve_script_open(script, NULL);
+	stream = sieve_script_open(script, error_r);
 	if ( stream == NULL )
 		return NULL;
 
@@ -81,6 +82,8 @@ const struct sieve_lexer *sieve_lexer_create
 		sieve_error(ehandler, sieve_script_name(script),
 			"sieve script is too large (max %"PRIuSIZE_T" bytes)",
 			svinst->max_script_size);
+		if ( error_r != NULL )
+			*error_r = SIEVE_ERROR_NOT_POSSIBLE;
 		return NULL;
 	}
 	
diff --git a/src/lib-sieve/sieve-lexer.h b/src/lib-sieve/sieve-lexer.h
index b96e9a821..8ae52baf8 100644
--- a/src/lib-sieve/sieve-lexer.h
+++ b/src/lib-sieve/sieve-lexer.h
@@ -59,7 +59,8 @@ struct sieve_lexer {
 };
 
 const struct sieve_lexer *sieve_lexer_create
-	(struct sieve_script *script, struct sieve_error_handler *ehandler);
+	(struct sieve_script *script, struct sieve_error_handler *ehandler, 
+		enum sieve_error *error_r);
 void sieve_lexer_free(const struct sieve_lexer **lexer);
 
 /* 
diff --git a/src/lib-sieve/sieve-parser.c b/src/lib-sieve/sieve-parser.c
index cc638b6fd..2e0f8cb95 100644
--- a/src/lib-sieve/sieve-parser.c
+++ b/src/lib-sieve/sieve-parser.c
@@ -45,12 +45,13 @@ struct sieve_parser {
 };
 
 struct sieve_parser *sieve_parser_create
-(struct sieve_script *script, struct sieve_error_handler *ehandler)
+(struct sieve_script *script, struct sieve_error_handler *ehandler,
+	enum sieve_error *error_r)
 {
 	struct sieve_parser *parser;
 	const struct sieve_lexer *lexer;
 	
-	lexer = sieve_lexer_create(script, ehandler);
+	lexer = sieve_lexer_create(script, ehandler, error_r);
   
 	if ( lexer != NULL ) {
 		pool_t pool = pool_alloconly_create("sieve_parser", 4096);	
diff --git a/src/lib-sieve/sieve-parser.h b/src/lib-sieve/sieve-parser.h
index 6c5e149e9..d0ab19f64 100644
--- a/src/lib-sieve/sieve-parser.h
+++ b/src/lib-sieve/sieve-parser.h
@@ -11,7 +11,8 @@
 struct sieve_parser;
 
 struct sieve_parser *sieve_parser_create
-	(struct sieve_script *script, struct sieve_error_handler *ehandler);
+	(struct sieve_script *script, struct sieve_error_handler *ehandler,
+		enum sieve_error *error_r);
 void sieve_parser_free(struct sieve_parser **parser);
 bool sieve_parser_run(struct sieve_parser *parser, struct sieve_ast **ast);
 
diff --git a/src/lib-sieve/sieve-script-private.h b/src/lib-sieve/sieve-script-private.h
index 47d2d4c8d..aef0d759a 100644
--- a/src/lib-sieve/sieve-script-private.h
+++ b/src/lib-sieve/sieve-script-private.h
@@ -38,6 +38,6 @@ struct sieve_script {
 struct sieve_script *sieve_script_init
 (struct sieve_script *script, struct sieve_instance *svinst,
 	const char *path, const char *name, struct sieve_error_handler *ehandler, 
-	bool *exists_r);
+	enum sieve_error *error_r);
 
 #endif /* __SIEVE_SCRIPT_PRIVATE_H */
diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c
index 1832dc9a7..cd2c28f68 100644
--- a/src/lib-sieve/sieve-script.c
+++ b/src/lib-sieve/sieve-script.c
@@ -112,6 +112,39 @@ static inline const char *_sieve_scriptfile_from_name(const char *name)
 	return name;
 }
 
+/*
+ * Common error handling
+ */
+
+static void sieve_script_handle_file_error
+(struct sieve_instance *svinst, const char *path, const char *name,
+	struct sieve_error_handler *ehandler, enum sieve_error *error_r)
+{
+	switch ( errno ) {
+	case ENOENT:
+		if ( error_r == NULL )
+			sieve_error(ehandler, name, "sieve script does not exist");
+		else {
+			if ( svinst->debug )
+				sieve_sys_debug("script file %s not found", t_abspath(path));
+			*error_r = SIEVE_ERROR_NOT_FOUND;
+		}
+		break;
+	case EACCES:
+		sieve_critical(ehandler, name, 
+			"failed to stat sieve script: %s",
+			eacces_error_get("stat", path));
+		if ( error_r != NULL )
+			*error_r = SIEVE_ERROR_NO_PERM;
+		break;
+	default:
+		sieve_critical(ehandler, name, 
+			"failed to stat sieve script: stat(%s) failed: %m", path);
+		if ( error_r != NULL )
+			*error_r = SIEVE_ERROR_TEMP_FAIL;
+		break;
+	}
+}
 
 /* 
  * Script object 
@@ -120,7 +153,7 @@ static inline const char *_sieve_scriptfile_from_name(const char *name)
 struct sieve_script *sieve_script_init
 (struct sieve_script *script, struct sieve_instance *svinst, 
 	const char *path, const char *name, struct sieve_error_handler *ehandler, 
-	bool *exists_r)
+	enum sieve_error *error_r)
 {
 	int ret;
 	pool_t pool;
@@ -128,8 +161,8 @@ struct sieve_script *sieve_script_init
 	struct stat lnk_st;
 	const char *filename, *dirpath, *basename, *binpath;
 
-	if ( exists_r != NULL )
-		*exists_r = TRUE;
+	if ( error_r != NULL )
+		*error_r = SIEVE_ERROR_NONE;
 
 	T_BEGIN {
 
@@ -162,25 +195,7 @@ struct sieve_script *sieve_script_init
 		/* First obtain stat data from the system */
 		
 		if ( (ret=lstat(path, &st)) < 0 ) {
-			switch ( errno ) {
-			case ENOENT:
-				if ( exists_r == NULL ) {
-					sieve_error(ehandler, basename, "sieve script does not exist");
-					if ( svinst->debug )
-						sieve_sys_debug("script file %s not found", t_abspath(path));
-				} else
-					*exists_r = FALSE;
-				break;
-			case EACCES:
-				sieve_critical(ehandler, basename, 
-					"failed to stat sieve script: %s",
-					eacces_error_get("lstat", path));
-				break;
-            default:
-				sieve_critical(ehandler, basename, 
-					"failed to stat sieve script: lstat(%s) failed: %m", path);
-			}
-
+			sieve_script_handle_file_error(svinst, path, basename, ehandler, error_r);
 			script = NULL;
 			ret = 1;
 
@@ -189,34 +204,18 @@ struct sieve_script *sieve_script_init
 			lnk_st = st;
 
 			/* Only create/init the object if it stat()s without problems */
-			if (S_ISLNK(st.st_mode)) {
-				if ( (ret=stat(path, &st)) < 0 ) { 
-					switch ( errno ) {
-					case ENOENT:
-						if ( exists_r == NULL )
-							sieve_error(ehandler, basename, "sieve script does not exist");
-						else
-							*exists_r = FALSE;
-						break;
-					case EACCES:
-						sieve_critical(ehandler, basename, 
-							"failed to stat sieve script: %s",
-							eacces_error_get("stat", path));
-						break;
-            		default:
-						sieve_critical(ehandler, basename, 
-							"failed to stat sieve script: stat(%s) failed: %m", path);
-						break;
-					}
-
-					script = NULL;	
-					ret = 1;
-				}
+			if ( S_ISLNK(st.st_mode) && (ret=stat(path, &st)) < 0 ) { 
+				sieve_script_handle_file_error
+					(svinst, path, basename, ehandler, error_r);
+				script = NULL;	
+				ret = 1;
 			}
 
 			if ( ret == 0 && !S_ISREG(st.st_mode) ) {
 				sieve_critical(ehandler, basename, 
 					"sieve script file '%s' is not a regular file.", path);
+				if ( error_r != NULL )
+					*error_r = SIEVE_ERROR_NOT_POSSIBLE;
 				script = NULL;
 				ret = 1;
 			} 
@@ -256,14 +255,14 @@ struct sieve_script *sieve_script_init
 
 struct sieve_script *sieve_script_create
 (struct sieve_instance *svinst, const char *path, const char *name, 
-	struct sieve_error_handler *ehandler, bool *exists_r)
+	struct sieve_error_handler *ehandler, enum sieve_error *error_r)
 {
-	return sieve_script_init(NULL, svinst, path, name, ehandler, exists_r);
+	return sieve_script_init(NULL, svinst, path, name, ehandler, error_r);
 }
 
 struct sieve_script *sieve_script_create_in_directory
 (struct sieve_instance *svinst, const char *dirpath, const char *name,
-	struct sieve_error_handler *ehandler, bool *exists_r)
+	struct sieve_error_handler *ehandler, enum sieve_error *error_r)
 {
 	const char *path;
 
@@ -274,7 +273,7 @@ struct sieve_script *sieve_script_create_in_directory
 		path = t_strconcat(dirpath, "/",
 			_sieve_scriptfile_from_name(name), NULL);
 
-	return sieve_script_init(NULL, svinst, path, name, ehandler, exists_r);
+	return sieve_script_init(NULL, svinst, path, name, ehandler, error_r);
 }
 
 void sieve_script_ref(struct sieve_script *script)
@@ -348,47 +347,35 @@ size_t sieve_script_size(const struct sieve_script *script)
  */
 
 struct istream *sieve_script_open
-(struct sieve_script *script, bool *deleted_r)
+(struct sieve_script *script, enum sieve_error *error_r)
 {
 	int fd;
 	struct stat st;
 	struct istream *result;
 
-	if ( deleted_r != NULL )
-		*deleted_r = FALSE;
+	if ( error_r != NULL )
+		*error_r = SIEVE_ERROR_NONE;
 
 	if ( (fd=open(script->path, O_RDONLY)) < 0 ) {
-		switch( errno ) {
-		case ENOENT:
-			if ( deleted_r == NULL ) 
-				/* Not supposed to occur, create() does stat already */
-				sieve_error(script->ehandler, script->basename, 
-					"sieve script does not exist");
-			else 
-				*deleted_r = TRUE;
-			break;
-		case EACCES:
-			sieve_critical(script->ehandler, script->path,
-				"failed to open sieve script: %s",
-				eacces_error_get("open", script->path));
-			break;
-		default:
-			sieve_critical(script->ehandler, script->path, 
-				"failed to open sieve script: open(%s) failed: %m", script->path);
-			break;
-		}
+		sieve_script_handle_file_error
+			(script->svinst, script->path, script->basename, script->ehandler, 
+				error_r);
 		return NULL;
 	}	
 	
 	if ( fstat(fd, &st) != 0 ) {
 		sieve_critical(script->ehandler, script->path, 
 			"failed to open sieve script: fstat(fd=%s) failed: %m", script->path);
+		if ( error_r != NULL )
+			*error_r = SIEVE_ERROR_TEMP_FAIL;
 		result = NULL;
 	} else {
 		/* Re-check the file type just to be sure */
 		if ( !S_ISREG(st.st_mode) ) {
 			sieve_critical(script->ehandler, script->path,
 				"sieve script file '%s' is not a regular file", script->path);
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_NOT_POSSIBLE;
 			result = NULL;
 		} else {
 			result = script->stream = 
diff --git a/src/lib-sieve/sieve-script.h b/src/lib-sieve/sieve-script.h
index eed50263c..e6d1515c5 100644
--- a/src/lib-sieve/sieve-script.h
+++ b/src/lib-sieve/sieve-script.h
@@ -23,11 +23,11 @@ struct sieve_script;
 
 struct sieve_script *sieve_script_create
 	(struct sieve_instance *svinst, const char *path, const char *name, 
-		struct sieve_error_handler *ehandler, bool *exists_r);
+		struct sieve_error_handler *ehandler, enum sieve_error *error_r);
 
 struct sieve_script *sieve_script_create_in_directory
 	(struct sieve_instance *svinst, const char *dirpath, const char *name,
-    	struct sieve_error_handler *ehandler, bool *exists_r);
+    	struct sieve_error_handler *ehandler, enum sieve_error *error_r);
 
 void sieve_script_ref(struct sieve_script *script);
 void sieve_script_unref(struct sieve_script **script);
@@ -57,7 +57,8 @@ size_t sieve_script_size(const struct sieve_script *script);
  * Stream management 
  */
 
-struct istream *sieve_script_open(struct sieve_script *script, bool *deleted_r);
+struct istream *sieve_script_open
+	(struct sieve_script *script, enum sieve_error *error_r);
 void sieve_script_close(struct sieve_script *script);
 
 uoff_t sieve_script_get_size(const struct sieve_script *script);
diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h
index 205a0e0e6..3ed8d5bb9 100644
--- a/src/lib-sieve/sieve-types.h
+++ b/src/lib-sieve/sieve-types.h
@@ -31,6 +31,35 @@ struct sieve_environment {
 	const char *(*get_setting)(void *context, const char *identifier);
 };
 
+/*
+ * Errors
+ */
+
+enum sieve_error {
+	SIEVE_ERROR_NONE = 0,
+
+	/* Temporary internal error */
+	SIEVE_ERROR_TEMP_FAIL,
+	/* It's not possible to do the wanted operation */
+	SIEVE_ERROR_NOT_POSSIBLE,
+	/* Invalid parameters (eg. script name not valid) */
+	SIEVE_ERROR_BAD_PARAMS,
+	/* No permission to do the request */
+	SIEVE_ERROR_NO_PERM,
+	/* Out of disk space */
+	SIEVE_ERROR_NO_SPACE,
+	/* Out of disk space */
+	SIEVE_ERROR_NO_QUOTA,
+	/* Item (e.g. script or binary) cannot be found */
+	SIEVE_ERROR_NOT_FOUND,
+	/* Item (e.g. script or binary) already exists */
+	SIEVE_ERROR_EXISTS,
+	/* Referenced item (e.g. script or binary) is not valid or currupt */
+	SIEVE_ERROR_NOT_VALID,
+	/* Not allowed to perform the operation because the item is in active use */
+	SIEVE_ERROR_ACTIVE
+};
+
 /* 
  * Message data
  *
diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c
index 93e8bfb70..bf70ef8e0 100644
--- a/src/lib-sieve/sieve.c
+++ b/src/lib-sieve/sieve.c
@@ -118,41 +118,58 @@ const char *sieve_get_capabilities
  */
 
 struct sieve_ast *sieve_parse
-(struct sieve_script *script, struct sieve_error_handler *ehandler)
+(struct sieve_script *script, struct sieve_error_handler *ehandler,
+	enum sieve_error *error_r)
 {
 	struct sieve_parser *parser;
 	struct sieve_ast *ast = NULL;
 	
 	/* Parse */
-	if ( (parser = sieve_parser_create(script, ehandler)) == NULL )
+	if ( (parser = sieve_parser_create(script, ehandler, error_r)) == NULL )
 		return NULL;
 
- 	if ( !sieve_parser_run(parser, &ast) || sieve_get_errors(ehandler) > 0 ) {
+ 	if ( !sieve_parser_run(parser, &ast) ) {
  		ast = NULL;
  	} else 
 		sieve_ast_ref(ast);
 	
 	sieve_parser_free(&parser); 	
+
+	if ( error_r != NULL ) {
+		if ( ast == NULL )
+			*error_r = SIEVE_ERROR_NOT_VALID;
+		else
+			*error_r = SIEVE_ERROR_NONE;
+	}
 	
 	return ast;
 }
 
 bool sieve_validate
-(struct sieve_ast *ast, struct sieve_error_handler *ehandler)
+(struct sieve_ast *ast, struct sieve_error_handler *ehandler,
+	enum sieve_error *error_r)
 {
 	bool result = TRUE;
 	struct sieve_validator *validator = sieve_validator_create(ast, ehandler);
 		
-	if ( !sieve_validator_run(validator) || sieve_get_errors(ehandler) > 0 ) 
+	if ( !sieve_validator_run(validator) ) 
 		result = FALSE;
 	
 	sieve_validator_free(&validator);	
+
+	if ( error_r != NULL ) {
+		if ( !result )
+			*error_r = SIEVE_ERROR_NOT_VALID;
+		else
+			*error_r = SIEVE_ERROR_NONE;
+	}
 		
 	return result;
 }
 
 static struct sieve_binary *sieve_generate
-(struct sieve_ast *ast, struct sieve_error_handler *ehandler)
+(struct sieve_ast *ast, struct sieve_error_handler *ehandler, 
+	enum sieve_error *error_r)
 {
 	struct sieve_generator *generator = sieve_generator_create(ast, ehandler);
 	struct sieve_binary *sbin = NULL;
@@ -161,6 +178,13 @@ static struct sieve_binary *sieve_generate
 	
 	sieve_generator_free(&generator);
 	
+	if ( error_r != NULL ) {
+		if ( sbin == NULL )
+			*error_r = SIEVE_ERROR_NOT_VALID;
+		else
+			*error_r = SIEVE_ERROR_NONE;
+	}
+
 	return sbin;
 }
 
@@ -169,19 +193,20 @@ static struct sieve_binary *sieve_generate
  */
 
 struct sieve_binary *sieve_compile_script
-(struct sieve_script *script, struct sieve_error_handler *ehandler) 
+(struct sieve_script *script, struct sieve_error_handler *ehandler,
+	enum sieve_error *error_r) 
 {
 	struct sieve_ast *ast;
-	struct sieve_binary *sbin;		
-  	
+	struct sieve_binary *sbin;  	
+
 	/* Parse */
-	if ( (ast = sieve_parse(script, ehandler)) == NULL ) {
+	if ( (ast = sieve_parse(script, ehandler, error_r)) == NULL ) {
  		sieve_error(ehandler, sieve_script_name(script), "parse failed");
 		return NULL;
 	}
 
 	/* Validate */
-	if ( !sieve_validate(ast, ehandler) ) {
+	if ( !sieve_validate(ast, ehandler, error_r) ) {
 		sieve_error(ehandler, sieve_script_name(script), "validation failed");
 		
  		sieve_ast_unref(&ast);
@@ -189,31 +214,35 @@ struct sieve_binary *sieve_compile_script
  	}
  	
 	/* Generate */
-	if ( (sbin=sieve_generate(ast, ehandler)) == NULL ) {
+	if ( (sbin=sieve_generate(ast, ehandler, error_r)) == NULL ) {
 		sieve_error(ehandler, sieve_script_name(script), "code generation failed");
 		
 		sieve_ast_unref(&ast);
 		return NULL;
 	}
-	
+
 	/* Cleanup */
 	sieve_ast_unref(&ast);
 
+	if ( error_r != NULL )
+		error_r = SIEVE_ERROR_NONE;
+
 	return sbin;
 }
 
 struct sieve_binary *sieve_compile
 (struct sieve_instance *svinst, const char *script_path,
-	const char *script_name, struct sieve_error_handler *ehandler)
+	const char *script_name, struct sieve_error_handler *ehandler,
+	enum sieve_error *error_r)
 {
 	struct sieve_script *script;
 	struct sieve_binary *sbin;
 
 	if ( (script = sieve_script_create
-		(svinst, script_path, script_name, ehandler, NULL)) == NULL )
+		(svinst, script_path, script_name, ehandler, error_r)) == NULL )
 		return NULL;
 	
-	sbin = sieve_compile_script(script, ehandler);
+	sbin = sieve_compile_script(script, ehandler, error_r);
 	
 	sieve_script_unref(&script);
 
@@ -266,9 +295,16 @@ static int sieve_run
  * Reading/writing sieve binaries
  */
 
+struct sieve_binary *sieve_load
+(struct sieve_instance *svinst, const char *bin_path, enum sieve_error *error_r)
+{
+	return sieve_binary_open(svinst, bin_path, NULL, error_r);
+}
+
 struct sieve_binary *sieve_open
 (struct sieve_instance *svinst, const char *script_path, 
-	const char *script_name, struct sieve_error_handler *ehandler, bool *exists_r)
+	const char *script_name, struct sieve_error_handler *ehandler,
+	enum sieve_error *error_r)
 {
 	struct sieve_script *script;
 	struct sieve_binary *sbin;
@@ -276,7 +312,7 @@ struct sieve_binary *sieve_open
 	
 	/* First open the scriptfile itself */
 	script = sieve_script_create
-		(svinst, script_path, script_name, ehandler, exists_r);
+		(svinst, script_path, script_name, ehandler, error_r);
 
 	if ( script == NULL ) {
 		/* Failed */
@@ -286,7 +322,7 @@ struct sieve_binary *sieve_open
 	T_BEGIN {
 		/* Then try to open the matching binary */
 		bin_path = sieve_script_binpath(script);	
-		sbin = sieve_binary_open(svinst, bin_path, script);
+		sbin = sieve_binary_open(svinst, bin_path, script, error_r);
 	
 		if (sbin != NULL) {
 			/* Ok, it exists; now let's see if it is up to date */
@@ -297,15 +333,10 @@ struct sieve_binary *sieve_open
 
 				sieve_binary_unref(&sbin);
 				sbin = NULL;
-
-			} else if ( !sieve_binary_load(sbin) ) {
-				/* Failed to load */
-				sieve_binary_unref(&sbin);
-				sbin = NULL;
-			}
+			} 
 		}
 		
-		/* If the binary does not exist, is not up-to-date or fails to load, we need
+		/* If the binary does not exist or is not up-to-date, we need
 		 * to (re-)compile.
 		 */
 		if ( sbin != NULL ) {
@@ -313,19 +344,12 @@ struct sieve_binary *sieve_open
 				sieve_sys_debug("script binary %s successfully loaded", bin_path);
 			
 		} else {	
-			sbin = sieve_compile_script(script, ehandler);
+			sbin = sieve_compile_script(script, ehandler, error_r);
 
 			/* Save the binary if compile was successful */
 			if ( sbin != NULL ) {
 				if ( svinst->debug )
 					sieve_sys_debug("script %s successfully compiled", script_path);
-
-				if ( sieve_binary_save(sbin, bin_path) ) {
-					if ( svinst->debug ) {
-						sieve_sys_debug
-							("compiled script saved as binary file %s", bin_path);
-					}
-				}
 			}
 		}
 	} T_END;
@@ -336,25 +360,23 @@ struct sieve_binary *sieve_open
 	sieve_script_unref(&script);
 
 	return sbin;
-} 
+}
 
-bool sieve_save
-(struct sieve_binary *sbin, const char *bin_path)
+const char *sieve_get_source(struct sieve_binary *sbin)
 {
-	return sieve_binary_save(sbin, bin_path);
+	return sieve_binary_source(sbin);
 }
 
-struct sieve_binary *sieve_load
-(struct sieve_instance *svinst, const char *bin_path)
+bool sieve_is_loaded(struct sieve_binary *sbin)
 {
-	struct sieve_binary *sbin = sieve_binary_open(svinst, bin_path, NULL);
-
-    if ( sbin != NULL && !sieve_binary_load(sbin) ) {
-        sieve_binary_unref(&sbin);
-        sbin = NULL;
-    }
+	return sieve_binary_loaded(sbin);
+}
 
-	return sbin;
+int sieve_save
+(struct sieve_binary *sbin, const char *bin_path, bool update,
+	enum sieve_error *error_r)
+{
+	return sieve_binary_save(sbin, bin_path, update, error_r);
 }
 
 void sieve_close(struct sieve_binary **sbin)
@@ -623,24 +645,34 @@ struct sieve_directory {
 		const char *path;
 };
 
-struct sieve_directory *sieve_directory_open(const char *path)
+struct sieve_directory *sieve_directory_open
+(const char *path, enum sieve_error *error_r)
 { 
 	struct sieve_directory *sdir = NULL;
 	DIR *dirp;
 	struct stat st;
 
+	if ( error_r != NULL )
+		*error_r = SIEVE_ERROR_NONE;
+
 	/* Specified path can either be a regular file or a directory */
 	if ( stat(path, &st) != 0 ) {
 		switch ( errno ) {
 		case ENOENT:
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_NOT_FOUND;
 			break;
 		case EACCES:
 			sieve_sys_error("failed to open sieve dir: %s",
 				eacces_error_get("stat", path));
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_NO_PERM;
 			break;
 		default:
 			sieve_sys_error("failed to open sieve dir: "
 				"stat(%s) failed: %m", path);
+			if ( error_r != NULL )
+				*error_r = SIEVE_ERROR_TEMP_FAIL;
 			break;
 		}
 		return NULL;
@@ -650,8 +682,24 @@ struct sieve_directory *sieve_directory_open(const char *path)
 	 	
 		/* Open the directory */
 		if ( (dirp = opendir(path)) == NULL ) {
-			sieve_sys_error("failed to open sieve dir: "
-				"opendir(%s) failed: %m", path);
+			switch ( errno ) {
+			case ENOENT:
+				if ( error_r != NULL )
+					*error_r = SIEVE_ERROR_NOT_FOUND;
+				break;
+			case EACCES:
+				sieve_sys_error("failed to open sieve dir: %s",
+					eacces_error_get("opendir", path));
+				if ( error_r != NULL )
+					*error_r = SIEVE_ERROR_NO_PERM;
+				break;
+			default:
+				sieve_sys_error("failed to open sieve dir: "
+					"opendir(%s) failed: %m", path);
+				if ( error_r != NULL )
+					*error_r = SIEVE_ERROR_TEMP_FAIL;
+				break;
+			}
 			return NULL;		
 		}
 	
@@ -680,12 +728,12 @@ const char *sieve_directory_get_scriptfile(struct sieve_directory *sdir)
 
 			errno = 0;
 			if ( (dp = readdir(sdir->dirp)) == NULL ) {
-				if ( errno != 0 ) { 
+				if ( errno != 0 ) {
 					sieve_sys_error("failed to read sieve dir: "
 						"readdir(%s) failed: %m", sdir->path);
-					continue;
-				} else 
-					return NULL;
+				}
+
+				return NULL;
 			}
 
 			if ( !sieve_script_file_has_extension(dp->d_name) )
diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h
index aa47978ea..8f3b4dc2f 100644
--- a/src/lib-sieve/sieve.h
+++ b/src/lib-sieve/sieve.h
@@ -48,7 +48,8 @@ void sieve_set_extensions
 /* sieve_compile_script:
  */
 struct sieve_binary *sieve_compile_script
-	(struct sieve_script *script, struct sieve_error_handler *ehandler);
+	(struct sieve_script *script, struct sieve_error_handler *ehandler,
+		enum sieve_error *error_r);
 
 /* sieve_compile:
  *
@@ -56,40 +57,42 @@ struct sieve_binary *sieve_compile_script
  */
 struct sieve_binary *sieve_compile
 	(struct sieve_instance *svinst, const char *script_path, 
-		const char *script_name, struct sieve_error_handler *ehandler);
+		const char *script_name, struct sieve_error_handler *ehandler,
+		enum sieve_error *error_r);
 
 /* 
  * Reading/writing Sieve binaries
  */
 
-/* sieve_open:
+/* sieve_load:
  *
- *   First tries to open the binary version of the specified script and
- *   if it does not exist or if it contains errors, the script is
- *   (re-)compiled. The binary is updated if the script is recompiled.
- *   Note that errors in the bytecode are not caught here.
+ *  Loads the sieve binary indicated by the provided path.
+ */
+struct sieve_binary *sieve_load
+	(struct sieve_instance *svinst, const char *bin_path,
+		enum sieve_error *error_r);
+
+/* sieve_open:
  *
+ *   First tries to open the binary version of the specified script and if it 
+ *   does not exist or if it contains errors, the script is (re-)compiled. Note 
+ *   that errors in the bytecode are caught only at runtime.
  */
 struct sieve_binary *sieve_open
 	(struct sieve_instance *svinst, const char *script_path, 
 		const char *script_name, struct sieve_error_handler *ehandler, 
-		bool *exists_r);
+		enum sieve_error *error_r);
 
 /* sieve_save:
  *
  *  Saves the binary as the file indicated by the path parameter. If 
  *  path is NULL, it chooses the default path relative to the original
- *  script.
- */
-bool sieve_save
-    (struct sieve_binary *sbin, const char *bin_path);
-
-/* sieve_load:
- *
- *  Loads the sieve binary indicated by the provided path.
+ *  script. This function will not write the binary to disk when it was
+ *  loaded from the indicated bin_path, unless update is TRUE. 
  */
-struct sieve_binary *sieve_load
-	(struct sieve_instance *svinst, const char *bin_path);
+int sieve_save
+    (struct sieve_binary *sbin, const char *bin_path, bool update,
+			enum sieve_error *error_r);
 
 /* sieve_close:
  *
@@ -97,6 +100,19 @@ struct sieve_binary *sieve_load
  */
 void sieve_close(struct sieve_binary **sbin);
 
+/* sieve_get_source:
+ *
+ *   Obtains the path the binary was compiled or loaded from
+ */
+const char *sieve_get_source(struct sieve_binary *sbin);
+
+/*
+ * sieve_is_loeded:
+ *
+ *   Indicates whether the binary was loaded from a pre-compiled file. 
+ */
+bool sieve_is_loaded(struct sieve_binary *sbin);
+
 /*
  * Debugging
  */
@@ -166,7 +182,8 @@ size_t sieve_max_script_size(struct sieve_instance *svinst);
 
 struct sieve_directory;
 
-struct sieve_directory *sieve_directory_open(const char *path);
+struct sieve_directory *sieve_directory_open
+	(const char *path, enum sieve_error *error_r);
 const char *sieve_directory_get_scriptfile(struct sieve_directory *sdir);
 void sieve_directory_close(struct sieve_directory **sdir);
 
diff --git a/src/lib-sievestorage/Makefile.am b/src/lib-sievestorage/Makefile.am
index 7636f5744..98f40e556 100644
--- a/src/lib-sievestorage/Makefile.am
+++ b/src/lib-sievestorage/Makefile.am
@@ -13,7 +13,6 @@ libsievestorage_a_SOURCES = \
 	sieve-storage.c 
 
 noinst_HEADERS = \
-	sieve-storage-error.h \
 	sieve-storage-save.h \
 	sieve-storage-script.h \
 	sieve-storage-list.h \
diff --git a/src/lib-sievestorage/sieve-storage-error.h b/src/lib-sievestorage/sieve-storage-error.h
deleted file mode 100644
index a088e9824..000000000
--- a/src/lib-sievestorage/sieve-storage-error.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file
- */
-
-#ifndef __SIEVE_STORAGE_ERROR_H
-#define __SIEVE_STORAGE_ERROR_H
-
-enum sieve_storage_error {
-	SIEVE_STORAGE_ERROR_NONE = 0,
-
-	/* Temporary internal error */
-	SIEVE_STORAGE_ERROR_TEMP,
-
-	/* It's not possible to do the wanted operation */
-	SIEVE_STORAGE_ERROR_IMPOSSIBLE,
-
-	/* Quota exceeded */
-	SIEVE_STORAGE_ERROR_QUOTA,
-
-	/* Out of disk space */	
-	SIEVE_STORAGE_ERROR_NOSPACE,
-
-	/* Script does not exist */
-	SIEVE_STORAGE_ERROR_NOTFOUND,
-
-	/* Operation not allowed on active script */
-	SIEVE_STORAGE_ERROR_ACTIVE,
-
-	/* Operation not allowed on existing script */
-	SIEVE_STORAGE_ERROR_EXISTS
-};
-
-#endif /* __SIEVE_STORAGE_ERROR_H */
diff --git a/src/lib-sievestorage/sieve-storage-list.c b/src/lib-sievestorage/sieve-storage-list.c
index ef7cf1aa9..6efc630b1 100644
--- a/src/lib-sievestorage/sieve-storage-list.c
+++ b/src/lib-sievestorage/sieve-storage-list.c
@@ -25,25 +25,22 @@ struct sieve_list_context {
 };
 
 struct sieve_list_context *sieve_storage_list_init
-	(struct sieve_storage *storage)
+(struct sieve_storage *storage)
 {	
 	struct sieve_list_context *ctx;
-	const char *active;
+	const char *active = NULL;
 	pool_t pool;
 	DIR *dirp;
 
 	/* Open the directory */
 	if ( (dirp = opendir(storage->dir)) == NULL ) {
-		sieve_storage_set_critical(storage, "opendir(%s) failed: %m",
-					   storage->dir);
+		sieve_storage_set_critical(storage, "opendir(%s) failed: %m", storage->dir);
 		return NULL;
 	}
 
 	T_BEGIN {
-
 		/* Get the name of the active script */
-		if ( (active = sieve_storage_get_active_scriptfile(storage)) 
-			== NULL ) {
+		if ( sieve_storage_get_active_scriptfile(storage, &active) < 0) {
 			ctx = NULL;
 		} else {
 			pool = pool_alloconly_create("sieve_list_context", 4096);
@@ -51,7 +48,7 @@ struct sieve_list_context *sieve_storage_list_init
 			ctx->pool = pool;
 			ctx->storage = storage;
 			ctx->dirp = dirp;
-			ctx->active = p_strdup(pool, active);
+			ctx->active = ( active != NULL ? p_strdup(pool, active) : NULL );
 			ctx->seen_active = FALSE;
 		}
 	} T_END;
@@ -60,7 +57,7 @@ struct sieve_list_context *sieve_storage_list_init
 }
 
 const char *sieve_storage_list_next
-	(struct sieve_list_context *ctx, bool *active)
+(struct sieve_list_context *ctx, bool *active)
 {
 	const struct sieve_storage *storage = ctx->storage;
 	struct dirent *dp;
@@ -87,8 +84,7 @@ const char *sieve_storage_list_next
 		}
 	}
 
-	if ( ctx->active != NULL && 
-		strcmp(dp->d_name, ctx->active) == 0 ) {
+	if ( ctx->active != NULL && strcmp(dp->d_name, ctx->active) == 0 ) {
 		*active = TRUE;
 		ctx->active = NULL;
 	}
@@ -100,7 +96,7 @@ int sieve_storage_list_deinit(struct sieve_list_context **ctx)
 {
 	if (closedir((*ctx)->dirp) < 0) {
 		sieve_storage_set_critical((*ctx)->storage, "closedir(%s) failed: %m",
-					   (*ctx)->storage->dir);
+			(*ctx)->storage->dir);
 	}
 
 	pool_unref(&(*ctx)->pool);
diff --git a/src/lib-sievestorage/sieve-storage-private.h b/src/lib-sievestorage/sieve-storage-private.h
index b359b2903..fe12d55ae 100644
--- a/src/lib-sievestorage/sieve-storage-private.h
+++ b/src/lib-sievestorage/sieve-storage-private.h
@@ -49,16 +49,14 @@ struct sieve_storage {
 	uint64_t max_scripts;
 	uint64_t max_storage;
 
-	enum sieve_storage_error error_code;
-
+	enum sieve_error error_code;
 	struct sieve_error_handler *ehandler;
 
 	enum sieve_storage_flags flags;
 };
 
 struct sieve_script *sieve_storage_script_init_from_path
-	(struct sieve_storage *storage, const char *path, 
-		const char *scriptname, bool *exists_r);
+	(struct sieve_storage *storage, const char *path, const char *scriptname);
 
 #endif
 
diff --git a/src/lib-sievestorage/sieve-storage-quota.c b/src/lib-sievestorage/sieve-storage-quota.c
index 92a931934..ccd9aa1be 100644
--- a/src/lib-sievestorage/sieve-storage-quota.c
+++ b/src/lib-sievestorage/sieve-storage-quota.c
@@ -22,10 +22,10 @@ bool sieve_storage_quota_validsize
 	uint64_t max_size;
 
 	max_size = sieve_max_script_size(storage->svinst);
-    if ( max_size > 0 && size > max_size ) {
+	if ( max_size > 0 && size > max_size ) {
 		*limit_r = max_size;
-        return FALSE;
-    }
+		return FALSE;
+	}
 
 	return TRUE;
 }
diff --git a/src/lib-sievestorage/sieve-storage-save.c b/src/lib-sievestorage/sieve-storage-save.c
index 8ae489b77..1476f6609 100644
--- a/src/lib-sievestorage/sieve-storage-save.c
+++ b/src/lib-sievestorage/sieve-storage-save.c
@@ -8,6 +8,7 @@
 #include "buffer.h"
 #include "ostream.h"
 #include "str.h"
+#include "eacces-error.h"
 
 #include "sieve-script.h"
 
@@ -112,7 +113,7 @@ static int sieve_storage_create_tmp
 	*fpath_r = str_c(path);
 	if (fd == -1) {
 		if (ENOSPACE(errno)) {
-			sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_NOSPACE,
+			sieve_storage_set_error(storage, SIEVE_ERROR_NO_SPACE,
 				"Not enough disk space");
 		} else {
 			sieve_storage_set_critical(storage,
@@ -140,12 +141,15 @@ static int sieve_storage_script_move(struct sieve_save_context *ctx,
 			failed = FALSE;
 		else {
 			failed = TRUE;
-			if (ENOSPACE(errno)) {
+			if ( ENOSPACE(errno) ) {
 				sieve_storage_set_error
-				  (ctx->storage, SIEVE_STORAGE_ERROR_NOSPACE, "Not enough disk space");
+				  (ctx->storage, SIEVE_ERROR_NO_SPACE, "Not enough disk space");
+			} else if ( errno == EACCES ) {
+				sieve_storage_set_critical
+				  (ctx->storage, "%s", eacces_error_get("rename", dst));
 			} else {
 				sieve_storage_set_critical
-				  (ctx->storage, "link(%s, %s) failed: %m", ctx->tmp_path, dst);
+				  (ctx->storage, "rename(%s, %s) failed: %m", ctx->tmp_path, dst);
 			}
 		}
 
@@ -169,7 +173,7 @@ sieve_storage_save_init(struct sieve_storage *storage,
 		/* Validate script name */
 		if ( !sieve_script_name_is_valid(scriptname) ) {
 			sieve_storage_set_error(storage, 
-				SIEVE_STORAGE_ERROR_IMPOSSIBLE,
+				SIEVE_ERROR_BAD_PARAMS,
 				"Invalid script name '%s'.", scriptname);
 			return NULL;
 		}
@@ -188,7 +192,7 @@ sieve_storage_save_init(struct sieve_storage *storage,
 				strncmp(scriptname, storage->active_fname, namelen) == 0 ) 
 			{
 				sieve_storage_set_error(
-					storage, SIEVE_STORAGE_ERROR_IMPOSSIBLE, 
+					storage, SIEVE_ERROR_BAD_PARAMS, 
 					"Script name '%s' is reserved for internal use.", scriptname); 
 				return NULL;
 			}
@@ -263,7 +267,7 @@ int sieve_storage_save_finish(struct sieve_save_context *ctx)
 
 			errno = output_errno;
 			if ( ENOSPACE(errno) ) {
-				sieve_storage_set_error(ctx->storage, SIEVE_STORAGE_ERROR_NOSPACE,
+				sieve_storage_set_error(ctx->storage, SIEVE_ERROR_NO_SPACE,
 					"Not enough disk space");
 			} else if ( errno != 0 ) {
 				sieve_storage_set_critical(ctx->storage,
@@ -289,7 +293,6 @@ struct sieve_script *sieve_storage_save_get_tempscript
 {
 	const char *scriptname = 
 		( ctx->scriptname == NULL ? "" : ctx->scriptname ); 
-	bool exists = FALSE;
 
 	if (ctx->failed) 
 		return NULL;
@@ -298,14 +301,15 @@ struct sieve_script *sieve_storage_save_get_tempscript
 		return ctx->scriptobject;
 
 	ctx->scriptobject = sieve_storage_script_init_from_path
-		(ctx->storage, ctx->tmp_path, scriptname, &exists);	
-
-	if ( !exists ) {
-		sieve_storage_set_critical(ctx->storage, 
-			"save: Temporary script file with name '%s' got lost, "
-			"which should not happen (possibly deleted externally).", 
-			ctx->tmp_path);
-		sieve_script_unref(&ctx->scriptobject);
+		(ctx->storage, ctx->tmp_path, scriptname);	
+
+	if ( ctx->scriptobject == NULL ) {
+		if ( ctx->storage->error_code == SIEVE_ERROR_NOT_FOUND ) {
+			sieve_storage_set_critical(ctx->storage, 
+				"save: Temporary script file with name '%s' got lost, "
+				"which should not happen (possibly deleted externally).", 
+				ctx->tmp_path);
+		}
 		return NULL;
 	}
 
diff --git a/src/lib-sievestorage/sieve-storage-script.c b/src/lib-sievestorage/sieve-storage-script.c
index 0b6a6eba6..7ce41d902 100644
--- a/src/lib-sievestorage/sieve-storage-script.c
+++ b/src/lib-sievestorage/sieve-storage-script.c
@@ -7,6 +7,7 @@
 #include "ioloop.h"
 #include "istream.h"
 #include "file-copy.h"
+#include "eacces-error.h"
 
 #include "sieve-script-private.h"
 
@@ -30,10 +31,11 @@ struct sieve_storage_script {
 
 struct sieve_script *sieve_storage_script_init_from_path
 (struct sieve_storage *storage, const char *path, 
-	const char *scriptname, bool *exists_r)
+	const char *scriptname)
 {
 	pool_t pool;
 	struct sieve_storage_script *st_script = NULL;	
+	enum sieve_error error;
 
 	/* Prevent initializing the active script link as a script when it
 	 * resides in the sieve storage directory.
@@ -48,8 +50,8 @@ struct sieve_script *sieve_storage_script_init_from_path
 			fname++;
 
 		if ( strcmp(fname, storage->active_fname) == 0 ) {
-			if ( exists_r != NULL )
-				*exists_r = FALSE;
+			sieve_storage_set_error
+				(storage, SIEVE_ERROR_NOT_FOUND, "Script does not exist.");
 			return NULL;
 		}
 	}
@@ -60,26 +62,27 @@ struct sieve_script *sieve_storage_script_init_from_path
 	st_script->storage = storage;
 
 	if ( sieve_script_init(&st_script->script, storage->svinst, path, scriptname, 
-		sieve_storage_get_error_handler(storage), exists_r) != NULL ) {
-
+		sieve_storage_get_error_handler(storage), &error) != NULL ) {
 		return &st_script->script;
 	}
 
 	pool_unref(&pool);
 
+	if ( error == SIEVE_ERROR_NOT_FOUND )
+		sieve_storage_set_error(storage, error, "Script does not exist.");
+
 	return NULL;
 }
 
 struct sieve_script *sieve_storage_script_init
-(struct sieve_storage *storage, const char *scriptname, bool *exists_r)
+(struct sieve_storage *storage, const char *scriptname)
 {	
 	struct sieve_script *script;
 	const char *path;
 
 	/* Validate script name */	
 	if ( !sieve_script_name_is_valid(scriptname) ) {
-		sieve_storage_set_error(storage, 
-			SIEVE_STORAGE_ERROR_IMPOSSIBLE,
+		sieve_storage_set_error(storage, SIEVE_ERROR_BAD_PARAMS,
 			"Invalid script name '%s'.", scriptname);
 		return NULL;
 	}
@@ -87,15 +90,14 @@ struct sieve_script *sieve_storage_script_init
 	T_BEGIN {
 		path = t_strconcat( storage->dir, "/", scriptname, ".sieve", NULL );
 
-		script = sieve_storage_script_init_from_path
-			(storage, path, NULL, exists_r);
+		script = sieve_storage_script_init_from_path(storage, path, NULL);
 	} T_END;
 
 	return script;
 }
 
 static struct sieve_script *sieve_storage_script_init_from_file
-(struct sieve_storage *storage, const char *scriptfile, bool *exists_r)
+(struct sieve_storage *storage, const char *scriptfile)
 {	
 	struct sieve_script *script;
 	const char *path;
@@ -103,8 +105,7 @@ static struct sieve_script *sieve_storage_script_init_from_file
 	T_BEGIN {
 		path = t_strconcat( storage->dir, "/", scriptfile, NULL );
 
-		script = sieve_storage_script_init_from_path
-			(storage, path, NULL, exists_r);
+		script = sieve_storage_script_init_from_path(storage, path, NULL);
 	} T_END;
 
 	return script;
@@ -123,14 +124,13 @@ const char *sieve_storage_file_get_scriptname
 	return t_strdup_until(filename, ext);
 }
 
-static const char *sieve_storage_read_active_link
-(struct sieve_storage *storage, bool *not_link)
+static int sieve_storage_read_active_link
+(struct sieve_storage *storage, const char **link_r)
 {
   char linkbuf[PATH_MAX];
   int ret;
 
-	if ( not_link != NULL )
-		*not_link = FALSE;
+	*link_r = NULL;
 
 	ret = readlink(storage->active_path, linkbuf, sizeof(linkbuf));
 
@@ -143,25 +143,24 @@ static const char *sieve_storage_read_active_link
 			i_warning
 			  ("sieve-storage: Active sieve script symlink %s is no symlink.",
 			   storage->active_path);
-			if ( not_link != NULL )
-				*not_link = TRUE;
-			return "";
+			return 0;
 		}
 
-		if (errno != ENOENT ) {
-			/* We do need to panic otherwise */
-			sieve_storage_set_critical
-			  (storage,
-			  	"Performing readlink() on active sieve symlink '%s' failed: %m", 
-					storage->active_path);
-			return NULL;
+		if (errno == ENOENT ) {
+			/* Symlink not found */
+			return 0;
 		}
 
-		return "";
+		/* We do need to panic otherwise */
+		sieve_storage_set_critical(storage,
+			"Performing readlink() on active sieve symlink '%s' failed: %m", 
+			storage->active_path);
+		return -1;
 	}
 
 	/* ret is now assured to be valid, i.e. > 0 */
-	return t_strndup(linkbuf, ret);
+	*link_r = t_strndup(linkbuf, ret);
+	return 1;
 }
 
 static const char *sieve_storage_parse_link
@@ -204,16 +203,17 @@ static const char *sieve_storage_parse_link
 	return fname;
 }
 
-const char *sieve_storage_get_active_scriptfile
-(struct sieve_storage *storage)
+int sieve_storage_get_active_scriptfile
+(struct sieve_storage *storage, const char **file_r)
 {
 	const char *link, *scriptfile;
+	int ret;
 
-	/* Read the active link */
-	link = sieve_storage_read_active_link(storage, NULL);
+	*file_r = NULL;
 
-	if ( link == NULL || *link == '\0' ) 
-		return link;
+	/* Read the active link */
+	if ( (ret=sieve_storage_read_active_link(storage, &link)) <= 0 )
+		return ret;
 
 	/* Parse the link */
 	scriptfile = sieve_storage_parse_link(storage, link);
@@ -223,37 +223,30 @@ const char *sieve_storage_get_active_scriptfile
 		 * ignore this situation and report 'no active script'.
 		 * Activation should fix this situation.
 		 */
-		return "";
+		return 0;
 	}
 
-	return scriptfile;
+	*file_r = scriptfile;
+	return 1;
 }
 
 struct sieve_script *sieve_storage_get_active_script
-(struct sieve_storage *storage, bool *no_active)
+(struct sieve_storage *storage)
 {
-	bool exists, no_link;
 	struct sieve_script *script;
 	const char *scriptfile, *link;
+	int ret;
 
-	*no_active = FALSE;
+	sieve_storage_clear_error(storage);
 
 	/* Read the active link */
-	link = sieve_storage_read_active_link(storage, &no_link);
-	
-	if ( link == NULL )
-		/* Error */
-		return NULL;
-
-	if ( *link == '\0' )
-	{
-		if (no_link) {
+	if ( (ret=sieve_storage_read_active_link(storage, &link)) <= 0 ) {
+		if ( ret == 0 ) {
 			/* Try to open the active_path as a regular file */
 			return sieve_storage_script_init_from_path
-				(storage, storage->active_path, NULL, NULL);
+				(storage, storage->active_path, NULL);
 		}
 
-		*no_active = TRUE;
 		return NULL;
 	}
 
@@ -261,43 +254,37 @@ struct sieve_script *sieve_storage_get_active_script
 	scriptfile = sieve_storage_parse_link(storage, link);
 
 	if (scriptfile == NULL) {
-  		/* Obviously someone has been playing with our symlink,
-		 * ignore this situation and report 'no active script'.
+		/* Obviously someone has been playing with our symlink,
+		 * ignore this situation and report.
 		 */
-		*no_active = TRUE;
 		return NULL;
 	}
 	
-	exists = TRUE;
-	script = sieve_storage_script_init_from_file(storage, scriptfile, &exists);	
+	script = sieve_storage_script_init_from_file(storage, scriptfile);	
 
-	if ( !exists ) {
+	if ( script == NULL && storage->error_code == SIEVE_ERROR_NOT_FOUND ) {
 		i_warning
 		  ("sieve-storage: Active sieve script symlink %s "
 		   "points to non-existent script (points to %s).",
 		   storage->active_path, link);
 	}
-	
-	*no_active = !exists;
+
 	return script;
 }
 
 int sieve_storage_script_is_active(struct sieve_script *script)
 {
-	struct sieve_storage_script *st_script = (struct sieve_storage_script *) script;
+	struct sieve_storage_script *st_script =
+		(struct sieve_storage_script *) script;
 	const char *afile;
 	int ret = 0;
 
 	T_BEGIN {
-		afile = sieve_storage_get_active_scriptfile(st_script->storage);
+		ret = sieve_storage_get_active_scriptfile(st_script->storage, &afile);
 	
-		if (afile == NULL) {
-			/* Critical error */
-			ret = -1;
-		} else {
+		if ( ret > 0 ) {
 		 	/* Is the requested script active? */
-			if ( strcmp(script->filename, afile) == 0 ) 
-				ret = 1;
+			ret = ( strcmp(script->filename, afile) == 0 ? 1 : 0 );
 		}
 	} T_END;
 
@@ -306,13 +293,14 @@ int sieve_storage_script_is_active(struct sieve_script *script)
 
 int sieve_storage_script_delete(struct sieve_script **script) 
 {
-	struct sieve_storage_script *st_script = (struct sieve_storage_script *) *script;
+	struct sieve_storage_script *st_script = 
+		(struct sieve_storage_script *) *script;
 	struct sieve_storage *storage = st_script->storage;
 	int ret = 0;
 
 	/* Is the requested script active? */
 	if ( sieve_storage_script_is_active(*script) ) {
-		sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_ACTIVE,
+		sieve_storage_set_error(storage, SIEVE_ERROR_ACTIVE,
 			"Cannot delete the active sieve script.");
 		ret = -1;
 	} else {
@@ -320,7 +308,7 @@ int sieve_storage_script_delete(struct sieve_script **script)
 
 		if ( ret < 0 ) {
 			if ( errno == ENOENT ) 
-				sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_NOTFOUND,
+				sieve_storage_set_error(storage, SIEVE_ERROR_NOT_FOUND,
 					"Sieve script does not exist.");
 			else
 				sieve_storage_set_critical(
@@ -331,7 +319,6 @@ int sieve_storage_script_delete(struct sieve_script **script)
 
 	/* Always deinitialize the script object */
 	sieve_script_unref(script);
-
 	return ret;	
 }
 
@@ -350,11 +337,11 @@ static bool sieve_storage_rescue_regular_file(struct sieve_storage *storage)
 		return TRUE;
 	}
 
-  	if ( S_ISLNK( st.st_mode ) ) {
+	if ( S_ISLNK( st.st_mode ) ) {
 		if ( storage->debug )
-	    	i_info( "sieve-storage: nothing to rescue %s.", storage->active_path);
-    	return TRUE; /* Nothing to rescue */
-  	}
+			i_info( "sieve-storage: nothing to rescue %s.", storage->active_path);
+		return TRUE; /* Nothing to rescue */
+	}
 
 	/* Only regular files can be rescued */
 	if ( S_ISREG( st.st_mode ) ) {
@@ -480,10 +467,10 @@ static int _sieve_storage_script_activate(struct sieve_script *script)
 	 * resolves automatically. This step is only necessary to provide a
 	 * proper return value indicating whether the script was already active.
 	 */
-	afile = sieve_storage_get_active_scriptfile(storage);
+	ret = sieve_storage_get_active_scriptfile(storage, &afile);
 
 	/* Is the requested script already active? */
-	if ( afile == NULL || strcmp(script->filename, afile) != 0 ) 
+	if ( ret <= 0 || strcmp(script->filename, afile) != 0 ) 
 		activated = 1; 
 
 	/* Check the scriptfile we are trying to activate */
@@ -550,7 +537,7 @@ int sieve_storage_script_rename
 	/* Check script name */
 	if ( !sieve_script_name_is_valid(newname) ) {
 		sieve_storage_set_error(storage, 
-			SIEVE_STORAGE_ERROR_IMPOSSIBLE, 
+			SIEVE_ERROR_BAD_PARAMS, 
 			"Invalid new script name '%s'.", newname);
 		return -1;
 	}
@@ -601,11 +588,11 @@ int sieve_storage_script_rename
 			/* Our efforts failed right away */
 			switch ( errno ) {
 			case ENOENT: 
-				sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_NOTFOUND, 
+				sieve_storage_set_error(storage, SIEVE_ERROR_NOT_FOUND, 
 					"Sieve script does not exist.");
 				break;
 			case EEXIST:
-				sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_EXISTS,
+				sieve_storage_set_error(storage, SIEVE_ERROR_EXISTS,
 					"A sieve script with that name already exists.");
 				break;
 			default:
diff --git a/src/lib-sievestorage/sieve-storage-script.h b/src/lib-sievestorage/sieve-storage-script.h
index 44e7380cb..ea7c44451 100644
--- a/src/lib-sievestorage/sieve-storage-script.h
+++ b/src/lib-sievestorage/sieve-storage-script.h
@@ -9,16 +9,16 @@
 #include "sieve-storage.h"
 
 struct sieve_script *sieve_storage_script_init
-    (struct sieve_storage *storage, const char *scriptname, bool *exists_r);
+	(struct sieve_storage *storage, const char *scriptname);
 
 const char *sieve_storage_file_get_scriptname
 	(const struct sieve_storage *storage, const char *filename);
 
-const char *
-	sieve_storage_get_active_scriptfile(struct sieve_storage *storage);
+int sieve_storage_get_active_scriptfile
+	(struct sieve_storage *storage, const char **file_r);
 
 struct sieve_script *sieve_storage_get_active_script
-	(struct sieve_storage *storage, bool *no_active);
+	(struct sieve_storage *storage);
 
 int sieve_storage_script_is_active(struct sieve_script *script);
 
@@ -29,7 +29,7 @@ int sieve_storage_deactivate(struct sieve_storage *storage);
 int sieve_storage_script_activate(struct sieve_script *script);
 
 int sieve_storage_script_rename
-	(struct sieve_script *script, const char *newname);
+(struct sieve_script *script, const char *newname);
 
 #endif
 
diff --git a/src/lib-sievestorage/sieve-storage.c b/src/lib-sievestorage/sieve-storage.c
index 25956e561..a8e73ea34 100644
--- a/src/lib-sievestorage/sieve-storage.c
+++ b/src/lib-sievestorage/sieve-storage.c
@@ -140,7 +140,10 @@ static int mkdir_verify
 	if ( stat(dir, &st) == 0 )
 		return 0;
 
-	if ( errno != ENOENT ) {
+	if ( errno == EACCES ) {
+		i_error("sieve-storage: %s", eacces_error_get("stat", dir));
+		return -1;
+	} else if ( errno != ENOENT ) {
 		i_error("sieve-storage: stat(%s) failed: %m", dir);
 		return -1;
 	}
@@ -151,14 +154,18 @@ static int mkdir_verify
 		return 0;
 	}
 
-	if ( errno == EEXIST ) {
+	switch ( errno ) {
+	case EEXIST:
 		return 0;
-	} else if (errno == ENOENT) {
+	case ENOENT:
 		i_error("sieve-storage: storage was deleted while it was being created");
-	} else if (errno == EACCES) {
+		break;
+	case EACCES:
 		i_error("sieve-storage: %s", eacces_error_get_creating("mkdir", dir));
-	} else {
+		break;
+	default:
 		i_error("sieve-storage: mkdir(%s) failed: %m", dir);
+		break;
 	}
 
 	return -1;
@@ -341,7 +348,7 @@ static struct sieve_storage *_sieve_storage_create
 	if ( sieve_setting_get_size_value
 		(svinst, "sieve_quota_max_storage", &size_setting) ) {
 		storage->max_storage = size_setting;
-    }
+	}
 
 	if ( sieve_setting_get_uint_value
 		(svinst, "sieve_quota_max_scripts", &uint_setting) ) {
@@ -416,16 +423,18 @@ static void sieve_storage_verror
 	if (fmt != NULL) {
 		storage->error = i_strdup_vprintf(fmt, args);
 	}
+	storage->error_code = SIEVE_ERROR_TEMP_FAIL;
 }
 
 void sieve_storage_clear_error(struct sieve_storage *storage)
 {
 	i_free(storage->error);
+	storage->error_code = SIEVE_ERROR_NONE;
 	storage->error = NULL;
 }
 
 void sieve_storage_set_error
-(struct sieve_storage *storage, enum sieve_storage_error error,
+(struct sieve_storage *storage, enum sieve_error error,
 	const char *fmt, ...)
 {
 	va_list va;
@@ -449,14 +458,14 @@ void sieve_storage_set_internal_error(struct sieve_storage *storage)
 	tm = localtime(&ioloop_time);
 
 	i_free(storage->error);
-	storage->error_code = SIEVE_STORAGE_ERROR_TEMP;
+	storage->error_code = SIEVE_ERROR_TEMP_FAIL;
 	storage->error =
 	  strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
 	  i_strdup(str) : i_strdup(CRITICAL_MSG);
 }
 
-void sieve_storage_set_critical(struct sieve_storage *storage,
-             const char *fmt, ...)
+void sieve_storage_set_critical
+(struct sieve_storage *storage, const char *fmt, ...)
 {
 	va_list va;
 	
@@ -474,7 +483,7 @@ void sieve_storage_set_critical(struct sieve_storage *storage,
 }
 
 const char *sieve_storage_get_last_error
-	(struct sieve_storage *storage, enum sieve_storage_error *error_r)
+(struct sieve_storage *storage, enum sieve_error *error_r)
 {
 	/* We get here only in error situations, so we have to return some
 	   error. If storage->error is NULL, it means we forgot to set it at
diff --git a/src/lib-sievestorage/sieve-storage.h b/src/lib-sievestorage/sieve-storage.h
index 603a897ae..0e245d666 100644
--- a/src/lib-sievestorage/sieve-storage.h
+++ b/src/lib-sievestorage/sieve-storage.h
@@ -8,7 +8,6 @@
 #include "mail-user.h"
 
 #include "sieve.h"
-#include "sieve-storage-error.h"
 
 struct sieve_storage *sieve_storage_create
 	(struct sieve_instance *svinst, const char *user, const char *home, bool debug);
@@ -22,7 +21,7 @@ struct sieve_error_handler *sieve_storage_get_error_handler
 void sieve_storage_clear_error(struct sieve_storage *storage);
 
 void sieve_storage_set_error
-	(struct sieve_storage *storage, enum sieve_storage_error error, 
+	(struct sieve_storage *storage, enum sieve_error error, 
 		const char *fmt, ...) ATTR_FORMAT(3, 4);
 
 void sieve_storage_set_critical(struct sieve_storage *storage,
@@ -31,6 +30,6 @@ void sieve_storage_set_critical(struct sieve_storage *storage,
 void sieve_storage_set_internal_error(struct sieve_storage *storage);
 
 const char *sieve_storage_get_last_error
-	(struct sieve_storage *storage, enum sieve_storage_error *error_r);
+	(struct sieve_storage *storage, enum sieve_error *error_r);
 
 #endif
diff --git a/src/managesieve/cmd-deletescript.c b/src/managesieve/cmd-deletescript.c
index 422ca533e..54c3d8a9a 100644
--- a/src/managesieve/cmd-deletescript.c
+++ b/src/managesieve/cmd-deletescript.c
@@ -15,21 +15,15 @@ bool cmd_deletescript(struct client_command_context *cmd)
 	struct sieve_storage *storage = client->storage;
 	const char *scriptname;
 	struct sieve_script *script;
-	bool exists;
 
 	/* <scrip name>*/
 	if (!client_read_string_args(cmd, 1, &scriptname))
 		return FALSE;
 
-	exists = TRUE;
-	script = sieve_storage_script_init(storage, scriptname, &exists);
+	script = sieve_storage_script_init(storage, scriptname);
 
 	if (script == NULL) {
-		if (!exists) 
-			client_send_noresp(client, "NONEXISTENT", "Script does not exist.");
-		else 
-			client_send_storage_error(client, storage);
-
+		client_send_storage_error(client, storage);
 		return TRUE;
 	}
 
diff --git a/src/managesieve/cmd-getscript.c b/src/managesieve/cmd-getscript.c
index dd0c3afd2..746089ad8 100644
--- a/src/managesieve/cmd-getscript.c
+++ b/src/managesieve/cmd-getscript.c
@@ -18,28 +18,23 @@ struct cmd_getscript_context {
 
 	struct sieve_script *script;
 	struct istream *script_stream;
-	bool failed;
-	bool exists;
+	
+	unsigned int failed:1;
 };
 
 static bool cmd_getscript_finish(struct cmd_getscript_context *ctx)
 {
 	struct client *client = ctx->client;
 
-	if (ctx->script != NULL)
+	if ( ctx->script != NULL )
 		sieve_script_unref(&ctx->script);
 
-	if (ctx->failed) {
-		if (client->output->closed) {
+	if ( ctx->failed ) {
+		if ( client->output->closed ) {
 			client_disconnect(client, "Disconnected");
 			return TRUE;
 		}
 
-		if (!ctx->exists) {
-			client_send_noresp(client, "NONEXISTENT", "Script does not exist.");
-			return TRUE;
-		}
-		
 		client_send_storage_error(client, client->storage);
 		return TRUE;
 	}
@@ -59,7 +54,8 @@ static bool cmd_getscript_continue(struct client_command_context *cmd)
 
 	if ( ret < 0 ) {
 		sieve_storage_set_critical(ctx->storage,
-			"o_stream_send_istream(%s) failed: %m", sieve_script_filename(ctx->script));
+			"o_stream_send_istream(%s) failed: %m", 
+			sieve_script_filename(ctx->script));
 		ctx->failed = TRUE;
 		return cmd_getscript_finish(ctx);
 	}
@@ -68,19 +64,19 @@ static bool cmd_getscript_continue(struct client_command_context *cmd)
 
 	if ( ctx->script_offset != ctx->script_size && !ctx->failed ) {
 		/* unfinished */
-		if (!i_stream_have_bytes_left(ctx->script_stream)) {
-            /* Input stream gave less data than expected */
-            i_error("GETSCRIPT for SCRIPT %s got too little data: "
-                "%"PRIuUOFF_T" vs %"PRIuUOFF_T,
-                sieve_script_name(ctx->script),
-                ctx->script_offset, ctx->script_size);
-
-            client_disconnect(ctx->client, "GETSCRIPT failed");
+		if ( !i_stream_have_bytes_left(ctx->script_stream) ) {
+			/* Input stream gave less data than expected */
+			sieve_storage_set_critical(ctx->storage,
+				"GETSCRIPT for SCRIPT %s got too little data: "
+				"%"PRIuUOFF_T" vs %"PRIuUOFF_T, sieve_script_name(ctx->script),
+				ctx->script_offset, ctx->script_size);
+
+			client_disconnect(ctx->client, "GETSCRIPT failed");
 			ctx->failed = TRUE;
-            return cmd_getscript_finish(ctx);
-        }
+			return cmd_getscript_finish(ctx);
+		}
 
-        return FALSE;
+		return FALSE;
 	}
 
 	return cmd_getscript_finish(ctx);
@@ -91,7 +87,7 @@ bool cmd_getscript(struct client_command_context *cmd)
 	struct client *client = cmd->client;
 	struct cmd_getscript_context *ctx;
 	const char *scriptname;
-	bool deleted_r;
+	enum sieve_error error;
 
 	/* <scriptname> */
 	if (!client_read_string_args(cmd, 1, &scriptname))
@@ -102,26 +98,27 @@ bool cmd_getscript(struct client_command_context *cmd)
 	ctx->client = client;
 	ctx->storage = client->storage;
 	ctx->failed = FALSE;
-	ctx->exists = TRUE;
-	ctx->script = sieve_storage_script_init(client->storage, scriptname, &ctx->exists);
+	ctx->script = sieve_storage_script_init(client->storage, scriptname);
 
 	if (ctx->script == NULL) {
 		ctx->failed = TRUE;
 		return cmd_getscript_finish(ctx);
 	}
 			
-	ctx->script_stream = sieve_script_open(ctx->script, &deleted_r);
+	ctx->script_stream = sieve_script_open(ctx->script, &error);
 
 	if ( ctx->script_stream == NULL ) {
 		ctx->failed = TRUE;
-		ctx->exists = !deleted_r;
+		if ( error == SIEVE_ERROR_NOT_FOUND )
+			sieve_storage_set_error(client->storage, error, "Script does not exist.");		
 		return cmd_getscript_finish(ctx);
 	}
 
 	ctx->script_size = sieve_script_get_size(ctx->script);
 	ctx->script_offset = 0;	
 
-	client_send_line(client, t_strdup_printf("{%"PRIuUOFF_T"}", ctx->script_size));
+	client_send_line
+		(client, t_strdup_printf("{%"PRIuUOFF_T"}", ctx->script_size));
 
 	client->command_pending = TRUE;
 	cmd->func = cmd_getscript_continue;
diff --git a/src/managesieve/cmd-putscript.c b/src/managesieve/cmd-putscript.c
index 58ca1cf97..844860676 100644
--- a/src/managesieve/cmd-putscript.c
+++ b/src/managesieve/cmd-putscript.c
@@ -203,7 +203,7 @@ static bool cmd_putscript_finish_parsing(struct client_command_context *cmd)
 				(errors, TRUE, client->set->managesieve_max_compile_errors);
 
 			/* Compile */
-			if ( (sbin=sieve_compile_script(script, ehandler)) == NULL ) {
+			if ( (sbin=sieve_compile_script(script, ehandler, NULL)) == NULL ) {
 				client_send_no(client, str_c(errors));
 				success = FALSE;
 			} else {
diff --git a/src/managesieve/cmd-renamescript.c b/src/managesieve/cmd-renamescript.c
index 4637b2a3b..32a053796 100644
--- a/src/managesieve/cmd-renamescript.c
+++ b/src/managesieve/cmd-renamescript.c
@@ -16,21 +16,15 @@ bool cmd_renamescript(struct client_command_context *cmd)
 	struct sieve_storage *storage = client->storage;
 	const char *scriptname, *newname;
 	struct sieve_script *script;
-	bool exists;
 
 	/* <oldname> <newname> */
 	if (!client_read_string_args(cmd, 2, &scriptname, &newname))
 		return FALSE;
 
-	exists = TRUE;
-	script = sieve_storage_script_init(storage, scriptname, &exists);
+	script = sieve_storage_script_init(storage, scriptname);
 
 	if (script == NULL) {
-		if (!exists)
-			client_send_noresp(client, "NONEXISTENT", "Script does not exist.");
-		else
-			client_send_storage_error(client, storage);
-
+		client_send_storage_error(client, storage);
 		return TRUE;
 	}
 
diff --git a/src/managesieve/cmd-setactive.c b/src/managesieve/cmd-setactive.c
index 2170273ba..319b62890 100644
--- a/src/managesieve/cmd-setactive.c
+++ b/src/managesieve/cmd-setactive.c
@@ -14,8 +14,7 @@ bool cmd_setactive(struct client_command_context *cmd)
 	struct client *client = cmd->client;
 	struct sieve_storage *storage = client->storage;
 	const char *scriptname;
-	struct sieve_script *script;
-	bool exists;
+	struct sieve_script *script;;
 	int ret;
 
 	/* <scriptname> */
@@ -23,15 +22,10 @@ bool cmd_setactive(struct client_command_context *cmd)
 		return FALSE;
 
 	if ( *scriptname != '\0' ) {
-		exists = TRUE;
-		script = sieve_storage_script_init(storage, scriptname, &exists);
+		script = sieve_storage_script_init(storage, scriptname);
 
 		if ( script == NULL ) {
-			if (!exists)
-				client_send_noresp(client, "NONEXISTENT", "Script does not exist.");
-			else
-				client_send_storage_error(client, storage);
-
+			client_send_storage_error(client, storage);
 			return TRUE;
 		}
 	
diff --git a/src/managesieve/managesieve-client.c b/src/managesieve/managesieve-client.c
index c19b4da88..c6479e2ff 100644
--- a/src/managesieve/managesieve-client.c
+++ b/src/managesieve/managesieve-client.c
@@ -374,37 +374,37 @@ void client_send_command_error
 	cmd->param_error = TRUE;
 }
 
-void client_send_storage_error(struct client *client,
-             struct sieve_storage *storage)
+void client_send_storage_error
+(struct client *client, struct sieve_storage *storage)
 {
-	enum sieve_storage_error error_code;
+	enum sieve_error error_code;
 	const char *error;
 
 	error = sieve_storage_get_last_error(storage, &error_code);
 
 	switch ( error_code ) {
-	case SIEVE_STORAGE_ERROR_TEMP:
+	case SIEVE_ERROR_TEMP_FAIL:
 		client_send_noresp(client, "TRYLATER", error);
 		break;
 
-	case SIEVE_STORAGE_ERROR_QUOTA:
-	case SIEVE_STORAGE_ERROR_NOSPACE: /* Not sure if this is appropriate */
+	case SIEVE_ERROR_NO_QUOTA:
+	case SIEVE_ERROR_NO_SPACE: /* Not sure if this is appropriate */
 		client_send_noresp(client, "QUOTA", error);
 		break;
 
-	case SIEVE_STORAGE_ERROR_NOTFOUND:
+	case SIEVE_ERROR_NOT_FOUND:
 		client_send_noresp(client, "NONEXISTENT", error);
 		break;
 
-	case SIEVE_STORAGE_ERROR_ACTIVE:
+	case SIEVE_ERROR_ACTIVE:
 		client_send_noresp(client, "ACTIVE", error);
 		break;
 
-	case SIEVE_STORAGE_ERROR_EXISTS:
+	case SIEVE_ERROR_EXISTS:
 		client_send_noresp(client, "ALREADYEXISTS", error);
 		break;
 
-	case SIEVE_STORAGE_ERROR_IMPOSSIBLE:
+	case SIEVE_ERROR_NOT_POSSIBLE:
 	default:
 		client_send_no(client, error);
 		break;
diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c
index 669b17b69..c36a6662a 100644
--- a/src/plugins/lda-sieve/lda-sieve-plugin.c
+++ b/src/plugins/lda-sieve/lda-sieve-plugin.c
@@ -121,7 +121,7 @@ struct lda_sieve_run_context {
 	struct sieve_instance *svinst;
 
 	struct mail_deliver_context *mdctx;
-	
+
 	const char *const *script_files;
 	unsigned int script_count;
 
@@ -143,7 +143,7 @@ static const char *lda_sieve_get_personal_path(struct mail_user *user)
 	if ( mail_user_get_home(user, &home) <= 0 )
         home = NULL;
 
-    script_path = mail_user_plugin_getenv(user, "sieve");
+	script_path = mail_user_plugin_getenv(user, "sieve");
 
 	/* userdb may specify Sieve path */
 	if (script_path != NULL) {
@@ -195,48 +195,68 @@ static const char *lda_sieve_get_default_path(struct mail_user *user)
 	return script_path;
 }
 
-static void lda_sieve_multiscript_get_scriptfiles
+static int lda_sieve_multiscript_get_scriptfiles
 (const char *script_path, ARRAY_TYPE(const_string) *scriptfiles)
 {
-	struct sieve_directory *sdir = sieve_directory_open(script_path);
+	struct sieve_directory *sdir;
+	enum sieve_error error;
+	const char *file;
 
-	if ( sdir != NULL ) {
-		const char *file;
+	if ( (sdir=sieve_directory_open(script_path, &error)) == NULL )
+		return ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 );
 
-		while ( (file=sieve_directory_get_scriptfile(sdir)) != NULL ) {
-			const char *const *scripts;
-			unsigned int count, i;
+	while ( (file=sieve_directory_get_scriptfile(sdir)) != NULL ) {
+		const char *const *scripts;
+		unsigned int count, i;
 
-			/* Insert into sorted array */
+		/* Insert into sorted array */
 
-			scripts = array_get(scriptfiles, &count);
-			for ( i = 0; i < count; i++ ) {
-				if ( strcmp(file, scripts[i]) < 0 )
-					break;			
-			}
-	
-			if ( i == count ) 
-				array_append(scriptfiles, &file, 1);
-			else
-				array_insert(scriptfiles, i, &file, 1);
+		scripts = array_get(scriptfiles, &count);
+		for ( i = 0; i < count; i++ ) {
+			if ( strcmp(file, scripts[i]) < 0 )
+				break;
 		}
 
-		sieve_directory_close(&sdir);
-	} 
+		if ( i == count ) 
+			array_append(scriptfiles, &file, 1);
+		else
+			array_insert(scriptfiles, i, &file, 1);
+	}
+
+	sieve_directory_close(&sdir);
+	return 1;
 }
 
-static int lda_sieve_open
+static void lda_sieve_binary_save
+(struct lda_sieve_run_context *srctx, struct sieve_binary *sbin, 
+	unsigned int script_index)
+{
+	const char *script_path = srctx->script_files[script_index];
+	enum sieve_error error;
+
+	/* Save binary when compiled */
+	if ( sieve_save(sbin, NULL, FALSE, &error) < 0 &&
+		error == SIEVE_ERROR_NO_PERM  && script_path != srctx->user_script ) {
+		/* Cannot save binary for global script */
+		sieve_sys_error(
+			"the lda sieve plugin does not have permission "
+			"to save global sieve script binaries; "
+			"global sieve scripts like %s need to be "
+			"pre-compiled using the sievec tool", script_path);
+	}
+}
+
+static struct sieve_binary *lda_sieve_open
 (struct lda_sieve_run_context *srctx, unsigned int script_index,
-	struct sieve_binary **sbin)
+	enum sieve_error *error_r)
 {
 	struct sieve_instance *svinst = srctx->svinst;
 	const char *script_path = srctx->script_files[script_index];
 	const char *script_name =
 		( script_path == srctx->main_script ? "main_script" : NULL );
 	struct sieve_error_handler *ehandler;
-	bool exists = TRUE;
+	struct sieve_binary *sbin;
 	bool debug = srctx->mdctx->dest_user->mail_debug;
-	int ret = 0;
 
 	if ( script_path == srctx->user_script )
 		ehandler = srctx->user_ehandler;
@@ -244,16 +264,14 @@ static int lda_sieve_open
 		ehandler = srctx->master_ehandler;
 
 	if ( debug )
-		sieve_sys_debug("opening script %s", script_path);		
+		sieve_sys_debug("opening script %s", script_path);
 
 	sieve_error_handler_reset(ehandler);
 
-	if ( (*sbin=sieve_open(svinst, script_path, script_name, ehandler, &exists)) 
+	/* Open the sieve script */
+	if ( (sbin=sieve_open(svinst, script_path, script_name, ehandler, error_r)) 
 		== NULL ) {
-
-		ret = sieve_get_errors(ehandler) > 0 ? -1 : 0;
-
-		if ( !exists && ret == 0 ) {
+		if ( *error_r == SIEVE_ERROR_NOT_FOUND ) {
 			if ( debug )
 				sieve_sys_debug("script file %s is missing", script_path);
 		} else {
@@ -269,25 +287,27 @@ static int lda_sieve_open
 			}
 		}
 
-		return ret;
+		return NULL;
 	}
 
-	return 1;
+	lda_sieve_binary_save(srctx, sbin, script_index);
+	return sbin;
 }
 
 static struct sieve_binary *lda_sieve_recompile
-(struct lda_sieve_run_context *srctx, unsigned int script_index)
+(struct lda_sieve_run_context *srctx, unsigned int script_index,
+	enum sieve_error *error_r)
 {
 	struct sieve_instance *svinst = srctx->svinst;
 	const char *script_path = srctx->script_files[script_index];
 	const char *script_name =
 		( script_path == srctx->main_script ? "main_script" : NULL );
-    struct sieve_error_handler *ehandler;
+	struct sieve_error_handler *ehandler;
 	struct sieve_binary *sbin;
 
 	/* Warn */
 
-	sieve_sys_warning("encountered corrupt binary: recompiling script %s", 
+	sieve_sys_warning("encountered corrupt binary: re-compiling script %s", 
 		script_path);
 
 	/* Recompile */	
@@ -298,7 +318,7 @@ static struct sieve_binary *lda_sieve_recompile
 		ehandler = srctx->master_ehandler;
 
 	if ( (sbin=sieve_compile
-		(svinst, script_path, script_name, ehandler)) == NULL ) {
+		(svinst, script_path, script_name, ehandler, error_r)) == NULL ) {
 
 		if ( script_path == srctx->user_script && srctx->userlog != NULL ) {
 			sieve_sys_error
@@ -318,7 +338,7 @@ static struct sieve_binary *lda_sieve_recompile
 
 static int lda_sieve_handle_exec_status(const char *script_path, int status)
 {
-	int ret; 
+	int ret;
 
 	switch ( status ) {
 	case SIEVE_EXEC_FAILURE:
@@ -327,7 +347,7 @@ static int lda_sieve_handle_exec_status(const char *script_path, int status)
 				script_path);
 		ret = 1;
 		break;
-	case SIEVE_EXEC_BIN_CORRUPT:		
+	case SIEVE_EXEC_BIN_CORRUPT:
 		sieve_sys_error
 			("!!BUG!!: binary compiled from %s is still corrupt; "
 				"bailing out and reverting to default delivery", 
@@ -351,21 +371,22 @@ static int lda_sieve_singlescript_execute
 (struct lda_sieve_run_context *srctx)
 {
 	const char *script_file = srctx->script_files[0];
-    bool user_script = ( script_file == srctx->user_script );
+	bool user_script = ( script_file == srctx->user_script );
 	struct sieve_error_handler *ehandler;
 	struct sieve_binary *sbin;
 	bool debug = srctx->mdctx->dest_user->mail_debug;
+	enum sieve_error error;
 	int ret;
 
 	/* Open the script */
 
-	if ( (ret=lda_sieve_open(srctx, 0, &sbin)) <= 0 )
-		return ret;
+	if ( (sbin=lda_sieve_open(srctx, 0, &error)) == NULL )
+		return ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 );
 
 	/* Execute */
 
 	if ( debug )
-		sieve_sys_debug("executing compiled script %s", script_file);
+		sieve_sys_debug("executing script from %s", sieve_get_source(sbin));
 
 	if ( user_script ) {
 		ehandler = srctx->user_ehandler;
@@ -380,19 +401,21 @@ static int lda_sieve_singlescript_execute
 
 	/* Recompile if corrupt binary */
 
-	if ( ret == SIEVE_EXEC_BIN_CORRUPT ) {
+	if ( ret == SIEVE_EXEC_BIN_CORRUPT && sieve_is_loaded(sbin) ) {
 		/* Close corrupt script */
 
 		sieve_close(&sbin);
 
 		/* Recompile */
 
-		if ( (sbin=lda_sieve_recompile(srctx, 0)) == NULL ) {
-			return -1;
-		}
+		if ( (sbin=lda_sieve_recompile(srctx, 0, &error)) == NULL )
+			return ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 );
 
 		/* Execute again */
 
+		if ( debug )
+			sieve_sys_debug("executing script from %s", sieve_get_source(sbin));
+
 		if ( user_script )
         	sieve_error_handler_copy_masterlog(ehandler, TRUE);
 
@@ -403,7 +426,7 @@ static int lda_sieve_singlescript_execute
 		/* Save new version */
 
 		if ( ret != SIEVE_EXEC_BIN_CORRUPT )
-			sieve_save(sbin, NULL);
+			lda_sieve_binary_save(srctx, sbin, 0);
 	}
 
 	sieve_close(&sbin);
@@ -420,11 +443,13 @@ static int lda_sieve_multiscript_execute
 	unsigned int count = srctx->script_count;
 	struct sieve_multiscript *mscript;
 	struct sieve_error_handler *ehandler = srctx->master_ehandler;
+	bool debug = srctx->mdctx->dest_user->mail_debug;
 	const char *last_script = NULL;
 	bool user_script = FALSE;
 	unsigned int i;
 	int ret = 1; 
 	bool more = TRUE;
+	enum sieve_error error;
 
 	/* Start execution */
 
@@ -439,7 +464,7 @@ static int lda_sieve_multiscript_execute
 		bool final = ( i == count - 1 );
 
 		user_script = ( script_file == srctx->user_script );
-		last_script = script_file;		
+		last_script = script_file;
 
 		if ( user_script )
 			ehandler = srctx->user_ehandler;
@@ -447,30 +472,35 @@ static int lda_sieve_multiscript_execute
 			ehandler = srctx->master_ehandler;
 
 		/* Open */
-	
-		if ( (ret=lda_sieve_open(srctx, i, &sbin)) <= 0 )
+
+		if ( (sbin=lda_sieve_open(srctx, i, &error)) == NULL ) {
+			ret = ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 );
 			break;
+		}
 
 		/* Execute */
 
-		if ( user_script )	
+		if ( user_script )
 			sieve_error_handler_copy_masterlog(ehandler, TRUE);
 
+		if ( debug )
+			sieve_sys_debug("executing script from %s", sieve_get_source(sbin));
+
 		more = sieve_multiscript_run(mscript, sbin, ehandler, final);
 
 		sieve_error_handler_copy_masterlog(ehandler, FALSE);
 
 		if ( !more ) {
-			if ( sieve_multiscript_status(mscript) == SIEVE_EXEC_BIN_CORRUPT ) {
+			if ( sieve_multiscript_status(mscript) == SIEVE_EXEC_BIN_CORRUPT &&
+				sieve_is_loaded(sbin) ) {
 				/* Close corrupt script */
 
 				sieve_close(&sbin);
 
 				/* Recompile */
 
-				if ( (sbin=lda_sieve_recompile(srctx, i))
-					== NULL ) {
-					ret = -1;
+				if ( (sbin=lda_sieve_recompile(srctx, i, &error))	== NULL ) {
+					ret = ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 );
 					break;
 				}
 
@@ -487,7 +517,7 @@ static int lda_sieve_multiscript_execute
 
 				if ( more && 
 					sieve_multiscript_status(mscript) != SIEVE_EXEC_BIN_CORRUPT )
-					sieve_save(sbin, NULL);
+					lda_sieve_binary_save(srctx, sbin, i);
 			}
 		}
 
@@ -496,7 +526,7 @@ static int lda_sieve_multiscript_execute
 
 	/* Finish execution */
 
-	if ( user_script )	
+	if ( user_script )
 		sieve_error_handler_copy_masterlog(ehandler, TRUE);
 
 	ret = sieve_multiscript_finish(&mscript, ehandler, NULL);
@@ -526,7 +556,7 @@ static int lda_sieve_run
 
 	/* Initialize Sieve engine */
 	svinst = sieve_init(&lda_sieve_env, mdctx->dest_user, debug);
-	
+
 	/* Initialize */
 
 	memset(&srctx, 0, sizeof(srctx));
@@ -611,7 +641,7 @@ static int lda_sieve_run
 	if ( srctx.script_count == 1 )
 		ret = lda_sieve_singlescript_execute(&srctx);
 	else
-		ret = lda_sieve_multiscript_execute(&srctx);	
+		ret = lda_sieve_multiscript_execute(&srctx);
 
 	/* Record status */
 
@@ -647,7 +677,7 @@ static int lda_sieve_deliver_mail
 		struct stat st;
 
 		/* Find the personal script to execute */
-	
+
 		user_script = lda_sieve_get_personal_path(mdctx->dest_user);
 		default_script = lda_sieve_get_default_path(mdctx->dest_user);
 
@@ -677,7 +707,7 @@ static int lda_sieve_deliver_mail
 		if ( debug ) {
 			const char *script = user_script == NULL ? default_script : user_script;
 
-			if ( script == NULL )			
+			if ( script == NULL )
 				sieve_sys_debug("user has no valid personal script");
 			else
 				sieve_sys_debug("using sieve path for user's script: %s", script);
@@ -692,11 +722,17 @@ static int lda_sieve_deliver_mail
 		sieve_after = mail_user_plugin_getenv(mdctx->dest_user, "sieve_after");
 
 		if ( sieve_before != NULL && *sieve_before != '\0' ) {
-			lda_sieve_multiscript_get_scriptfiles(sieve_before, &scripts_before);
+			if ( lda_sieve_multiscript_get_scriptfiles
+				(sieve_before, &scripts_before) == 0 && debug ) {
+				sieve_sys_debug("sieve_before path not found: %s", sieve_before);
+			}
 		}
 
 		if ( sieve_after != NULL && *sieve_after != '\0' ) {
-			lda_sieve_multiscript_get_scriptfiles(sieve_after, &scripts_after);
+			if ( lda_sieve_multiscript_get_scriptfiles
+				(sieve_after, &scripts_after) == 0 && debug ) {
+				sieve_sys_debug("sieve_after path not found: %s", sieve_after);
+			}
 		}
 
 		if ( debug ) {
@@ -705,17 +741,17 @@ static int lda_sieve_deliver_mail
 
 			scriptfiles = array_get(&scripts_before, &count);
 			for ( i = 0; i < count; i ++ ) {
-				sieve_sys_debug("executed before user's script(%d): %s", 
-					i+1, scriptfiles[i]);				
+				sieve_sys_debug("executed before user's script(%d): %s",
+					i+1, scriptfiles[i]);
 			}
 
 			scriptfiles = array_get(&scripts_after, &count);
 			for ( i = 0; i < count; i ++ ) {
-				sieve_sys_debug("executed after user's script(%d): %s", 
-					i+1, scriptfiles[i]);				
+				sieve_sys_debug("executed after user's script(%d): %s",
+					i+1, scriptfiles[i]);
 			}
 		}
-	
+
 		/* Check whether there are any scripts to execute */
 
 		if ( array_count(&scripts_before) == 0 && array_count(&scripts_after) == 0 &&
@@ -731,7 +767,7 @@ static int lda_sieve_deliver_mail
 			ret = 0; 
 		} else {
 			/* Run the script(s) */
-				
+
 			ret = lda_sieve_run
 				(mdctx, user_script, default_script, &scripts_before, &scripts_after, 
 					storage_r);
diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c
index 198e5e09c..3c596c10f 100644
--- a/src/sieve-tools/sieve-test.c
+++ b/src/sieve-tools/sieve-test.c
@@ -215,7 +215,7 @@ int main(int argc, char **argv)
 	if ( force_compile ) {
 		main_sbin = sieve_tool_script_compile(svinst, scriptfile, NULL);
 		if ( main_sbin != NULL )
-			(void) sieve_save(main_sbin, NULL);
+			(void) sieve_save(main_sbin, NULL, TRUE, NULL);
 	} else {
 		main_sbin = sieve_tool_script_open(svinst, scriptfile);
 	}
@@ -314,7 +314,7 @@ int main(int argc, char **argv)
 				if ( force_compile ) {
 					sbin = sieve_tool_script_compile(svinst, sfiles[i], sfiles[i]);
 					if ( sbin != NULL )
-						(void) sieve_save(sbin, NULL);
+						(void) sieve_save(sbin, NULL, FALSE, NULL);
 				} else {
 					sbin = sieve_tool_script_open(svinst, sfiles[i]);
 				}
diff --git a/src/sieve-tools/sievec.c b/src/sieve-tools/sievec.c
index 7fce62c8b..4ad5811a6 100644
--- a/src/sieve-tools/sievec.c
+++ b/src/sieve-tools/sievec.c
@@ -125,7 +125,7 @@ int main(int argc, char **argv)
 				sbin = sieve_tool_script_compile(svinst, file, dp->d_name);
 
 				if ( sbin != NULL ) {
-					sieve_save(sbin, NULL);		
+					sieve_save(sbin, NULL, TRUE, NULL);		
 					sieve_close(&sbin);
 				}
 			}
@@ -145,7 +145,7 @@ int main(int argc, char **argv)
 			if ( dump ) 
 				sieve_tool_dump_binary_to(sbin, outfile);
 			else {
-				sieve_save(sbin, outfile);
+				sieve_save(sbin, outfile, TRUE, NULL);
 			}
 		
 			sieve_close(&sbin);
diff --git a/src/sieve-tools/sieved.c b/src/sieve-tools/sieved.c
index 61747cbc1..b48a8f611 100644
--- a/src/sieve-tools/sieved.c
+++ b/src/sieve-tools/sieved.c
@@ -74,7 +74,7 @@ int main(int argc, char **argv)
 	(void) sieve_extension_register(svinst, &debug_extension, TRUE);
 		
 	/* Dump binary */
-	sbin = sieve_load(svinst, binfile);
+	sbin = sieve_load(svinst, binfile, NULL);
 	if ( sbin != NULL ) {
 		sieve_tool_dump_binary_to(sbin, outfile == NULL ? "-" : outfile);
 	
diff --git a/src/testsuite/testsuite-binary.c b/src/testsuite/testsuite-binary.c
index 11485a8cf..c573704b3 100644
--- a/src/testsuite/testsuite-binary.c
+++ b/src/testsuite/testsuite-binary.c
@@ -61,8 +61,8 @@ void testsuite_binary_reset(void)
 
 bool testsuite_binary_save(struct sieve_binary *sbin, const char *name)
 {
-	return sieve_save
-    (sbin, t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name));
+	return sieve_save(sbin, 
+		t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name), TRUE, NULL);
 }
 
 struct sieve_binary *testsuite_binary_load(const char *name)
@@ -70,7 +70,7 @@ struct sieve_binary *testsuite_binary_load(const char *name)
 	struct sieve_instance *svinst = testsuite_sieve_instance;
 
 	return sieve_load(svinst, 
-		t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name));
+		t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name), NULL);
 }
 
 
diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c
index fe264f096..c7a7d1577 100644
--- a/src/testsuite/testsuite-script.c
+++ b/src/testsuite/testsuite-script.c
@@ -65,8 +65,8 @@ static struct sieve_binary *_testsuite_script_compile
 	testsuite_setting_set
 		("sieve_global_dir", t_strconcat(sieve_dir, "included-global", NULL));
 	
-	if ( (sbin = sieve_compile(svinst, script_path, NULL, testsuite_log_ehandler)) 
-		== NULL )
+	if ( (sbin = sieve_compile(svinst, script_path, NULL, testsuite_log_ehandler,
+		NULL)) == NULL )
 		return NULL;
 
 	return sbin;
diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c
index dfbaffcf4..089a18cef 100644
--- a/src/testsuite/testsuite.c
+++ b/src/testsuite/testsuite.c
@@ -165,7 +165,7 @@ int main(int argc, char **argv)
 
 	/* Compile sieve script */
 	if ( (sbin = sieve_compile
-		(svinst, scriptfile, NULL, testsuite_log_main_ehandler)) != NULL ) {
+		(svinst, scriptfile, NULL, testsuite_log_main_ehandler, NULL)) != NULL ) {
 		struct ostream *tracestream = NULL;
 		struct sieve_script_env scriptenv;
 
-- 
GitLab