-
@@ -582,6 +614,8 @@ if (isset($_SESSION['mailcow_cc_role'])) {
+
+ 1 =$lang['diagnostics']['cname_from_a'];?>
+ 2 =$lang['diagnostics']['optional'];?>
+
+ execute(array(
':domain' => '%@' . $domain
));
- $stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `defquota`, `maxquota`, `quota`, `backupmx`, `gal`, `active`, `relay_unknown_only`, `relay_all_recipients`)
- VALUES (:domain, :description, :aliases, :mailboxes, :defquota, :maxquota, :quota, :backupmx, :gal, :active, :relay_unknown_only, :relay_all_recipients)");
+ $stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `defquota`, `maxquota`, `quota`, `backupmx`, `gal`, `xmpp`, `xmpp_prefix`, `active`, `relay_unknown_only`, `relay_all_recipients`)
+ VALUES (:domain, :description, :aliases, :mailboxes, :defquota, :maxquota, :quota, :backupmx, :gal, :xmpp, :xmpp_prefix, :active, :relay_unknown_only, :relay_all_recipients)");
$stmt->execute(array(
':domain' => $domain,
':description' => $description,
@@ -554,6 +556,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':quota' => $quota,
':backupmx' => $backupmx,
':gal' => $gal,
+ ':xmpp' => $xmpp,
+ ':xmpp_prefix' => $xmpp_prefix,
':active' => $active,
':relay_unknown_only' => $relay_unknown_only,
':relay_all_recipients' => $relay_all_recipients
@@ -948,6 +952,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$imap_access = (isset($_data['imap_access'])) ? intval($_data['imap_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
$pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
$smtp_access = (isset($_data['smtp_access'])) ? intval($_data['smtp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
+ $xmpp_access = (isset($_data['xmpp_access'])) ? intval($_data['xmpp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['xmpp_access']);
+ $xmpp_admin = (isset($_data['xmpp_admin'])) ? intval($_data['xmpp_admin']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['xmpp_admin']);
$quarantine_notification = (isset($_data['quarantine_notification'])) ? strval($_data['quarantine_notification']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
$quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
$quota_b = ($quota_m * 1048576);
@@ -960,6 +966,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
'imap_access' => strval($imap_access),
'pop3_access' => strval($pop3_access),
'smtp_access' => strval($smtp_access),
+ 'xmpp_access' => strval($xmpp_access),
+ 'xmpp_admin' => strval($xmpp_admin),
'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']),
'quarantine_notification' => strval($quarantine_notification),
'quarantine_category' => strval($quarantine_category)
@@ -2095,6 +2103,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$is_now = mailbox('get', 'domain_details', $domain);
if (!empty($is_now)) {
$gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
+ $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'];
}
else {
@@ -2107,11 +2117,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
}
$stmt = $pdo->prepare("UPDATE `domain` SET
`description` = :description,
- `gal` = :gal
+ `gal` = :gal,
+ `xmpp` = :xmpp,
+ `xmpp_prefix` = :xmpp_prefix
WHERE `domain` = :domain");
$stmt->execute(array(
':description' => $description,
':gal' => $gal,
+ ':xmpp' => $xmpp,
+ ':xmpp_prefix' => $xmpp_prefix,
':domain' => $domain
));
$_SESSION['return'][] = array(
@@ -2126,6 +2140,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$backupmx = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : $is_now['backupmx'];
$gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
+ $xmpp = (isset($_data['xmpp'])) ? intval($_data['xmpp']) : $is_now['xmpp'];
$relay_all_recipients = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : $is_now['relay_all_recipients'];
$relay_unknown_only = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : $is_now['relay_unknown_only'];
$relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : $is_now['relayhost'];
@@ -2135,6 +2150,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$maxquota = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_quota_for_mbox'] / 1048576);
$quota = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['max_quota_for_domain'] / 1048576);
$description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
+ $xmpp_prefix = (!empty($_data['xmpp_prefix'])) ? $_data['xmpp_prefix'] : $is_now['xmpp_prefix'];
if ($relay_all_recipients == '1') {
$backupmx = '1';
}
@@ -2238,6 +2254,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`relay_unknown_only` = :relay_unknown_only,
`backupmx` = :backupmx,
`gal` = :gal,
+ `xmpp` = :xmpp,
+ `xmpp_prefix` = :xmpp_prefix,
`active` = :active,
`quota` = :quota,
`defquota` = :defquota,
@@ -2252,6 +2270,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':relay_unknown_only' => $relay_unknown_only,
':backupmx' => $backupmx,
':gal' => $gal,
+ ':xmpp' => $xmpp,
+ ':xmpp_prefix' => $xmpp_prefix,
':active' => $active,
':quota' => $quota,
':defquota' => $defquota,
@@ -2300,6 +2320,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
(int)$imap_access = (isset($_data['imap_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']);
(int)$pop3_access = (isset($_data['pop3_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']);
(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)$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'];
@@ -2587,6 +2609,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access),
`attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access),
`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`, '$.smtp_access', :smtp_access)
WHERE `username` = :username");
$stmt->execute(array(
@@ -2598,6 +2622,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':imap_access' => $imap_access,
':pop3_access' => $pop3_access,
':smtp_access' => $smtp_access,
+ ':xmpp_admin' => $xmpp_admin,
+ ':xmpp_access' => $xmpp_access,
':username' => $username
));
$_SESSION['return'][] = array(
@@ -3353,6 +3379,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`relay_unknown_only`,
`backupmx`,
`gal`,
+ `xmpp`,
+ `xmpp_prefix`,
`active`
FROM `domain` WHERE `domain`= :domain");
$stmt->execute(array(
@@ -3411,6 +3439,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$domaindata['backupmx'] = $row['backupmx'];
$domaindata['backupmx_int'] = $row['backupmx'];
$domaindata['gal'] = $row['gal'];
+ $domaindata['xmpp'] = $row['xmpp'];
+ $domaindata['xmpp_prefix'] = $row['xmpp_prefix'];
$domaindata['gal_int'] = $row['gal'];
$domaindata['rl'] = $rl;
$domaindata['active'] = $row['active'];
@@ -3469,6 +3499,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`mailbox`.`domain`,
`mailbox`.`local_part`,
`mailbox`.`quota`,
+ `domain`.`xmpp` AS `domain_xmpp`,
+ `domain`.`xmpp_prefix` AS `domain_xmpp_prefix`,
`quota2`.`bytes`,
`attributes`,
`quota2`.`messages`
@@ -3484,6 +3516,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`mailbox`.`domain`,
`mailbox`.`local_part`,
`mailbox`.`quota`,
+ `domain`.`xmpp` AS `domain_xmpp`,
+ `domain`.`xmpp_prefix` AS `domain_xmpp_prefix`,
`quota2replica`.`bytes`,
`attributes`,
`quota2replica`.`messages`
@@ -3527,6 +3561,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$mailboxdata['active'] = $row['active'];
$mailboxdata['active_int'] = $row['active'];
$mailboxdata['domain'] = $row['domain'];
+ $mailboxdata['domain_xmpp'] = $row['domain_xmpp'];
+ $mailboxdata['domain_xmpp_prefix'] = $row['domain_xmpp_prefix'];
$mailboxdata['local_part'] = $row['local_part'];
$mailboxdata['quota'] = $row['quota'];
$mailboxdata['attributes'] = json_decode($row['attributes'], true);
@@ -4268,5 +4304,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
}
if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'mailbox', 'resource'))) {
update_sogo_static_view();
+ xmpp_rebuild_configs();
}
}
diff --git a/data/web/inc/functions.xmpp.inc.php b/data/web/inc/functions.xmpp.inc.php
new file mode 100644
index 00000000..c6c5133d
--- /dev/null
+++ b/data/web/inc/functions.xmpp.inc.php
@@ -0,0 +1,208 @@
+ 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data_log),
+ 'msg' => 'xmpp_reloaded'
+ );
+ }
+ else {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data_log),
+ 'msg' => 'xmpp_reload_failed'
+ );
+ }
+ break;
+ case 'restart':
+ $curl = curl_init();
+ curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ curl_setopt($curl, CURLOPT_URL, 'https://ejabberd:5443/api/restart');
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+ $response = curl_exec($curl);
+ curl_close($curl);
+
+ if ($response === "0") {
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data_log),
+ 'msg' => 'xmpp_restarted'
+ );
+ }
+ else {
+ // If no host is available, the container might be in sleeping state, we need to restart the container
+ $response = json_decode(docker('post', 'ejabberd-mailcow', 'restart'), true);
+ if (isset($response['type']) && $response['type'] == "success") {
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data_log),
+ 'msg' => 'xmpp_restarted'
+ );
+ }
+ else {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data_log),
+ 'msg' => 'xmpp_restart_failed'
+ );
+ }
+ }
+ break;
+ case 'status':
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data_log),
+ 'msg' => 'access_denied'
+ );
+ return false;
+ }
+ foreach (array(
+ 'onlineusers' => 'stats?name=onlineusers',
+ 'uptimeseconds' => 'stats?name=uptimeseconds',
+ 'muc_online_rooms' => 'muc_online_rooms?service=global'
+ ) as $stat => $url) {
+ $curl = curl_init();
+ curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ curl_setopt($curl, CURLOPT_URL, 'https://ejabberd:5443/api/' . $url);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+ $response_json = json_decode(curl_exec($curl), true);
+ if (isset($response_json['stat'])) {
+ $response_data[$stat] = $response_json['stat'];
+ }
+ else {
+ $response_data[$stat] = $response_json;
+ }
+ curl_close($curl);
+ // Something went wrong
+ if ($response_data[$stat] === false) {
+ $response_data[$stat] = '?';
+ }
+ }
+ return $response_data;
+ break;
+ }
+}
+function xmpp_rebuild_configs() {
+ global $pdo;
+ global $lang;
+ $_data_log = $_data;
+
+ try {
+ $xmpp_domains = array();
+ $stmt = $pdo->query('SELECT CONCAT(`xmpp_prefix`, ".", `domain`) AS `xmpp_host`, `domain` FROM `domain` WHERE `xmpp` = 1');
+ $xmpp_domain_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+ foreach ($xmpp_domain_rows as $xmpp_domain_row) {
+ $xmpp_domains[$xmpp_domain_row['domain']] = array('xmpp_host' => $xmpp_domain_row['xmpp_host']);
+ $stmt = $pdo->query('SELECT CONCAT(`local_part`, "@", CONCAT(`domain`.`xmpp_prefix`, ".", `domain`.`domain`)) AS `xmpp_username` FROM `mailbox`
+ JOIN `domain`
+ WHERE `domain`.`xmpp` = 1
+ AND JSON_VALUE(`attributes`, "$.xmpp_admin") = 1');
+ $xmpp_admin_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ foreach ($xmpp_admin_rows as $xmpp_admin_row) {
+ $xmpp_domains[$xmpp_domain_row['domain']]['xmpp_admins'][] = $xmpp_admin_row['xmpp_username'];
+ }
+ }
+
+ touch('/ejabberd/ejabberd_hosts.yml');
+ touch('/ejabberd/ejabberd_acl.yml');
+ $ejabberd_hosts_md5 = md5_file('/ejabberd/ejabberd_hosts.yml');
+ $ejabberd_acl_md5 = md5_file('/ejabberd/ejabberd_acl.yml');
+
+ if (!empty($xmpp_domains)) {
+ // Handle hosts file
+ $map_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
+ if (!$map_handle) {
+ throw new Exception($lang['danger']['file_open_error']);
+ }
+ fwrite($map_handle, '# Autogenerated by mailcow' . PHP_EOL);
+ fwrite($map_handle, 'hosts:' . PHP_EOL);
+ foreach ($xmpp_domains as $domain => $domain_values) {
+ fwrite($map_handle, ' - ' . $xmpp_domains[$domain]['xmpp_host'] . PHP_EOL);
+ }
+ fclose($map_handle);
+
+ // Handle ACL file
+ $map_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
+ if (!$map_handle) {
+ throw new Exception($lang['danger']['file_open_error']);
+ }
+ fwrite($map_handle, '# Autogenerated by mailcow' . PHP_EOL);
+ fwrite($map_handle, 'append_host_config:' . PHP_EOL);
+ foreach ($xmpp_domains as $domain => $domain_values) {
+ fwrite($map_handle, ' ' . $xmpp_domains[$domain]['xmpp_host'] . ':' . PHP_EOL);
+ fwrite($map_handle, ' acl:' . PHP_EOL);
+ fwrite($map_handle, ' admin:' . PHP_EOL);
+ fwrite($map_handle, ' user:' . PHP_EOL);
+ foreach ($xmpp_domains[$domain]['xmpp_admins'] as $xmpp_admin) {
+ fwrite($map_handle, ' - ' . $xmpp_admin . PHP_EOL);
+ }
+ }
+ fclose($map_handle);
+ }
+ else {
+ // Write empty hosts file
+ $map_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
+ if (!$map_handle) {
+ throw new Exception($lang['danger']['file_open_error']);
+ }
+ fwrite($map_handle, '# Autogenerated by mailcow' . PHP_EOL);
+ fclose($map_handle);
+ // Write empty ACL file
+ $map_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
+ if (!$map_handle) {
+ throw new Exception($lang['danger']['file_open_error']);
+ }
+ fwrite($map_handle, '# Autogenerated by mailcow' . PHP_EOL);
+ fclose($map_handle);
+ }
+
+ if (md5_file('/ejabberd/ejabberd_acl.yml') != $ejabberd_acl_md5) {
+ xmpp_control('restart');
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data_log),
+ 'msg' => 'xmpp_maps_updated'
+ );
+ }
+ elseif (md5_file('/ejabberd/ejabberd_hosts.yml') != $ejabberd_hosts_md5) {
+ xmpp_control('reload');
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data_log),
+ 'msg' => 'xmpp_maps_updated'
+ );
+ }
+
+ }
+ catch (Exception $e) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data_log),
+ 'msg' => array('xmpp_map_write_error', htmlspecialchars($e->getMessage()))
+ );
+ }
+}
+
diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php
index 8010bbdd..a789182c 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 = "28112020_1210";
+ $db_version = "08022021_1000";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -240,6 +240,8 @@ function init_db_schema() {
"gal" => "TINYINT(1) NOT NULL DEFAULT '1'",
"relay_all_recipients" => "TINYINT(1) NOT NULL DEFAULT '0'",
"relay_unknown_only" => "TINYINT(1) NOT NULL DEFAULT '0'",
+ "xmpp" => "TINYINT(1) NOT NULL DEFAULT '0'",
+ "xmpp_prefix" => "VARCHAR(255) DEFAULT 'im'",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
@@ -567,6 +569,10 @@ 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'",
+ "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'",
+ "xmpp_admin" => "TINYINT(1) NOT NULL DEFAULT '0'",
"domain_desc" => "TINYINT(1) NOT NULL DEFAULT '0'"
),
"keys" => array(
@@ -1179,6 +1185,8 @@ 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`, '$.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;");
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.sogo_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.sogo_access') IS NULL;");
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.imap_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.imap_access') IS NULL;");
@@ -1226,6 +1234,7 @@ function init_db_schema() {
}
if (php_sapi_name() == "cli") {
include '/web/inc/vars.inc.php';
+ include '/web/inc/functions.xmpp.inc.php';
// $now = new DateTime();
// $mins = $now->getOffset() / 60;
// $sgn = ($mins < 0 ? -1 : 1);
@@ -1264,5 +1273,7 @@ if (php_sapi_name() == "cli") {
catch ( Exception $e ) {
// Dunno
}
+ xmpp_rebuild_configs();
+ echo "Rebuilt XMPP configuration". PHP_EOL;
init_db_schema();
}
diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php
index 220c87cb..3b22e439 100644
--- a/data/web/inc/prerequisites.inc.php
+++ b/data/web/inc/prerequisites.inc.php
@@ -234,27 +234,28 @@ if(file_exists($langFile)) {
}
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.acl.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.app_passwd.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.customize.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.address_rewriting.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.domain_admin.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.admin.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.quarantine.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.quota_notification.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.app_passwd.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.customize.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.docker.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.domain_admin.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fail2ban.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fwdhost.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailq.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.oauth2.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.presets.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.pushover.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.quarantine.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.quota_notification.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.ratelimit.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.transports.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.rspamd.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.tls_policy_maps.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fail2ban.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.docker.inc.php';
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.presets.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.transports.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.xmpp.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/init_db.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/triggers.inc.php';
init_db_schema();
diff --git a/data/web/inc/spf.inc.php b/data/web/inc/spf.inc.php
index 199f572a..a3abcbe4 100644
--- a/data/web/inc/spf.inc.php
+++ b/data/web/inc/spf.inc.php
@@ -1,8 +1,6 @@
");
+ try {
+ item.message = atob(item.message.slice(7)).replace(/\\n/g, "
");
+ } catch(e) {
+ item.message = item.message.slice(7);
+ }
} else {
item.message = escapeHtml(item.message);
}
diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js
index 68a5ad45..ace75d49 100644
--- a/data/web/js/site/mailbox.js
+++ b/data/web/js/site/mailbox.js
@@ -256,6 +256,7 @@ jQuery(function($){
{"name":"rl","title":"RL","breakpoints":"xs sm md lg","style":{"maxWidth":"100px","width":"100px"}},
{"name":"backupmx","filterable": false,"style":{"maxWidth":"120px","width":"120px"},"title":lang.backup_mx,"breakpoints":"xs sm md lg","formatter": function(value){return 1==value?'✓':0==value&&'✕';}},
{"name":"domain_admins","title":lang.domain_admins,"style":{"word-break":"break-all","min-width":"200px"},"breakpoints":"xs sm md lg","filterable":(role == "admin"),"visible":(role == "admin")},
+ {"name":"xmpp","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":"XMPP","formatter": function(value){return 1==value?'✓':0==value&&'✕';}},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'✓':0==value&&'✕';}},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"240px","width":"240px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
],
diff --git a/data/web/lang/lang.cs.json b/data/web/lang/lang.cs.json
index dccdc22d..7e830279 100644
--- a/data/web/lang/lang.cs.json
+++ b/data/web/lang/lang.cs.json
@@ -435,12 +435,12 @@
"logs": "Logy",
"restart_container": "Restartovat",
"solr_dead": "Solr se spouští, je vypnutý nebo spadl.",
- "solr_docs": "Dokumentace",
- "solr_last_modified": "Naposledy změněn",
- "solr_size": "Velikost",
- "solr_started_at": "Spuštěn",
+ "docs": "Dokumentace",
+ "last_modified": "Naposledy změněn",
+ "size": "Velikost",
+ "started_at": "Spuštěn",
"solr_status": "Stav Solr",
- "solr_uptime": "Doba běhu",
+ "uptime": "Doba běhu",
"started_on": "Spuštěno",
"static_logs": "Statické logy",
"system_containers": "Systém a kontejnery"
diff --git a/data/web/lang/lang.de.json b/data/web/lang/lang.de.json
index 8f909226..3a5b9320 100644
--- a/data/web/lang/lang.de.json
+++ b/data/web/lang/lang.de.json
@@ -26,7 +26,10 @@
"syncjobs": "Sync Jobs",
"tls_policy": "Verschlüsselungsrichtlinie",
"unlimited_quota": "Unendliche Quota für Mailboxen",
- "domain_desc": "Domainbeschreibung ändern"
+ "domain_desc": "Domainbeschreibung ändern",
+ "xmpp_admin": "Benutzer zum XMPP-Administrator ernennen",
+ "xmpp_access": "XMPP-Zugang eines Benutzers einstellen",
+ "xmpp_prefix": "XMPP-Subdomain ändern"
},
"add": {
"activate_filter_warn": "Alle anderen Filter diesen Typs werden deaktiviert, falls dieses Script aktiv markiert wird.",
@@ -59,6 +62,14 @@
"full_name": "Vor- und Nachname",
"gal": "Globales Adressbuch",
"gal_info": "Das globale Adressbuch enthält alle Objekte einer Domain und kann durch keinen Benutzer geändert werden. Die Verfügbarkeitsinformation in SOGo ist nur bei eingeschaltetem globalen Adressbuch ersichtlich!
Zum Anwenden einer Änderung muss SOGo neugestartet werden.",
+ "xmpp": "XMPP für diese Domain aktivieren",
+ "xmpp_prefix": "XMPP-Prefix für Domain (\"im\" für
im.example.org)",
+ "xmpp_prefix_info": "Für die Bereitstellung eines Zertifikates sollte vorab ein DNS-Eintrag, etwa in Form eines CNAMEs, für
im.example.org sowie
*.im.example.org auf
%s zeigend angelegt werden. Im Anschluss an die Aktivierung sollte der DNS-Check für diese Domain ausgeführt werden.",
+ "xmpp_info": "Diese Funktion stellt eine Chat-Funktionalität für die Domain bereit.",
+ "xmpp_access": "XMPP Zugang",
+ "xmpp_access_info": "XMPP muss für diese Domain aktiviert sein.",
+ "xmpp_admin": "XMPP Administrator",
+ "xmpp_admin_info": "
Vorsicht: Ernennt den Benutzer zum Administrator der jeweiligen XMPP Domain.",
"generate": "generieren",
"goto_ham": "Nachrichten als
Ham lernen",
"goto_null": "Nachrichten sofort verwerfen",
@@ -350,6 +361,7 @@
"global_filter_write_error": "Kann Filterdatei nicht schreiben: %s",
"global_map_invalid": "Rspamd Map %s ist ungültig",
"global_map_write_error": "Kann globale Map ID %s nicht schreiben: %s",
+ "xmpp_map_write_error": "Kann XMPP Map nicht schreiben: %s",
"goto_empty": "Eine Alias-Adresse muss auf mindestens eine gütlige Ziel-Adresse zeigen",
"goto_invalid": "Ziel-Adresse %s ist ungültig",
"ham_learn_error": "Ham Lernfehler: %s",
@@ -434,7 +446,9 @@
"username_invalid": "Benutzername %s kann nicht verwendet werden",
"validity_missing": "Bitte geben Sie eine Gültigkeitsdauer an",
"value_missing": "Bitte alle Felder ausfüllen",
- "yotp_verification_failed": "Yubico OTP-Verifizierung fehlgeschlagen: %s"
+ "yotp_verification_failed": "Yubico OTP-Verifizierung fehlgeschlagen: %s",
+ "xmpp_restart_failed": "XMPP konnte nicht neu gestartet werden",
+ "xmpp_reload_failed": "XMPP konnte nicht neu geladen werden"
},
"debug": {
"chart_this_server": "Chart (dieser Server)",
@@ -448,15 +462,18 @@
"logs": "Protokolle",
"restart_container": "Neustart",
"solr_dead": "Solr startet, ist deaktiviert oder temporär nicht erreichbar.",
- "solr_docs": "Dokumente",
- "solr_last_modified": "Zuletzt geändert",
- "solr_size": "Größe",
- "solr_started_at": "Gestartet am",
+ "xmpp_dead": "XMPP startet, ist deaktiviert oder temporär nicht erreichbar.",
+ "docs": "Dokumente",
+ "last_modified": "Zuletzt geändert",
+ "online_users": "Benutzer online",
+ "size": "Größe",
+ "started_at": "Gestartet am",
"solr_status": "Solr Status",
- "solr_uptime": "Uptime",
+ "uptime": "Uptime",
"started_on": "Gestartet am",
"static_logs": "Statische Logs",
- "system_containers": "System & Container"
+ "system_containers": "System & Container",
+ "xmpp_status": "XMPP Status"
},
"diagnostics": {
"cname_from_a": "Wert abgeleitet von A/AAAA-Eintrag. Wird unterstützt, sofern der Eintrag auf die korrekte Ressource zeigt.",
@@ -505,6 +522,14 @@
"full_name": "Voller Name",
"gal": "Globales Adressbuch",
"gal_info": "Das globale Adressbuch enthält alle Objekte einer Domain und kann durch keinen Benutzer geändert werden. Die Verfügbarkeitsinformation in SOGo ist nur bei eingeschaltetem globalen Adressbuch ersichtlich
Zum Anwenden einer Änderung muss SOGo neugestartet werden.",
+ "xmpp": "XMPP für diese Domain aktivieren",
+ "xmpp_prefix": "XMPP-Prefix für Domain (\"im\" für
im.example.org)",
+ "xmpp_prefix_info": "Für die Bereitstellung eines Zertifikates sollte vorab ein DNS-Eintrag, etwa in Form eines CNAMEs, für
im.example.org sowie
*.im.example.org auf
%s zeigend angelegt werden. Im Anschluss an die Aktivierung sollte der DNS-Check für diese Domain ausgeführt werden.",
+ "xmpp_info": "Diese Funktion stellt eine Chat-Funktionalität für die Domain bereit.",
+ "xmpp_access": "XMPP Zugang",
+ "xmpp_access_info": "XMPP muss für diese Domain aktiviert sein.",
+ "xmpp_admin": "XMPP Administrator",
+ "xmpp_admin_info": "
Vorsicht: Ernennt den Benutzer zum Administrator der jeweiligen XMPP Domain.",
"generate": "generieren",
"grant_types": "Grant types",
"hostname": "Servername",
@@ -536,6 +561,7 @@
"pushover_vars": "Wenn kein Sender-Filter definiert ist, werden alle E-Mails berücksichtigt.
Die direkte Absenderprüfung und reguläre Ausdrücke werden unabhängig voneinander geprüft, sie
hängen nicht voneinander ab und werden der Reihe nach ausgeführt.
Verwendbare Variablen für Titel und Text (Datenschutzrichtlinien beachten)",
"pushover_verify": "Verbindung verifizieren",
"quota_mb": "Speicherplatz (MiB)",
+ "ratelimit": "Rate Limit",
"redirect_uri": "Redirect/Callback-URL",
"relay_all": "Alle Empfänger-Adressen relayen",
"relay_all_info": "↪ Wenn
nicht alle Empfänger-Adressen relayt werden sollen, müssen \"blinde\" Mailboxen für jede Adresse, die relayt werden soll, erstellen werden.",
@@ -558,6 +584,7 @@
"sogo_visible": "Alias in SOGo sichtbar",
"sogo_visible_info": "Diese Option hat lediglich Einfluss auf Objekte, die in SOGo darstellbar sind (geteilte oder nicht-geteilte Alias-Adressen mit dem Ziel mindestens einer lokalen Mailbox).",
"spam_alias": "Anpassen temporärer Alias-Adressen",
+ "spam_filter": "Spamfilter",
"spam_policy": "Hinzufügen und Entfernen von Einträgen in White- und Blacklists",
"spam_score": "Einen benutzerdefiniterten Spam-Score festlegen",
"subfolder2": "Ziel-Ordner
(leer = kein Unterordner)",
@@ -891,7 +918,10 @@
"verified_totp_login": "TOTP-Anmeldung verifiziert",
"verified_u2f_login": "U2F-Anmeldung verifiziert",
"verified_fido2_login": "FIDO2-Anmeldung verifiziert",
- "verified_yotp_login": "Yubico OTP-Anmeldung verifiziert"
+ "verified_yotp_login": "Yubico OTP-Anmeldung verifiziert",
+ "xmpp_restarted": "XMPP-Dienst wurde neu gestartet",
+ "xmpp_reloaded": "XMPP-Dienst wurde neu geladen",
+ "xmpp_maps_updated": "XMPP-Maps wurden aktualisiert"
},
"tfa": {
"api_register": "%s verwendet die Yubico Cloud API. Ein API-Key für den Yubico Stick kann
hier bezogen werden.",
diff --git a/data/web/lang/lang.en.json b/data/web/lang/lang.en.json
index 3e1826e9..41458e1f 100644
--- a/data/web/lang/lang.en.json
+++ b/data/web/lang/lang.en.json
@@ -26,7 +26,10 @@
"syncjobs": "Sync jobs",
"tls_policy": "TLS policy",
"unlimited_quota": "Unlimited quota for mailboxes",
- "domain_desc": "Change domain description"
+ "domain_desc": "Change domain description",
+ "xmpp_admin": "Change XMPP admin status of a user",
+ "xmpp_access": "Change XMPP access for a user",
+ "xmpp_prefix": "Change XMPP subdomain"
},
"add": {
"activate_filter_warn": "All other filters will be deactivated, when active is checked.",
@@ -59,6 +62,12 @@
"full_name": "Full name",
"gal": "Global Address List",
"gal_info": "The GAL contains all objects of a domain and cannot be edited by any user. Free/busy information in SOGo is missing, if disabled!
Restart SOGo to apply changes.",
+ "xmpp": "Activate XMPP for this domain",
+ "xmpp_info": "This function will enable chat functionality for this domain.",
+ "xmpp_access": "XMPP access",
+ "xmpp_access_info": "XMPP must be enabled for this domain.",
+ "xmpp_admin": "XMPP administrator",
+ "xmpp_admin_info": "
Danger: Promotes a user to an XMPP administrator of this domain.",
"generate": "generate",
"goto_ham": "Learn as
ham",
"goto_null": "Silently discard mail",
@@ -353,6 +362,7 @@
"global_filter_write_error": "Could not write filter file: %s",
"global_map_invalid": "Global map ID %s invalid",
"global_map_write_error": "Could not write global map ID %s: %s",
+ "xmpp_map_write_error": "Could not write XMPP map: %s",
"goto_empty": "An alias address must contain at least one valid goto address",
"goto_invalid": "Goto address %s is invalid",
"ham_learn_error": "Ham learn error: %s",
@@ -437,7 +447,9 @@
"username_invalid": "Username %s cannot be used",
"validity_missing": "Please assign a period of validity",
"value_missing": "Please provide all values",
- "yotp_verification_failed": "Yubico OTP verification failed: %s"
+ "yotp_verification_failed": "Yubico OTP verification failed: %s",
+ "xmpp_restart_failed": "XMPP could not be restarted",
+ "xmpp_reload_failed": "XMPP could not be reloaded"
},
"debug": {
"chart_this_server": "Chart (this server)",
@@ -451,15 +463,18 @@
"logs": "Logs",
"restart_container": "Restart",
"solr_dead": "Solr is starting, disabled or died.",
- "solr_docs": "Docs",
- "solr_last_modified": "Last modified",
- "solr_size": "Size",
- "solr_started_at": "Started at",
+ "xmpp_dead": "XMPP is starting, disabled or died.",
+ "docs": "Docs",
+ "last_modified": "Last modified",
+ "online_users": "Users online",
+ "size": "Size",
+ "started_at": "Started at",
"solr_status": "Solr status",
- "solr_uptime": "Uptime",
+ "uptime": "Uptime",
"started_on": "Started on",
"static_logs": "Static logs",
- "system_containers": "System & Containers"
+ "system_containers": "System & Containers",
+ "xmpp_status": "XMPP status"
},
"diagnostics": {
"cname_from_a": "Value derived from A/AAAA record. This is supported as long as the record points to the correct resource.",
@@ -508,6 +523,14 @@
"full_name": "Full name",
"gal": "Global Address List",
"gal_info": "The GAL contains all objects of a domain and cannot be edited by any user. Free/busy information in SOGo is missing, if disabled!
Restart SOGo to apply changes.",
+ "xmpp": "Activate XMPP for this domain",
+ "xmpp_prefix": "XMPP prefix for domain (\"im\" to use
im.example.org)",
+ "xmpp_prefix_info": "To request certificates for XMPP, two CNAME DNS records should point from
im.example.org as well as
*.im.example.org to
%s. Please also run the DNS check for this domain after enabling XMPP.",
+ "xmpp_info": "This function will enable chat functionality for this domain.",
+ "xmpp_access": "XMPP access",
+ "xmpp_access_info": "XMPP must be enabled for this domain.",
+ "xmpp_admin": "XMPP administrator",
+ "xmpp_admin_info": "
Danger: Promotes a user to an XMPP administrator of this domain.",
"generate": "generate",
"grant_types": "Grant types",
"hostname": "Hostname",
@@ -539,6 +562,7 @@
"pushover_vars": "When no sender filter is defined, all mails will be considered.
Regex filters as well as exact sender checks can be defined individually and will be considered sequentially. They do not depend on each other.
Useable variables for text and title (please take note of data protection policies)",
"pushover_verify": "Verify credentials",
"quota_mb": "Quota (MiB)",
+ "ratelimit": "Rate limit",
"redirect_uri": "Redirect/Callback URL",
"relay_all": "Relay all recipients",
"relay_all_info": "↪ If you choose
not to relay all recipients, you will need to add a (\"blind\") mailbox for every single recipient that should be relayed.",
@@ -561,6 +585,7 @@
"sogo_visible": "Alias is visible in SOGo",
"sogo_visible_info": "This option only affects objects, that can be displayed in SOGo (shared or non-shared alias addresses pointing to at least one local mailbox). If hidden, an alias will not appear as selectable sender in SOGo.",
"spam_alias": "Create or change time limited alias addresses",
+ "spam_filter": "Spam filter",
"spam_policy": "Add or remove items to white-/blacklist",
"spam_score": "Set a custom spam score",
"subfolder2": "Sync into subfolder on destination
(empty = do not use subfolder)",
@@ -894,7 +919,10 @@
"verified_totp_login": "Verified TOTP login",
"verified_u2f_login": "Verified U2F login",
"verified_fido2_login": "Verified FIDO2 login",
- "verified_yotp_login": "Verified Yubico OTP login"
+ "verified_yotp_login": "Verified Yubico OTP login",
+ "xmpp_restarted": "XMPP service was restarted",
+ "xmpp_reloaded": "XMPP service was reloaded",
+ "xmpp_maps_updated": "XMPP maps were updated"
},
"tfa": {
"api_register": "%s uses the Yubico Cloud API. Please get an API key for your key
here",
diff --git a/data/web/lang/lang.es.json b/data/web/lang/lang.es.json
index 4e78b6fb..83a77460 100644
--- a/data/web/lang/lang.es.json
+++ b/data/web/lang/lang.es.json
@@ -344,12 +344,12 @@
"logs": "Logs",
"restart_container": "Reiniciar",
"solr_dead": "Solr está empezando, deshabilitado o caído.",
- "solr_docs": "Docs",
- "solr_last_modified": "Última modificación",
- "solr_size": "Tamaño",
- "solr_started_at": "Iniciado el",
+ "docs": "Docs",
+ "last_modified": "Última modificación",
+ "size": "Tamaño",
+ "started_at": "Iniciado el",
"solr_status": "Solr status",
- "solr_uptime": "Uptime",
+ "uptime": "Uptime",
"static_logs": "Logs estáticos",
"system_containers": "Sistema y Contenedores"
},
diff --git a/data/web/lang/lang.fi.json b/data/web/lang/lang.fi.json
index f7624018..ea623b55 100644
--- a/data/web/lang/lang.fi.json
+++ b/data/web/lang/lang.fi.json
@@ -389,12 +389,12 @@
"logs": "Logit tausta palveluista",
"restart_container": "Uudelleen käynnistä",
"solr_dead": "Solr käynnistyy, on poissa käytöstä tai kuoli.",
- "solr_docs": "Docs",
- "solr_last_modified": "Viimeksi muokattu",
- "solr_size": "Koko",
- "solr_started_at": "Käynnistetty",
+ "docs": "Docs",
+ "last_modified": "Viimeksi muokattu",
+ "size": "Koko",
+ "started_at": "Käynnistetty",
"solr_status": "Solr-tila",
- "solr_uptime": "Päällä",
+ "uptime": "Päällä",
"started_on": "Aloitettiin",
"static_logs": "Staattiset lokit",
"system_containers": "Systeemi & Säiliöt"
diff --git a/data/web/lang/lang.fr.json b/data/web/lang/lang.fr.json
index 94f86570..9c267130 100644
--- a/data/web/lang/lang.fr.json
+++ b/data/web/lang/lang.fr.json
@@ -438,12 +438,12 @@
"logs": "Logs",
"restart_container": "Redémarrer",
"solr_dead": "Solr est en cours de démarrage, désactivé ou mort.",
- "solr_docs": "Docs",
- "solr_last_modified": "Dernière modification",
- "solr_size": "Taille",
- "solr_started_at": "Démarré à",
+ "docs": "Docs",
+ "last_modified": "Dernière modification",
+ "size": "Taille",
+ "started_at": "Démarré à",
"solr_status": "Etat Solr",
- "solr_uptime": "Disponibilité",
+ "uptime": "Disponibilité",
"started_on": "Démarré à",
"static_logs": "Logs statiques",
"system_containers": "Système & Conteneurs"
diff --git a/data/web/lang/lang.ko.json b/data/web/lang/lang.ko.json
index 59be6833..a208d416 100644
--- a/data/web/lang/lang.ko.json
+++ b/data/web/lang/lang.ko.json
@@ -438,12 +438,12 @@
"logs": "Logs",
"restart_container": "Restart",
"solr_dead": "Solr is starting, disabled or died.",
- "solr_docs": "Docs",
- "solr_last_modified": "Last modified",
- "solr_size": "Size",
- "solr_started_at": "Started at",
+ "docs": "Docs",
+ "last_modified": "Last modified",
+ "size": "Size",
+ "started_at": "Started at",
"solr_status": "Solr status",
- "solr_uptime": "Uptime",
+ "uptime": "Uptime",
"started_on": "Started on",
"static_logs": "Static logs",
"system_containers": "System & Containers"
diff --git a/data/web/lang/lang.nl.json b/data/web/lang/lang.nl.json
index 053e109c..942d835d 100644
--- a/data/web/lang/lang.nl.json
+++ b/data/web/lang/lang.nl.json
@@ -449,12 +449,12 @@
"logs": "Logs",
"restart_container": "Herstart",
"solr_dead": "Solr is uitgeschakeld, uitgevallen of nog bezig met opstarten.",
- "solr_docs": "Documenten",
- "solr_last_modified": "Voor het laatst bijgewerkt op",
- "solr_size": "Grootte",
- "solr_started_at": "Opgestart op",
+ "docs": "Documenten",
+ "last_modified": "Voor het laatst bijgewerkt op",
+ "size": "Grootte",
+ "started_at": "Opgestart op",
"solr_status": "Status van Solr",
- "solr_uptime": "Uptime",
+ "uptime": "Uptime",
"started_on": "Gestart op",
"static_logs": "Statische logs",
"system_containers": "Systeem & containers"
diff --git a/data/web/lang/lang.ro.json b/data/web/lang/lang.ro.json
index 21af2911..628bf8d8 100644
--- a/data/web/lang/lang.ro.json
+++ b/data/web/lang/lang.ro.json
@@ -451,12 +451,12 @@
"logs": "Jurnale",
"restart_container": "Repornire",
"solr_dead": "Solr începe, este invalid sau s-a oprit.",
- "solr_docs": "Documente",
- "solr_last_modified": "Ultima modificare",
- "solr_size": "Mărime",
- "solr_started_at": "Pornit la",
+ "docs": "Documente",
+ "last_modified": "Ultima modificare",
+ "size": "Mărime",
+ "started_at": "Pornit la",
"solr_status": "Stare Solr",
- "solr_uptime": "Timp de funcționare",
+ "uptime": "Timp de funcționare",
"started_on": "Început pe",
"static_logs": "Jurnale statice",
"system_containers": "Sistem și Containere"
diff --git a/data/web/lang/lang.ru.json b/data/web/lang/lang.ru.json
index 3eba3443..e841baee 100644
--- a/data/web/lang/lang.ru.json
+++ b/data/web/lang/lang.ru.json
@@ -451,12 +451,12 @@
"logs": "Журналы",
"restart_container": "Перезапустить",
"solr_dead": "Solr не запущен. Если вы включили Solf в файле настроек
mailcow.conf
и это сообщение отображает более получаса, скорее всего Solr сломан.",
- "solr_docs": "Проиндексировано обьектов",
- "solr_last_modified": "Последние изменения",
- "solr_size": "Индексы занимают",
- "solr_started_at": "Запущен",
+ "docs": "Проиндексировано обьектов",
+ "last_modified": "Последние изменения",
+ "size": "Индексы занимают",
+ "started_at": "Запущен",
"solr_status": "Состояние Solr",
- "solr_uptime": "Время работы",
+ "uptime": "Время работы",
"started_on": "Запущен в",
"static_logs": "Статические журналы",
"system_containers": "Система и контейнеры"
diff --git a/data/web/lang/lang.sk.json b/data/web/lang/lang.sk.json
index 5cfda734..fe1f4c8c 100644
--- a/data/web/lang/lang.sk.json
+++ b/data/web/lang/lang.sk.json
@@ -448,12 +448,12 @@
"logs": "Správy",
"restart_container": "Reštartovať",
"solr_dead": "Solr štartuje, bol vypnutý alebo zlyhal.",
- "solr_docs": "Dokumenty",
- "solr_last_modified": "Naposledy upravené",
- "solr_size": "Veľkosť",
- "solr_started_at": "Spustený",
+ "docs": "Dokumenty",
+ "last_modified": "Naposledy upravené",
+ "size": "Veľkosť",
+ "started_at": "Spustený",
"solr_status": "Solr status",
- "solr_uptime": "Doba behu",
+ "uptime": "Doba behu",
"started_on": "Spustený",
"static_logs": "Statické správy",
"system_containers": "Systém & Kontajnery"
diff --git a/data/web/lang/lang.sv.json b/data/web/lang/lang.sv.json
index e123028d..3861ee2b 100644
--- a/data/web/lang/lang.sv.json
+++ b/data/web/lang/lang.sv.json
@@ -448,12 +448,12 @@
"logs": "Loggar",
"restart_container": "Omstart",
"solr_dead": "Solr är i uppstart, har inaktiveras eller är tillfälligt avstängd.",
- "solr_docs": "Dokumentation",
- "solr_last_modified": "Senast ändrad",
- "solr_size": "Storlek",
- "solr_started_at": "Startades kl.",
+ "docs": "Dokumentation",
+ "last_modified": "Senast ändrad",
+ "size": "Storlek",
+ "started_at": "Startades kl.",
"solr_status": "Solr status",
- "solr_uptime": "Upptid",
+ "uptime": "Upptid",
"started_on": "Startades",
"static_logs": "Statiska loggar",
"system_containers": "System & behållare"
diff --git a/data/web/lang/lang.zh.json b/data/web/lang/lang.zh.json
index 00fecef9..56eadc2e 100644
--- a/data/web/lang/lang.zh.json
+++ b/data/web/lang/lang.zh.json
@@ -445,12 +445,12 @@
"logs": "日志",
"restart_container": "重启",
"solr_dead": "Solr在启动中、已关闭或已停止运行",
- "solr_docs": "文档",
- "solr_last_modified": "最后修改",
- "solr_size": "大小",
- "solr_started_at": "开始于",
+ "docs": "文档",
+ "last_modified": "最后修改",
+ "size": "大小",
+ "started_at": "开始于",
"solr_status": "Solr状态",
- "solr_uptime": "运行时间",
+ "uptime": "运行时间",
"started_on": "启动于",
"static_logs": "静态日志",
"system_containers": "系统和容器"