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.merged_vars_hint|raw }}
@@ -86,7 +86,7 @@