diff --git a/data/web/admin.php b/data/web/admin.php index a3b908b7..cd3eb890 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -103,6 +103,7 @@ $template_data = [ 'rsettings' => $rsettings, 'rspamd_regex_maps' => $rspamd_regex_maps, 'logo_specs' => customize('get', 'main_logo_specs'), + 'ip_check' => customize('get', 'ip_check'), 'password_complexity' => password_complexity('get'), 'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'], 'lang_admin' => json_encode($lang['admin']), diff --git a/data/web/css/build/015-datatables.css b/data/web/css/build/013-datatables.css similarity index 100% rename from data/web/css/build/015-datatables.css rename to data/web/css/build/013-datatables.css diff --git a/data/web/css/build/013-mailcow.css b/data/web/css/build/014-mailcow.css similarity index 92% rename from data/web/css/build/013-mailcow.css rename to data/web/css/build/014-mailcow.css index 374d484d..3d0eeaee 100644 --- a/data/web/css/build/013-mailcow.css +++ b/data/web/css/build/014-mailcow.css @@ -370,3 +370,14 @@ button[aria-expanded='true'] > .caret { .btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show { background-color: #f0f0f0 !important; } + + +div.dataTables_wrapper div.dataTables_filter { + text-align: left; +} +div.dataTables_wrapper div.dataTables_length { + text-align: right; +} +.dataTables_paginate, .dataTables_length, .dataTables_filter { + margin: 10px 0!important; +} \ No newline at end of file diff --git a/data/web/css/build/014-responsive.css b/data/web/css/build/015-responsive.css similarity index 98% rename from data/web/css/build/014-responsive.css rename to data/web/css/build/015-responsive.css index a9877271..47eadb53 100644 --- a/data/web/css/build/014-responsive.css +++ b/data/web/css/build/015-responsive.css @@ -199,6 +199,10 @@ display: none !important; } + div.dataTables_wrapper div.dataTables_length { + text-align: left; + } + } @media (max-width: 350px) { diff --git a/data/web/css/themes/lumen-bootstrap.css b/data/web/css/themes/lumen-bootstrap.css index a7582237..bcf62683 100644 --- a/data/web/css/themes/lumen-bootstrap.css +++ b/data/web/css/themes/lumen-bootstrap.css @@ -11,7 +11,86 @@ * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ -@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,300;0,400;0,700;1,400&display=swap"); + +/* source-sans-pro-300 - latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: url('/fonts/source-sans-pro-v21-latin-300.eot'); /* IE9 Compat Modes */ + src: local(''), + url('/fonts/source-sans-pro-v21-latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('/fonts/source-sans-pro-v21-latin-300.woff2') format('woff2'), /* Super Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-300.woff') format('woff'), /* Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-300.ttf') format('truetype'), /* Safari, Android, iOS */ + url('/fonts/source-sans-pro-v21-latin-300.svg#SourceSansPro') format('svg'); /* Legacy iOS */ +} +/* source-sans-pro-300italic - latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 300; + src: url('/fonts/source-sans-pro-v21-latin-300italic.eot'); /* IE9 Compat Modes */ + src: local(''), + url('/fonts/source-sans-pro-v21-latin-300italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('/fonts/source-sans-pro-v21-latin-300italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-300italic.woff') format('woff'), /* Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-300italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('/fonts/source-sans-pro-v21-latin-300italic.svg#SourceSansPro') format('svg'); /* Legacy iOS */ +} +/* source-sans-pro-regular - latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: url('/fonts/source-sans-pro-v21-latin-regular.eot'); /* IE9 Compat Modes */ + src: local(''), + url('/fonts/source-sans-pro-v21-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('/fonts/source-sans-pro-v21-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('/fonts/source-sans-pro-v21-latin-regular.svg#SourceSansPro') format('svg'); /* Legacy iOS */ +} +/* source-sans-pro-italic - latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 400; + src: url('/fonts/source-sans-pro-v21-latin-italic.eot'); /* IE9 Compat Modes */ + src: local(''), + url('/fonts/source-sans-pro-v21-latin-italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('/fonts/source-sans-pro-v21-latin-italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-italic.woff') format('woff'), /* Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('/fonts/source-sans-pro-v21-latin-italic.svg#SourceSansPro') format('svg'); /* Legacy iOS */ +} +/* source-sans-pro-700 - latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 700; + src: url('/fonts/source-sans-pro-v21-latin-700.eot'); /* IE9 Compat Modes */ + src: local(''), + url('/fonts/source-sans-pro-v21-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('/fonts/source-sans-pro-v21-latin-700.woff2') format('woff2'), /* Super Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-700.woff') format('woff'), /* Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */ + url('/fonts/source-sans-pro-v21-latin-700.svg#SourceSansPro') format('svg'); /* Legacy iOS */ +} +/* source-sans-pro-700italic - latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 700; + src: url('/fonts/source-sans-pro-v21-latin-700italic.eot'); /* IE9 Compat Modes */ + src: local(''), + url('/fonts/source-sans-pro-v21-latin-700italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('/fonts/source-sans-pro-v21-latin-700italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-700italic.woff') format('woff'), /* Modern Browsers */ + url('/fonts/source-sans-pro-v21-latin-700italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('/fonts/source-sans-pro-v21-latin-700italic.svg#SourceSansPro') format('svg'); /* Legacy iOS */ +} + :root { --bs-blue: #158cba; --bs-indigo: #6610f2; diff --git a/data/web/css/themes/mailcow-darkmode.css b/data/web/css/themes/mailcow-darkmode.css index e1824420..6e0db0e9 100644 --- a/data/web/css/themes/mailcow-darkmode.css +++ b/data/web/css/themes/mailcow-darkmode.css @@ -358,3 +358,11 @@ table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty { background: #333; } +span.mail-address-item { + background-color: #333; + border-radius: 4px; + border: 1px solid #555; + padding: 2px 7px; + display: inline-block; + margin: 2px 6px 2px 0; +} diff --git a/data/web/debug.php b/data/web/debug.php index 45c4456c..52052f68 100644 --- a/data/web/debug.php +++ b/data/web/debug.php @@ -65,6 +65,7 @@ $template_data = [ 'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60), 'clamd_status' => $clamd_status, 'containers' => $containers, + 'ip_check' => customize('get', 'ip_check'), 'lang_admin' => json_encode($lang['admin']), 'lang_debug' => json_encode($lang['debug']), 'lang_datatables' => json_encode($lang['datatables']), diff --git a/data/web/fonts/source-sans-pro-v21-latin-300.woff b/data/web/fonts/source-sans-pro-v21-latin-300.woff new file mode 100644 index 00000000..e966494d Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-300.woff differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-300.woff2 b/data/web/fonts/source-sans-pro-v21-latin-300.woff2 new file mode 100644 index 00000000..fed32a93 Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-300.woff2 differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-300italic.woff b/data/web/fonts/source-sans-pro-v21-latin-300italic.woff new file mode 100644 index 00000000..c0dca072 Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-300italic.woff differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-300italic.woff2 b/data/web/fonts/source-sans-pro-v21-latin-300italic.woff2 new file mode 100644 index 00000000..a8e1fff2 Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-300italic.woff2 differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-700.woff b/data/web/fonts/source-sans-pro-v21-latin-700.woff new file mode 100644 index 00000000..a6786d1f Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-700.woff differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-700.woff2 b/data/web/fonts/source-sans-pro-v21-latin-700.woff2 new file mode 100644 index 00000000..cd6bfd0f Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-700.woff2 differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-700italic.woff b/data/web/fonts/source-sans-pro-v21-latin-700italic.woff new file mode 100644 index 00000000..729bdee9 Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-700italic.woff differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-700italic.woff2 b/data/web/fonts/source-sans-pro-v21-latin-700italic.woff2 new file mode 100644 index 00000000..b413356f Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-700italic.woff2 differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-italic.woff b/data/web/fonts/source-sans-pro-v21-latin-italic.woff new file mode 100644 index 00000000..f927419c Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-italic.woff differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-italic.woff2 b/data/web/fonts/source-sans-pro-v21-latin-italic.woff2 new file mode 100644 index 00000000..9448cd52 Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-italic.woff2 differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-regular.woff b/data/web/fonts/source-sans-pro-v21-latin-regular.woff new file mode 100644 index 00000000..db90a83e Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-regular.woff differ diff --git a/data/web/fonts/source-sans-pro-v21-latin-regular.woff2 b/data/web/fonts/source-sans-pro-v21-latin-regular.woff2 new file mode 100644 index 00000000..e49928e8 Binary files /dev/null and b/data/web/fonts/source-sans-pro-v21-latin-regular.woff2 differ diff --git a/data/web/inc/functions.customize.inc.php b/data/web/inc/functions.customize.inc.php index 16c5c036..6025d97d 100644 --- a/data/web/inc/functions.customize.inc.php +++ b/data/web/inc/functions.customize.inc.php @@ -160,6 +160,25 @@ function customize($_action, $_item, $_data = null) { 'msg' => 'ui_texts' ); break; + case 'ip_check': + $ip_check = ($_data['ip_check_opt_in'] == "1") ? 1 : 0; + try { + $redis->set('IP_CHECK', $ip_check); + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => array('redis_error', $e) + ); + return false; + } + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'ip_check_opt_in_modified' + ); + break; } break; case 'delete': @@ -276,6 +295,20 @@ function customize($_action, $_item, $_data = null) { return false; } break; + case 'ip_check': + try { + $ip_check = ($ip_check = $redis->get('IP_CHECK')) ? $ip_check : 0; + return $ip_check; + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => array('redis_error', $e) + ); + return false; + } + break; } break; } diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index d67fa3e3..f6162cc6 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -2879,67 +2879,68 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $_SESSION['return'][] = array( 'type' => 'danger', 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), - 'msg' => 'access_denied' + 'msg' => 'extended_sender_acl_denied' ); - return false; } - $extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl'])); - foreach ($extra_acls as $i => &$extra_acl) { - if (empty($extra_acl)) { - continue; - } - if (substr($extra_acl, 0, 1) === "@") { - $extra_acl = ltrim($extra_acl, '@'); - } - if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) { - $_SESSION['return'][] = array( - 'type' => 'danger', - 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), - 'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl)) - ); - unset($extra_acls[$i]); - continue; - } - $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')); - if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) { - $extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46); - if (in_array($extra_acl_domain, $domains)) { + else { + $extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl'])); + foreach ($extra_acls as $i => &$extra_acl) { + if (empty($extra_acl)) { + continue; + } + if (substr($extra_acl, 0, 1) === "@") { + $extra_acl = ltrim($extra_acl, '@'); + } + if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) { $_SESSION['return'][] = array( 'type' => 'danger', 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), - 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain) + 'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl)) ); unset($extra_acls[$i]); continue; } - } - else { - if (in_array($extra_acl, $domains)) { - $_SESSION['return'][] = array( - 'type' => 'danger', - 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), - 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain) - ); - unset($extra_acls[$i]); - continue; + $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')); + if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) { + $extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46); + if (in_array($extra_acl_domain, $domains)) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain) + ); + unset($extra_acls[$i]); + continue; + } + } + else { + if (in_array($extra_acl, $domains)) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain) + ); + unset($extra_acls[$i]); + continue; + } + $extra_acl = '@' . $extra_acl; } - $extra_acl = '@' . $extra_acl; } - } - $extra_acls = array_filter($extra_acls); - $extra_acls = array_values($extra_acls); - $extra_acls = array_unique($extra_acls); - $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username"); - $stmt->execute(array( - ':username' => $username - )); - foreach ($extra_acls as $sender_acl_external) { - $stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`) - VALUES (:sender_acl, :username, 1)"); + $extra_acls = array_filter($extra_acls); + $extra_acls = array_values($extra_acls); + $extra_acls = array_unique($extra_acls); + $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username"); $stmt->execute(array( - ':sender_acl' => $sender_acl_external, ':username' => $username )); + foreach ($extra_acls as $sender_acl_external) { + $stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`) + VALUES (:sender_acl, :username, 1)"); + $stmt->execute(array( + ':sender_acl' => $sender_acl_external, + ':username' => $username + )); + } } } if (isset($_data['sender_acl'])) { diff --git a/data/web/js/build/013-mailcow.js b/data/web/js/build/013-mailcow.js index c734c824..afe17bc6 100644 --- a/data/web/js/build/013-mailcow.js +++ b/data/web/js/build/013-mailcow.js @@ -12,14 +12,22 @@ $(document).ready(function() { $.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}}); } - $(".generate_password").click(function( event ) { + $(".generate_password").click(async function( event ) { + try { + var password_policy = await window.fetch("/api/v1/get/passwordpolicy", { method:'GET', cache:'no-cache' }); + var password_policy = await password_policy.json(); + random_passwd_length = password_policy.length; + } catch(err) { + var random_passwd_length = 8; + } + event.preventDefault(); $('[data-hibp]').trigger('input'); if (typeof($(this).closest("form").data('pwgen-length')) == "number") { var random_passwd = GPW.pronounceable($(this).closest("form").data('pwgen-length')) } else { - var random_passwd = GPW.pronounceable(8) + var random_passwd = GPW.pronounceable(random_passwd_length) } $(this).closest("form").find('[data-pwgen-field]').attr('type', 'text'); $(this).closest("form").find('[data-pwgen-field]').val(random_passwd); diff --git a/data/web/js/site/admin.js b/data/web/js/site/admin.js index d47a2227..9877bb68 100644 --- a/data/web/js/site/admin.js +++ b/data/web/js/site/admin.js @@ -70,8 +70,13 @@ jQuery(function($){ } $('#domainadminstable').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -143,8 +148,13 @@ jQuery(function($){ } $('#oauth2clientstable').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -206,8 +216,13 @@ jQuery(function($){ } $('#adminstable').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -272,8 +287,13 @@ jQuery(function($){ } $('#forwardinghoststable').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -330,8 +350,13 @@ jQuery(function($){ } $('#relayhoststable').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -402,8 +427,13 @@ jQuery(function($){ } $('#transportstable').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index 358b00c6..7a84503d 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -51,7 +51,40 @@ $(document).ready(function() { showVersionModal("Version " + mailcow_info.version_tag, mailcow_info.version_tag); }) // get public ips - get_public_ips(); + $("#host_show_ip").click(function(){ + $("#host_show_ip").find(".text").addClass("d-none"); + $("#host_show_ip").find(".spinner-border").removeClass("d-none"); + + window.fetch("/api/v1/get/status/host/ip", { method:'GET', cache:'no-cache' }).then(function(response) { + return response.json(); + }).then(function(data) { + console.log(data); + + // display host ips + if (data.ipv4) + $("#host_ipv4").text(data.ipv4); + if (data.ipv6) + $("#host_ipv6").text(data.ipv6); + + $("#host_show_ip").addClass("d-none"); + $("#host_show_ip").find(".text").removeClass("d-none"); + $("#host_show_ip").find(".spinner-border").addClass("d-none"); + $("#host_ipv4").removeClass("d-none"); + $("#host_ipv6").removeClass("d-none"); + $("#host_ipv6").removeClass("text-danger"); + $("#host_ipv4").addClass("d-block"); + $("#host_ipv6").addClass("d-block"); + }).catch(function(error){ + console.log(error); + + $("#host_ipv6").removeClass("d-none"); + $("#host_ipv6").addClass("d-block"); + $("#host_ipv6").addClass("text-danger"); + $("#host_ipv6").text(lang_debug.error_show_ip); + $("#host_show_ip").find(".text").removeClass("d-none"); + $("#host_show_ip").find(".spinner-border").addClass("d-none"); + }); + }); update_container_stats(); }); jQuery(function($){ @@ -86,8 +119,13 @@ jQuery(function($){ } $('#autodiscover_log').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -143,8 +181,13 @@ jQuery(function($){ } $('#postfix_log').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -185,8 +228,13 @@ jQuery(function($){ } $('#watchdog_log').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -231,8 +279,13 @@ jQuery(function($){ } $('#api_log').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -284,8 +337,13 @@ jQuery(function($){ } $('#rl_log').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -375,8 +433,13 @@ jQuery(function($){ } $('#ui_logs').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -446,8 +509,13 @@ jQuery(function($){ } $('#sasl_logs').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -494,8 +562,13 @@ jQuery(function($){ } $('#acme_log').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -531,8 +604,13 @@ jQuery(function($){ } $('#netfilter_log').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -573,8 +651,13 @@ jQuery(function($){ } $('#sogo_log').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -615,8 +698,13 @@ jQuery(function($){ } $('#dovecot_log').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -718,8 +806,13 @@ jQuery(function($){ } $('#rspamd_history').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order: [[0, 'desc']], ajax: { @@ -1224,20 +1317,6 @@ function update_container_stats(timeout=5){ // run again in n seconds setTimeout(update_container_stats, timeout * 1000); } -// get public ips -function get_public_ips(){ - window.fetch("/api/v1/get/status/host/ip", {method:'GET',cache:'no-cache'}).then(function(response) { - return response.json(); - }).then(function(data) { - console.log(data); - - // display host ips - if (data.ipv4) - $("#host_ipv4").text(data.ipv4); - if (data.ipv6) - $("#host_ipv6").text(data.ipv6); - }); -} // format hosts uptime seconds to readable string function formatUptime(seconds){ seconds = Number(seconds); diff --git a/data/web/js/site/edit.js b/data/web/js/site/edit.js index 55a8e6b4..4c57b35e 100644 --- a/data/web/js/site/edit.js +++ b/data/web/js/site/edit.js @@ -78,8 +78,13 @@ jQuery(function($){ } function draw_wl_policy_domain_table() { $('#wl_policy_domain_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -133,8 +138,13 @@ jQuery(function($){ } function draw_bl_policy_domain_table() { $('#bl_policy_domain_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js index 0e400b30..cdcf7dbb 100644 --- a/data/web/js/site/mailbox.js +++ b/data/web/js/site/mailbox.js @@ -433,8 +433,13 @@ jQuery(function($){ } var table = $('#domain_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -619,9 +624,13 @@ jQuery(function($){ } $('#templates_domain_table').DataTable({ - responsive : true, + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order:[[2, 'desc']], ajax: { @@ -817,16 +826,26 @@ jQuery(function($){ } $('#mailbox_table').DataTable({ - responsive : true, + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", url: "/api/v1/get/mailbox/reduced", dataSrc: function(json){ $.each(json, function (i, item) { - item.quota = item.quota_used + "/" + item.quota; + item.quota = { + sortBy: item.quota_used, + value: item.quota + } + item.quota.value = (item.quota.value == 0 ? "∞" : humanFileSize(item.quota.value)); + item.quota.value = humanFileSize(item.quota_used) + "/" + item.quota.value; + item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox); item.last_mail_login = item.last_imap_login + '/' + item.last_pop3_login + '/' + item.last_smtp_login; /* @@ -931,14 +950,10 @@ jQuery(function($){ }, { title: lang.domain_quota, - data: 'quota', + data: 'quota.value', responsivePriority: 8, - defaultContent: '', - render: function (data, type) { - data = data.split("/"); - var of_q = (data[1] == 0 ? "∞" : humanFileSize(data[1])); - return humanFileSize(data[0]) + " / " + of_q; - } + defaultContent: '', + orderData: 23 }, { title: lang.last_mail_login, @@ -1064,6 +1079,13 @@ jQuery(function($){ responsivePriority: 6, defaultContent: '' }, + { + title: "", + data: 'quota.sortBy', + responsivePriority: 8, + defaultContent: '', + className: "d-none" + }, ] }); } @@ -1075,9 +1097,13 @@ jQuery(function($){ } $('#templates_mbox_table').DataTable({ - responsive : true, + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order:[[2, 'desc']], ajax: { @@ -1287,8 +1313,13 @@ jQuery(function($){ } $('#resource_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -1413,8 +1444,13 @@ jQuery(function($){ } $('#bcc_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order:[[2, 'desc']], ajax: { @@ -1510,8 +1546,13 @@ jQuery(function($){ } $('#recipient_map_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order:[[2, 'desc']], ajax: { @@ -1594,8 +1635,13 @@ jQuery(function($){ } $('#tls_policy_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order:[[2, 'desc']], ajax: { @@ -1688,8 +1734,13 @@ jQuery(function($){ } $('#alias_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order:[[2, 'desc']], ajax: { @@ -1829,8 +1880,13 @@ jQuery(function($){ } $('#aliasdomain_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -1911,8 +1967,13 @@ jQuery(function($){ } $('#sync_job_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order:[[2, 'desc']], ajax: { @@ -2051,9 +2112,14 @@ jQuery(function($){ } var table = $('#filter_table').DataTable({ + responsive: true, autoWidth: false, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, order:[[2, 'desc']], ajax: { diff --git a/data/web/js/site/quarantine.js b/data/web/js/site/quarantine.js index 34531b0d..2c4d541b 100644 --- a/data/web/js/site/quarantine.js +++ b/data/web/js/site/quarantine.js @@ -14,8 +14,13 @@ jQuery(function($){ }); function draw_quarantine_table() { $('#quarantinetable').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -129,9 +134,15 @@ jQuery(function($){ title: lang.received, data: 'created', defaultContent: '', - render: function (data,type) { - var date = new Date(data ? data * 1000 : 0); - return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); + createdCell: function(td, cellData) { + $(td).attr({ + "data-order": cellData, + "data-sort": cellData + }); + + var date = new Date(cellData ? cellData * 1000 : 0); + var dateString = date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); + $(td).html(dateString); } }, { diff --git a/data/web/js/site/queue.js b/data/web/js/site/queue.js index 057ad840..6b2d2b3b 100644 --- a/data/web/js/site/queue.js +++ b/data/web/js/site/queue.js @@ -35,8 +35,13 @@ jQuery(function($){ } $('#queuetable').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", diff --git a/data/web/js/site/user.js b/data/web/js/site/user.js index 36bcfa63..d1b9780f 100644 --- a/data/web/js/site/user.js +++ b/data/web/js/site/user.js @@ -135,8 +135,13 @@ jQuery(function($){ } $('#tla_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -216,8 +221,13 @@ jQuery(function($){ } $('#sync_job_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -366,8 +376,13 @@ jQuery(function($){ } $('#app_passwd_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -456,8 +471,13 @@ jQuery(function($){ } $('#wl_policy_mailbox_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", @@ -521,8 +541,13 @@ jQuery(function($){ } $('#bl_policy_mailbox_table').DataTable({ + responsive: true, processing: true, serverSide: false, + stateSave: true, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, ajax: { type: "GET", diff --git a/data/web/json_api.php b/data/web/json_api.php index 79b6bfd5..acaeaba9 100644 --- a/data/web/json_api.php +++ b/data/web/json_api.php @@ -561,6 +561,15 @@ if (isset($_GET['query'])) { echo '{}'; } break; + default: + $password_complexity_rules = password_complexity('get'); + if ($password_complexity_rules !== false) { + process_get_return($password_complexity_rules); + } + else { + echo '{}'; + } + break; } break; @@ -1544,14 +1553,15 @@ if (isset($_GET['query'])) { } else if ($extra == "ip") { // get public ips + $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL, 'http://ipv4.mailcow.email'); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_POST, 0); + curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_setopt($curl, CURLOPT_TIMEOUT, 15); + curl_setopt($curl, CURLOPT_URL, 'http://ipv4.mailcow.email'); $ipv4 = curl_exec($curl); curl_setopt($curl, CURLOPT_URL, 'http://ipv6.mailcow.email'); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($curl, CURLOPT_POST, 0); $ipv6 = curl_exec($curl); $ips = array( "ipv4" => $ipv4, @@ -1913,6 +1923,9 @@ if (isset($_GET['query'])) { case "ui_texts": process_edit_return(customize('edit', 'ui_texts', $attr)); break; + case "ip_check": + process_edit_return(customize('edit', 'ip_check', $attr)); + break; case "self": if ($_SESSION['mailcow_cc_role'] == "domainadmin") { process_edit_return(domain_admin('edit', $attr)); diff --git a/data/web/lang/lang.de-de.json b/data/web/lang/lang.de-de.json index d430d0b3..4f7feb5b 100644 --- a/data/web/lang/lang.de-de.json +++ b/data/web/lang/lang.de-de.json @@ -204,6 +204,9 @@ "include_exclude": "Ein- und Ausschlüsse", "include_exclude_info": "Ohne Auswahl werden alle Mailboxen adressiert.", "includes": "Diese Empfänger einschließen", + "ip_check": "IP Check", + "ip_check_disabled": "IP check ist deaktiviert. Unter dem angegebenen Pfad kann es aktiviert werden
System > Konfiguration > Einstellungen > UI-Anpassung", + "ip_check_opt_in": "Opt-In für die Nutzung der Drittanbieter-Dienste ipv4.mailcow.email und ipv6.mailcow.email zur Auflösung externer IP-Adressen.", "is_mx_based": "MX-basiert", "last_applied": "Zuletzt angewendet", "license_info": "Eine Lizenz ist nicht erforderlich, hilft jedoch der Entwicklung mailcows.
Hier kann die mailcow-GUID registriert werden. Alternativ ist die Bestellung von Support-Paketen möglich.", @@ -363,6 +366,7 @@ "domain_not_empty": "Domain %s ist nicht leer", "domain_not_found": "Domain %s nicht gefunden", "domain_quota_m_in_use": "Domain-Speicherplatzlimit muss größer oder gleich %d MiB sein", + "extended_sender_acl_denied": "Keine Rechte zum setzen von externen Absenderadressen", "extra_acl_invalid": "Externe Absenderadresse \"%s\" ist ungültig", "extra_acl_invalid_domain": "Externe Absenderadresse \"%s\" verwendet eine ungültige Domain", "fido2_verification_failed": "FIDO2-Verifizierung fehlgeschlagen: %s", @@ -494,6 +498,7 @@ "current_time": "Systemzeit", "disk_usage": "Festplattennutzung", "docs": "Dokumente", + "error_show_ip": "konnte die öffentlichen IP Adressen nicht auflösen", "external_logs": "Externe Logs", "history_all_servers": "History (alle Server)", "in_memory_logs": "In-memory Logs", @@ -506,6 +511,7 @@ "online_users": "Benutzer online", "restart_container": "Neustart", "service": "Dienst", + "show_ip": "Zeige öffentliche IP", "size": "Größe", "solr_dead": "Solr startet, ist deaktiviert oder temporär nicht erreichbar.", "solr_status": "Solr Status", @@ -1001,6 +1007,7 @@ "forwarding_host_removed": "Weiterleitungs-Host %s wurde entfernt", "global_filter_written": "Filterdatei wurde erfolgreich geschrieben", "hash_deleted": "Hash wurde gelöscht", + "ip_check_opt_in_modified": "IP Check wurde erfolgreich gespeichert", "item_deleted": "Objekt %s wurde entfernt", "item_released": "Objekt %s freigegeben", "items_deleted": "Objekt(e) %s wurde(n) erfolgreich entfernt", diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json index 22fffac8..329e9327 100644 --- a/data/web/lang/lang.en-gb.json +++ b/data/web/lang/lang.en-gb.json @@ -206,6 +206,9 @@ "include_exclude": "Include/Exclude", "include_exclude_info": "By default - with no selection - all mailboxes are addressed", "includes": "Include these recipients", + "ip_check": "IP Check", + "ip_check_disabled": "IP check is disabled. You can enable it under
System > Configuration > Options > Customize", + "ip_check_opt_in": "Opt-In for using third party service ipv4.mailcow.email and ipv6.mailcow.email to resolve external IP addresses.", "is_mx_based": "MX based", "last_applied": "Last applied", "license_info": "A license is not required but helps further development.
Register your GUID here or buy support for your mailcow installation.", @@ -363,6 +366,7 @@ "domain_not_empty": "Cannot remove non-empty domain %s", "domain_not_found": "Domain %s not found", "domain_quota_m_in_use": "Domain quota must be greater or equal to %s MiB", + "extended_sender_acl_denied": "missing ACL to set external sender addresses", "extra_acl_invalid": "External sender address \"%s\" is invalid", "extra_acl_invalid_domain": "External sender \"%s\" uses an invalid domain", "fido2_verification_failed": "FIDO2 verification failed: %s", @@ -497,6 +501,7 @@ "current_time": "System Time", "disk_usage": "Disk usage", "docs": "Docs", + "error_show_ip": "Could not resolve the public IP addresses", "external_logs": "External logs", "history_all_servers": "History (all servers)", "in_memory_logs": "In-memory logs", @@ -509,6 +514,7 @@ "online_users": "Users online", "restart_container": "Restart", "service": "Service", + "show_ip": "Show public IP", "size": "Size", "solr_dead": "Solr is starting, disabled or died.", "solr_status": "Solr status", @@ -1013,6 +1019,7 @@ "forwarding_host_removed": "Forwarding host %s has been removed", "global_filter_written": "Filter was successfully written to file", "hash_deleted": "Hash deleted", + "ip_check_opt_in_modified": "IP check was saved successfully", "item_deleted": "Item %s successfully deleted", "item_released": "Item %s released", "items_deleted": "Item %s successfully deleted", diff --git a/data/web/templates/admin/tab-config-customize.twig b/data/web/templates/admin/tab-config-customize.twig index 4ec6aecb..766c0b6a 100644 --- a/data/web/templates/admin/tab-config-customize.twig +++ b/data/web/templates/admin/tab-config-customize.twig @@ -33,6 +33,20 @@ {% endif %} + {{ lang.admin.ip_check }}
+
+
+
+ + +
+

+ +

+
+
{{ lang.admin.app_links }}

{{ lang.admin.merged_vars_hint|raw }}

diff --git a/data/web/templates/admin/tab-routing.twig b/data/web/templates/admin/tab-routing.twig index 8caeec8a..9b584289 100644 --- a/data/web/templates/admin/tab-routing.twig +++ b/data/web/templates/admin/tab-routing.twig @@ -36,7 +36,7 @@
- +
@@ -86,7 +86,7 @@
- +
diff --git a/data/web/templates/mailbox.twig b/data/web/templates/mailbox.twig index cdb6a428..d1044288 100644 --- a/data/web/templates/mailbox.twig +++ b/data/web/templates/mailbox.twig @@ -4,18 +4,18 @@