diff --git a/install/installCyberPanel.py b/install/installCyberPanel.py index 9b6469bc9..9bde377ef 100644 --- a/install/installCyberPanel.py +++ b/install/installCyberPanel.py @@ -696,6 +696,7 @@ module cyberpanel_ols { # Write ManageSieve config managesieve_conf = '/etc/dovecot/conf.d/20-managesieve.conf' + os.makedirs('/etc/dovecot/conf.d', exist_ok=True) with open(managesieve_conf, 'w') as f: f.write("""protocols = $protocols sieve diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 38770e225..f2d7cbaaf 100644 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -2857,6 +2857,8 @@ CREATE TABLE `websiteFunctions_backupsv2` (`id` integer AUTO_INCREMENT NOT NULL Upgrade.stdOut("Dovecot not installed, skipping Sieve setup.", 0) return + import re + dovecot_conf = '/etc/dovecot/dovecot.conf' with open(dovecot_conf, 'r') as f: content = f.read() @@ -2864,33 +2866,37 @@ CREATE TABLE `websiteFunctions_backupsv2` (`id` integer AUTO_INCREMENT NOT NULL changed = False # Add sieve to protocols if missing - if 'sieve' not in content.split('\n')[0]: - content = content.replace('protocols = imap pop3', 'protocols = imap pop3 sieve', 1) + protocols_match = re.search(r'^protocols\s*=\s*(.+)$', content, re.MULTILINE) + if protocols_match and 'sieve' not in protocols_match.group(1): + content = content.replace(protocols_match.group(0), + protocols_match.group(0) + ' sieve') changed = True - # Add sieve plugin to protocol lda if missing - import re - lda_match = re.search(r'(protocol lda\s*\{[^}]*mail_plugins\s*=\s*)(zlib)(\s*\n)', content) - if lda_match and 'sieve' not in lda_match.group(0): + # Add sieve plugin to protocol lda mail_plugins if missing + lda_match = re.search(r'(protocol lda\s*\{[^}]*mail_plugins\s*=\s*)([^\n]+)', content) + if lda_match and 'sieve' not in lda_match.group(2): content = content.replace(lda_match.group(0), - lda_match.group(1) + 'zlib sieve' + lda_match.group(3)) + lda_match.group(1) + lda_match.group(2).rstrip() + ' sieve') changed = True # Add lda_mailbox_autocreate/autosubscribe for sieve fileinto if 'lda_mailbox_autocreate' not in content: - content = re.sub( - r'(protocol lda\s*\{[^}]*mail_plugins\s*=\s*zlib sieve\n)', - r'\1 lda_mailbox_autocreate = yes\n lda_mailbox_autosubscribe = yes\n', - content) - changed = True + lda_plugins = re.search(r'(protocol lda\s*\{[^}]*mail_plugins\s*=[^\n]+\n)', content) + if lda_plugins: + content = content.replace(lda_plugins.group(0), + lda_plugins.group(0) + + ' lda_mailbox_autocreate = yes\n lda_mailbox_autosubscribe = yes\n') + changed = True # Add sieve storage settings to plugin section if 'sieve_dir' not in content: - content = re.sub( - r'(plugin\s*\{[^}]*zlib_save_level\s*=\s*6\n)', - r'\1\n sieve = ~/sieve/.dovecot.sieve\n sieve_dir = ~/sieve\n', - content) - changed = True + plugin_match = re.search(r'(plugin\s*\{[^}]*)(})', content) + if plugin_match: + content = content.replace(plugin_match.group(0), + plugin_match.group(1) + + '\n sieve = ~/sieve/.dovecot.sieve\n sieve_dir = ~/sieve\n\n' + + plugin_match.group(2)) + changed = True if changed: with open(dovecot_conf, 'w') as f: @@ -2901,11 +2907,11 @@ CREATE TABLE `websiteFunctions_backupsv2` (`id` integer AUTO_INCREMENT NOT NULL if os.path.exists(sql_conf): with open(sql_conf, 'r') as f: sql_content = f.read() - if 'as home' not in sql_content and "user_query" in sql_content: - sql_content = sql_content.replace( - "user_query = SELECT '5000' as uid, '5000' as gid, mail FROM e_users WHERE email='%u';", - "user_query = SELECT '5000' as uid, '5000' as gid, mail, CONCAT('/home/vmail/', SUBSTRING_INDEX(email, '@', -1), '/', SUBSTRING_INDEX(email, '@', 1)) as home FROM e_users WHERE email='%u';" - ) + if 'as home' not in sql_content and 'user_query' in sql_content: + sql_content = re.sub( + r"(user_query\s*=\s*SELECT\s+'5000'\s+as\s+uid,\s+'5000'\s+as\s+gid,\s+mail)\s+(FROM\s+e_users\s+WHERE\s+email='%u';)", + r"\1, CONCAT('/home/vmail/', SUBSTRING_INDEX(email, '@', -1), '/', SUBSTRING_INDEX(email, '@', 1)) as home \2", + sql_content) with open(sql_conf, 'w') as f: f.write(sql_content) @@ -2915,10 +2921,11 @@ CREATE TABLE `websiteFunctions_backupsv2` (`id` integer AUTO_INCREMENT NOT NULL if os.path.exists(managesieve_conf): with open(managesieve_conf, 'r') as f: existing = f.read() - if 'inet_listener sieve' in existing and not existing.strip().startswith('#'): + if 'inet_listener sieve' in existing and 'service managesieve' in existing: write_managesieve = False if write_managesieve: + os.makedirs('/etc/dovecot/conf.d', exist_ok=True) with open(managesieve_conf, 'w') as f: f.write("""protocols = $protocols sieve diff --git a/webmail/services/sieve_client.py b/webmail/services/sieve_client.py index 4cdfc4e46..b307613cb 100644 --- a/webmail/services/sieve_client.py +++ b/webmail/services/sieve_client.py @@ -208,7 +208,11 @@ class SieveClient: # Map action if action_type == 'move': requires.add('fileinto') - action = 'fileinto "%s";' % action_value + # Ensure folder uses INBOX. namespace prefix for dovecot + folder = action_value + if folder and not folder.startswith('INBOX.'): + folder = 'INBOX.%s' % folder + action = 'fileinto "%s";' % folder elif action_type == 'forward': requires.add('redirect') action = 'redirect "%s";' % action_value @@ -254,6 +258,9 @@ class SieveClient: action_type = 'move' av = re.search(r'fileinto\s+"([^"]+)"', action_block) action_value = av.group(1) if av else '' + # Strip INBOX. namespace prefix for display + if action_value.startswith('INBOX.'): + action_value = action_value[6:] elif 'redirect' in action_block: action_type = 'forward' av = re.search(r'redirect\s+"([^"]+)"', action_block) diff --git a/webmail/templates/webmail/index.html b/webmail/templates/webmail/index.html index 822323b7e..fc93ca2b2 100644 --- a/webmail/templates/webmail/index.html +++ b/webmail/templates/webmail/index.html @@ -392,10 +392,17 @@ -