dovecot-2.2-pigeonhole: lib-sieve: storage: Implemented magic to...

pigeonhole at rename-it.nl pigeonhole at rename-it.nl
Wed May 6 22:05:10 UTC 2015


details:   http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/70a3e6c5bb1f
changeset: 2044:70a3e6c5bb1f
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Wed May 06 23:58:57 2015 +0200
description:
lib-sieve: storage: Implemented magic to make sieve_default script visible in main storage (e.g. from ManageSieve).

diffstat:

 INSTALL                                              |   49 ++-
 src/lib-sieve/sieve-script.c                         |  142 ++++++-
 src/lib-sieve/sieve-script.h                         |   16 +-
 src/lib-sieve/sieve-storage-private.h                |   23 +-
 src/lib-sieve/sieve-storage.c                        |  370 +++++++++++++++++-
 src/lib-sieve/sieve-storage.h                        |    9 +
 src/lib-sieve/storage/file/sieve-file-storage-save.c |   74 ++-
 src/lib-sieve/storage/file/sieve-file-storage.c      |    1 +
 src/lib-sieve/storage/file/sieve-file-storage.h      |   10 +-
 src/plugins/lda-sieve/lda-sieve-plugin.c             |  117 +-----
 10 files changed, 627 insertions(+), 184 deletions(-)

diffs (truncated from 1281 to 300 lines):

diff -r a3d26f12c2cd -r 70a3e6c5bb1f INSTALL
--- a/INSTALL	Tue May 05 13:42:38 2015 +0200
+++ b/INSTALL	Wed May 06 23:58:57 2015 +0200
@@ -126,6 +126,11 @@
     Multiple mail users can share a single script directory if the script
     location is the same and all users share the same system credentials (uid,
     gid).
+ 
+  default=<script-name>
+    The name by which the default Sieve script (see `sieve_default=' setting
+    below) is visible to ManageSieve clients. Normally, it is not visible at
+    all. See "Visible Default Script" section below for more information.
 
 Sieve Interpreter - Basic Configuration
 ---------------------------------------
@@ -166,7 +171,9 @@
    /var/lib/dovecot/default.sieve. This is usually a global script, so be sure
    to pre-compile this script manually using the sievec command line tool, as
    explained in the README file. This setting used to be called
-   `sieve_global_path', but that name is now deprecated.
+   `sieve_global_path', but that name is now deprecated. See the "Visible
+   Default Script" section below for information on how to make the default
+   script visible from ManageSieve.
 
  sieve_global =
    Location for :global include scripts for the Sieve include extension. This
@@ -388,6 +395,46 @@
 to store the compiled binaries. In that case, be sure to manually pre-compile
 those scripts using the sievec tool, as explained in the README file.
 
+Sieve Interpreter - Visible Default Script
+------------------------------------------
+
+The `sieve_default=' setting specifies the location of a default script that
+is executed when the user has no active personal script. Normally, this
+default script is invisible to the user; i.e., it is not listed in ManageSieve.
+To give the user the ability to base a custom personal script on the default
+script, it is possible to make it visible under a specific configurable name.
+
+ManageSieve will magically list the default script under that name, even though
+it does not actually exist in the user's normal script storage location. This
+way, the ManageSieve client can see that it exists and it can retrieve its
+contents. If no normal script is active, the default is always listed as active.
+The user can replace the default with a custom script, by uploading it under the
+default script's name. If that custom script is ever deleted, the default script
+will reappear from the shadows implicitly.
+
+This way, ManageSieve clients will not need any special handling for this
+feature. If the name of the default script is equal to the name the client uses
+for the main script, it will initially see and read the default script when the
+user account is freshly created. The user can edit the script, and when the
+edited script is saved through the ManageSieve client, it will will override the
+default script. If the user ever wants to revert to the default, the user only
+needs to delete the edited script and the default will reappear.
+
+To enable this feature, the the `;default=<script-name>' option must be
+specified for the `sieve=' setting. It configures the name by which the default
+script will be known. Of course, the `sieve_default=' setting needs to point to
+a valid script location as well for this to work. If the default script does not
+exist at the indicated location, it is not shown.
+
+For example:
+
+plugin {
+...
+  sieve = file:~/sieve;active=~/.dovecot.sieve;default=roundcube
+
+  sieve_default = /var/lib/dovecot/sieve/default.sieve
+}
+
 Sieve Interpreter - Extension Configuration
 -------------------------------------------
 
diff -r a3d26f12c2cd -r 70a3e6c5bb1f src/lib-sieve/sieve-script.c
--- a/src/lib-sieve/sieve-script.c	Tue May 05 13:42:38 2015 +0200
+++ b/src/lib-sieve/sieve-script.c	Wed May 06 23:58:57 2015 +0200
@@ -219,6 +219,24 @@
 	return script;
 }
 
+int sieve_script_check
+(struct sieve_instance *svinst, const char *location, const char *name,
+	enum sieve_error *error_r)
+{
+	struct sieve_script *script;
+	enum sieve_error error;
+
+	if (error_r == NULL)
+		error_r = &error;
+
+	script = sieve_script_create_open(svinst, location, name, error_r);
+	if (script == NULL)
+		return ( *error_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
+
+	sieve_script_unref(&script);
+	return 1;
+}
+
 /*
  * Properties
  */
@@ -261,6 +279,11 @@
 	return script->open;
 }
 
+bool sieve_script_is_default(const struct sieve_script *script)
+{
+	return script->storage->is_default;
+}
+
 /*
  * Stream management
  */
@@ -525,15 +548,65 @@
 		return -1;
 	}
 
-	i_assert( (script->storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 );
 	i_assert( script->open ); // FIXME: auto-open?
 
-	i_assert( script->v.rename != NULL );
-	ret = script->v.rename(script, newname);
+	if ( storage->default_for == NULL ) {
+		i_assert( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 );
 
-	/* rename INBOX mailbox attribute */
-	if ( ret >= 0 && oldname != NULL )
-		(void)sieve_storage_sync_script_rename(storage, oldname, newname);
+		/* rename script */
+		i_assert( script->v.rename != NULL );
+		ret = script->v.rename(script, newname);
+
+		/* rename INBOX mailbox attribute */
+		if ( ret >= 0 && oldname != NULL )
+			(void)sieve_storage_sync_script_rename(storage, oldname, newname);
+
+	} else if ( sieve_storage_check_script
+			(storage->default_for, newname, NULL) > 0 ) {
+		sieve_script_set_error(script, SIEVE_ERROR_EXISTS,
+			"A sieve script with that name already exists.");
+		sieve_storage_copy_error(storage->default_for, storage);
+		ret = -1;
+
+	} else {
+		struct istream *input;
+		
+		/* copy from default */
+		if ( (ret=sieve_script_open(script, NULL)) >= 0 &&
+			(ret=sieve_script_get_stream(script, &input, NULL)) >= 0 ) {
+			ret = sieve_storage_save_as
+				(storage->default_for, input, newname);
+
+			if ( ret < 0 ) {
+				sieve_storage_copy_error(storage, storage->default_for);
+
+			} else if ( sieve_script_is_active(script) > 0 ) {
+				struct sieve_script *newscript;
+				enum sieve_error error;
+
+				newscript = sieve_storage_open_script
+					(storage->default_for, newname, &error);
+				if ( newscript == NULL ) {
+					/* Somehow not actually saved */
+					ret = ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 );
+				} else if ( sieve_script_activate(newscript, (time_t)-1) < 0 ) {
+					/* Failed to activate; roll back */
+					ret = -1;
+					(void)sieve_script_delete(newscript);
+					sieve_script_unref(&newscript);
+				}
+
+				if (ret < 0) {
+					sieve_storage_sys_error(storage,
+						"Failed to implicitly activate script `%s' "
+						"after rename",	newname);
+					sieve_storage_copy_error(storage->default_for, storage);
+				}
+			}
+		} else {
+			sieve_storage_copy_error(storage->default_for, storage);
+		}
+	}
 
 	return ret;
 }
@@ -543,19 +616,28 @@
 	struct sieve_storage *storage = script->storage;
 	int ret = 0;
 
-	i_assert( (script->storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 );
 	i_assert( script->open ); // FIXME: auto-open?
 
 	/* Is the requested script active? */
-	if ( sieve_script_is_active(script) ) {
+	if ( sieve_script_is_active(script) > 0 ) {
 		sieve_script_set_error(script, SIEVE_ERROR_ACTIVE,
 			"Cannot delete the active Sieve script.");
-		ret = -1;
-	} else {
-		i_assert( script->v.delete != NULL );
-		ret = script->v.delete(script);
+		if (storage->default_for != NULL)
+			sieve_storage_copy_error(storage->default_for, storage);
+		return -1;
 	}
 
+	/* Trying to delete the default script? */
+	if ( storage->is_default ) {
+		/* ignore */
+		return 0;
+	}
+
+	i_assert( (script->storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 );
+
+	i_assert( script->v.delete != NULL );
+	ret = script->v.delete(script);
+
 	/* unset INBOX mailbox attribute */
 	if ( ret >= 0 )
 		(void)sieve_storage_sync_script_delete(storage, script->name);
@@ -564,6 +646,17 @@
 
 int sieve_script_is_active(struct sieve_script *script)
 {
+	struct sieve_storage *storage = script->storage;
+
+	/* Special handling if this is a default script */
+	if ( storage->default_for != NULL ) {
+		int ret = sieve_storage_active_script_is_default
+			(storage->default_for);
+		if (ret < 0)
+			sieve_storage_copy_error(storage, storage->default_for);
+		return ret;
+	}	
+
 	if ( script->v.is_active == NULL )
 		return 0;
 	return script->v.is_active(script);
@@ -572,17 +665,28 @@
 int sieve_script_activate(struct sieve_script *script, time_t mtime)
 {
 	struct sieve_storage *storage = script->storage;
-	int ret;
+	int ret = 0;
 
-	i_assert( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 );
 	i_assert( script->open ); // FIXME: auto-open?
 
-	i_assert( script->v.activate != NULL );
-	ret = script->v.activate(script);
+	if (storage->default_for == NULL) {
+		i_assert( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 );
+	
+		i_assert( script->v.activate != NULL );
+		ret = script->v.activate(script);
 
-	if (ret >= 0) {
-		sieve_storage_set_modified(storage, mtime);
-		(void)sieve_storage_sync_script_activate(storage);
+		if (ret >= 0) {
+			sieve_storage_set_modified(storage, mtime);
+			(void)sieve_storage_sync_script_activate(storage);
+		}
+
+	} else {
+		/* Activating the default script is equal to deactivating
+		   the storage */
+		ret = sieve_storage_deactivate
+			(storage->default_for, (time_t)-1);
+		if (ret < 0)
+			sieve_storage_copy_error(storage, storage->default_for);
 	}
 
 	return ret;
diff -r a3d26f12c2cd -r 70a3e6c5bb1f src/lib-sieve/sieve-script.h
--- a/src/lib-sieve/sieve-script.h	Tue May 05 13:42:38 2015 +0200
+++ b/src/lib-sieve/sieve-script.h	Wed May 06 23:58:57 2015 +0200
@@ -50,13 +50,17 @@
 	(struct sieve_script *script, enum sieve_error *error_r)
 		ATTR_NULL(2);
 int sieve_script_open_as
-	(struct sieve_script *script, const char *name, enum sieve_error *error_r)
-		ATTR_NULL(3);
+	(struct sieve_script *script, const char *name,
+		enum sieve_error *error_r) ATTR_NULL(3);
 
 struct sieve_script *sieve_script_create_open
-	(struct sieve_instance *svinst, const char *location, const char *name,
-		enum sieve_error *error_r)
-		ATTR_NULL(3,4);
+	(struct sieve_instance *svinst, const char *location,
+		const char *name, enum sieve_error *error_r)
+		ATTR_NULL(3, 4);
+int sieve_script_check
+	(struct sieve_instance *svinst, const char *location,
+		const char *name, enum sieve_error *error_r)
+		ATTR_NULL(3, 4);
 
 /*
  * Binary


More information about the dovecot-cvs mailing list