From bfd88937c34d2387057a59a00eedb2e3e6a118c5 Mon Sep 17 00:00:00 2001
From: Judah - MW <6523-maximaweb@users.noreply.git.ispconfig.org>
Date: Fri, 28 Apr 2023 09:27:37 +0000
Subject: [PATCH] Support configurable IMAP prefix per mailbox

---
 .../sql/incremental/upd_dev_collection.sql    |  4 +++-
 install/sql/ispconfig3.sql                    |  1 +
 install/tpl/debian6_dovecot-sql.conf.master   |  4 ++--
 install/tpl/debian_dovecot-sql.conf.master    |  4 ++--
 install/tpl/fedora_dovecot-sql.conf.master    |  4 ++--
 install/tpl/opensuse_dovecot-sql.conf.master  |  4 ++--
 interface/web/mail/form/mail_user.tform.php   | 24 ++++++++++++++++++-
 interface/web/mail/lib/lang/ar_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/bg_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/ca_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/de_mail_user.lng  |  3 +++
 interface/web/mail/lib/lang/dk_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/el_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/en_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/es_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/fi_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/fr_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/hr_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/hu_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/id_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/it_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/ja_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/nl_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/pl_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/pt_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/ro_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/ru_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/se_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/sk_mail_user.lng  |  2 ++
 interface/web/mail/lib/lang/tr_mail_user.lng  |  2 ++
 .../mail/templates/mail_user_mailbox_edit.htm |  6 +++++
 server/conf/sieve_filter.master               |  4 ++--
 .../cron.d/500-clean_mailboxes.inc.php        | 20 ++++++++++++----
 .../maildeliver_plugin.inc.php                |  1 +
 34 files changed, 106 insertions(+), 17 deletions(-)

diff --git a/install/sql/incremental/upd_dev_collection.sql b/install/sql/incremental/upd_dev_collection.sql
index c3d8c5b210..55bb0f294a 100644
--- a/install/sql/incremental/upd_dev_collection.sql
+++ b/install/sql/incremental/upd_dev_collection.sql
@@ -1,2 +1,4 @@
-
 ALTER TABLE `mail_user` CHANGE `quota` `quota` BIGINT(20) NOT NULL DEFAULT '0';
+-- 5918 add imap_prefix column to mail_user table
+ALTER TABLE `mail_user` ADD COLUMN `imap_prefix` varchar(255) NULL default NULL AFTER `backup_copies`;
+
diff --git a/install/sql/ispconfig3.sql b/install/sql/ispconfig3.sql
index e9ed67c86a..985720b845 100644
--- a/install/sql/ispconfig3.sql
+++ b/install/sql/ispconfig3.sql
@@ -1101,6 +1101,7 @@ CREATE TABLE `mail_user` (
   `last_quota_notification` date NULL default NULL,
   `backup_interval` VARCHAR( 255 ) NOT NULL default 'none',
   `backup_copies` INT NOT NULL DEFAULT '1',
+  `imap_prefix` varchar(255) NULL default NULL,
   PRIMARY KEY  (`mailuser_id`),
   KEY `server_id` (`server_id`,`email`),
   KEY `email_access` (`email`,`access`)
diff --git a/install/tpl/debian6_dovecot-sql.conf.master b/install/tpl/debian6_dovecot-sql.conf.master
index d0b5269e13..370c2aa9cb 100644
--- a/install/tpl/debian6_dovecot-sql.conf.master
+++ b/install/tpl/debian6_dovecot-sql.conf.master
@@ -5,9 +5,9 @@ connect = host={mysql_server_host} dbname={mysql_server_database} user={mysql_se
 default_pass_scheme = CRYPT
 
 # password-query with prefetch
-password_query = SELECT email as user, password, maildir as userdb_home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as userdb_mail, uid as userdb_uid, gid as userdb_gid, CONCAT('*:storage=', quota, 'B') AS userdb_quota_rule, CONCAT(maildir, '/.sieve') as userdb_sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}' AND NOT EXISTS (SELECT domain_id FROM mail_domain WHERE domain = '%d' AND active = 'n' AND server_id = {server_id})
+password_query = SELECT email as user, password, maildir as userdb_home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as userdb_mail, uid as userdb_uid, gid as userdb_gid, CONCAT('*:storage=', quota, 'B') AS userdb_quota_rule, CONCAT(maildir, '/.sieve') as userdb_sieve, NULLIF(imap_prefix, '') as "userdb_namespace/inbox/prefix" FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}' AND NOT EXISTS (SELECT domain_id FROM mail_domain WHERE domain = '%d' AND active = 'n' AND server_id = {server_id})
 
-user_query = SELECT email as user, maildir as home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}'
+user_query = SELECT email as user, maildir as home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve, NULLIF(imap_prefix, '') as "namespace/inbox/prefix" FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}'
 
 # The iterate_query is required for the doveadm command only and works only on dovecot 2 servers.
 # Do not enable it on Dovecot 1.x servers
diff --git a/install/tpl/debian_dovecot-sql.conf.master b/install/tpl/debian_dovecot-sql.conf.master
index d0b5269e13..370c2aa9cb 100644
--- a/install/tpl/debian_dovecot-sql.conf.master
+++ b/install/tpl/debian_dovecot-sql.conf.master
@@ -5,9 +5,9 @@ connect = host={mysql_server_host} dbname={mysql_server_database} user={mysql_se
 default_pass_scheme = CRYPT
 
 # password-query with prefetch
-password_query = SELECT email as user, password, maildir as userdb_home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as userdb_mail, uid as userdb_uid, gid as userdb_gid, CONCAT('*:storage=', quota, 'B') AS userdb_quota_rule, CONCAT(maildir, '/.sieve') as userdb_sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}' AND NOT EXISTS (SELECT domain_id FROM mail_domain WHERE domain = '%d' AND active = 'n' AND server_id = {server_id})
+password_query = SELECT email as user, password, maildir as userdb_home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as userdb_mail, uid as userdb_uid, gid as userdb_gid, CONCAT('*:storage=', quota, 'B') AS userdb_quota_rule, CONCAT(maildir, '/.sieve') as userdb_sieve, NULLIF(imap_prefix, '') as "userdb_namespace/inbox/prefix" FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}' AND NOT EXISTS (SELECT domain_id FROM mail_domain WHERE domain = '%d' AND active = 'n' AND server_id = {server_id})
 
-user_query = SELECT email as user, maildir as home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}'
+user_query = SELECT email as user, maildir as home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve, NULLIF(imap_prefix, '') as "namespace/inbox/prefix" FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}'
 
 # The iterate_query is required for the doveadm command only and works only on dovecot 2 servers.
 # Do not enable it on Dovecot 1.x servers
diff --git a/install/tpl/fedora_dovecot-sql.conf.master b/install/tpl/fedora_dovecot-sql.conf.master
index d0b5269e13..370c2aa9cb 100644
--- a/install/tpl/fedora_dovecot-sql.conf.master
+++ b/install/tpl/fedora_dovecot-sql.conf.master
@@ -5,9 +5,9 @@ connect = host={mysql_server_host} dbname={mysql_server_database} user={mysql_se
 default_pass_scheme = CRYPT
 
 # password-query with prefetch
-password_query = SELECT email as user, password, maildir as userdb_home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as userdb_mail, uid as userdb_uid, gid as userdb_gid, CONCAT('*:storage=', quota, 'B') AS userdb_quota_rule, CONCAT(maildir, '/.sieve') as userdb_sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}' AND NOT EXISTS (SELECT domain_id FROM mail_domain WHERE domain = '%d' AND active = 'n' AND server_id = {server_id})
+password_query = SELECT email as user, password, maildir as userdb_home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as userdb_mail, uid as userdb_uid, gid as userdb_gid, CONCAT('*:storage=', quota, 'B') AS userdb_quota_rule, CONCAT(maildir, '/.sieve') as userdb_sieve, NULLIF(imap_prefix, '') as "userdb_namespace/inbox/prefix" FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}' AND NOT EXISTS (SELECT domain_id FROM mail_domain WHERE domain = '%d' AND active = 'n' AND server_id = {server_id})
 
-user_query = SELECT email as user, maildir as home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}'
+user_query = SELECT email as user, maildir as home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve, NULLIF(imap_prefix, '') as "namespace/inbox/prefix" FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}'
 
 # The iterate_query is required for the doveadm command only and works only on dovecot 2 servers.
 # Do not enable it on Dovecot 1.x servers
diff --git a/install/tpl/opensuse_dovecot-sql.conf.master b/install/tpl/opensuse_dovecot-sql.conf.master
index d0b5269e13..370c2aa9cb 100644
--- a/install/tpl/opensuse_dovecot-sql.conf.master
+++ b/install/tpl/opensuse_dovecot-sql.conf.master
@@ -5,9 +5,9 @@ connect = host={mysql_server_host} dbname={mysql_server_database} user={mysql_se
 default_pass_scheme = CRYPT
 
 # password-query with prefetch
-password_query = SELECT email as user, password, maildir as userdb_home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as userdb_mail, uid as userdb_uid, gid as userdb_gid, CONCAT('*:storage=', quota, 'B') AS userdb_quota_rule, CONCAT(maildir, '/.sieve') as userdb_sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}' AND NOT EXISTS (SELECT domain_id FROM mail_domain WHERE domain = '%d' AND active = 'n' AND server_id = {server_id})
+password_query = SELECT email as user, password, maildir as userdb_home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as userdb_mail, uid as userdb_uid, gid as userdb_gid, CONCAT('*:storage=', quota, 'B') AS userdb_quota_rule, CONCAT(maildir, '/.sieve') as userdb_sieve, NULLIF(imap_prefix, '') as "userdb_namespace/inbox/prefix" FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}' AND NOT EXISTS (SELECT domain_id FROM mail_domain WHERE domain = '%d' AND active = 'n' AND server_id = {server_id})
 
-user_query = SELECT email as user, maildir as home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}'
+user_query = SELECT email as user, maildir as home, CONCAT( maildir_format, ':', maildir, '/', IF(maildir_format='maildir','Maildir',maildir_format)) as mail, uid, gid, CONCAT('*:storage=', quota, 'B') AS quota_rule, CONCAT(maildir, '/.sieve') as sieve, NULLIF(imap_prefix, '') as "namespace/inbox/prefix" FROM mail_user WHERE (login = '%u' OR email = '%u') AND `disable%Ls` = 'n' AND server_id = '{server_id}'
 
 # The iterate_query is required for the doveadm command only and works only on dovecot 2 servers.
 # Do not enable it on Dovecot 1.x servers
diff --git a/interface/web/mail/form/mail_user.tform.php b/interface/web/mail/form/mail_user.tform.php
index f513aeb9d3..d135e4f3de 100644
--- a/interface/web/mail/form/mail_user.tform.php
+++ b/interface/web/mail/form/mail_user.tform.php
@@ -216,6 +216,29 @@ $form["tabs"]['mailuser'] = array(
 			'maxlength' => '255',
 			'searchable' => 2
 		),
+	)
+);
+
+if($app->auth->is_admin()) {
+	$form["tabs"]['mailuser']['fields'] += array(
+			'imap_prefix' => array (
+				'datatype' => 'VARCHAR',
+				'formtype' => 'TEXT',
+				'filters'   => array(
+						0 => array( 'event' => 'SAVE',
+						'type' => 'STRIPTAGS'),
+						1 => array( 'event' => 'SAVE',
+						'type' => 'STRIPNL')
+				),
+				'default' => '',
+				'value'  => '',
+				'width'  => '30',
+				'maxlength' => '255',
+			),
+	);
+}
+
+$form["tabs"]['mailuser']['fields'] += array(
 		'maildir' => array (
 			'datatype' => 'VARCHAR',
 			'formtype' => 'TEXT',
@@ -321,7 +344,6 @@ $form["tabs"]['mailuser'] = array(
 		//#################################
 		// END Datatable fields
 		//#################################
-	)
 );
 
 if($global_config['mail']['mail_password_onlyascii'] == 'y') {
diff --git a/interface/web/mail/lib/lang/ar_mail_user.lng b/interface/web/mail/lib/lang/ar_mail_user.lng
index 36d274c7ab..a879201cb0 100644
--- a/interface/web/mail/lib/lang/ar_mail_user.lng
+++ b/interface/web/mail/lib/lang/ar_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/bg_mail_user.lng b/interface/web/mail/lib/lang/bg_mail_user.lng
index d051c9efd9..3084b0d050 100644
--- a/interface/web/mail/lib/lang/bg_mail_user.lng
+++ b/interface/web/mail/lib/lang/bg_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/ca_mail_user.lng b/interface/web/mail/lib/lang/ca_mail_user.lng
index 0862ca5d1d..9489390a7e 100644
--- a/interface/web/mail/lib/lang/ca_mail_user.lng
+++ b/interface/web/mail/lib/lang/ca_mail_user.lng
@@ -74,4 +74,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/de_mail_user.lng b/interface/web/mail/lib/lang/de_mail_user.lng
index 2c49f352ff..db8c85a2da 100644
--- a/interface/web/mail/lib/lang/de_mail_user.lng
+++ b/interface/web/mail/lib/lang/de_mail_user.lng
@@ -74,4 +74,7 @@ $wb['purge_trash_days_txt'] = 'Papierkorb automatisch nach X Tagen leeren';
 $wb['tooltip_purge_trash_days_txt'] = '0 = deaktiviert';
 $wb['purge_junk_days_txt'] = 'Junk-Ordner automatisch nach X Tagen leeren';
 $wb['tooltip_purge_junk_days_txt'] = '0 = deaktiviert';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
+?>
 
diff --git a/interface/web/mail/lib/lang/dk_mail_user.lng b/interface/web/mail/lib/lang/dk_mail_user.lng
index 47b61bf225..d2e7cfd008 100644
--- a/interface/web/mail/lib/lang/dk_mail_user.lng
+++ b/interface/web/mail/lib/lang/dk_mail_user.lng
@@ -74,4 +74,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/el_mail_user.lng b/interface/web/mail/lib/lang/el_mail_user.lng
index 4eb1a35455..52b42874dd 100644
--- a/interface/web/mail/lib/lang/el_mail_user.lng
+++ b/interface/web/mail/lib/lang/el_mail_user.lng
@@ -74,4 +74,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/en_mail_user.lng b/interface/web/mail/lib/lang/en_mail_user.lng
index 42004fe5fd..96975a1a70 100644
--- a/interface/web/mail/lib/lang/en_mail_user.lng
+++ b/interface/web/mail/lib/lang/en_mail_user.lng
@@ -74,4 +74,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/es_mail_user.lng b/interface/web/mail/lib/lang/es_mail_user.lng
index a5299c488d..43e1c3c550 100644
--- a/interface/web/mail/lib/lang/es_mail_user.lng
+++ b/interface/web/mail/lib/lang/es_mail_user.lng
@@ -74,4 +74,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/fi_mail_user.lng b/interface/web/mail/lib/lang/fi_mail_user.lng
index 6f9d0639b7..bbb479d463 100644
--- a/interface/web/mail/lib/lang/fi_mail_user.lng
+++ b/interface/web/mail/lib/lang/fi_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/fr_mail_user.lng b/interface/web/mail/lib/lang/fr_mail_user.lng
index ddc82352f0..74abb9de7f 100644
--- a/interface/web/mail/lib/lang/fr_mail_user.lng
+++ b/interface/web/mail/lib/lang/fr_mail_user.lng
@@ -74,4 +74,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/hr_mail_user.lng b/interface/web/mail/lib/lang/hr_mail_user.lng
index 6c22395eca..0fa0370ceb 100644
--- a/interface/web/mail/lib/lang/hr_mail_user.lng
+++ b/interface/web/mail/lib/lang/hr_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/hu_mail_user.lng b/interface/web/mail/lib/lang/hu_mail_user.lng
index 7d26eab5cf..1661f5b669 100644
--- a/interface/web/mail/lib/lang/hu_mail_user.lng
+++ b/interface/web/mail/lib/lang/hu_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/id_mail_user.lng b/interface/web/mail/lib/lang/id_mail_user.lng
index 31a8bcb18e..fa5b74e8ea 100644
--- a/interface/web/mail/lib/lang/id_mail_user.lng
+++ b/interface/web/mail/lib/lang/id_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/it_mail_user.lng b/interface/web/mail/lib/lang/it_mail_user.lng
index fbfdfd2ae4..dba7214e90 100644
--- a/interface/web/mail/lib/lang/it_mail_user.lng
+++ b/interface/web/mail/lib/lang/it_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Svuota automaticamente il Cestino dopo X giorni';
 $wb['tooltip_purge_trash_days_txt'] = '0 = Disabilitato';
 $wb['purge_junk_days_txt'] = 'Svuota cartella Indesiderati automaticamente dopo X giorni';
 $wb['tooltip_purge_junk_days_txt'] = '0 = Disabilitato';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/ja_mail_user.lng b/interface/web/mail/lib/lang/ja_mail_user.lng
index 961dd4166a..fc094c352a 100644
--- a/interface/web/mail/lib/lang/ja_mail_user.lng
+++ b/interface/web/mail/lib/lang/ja_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/nl_mail_user.lng b/interface/web/mail/lib/lang/nl_mail_user.lng
index f2263aeea5..bf57cd61a9 100644
--- a/interface/web/mail/lib/lang/nl_mail_user.lng
+++ b/interface/web/mail/lib/lang/nl_mail_user.lng
@@ -74,4 +74,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/pl_mail_user.lng b/interface/web/mail/lib/lang/pl_mail_user.lng
index 6fe385fb3c..7ed80ace95 100644
--- a/interface/web/mail/lib/lang/pl_mail_user.lng
+++ b/interface/web/mail/lib/lang/pl_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/pt_mail_user.lng b/interface/web/mail/lib/lang/pt_mail_user.lng
index c69e9e00cd..3bc325a52e 100644
--- a/interface/web/mail/lib/lang/pt_mail_user.lng
+++ b/interface/web/mail/lib/lang/pt_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/ro_mail_user.lng b/interface/web/mail/lib/lang/ro_mail_user.lng
index 9970ea87f4..a7f2c4164d 100644
--- a/interface/web/mail/lib/lang/ro_mail_user.lng
+++ b/interface/web/mail/lib/lang/ro_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/ru_mail_user.lng b/interface/web/mail/lib/lang/ru_mail_user.lng
index f35ae2f750..f0ab8c0bba 100644
--- a/interface/web/mail/lib/lang/ru_mail_user.lng
+++ b/interface/web/mail/lib/lang/ru_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/se_mail_user.lng b/interface/web/mail/lib/lang/se_mail_user.lng
index 46f8776755..40c91caaa8 100644
--- a/interface/web/mail/lib/lang/se_mail_user.lng
+++ b/interface/web/mail/lib/lang/se_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/sk_mail_user.lng b/interface/web/mail/lib/lang/sk_mail_user.lng
index b9f59ec403..6af4528543 100644
--- a/interface/web/mail/lib/lang/sk_mail_user.lng
+++ b/interface/web/mail/lib/lang/sk_mail_user.lng
@@ -75,4 +75,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/lib/lang/tr_mail_user.lng b/interface/web/mail/lib/lang/tr_mail_user.lng
index 8a0bd4e27a..c3dfbf1ecf 100644
--- a/interface/web/mail/lib/lang/tr_mail_user.lng
+++ b/interface/web/mail/lib/lang/tr_mail_user.lng
@@ -74,4 +74,6 @@ $wb['purge_trash_days_txt'] = 'Purge Trash automatically after X days';
 $wb['tooltip_purge_trash_days_txt'] = '0 = disabled';
 $wb['purge_junk_days_txt'] = 'Purge Junk automatically after X days';
 $wb['tooltip_purge_junk_days_txt'] = '0 = disabled';
+$wb['imap_prefix_txt'] = 'IMAP prefix';
+$wb['tooltip_imap_prefix_txt'] = 'In most cases this should be left empty.  To allow seamless per-mailbox migration of legacy systems you can specify a prefix followed by the hierarchy separator. e.g.: \'INBOX.\'';
 ?>
diff --git a/interface/web/mail/templates/mail_user_mailbox_edit.htm b/interface/web/mail/templates/mail_user_mailbox_edit.htm
index 4bc77ac74d..7f6594267b 100644
--- a/interface/web/mail/templates/mail_user_mailbox_edit.htm
+++ b/interface/web/mail/templates/mail_user_mailbox_edit.htm
@@ -69,6 +69,12 @@
                 <label for="sender_name" class="col-sm-3 control-label">{tmpl_var name='sender_cc_txt'}</label>
                 <div class="col-sm-6"><input type="text" name="sender_cc" id="sender_cc" value="{tmpl_var name='sender_cc'}" class="form-control" /></div><div class="col-sm-3 input-sm"> &nbsp; {tmpl_var name='name_optional_txt'} {tmpl_var name='sender_cc_note_txt'}
             </div></div>
+            <tmpl_if name="is_admin"><div class="form-group">
+                <label for="imap_prefix" class="col-sm-3 control-label">{tmpl_var name='imap_prefix_txt'}</label>
+                <div class="col-sm-6">
+                    <input type="text" name="imap_prefix" id="imap_prefix" value="{tmpl_var name='imap_prefix'}" data-toggle="tooltip" title="{tmpl_var name='tooltip_imap_prefix_txt'}" class="form-control" />
+                </div><div class="col-sm-3 input-sm"> &nbsp; {tmpl_var name='name_optional_txt'}</div>
+            </div></tmpl_if>
             <div class="form-group">
                 <label for="policy" class="col-sm-3 control-label">{tmpl_var name='policy_txt'}</label>
                 <div class="col-sm-9"><select name="policy" id="policy" class="form-control">
diff --git a/server/conf/sieve_filter.master b/server/conf/sieve_filter.master
index 5635b946aa..8719717da8 100644
--- a/server/conf/sieve_filter.master
+++ b/server/conf/sieve_filter.master
@@ -8,7 +8,7 @@ require ["body", "copy", "date", "envelope", "fileinto", "imap4flags", "mailbox"
 <tmpl_if name="move_junk" op="==" value="y">
 # Move spam to spam folder
 if anyof (header :is ["X-Spam", "X-Spam-Flag"] "Yes", header :matches "X-Spam-Status" "Yes, *") {
-  fileinto :create "Junk";
+  fileinto :create "<tmpl_var name='imap_prefix'>Junk";
   # Stop here so that we do not reply on spams
   stop;
 }
@@ -34,7 +34,7 @@ require ["body", "copy", "date", "envelope", "fileinto", "imap4flags", "mailbox"
 <tmpl_if name="move_junk" op="==" value="a">
 # Move spam to spam folder
 if anyof (header :is ["X-Spam", "X-Spam-Flag"] "Yes", header :matches "X-Spam-Status" "Yes, *") {
-  fileinto :create "Junk";
+  fileinto :create "<tmpl_var name='imap_prefix'>Junk";
   # Stop here so that we do not reply on spams
   stop;
 }
diff --git a/server/lib/classes/cron.d/500-clean_mailboxes.inc.php b/server/lib/classes/cron.d/500-clean_mailboxes.inc.php
index 711c735db1..4a879dd7d7 100755
--- a/server/lib/classes/cron.d/500-clean_mailboxes.inc.php
+++ b/server/lib/classes/cron.d/500-clean_mailboxes.inc.php
@@ -53,27 +53,37 @@ class cronjob_clean_mailboxes extends cronjob {
 	public function onRunJob() {
 		global $app, $conf;
 
-		$trash_names=array('Trash', 'Papierkorb', 'Deleted Items', 'Deleted Messages', 'INBOX.Trash', 'INBOX.Papierkorb', 'INBOX.Deleted Messages', 'Corbeille');
-		$junk_names=array('Junk', 'Junk Email', 'SPAM', 'INBOX.SPAM');
+		$trash_names=array('Trash', 'Papierkorb', 'Deleted Items', 'Deleted Messages', 'Corbeille');
+		$junk_names=array('Junk', 'Junk Email', 'SPAM');
 
 		$expunge_cmd = 'doveadm expunge -u ? mailbox ? sentbefore ';
 		$purge_cmd = 'doveadm purge -u ?';
 		$recalc_cmd = 'doveadm quota recalc -u ?';
 
 		$server_id = intval($conf['server_id']);
-		$records = $app->db->queryAllRecords("SELECT email, maildir, purge_trash_days, purge_junk_days FROM mail_user WHERE maildir_format = 'maildir' AND disableimap = 'n' AND server_id = ? AND (purge_trash_days > 0 OR purge_junk_days > 0)", $server_id);
+		$records = $app->db->queryAllRecords("SELECT email, maildir, purge_trash_days, purge_junk_days, imap_prefix FROM mail_user WHERE maildir_format = 'maildir' AND disableimap = 'n' AND server_id = ? AND (purge_trash_days > 0 OR purge_junk_days > 0)", $server_id);
 		
 		if(is_array($records) && !empty($records)) {
 			foreach($records as $email) {
+
+				// Mapping function to add a prefix to all folder names.
+				$prefix_folders = function($folder) use($email) {
+					return $email['imap_prefix'] . $folder;
+				};
+
+				// Add a prefix to all folder names.
+				$prefixed_trash_names = array_map($prefix_folders, $trash_names);
+				$prefixed_junk_names = array_map($prefix_folders, $junk_names);
+
 				if($email['purge_trash_days'] > 0) {
-					foreach($trash_names as $trash) {
+					foreach($prefixed_trash_names as $trash) {
 						if(is_dir($email['maildir'].'/Maildir/.'.$trash)) {
 							$app->system->exec_safe($expunge_cmd.intval($email['purge_trash_days']).'d', $email['email'], $trash);
 						}
 					}
 				}
 				if($email['purge_junk_days'] > 0) {
-					foreach($junk_names as $junk) {
+					foreach($prefixed_junk_names as $junk) {
 						if(is_dir($email['maildir'].'/Maildir/.'.$junk)) {
 							$app->system->exec_safe($expunge_cmd.intval($email['purge_junk_days']).'d', $email['email'], $junk);
 						}
diff --git a/server/plugins-available/maildeliver_plugin.inc.php b/server/plugins-available/maildeliver_plugin.inc.php
index 168063c1a2..4a7a46fa89 100644
--- a/server/plugins-available/maildeliver_plugin.inc.php
+++ b/server/plugins-available/maildeliver_plugin.inc.php
@@ -139,6 +139,7 @@ class maildeliver_plugin {
 
 				// Move junk
 				$tpl->setVar('move_junk', $data["new"]["move_junk"]);
+				$tpl->setVar('imap_prefix', $data["new"]["imap_prefix"]);
 
 				// Set autoresponder start date
 				$data["new"]["autoresponder_start_date"] = str_replace(" ", "T", $data["new"]["autoresponder_start_date"]);
-- 
GitLab