From 5065667ae467261d6a2336ec01faf9d26998044c Mon Sep 17 00:00:00 2001 From: andryyy Date: Wed, 26 May 2021 14:02:27 +0200 Subject: [PATCH] [Postfix] Allow to set and override a relayhost per mailbox [Web] Replace recycle icon with trash (this one made me a bit sad) [Web] Various small fixes [Web] Allow or disallow a domain admin to change relayhost settings (default is off, as previous default) --- data/Dockerfiles/postfix/postfix.sh | 29 +++++++++---- data/web/admin.php | 6 +-- data/web/css/build/008-mailcow.css | 1 - data/web/css/site/edit.css | 4 ++ data/web/edit.php | 51 +++++++++++++++-------- data/web/inc/functions.inc.php | 13 +++--- data/web/inc/functions.mailbox.inc.php | 5 +++ data/web/inc/functions.transports.inc.php | 9 +++- data/web/inc/init_db.inc.php | 5 ++- data/web/js/site/admin.js | 19 +++++---- data/web/js/site/debug.js | 2 +- data/web/js/site/mailbox.js | 26 ++++++------ data/web/js/site/quarantine.js | 2 +- data/web/js/site/user.js | 6 +-- data/web/lang/lang.cs.json | 2 +- data/web/lang/lang.da.json | 2 +- data/web/lang/lang.de.json | 6 ++- data/web/lang/lang.en.json | 6 ++- data/web/lang/lang.fi.json | 2 +- data/web/lang/lang.fr.json | 2 +- data/web/lang/lang.ko.json | 2 +- data/web/lang/lang.nl.json | 4 +- data/web/lang/lang.ro.json | 2 +- data/web/lang/lang.sk.json | 2 +- data/web/lang/lang.sv.json | 2 +- data/web/lang/lang.zh.json | 2 +- data/web/user.php | 25 +++++------ docker-compose.yml | 2 +- 28 files changed, 150 insertions(+), 89 deletions(-) diff --git a/data/Dockerfiles/postfix/postfix.sh b/data/Dockerfiles/postfix/postfix.sh index 753f446e..fac8bbf4 100755 --- a/data/Dockerfiles/postfix/postfix.sh +++ b/data/Dockerfiles/postfix/postfix.sh @@ -125,16 +125,31 @@ query = SELECT GROUP_CONCAT(transport SEPARATOR '') AS transport_maps AND mailbox.active = '1' ), 'smtp_enforced_tls:', 'smtp:') AS 'transport' UNION ALL - SELECT hostname AS transport FROM relayhosts + SELECT COALESCE( + (SELECT hostname FROM relayhosts + LEFT OUTER JOIN mailbox ON JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.relayhost')) = relayhosts.id + WHERE relayhosts.active = '1' + AND ( + mailbox.username IN (SELECT alias.goto from alias + JOIN mailbox ON mailbox.username = alias.goto + WHERE alias.active = '1' + AND alias.address = '%s' + AND alias.address NOT LIKE '@%%' + ) + ) + ), + (SELECT hostname FROM relayhosts LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id WHERE relayhosts.active = '1' - AND domain = '%d' - OR domain IN ( - SELECT target_domain FROM alias_domain - WHERE alias_domain = '%d' + AND (domain.domain = '%d' + OR domain.domain IN ( + SELECT target_domain FROM alias_domain + WHERE alias_domain = '%d' + ) ) - ) - AS transport_view; + ) + ) + ) AS transport_view; EOF cat < /opt/postfix/conf/sql/mysql_transport_maps.cf diff --git a/data/web/admin.php b/data/web/admin.php index 0d02c947..a9a85a2a 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -139,7 +139,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC @@ -618,7 +618,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
- +
@@ -1402,7 +1402,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC data-api-url='edit/mailq' data-api-attr='{"action":"super_delete"}' data-toggle="tooltip" title="postsuper -d ALL" - href="#"> + href="#"> diff --git a/data/web/css/build/008-mailcow.css b/data/web/css/build/008-mailcow.css index cdd44817..9418da50 100644 --- a/data/web/css/build/008-mailcow.css +++ b/data/web/css/build/008-mailcow.css @@ -76,7 +76,6 @@ font-size: inherit; } .icon-spin { - font-size: 1.0rem; animation-name: spin; animation-duration: 2000ms; animation-iteration-count: infinite; diff --git a/data/web/css/site/edit.css b/data/web/css/site/edit.css index 1242af2b..558215b4 100644 --- a/data/web/css/site/edit.css +++ b/data/web/css/site/edit.css @@ -40,4 +40,8 @@ .input-group-addon-xmpp { background-color: #fff; border: 0px solid #fff; +} +#sender_acl_disabled { + display:none; + margin-top:10px; } \ No newline at end of file diff --git a/data/web/edit.php b/data/web/edit.php index fa061523..f1168ded 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -281,6 +281,21 @@ if (isset($_SESSION['mailcow_cc_role'])) { +
+ +
+ +
+
@@ -314,21 +329,6 @@ if (isset($_SESSION['mailcow_cc_role'])) { -
- -
- -
-
@@ -640,6 +640,7 @@ if (isset($_SESSION['mailcow_cc_role'])) { $quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox); $quarantine_category = mailbox('get', 'quarantine_category', $mailbox); $get_tls_policy = mailbox('get', 'tls_policy', $mailbox); + $rlyhosts = relayhost('get'); if (!empty($result)) { ?>

@@ -724,10 +725,26 @@ if (isset($_SESSION['mailcow_cc_role'])) { ?> - +
+
+ +
+ + +
+
@@ -965,7 +982,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 33c58007..f107863b 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -940,8 +940,9 @@ function edit_user_account($_data) { } function user_get_alias_details($username) { global $pdo; - $data['direct_aliases'] = false; - $data['shared_aliases'] = false; + global $lang; + $data['direct_aliases'] = array(); + $data['shared_aliases'] = array(); if ($_SESSION['mailcow_cc_role'] == "user") { $username = $_SESSION['mailcow_cc_username']; } @@ -987,22 +988,22 @@ function user_get_alias_details($username) { if (empty($row['ad_alias'])) { continue; } - $data['direct_aliases'][$row['ad_alias']]['public_comment'] = '↪ ' . $row['alias_domain']; + $data['direct_aliases'][$row['ad_alias']]['public_comment'] = '' . $row['alias_domain'] . ''; $data['alias_domains'][] = $row['alias_domain']; } - $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 = $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); while ($row = array_shift($run)) { $data['aliases_also_send_as'] = $row['send_as']; } - $stmt = $pdo->prepare("SELECT CONCAT_WS(', ', IFNULL(GROUP_CONCAT(DISTINCT `send_as` SEPARATOR ', '), '✘'), GROUP_CONCAT(DISTINCT CONCAT('@',`alias_domain`) SEPARATOR ', ')) AS `send_as` FROM `sender_acl` LEFT JOIN `alias_domain` ON `alias_domain`.`target_domain` = TRIM(LEADING '@' FROM `send_as`) WHERE `logged_in_as` = :username AND `send_as` LIKE '@%';"); + $stmt = $pdo->prepare("SELECT CONCAT_WS(', ', IFNULL(GROUP_CONCAT(DISTINCT `send_as` SEPARATOR ', '), ''), GROUP_CONCAT(DISTINCT CONCAT('@',`alias_domain`) SEPARATOR ', ')) AS `send_as` FROM `sender_acl` LEFT JOIN `alias_domain` ON `alias_domain`.`target_domain` = TRIM(LEADING '@' FROM `send_as`) WHERE `logged_in_as` = :username AND `send_as` LIKE '@%';"); $stmt->execute(array(':username' => $username)); $run = $stmt->fetchAll(PDO::FETCH_ASSOC); while ($row = array_shift($run)) { $data['aliases_send_as_all'] = $row['send_as']; } - $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '✘') as `address` FROM `alias` WHERE `goto` REGEXP :username AND `address` LIKE '@%';"); + $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '') as `address` FROM `alias` WHERE `goto` REGEXP :username AND `address` LIKE '@%';"); $stmt->execute(array(':username' => '(^|,)'.$username.'($|,)')); $run = $stmt->fetchAll(PDO::FETCH_ASSOC); while ($row = array_shift($run)) { diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index 33ddac39..8bea647b 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -2141,6 +2141,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $xmpp = (isset($_data['xmpp']) && !empty($_SESSION['acl']['xmpp_domain_access']) && $_SESSION['acl']['xmpp_domain_access'] == "1") ? intval($_data['xmpp']) : $is_now['xmpp']; $xmpp_prefix = (!empty($_data['xmpp_prefix']) && !empty($_SESSION['acl']['xmpp_prefix']) && $_SESSION['acl']['xmpp_prefix'] == "1") ? $_data['xmpp_prefix'] : $is_now['xmpp_prefix']; $description = (!empty($_data['description']) && isset($_SESSION['acl']['domain_desc']) && $_SESSION['acl']['domain_desc'] == "1") ? $_data['description'] : $is_now['description']; + (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['domain_relayhost']) && $_SESSION['acl']['domain_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['relayhost']); } else { $_SESSION['return'][] = array( @@ -2359,6 +2360,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { (int)$smtp_access = (isset($_data['smtp_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']); (int)$xmpp_admin = (isset($_data['xmpp_admin']) && isset($_SESSION['acl']['xmpp_admin']) && $_SESSION['acl']['xmpp_admin'] == "1") ? intval($_data['xmpp_admin']) : intval($is_now['attributes']['xmpp_admin']); (int)$xmpp_access = (isset($_data['xmpp_access']) && isset($_SESSION['acl']['xmpp_mailbox_access']) && $_SESSION['acl']['xmpp_mailbox_access'] == "1") ? intval($_data['xmpp_access']) : intval($is_now['attributes']['xmpp_access']); + (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['mailbox_relayhost']) && $_SESSION['acl']['mailbox_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']); (int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576); $name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name']; $domain = $is_now['domain']; @@ -2631,6 +2633,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { `attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access), `attributes` = JSON_SET(`attributes`, '$.xmpp_admin', :xmpp_admin), `attributes` = JSON_SET(`attributes`, '$.xmpp_access', :xmpp_access), + `attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost), `attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access) WHERE `username` = :username"); $stmt->execute(array( @@ -2644,6 +2647,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ':smtp_access' => $smtp_access, ':xmpp_admin' => $xmpp_admin, ':xmpp_access' => $xmpp_access, + ':relayhost' => $relayhost, ':username' => $username )); $_SESSION['return'][] = array( @@ -3561,6 +3565,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $mailboxdata['active_int'] = $row['active']; $mailboxdata['domain'] = $row['domain']; $mailboxdata['domain_xmpp'] = $row['domain_xmpp']; + $mailboxdata['relayhost'] = $row['relayhost']; $mailboxdata['name'] = $row['name']; $mailboxdata['domain_xmpp_prefix'] = $row['domain_xmpp_prefix']; $mailboxdata['local_part'] = $row['local_part']; diff --git a/data/web/inc/functions.transports.inc.php b/data/web/inc/functions.transports.inc.php index 7d8031aa..bc14ecb2 100644 --- a/data/web/inc/functions.transports.inc.php +++ b/data/web/inc/functions.transports.inc.php @@ -137,11 +137,11 @@ function relayhost($_action, $_data = null) { } break; case 'get': - if ($_SESSION['mailcow_cc_role'] != "admin") { + if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { return false; } $relayhosts = array(); - $stmt = $pdo->query("SELECT `id`, `hostname`, `username` FROM `relayhosts`"); + $stmt = $pdo->query("SELECT `id`, `hostname`, `username`, `active` FROM `relayhosts`"); $relayhosts = $stmt->fetchAll(PDO::FETCH_ASSOC); return $relayhosts; break; @@ -166,6 +166,11 @@ function relayhost($_action, $_data = null) { $used_by_domains = $stmt->fetch(PDO::FETCH_ASSOC)['used_by_domains']; $used_by_domains = (empty($used_by_domains)) ? '' : $used_by_domains; $relayhostdata['used_by_domains'] = $used_by_domains; + $stmt = $pdo->prepare("SELECT GROUP_CONCAT(`username` SEPARATOR ', ') AS `used_by_mailboxes` FROM `mailbox` WHERE JSON_VALUE(`attributes`, '$.relayhost') = :id"); + $stmt->execute(array(':id' => $_data)); + $used_by_mailboxes = $stmt->fetch(PDO::FETCH_ASSOC)['used_by_mailboxes']; + $used_by_mailboxes = (empty($used_by_mailboxes)) ? '' : $used_by_mailboxes; + $relayhostdata['used_by_mailboxes'] = $used_by_mailboxes; } return $relayhostdata; break; diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index 1f423ac5..85e20a7a 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 = "21052021_0900"; + $db_version = "25052021_0900"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -572,6 +572,8 @@ function init_db_schema() { "protocol_access" => "TINYINT(1) NOT NULL DEFAULT '1'", "smtp_ip_access" => "TINYINT(1) NOT NULL DEFAULT '1'", "alias_domains" => "TINYINT(1) NOT NULL DEFAULT '0'", + "mailbox_relayhost" => "TINYINT(1) NOT NULL DEFAULT '1'", + "domain_relayhost" => "TINYINT(1) NOT NULL DEFAULT '1'", "xmpp_prefix" => "TINYINT(1) NOT NULL DEFAULT '0'", "xmpp_domain_access" => "TINYINT(1) NOT NULL DEFAULT '0'", "xmpp_mailbox_access" => "TINYINT(1) NOT NULL DEFAULT '0'", @@ -1188,6 +1190,7 @@ function init_db_schema() { $pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.only_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.only_x_prio') IS NULL;"); // mailbox $pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;"); + $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.relayhost', \"0\") WHERE JSON_VALUE(`attributes`, '$.relayhost') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.xmpp_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.xmpp_access') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.xmpp_admin', \"0\") WHERE JSON_VALUE(`attributes`, '$.xmpp_admin') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.force_pw_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.force_pw_update') IS NULL;"); diff --git a/data/web/js/site/admin.js b/data/web/js/site/admin.js index ffaf5dff..f7dbec8c 100644 --- a/data/web/js/site/admin.js +++ b/data/web/js/site/admin.js @@ -187,7 +187,7 @@ jQuery(function($){ {"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"}, - {"name":"used_by_domains","title":lang.in_use_by,"style":{"width":"110px"}, "type": "text","breakpoints":"xs sm"}, + {"name":"in_use_by","title":lang.in_use_by,"style":{"width":"110px"}, "type": "text","breakpoints":"xs sm"}, {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'':0==value&&'';}}, {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"} ], @@ -209,7 +209,7 @@ jQuery(function($){ }); } function draw_transport_maps() { - ft_relayhoststable = FooTable.init('#transportstable', { + ft_transportstable = FooTable.init('#transportstable', { "columns": [ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"}, {"name":"id","type":"text","title":"ID","style":{"width":"50px"}}, @@ -279,8 +279,11 @@ jQuery(function($){ item.action = ''; + if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; } + else if (item.used_by_domains == '') { item.in_use_by = item.used_by_mailboxes; } + else { item.in_use_by = item.used_by_mailboxes + '
' + item.used_by_domains; } item.chkbox = ''; }); } else if (table == 'transportstable') { @@ -291,7 +294,7 @@ jQuery(function($){ item.action = ''; item.chkbox = ''; }); @@ -309,7 +312,7 @@ jQuery(function($){ } else if (table == 'forwardinghoststable') { $.each(data, function (i, item) { item.action = ''; item.chkbox = ''; }); @@ -317,7 +320,7 @@ jQuery(function($){ $.each(data, function (i, item) { item.action = ''; item.scope = "profile"; item.grant_types = 'refresh_token password authorization_code'; @@ -330,7 +333,7 @@ jQuery(function($){ item.chkbox = ''; item.action = ''; }); @@ -344,7 +347,7 @@ jQuery(function($){ item.chkbox = ''; item.action = ''; }); } diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index 246209ad..fa9ffbb5 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -710,7 +710,7 @@ jQuery(function($){ } item.indicator = ' '; if (item.rl_hash != 'err') { - item.action = ' ' + lang.reset_limit + ''; + item.action = ' ' + lang.reset_limit + ''; } }); } diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js index b7896f8d..14a217bc 100644 --- a/data/web/js/site/mailbox.js +++ b/data/web/js/site/mailbox.js @@ -128,7 +128,7 @@ $(document).ready(function() { // Log modal $('#dnsInfoModal').on('show.bs.modal', function(e) { var domain = $(e.relatedTarget).data('domain'); - $('.dns-modal-body').html('
'); + $('.dns-modal-body').html('
'); $.ajax({ url: '/inc/ajax/dns_diagnostics.php', data: { domain: domain }, @@ -286,7 +286,7 @@ jQuery(function($){ item.action = '
'; if (role == "admin") { item.action += ' ' + lang.edit + '' + - ' ' + lang.remove + ''; + ' ' + lang.remove + ''; } else { item.action += ' ' + lang.edit + ''; @@ -432,7 +432,7 @@ jQuery(function($){ if (acl_data.login_as === 1) { item.action = '
' + ' ' + lang.edit + '' + - ' ' + lang.remove + '' + + ' ' + lang.remove + '' + ''; if (ALLOW_ADMIN_EMAIL_LOGIN) { item.action += ''; @@ -442,7 +442,7 @@ jQuery(function($){ else { item.action = ''; } item.in_use = '
' + @@ -519,7 +519,7 @@ jQuery(function($){ } item.action = ''; item.chkbox = ''; item.name = escapeHtml(item.name); @@ -585,7 +585,7 @@ jQuery(function($){ $.each(data, function (i, item) { item.action = ''; item.chkbox = ''; item.local_dest = escapeHtml(item.local_dest); @@ -655,7 +655,7 @@ jQuery(function($){ item.recipient_map_new = escapeHtml(item.recipient_map_new); item.action = ''; item.chkbox = ''; }); @@ -725,7 +725,7 @@ jQuery(function($){ } item.action = ''; item.chkbox = ''; }); @@ -790,7 +790,7 @@ jQuery(function($){ $.each(data, function (i, item) { item.action = ''; item.chkbox = ''; item.goto = escapeHtml(item.goto.replace(/,/g, " ")); @@ -813,7 +813,7 @@ jQuery(function($){ item.address = escapeHtml(item.address); } if (item.goto == "null@localhost") { - item.goto = '⤷ '; + item.goto = '⤷ '; } else if (item.goto == "spam@localhost") { item.goto = 'Learn as spam'; @@ -884,7 +884,7 @@ jQuery(function($){ $.each(data, function (i, item) { item.action = '' + '
'; item.chkbox = ''; @@ -964,7 +964,7 @@ jQuery(function($){ item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1; item.action = ''; item.chkbox = ''; if (item.is_running == 1) { @@ -1042,7 +1042,7 @@ jQuery(function($){ item.filter_type = '
' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '
' item.action = ''; item.chkbox = '' }); diff --git a/data/web/js/site/quarantine.js b/data/web/js/site/quarantine.js index e98fb820..748f43d6 100644 --- a/data/web/js/site/quarantine.js +++ b/data/web/js/site/quarantine.js @@ -97,7 +97,7 @@ jQuery(function($){ if (acl_data.login_as === 1) { item.action = ''; } else { diff --git a/data/web/js/site/user.js b/data/web/js/site/user.js index 6bfd982d..c2ff3897 100644 --- a/data/web/js/site/user.js +++ b/data/web/js/site/user.js @@ -94,7 +94,7 @@ jQuery(function($){ $.each(data, function (i, item) { if (acl_data.spam_alias === 1) { item.action = ''; item.chkbox = ''; item.address = escapeHtml(item.address); @@ -155,7 +155,7 @@ jQuery(function($){ if (acl_data.syncjobs === 1) { item.action = ''; item.chkbox = ''; } @@ -209,7 +209,7 @@ jQuery(function($){ if (acl_data.app_passwds === 1) { item.action = ''; item.chkbox = ''; } diff --git a/data/web/lang/lang.cs.json b/data/web/lang/lang.cs.json index c11937f2..7c807155 100644 --- a/data/web/lang/lang.cs.json +++ b/data/web/lang/lang.cs.json @@ -531,7 +531,7 @@ "save": "Uložit změny", "scope": "Rozsah", "sender_acl": "Povolit odesílání jako", - "sender_acl_disabled": "↳ Kontrola odesílatele vypnuta", + "sender_acl_disabled": "Kontrola odesílatele vypnuta", "sender_acl_info": "Má-li uživatel schránky A dovoleno odesílat jako uživatel schránky B, nezobrazuje se adresa odesílatele B v seznamu \"Od\" v SOGo automaticky.
\r\n Uživatel schránky A musí nejdříve v SOGo vytvořit pověření, jež umožní uživateli B vybrat svou adresu jako odesílatele. Tento mechanismus neplatí pro aliasy.", "sieve_desc": "Krátký popis", "sieve_type": "Typ filtru", diff --git a/data/web/lang/lang.da.json b/data/web/lang/lang.da.json index 797b9dd4..3b467a35 100644 --- a/data/web/lang/lang.da.json +++ b/data/web/lang/lang.da.json @@ -552,7 +552,7 @@ "save": "Gem ændringer", "scope": "Anvendelsesområde", "sender_acl": "Tillad at sende som", - "sender_acl_disabled": "↳ Afsenderkontrol er deaktiveret", + "sender_acl_disabled": "Afsenderkontrol er deaktiveret", "sender_acl_info": "Hvis postkassebruger A har tilladelse til at sende som postkassebruger B, vises afsenderadressen ikke automatisk som valgbar \"from\" felt i SOGo.
\r\n Postkassebruger B skal oprette en delegation i SOGo for at tillade postkassebruger A at vælge deres adresse som afsender. For at delegere en postkasse i SOGo skal du bruge menuen (tre prikker) til højre for dit postkassens navn øverst til venstre, mens du er i postvisningen. Denne adfærd gælder ikke for aliasadresser.", "sieve_desc": "Kort beskrivelse", "sieve_type": "Filtertype", diff --git a/data/web/lang/lang.de.json b/data/web/lang/lang.de.json index f3785cbe..0a16bc31 100644 --- a/data/web/lang/lang.de.json +++ b/data/web/lang/lang.de.json @@ -27,6 +27,8 @@ "tls_policy": "Verschlüsselungsrichtlinie", "unlimited_quota": "Unendliche Quota für Mailboxen", "domain_desc": "Domainbeschreibung ändern", + "mailbox_relayhost": "Relayhost für eine Mailbox setzen", + "domain_relayhost": "Relayhost für eine Domain setzen", "xmpp_admin": "Benutzer zum XMPP-Administrator ernennen", "xmpp_domain_access": "XMPP-Zugang einer Domain konfigurieren", "xmpp_mailbox_access": "XMPP-Zugang eines Benutzers einstellen", @@ -554,6 +556,7 @@ "inactive": "Inaktiv", "kind": "Art", "mailbox": "Mailbox bearbeiten", + "mailbox_relayhost_info": "Wird auf eine Mailbox und direkte Alias-Adressen angewendet. Überschreibt die Einstellung einer Domain.", "mailbox_quota_def": "Standard-Quota einer Mailbox", "max_aliases": "Max. Aliasse", "max_mailboxes": "Max. Mailboxanzahl", @@ -594,7 +597,7 @@ "save": "Änderungen speichern", "scope": "Scope", "sender_acl": "Darf Nachrichten versenden als", - "sender_acl_disabled": "↳ Absenderprüfung deaktiviert", + "sender_acl_disabled": "Absenderprüfung deaktiviert", "sender_acl_info": "Wird einem Mailbox-Benutzer A der Versand als Mailbox-Benutzer B gestattet, so erscheint der Absender nicht automatisch in SOGo zur Auswahl.
\r\n In SOGo muss zusätzlich eine Delegation eingerichtet werden. Dieses Verhalten trifft nicht auf Alias-Adressen zu.", "sieve_desc": "Kurze Beschreibung", "sieve_type": "Filtertyp", @@ -1020,6 +1023,7 @@ "eas_reset_help": "In vielen Fällen kann ein ActiveSync-Profil durch das Zurücksetzen des Caches repariert werden.
Vorsicht: Alle Elemente werden erneut heruntergeladen!", "eas_reset_now": "Jetzt zurücksetzen", "edit": "Bearbeiten", + "empty": "Keine Einträge vorhanden", "email": "E-Mail", "email_and_dav": "E-Mail, Kalender und Adressbücher", "encryption": "Verschlüsselung", diff --git a/data/web/lang/lang.en.json b/data/web/lang/lang.en.json index 08ce6fe8..780d6b3a 100644 --- a/data/web/lang/lang.en.json +++ b/data/web/lang/lang.en.json @@ -27,6 +27,8 @@ "tls_policy": "TLS policy", "unlimited_quota": "Unlimited quota for mailboxes", "domain_desc": "Change domain description", + "mailbox_relayhost": "Change relayhost for a mailbox", + "domain_relayhost": "Change relayhost for a domain", "xmpp_admin": "Promote XMPP user to administrator", "xmpp_domain_access": "Configure XMPP domain access", "xmpp_mailbox_access": "Configure XMPP user access", @@ -553,6 +555,7 @@ "kind": "Kind", "mailbox": "Edit mailbox", "mailbox_quota_def": "Default mailbox quota", + "mailbox_relayhost_info": "Applied to the mailbox and direct aliases only, does override a domain relayhost.", "max_aliases": "Max. aliases", "max_mailboxes": "Max. possible mailboxes", "max_quota": "Max. quota per mailbox (MiB)", @@ -592,7 +595,7 @@ "save": "Save changes", "scope": "Scope", "sender_acl": "Allow to send as", - "sender_acl_disabled": "↳ Sender check is disabled", + "sender_acl_disabled": "Sender check is disabled", "sender_acl_info": "If mailbox user A is allowed to send as mailbox user B, the sender address is not automatically displayed as selectable \"from\" field in SOGo.
\r\n Mailbox user B needs to create a delegation in SOGo to allow mailbox user A to select their address as sender. To delegate a mailbox in SOGo, use the menu (three dots) to the right of your mailbox name in the upper left while in mail view. This behaviour does not apply to alias addresses.", "sieve_desc": "Short description", "sieve_type": "Filter type", @@ -1018,6 +1021,7 @@ "eas_reset_help": "In many cases a device cache reset will help to recover a broken ActiveSync profile.
Attention: All elements will be redownloaded!", "eas_reset_now": "Reset now", "edit": "Edit", + "empty": "No results", "email": "Email", "email_and_dav": "Email, calendars and contacts", "encryption": "Encryption", diff --git a/data/web/lang/lang.fi.json b/data/web/lang/lang.fi.json index 25bfe4dc..3410ccc7 100644 --- a/data/web/lang/lang.fi.json +++ b/data/web/lang/lang.fi.json @@ -468,7 +468,7 @@ "save": "Tallenna muutokset", "scope": "Laajuus", "sender_acl": "Salli lähettää nimellä", - "sender_acl_disabled": "↳ Lähettäjän tarkistus on poistettu käytöstä", + "sender_acl_disabled": "Lähettäjän tarkistus on poistettu käytöstä", "sender_acl_info": "Jos postilaatikon käyttäjän A sallitaan lähettävän postilaatikon käyttäjäksi B, lähettäjän osoitetta ei näytetä automaattisesti valittavana \"alkaen\" -kentässä SOGossa.
\r\nSähkö postilaatikon käyttäjän A on luotava valtuutus SOGoon, jotta sähkö postilaatikon käyttäjä b voi valita osoitteen lähettäjäksi. Tämä käyttäytyminen ei koske alias-osoitteita", "sieve_desc": "Lyhyt kuvaus", "sieve_type": "Suodattimen tyyppi", diff --git a/data/web/lang/lang.fr.json b/data/web/lang/lang.fr.json index e8177ae8..07cd326c 100644 --- a/data/web/lang/lang.fr.json +++ b/data/web/lang/lang.fr.json @@ -578,7 +578,7 @@ "save": "Enregistrer les modifications", "scope": "Portée", "sender_acl": "Permettre d’envoyer comme", - "sender_acl_disabled": "↳ Le contrôle de l’expéditeur est désactivé", + "sender_acl_disabled": "Le contrôle de l’expéditeur est désactivé", "sender_acl_info": "Si l’utilisateur de la boîte A est autorisé à envoyer en tant qu’utilisateur de la boîte B, l’adresse de l’expéditeur n’est pas automatiquement affichée comme sélectionnable du champ \"from\" dans SOGo.
\r\n L’utilisateur B de la boîte doit créer une délégation dans Sogo pour permettre à l’utilisateur A de la boîte de sélectionner son adresse comme expéditeur. Pour déléguer une boîte dans Sogo, utilisez le menu (trois points) à droite du nom de votre boîte dans le coin supérieur gauche dans la vue de courrier. Ce comportement ne s’applique pas aux adresses alias.", "sieve_desc": "Description courte", "sieve_type": "Type de filtre", diff --git a/data/web/lang/lang.ko.json b/data/web/lang/lang.ko.json index 7e484fc9..cdd34b1b 100644 --- a/data/web/lang/lang.ko.json +++ b/data/web/lang/lang.ko.json @@ -534,7 +534,7 @@ "save": "Save changes", "scope": "Scope", "sender_acl": "Allow to send as", - "sender_acl_disabled": "↳ Sender check is disabled", + "sender_acl_disabled": "Sender check is disabled", "sender_acl_info": "If mailbox user A is allowed to send as mailbox user B, the sender address is not automatically displayed as selectable \"from\" field in SOGo.
\r\n Mailbox user B needs to create a delegation in SOGo to allow mailbox user A to select their address as sender. To delegate a mailbox in SOGo, use the menu (three dots) to the right of your mailbox name in the upper left while in mail view. This behaviour does not apply to alias addresses.", "sieve_desc": "Short description", "sieve_type": "Filter type", diff --git a/data/web/lang/lang.nl.json b/data/web/lang/lang.nl.json index 24487f91..03c55e9a 100644 --- a/data/web/lang/lang.nl.json +++ b/data/web/lang/lang.nl.json @@ -578,7 +578,7 @@ "save": "Wijzigingen opslaan", "scope": "Scope", "sender_acl": "Sta toe om te verzenden als", - "sender_acl_disabled": "↳ Verzendcontrole is uitgeschakeld", + "sender_acl_disabled": "Verzendcontrole is uitgeschakeld", "sender_acl_info": "Wanneer mailboxgebruiker A toegestaan is te verzenden namens mailboxgebruiker B, zal het verzendadres niet automatisch worden weergegeven in het \"van\"-veld in SOGo. Mailboxgebruiker A dient hiervoor een aparte vermelding te maken in SOGo. Om een mailbox te delegeren in SOGo kan het menu (drie punten) aan de rechterkant van de naam van het mailbox linksboven worden gebruikt in de mailweergave. Dit is niet van toepassing op aliasadressen.", "sieve_desc": "Korte beschrijving", "sieve_type": "Filtertype", @@ -1047,7 +1047,7 @@ "running": "Wordt uitgevoerd", "save": "Sla wijzigingen op", "save_changes": "Wijzigingen opslaan", - "sender_acl_disabled": "↳ Verzendcontrole is uitgeschakeld", + "sender_acl_disabled": "Verzendcontrole is uitgeschakeld", "shared_aliases": "Gedeelde aliasadressen", "shared_aliases_desc": "Een gedeeld aliasadres wordt niet beïnvloed door gebruikersspecifieke instellingen. Een aangepast spamfilter kan eventueel worden ingesteld door een administrator.", "show_sieve_filters": "Toon actieve filters", diff --git a/data/web/lang/lang.ro.json b/data/web/lang/lang.ro.json index e2218f8a..58ca140e 100644 --- a/data/web/lang/lang.ro.json +++ b/data/web/lang/lang.ro.json @@ -587,7 +587,7 @@ "save": "Salvează modificările", "scope": "Scop", "sender_acl": "Permite trimiterea ca", - "sender_acl_disabled": "↳ Verificarea expeditorului este dezactivată", + "sender_acl_disabled": "Verificarea expeditorului este dezactivată", "sender_acl_info": "Dacă utilizatorului A de căsuță poștală îi este permis să trimită ca utilizatorul B, adresa expeditorului nu este afișată automat ca fiind câmp selectabil \"de la\" în SOGo.
\r\n Utilizatorul căsuței poștale B trebuie să creeze o delegație în SOGo pentru a permite utilizatorul cutiei poștale A să selecteze adresa ca expeditor. Pentru a delega o cutie poștală în SOGo, utilizați meniul (trei puncte) din dreapta numelui căsuței poștale în stânga sus, în timp ce vă aflați în vizualizarea e-mailului. Acest comportament nu se aplică adreselor alias.", "sieve_desc": "Descriere scurtă", "sieve_type": "Tip filtru", diff --git a/data/web/lang/lang.sk.json b/data/web/lang/lang.sk.json index 39df5723..f6926ebb 100644 --- a/data/web/lang/lang.sk.json +++ b/data/web/lang/lang.sk.json @@ -590,7 +590,7 @@ "save": "Uložiť zmeny", "scope": "Rozsah", "sender_acl": "Povoliť odosielanie ako", - "sender_acl_disabled": "↳ Kontrola odosielateľa vypnutá", + "sender_acl_disabled": "Kontrola odosielateľa vypnutá", "sender_acl_info": "Ak poštový používateľ A má povolenie poslať ako poštový používateľ B, adresa odosielateľa nieje automaticky viditeľná ako voliteľné \"from\" pole v SOGo.
\r\n Poštový používateľ B potrebuje vytvoriť delegáciu v SOGo, aby bol schopný poštový používateľ A vybrať svoju adresu ako odosielateľ. Na delegovanie poštovej adresy v SOGo, použite menu (tri bodky) napravo vášho poštového mena v hornom ľavom rohu, v prehľade správ. Toto neplatí pre alias adresy.", "sieve_desc": "Krátky popis", "sieve_type": "Typ filtru", diff --git a/data/web/lang/lang.sv.json b/data/web/lang/lang.sv.json index 135f6c0f..3c139d79 100644 --- a/data/web/lang/lang.sv.json +++ b/data/web/lang/lang.sv.json @@ -592,7 +592,7 @@ "save": "Spara ändringar", "scope": "Omfattning", "sender_acl": "Tillåt att skicka som", - "sender_acl_disabled": "↳ Avsändarkontroll är avaktiverad", + "sender_acl_disabled": "Avsändarkontroll är avaktiverad", "sender_acl_info": "Om användaren A tillåts skicka som användaren B visas inte avsändaradressen automatiskt i \"från\" fältet i SOGo.
\r\n Användaren B måste skapa en delegation i SOGo för att låta användaren A välja Användaren B's adress som avsändare. För att delegera en postlåda i SOGo, gå till menyn (tre punkter) till höger om ditt namn uppe till vänster i postvyn. Detta gäller inte för aliasadresser.", "sieve_desc": "Kort beskrivning", "sieve_type": "Filtertyp", diff --git a/data/web/lang/lang.zh.json b/data/web/lang/lang.zh.json index 6adfb52c..8993cb9c 100644 --- a/data/web/lang/lang.zh.json +++ b/data/web/lang/lang.zh.json @@ -544,7 +544,7 @@ "save": "保存更改", "scope": "范围", "sender_acl": "允许发送为", - "sender_acl_disabled": "↳ 发件人检查已关闭", + "sender_acl_disabled": "发件人检查已关闭", "sender_acl_info": "如果允许邮箱用户A作为邮箱用户B发送邮件,发件人的地址不会在SOGo中\"来自\"区域自动地作为下拉可选项显示。
\r\n 邮箱用户B需要添加授权以允许邮箱用户A选择B的地址作为发件人;授权方法为,在SOGo中点击左上方邮箱地址右边的菜单按钮(三个点)并授权。", "sieve_desc": "简短描述", "sieve_type": "过滤器类型", diff --git a/data/web/user.php b/data/web/user.php index 7006aaaa..61a04be2 100644 --- a/data/web/user.php +++ b/data/web/user.php @@ -94,7 +94,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma @@ -229,32 +229,33 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == ' } ?>
-
: +
:

'; } else { foreach (array_filter($user_get_alias_details['direct_aliases']) as $direct_alias => $direct_alias_meta) { (!empty($direct_alias_meta['public_comment'])) ? - printf('%s — %s
', $direct_alias, $direct_alias_meta['public_comment']) : + printf('%s — %s
', $direct_alias, $direct_alias_meta['public_comment']) : printf('%s
', $direct_alias); } } ?>
+
-
: +
:

'; } else { foreach (array_filter($user_get_alias_details['shared_aliases']) as $shared_alias => $shared_alias_meta) { @@ -271,19 +272,19 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
:
-

+

' : '' ;?>

:
-

+

' : '' ;?>

:
-

+

' : '' ;?>


@@ -648,7 +649,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
- +
diff --git a/docker-compose.yml b/docker-compose.yml index 44733122..2e984e0a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -290,7 +290,7 @@ services: - dovecot postfix-mailcow: - image: mailcow/postfix:1.61 + image: mailcow/postfix:1.62 depends_on: - mysql-mailcow volumes: