[Postfix] Allow to set and override a relayhost per mailbox

[Web] Replace recycle icon with trash (this one made me a bit sad)
[Web] Various small fixes
[Web] Allow or disallow a domain admin to change relayhost settings (default is off, as previous default)
master
andryyy 2021-05-26 14:02:27 +02:00
parent 82f7df9165
commit 5065667ae4
No known key found for this signature in database
GPG Key ID: 8EC34FF2794E25EF
28 changed files with 150 additions and 89 deletions

View File

@ -125,16 +125,31 @@ query = SELECT GROUP_CONCAT(transport SEPARATOR '') AS transport_maps
AND mailbox.active = '1' AND mailbox.active = '1'
), 'smtp_enforced_tls:', 'smtp:') AS 'transport' ), 'smtp_enforced_tls:', 'smtp:') AS 'transport'
UNION ALL UNION ALL
SELECT hostname AS transport FROM relayhosts SELECT COALESCE(
(SELECT hostname FROM relayhosts
LEFT OUTER JOIN mailbox ON JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.relayhost')) = relayhosts.id
WHERE relayhosts.active = '1'
AND (
mailbox.username IN (SELECT alias.goto from alias
JOIN mailbox ON mailbox.username = alias.goto
WHERE alias.active = '1'
AND alias.address = '%s'
AND alias.address NOT LIKE '@%%'
)
)
),
(SELECT hostname FROM relayhosts
LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id
WHERE relayhosts.active = '1' WHERE relayhosts.active = '1'
AND domain = '%d' AND (domain.domain = '%d'
OR domain IN ( OR domain.domain IN (
SELECT target_domain FROM alias_domain SELECT target_domain FROM alias_domain
WHERE alias_domain = '%d' WHERE alias_domain = '%d'
)
) )
) )
AS transport_view; )
) AS transport_view;
EOF EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_transport_maps.cf cat <<EOF > /opt/postfix/conf/sql/mysql_transport_maps.cf

View File

@ -139,7 +139,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
<input type="hidden" name="unset_fido2_key" value="<?=$key_info['cid'];?>"> <input type="hidden" name="unset_fido2_key" value="<?=$key_info['cid'];?>">
<div class="btn-group"> <div class="btn-group">
<a href="#" class="btn btn-xs btn-default" data-cid="<?=$key_info['cid'];?>" data-subject="<?=base64_encode($key_info['subject']);?>" data-toggle="modal" data-target="#fido2ChangeFn"><i class="bi bi-pencil-fill"></i> <?=$lang['fido2']['rename'];?></a> <a href="#" class="btn btn-xs btn-default" data-cid="<?=$key_info['cid'];?>" data-subject="<?=base64_encode($key_info['subject']);?>" data-toggle="modal" data-target="#fido2ChangeFn"><i class="bi bi-pencil-fill"></i> <?=$lang['fido2']['rename'];?></a>
<a href="#" onClick='return confirm("<?=$lang['admin']['ays'];?>")?$(this).closest("form").submit():"";' class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> <?=$lang['admin']['remove'];?></a> <a href="#" onClick='return confirm("<?=$lang['admin']['ays'];?>")?$(this).closest("form").submit():"";' class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> <?=$lang['admin']['remove'];?></a>
</form> </form>
</div> </div>
</td> </td>
@ -618,7 +618,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
<div class="mass-actions-admin"> <div class="mass-actions-admin">
<div class="btn-group btn-group-sm"> <div class="btn-group btn-group-sm">
<button type="button" id="toggle_multi_select_all" data-id="dkim" class="btn btn-default"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></button> <button type="button" id="toggle_multi_select_all" data-id="dkim" class="btn btn-default"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></button>
<button type="button" data-action="delete_selected" name="delete_selected" data-id="dkim" data-api-url="delete/dkim" class="btn btn-danger"><i class="bi bi-recycle"></i> <?=$lang['admin']['remove'];?></button> <button type="button" data-action="delete_selected" name="delete_selected" data-id="dkim" data-api-url="delete/dkim" class="btn btn-danger"><i class="bi bi-trash"></i> <?=$lang['admin']['remove'];?></button>
</div> </div>
</div> </div>
@ -1402,7 +1402,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
data-api-url='edit/mailq' data-api-url='edit/mailq'
data-api-attr='{"action":"super_delete"}' data-api-attr='{"action":"super_delete"}'
data-toggle="tooltip" title="postsuper -d ALL" data-toggle="tooltip" title="postsuper -d ALL"
href="#"><i class="bi bi-recycle"></i> <?=$lang['admin']['delete_queue'];?></a> href="#"><i class="bi bi-trash"></i> <?=$lang['admin']['delete_queue'];?></a>
</div> </div>
</div> </div>
</div> </div>

View File

@ -76,7 +76,6 @@
font-size: inherit; font-size: inherit;
} }
.icon-spin { .icon-spin {
font-size: 1.0rem;
animation-name: spin; animation-name: spin;
animation-duration: 2000ms; animation-duration: 2000ms;
animation-iteration-count: infinite; animation-iteration-count: infinite;

View File

@ -40,4 +40,8 @@
.input-group-addon-xmpp { .input-group-addon-xmpp {
background-color: #fff; background-color: #fff;
border: 0px solid #fff; border: 0px solid #fff;
}
#sender_acl_disabled {
display:none;
margin-top:10px;
} }

View File

@ -281,6 +281,21 @@ if (isset($_SESSION['mailcow_cc_role'])) {
<input type="text" class="form-control" name="description" value="<?=htmlspecialchars($result['description']);?>"> <input type="text" class="form-control" name="description" value="<?=htmlspecialchars($result['description']);?>">
</div> </div>
</div> </div>
<div class="form-group">
<label class="control-label col-sm-2" for="relayhost"><?=$lang['edit']['relayhost'];?></label>
<div class="col-sm-10">
<select data-acl="<?=$_SESSION['acl']['domain_relayhost'];?>" data-live-search="true" id="relayhost" name="relayhost" class="form-control">
<?php
foreach ($rlyhosts as $rlyhost) {
?>
<option class="<?=($rlyhost['active'] == 1) ? '' : 'background: #ff4136; color: #fff';?>" value="<?=$rlyhost['id'];?>" <?=($result['relayhost'] == $rlyhost['id']) ? 'selected' : null;?>>ID <?=$rlyhost['id'];?>: <?=$rlyhost['hostname'];?> (<?=$rlyhost['username'];?>)</option>
<?php
}
?>
<option value="" <?=($result['relayhost'] == "0") ? 'selected' : null;?>>None</option>
</select>
</div>
</div>
<?php <?php
if ($_SESSION['mailcow_cc_role'] == "admin") { if ($_SESSION['mailcow_cc_role'] == "admin") {
?> ?>
@ -314,21 +329,6 @@ if (isset($_SESSION['mailcow_cc_role'])) {
<input type="number" class="form-control" name="quota" value="<?=intval($result['max_quota_for_domain'] / 1048576);?>"> <input type="number" class="form-control" name="quota" value="<?=intval($result['max_quota_for_domain'] / 1048576);?>">
</div> </div>
</div> </div>
<div class="form-group">
<label class="control-label col-sm-2" for="quota"><?=$lang['edit']['relayhost'];?></label>
<div class="col-sm-10">
<select data-live-search="true" name="relayhost" class="form-control">
<?php
foreach ($rlyhosts as $rlyhost) {
?>
<option value="<?=$rlyhost['id'];?>" <?=($result['relayhost'] == $rlyhost['id']) ? 'selected' : null;?>>ID <?=$rlyhost['id'];?>: <?=$rlyhost['hostname'];?> (<?=$rlyhost['username'];?>)</option>
<?php
}
?>
<option value="" <?=($result['relayhost'] == "0") ? 'selected' : null;?>>None</option>
</select>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-2"><?=$lang['edit']['backup_mx_options'];?></label> <label class="control-label col-sm-2"><?=$lang['edit']['backup_mx_options'];?></label>
<div class="col-sm-10"> <div class="col-sm-10">
@ -640,6 +640,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
$quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox); $quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox);
$quarantine_category = mailbox('get', 'quarantine_category', $mailbox); $quarantine_category = mailbox('get', 'quarantine_category', $mailbox);
$get_tls_policy = mailbox('get', 'tls_policy', $mailbox); $get_tls_policy = mailbox('get', 'tls_policy', $mailbox);
$rlyhosts = relayhost('get');
if (!empty($result)) { if (!empty($result)) {
?> ?>
<h4><?=$lang['edit']['mailbox'];?></h4> <h4><?=$lang['edit']['mailbox'];?></h4>
@ -724,10 +725,26 @@ if (isset($_SESSION['mailcow_cc_role'])) {
?> ?>
</select> </select>
<div style="display:none" id="sender_acl_disabled"><?=$lang['edit']['sender_acl_disabled'];?></div> <div id="sender_acl_disabled"><i class="bi bi-shield-exclamation"></i> <?=$lang['edit']['sender_acl_disabled'];?></div>
<small class="help-block"><?=$lang['edit']['sender_acl_info'];?></small> <small class="help-block"><?=$lang['edit']['sender_acl_info'];?></small>
</div> </div>
</div> </div>
<div class="form-group">
<label class="control-label col-sm-2" for="relayhost"><?=$lang['edit']['relayhost'];?></label>
<div class="col-sm-10">
<select data-acl="<?=$_SESSION['acl']['mailbox_relayhost'];?>" data-live-search="true" id="relayhost" name="relayhost" class="form-control">
<?php
foreach ($rlyhosts as $rlyhost) {
?>
<option style="<?=($rlyhost['active'] == 1) ? '' : 'background: #ff4136; color: #fff';?>" value="<?=$rlyhost['id'];?>" <?=($result['attributes']['relayhost'] == $rlyhost['id']) ? 'selected' : null;?>>ID <?=$rlyhost['id'];?>: <?=$rlyhost['hostname'];?> (<?=$rlyhost['username'];?>)</option>
<?php
}
?>
<option value="" <?=($result['attributes']['relayhost'] == "0") ? 'selected' : null;?>>None</option>
</select>
<small class="help-block"><?=$lang['edit']['mailbox_relayhost_info'];?></small>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-2"><?=$lang['user']['quarantine_notification'];?></label> <label class="control-label col-sm-2"><?=$lang['user']['quarantine_notification'];?></label>
<div class="col-sm-10"> <div class="col-sm-10">
@ -965,7 +982,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
<div class="btn-group" data-acl="<?=$_SESSION['acl']['pushover'];?>"> <div class="btn-group" data-acl="<?=$_SESSION['acl']['pushover'];?>">
<a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></a> <a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></a>
<a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover-test" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['edit']['pushover_verify'];?></a> <a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover-test" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['edit']['pushover_verify'];?></a>
<a id="pushover_delete" class="btn btn-sm btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-recycle"></i> <?=$lang['edit']['remove'];?></a> <a id="pushover_delete" class="btn btn-sm btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-trash"></i> <?=$lang['edit']['remove'];?></a>
</div> </div>
</div> </div>
</div> </div>

View File

@ -940,8 +940,9 @@ function edit_user_account($_data) {
} }
function user_get_alias_details($username) { function user_get_alias_details($username) {
global $pdo; global $pdo;
$data['direct_aliases'] = false; global $lang;
$data['shared_aliases'] = false; $data['direct_aliases'] = array();
$data['shared_aliases'] = array();
if ($_SESSION['mailcow_cc_role'] == "user") { if ($_SESSION['mailcow_cc_role'] == "user") {
$username = $_SESSION['mailcow_cc_username']; $username = $_SESSION['mailcow_cc_username'];
} }
@ -987,22 +988,22 @@ function user_get_alias_details($username) {
if (empty($row['ad_alias'])) { if (empty($row['ad_alias'])) {
continue; continue;
} }
$data['direct_aliases'][$row['ad_alias']]['public_comment'] = '' . $row['alias_domain']; $data['direct_aliases'][$row['ad_alias']]['public_comment'] = '<span data-toggle="tooltip" title="' . $lang['add']['alias_domain'] . '">' . $row['alias_domain'] . '</span>';
$data['alias_domains'][] = $row['alias_domain']; $data['alias_domains'][] = $row['alias_domain'];
} }
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`send_as` SEPARATOR ', '), '&#10008;') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `send_as` NOT LIKE '@%';"); $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`send_as` SEPARATOR ', '), '') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `send_as` NOT LIKE '@%';");
$stmt->execute(array(':username' => $username)); $stmt->execute(array(':username' => $username));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC); $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) { while ($row = array_shift($run)) {
$data['aliases_also_send_as'] = $row['send_as']; $data['aliases_also_send_as'] = $row['send_as'];
} }
$stmt = $pdo->prepare("SELECT CONCAT_WS(', ', IFNULL(GROUP_CONCAT(DISTINCT `send_as` SEPARATOR ', '), '&#10008;'), GROUP_CONCAT(DISTINCT CONCAT('@',`alias_domain`) SEPARATOR ', ')) AS `send_as` FROM `sender_acl` LEFT JOIN `alias_domain` ON `alias_domain`.`target_domain` = TRIM(LEADING '@' FROM `send_as`) WHERE `logged_in_as` = :username AND `send_as` LIKE '@%';"); $stmt = $pdo->prepare("SELECT CONCAT_WS(', ', IFNULL(GROUP_CONCAT(DISTINCT `send_as` SEPARATOR ', '), ''), GROUP_CONCAT(DISTINCT CONCAT('@',`alias_domain`) SEPARATOR ', ')) AS `send_as` FROM `sender_acl` LEFT JOIN `alias_domain` ON `alias_domain`.`target_domain` = TRIM(LEADING '@' FROM `send_as`) WHERE `logged_in_as` = :username AND `send_as` LIKE '@%';");
$stmt->execute(array(':username' => $username)); $stmt->execute(array(':username' => $username));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC); $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) { while ($row = array_shift($run)) {
$data['aliases_send_as_all'] = $row['send_as']; $data['aliases_send_as_all'] = $row['send_as'];
} }
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '&#10008;') as `address` FROM `alias` WHERE `goto` REGEXP :username AND `address` LIKE '@%';"); $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '') as `address` FROM `alias` WHERE `goto` REGEXP :username AND `address` LIKE '@%';");
$stmt->execute(array(':username' => '(^|,)'.$username.'($|,)')); $stmt->execute(array(':username' => '(^|,)'.$username.'($|,)'));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC); $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) { while ($row = array_shift($run)) {

View File

@ -2141,6 +2141,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$xmpp = (isset($_data['xmpp']) && !empty($_SESSION['acl']['xmpp_domain_access']) && $_SESSION['acl']['xmpp_domain_access'] == "1") ? intval($_data['xmpp']) : $is_now['xmpp']; $xmpp = (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']; $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']; $description = (!empty($_data['description']) && isset($_SESSION['acl']['domain_desc']) && $_SESSION['acl']['domain_desc'] == "1") ? $_data['description'] : $is_now['description'];
(int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['domain_relayhost']) && $_SESSION['acl']['domain_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['relayhost']);
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
@ -2359,6 +2360,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
(int)$smtp_access = (isset($_data['smtp_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']); (int)$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_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)$xmpp_access = (isset($_data['xmpp_access']) && isset($_SESSION['acl']['xmpp_mailbox_access']) && $_SESSION['acl']['xmpp_mailbox_access'] == "1") ? intval($_data['xmpp_access']) : intval($is_now['attributes']['xmpp_access']);
(int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['mailbox_relayhost']) && $_SESSION['acl']['mailbox_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']);
(int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576); (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']; $name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name'];
$domain = $is_now['domain']; $domain = $is_now['domain'];
@ -2631,6 +2633,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access), `attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access),
`attributes` = JSON_SET(`attributes`, '$.xmpp_admin', :xmpp_admin), `attributes` = JSON_SET(`attributes`, '$.xmpp_admin', :xmpp_admin),
`attributes` = JSON_SET(`attributes`, '$.xmpp_access', :xmpp_access), `attributes` = JSON_SET(`attributes`, '$.xmpp_access', :xmpp_access),
`attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost),
`attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access) `attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access)
WHERE `username` = :username"); WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
@ -2644,6 +2647,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':smtp_access' => $smtp_access, ':smtp_access' => $smtp_access,
':xmpp_admin' => $xmpp_admin, ':xmpp_admin' => $xmpp_admin,
':xmpp_access' => $xmpp_access, ':xmpp_access' => $xmpp_access,
':relayhost' => $relayhost,
':username' => $username ':username' => $username
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
@ -3561,6 +3565,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$mailboxdata['active_int'] = $row['active']; $mailboxdata['active_int'] = $row['active'];
$mailboxdata['domain'] = $row['domain']; $mailboxdata['domain'] = $row['domain'];
$mailboxdata['domain_xmpp'] = $row['domain_xmpp']; $mailboxdata['domain_xmpp'] = $row['domain_xmpp'];
$mailboxdata['relayhost'] = $row['relayhost'];
$mailboxdata['name'] = $row['name']; $mailboxdata['name'] = $row['name'];
$mailboxdata['domain_xmpp_prefix'] = $row['domain_xmpp_prefix']; $mailboxdata['domain_xmpp_prefix'] = $row['domain_xmpp_prefix'];
$mailboxdata['local_part'] = $row['local_part']; $mailboxdata['local_part'] = $row['local_part'];

View File

@ -137,11 +137,11 @@ function relayhost($_action, $_data = null) {
} }
break; break;
case 'get': case 'get':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
return false; return false;
} }
$relayhosts = array(); $relayhosts = array();
$stmt = $pdo->query("SELECT `id`, `hostname`, `username` FROM `relayhosts`"); $stmt = $pdo->query("SELECT `id`, `hostname`, `username`, `active` FROM `relayhosts`");
$relayhosts = $stmt->fetchAll(PDO::FETCH_ASSOC); $relayhosts = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $relayhosts; return $relayhosts;
break; break;
@ -166,6 +166,11 @@ function relayhost($_action, $_data = null) {
$used_by_domains = $stmt->fetch(PDO::FETCH_ASSOC)['used_by_domains']; $used_by_domains = $stmt->fetch(PDO::FETCH_ASSOC)['used_by_domains'];
$used_by_domains = (empty($used_by_domains)) ? '' : $used_by_domains; $used_by_domains = (empty($used_by_domains)) ? '' : $used_by_domains;
$relayhostdata['used_by_domains'] = $used_by_domains; $relayhostdata['used_by_domains'] = $used_by_domains;
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(`username` SEPARATOR ', ') AS `used_by_mailboxes` FROM `mailbox` WHERE JSON_VALUE(`attributes`, '$.relayhost') = :id");
$stmt->execute(array(':id' => $_data));
$used_by_mailboxes = $stmt->fetch(PDO::FETCH_ASSOC)['used_by_mailboxes'];
$used_by_mailboxes = (empty($used_by_mailboxes)) ? '' : $used_by_mailboxes;
$relayhostdata['used_by_mailboxes'] = $used_by_mailboxes;
} }
return $relayhostdata; return $relayhostdata;
break; break;

View File

@ -3,7 +3,7 @@ function init_db_schema() {
try { try {
global $pdo; global $pdo;
$db_version = "21052021_0900"; $db_version = "25052021_0900";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@ -572,6 +572,8 @@ function init_db_schema() {
"protocol_access" => "TINYINT(1) NOT NULL DEFAULT '1'", "protocol_access" => "TINYINT(1) NOT NULL DEFAULT '1'",
"smtp_ip_access" => "TINYINT(1) NOT NULL DEFAULT '1'", "smtp_ip_access" => "TINYINT(1) NOT NULL DEFAULT '1'",
"alias_domains" => "TINYINT(1) NOT NULL DEFAULT '0'", "alias_domains" => "TINYINT(1) NOT NULL DEFAULT '0'",
"mailbox_relayhost" => "TINYINT(1) NOT NULL DEFAULT '1'",
"domain_relayhost" => "TINYINT(1) NOT NULL DEFAULT '1'",
"xmpp_prefix" => "TINYINT(1) NOT NULL DEFAULT '0'", "xmpp_prefix" => "TINYINT(1) NOT NULL DEFAULT '0'",
"xmpp_domain_access" => "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_mailbox_access" => "TINYINT(1) NOT NULL DEFAULT '0'",
@ -1188,6 +1190,7 @@ function init_db_schema() {
$pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.only_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.only_x_prio') IS NULL;"); $pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.only_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.only_x_prio') IS NULL;");
// mailbox // mailbox
$pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.relayhost', \"0\") WHERE JSON_VALUE(`attributes`, '$.relayhost') IS NULL;");
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.xmpp_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.xmpp_access') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.xmpp_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`, '$.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`, '$.force_pw_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.force_pw_update') IS NULL;");

View File

@ -187,7 +187,7 @@ jQuery(function($){
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}}, {"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
{"name":"hostname","type":"text","title":lang.host,"style":{"width":"250px"}}, {"name":"hostname","type":"text","title":lang.host,"style":{"width":"250px"}},
{"name":"username","title":lang.username,"breakpoints":"xs sm"}, {"name":"username","title":lang.username,"breakpoints":"xs sm"},
{"name":"used_by_domains","title":lang.in_use_by,"style":{"width":"110px"}, "type": "text","breakpoints":"xs sm"}, {"name":"in_use_by","title":lang.in_use_by,"style":{"width":"110px"}, "type": "text","breakpoints":"xs sm"},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}}, {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"} {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
], ],
@ -209,7 +209,7 @@ jQuery(function($){
}); });
} }
function draw_transport_maps() { function draw_transport_maps() {
ft_relayhoststable = FooTable.init('#transportstable', { ft_transportstable = FooTable.init('#transportstable', {
"columns": [ "columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"}, {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}}, {"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
@ -279,8 +279,11 @@ jQuery(function($){
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' + '<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' +
'<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; }
else if (item.used_by_domains == '') { item.in_use_by = item.used_by_mailboxes; }
else { item.in_use_by = item.used_by_mailboxes + '<hr style="margin:5px 0px 5px 0px;">' + item.used_by_domains; }
item.chkbox = '<input type="checkbox" data-id="rlyhosts" name="multi_select" value="' + item.id + '" />'; item.chkbox = '<input type="checkbox" data-id="rlyhosts" name="multi_select" value="' + item.id + '" />';
}); });
} else if (table == 'transportstable') { } else if (table == 'transportstable') {
@ -291,7 +294,7 @@ jQuery(function($){
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' + '<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' +
'<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />'; item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />';
}); });
@ -309,7 +312,7 @@ jQuery(function($){
} else if (table == 'forwardinghoststable') { } else if (table == 'forwardinghoststable') {
$.each(data, function (i, item) { $.each(data, function (i, item) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="#" data-action="delete_selected" data-id="single-fwdhost" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-fwdhost" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />'; item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
}); });
@ -317,7 +320,7 @@ jQuery(function($){
$.each(data, function (i, item) { $.each(data, function (i, item) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.scope = "profile"; item.scope = "profile";
item.grant_types = 'refresh_token password authorization_code'; item.grant_types = 'refresh_token password authorization_code';
@ -330,7 +333,7 @@ jQuery(function($){
item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />'; item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-success"><i class="bi bi-person-fill"></i> Login</a>' + '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-success"><i class="bi bi-person-fill"></i> Login</a>' +
'</div>'; '</div>';
}); });
@ -344,7 +347,7 @@ jQuery(function($){
item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />'; item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />';
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
}); });
} }

View File

@ -710,7 +710,7 @@ jQuery(function($){
} }
item.indicator = '<span style="border-right:6px solid #' + intToRGB(hashCode(item.rl_hash)) + ';padding-left:5px;">&nbsp;</span>'; item.indicator = '<span style="border-right:6px solid #' + intToRGB(hashCode(item.rl_hash)) + ';padding-left:5px;">&nbsp;</span>';
if (item.rl_hash != 'err') { if (item.rl_hash != 'err') {
item.action = '<a href="#" data-action="delete_selected" data-id="single-hash" data-api-url="delete/rlhash" data-item="' + encodeURI(item.rl_hash) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.reset_limit + '</a>'; item.action = '<a href="#" data-action="delete_selected" data-id="single-hash" data-api-url="delete/rlhash" data-item="' + encodeURI(item.rl_hash) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.reset_limit + '</a>';
} }
}); });
} }

View File

@ -128,7 +128,7 @@ $(document).ready(function() {
// Log modal // Log modal
$('#dnsInfoModal').on('show.bs.modal', function(e) { $('#dnsInfoModal').on('show.bs.modal', function(e) {
var domain = $(e.relatedTarget).data('domain'); var domain = $(e.relatedTarget).data('domain');
$('.dns-modal-body').html('<center><i class="bi bi-arrow-repeat icon-spin" style="font-size:18pt;margin:50px"></i></center>'); $('.dns-modal-body').html('<center><i class="bi bi-arrow-repeat icon-spin"></i></center>');
$.ajax({ $.ajax({
url: '/inc/ajax/dns_diagnostics.php', url: '/inc/ajax/dns_diagnostics.php',
data: { domain: domain }, data: { domain: domain },
@ -286,7 +286,7 @@ jQuery(function($){
item.action = '<div class="btn-group">'; item.action = '<div class="btn-group">';
if (role == "admin") { if (role == "admin") {
item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>'; '<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>';
} }
else { else {
item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>'; item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>';
@ -432,7 +432,7 @@ jQuery(function($){
if (acl_data.login_as === 1) { if (acl_data.login_as === 1) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs btn-success"><i class="bi bi-person-fill"></i> Login</a>'; '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs btn-success"><i class="bi bi-person-fill"></i> Login</a>';
if (ALLOW_ADMIN_EMAIL_LOGIN) { if (ALLOW_ADMIN_EMAIL_LOGIN) {
item.action += '<a href="/sogo-auth.php?login=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs btn-primary" target="_blank"><i class="bi bi-envelope-fill"></i> SOGo</a>'; item.action += '<a href="/sogo-auth.php?login=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs btn-primary" target="_blank"><i class="bi bi-envelope-fill"></i> SOGo</a>';
@ -442,7 +442,7 @@ jQuery(function($){
else { else {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
} }
item.in_use = '<div class="progress">' + item.in_use = '<div class="progress">' +
@ -519,7 +519,7 @@ jQuery(function($){
} }
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />'; item.chkbox = '<input type="checkbox" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />';
item.name = escapeHtml(item.name); item.name = escapeHtml(item.name);
@ -585,7 +585,7 @@ jQuery(function($){
$.each(data, function (i, item) { $.each(data, function (i, item) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/bcc/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/bcc/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="bcc" name="multi_select" value="' + item.id + '" />'; item.chkbox = '<input type="checkbox" data-id="bcc" name="multi_select" value="' + item.id + '" />';
item.local_dest = escapeHtml(item.local_dest); item.local_dest = escapeHtml(item.local_dest);
@ -655,7 +655,7 @@ jQuery(function($){
item.recipient_map_new = escapeHtml(item.recipient_map_new); item.recipient_map_new = escapeHtml(item.recipient_map_new);
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/recipient_map/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/recipient_map/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="recipient_map" name="multi_select" value="' + item.id + '" />'; item.chkbox = '<input type="checkbox" data-id="recipient_map" name="multi_select" value="' + item.id + '" />';
}); });
@ -725,7 +725,7 @@ jQuery(function($){
} }
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />'; item.chkbox = '<input type="checkbox" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />';
}); });
@ -790,7 +790,7 @@ jQuery(function($){
$.each(data, function (i, item) { $.each(data, function (i, item) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="alias" name="multi_select" value="' + encodeURIComponent(item.id) + '" />'; item.chkbox = '<input type="checkbox" data-id="alias" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
item.goto = escapeHtml(item.goto.replace(/,/g, " ")); item.goto = escapeHtml(item.goto.replace(/,/g, " "));
@ -813,7 +813,7 @@ jQuery(function($){
item.address = escapeHtml(item.address); item.address = escapeHtml(item.address);
} }
if (item.goto == "null@localhost") { if (item.goto == "null@localhost") {
item.goto = '⤷ <i class="bi bi-recycle" style="font-size:12px"></i>'; item.goto = '⤷ <i class="bi bi-trash" style="font-size:12px"></i>';
} }
else if (item.goto == "spam@localhost") { else if (item.goto == "spam@localhost") {
item.goto = '<span class="label label-danger">Learn as spam</span>'; item.goto = '<span class="label label-danger">Learn as spam</span>';
@ -884,7 +884,7 @@ jQuery(function($){
$.each(data, function (i, item) { $.each(data, function (i, item) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><i class="bi bi-question-lg"></i> DNS</a></div>' + '<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><i class="bi bi-question-lg"></i> DNS</a></div>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="alias-domain" name="multi_select" value="' + encodeURIComponent(item.alias_domain) + '" />'; item.chkbox = '<input type="checkbox" data-id="alias-domain" name="multi_select" value="' + encodeURIComponent(item.alias_domain) + '" />';
@ -964,7 +964,7 @@ jQuery(function($){
item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1; item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1;
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />'; item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
if (item.is_running == 1) { if (item.is_running == 1) {
@ -1042,7 +1042,7 @@ jQuery(function($){
item.filter_type = '<div class="label label-default">' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '</div>' item.filter_type = '<div class="label label-default">' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '</div>'
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/filter/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/filter/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="filter_item" name="multi_select" value="' + item.id + '" />' item.chkbox = '<input type="checkbox" data-id="filter_item" name="multi_select" value="' + item.id + '" />'
}); });

View File

@ -97,7 +97,7 @@ jQuery(function($){
if (acl_data.login_as === 1) { if (acl_data.login_as === 1) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-info show_qid_info"><i class="bi bi-box-arrow-up-right"></i> ' + lang.show_item + '</a>' + '<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-info show_qid_info"><i class="bi bi-box-arrow-up-right"></i> ' + lang.show_item + '</a>' +
'<a href="#" data-action="delete_selected" data-id="del-single-qitem" data-api-url="delete/qitem" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="del-single-qitem" data-api-url="delete/qitem" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
} }
else { else {

View File

@ -94,7 +94,7 @@ jQuery(function($){
$.each(data, function (i, item) { $.each(data, function (i, item) {
if (acl_data.spam_alias === 1) { if (acl_data.spam_alias === 1) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="#" data-action="delete_selected" data-id="single-tla" data-api-url="delete/time_limited_alias" data-item="' + encodeURIComponent(item.address) + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-tla" data-api-url="delete/time_limited_alias" data-item="' + encodeURIComponent(item.address) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />'; item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
item.address = escapeHtml(item.address); item.address = escapeHtml(item.address);
@ -155,7 +155,7 @@ jQuery(function($){
if (acl_data.syncjobs === 1) { if (acl_data.syncjobs === 1) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />'; item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
} }
@ -209,7 +209,7 @@ jQuery(function($){
if (acl_data.app_passwds === 1) { if (acl_data.app_passwds === 1) {
item.action = '<div class="btn-group">' + item.action = '<div class="btn-group">' +
'<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-apppasswd" data-api-url="delete/app-passwd" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> ' + lang.remove + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-apppasswd" data-api-url="delete/app-passwd" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>'; '</div>';
item.chkbox = '<input type="checkbox" data-id="apppasswd" name="multi_select" value="' + item.id + '" />'; item.chkbox = '<input type="checkbox" data-id="apppasswd" name="multi_select" value="' + item.id + '" />';
} }

View File

@ -531,7 +531,7 @@
"save": "Uložit změny", "save": "Uložit změny",
"scope": "Rozsah", "scope": "Rozsah",
"sender_acl": "Povolit odesílání jako", "sender_acl": "Povolit odesílání jako",
"sender_acl_disabled": "<span class=\"label label-danger\">Kontrola odesílatele vypnuta</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Kontrola odesílatele vypnuta</span>",
"sender_acl_info": "Má-li uživatel schránky A dovoleno odesílat jako uživatel schránky B, nezobrazuje se adresa odesílatele B v seznamu \"Od\" v SOGo automaticky.<br>\r\n Uživatel schránky A musí nejdříve v SOGo vytvořit pověření, jež umožní uživateli B vybrat svou adresu jako odesílatele. Tento mechanismus neplatí pro aliasy.", "sender_acl_info": "Má-li uživatel schránky A dovoleno odesílat jako uživatel schránky B, nezobrazuje se adresa odesílatele B v seznamu \"Od\" v SOGo automaticky.<br>\r\n Uživatel schránky A musí nejdříve v SOGo vytvořit pověření, jež umožní uživateli B vybrat svou adresu jako odesílatele. Tento mechanismus neplatí pro aliasy.",
"sieve_desc": "Krátký popis", "sieve_desc": "Krátký popis",
"sieve_type": "Typ filtru", "sieve_type": "Typ filtru",

View File

@ -552,7 +552,7 @@
"save": "Gem ændringer", "save": "Gem ændringer",
"scope": "Anvendelsesområde", "scope": "Anvendelsesområde",
"sender_acl": "Tillad at sende som", "sender_acl": "Tillad at sende som",
"sender_acl_disabled": "<span class=\"label label-danger\">Afsenderkontrol er deaktiveret</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Afsenderkontrol er deaktiveret</span>",
"sender_acl_info": "Hvis postkassebruger A har tilladelse til at sende som postkassebruger B, vises afsenderadressen ikke automatisk som valgbar \"from\" felt i SOGo.<br>\r\n Postkassebruger B skal oprette en delegation i SOGo for at tillade postkassebruger A at vælge deres adresse som afsender. For at delegere en postkasse i SOGo skal du bruge menuen (tre prikker) til højre for dit postkassens navn øverst til venstre, mens du er i postvisningen. Denne adfærd gælder ikke for aliasadresser.", "sender_acl_info": "Hvis postkassebruger A har tilladelse til at sende som postkassebruger B, vises afsenderadressen ikke automatisk som valgbar \"from\" felt i SOGo.<br>\r\n Postkassebruger B skal oprette en delegation i SOGo for at tillade postkassebruger A at vælge deres adresse som afsender. For at delegere en postkasse i SOGo skal du bruge menuen (tre prikker) til højre for dit postkassens navn øverst til venstre, mens du er i postvisningen. Denne adfærd gælder ikke for aliasadresser.",
"sieve_desc": "Kort beskrivelse", "sieve_desc": "Kort beskrivelse",
"sieve_type": "Filtertype", "sieve_type": "Filtertype",

View File

@ -27,6 +27,8 @@
"tls_policy": "Verschlüsselungsrichtlinie", "tls_policy": "Verschlüsselungsrichtlinie",
"unlimited_quota": "Unendliche Quota für Mailboxen", "unlimited_quota": "Unendliche Quota für Mailboxen",
"domain_desc": "Domainbeschreibung ändern", "domain_desc": "Domainbeschreibung ändern",
"mailbox_relayhost": "Relayhost für eine Mailbox setzen",
"domain_relayhost": "Relayhost für eine Domain setzen",
"xmpp_admin": "Benutzer zum XMPP-Administrator ernennen", "xmpp_admin": "Benutzer zum XMPP-Administrator ernennen",
"xmpp_domain_access": "XMPP-Zugang einer Domain konfigurieren", "xmpp_domain_access": "XMPP-Zugang einer Domain konfigurieren",
"xmpp_mailbox_access": "XMPP-Zugang eines Benutzers einstellen", "xmpp_mailbox_access": "XMPP-Zugang eines Benutzers einstellen",
@ -554,6 +556,7 @@
"inactive": "Inaktiv", "inactive": "Inaktiv",
"kind": "Art", "kind": "Art",
"mailbox": "Mailbox bearbeiten", "mailbox": "Mailbox bearbeiten",
"mailbox_relayhost_info": "Wird auf eine Mailbox und direkte Alias-Adressen angewendet. Überschreibt die Einstellung einer Domain.",
"mailbox_quota_def": "Standard-Quota einer Mailbox", "mailbox_quota_def": "Standard-Quota einer Mailbox",
"max_aliases": "Max. Aliasse", "max_aliases": "Max. Aliasse",
"max_mailboxes": "Max. Mailboxanzahl", "max_mailboxes": "Max. Mailboxanzahl",
@ -594,7 +597,7 @@
"save": "Änderungen speichern", "save": "Änderungen speichern",
"scope": "Scope", "scope": "Scope",
"sender_acl": "Darf Nachrichten versenden als", "sender_acl": "Darf Nachrichten versenden als",
"sender_acl_disabled": "<span class=\"label label-danger\">Absenderprüfung deaktiviert</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Absenderprüfung deaktiviert</span>",
"sender_acl_info": "Wird einem Mailbox-Benutzer A der Versand als Mailbox-Benutzer B gestattet, so erscheint der Absender <b>nicht</b> automatisch in SOGo zur Auswahl.<br>\r\n In SOGo muss zusätzlich eine Delegation eingerichtet werden. Dieses Verhalten trifft nicht auf Alias-Adressen zu.", "sender_acl_info": "Wird einem Mailbox-Benutzer A der Versand als Mailbox-Benutzer B gestattet, so erscheint der Absender <b>nicht</b> automatisch in SOGo zur Auswahl.<br>\r\n In SOGo muss zusätzlich eine Delegation eingerichtet werden. Dieses Verhalten trifft nicht auf Alias-Adressen zu.",
"sieve_desc": "Kurze Beschreibung", "sieve_desc": "Kurze Beschreibung",
"sieve_type": "Filtertyp", "sieve_type": "Filtertyp",
@ -1020,6 +1023,7 @@
"eas_reset_help": "In vielen Fällen kann ein ActiveSync-Profil durch das Zurücksetzen des Caches repariert werden.<br><b>Vorsicht:</b> Alle Elemente werden erneut heruntergeladen!", "eas_reset_help": "In vielen Fällen kann ein ActiveSync-Profil durch das Zurücksetzen des Caches repariert werden.<br><b>Vorsicht:</b> Alle Elemente werden erneut heruntergeladen!",
"eas_reset_now": "Jetzt zurücksetzen", "eas_reset_now": "Jetzt zurücksetzen",
"edit": "Bearbeiten", "edit": "Bearbeiten",
"empty": "Keine Einträge vorhanden",
"email": "E-Mail", "email": "E-Mail",
"email_and_dav": "E-Mail, Kalender und Adressbücher", "email_and_dav": "E-Mail, Kalender und Adressbücher",
"encryption": "Verschlüsselung", "encryption": "Verschlüsselung",

View File

@ -27,6 +27,8 @@
"tls_policy": "TLS policy", "tls_policy": "TLS policy",
"unlimited_quota": "Unlimited quota for mailboxes", "unlimited_quota": "Unlimited quota for mailboxes",
"domain_desc": "Change domain description", "domain_desc": "Change domain description",
"mailbox_relayhost": "Change relayhost for a mailbox",
"domain_relayhost": "Change relayhost for a domain",
"xmpp_admin": "Promote XMPP user to administrator", "xmpp_admin": "Promote XMPP user to administrator",
"xmpp_domain_access": "Configure XMPP domain access", "xmpp_domain_access": "Configure XMPP domain access",
"xmpp_mailbox_access": "Configure XMPP user access", "xmpp_mailbox_access": "Configure XMPP user access",
@ -553,6 +555,7 @@
"kind": "Kind", "kind": "Kind",
"mailbox": "Edit mailbox", "mailbox": "Edit mailbox",
"mailbox_quota_def": "Default mailbox quota", "mailbox_quota_def": "Default mailbox quota",
"mailbox_relayhost_info": "Applied to the mailbox and direct aliases only, does override a domain relayhost.",
"max_aliases": "Max. aliases", "max_aliases": "Max. aliases",
"max_mailboxes": "Max. possible mailboxes", "max_mailboxes": "Max. possible mailboxes",
"max_quota": "Max. quota per mailbox (MiB)", "max_quota": "Max. quota per mailbox (MiB)",
@ -592,7 +595,7 @@
"save": "Save changes", "save": "Save changes",
"scope": "Scope", "scope": "Scope",
"sender_acl": "Allow to send as", "sender_acl": "Allow to send as",
"sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>",
"sender_acl_info": "If mailbox user A is allowed to send as mailbox user B, the sender address is not automatically displayed as selectable \"from\" field in SOGo.<br>\r\n Mailbox user B needs to create a delegation in SOGo to allow mailbox user A to select their address as sender. To delegate a mailbox in SOGo, use the menu (three dots) to the right of your mailbox name in the upper left while in mail view. This behaviour does not apply to alias addresses.", "sender_acl_info": "If mailbox user A is allowed to send as mailbox user B, the sender address is not automatically displayed as selectable \"from\" field in SOGo.<br>\r\n Mailbox user B needs to create a delegation in SOGo to allow mailbox user A to select their address as sender. To delegate a mailbox in SOGo, use the menu (three dots) to the right of your mailbox name in the upper left while in mail view. This behaviour does not apply to alias addresses.",
"sieve_desc": "Short description", "sieve_desc": "Short description",
"sieve_type": "Filter type", "sieve_type": "Filter type",
@ -1018,6 +1021,7 @@
"eas_reset_help": "In many cases a device cache reset will help to recover a broken ActiveSync profile.<br><b>Attention:</b> All elements will be redownloaded!", "eas_reset_help": "In many cases a device cache reset will help to recover a broken ActiveSync profile.<br><b>Attention:</b> All elements will be redownloaded!",
"eas_reset_now": "Reset now", "eas_reset_now": "Reset now",
"edit": "Edit", "edit": "Edit",
"empty": "No results",
"email": "Email", "email": "Email",
"email_and_dav": "Email, calendars and contacts", "email_and_dav": "Email, calendars and contacts",
"encryption": "Encryption", "encryption": "Encryption",

View File

@ -468,7 +468,7 @@
"save": "Tallenna muutokset", "save": "Tallenna muutokset",
"scope": "Laajuus", "scope": "Laajuus",
"sender_acl": "Salli lähettää nimellä", "sender_acl": "Salli lähettää nimellä",
"sender_acl_disabled": "<span class=\"label label-danger\">Lähettäjän tarkistus on poistettu käytöstä</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Lähettäjän tarkistus on poistettu käytöstä</span>",
"sender_acl_info": "Jos postilaatikon käyttäjän A sallitaan lähettävän postilaatikon käyttäjäksi B, lähettäjän osoitetta ei näytetä automaattisesti valittavana \"alkaen\" -kentässä SOGossa.<br>\r\nSähkö postilaatikon käyttäjän A on luotava valtuutus SOGoon, jotta sähkö postilaatikon käyttäjä b voi valita osoitteen lähettäjäksi. Tämä käyttäytyminen ei koske alias-osoitteita", "sender_acl_info": "Jos postilaatikon käyttäjän A sallitaan lähettävän postilaatikon käyttäjäksi B, lähettäjän osoitetta ei näytetä automaattisesti valittavana \"alkaen\" -kentässä SOGossa.<br>\r\nSähkö postilaatikon käyttäjän A on luotava valtuutus SOGoon, jotta sähkö postilaatikon käyttäjä b voi valita osoitteen lähettäjäksi. Tämä käyttäytyminen ei koske alias-osoitteita",
"sieve_desc": "Lyhyt kuvaus", "sieve_desc": "Lyhyt kuvaus",
"sieve_type": "Suodattimen tyyppi", "sieve_type": "Suodattimen tyyppi",

View File

@ -578,7 +578,7 @@
"save": "Enregistrer les modifications", "save": "Enregistrer les modifications",
"scope": "Portée", "scope": "Portée",
"sender_acl": "Permettre denvoyer comme", "sender_acl": "Permettre denvoyer comme",
"sender_acl_disabled": "<span class=\"label label-danger\">Le contrôle de lexpéditeur est désactivé</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Le contrôle de lexpéditeur est désactivé</span>",
"sender_acl_info": "Si lutilisateur de la boîte A est autorisé à envoyer en tant quutilisateur de la boîte B, ladresse de lexpéditeur nest pas automatiquement affichée comme sélectionnable du champ \"from\" dans SOGo.<br>\r\n Lutilisateur B de la boîte doit créer une délégation dans Sogo pour permettre à lutilisateur A de la boîte de sélectionner son adresse comme expéditeur. Pour déléguer une boîte dans Sogo, utilisez le menu (trois points) à droite du nom de votre boîte dans le coin supérieur gauche dans la vue de courrier. Ce comportement ne sapplique pas aux adresses alias.", "sender_acl_info": "Si lutilisateur de la boîte A est autorisé à envoyer en tant quutilisateur de la boîte B, ladresse de lexpéditeur nest pas automatiquement affichée comme sélectionnable du champ \"from\" dans SOGo.<br>\r\n Lutilisateur B de la boîte doit créer une délégation dans Sogo pour permettre à lutilisateur A de la boîte de sélectionner son adresse comme expéditeur. Pour déléguer une boîte dans Sogo, utilisez le menu (trois points) à droite du nom de votre boîte dans le coin supérieur gauche dans la vue de courrier. Ce comportement ne sapplique pas aux adresses alias.",
"sieve_desc": "Description courte", "sieve_desc": "Description courte",
"sieve_type": "Type de filtre", "sieve_type": "Type de filtre",

View File

@ -534,7 +534,7 @@
"save": "Save changes", "save": "Save changes",
"scope": "Scope", "scope": "Scope",
"sender_acl": "Allow to send as", "sender_acl": "Allow to send as",
"sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Sender check is disabled</span>",
"sender_acl_info": "If mailbox user A is allowed to send as mailbox user B, the sender address is not automatically displayed as selectable \"from\" field in SOGo.<br>\r\n Mailbox user B needs to create a delegation in SOGo to allow mailbox user A to select their address as sender. To delegate a mailbox in SOGo, use the menu (three dots) to the right of your mailbox name in the upper left while in mail view. This behaviour does not apply to alias addresses.", "sender_acl_info": "If mailbox user A is allowed to send as mailbox user B, the sender address is not automatically displayed as selectable \"from\" field in SOGo.<br>\r\n Mailbox user B needs to create a delegation in SOGo to allow mailbox user A to select their address as sender. To delegate a mailbox in SOGo, use the menu (three dots) to the right of your mailbox name in the upper left while in mail view. This behaviour does not apply to alias addresses.",
"sieve_desc": "Short description", "sieve_desc": "Short description",
"sieve_type": "Filter type", "sieve_type": "Filter type",

View File

@ -578,7 +578,7 @@
"save": "Wijzigingen opslaan", "save": "Wijzigingen opslaan",
"scope": "Scope", "scope": "Scope",
"sender_acl": "Sta toe om te verzenden als", "sender_acl": "Sta toe om te verzenden als",
"sender_acl_disabled": "<span class=\"label label-danger\">Verzendcontrole is uitgeschakeld</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Verzendcontrole is uitgeschakeld</span>",
"sender_acl_info": "Wanneer mailboxgebruiker A toegestaan is te verzenden namens mailboxgebruiker B, zal het verzendadres niet automatisch worden weergegeven in het \"van\"-veld in SOGo. Mailboxgebruiker A dient hiervoor een aparte vermelding te maken in SOGo. Om een mailbox te delegeren in SOGo kan het menu (drie punten) aan de rechterkant van de naam van het mailbox linksboven worden gebruikt in de mailweergave. Dit is niet van toepassing op aliasadressen.", "sender_acl_info": "Wanneer mailboxgebruiker A toegestaan is te verzenden namens mailboxgebruiker B, zal het verzendadres niet automatisch worden weergegeven in het \"van\"-veld in SOGo. Mailboxgebruiker A dient hiervoor een aparte vermelding te maken in SOGo. Om een mailbox te delegeren in SOGo kan het menu (drie punten) aan de rechterkant van de naam van het mailbox linksboven worden gebruikt in de mailweergave. Dit is niet van toepassing op aliasadressen.",
"sieve_desc": "Korte beschrijving", "sieve_desc": "Korte beschrijving",
"sieve_type": "Filtertype", "sieve_type": "Filtertype",
@ -1047,7 +1047,7 @@
"running": "Wordt uitgevoerd", "running": "Wordt uitgevoerd",
"save": "Sla wijzigingen op", "save": "Sla wijzigingen op",
"save_changes": "Wijzigingen opslaan", "save_changes": "Wijzigingen opslaan",
"sender_acl_disabled": "<span class=\"label label-danger\">Verzendcontrole is uitgeschakeld</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Verzendcontrole is uitgeschakeld</span>",
"shared_aliases": "Gedeelde aliasadressen", "shared_aliases": "Gedeelde aliasadressen",
"shared_aliases_desc": "Een gedeeld aliasadres wordt niet beïnvloed door gebruikersspecifieke instellingen. Een aangepast spamfilter kan eventueel worden ingesteld door een administrator.", "shared_aliases_desc": "Een gedeeld aliasadres wordt niet beïnvloed door gebruikersspecifieke instellingen. Een aangepast spamfilter kan eventueel worden ingesteld door een administrator.",
"show_sieve_filters": "Toon actieve filters", "show_sieve_filters": "Toon actieve filters",

View File

@ -587,7 +587,7 @@
"save": "Salvează modificările", "save": "Salvează modificările",
"scope": "Scop", "scope": "Scop",
"sender_acl": "Permite trimiterea ca", "sender_acl": "Permite trimiterea ca",
"sender_acl_disabled": "<span class=\"label label-danger\">Verificarea expeditorului este dezactivată</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Verificarea expeditorului este dezactivată</span>",
"sender_acl_info": "Dacă utilizatorului A de căsuță poștală îi este permis să trimită ca utilizatorul B, adresa expeditorului nu este afișată automat ca fiind câmp selectabil \"de la\" în SOGo.<br>\r\n Utilizatorul căsuței poștale B trebuie să creeze o delegație în SOGo pentru a permite utilizatorul cutiei poștale A să selecteze adresa ca expeditor. Pentru a delega o cutie poștală în SOGo, utilizați meniul (trei puncte) din dreapta numelui căsuței poștale în stânga sus, în timp ce vă aflați în vizualizarea e-mailului. Acest comportament nu se aplică adreselor alias.", "sender_acl_info": "Dacă utilizatorului A de căsuță poștală îi este permis să trimită ca utilizatorul B, adresa expeditorului nu este afișată automat ca fiind câmp selectabil \"de la\" în SOGo.<br>\r\n Utilizatorul căsuței poștale B trebuie să creeze o delegație în SOGo pentru a permite utilizatorul cutiei poștale A să selecteze adresa ca expeditor. Pentru a delega o cutie poștală în SOGo, utilizați meniul (trei puncte) din dreapta numelui căsuței poștale în stânga sus, în timp ce vă aflați în vizualizarea e-mailului. Acest comportament nu se aplică adreselor alias.",
"sieve_desc": "Descriere scurtă", "sieve_desc": "Descriere scurtă",
"sieve_type": "Tip filtru", "sieve_type": "Tip filtru",

View File

@ -590,7 +590,7 @@
"save": "Uložiť zmeny", "save": "Uložiť zmeny",
"scope": "Rozsah", "scope": "Rozsah",
"sender_acl": "Povoliť odosielanie ako", "sender_acl": "Povoliť odosielanie ako",
"sender_acl_disabled": "<span class=\"label label-danger\">Kontrola odosielateľa vypnutá</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Kontrola odosielateľa vypnutá</span>",
"sender_acl_info": "Ak poštový používateľ A má povolenie poslať ako poštový používateľ B, adresa odosielateľa nieje automaticky viditeľná ako voliteľné \"from\" pole v SOGo.<br>\r\n Poštový používateľ B potrebuje vytvoriť delegáciu v SOGo, aby bol schopný poštový používateľ A vybrať svoju adresu ako odosielateľ. Na delegovanie poštovej adresy v SOGo, použite menu (tri bodky) napravo vášho poštového mena v hornom ľavom rohu, v prehľade správ. Toto neplatí pre alias adresy.", "sender_acl_info": "Ak poštový používateľ A má povolenie poslať ako poštový používateľ B, adresa odosielateľa nieje automaticky viditeľná ako voliteľné \"from\" pole v SOGo.<br>\r\n Poštový používateľ B potrebuje vytvoriť delegáciu v SOGo, aby bol schopný poštový používateľ A vybrať svoju adresu ako odosielateľ. Na delegovanie poštovej adresy v SOGo, použite menu (tri bodky) napravo vášho poštového mena v hornom ľavom rohu, v prehľade správ. Toto neplatí pre alias adresy.",
"sieve_desc": "Krátky popis", "sieve_desc": "Krátky popis",
"sieve_type": "Typ filtru", "sieve_type": "Typ filtru",

View File

@ -592,7 +592,7 @@
"save": "Spara ändringar", "save": "Spara ändringar",
"scope": "Omfattning", "scope": "Omfattning",
"sender_acl": "Tillåt att skicka som", "sender_acl": "Tillåt att skicka som",
"sender_acl_disabled": "<span class=\"label label-danger\">Avsändarkontroll är avaktiverad</span>", "sender_acl_disabled": "<span class=\"label label-danger\">Avsändarkontroll är avaktiverad</span>",
"sender_acl_info": "Om användaren A tillåts skicka som användaren B visas inte avsändaradressen automatiskt i \"från\" fältet i SOGo.<br>\r\n Användaren B måste skapa en delegation i SOGo för att låta användaren A välja Användaren B's adress som avsändare. För att delegera en postlåda i SOGo, gå till menyn (tre punkter) till höger om ditt namn uppe till vänster i postvyn. Detta gäller inte för aliasadresser.", "sender_acl_info": "Om användaren A tillåts skicka som användaren B visas inte avsändaradressen automatiskt i \"från\" fältet i SOGo.<br>\r\n Användaren B måste skapa en delegation i SOGo för att låta användaren A välja Användaren B's adress som avsändare. För att delegera en postlåda i SOGo, gå till menyn (tre punkter) till höger om ditt namn uppe till vänster i postvyn. Detta gäller inte för aliasadresser.",
"sieve_desc": "Kort beskrivning", "sieve_desc": "Kort beskrivning",
"sieve_type": "Filtertyp", "sieve_type": "Filtertyp",

View File

@ -544,7 +544,7 @@
"save": "保存更改", "save": "保存更改",
"scope": "范围", "scope": "范围",
"sender_acl": "允许发送为", "sender_acl": "允许发送为",
"sender_acl_disabled": "<span class=\"label label-danger\">发件人检查已关闭</span>", "sender_acl_disabled": "<span class=\"label label-danger\">发件人检查已关闭</span>",
"sender_acl_info": "如果允许邮箱用户A作为邮箱用户B发送邮件发件人的地址不会在SOGo中\"来自\"区域自动地作为下拉可选项显示。<br>\r\n 邮箱用户B需要添加授权以允许邮箱用户A选择B的地址作为发件人授权方法为在SOGo中点击左上方邮箱地址右边的菜单按钮(三个点)并授权。", "sender_acl_info": "如果允许邮箱用户A作为邮箱用户B发送邮件发件人的地址不会在SOGo中\"来自\"区域自动地作为下拉可选项显示。<br>\r\n 邮箱用户B需要添加授权以允许邮箱用户A选择B的地址作为发件人授权方法为在SOGo中点击左上方邮箱地址右边的菜单按钮(三个点)并授权。",
"sieve_desc": "简短描述", "sieve_desc": "简短描述",
"sieve_type": "过滤器类型", "sieve_type": "过滤器类型",

View File

@ -94,7 +94,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma
<input type="hidden" name="unset_fido2_key" value="<?=$key_info['cid'];?>" /> <input type="hidden" name="unset_fido2_key" value="<?=$key_info['cid'];?>" />
<div class="btn-group"> <div class="btn-group">
<a href="#" class="btn btn-xs btn-default" data-cid="<?=$key_info['cid'];?>" data-subject="<?=base64_encode($key_info['subject']);?>" data-toggle="modal" data-target="#fido2ChangeFn"><i class="bi bi-pencil-fill"></i> <?=strtolower($lang['fido2']['rename']);?></a> <a href="#" class="btn btn-xs btn-default" data-cid="<?=$key_info['cid'];?>" data-subject="<?=base64_encode($key_info['subject']);?>" data-toggle="modal" data-target="#fido2ChangeFn"><i class="bi bi-pencil-fill"></i> <?=strtolower($lang['fido2']['rename']);?></a>
<a href="#" onClick='return confirm("<?=$lang['admin']['ays'];?>")?$(this).closest("form").submit():"";' class="btn btn-xs btn-danger"><i class="bi bi-recycle"></i> <?=strtolower($lang['admin']['remove']);?></a> <a href="#" onClick='return confirm("<?=$lang['admin']['ays'];?>")?$(this).closest("form").submit():"";' class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> <?=strtolower($lang['admin']['remove']);?></a>
</form> </form>
</div> </div>
</td> </td>
@ -229,32 +229,33 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
} }
?> ?>
<div class="row"> <div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['direct_aliases'];?>: <div class="col-md-3 col-xs-5 text-right"><i class="bi bi-pin-angle"></i> <?=$lang['user']['direct_aliases'];?>:
<p class="small"><?=$lang['user']['direct_aliases_desc'];?></p> <p class="small"><?=$lang['user']['direct_aliases_desc'];?></p>
</div> </div>
<div class="col-md-9 col-xs-7"> <div class="col-md-9 col-xs-7">
<?php <?php
if ($user_get_alias_details['direct_aliases'] === false) { if (empty($user_get_alias_details['direct_aliases'])) {
echo '&#10008;'; echo '<i class="bi bi-x-lg"></i>';
} }
else { else {
foreach (array_filter($user_get_alias_details['direct_aliases']) as $direct_alias => $direct_alias_meta) { foreach (array_filter($user_get_alias_details['direct_aliases']) as $direct_alias => $direct_alias_meta) {
(!empty($direct_alias_meta['public_comment'])) ? (!empty($direct_alias_meta['public_comment'])) ?
printf('%s &mdash; <span class="bg-info">%s</span><br>', $direct_alias, $direct_alias_meta['public_comment']) : printf('%s &mdash; <i class="bi bi-chat-left"></i> %s<br>', $direct_alias, $direct_alias_meta['public_comment']) :
printf('%s<br>', $direct_alias); printf('%s<br>', $direct_alias);
} }
} }
?> ?>
</div> </div>
</div> </div>
<br>
<div class="row"> <div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['shared_aliases'];?>: <div class="col-md-3 col-xs-5 text-right"><i class="bi bi-share"></i> <?=$lang['user']['shared_aliases'];?>:
<p class="small"><?=$lang['user']['shared_aliases_desc'];?></p> <p class="small"><?=$lang['user']['shared_aliases_desc'];?></p>
</div> </div>
<div class="col-md-9 col-xs-7"> <div class="col-md-9 col-xs-7">
<?php <?php
if ($user_get_alias_details['shared_aliases'] === false) { if (empty($user_get_alias_details['shared_aliases'])) {
echo '&#10008;'; echo '<i class="bi bi-x-lg"></i>';
} }
else { else {
foreach (array_filter($user_get_alias_details['shared_aliases']) as $shared_alias => $shared_alias_meta) { foreach (array_filter($user_get_alias_details['shared_aliases']) as $shared_alias => $shared_alias_meta) {
@ -271,19 +272,19 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
<div class="row"> <div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_also_send_as'];?>:</div> <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_also_send_as'];?>:</div>
<div class="col-md-9 col-xs-7"> <div class="col-md-9 col-xs-7">
<p><?=($user_get_alias_details['aliases_also_send_as'] == '*') ? $lang['user']['sender_acl_disabled'] : $user_get_alias_details['aliases_also_send_as'];?></p> <p><?=($user_get_alias_details['aliases_also_send_as'] == '*') ? $lang['user']['sender_acl_disabled'] : (empty($user_get_alias_details['aliases_also_send_as'])) ? '<i class="bi bi-x-lg"></i>' : '' ;?></p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_send_as_all'];?>:</div> <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_send_as_all'];?>:</div>
<div class="col-md-9 col-xs-7"> <div class="col-md-9 col-xs-7">
<p><?=$user_get_alias_details['aliases_send_as_all'];?></p> <p><?=(empty($user_get_alias_details['aliases_send_as_all'])) ? '<i class="bi bi-x-lg"></i>' : '' ;?></p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['is_catch_all'];?>:</div> <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['is_catch_all'];?>:</div>
<div class="col-md-9 col-xs-7"> <div class="col-md-9 col-xs-7">
<p><?=$user_get_alias_details['is_catch_all'];?></p> <p><?=(empty($user_get_alias_details['is_catch_all'])) ? '<i class="bi bi-x-lg"></i>' : '' ;?></p>
</div> </div>
</div> </div>
<hr> <hr>
@ -648,7 +649,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
<div class="btn-group" data-acl="<?=$_SESSION['acl']['pushover'];?>"> <div class="btn-group" data-acl="<?=$_SESSION['acl']['pushover'];?>">
<a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover" data-item="<?=htmlspecialchars($username);?>" data-api-url='edit/pushover' data-api-attr='{}' href="#"><?=$lang['user']['save'];?></a> <a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover" data-item="<?=htmlspecialchars($username);?>" data-api-url='edit/pushover' data-api-attr='{}' href="#"><?=$lang['user']['save'];?></a>
<a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover-test" data-item="<?=htmlspecialchars($username);?>" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-all"></i> <?=$lang['user']['pushover_verify'];?></a> <a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover-test" data-item="<?=htmlspecialchars($username);?>" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-all"></i> <?=$lang['user']['pushover_verify'];?></a>
<a id="pushover_delete" class="btn btn-sm btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="<?=htmlspecialchars($username);?>" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-recycle"></i> <?=$lang['user']['remove'];?></a> <a id="pushover_delete" class="btn btn-sm btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="<?=htmlspecialchars($username);?>" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-trash"></i> <?=$lang['user']['remove'];?></a>
</div> </div>
</div> </div>
</div> </div>

View File

@ -290,7 +290,7 @@ services:
- dovecot - dovecot
postfix-mailcow: postfix-mailcow:
image: mailcow/postfix:1.61 image: mailcow/postfix:1.62
depends_on: depends_on:
- mysql-mailcow - mysql-mailcow
volumes: volumes: