diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index 1181b3f5..21852259 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -332,6 +332,9 @@ function hasDomainAccess($username, $role, $domain) {
}
function hasMailboxObjectAccess($username, $role, $object) {
global $pdo;
+ if (empty($username) || empty($role) || empty($object)) {
+ return false;
+ }
if (!filter_var(html_entity_decode(rawurldecode($username)), FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) {
return false;
}
diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php
index 0ca2253b..518dee15 100644
--- a/data/web/inc/functions.mailbox.inc.php
+++ b/data/web/inc/functions.mailbox.inc.php
@@ -949,6 +949,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
$smtp_access = (isset($_data['smtp_access'])) ? intval($_data['smtp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
$quarantine_notification = (isset($_data['quarantine_notification'])) ? strval($_data['quarantine_notification']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
+ $quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
$quota_b = ($quota_m * 1048576);
$mailbox_attrs = json_encode(
array(
@@ -960,7 +961,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
'pop3_access' => strval($pop3_access),
'smtp_access' => strval($smtp_access),
'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']),
- 'quarantine_notification' => strval($quarantine_notification)
+ 'quarantine_notification' => strval($quarantine_notification),
+ 'quarantine_category' => strval($quarantine_category)
)
);
if (!is_valid_domain_name($domain)) {
@@ -1409,6 +1411,65 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
}
break;
+ case 'quarantine_category':
+ if (!is_array($_data['username'])) {
+ $usernames = array();
+ $usernames[] = $_data['username'];
+ }
+ else {
+ $usernames = $_data['username'];
+ }
+ if (!isset($_SESSION['acl']['quarantine_category']) || $_SESSION['acl']['quarantine_category'] != "1" ) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
+ 'msg' => 'access_denied'
+ );
+ return false;
+ }
+ foreach ($usernames as $username) {
+ if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
+ 'msg' => 'access_denied'
+ );
+ continue;
+ }
+ $is_now = mailbox('get', 'quarantine_category', $username);
+ if (!empty($is_now)) {
+ $quarantine_category = (isset($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
+ }
+ else {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
+ 'msg' => 'access_denied'
+ );
+ continue;
+ }
+ if (!in_array($quarantine_category, array('add_header', 'reject', 'all'))) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
+ 'msg' => 'access_denied'
+ );
+ continue;
+ }
+ $stmt = $pdo->prepare("UPDATE `mailbox`
+ SET `attributes` = JSON_SET(`attributes`, '$.quarantine_category', :quarantine_category)
+ WHERE `username` = :username");
+ $stmt->execute(array(
+ ':quarantine_category' => $quarantine_category,
+ ':username' => $username
+ ));
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
+ 'msg' => array('mailbox_modified', $username)
+ );
+ }
+ break;
case 'spam_score':
if (!is_array($_data['username'])) {
$usernames = array();
@@ -2803,6 +2864,22 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$attrs = json_decode($attrs['attributes'], true);
return $attrs['quarantine_notification'];
break;
+ case 'quarantine_category':
+ $attrs = array();
+ if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
+ if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+ return false;
+ }
+ }
+ else {
+ $_data = $_SESSION['mailcow_cc_username'];
+ }
+ $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
+ $stmt->execute(array(':username' => $_data));
+ $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
+ $attrs = json_decode($attrs['attributes'], true);
+ return $attrs['quarantine_category'];
+ break;
case 'filters':
$filters = array();
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php
index 396e0aa5..8010bbdd 100644
--- a/data/web/inc/init_db.inc.php
+++ b/data/web/inc/init_db.inc.php
@@ -3,7 +3,7 @@ function init_db_schema() {
try {
global $pdo;
- $db_version = "16112020_1210";
+ $db_version = "28112020_1210";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -401,6 +401,7 @@ function init_db_schema() {
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
"quarantine_attachments" => "TINYINT(1) NOT NULL DEFAULT '1'",
"quarantine_notification" => "TINYINT(1) NOT NULL DEFAULT '1'",
+ "quarantine_category" => "TINYINT(1) NOT NULL DEFAULT '1'",
"app_passwds" => "TINYINT(1) NOT NULL DEFAULT '1'",
),
"keys" => array(
@@ -1185,6 +1186,7 @@ function init_db_schema() {
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.smtp_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.smtp_access') IS NULL;");
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.mailbox_format', \"maildir:\") WHERE JSON_VALUE(`attributes`, '$.mailbox_format') IS NULL;");
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.quarantine_notification', \"never\") WHERE JSON_VALUE(`attributes`, '$.quarantine_notification') IS NULL;");
+ $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.quarantine_category', \"reject\") WHERE JSON_VALUE(`attributes`, '$.quarantine_category') IS NULL;");
foreach($tls_options as $tls_user => $tls_options) {
$stmt = $pdo->prepare("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.tls_enforce_in', :tls_enforce_in),
`attributes` = JSON_SET(`attributes`, '$.tls_enforce_out', :tls_enforce_out)
diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php
index 83b0e0bc..aa38a72f 100644
--- a/data/web/inc/vars.inc.php
+++ b/data/web/inc/vars.inc.php
@@ -167,6 +167,12 @@ $MAILBOX_DEFAULT_ATTRIBUTES['pop3_access'] = true;
// Mailbox has SMTP access by default
$MAILBOX_DEFAULT_ATTRIBUTES['smtp_access'] = true;
+// Mailbox receives notifications about...
+// "add_header" - mail that was put into the Junk folder
+// "reject" - mail that was rejected
+// "all" - mail that was rejected and put into the Junk folder
+$MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category'] = 'reject';
+
// Default mailbox format, should not be changed unless you know exactly, what you do, keep the trailing ":"
// Check dovecot.conf for further changes (e.g. shared namespace)
$MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format'] = 'maildir:';
diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js
index 217a4323..68a5ad45 100644
--- a/data/web/js/site/mailbox.js
+++ b/data/web/js/site/mailbox.js
@@ -371,13 +371,14 @@ jQuery(function($){
'
SMTP @ ' + unix_time_format(Number(res[2])) + '
';
}},
{"name":"quarantine_notification","filterable": false,"title":lang.quarantine_notification,"breakpoints":"all"},
+ {"name":"quarantine_category","filterable": false,"title":lang.quarantine_category,"breakpoints":"all"},
{"name":"in_use","filterable": false,"type":"html","title":lang.in_use,"sortValue": function(value){
return Number($(value).find(".progress-bar-mailbox").attr('aria-valuenow'));
},
},
{"name":"messages","filterable": false,"title":lang.msg_num,"breakpoints":"xs sm md"},
{"name":"rl","title":"RL","breakpoints":"all","style":{"width":"125px"}},
- {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'✓':0==value&&'✕';}},
+ {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'✓':(0==value?'✕':2==value&&'—');}},
{"name":"action","filterable": false,"sortable": false,"style":{"min-width":"290px","text-align":"right"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
],
"empty": lang.empty,
@@ -418,6 +419,13 @@ jQuery(function($){
} else if (item.attributes.quarantine_notification === 'weekly') {
item.quarantine_notification = lang.weekly;
}
+ if (item.attributes.quarantine_category === 'reject') {
+ item.quarantine_category = '
' + lang.q_reject + '';
+ } else if (item.attributes.quarantine_category === 'add_header') {
+ item.quarantine_category = '
' + lang.q_add_header + '';
+ } else if (item.attributes.quarantine_category === 'all') {
+ item.quarantine_category = lang.q_all;
+ }
if (acl_data.login_as === 1) {
item.action = '
' +
'
' + lang.edit + '' +
diff --git a/data/web/json_api.php b/data/web/json_api.php
index e552b025..783ba127 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -1576,6 +1576,9 @@ if (isset($_GET['query'])) {
case "quarantine_notification":
process_edit_return(mailbox('edit', 'quarantine_notification', array_merge(array('username' => $items), $attr)));
break;
+ case "quarantine_category":
+ process_edit_return(mailbox('edit', 'quarantine_category', array_merge(array('username' => $items), $attr)));
+ break;
case "qitem":
process_edit_return(quarantine('edit', array_merge(array('id' => $items), $attr)));
break;
diff --git a/data/web/lang/lang.de.json b/data/web/lang/lang.de.json
index 46223842..4ab9331c 100644
--- a/data/web/lang/lang.de.json
+++ b/data/web/lang/lang.de.json
@@ -14,6 +14,7 @@
"quarantine": "Quarantäne-Aktionen",
"quarantine_attachments": "Anhänge aus Quarantäne",
"quarantine_notification": "Ändern der Quarantäne-Benachrichtigung",
+ "quarantine_category": "Ändern der Quarantäne-Benachrichtigungskategorie",
"ratelimit": "Rate limit",
"recipient_maps": "Empfängerumschreibungen",
"smtp_ip_access": "Verwalten der erlaubten Hosts für SMTP",
@@ -691,7 +692,11 @@
"owner": "Besitzer",
"private_comment": "Privater Kommentar",
"public_comment": "Öffentlicher Kommentar",
+ "q_add_header": "Junk-Ordner",
+ "q_all": "Alle Kategorien",
+ "q_reject": "Abgelehnt",
"quarantine_notification": "Quarantäne-Benachrichtigung",
+ "quarantine_category": "Quarantäne-Benachrichtigungskategorie",
"quick_actions": "Aktionen",
"recipient_map": "Empfängerumschreibung",
"recipient_map_info": "Empfängerumschreibung ersetzen den Empfänger einer E-Mail vor dem Versand.",
@@ -996,8 +1001,13 @@
"pushover_title": "Notification Titel",
"pushover_vars": "Wenn kein Sender-Filter definiert ist, werden alle E-Mails berücksichtigt.
Die direkte Absenderprüfung und reguläre Ausdrücke werden unabhängig voneinander geprüft, sie
hängen nicht voneinander ab und werden der Reihe nach ausgeführt.
Verwendbare Variablen für Titel und Text (Datenschutzrichtlinien beachten)",
"pushover_verify": "Verbindung verifizieren",
+ "q_add_header": "Junk-Ordner",
+ "q_all": "Alle Kategorien",
+ "q_reject": "Abgelehnt",
"quarantine_notification": "Quarantäne-Benachrichtigung",
+ "quarantine_category": "Quarantäne-Benachrichtigungskategorie",
"quarantine_notification_info": "Wurde über eine E-Mail in Quarantäne informiert, wird sie als \"benachrichtigt\" markiert und keine weitere Benachrichtigung zu dieser E-Mail versendet.",
+ "quarantine_category_info": "Die Kategorie \"Abgelehnt\" informiert über abgelehnte E-Mails, während \"Junk-Ordner\" über E-Mails berichtet, die im Junk-Ordner des jeweiligen Benutzers abgelegt wurden.",
"remove": "Entfernen",
"running": "Wird ausgeführt",
"save": "Änderungen speichern",
diff --git a/data/web/lang/lang.en.json b/data/web/lang/lang.en.json
index 51825450..0452cfb3 100644
--- a/data/web/lang/lang.en.json
+++ b/data/web/lang/lang.en.json
@@ -14,6 +14,7 @@
"quarantine": "Quarantine actions",
"quarantine_attachments": "Quarantine attachments",
"quarantine_notification": "Change quarantine notifications",
+ "quarantine_category": "Change quarantine notification category",
"ratelimit": "Rate limit",
"recipient_maps": "Recipient maps",
"smtp_ip_access": "Change allowed hosts for SMTP",
@@ -691,7 +692,11 @@
"owner": "Owner",
"private_comment": "Private comment",
"public_comment": "Public comment",
+ "q_add_header": "Junk folder",
+ "q_all": "All categories",
+ "q_reject": "Rejected",
"quarantine_notification": "Quarantine notifications",
+ "quarantine_category": "Quarantine notification category",
"quick_actions": "Actions",
"recipient_map": "Recipient map",
"recipient_map_info": "Recipient maps are used to replace the destination address on a message before it is delivered.",
@@ -997,8 +1002,13 @@
"pushover_title": "Notification title",
"pushover_vars": "When no sender filter is defined, all mails will be considered.
Regex filters as well as exact sender checks can be defined individually and will be considered sequentially. They do not depend on each other.
Useable variables for text and title (please take note of data protection policies)",
"pushover_verify": "Verify credentials",
+ "q_add_header": "Junk folder",
+ "q_all": "All categories",
+ "q_reject": "Rejected",
"quarantine_notification": "Quarantine notifications",
+ "quarantine_category": "Quarantine notification category",
"quarantine_notification_info": "Once a notification has been sent, items will be marked as \"notified\" and no further notifications will be sent for this particular item.",
+ "quarantine_category_info": "The notification category \"Rejected\" includes mail that was rejected, while \"Junk folder\" will notify a user about mails that were put into the junk folder.",
"remove": "Remove",
"running": "Running",
"save": "Save changes",
diff --git a/data/web/mailbox.php b/data/web/mailbox.php
index 657d88e5..01663a44 100644
--- a/data/web/mailbox.php
+++ b/data/web/mailbox.php
@@ -116,7 +116,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
=$lang['mailbox']['sogo_allow_admin_hint'];?>
-
+
@@ -144,6 +144,10 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
=$lang['user']['weekly'];?>
=$lang['user']['never'];?>
+
=$lang['user']['q_reject'];?>
+
=$lang['user']['q_add_header'];?>
+
=$lang['user']['q_all'];?>
+
=$lang['mailbox']['activate'];?>
@@ -165,6 +169,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
=$lang['mailbox']['mailbox'];?>
diff --git a/data/web/user.php b/data/web/user.php
index 8cf804ba..57b2803f 100644
--- a/data/web/user.php
+++ b/data/web/user.php
@@ -337,6 +337,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '