diff --git a/data/web/fonts/SourceSansPro-Italic.woff2 b/data/web/fonts/SourceSansPro-Italic.woff2
new file mode 100644
index 00000000..ff006be7
Binary files /dev/null and b/data/web/fonts/SourceSansPro-Italic.woff2 differ
diff --git a/data/web/inc/ajax/qitem_details.php b/data/web/inc/ajax/qitem_details.php
index fedca73b..71d32cc9 100644
--- a/data/web/inc/ajax/qitem_details.php
+++ b/data/web/inc/ajax/qitem_details.php
@@ -74,6 +74,9 @@ if (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
}
}
if (isset($_GET['att'])) {
+ if ($_SESSION['acl']['quarantine_attachments'] == 0) {
+ exit(json_encode('Forbidden'));
+ }
$dl_id = intval($_GET['att']);
$dl_filename = $data['attachments'][$dl_id][0];
if (!is_dir($tmpdir . $dl_filename) && file_exists($tmpdir . $dl_filename)) {
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index 5712e525..dae26665 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -611,6 +611,8 @@ function edit_user_account($_data) {
function user_get_alias_details($username) {
global $lang;
global $pdo;
+ $data['direct_aliases'] = false;
+ $data['shared_aliases'] = false;
if ($_SESSION['mailcow_cc_role'] == "user") {
$username = $_SESSION['mailcow_cc_username'];
}
@@ -618,7 +620,7 @@ function user_get_alias_details($username) {
return false;
}
$data['address'] = $username;
- $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '✘') AS `shared_aliases` FROM `alias`
+ $stmt = $pdo->prepare("SELECT `address` AS `shared_aliases`, `public_comment` FROM `alias`
WHERE `goto` REGEXP :username_goto
AND `address` NOT LIKE '@%'
AND `goto` != :username_goto2
@@ -630,9 +632,10 @@ function user_get_alias_details($username) {
));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) {
- $data['shared_aliases'] = $row['shared_aliases'];
+ $data['shared_aliases'][] = $row['shared_aliases'];
}
- $stmt = $pdo->prepare("SELECT GROUP_CONCAT(`address` SEPARATOR ', ') AS `direct_aliases` FROM `alias`
+
+ $stmt = $pdo->prepare("SELECT `address` AS `direct_aliases`, `public_comment` FROM `alias`
WHERE `goto` = :username_goto
AND `address` NOT LIKE '@%'
AND `address` != :username_address");
@@ -640,21 +643,19 @@ function user_get_alias_details($username) {
array(
':username_goto' => $username,
':username_address' => $username
- ));
+ ));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) {
- $data['direct_aliases'][] = $row['direct_aliases'];
+ $data['direct_aliases'][$row['direct_aliases']]['public_comment'] = htmlspecialchars($row['public_comment']);
}
- $stmt = $pdo->prepare("SELECT GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ', ') AS `ad_alias` FROM `mailbox`
+ $stmt = $pdo->prepare("SELECT CONCAT(local_part, '@', alias_domain) AS `ad_alias`, `alias_domain` FROM `mailbox`
LEFT OUTER JOIN `alias_domain` on `target_domain` = `domain`
WHERE `username` = :username ;");
$stmt->execute(array(':username' => $username));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) {
- $data['direct_aliases'][] = $row['ad_alias'];
+ $data['direct_aliases'][$row['ad_alias']]['public_comment'] = '↪ ' . $row['alias_domain'];
}
- $data['direct_aliases'] = implode(', ', array_filter($data['direct_aliases']));
- $data['direct_aliases'] = empty($data['direct_aliases']) ? '✘' : $data['direct_aliases'];
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`send_as` SEPARATOR ', '), '✘') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `send_as` NOT LIKE '@%';");
$stmt->execute(array(':username' => $username));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php
index 508f8049..62323645 100644
--- a/data/web/inc/functions.mailbox.inc.php
+++ b/data/web/inc/functions.mailbox.inc.php
@@ -453,6 +453,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$goto_null = intval($_data['goto_null']);
$goto_spam = intval($_data['goto_spam']);
$goto_ham = intval($_data['goto_ham']);
+ $private_comment = $_data['private_comment'];
+ $public_comment = $_data['public_comment'];
+ if (strlen($private_comment) > 160 | strlen($public_comment) > 160){
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
+ 'msg' => 'comment_too_long'
+ );
+ return false;
+ }
if (empty($addresses[0])) {
$_SESSION['return'][] = array(
'type' => 'danger',
@@ -593,10 +603,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
return false;
}
- $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
+ $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `public_comment`, `private_comment`, `goto`, `domain`, `active`)
VALUES (:address, :goto, :domain, :active)");
if (!filter_var($address, FILTER_VALIDATE_EMAIL) === true) {
$stmt->execute(array(
+ ':address' => '@'.$domain,
+ ':public_comment' => $public_comment,
+ ':private_comment' => $private_comment,
':address' => '@'.$domain,
':goto' => $goto,
':domain' => $domain,
@@ -606,6 +619,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
else {
$stmt->execute(array(
':address' => $address,
+ ':public_comment' => $public_comment,
+ ':private_comment' => $private_comment,
':goto' => $goto,
':domain' => $domain,
':active' => $active
@@ -753,7 +768,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
'tls_enforce_in' => strval(intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in'])),
'tls_enforce_out' => strval(intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out'])),
'sogo_access' => strval(intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access'])),
- 'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format'])
+ 'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']),
+ 'quarantine_notification' => strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification'])
)
);
if (!is_valid_domain_name($domain)) {
@@ -1148,6 +1164,65 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
}
break;
+ case 'quarantine_notification':
+ if (!is_array($_data['username'])) {
+ $usernames = array();
+ $usernames[] = $_data['username'];
+ }
+ else {
+ $usernames = $_data['username'];
+ }
+ if (!isset($_SESSION['acl']['quarantine_notification']) || $_SESSION['acl']['quarantine_notification'] != "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_notification', $username);
+ if (!empty($is_now)) {
+ $quarantine_notification = (isset($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
+ }
+ else {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
+ 'msg' => 'access_denied'
+ );
+ continue;
+ }
+ if (!in_array($quarantine_notification, array('never', 'hourly', 'daily', 'weekly'))) {
+ $_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_notification', :quarantine_notification)
+ WHERE `username` = :username");
+ $stmt->execute(array(
+ ':quarantine_notification' => $quarantine_notification,
+ ':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();
@@ -1587,6 +1662,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$goto_null = (isset($_data['goto_null'])) ? intval($_data['goto_null']) : 0;
$goto_spam = (isset($_data['goto_spam'])) ? intval($_data['goto_spam']) : 0;
$goto_ham = (isset($_data['goto_ham'])) ? intval($_data['goto_ham']) : 0;
+ $public_comment = (isset($_data['public_comment'])) ? $_data['public_comment'] : $is_now['public_comment'];
+ $private_comment = (isset($_data['private_comment'])) ? $_data['private_comment'] : $is_now['private_comment'];
$goto = (!empty($_data['goto'])) ? $_data['goto'] : $is_now['goto'];
$address = (!empty($_data['address'])) ? $_data['address'] : $is_now['address'];
}
@@ -1703,11 +1780,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
if (!empty($goto)) {
$stmt = $pdo->prepare("UPDATE `alias` SET
`address` = :address,
+ `public_comment` = :public_comment,
+ `private_comment` = :private_comment,
`goto` = :goto,
`active`= :active
WHERE `id` = :id");
$stmt->execute(array(
':address' => $address,
+ ':public_comment' => $public_comment,
+ ':private_comment' => $private_comment,
':goto' => $goto,
':active' => $active,
':id' => $id
@@ -2367,6 +2448,22 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
'tls_enforce_out' => $attrs['tls_enforce_out']
);
break;
+ case 'quarantine_notification':
+ $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_notification'];
+ break;
case 'filters':
$filters = array();
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
@@ -2699,6 +2796,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`domain`,
`goto`,
`address`,
+ `public_comment`,
+ `private_comment`,
`active` as `active_int`,
CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
`created`,
@@ -2722,6 +2821,9 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
}
$aliasdata['id'] = $row['id'];
$aliasdata['domain'] = $row['domain'];
+ $aliasdata['public_comment'] = $row['public_comment'];
+ $aliasdata['private_comment'] = $row['private_comment'];
+ $aliasdata['domain'] = $row['domain'];
$aliasdata['goto'] = $row['goto'];
$aliasdata['address'] = $row['address'];
(!filter_var($aliasdata['address'], FILTER_VALIDATE_EMAIL)) ? $aliasdata['is_catch_all'] = 1 : $aliasdata['is_catch_all'] = 0;
diff --git a/data/web/inc/functions.quarantine.inc.php b/data/web/inc/functions.quarantine.inc.php
index bcc9d15d..cb9ae075 100644
--- a/data/web/inc/functions.quarantine.inc.php
+++ b/data/web/inc/functions.quarantine.inc.php
@@ -81,12 +81,18 @@ function quarantine($_action, $_data = null) {
$release_format = 'raw';
}
$max_size = $_data['max_size'];
+ $subject = $_data['subject'];
+ $sender = $_data['sender'];
+ $html = $_data['html'];
$exclude_domains = (array)$_data['exclude_domains'];
try {
$redis->Set('Q_RETENTION_SIZE', intval($retention_size));
$redis->Set('Q_MAX_SIZE', intval($max_size));
$redis->Set('Q_EXCLUDE_DOMAINS', json_encode($exclude_domains));
$redis->Set('Q_RELEASE_FORMAT', $release_format);
+ $redis->Set('Q_SENDER', $sender);
+ $redis->Set('Q_SUBJECT', $subject);
+ $redis->Set('Q_HTML', $html);
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
@@ -393,7 +399,7 @@ function quarantine($_action, $_data = null) {
break;
case 'get':
if ($_SESSION['mailcow_cc_role'] == "user") {
- $stmt = $pdo->prepare('SELECT `id`, `qid`, `subject`, `rcpt`, `sender`, UNIX_TIMESTAMP(`created`) AS `created` FROM `quarantine` WHERE `rcpt` = :mbox');
+ $stmt = $pdo->prepare('SELECT `id`, `qid`, `subject`, LOCATE("VIRUS_FOUND", `symbols`) AS `virus_flag`, `rcpt`, `sender`, UNIX_TIMESTAMP(`created`) AS `created` FROM `quarantine` WHERE `rcpt` = :mbox');
$stmt->execute(array(':mbox' => $_SESSION['mailcow_cc_username']));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
@@ -401,7 +407,7 @@ function quarantine($_action, $_data = null) {
}
}
elseif ($_SESSION['mailcow_cc_role'] == "admin") {
- $stmt = $pdo->query('SELECT `id`, `qid`, `subject`, `rcpt`, `sender`, UNIX_TIMESTAMP(`created`) AS `created` FROM `quarantine`');
+ $stmt = $pdo->query('SELECT `id`, `qid`, `subject`, LOCATE("VIRUS_FOUND", `symbols`) AS `virus_flag`, `rcpt`, `sender`, UNIX_TIMESTAMP(`created`) AS `created` FROM `quarantine`');
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$q_meta[] = $row;
@@ -410,7 +416,7 @@ function quarantine($_action, $_data = null) {
else {
$domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
foreach ($domains as $domain) {
- $stmt = $pdo->prepare('SELECT `id`, `qid`, `subject`, `rcpt`, `sender`, UNIX_TIMESTAMP(`created`) AS `created` FROM `quarantine` WHERE `rcpt` REGEXP :domain');
+ $stmt = $pdo->prepare('SELECT `id`, `qid`, `subject`, LOCATE("VIRUS_FOUND", `symbols`) AS `virus_flag`, `rcpt`, `sender`, UNIX_TIMESTAMP(`created`) AS `created` FROM `quarantine` WHERE `rcpt` REGEXP :domain');
$stmt->execute(array(':domain' => '@' . $domain . '$'));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
@@ -428,6 +434,12 @@ function quarantine($_action, $_data = null) {
$settings['max_size'] = $redis->Get('Q_MAX_SIZE');
$settings['retention_size'] = $redis->Get('Q_RETENTION_SIZE');
$settings['release_format'] = $redis->Get('Q_RELEASE_FORMAT');
+ $settings['subject'] = $redis->Get('Q_SUBJECT');
+ $settings['sender'] = $redis->Get('Q_SENDER');
+ $settings['html'] = htmlspecialchars($redis->Get('Q_HTML'));
+ if (empty($settings['html'])) {
+ $settings['html'] = htmlspecialchars(file_get_contents("/templates/quarantine.tpl"));
+ }
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php
index 9702a2c1..a66d2ab3 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 = "17012019_0717";
+ $db_version = "27012019_1217";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -137,6 +137,8 @@ function init_db_schema() {
"domain" => "VARCHAR(255) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
+ "private_comment" => "TEXT",
+ "public_comment" => "TEXT",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
@@ -237,6 +239,7 @@ function init_db_schema() {
"rcpt" => "VARCHAR(255)",
"msg" => "LONGTEXT",
"domain" => "VARCHAR(255)",
+ "notified" => "TINYINT(1) NOT NULL DEFAULT '0'",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"user" => "VARCHAR(255) NOT NULL DEFAULT 'unknown'",
),
@@ -316,6 +319,8 @@ function init_db_schema() {
"eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
"sogo_profile_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
+ "quarantine_attachments" => "TINYINT(1) NOT NULL DEFAULT '1'",
+ "quarantine_notification" => "TINYINT(1) NOT NULL DEFAULT '1'",
),
"keys" => array(
"primary" => array(
@@ -991,6 +996,7 @@ DELIMITER ;';
$stmt = $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.force_pw_update', \"0\") WHERE JSON_EXTRACT(`attributes`, '$.force_pw_update') IS NULL;");
$stmt = $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.sogo_access', \"1\") WHERE JSON_EXTRACT(`attributes`, '$.sogo_access') IS NULL;");
$stmt = $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.mailbox_format', \"maildir:\") WHERE JSON_EXTRACT(`attributes`, '$.mailbox_format') IS NULL;");
+ $stmt = $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.quarantine_notification', \"never\") WHERE JSON_EXTRACT(`attributes`, '$.quarantine_notification') 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 8a4d65bc..1b4a25f3 100644
--- a/data/web/inc/vars.inc.php
+++ b/data/web/inc/vars.inc.php
@@ -131,6 +131,9 @@ $DOCKER_TIMEOUT = 60;
// Anonymize IPs logged via UI
$ANONYMIZE_IPS = true;
+// MAILBOX_DEFAULT_ATTRIBUTES define default attributes for new mailboxes
+// These settings will not change existing mailboxes
+
// Force incoming TLS for new mailboxes by default
$MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in'] = false;
@@ -143,6 +146,9 @@ $MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update'] = false;
// Force password change on next login (only allows login to mailcow UI)
$MAILBOX_DEFAULT_ATTRIBUTES['sogo_access'] = true;
+// Send notification when quarantine is not empty (never, hourly, daily, weekly)
+$MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification'] = 'never';
+
// 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/admin.js b/data/web/js/admin.js
index 5b5e1594..7b04e674 100644
--- a/data/web/js/admin.js
+++ b/data/web/js/admin.js
@@ -54,7 +54,7 @@ jQuery(function($){
function draw_domain_admins() {
ft_domainadmins = FooTable.init('#domainadminstable', {
"columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
+ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"username","title":lang.username,"style":{"width":"250px"}},
{"name":"selected_domains","title":lang.admin_domains,"breakpoints":"xs sm"},
{"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"}},
@@ -82,7 +82,7 @@ jQuery(function($){
function draw_admins() {
ft_admins = FooTable.init('#adminstable', {
"columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
+ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"usr","title":lang.username,"style":{"width":"250px"}},
{"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"}},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
@@ -109,7 +109,7 @@ jQuery(function($){
function draw_fwd_hosts() {
ft_forwardinghoststable = FooTable.init('#forwardinghoststable', {
"columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
+ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"name":"host","type":"text","title":lang.host,"style":{"width":"250px"}},
{"name":"source","title":lang.source,"breakpoints":"xs sm"},
{"name":"keep_spam","title":lang.spamfilter, "type": "text","style":{"maxWidth":"80px","width":"80px"}},
@@ -134,7 +134,7 @@ jQuery(function($){
function draw_relayhosts() {
ft_relayhoststable = FooTable.init('#relayhoststable', {
"columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
+ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
{"name":"hostname","type":"text","title":lang.host,"style":{"width":"250px"}},
{"name":"username","title":lang.username,"breakpoints":"xs sm"},
@@ -161,7 +161,7 @@ jQuery(function($){
function draw_transport_maps() {
ft_relayhoststable = FooTable.init('#transportstable', {
"columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
+ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
{"name":"destination","type":"text","title":lang.destination,"style":{"width":"250px"}},
{"name":"nexthop","type":"text","title":lang.nexthop,"style":{"width":"250px"}},
@@ -188,7 +188,7 @@ jQuery(function($){
function draw_queue() {
ft_queuetable = FooTable.init('#queuetable', {
"columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
+ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"name":"queue_id","type":"text","title":"QID","style":{"width":"50px"}},
{"name":"queue_name","type":"text","title":"Queue","style":{"width":"120px"}},
{"name":"arrival_time","sorted": true,"direction": "DESC","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.arrival_time,"style":{"width":"170px"}},
diff --git a/data/web/js/api.js b/data/web/js/api.js
index 1a5f4b06..2f98a840 100644
--- a/data/web/js/api.js
+++ b/data/web/js/api.js
@@ -193,7 +193,6 @@ $(document).ready(function() {
}
if ($(this).attr("max")) {
if (Number($(this).val()) > Number($(this).attr("max"))) {
- alert($(this).attr("max"))
invalid = true;
$(this).addClass('inputMissingAttr');
} else {
@@ -314,4 +313,4 @@ $(document).ready(function() {
$('#ConfirmDeleteModal').modal('hide');
});
});
-});
\ No newline at end of file
+});
diff --git a/data/web/js/debug.js b/data/web/js/debug.js
index 4c5119cb..8406a2cb 100644
--- a/data/web/js/debug.js
+++ b/data/web/js/debug.js
@@ -381,11 +381,13 @@ jQuery(function($){
function drawChart() {
var data = google.visualization.arrayToDataTable(graphdata);
-
+ var body_font_color = $('body').css("color");
var options = {
is3D: true,
sliceVisibilityThreshold: 0,
pieSliceText: 'percentage',
+ backgroundColor: { fill:'transparent' },
+ legend: {textStyle: {color: body_font_color}},
chartArea: {
left: 0,
right: 0,
@@ -416,7 +418,7 @@ jQuery(function($){
{"name":"unix_time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
{"name": "ip","title": "IP address","breakpoints": "all","style": {"minWidth": 88}},
{"name": "sender_mime","title": "From","breakpoints": "xs sm md","style": {"minWidth": 100}},
- {"name": "rcpt_mime","title": "To","breakpoints": "xs sm md","style": {"minWidth": 100}},
+ {"name": "rcpt","title": "To","breakpoints": "xs sm md","style": {"minWidth": 100}},
{"name": "subject","title": "Subject","breakpoints": "all","style": {"word-break": "break-all","minWidth": 150}},
{"name": "action","title": "Action","style": {"minwidth": 82}},
{"name": "score","title": "Score","style": {"maxWidth": 110},},
@@ -460,7 +462,12 @@ jQuery(function($){
function process_table_data(data, table) {
if (table == 'rspamd_history') {
$.each(data, function (i, item) {
- item.rcpt_mime = item.rcpt_mime.join(",");
+ if (item.rcpt_mime != "") {
+ item.rcpt = item.rcpt_mime.join(", ");
+ }
+ else {
+ item.rcpt = item.rcpt_smtp.join(", ");
+ }
Object.keys(item.symbols).map(function(key) {
var sym = item.symbols[key];
if (sym.score <= 0) {
diff --git a/data/web/js/edit.js b/data/web/js/edit.js
index 45690710..97c48585 100644
--- a/data/web/js/edit.js
+++ b/data/web/js/edit.js
@@ -22,8 +22,6 @@ $(document).ready(function() {
$('#textarea_alias_goto').prop('disabled', true);
}
- $("#script_data").numberedtextarea({allowTabChar: true});
-
$("#mailbox-password-warning-close").click(function( event ) {
$('#mailbox-passwd-hidden-info').addClass('hidden');
$('#mailbox-passwd-form-groups').removeClass('hidden');
diff --git a/data/web/js/mailbox.js b/data/web/js/mailbox.js
index 4153aa18..7b14d735 100644
--- a/data/web/js/mailbox.js
+++ b/data/web/js/mailbox.js
@@ -141,8 +141,6 @@ $(document).ready(function() {
var sieveScript = $(e.relatedTarget).data('sieve-script');
$(e.currentTarget).find('#sieveDataText').html('
' + sieveScript + '
');
});
- // Set line numbers for textarea
- $("#script_data").numberedtextarea({allowTabChar: true});
// Disable submit button on script change
$('#script_data').on('keyup', function() {
$('#add_filter_btns > #add_sieve_script').attr({"disabled": true});
@@ -712,6 +710,8 @@ jQuery(function($){
{"sorted": true,"name":"address","title":lang.alias,"style":{"width":"250px"}},
{"name":"goto","title":lang.target_address},
{"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
+ {"name":"public_comment","title":lang.public_comment,"breakpoints":"all"},
+ {"name":"private_comment","title":lang.private_comment,"breakpoints":"all"},
{"name":"active","filterable": false,"style":{"maxWidth":"50px","width":"70px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
@@ -731,6 +731,8 @@ jQuery(function($){
'
';
item.goto = escapeHtml(item.goto.replace(/,/g, " "));
+ item.public_comment = escapeHtml(item.public_comment);
+ item.private_comment = escapeHtml(item.private_comment);
if (item.is_catch_all == 1) {
item.address = '
' + escapeHtml(item.address);
}
diff --git a/data/web/js/mailcow.js b/data/web/js/mailcow.js
index 6dd7e4d8..cf3a3a72 100644
--- a/data/web/js/mailcow.js
+++ b/data/web/js/mailcow.js
@@ -161,7 +161,8 @@ $(document).ready(function() {
$(document).on("keydown", disableF5);
}
});
-
+ // Textarea line numbers
+ $(".textarea-code").numberedtextarea({allowTabChar: true});
// trigger container restart
$('#RestartContainer').on('show.bs.modal', function(e) {
var container = $(e.relatedTarget).data('container');
diff --git a/data/web/js/quarantine.js b/data/web/js/quarantine.js
index 5a6162c9..090b5054 100644
--- a/data/web/js/quarantine.js
+++ b/data/web/js/quarantine.js
@@ -1,22 +1,23 @@
// Base64 functions
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C