diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php
index f3d4b114..bfcd1dca 100644
--- a/install/froxlor.sql.php
+++ b/install/froxlor.sql.php
@@ -95,6 +95,7 @@ CREATE TABLE `mail_virtual` (
`iscatchall` tinyint(1) unsigned NOT NULL default '0',
`description` varchar(255) NOT NULL DEFAULT '',
`spam_tag_level` float(4,1) NOT NULL DEFAULT 7.0,
+ `rewrite_subject` tinyint(1) NOT NULL default '1',
`spam_kill_level` float(4,1) NOT NULL DEFAULT 14.0,
`bypass_spam` tinyint(1) NOT NULL default '0',
`policy_greylist` tinyint(1) NOT NULL default '1',
@@ -730,7 +731,7 @@ opcache.validate_timestamps'),
('panel', 'settings_mode', '0'),
('panel', 'menu_collapsed', '1'),
('panel', 'version', '2.2.1'),
- ('panel', 'db_version', '202408140');
+ ('panel', 'db_version', '202409280');
DROP TABLE IF EXISTS `panel_tasks`;
diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php
index ccabd891..b9d9b900 100644
--- a/install/updates/froxlor/update_2.2.inc.php
+++ b/install/updates/froxlor/update_2.2.inc.php
@@ -169,3 +169,12 @@ if (Froxlor::isFroxlorVersion('2.2.0')) {
Update::showUpdateStep("Updating from 2.2.0 to 2.2.1", false);
Froxlor::updateToVersion('2.2.1');
}
+
+if (Froxlor::isDatabaseVersion('202408140')) {
+
+ Update::showUpdateStep("Adding new rewrite-subject field to email table");
+ Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `rewrite_subject` tinyint(1) NOT NULL default '1' AFTER `spam_tag_level`;");
+ Update::lastStepStatus(0);
+
+ Froxlor::updateToDbVersion('202409280');
+}
diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php
index ee7a2128..5294e639 100644
--- a/lib/Froxlor/Api/Commands/Emails.php
+++ b/lib/Froxlor/Api/Commands/Emails.php
@@ -53,6 +53,8 @@ class Emails extends ApiCommand implements ResourceEntity
* domain-name for the email-address
* @param float $spam_tag_level
* optional, score which is required to tag emails as spam, default: 7.0
+ * @param bool $rewrite_subject
+ * optional, whether to add ***SPAM*** to the email's subject if applicable, default true
* @param float $spam_kill_level
* optional, score which is required to discard emails, default: 14.0
* @param boolean $bypass_spam
@@ -85,7 +87,8 @@ class Emails extends ApiCommand implements ResourceEntity
// parameters
$spam_tag_level = $this->getParam('spam_tag_level', true, '7.0');
- $spam_kill_level = $this->getParam('spam_kill_level', true, '14.0');
+ $rewrite_subject = $this->getBoolParam('rewrite_subject', true, 1);
+ $spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, '14.0');
$bypass_spam = $this->getBoolParam('bypass_spam', true, 0);
$policy_greylist = $this->getBoolParam('policy_greylist', true, 1);
$iscatchall = $this->getBoolParam('iscatchall', true, 0);
@@ -155,8 +158,10 @@ class Emails extends ApiCommand implements ResourceEntity
}
}
- $spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1,2})?$/', '', [7.0], true);
- $spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1,2})?$/', '', [14.0], true);
+ $spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1})?$/', '', [7.0], true);
+ if ($spam_kill_level > -1) {
+ $spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1})?$/', '', [14.0], true);
+ }
$description = Validate::validate(trim($description), 'description', Validate::REGEX_DESC_TEXT, '', [], true);
$stmt = Database::prepare("
@@ -165,6 +170,7 @@ class Emails extends ApiCommand implements ResourceEntity
`email` = :email,
`email_full` = :email_full,
`spam_tag_level` = :spam_tag_level,
+ `rewrite_subject` = :rewrite_subject,
`spam_kill_level` = :spam_kill_level,
`bypass_spam` = :bypass_spam,
`policy_greylist` = :policy_greylist,
@@ -177,6 +183,7 @@ class Emails extends ApiCommand implements ResourceEntity
"email" => $email,
"email_full" => $email_full,
"spam_tag_level" => $spam_tag_level,
+ "rewrite_subject" => $rewrite_subject,
"spam_kill_level" => $spam_kill_level,
"bypass_spam" => $bypass_spam,
"policy_greylist" => $policy_greylist,
@@ -250,6 +257,8 @@ class Emails extends ApiCommand implements ResourceEntity
* optional, required when called as admin (if $customerid is not specified)
* @param float $spam_tag_level
* optional, score which is required to tag emails as spam, default: 7.0
+ * @param bool $rewrite_subject
+ * optional, whether to add ***SPAM*** to the email's subject if applicable, default true
* @param float $spam_kill_level
* optional, score which is required to discard emails, default: 14.0
* @param boolean $bypass_spam
@@ -283,7 +292,8 @@ class Emails extends ApiCommand implements ResourceEntity
// parameters
$spam_tag_level = $this->getParam('spam_tag_level', true, $result['spam_tag_level']);
- $spam_kill_level = $this->getParam('spam_kill_level', true, $result['spam_kill_level']);
+ $rewrite_subject = $this->getBoolParam('rewrite_subject', true, $result['rewrite_subject']);
+ $spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, $result['spam_kill_level']);
$bypass_spam = $this->getBoolParam('bypass_spam', true, $result['bypass_spam']);
$policy_greylist = $this->getBoolParam('policy_greylist', true, $result['policy_greylist']);
$iscatchall = $this->getBoolParam('iscatchall', true, $result['iscatchall']);
@@ -327,13 +337,16 @@ class Emails extends ApiCommand implements ResourceEntity
}
$spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1,2})?$/', '', [7.0], true);
- $spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1,2})?$/', '', [14.0], true);
+ if ($spam_kill_level > -1) {
+ $spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1,2})?$/', '', [14.0], true);
+ }
$description = Validate::validate(trim($description), 'description', Validate::REGEX_DESC_TEXT, '', [], true);
$stmt = Database::prepare("
UPDATE `" . TABLE_MAIL_VIRTUAL . "` SET
`email` = :email ,
`spam_tag_level` = :spam_tag_level,
+ `rewrite_subject` = :rewrite_subject,
`spam_kill_level` = :spam_kill_level,
`bypass_spam` = :bypass_spam,
`policy_greylist` = :policy_greylist,
@@ -344,6 +357,7 @@ class Emails extends ApiCommand implements ResourceEntity
$params = [
"email" => $email,
"spam_tag_level" => $spam_tag_level,
+ "rewrite_subject" => $rewrite_subject,
"spam_kill_level" => $spam_kill_level,
"bypass_spam" => $bypass_spam,
"policy_greylist" => $policy_greylist,
diff --git a/lib/Froxlor/Cron/Mail/Rspamd.php b/lib/Froxlor/Cron/Mail/Rspamd.php
index 624e91dd..625552f6 100644
--- a/lib/Froxlor/Cron/Mail/Rspamd.php
+++ b/lib/Froxlor/Cron/Mail/Rspamd.php
@@ -165,7 +165,7 @@ class Rspamd
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Generating antispam config for ' . $email['email']);
$email['spam_tag_level'] = floatval($email['spam_tag_level']);
- $email['spam_kill_level'] = floatval($email['spam_kill_level']);
+ $email['spam_kill_level'] = $email['spam_kill_level'] == -1 ? "null" : floatval($email['spam_kill_level']);
$email_id = md5($email['email']);
$this->frx_settings_file .= '# Email: ' . $email['email'] . "\n";
@@ -185,7 +185,9 @@ class Rspamd
$this->frx_settings_file .= ' apply {' . "\n";
$this->frx_settings_file .= ' actions {' . "\n";
$this->frx_settings_file .= ' "add header" = ' . $email['spam_tag_level'] . ';' . "\n";
- $this->frx_settings_file .= ' rewrite_subject = ' . ($email['spam_tag_level'] + 0.01) . ';' . "\n";
+ if ((int)$email['rewrite_subject'] == 1) {
+ $this->frx_settings_file .= ' rewrite_subject = ' . ($email['spam_tag_level'] + 0.01) . ';' . "\n";
+ }
$this->frx_settings_file .= ' reject = ' . $email['spam_kill_level'] . ';' . "\n";
if ($type == 'rcpt' && (int)$email['policy_greylist'] == 0) {
$this->frx_settings_file .= ' greylist = null;' . "\n";
diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php
index 92eb1b70..046e3855 100644
--- a/lib/Froxlor/Froxlor.php
+++ b/lib/Froxlor/Froxlor.php
@@ -34,7 +34,7 @@ final class Froxlor
const VERSION = '2.2.1';
// Database version (YYYYMMDDC where C is a daily counter)
- const DBVERSION = '202408140';
+ const DBVERSION = '202409280';
// Distribution branding-tag (used for Debian etc.)
const BRANDING = '';
diff --git a/lib/formfields/customer/email/formfield.emails_edit.php b/lib/formfields/customer/email/formfield.emails_edit.php
index a56f14a1..2642c091 100644
--- a/lib/formfields/customer/email/formfield.emails_edit.php
+++ b/lib/formfields/customer/email/formfield.emails_edit.php
@@ -96,20 +96,6 @@ return [
'value' => '1',
'checked' => (int)$result['iscatchall'],
],
- 'spam_tag_level' => [
- 'visible' => Settings::Get('antispam.activated') == '1',
- 'label' => lng('antispam.spam_tag_level'),
- 'type' => 'text',
- 'string_regexp' => '/^\d{1,}(\.\d{1,2})?$/',
- 'value' => $result['spam_tag_level']
- ],
- 'spam_kill_level' => [
- 'visible' => Settings::Get('antispam.activated') == '1',
- 'label' => lng('antispam.spam_kill_level'),
- 'type' => 'text',
- 'string_regexp' => '/^\d{1,}(\.\d{1,2})?$/',
- 'value' => $result['spam_kill_level']
- ],
'bypass_spam' => [
'visible' => Settings::Get('antispam.activated') == '1',
'label' => lng('antispam.bypass_spam'),
@@ -117,6 +103,29 @@ return [
'value' => '1',
'checked' => (int)$result['bypass_spam'],
],
+ 'spam_tag_level' => [
+ 'visible' => Settings::Get('antispam.activated') == '1',
+ 'label' => lng('antispam.spam_tag_level'),
+ 'type' => 'number',
+ 'min' => 0,
+ 'step' => 0.1,
+ 'value' => $result['spam_tag_level'],
+ ],
+ 'spam_rewrite_subject' => [
+ 'visible' => Settings::Get('antispam.activated') == '1',
+ 'label' => lng('antispam.rewrite_subject'),
+ 'type' => 'checkbox',
+ 'value' => '1',
+ 'checked' => (int)$result['rewrite_subject'],
+ ],
+ 'spam_kill_level' => [
+ 'visible' => Settings::Get('antispam.activated') == '1',
+ 'label' => lng('antispam.spam_kill_level'),
+ 'desc' => lng('panel.use_checkbox_to_disable'),
+ 'type' => 'textul',
+ 'step' => 0.1,
+ 'value' => $result['spam_kill_level']
+ ],
'policy_greylist' => [
'visible' => Settings::Get('antispam.activated') == '1',
'label' => lng('antispam.policy_greylist'),
diff --git a/lng/de.lng.php b/lng/de.lng.php
index 627bef2a..7199ee87 100644
--- a/lng/de.lng.php
+++ b/lng/de.lng.php
@@ -621,6 +621,10 @@ return [
'title' => 'Spam Level',
'description' => 'Erforderliche Punktzahl zum Markieren einer E-Mail als Spam
Standard: 7.0'
],
+ 'rewrite_subject' => [
+ 'title' => 'Betreff ändern',
+ 'description' => 'Dem E-Mail Betreff ***SPAM*** hinzufügen, sofern zutreffend',
+ ],
'spam_kill_level' => [
'title' => 'Ablehnungs Level',
'description' => 'Erforderliche Punktzahl für das Ablehnen einer E-Mail
Standard: 14.0'
@@ -1262,6 +1266,7 @@ Vielen Dank, Ihr Administrator',
'upload_import' => 'Hochladen und importieren',
'profile' => 'Mein Profil',
'use_checkbox_for_unlimited' => 'Der Wert "0" deaktiviert die Resource. Die Checkbox rechts erlaubt "unlimitierte" Nutzung.',
+ 'use_checkbox_to_disable' => 'Zum Deaktivieren, klicke die Checkbox auf der rechten Seite des Eingabefeldes',
],
'phpfpm' => [
'vhost_httpuser' => 'Lokaler Benutzer für PHP-FPM (Froxlor-Vhost)',
diff --git a/lng/en.lng.php b/lng/en.lng.php
index 48fb799c..6c0af9c1 100644
--- a/lng/en.lng.php
+++ b/lng/en.lng.php
@@ -670,6 +670,10 @@ return [
'title' => 'Spam tag level',
'description' => 'Score that is required to mark an email as spam
Default: 7.0'
],
+ 'rewrite_subject' => [
+ 'title' => 'Rewrite subject',
+ 'description' => 'Whether to add ***SPAM*** to the email subject if applicable',
+ ],
'spam_kill_level' => [
'title' => 'Spam kill level',
'description' => 'Score that is required to discard an email entirely
Default: 14.0'
@@ -1377,6 +1381,7 @@ Yours sincerely, your administrator',
'upload_import' => 'Upload and import',
'profile' => 'My profile',
'use_checkbox_for_unlimited' => 'The value "0" deactivates this resource. The checkbox on the right allows "unlimited" usage.',
+ 'use_checkbox_to_disable' => 'To disable, activate the checkbox on the right of the input field',
],
'phpfpm' => [
'vhost_httpuser' => 'Local user to use for PHP-FPM (Froxlor vHost)',
diff --git a/templates/Froxlor/assets/js/jquery/emails.js b/templates/Froxlor/assets/js/jquery/emails.js
new file mode 100644
index 00000000..93ffbcbd
--- /dev/null
+++ b/templates/Froxlor/assets/js/jquery/emails.js
@@ -0,0 +1,33 @@
+export default function () {
+ $(function () {
+
+ /**
+ * bypass spam - hide unnecessary/unused sections
+ */
+ if ($('#id') && $('#bypass_spam').is(':checked')) {
+ $('#spam_tag_level').closest('.row').addClass('d-none');
+ $('#spam_rewrite_subject').closest('.row').addClass('d-none');
+ $('#spam_kill_level').closest('.row').addClass('d-none');
+ $('#policy_greylist').closest('.row').addClass('d-none');
+ }
+
+ /**
+ * toggle show/hide of sections in case of bypass spam flag
+ */
+ $('#bypass_spam').on('click', function () {
+ if ($(this).is(':checked')) {
+ // hide unnecessary sections
+ $('#spam_tag_level').closest('.row').addClass('d-none');
+ $('#spam_rewrite_subject').closest('.row').addClass('d-none');
+ $('#spam_kill_level').closest('.row').addClass('d-none');
+ $('#policy_greylist').closest('.row').addClass('d-none');
+ } else {
+ // show sections
+ $('#spam_tag_level').closest('.row').removeClass('d-none');
+ $('#spam_rewrite_subject').closest('.row').removeClass('d-none');
+ $('#spam_kill_level').closest('.row').removeClass('d-none');
+ $('#policy_greylist').closest('.row').removeClass('d-none');
+ }
+ })
+ });
+}
diff --git a/templates/Froxlor/form/formfields.html.twig b/templates/Froxlor/form/formfields.html.twig
index f93b2038..ae8f146d 100644
--- a/templates/Froxlor/form/formfields.html.twig
+++ b/templates/Froxlor/form/formfields.html.twig
@@ -19,6 +19,8 @@
{% endif %}
{% if field.label.description is defined and field.label.description is not empty %}
{{ field.label.description|raw }}
{% endif %}
+ {% if field.desc is defined and field.desc is not empty %}
{{ field.desc|raw }}
+ {% endif %}
{% if field.requires_reconf is defined and field.requires_reconf is not empty %}
{{ lng('serversettings.requires_reconfiguration', [field.requires_reconf|join(', ')])|raw }}
@@ -170,7 +172,7 @@ {% if field.next_to is defined %}