mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-05-06 09:25:54 +02:00
- Add install/snappymail/plugins/list-unsubscribe-header (upstream GitHub plugin) - Add plogical/snappymail_plugin_utilities.py to copy into snappymail + legacy rainloop data roots and merge enabled_list - Run after SnappyMail CyberPanel installer in install.py and upgrade.py - InstallMailBoxFoldersPlugin now merges plugins instead of replacing enabled_list; also installs list-unsubscribe Roundcube is not shipped by CyberPanel core; SnappyMail is the bundled webmail.
137 lines
4.3 KiB
Python
137 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
Bundle and enable the SnappyMail list-unsubscribe-header plugin (CyberPanel).
|
|
|
|
Data may live under snappymail/ or legacy rainloop/ until migration completes.
|
|
Upstream plugin: https://github.com/master3395/snappymail-list-unsubscribe-header
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
|
|
PLUGIN_ID_LIST_UNSUBSCRIBE = 'list-unsubscribe-header'
|
|
BUNDLE_REL = 'install/snappymail/plugins/list-unsubscribe-header/index.php'
|
|
CYBERCP_ROOT = '/usr/local/CyberCP'
|
|
|
|
DATA_ROOT_CANDIDATES = (
|
|
'/usr/local/lscp/cyberpanel/snappymail/data',
|
|
'/usr/local/lscp/cyberpanel/rainloop/data',
|
|
)
|
|
|
|
|
|
def bundled_list_unsubscribe_src():
|
|
return os.path.join(CYBERCP_ROOT, BUNDLE_REL)
|
|
|
|
|
|
def _merge_enabled_list_line(line, plugin_id):
|
|
"""Merge plugin_id into SnappyMail enabled_list = \"...\" line."""
|
|
m = re.match(r'^(\s*enabled_list\s*=\s*")([^"]*)("\s*)\r?$', line)
|
|
if not m:
|
|
return line
|
|
inner = m.group(2)
|
|
parts = [p.strip() for p in inner.split(',') if p.strip()]
|
|
if plugin_id not in parts:
|
|
parts.append(plugin_id)
|
|
inner_new = ','.join(parts)
|
|
return m.group(1) + inner_new + m.group(3) + ('\n' if line.endswith('\n') else '')
|
|
|
|
|
|
def _force_plugins_enable_on_line(line):
|
|
"""Under [plugins], ensure enable = On."""
|
|
if not re.match(r'^\s*enable\s*=', line):
|
|
return line
|
|
if re.search(r'(?i)=\s*On\b', line):
|
|
return line
|
|
return re.sub(r'(?i)=\s*\S+', '= On', line, count=1)
|
|
|
|
|
|
def merge_plugin_into_application_ini(application_ini_path, plugin_id):
|
|
"""
|
|
Merge plugin_id into [plugins] enabled_list; set enable = On when that key is present.
|
|
"""
|
|
if not os.path.isfile(application_ini_path):
|
|
return False
|
|
with open(application_ini_path, 'r') as f:
|
|
lines = f.readlines()
|
|
out = []
|
|
in_plugins = False
|
|
for line in lines:
|
|
stripped = line.lstrip()
|
|
if stripped.startswith('[plugins]'):
|
|
in_plugins = True
|
|
out.append(line)
|
|
continue
|
|
if in_plugins and stripped.startswith('[') and not stripped.startswith('[plugins]'):
|
|
in_plugins = False
|
|
if in_plugins and re.match(r'^\s*enabled_list\s*=', line):
|
|
out.append(_merge_enabled_list_line(line, plugin_id))
|
|
continue
|
|
if in_plugins and re.match(r'^\s*enable\s*=', line):
|
|
out.append(_force_plugins_enable_on_line(line))
|
|
continue
|
|
out.append(line)
|
|
with open(application_ini_path, 'w') as f:
|
|
f.writelines(out)
|
|
return True
|
|
|
|
|
|
def _chown_lscpd(path):
|
|
try:
|
|
subprocess.check_call(['chown', 'lscpd:lscpd', path], stderr=subprocess.DEVNULL)
|
|
except (OSError, subprocess.CalledProcessError):
|
|
pass
|
|
|
|
|
|
def _copy_bundled_plugin_to_data_root(data_root):
|
|
"""Copy bundled index.php into .../plugins/list-unsubscribe-header/."""
|
|
src = bundled_list_unsubscribe_src()
|
|
if not os.path.isfile(src):
|
|
return False
|
|
dest_dir = os.path.join(
|
|
data_root, '_data_', '_default_', 'plugins', PLUGIN_ID_LIST_UNSUBSCRIBE
|
|
)
|
|
try:
|
|
os.makedirs(dest_dir, mode=0o700, exist_ok=True)
|
|
except OSError:
|
|
return False
|
|
dest_file = os.path.join(dest_dir, 'index.php')
|
|
try:
|
|
shutil.copy2(src, dest_file)
|
|
except (OSError, IOError):
|
|
return False
|
|
try:
|
|
os.chmod(dest_file, 0o644)
|
|
except OSError:
|
|
pass
|
|
_chown_lscpd(dest_file)
|
|
_chown_lscpd(dest_dir)
|
|
return True
|
|
|
|
|
|
def install_and_enable_list_unsubscribe_header_plugin():
|
|
"""
|
|
Copy bundled plugin into each existing SnappyMail data root and merge into enabled_list.
|
|
Idempotent. Returns 1 if at least one data root was updated, else 0.
|
|
"""
|
|
if not os.path.isfile(bundled_list_unsubscribe_src()):
|
|
return 0
|
|
ok = 0
|
|
for root in DATA_ROOT_CANDIDATES:
|
|
default_path = os.path.join(root, '_data_', '_default_')
|
|
if not os.path.isdir(default_path):
|
|
continue
|
|
if not _copy_bundled_plugin_to_data_root(root):
|
|
continue
|
|
app_ini = os.path.join(default_path, 'configs', 'application.ini')
|
|
if os.path.isfile(app_ini):
|
|
merge_plugin_into_application_ini(app_ini, PLUGIN_ID_LIST_UNSUBSCRIBE)
|
|
try:
|
|
os.chmod(app_ini, 0o600)
|
|
except OSError:
|
|
pass
|
|
_chown_lscpd(app_ini)
|
|
ok = 1
|
|
return ok
|