From d9a2d35574f20d5403507f50f655ac98b749787e Mon Sep 17 00:00:00 2001
From: Jesse Norell <jesse@kci.net>
Date: Wed, 13 Nov 2019 17:20:33 -0700
Subject: [PATCH] read ISPConfig's sieve script via sieve_after: closes #3395

---
 install/tpl/debian6_dovecot.conf.master       |  6 +++
 install/tpl/debian6_dovecot2.conf.master      |  6 +++
 install/tpl/debian_dovecot.conf.master        |  7 +++-
 install/tpl/debian_dovecot2.conf.master       |  6 +++
 install/tpl/fedora_dovecot.conf.master        |  9 ++++-
 install/tpl/fedora_dovecot2.conf.master       |  7 ++++
 install/tpl/opensuse_dovecot.conf.master      |  9 ++++-
 install/tpl/opensuse_dovecot2.conf.master     |  7 ++++
 server/conf/sieve_filter.master               |  5 ++-
 server/conf/sieve_filter_1.2.master           |  3 ++
 .../maildeliver_plugin.inc.php                | 37 ++++++++++++-------
 11 files changed, 83 insertions(+), 19 deletions(-)

diff --git a/install/tpl/debian6_dovecot.conf.master b/install/tpl/debian6_dovecot.conf.master
index 4286689cd4..a112712690 100644
--- a/install/tpl/debian6_dovecot.conf.master
+++ b/install/tpl/debian6_dovecot.conf.master
@@ -57,7 +57,13 @@ plugin {
   # the maildir quota does not need to be set.
   # You do not need: quota = maildir
 
+  # no longer needed, as 'sieve' is in userdb extra fields:
   sieve=/var/vmail/%d/%n/.sieve
+
+  sieve_after=/var/vmail/%d/%n/.ispconfig.sieve
+  sieve_max_script_size = 2M
+  sieve_max_actions = 100
+  sieve_max_redirects = 25
 }
 
 
diff --git a/install/tpl/debian6_dovecot2.conf.master b/install/tpl/debian6_dovecot2.conf.master
index 973ada2f99..c82ac59a38 100644
--- a/install/tpl/debian6_dovecot2.conf.master
+++ b/install/tpl/debian6_dovecot2.conf.master
@@ -24,7 +24,13 @@ userdb {
 }
 plugin {
   quota = dict:user::file:/var/vmail/%d/%n/.quotausage
+
+  # no longer needed, as 'sieve' is in userdb extra fields:
   sieve=/var/vmail/%d/%n/.sieve
+
+  sieve_after=/var/vmail/%d/%n/.ispconfig.sieve
+  sieve_max_script_size = 2M
+  sieve_max_actions = 100
   sieve_max_redirects = 25
 }
 service auth {
diff --git a/install/tpl/debian_dovecot.conf.master b/install/tpl/debian_dovecot.conf.master
index 8d6022502f..f91959a1f5 100644
--- a/install/tpl/debian_dovecot.conf.master
+++ b/install/tpl/debian_dovecot.conf.master
@@ -682,7 +682,7 @@ protocol managesieve {
   # the sieve storage directory. This must match the SIEVE setting used by
   # deliver (refer to http://wiki.dovecot.org/LDA/Sieve#location for more
   # info). Variable substitution with % is recognized.
-  sieve=~/.dovecot.sieve
+  sieve=~/.sieve
 
   # This specifies the path to the directory where the uploaded scripts must
   # be stored. In terms of '%' variable substitution it is identical to
@@ -1144,4 +1144,9 @@ plugin {
   # they're moved to a 3rd namespace. The mails won't be counted in quota,
   # and they're not deleted automatically (use a cronjob or something).
   #lazy_expunge = .EXPUNGED/ .DELETED/ .DELETED/.EXPUNGED/
+
+  sieve_after=/var/vmail/%d/%n/.ispconfig.sieve
+  sieve_max_script_size = 2M
+  sieve_max_actions = 100
+  sieve_max_redirects = 25
 }
diff --git a/install/tpl/debian_dovecot2.conf.master b/install/tpl/debian_dovecot2.conf.master
index d4fc7ebd0f..25c586118c 100644
--- a/install/tpl/debian_dovecot2.conf.master
+++ b/install/tpl/debian_dovecot2.conf.master
@@ -23,7 +23,13 @@ userdb {
 }
 plugin {
   quota = dict:user::file:/var/vmail/%d/%n/.quotausage
+
+  # no longer needed, as 'sieve' is in userdb extra fields:
   sieve=/var/vmail/%d/%n/.sieve
+
+  sieve_after=/var/vmail/%d/%n/.ispconfig.sieve
+  sieve_max_script_size = 2M
+  sieve_max_actions = 100
   sieve_max_redirects = 25
 }
 service auth {
diff --git a/install/tpl/fedora_dovecot.conf.master b/install/tpl/fedora_dovecot.conf.master
index cfac856414..e687954986 100644
--- a/install/tpl/fedora_dovecot.conf.master
+++ b/install/tpl/fedora_dovecot.conf.master
@@ -1300,11 +1300,16 @@ plugin {
   # 
   # Location of the active script. When ManageSieve is used this is actually 
   # a symlink pointing to the active script in the sieve storage directory. 
-  #sieve=~/.dovecot.sieve
-  #
+  sieve=~/.sieve
+
   # The path to the directory where the personal Sieve scripts are stored. For 
   # ManageSieve this is where the uploaded scripts are stored.
   sieve_dir=~/sieve
+
+  sieve_after=/var/vmail/%d/%n/.ispconfig.sieve
+  sieve_max_script_size = 2M
+  sieve_max_actions = 100
+  sieve_max_redirects = 25
 }
 
 # Config files can also be included. deliver doesn't support them currently.
diff --git a/install/tpl/fedora_dovecot2.conf.master b/install/tpl/fedora_dovecot2.conf.master
index dbef641fdf..9fd5ed92c2 100644
--- a/install/tpl/fedora_dovecot2.conf.master
+++ b/install/tpl/fedora_dovecot2.conf.master
@@ -21,7 +21,14 @@ userdb {
 }
 plugin {
   quota = dict:user::file:/var/vmail/%d/%n/.quotausage
+
+  # no longer needed, as 'sieve' is in userdb extra fields:
   sieve=/var/vmail/%d/%n/.sieve
+
+  sieve_after=/var/vmail/%d/%n/.ispconfig.sieve
+  sieve_max_script_size = 2M
+  sieve_max_actions = 100
+  sieve_max_redirects = 25
 }
 service auth {
   unix_listener /var/spool/postfix/private/auth {
diff --git a/install/tpl/opensuse_dovecot.conf.master b/install/tpl/opensuse_dovecot.conf.master
index 9d345fa911..1eacf4c3a3 100644
--- a/install/tpl/opensuse_dovecot.conf.master
+++ b/install/tpl/opensuse_dovecot.conf.master
@@ -1274,11 +1274,16 @@ plugin {
   # 
   # Location of the active script. When ManageSieve is used this is actually 
   # a symlink pointing to the active script in the sieve storage directory. 
-  sieve=~/.dovecot.sieve
-  #
+  sieve=~/.sieve
+
   # The path to the directory where the personal Sieve scripts are stored. For 
   # ManageSieve this is where the uploaded scripts are stored.
   sieve_dir=~/sieve
+
+  sieve_after=/var/vmail/%d/%n/.ispconfig.sieve
+  sieve_max_script_size = 2M
+  sieve_max_actions = 100
+  sieve_max_redirects = 25
 }
 
 # Config files can also be included. deliver doesn't support them currently.
diff --git a/install/tpl/opensuse_dovecot2.conf.master b/install/tpl/opensuse_dovecot2.conf.master
index a1bdfa1f91..94e658aecc 100644
--- a/install/tpl/opensuse_dovecot2.conf.master
+++ b/install/tpl/opensuse_dovecot2.conf.master
@@ -21,7 +21,14 @@ userdb {
 }
 plugin {
   quota = dict:user::file:/var/vmail/%d/%n/.quotausage
+
+  # no longer needed, as 'sieve' is in userdb extra fields:
   sieve=/var/vmail/%d/%n/.sieve
+
+  sieve_after=/var/vmail/%d/%n/.ispconfig.sieve
+  sieve_max_script_size = 2M
+  sieve_max_actions = 100
+  sieve_max_redirects = 25
 }
 service auth {
   unix_listener /var/spool/postfix/private/auth {
diff --git a/server/conf/sieve_filter.master b/server/conf/sieve_filter.master
index 13c08dd56b..f72cd11d1f 100644
--- a/server/conf/sieve_filter.master
+++ b/server/conf/sieve_filter.master
@@ -1,3 +1,6 @@
+# This sieve script is generated by ISPConfig, any changes made will be overwritten.
+# You can create and activate a per-user sieve script (manually or via managesieve),
+# which will execute before this.
 require ["fileinto", "regex", "date", "relational", "vacation", "imap4flags", "envelope", "subaddress", "copy", "reject"];
 
 <tmpl_if name="cc">
@@ -36,4 +39,4 @@ vacation  :days 1
   # :addresses ["test@test.int", "till@test.int"]
   <tmpl_var name='addresses'>
   "<tmpl_var name='autoresponder_text'>";
-</tmpl_if>
\ No newline at end of file
+</tmpl_if>
diff --git a/server/conf/sieve_filter_1.2.master b/server/conf/sieve_filter_1.2.master
index 5244693102..edd4060b9f 100644
--- a/server/conf/sieve_filter_1.2.master
+++ b/server/conf/sieve_filter_1.2.master
@@ -1,3 +1,6 @@
+# This sieve script is generated by ISPConfig, any changes made will be overwritten.
+# You can create and activate a per-user sieve script (manually or via managesieve),
+# which will execute before this.
 require ["fileinto", "regex", "date", "relational", "vacation", "imap4flags", "envelope", "subaddress", "copy", "reject"];
 
 <tmpl_if name="move_junk" op="==" value="y">
diff --git a/server/plugins-available/maildeliver_plugin.inc.php b/server/plugins-available/maildeliver_plugin.inc.php
index 2c16601f50..9c9939655c 100644
--- a/server/plugins-available/maildeliver_plugin.inc.php
+++ b/server/plugins-available/maildeliver_plugin.inc.php
@@ -98,9 +98,16 @@ class maildeliver_plugin {
 			$app->log("Mailfilter config has been changed", LOGLEVEL_DEBUG);
 
 			$sieve_file = $data["new"]["maildir"].'/.sieve';
-			$sieve_file_isp = $data["new"]["maildir"].'/sieve/ispconfig.sieve';
-			if(is_file($sieve_file)) unlink($sieve_file)  or $app->log("Unable to delete file: $sieve_file", LOGLEVEL_WARN);
+			$sieve_file_svbin = $data["new"]["maildir"].'/.sieve.svbin';
+			$old_sieve_file_isp = $data["new"]["maildir"].'/sieve/ispconfig.sieve';
+			$sieve_file_isp = $data["new"]["maildir"].'/.ispconfig.sieve';
+			$sieve_file_isp_svbin = $data["new"]["maildir"].'/.ispconfig.svbin';
+			if(is_file($old_sieve_file_isp)) unlink($old_sieve_file_isp)  or $app->log("Unable to delete file: $old_sieve_file_isp", LOGLEVEL_WARN);
+			// cleanup .sieve file if it is now a broken link
+			if(is_link($sieve_file) && !file_exists($sieve_file)) unlink($sieve_file)  or $app->log("Unable to delete file: $sieve_file", LOGLEVEL_WARN);
+			if(is_file($sieve_file_svbin)) unlink($sieve_file_svbin)  or $app->log("Unable to delete file: $sieve_file_svbin", LOGLEVEL_WARN);
 			if(is_file($sieve_file_isp)) unlink($sieve_file_isp)  or $app->log("Unable to delete file: $sieve_file_isp", LOGLEVEL_WARN);
+			if(is_file($sieve_file_isp_svbin)) unlink($sieve_file_isp_svbin)  or $app->log("Unable to delete file: $sieve_file_isp_svbin", LOGLEVEL_WARN);
 			$app->load('tpl');
 
 			//* Select sieve filter file for dovecot version
@@ -221,16 +228,13 @@ class maildeliver_plugin {
 			if ( is_file($sieve_file_isp) ) {
 				$app->system->chown($sieve_file_isp,$mail_config['mailuser_name'],false);
 				$app->system->chgrp($sieve_file_isp,$mail_config['mailuser_group'],false);
+
+				$app->system->exec_safe("sievec ?", "$sieve_file_isp");
+				if ( is_file($sieve_file_isp_svbin) ) {
+					$app->system->chown($sieve_file_isp_svbin,$mail_config['mailuser_name'],false);
+					$app->system->chgrp($sieve_file_isp_svbin,$mail_config['mailuser_group'],false);
+				}
 			}
-			chdir($data["new"]["maildir"]);
-			//* create symlink to activate sieve script
-			symlink("sieve/ispconfig.sieve", ".sieve")  or $app->log("Unable to create symlink to active sieve filter", LOGLEVEL_WARN);
-			if (is_link(".sieve")) {
-				$app->system->chown(".sieve",$mail_config['mailuser_name'],true);
-				$app->system->chgrp(".sieve",$mail_config['mailuser_group'],true);
-			}
-			$app->system->chown($sieve_file,$mail_config['mailuser_name'],true);
-			$app->system->chgrp($sieve_file,$mail_config['mailuser_group'],true);
 
 			unset($tpl);
 
@@ -241,9 +245,16 @@ class maildeliver_plugin {
 		global $app, $conf;
 
 		$sieve_file = $data["old"]["maildir"].'/.sieve';
-		$sieve_file_isp = $data["old"]["maildir"].'/sieve/ispconfig.sieve';
-		if(is_file($sieve_file)) unlink($sieve_file)  or $app->log("Unable to delete file: $sieve_file", LOGLEVEL_WARN);
+		$sieve_file_svbin = $data["old"]["maildir"].'/.sieve.svbin';
+		$old_sieve_file_isp = $data["old"]["maildir"].'/sieve/ispconfig.sieve';
+		$sieve_file_isp = $data["old"]["maildir"].'/.ispconfig.sieve';
+		$sieve_file_isp_svbin = $data["old"]["maildir"].'/.ispconfig.svbin';
+		if(is_file($old_sieve_file_isp)) unlink($old_sieve_file_isp)  or $app->log("Unable to delete file: $old_sieve_file_isp", LOGLEVEL_WARN);
+		// cleanup .sieve file if it is now a broken link
+		if(is_link($sieve_file) && !file_exists($sieve_file)) unlink($sieve_file)  or $app->log("Unable to delete file: $sieve_file", LOGLEVEL_WARN);
+		if(is_file($sieve_file_svbin)) unlink($sieve_file_svbin)  or $app->log("Unable to delete file: $sieve_file_svbin", LOGLEVEL_WARN);
 		if(is_file($sieve_file_isp)) unlink($sieve_file_isp)  or $app->log("Unable to delete file: $sieve_file_isp", LOGLEVEL_WARN);
+		if(is_file($sieve_file_isp_svbin)) unlink($sieve_file_isp_svbin)  or $app->log("Unable to delete file: $sieve_file_isp_svbin", LOGLEVEL_WARN);
 	}
 
 
-- 
GitLab